Update libjingle to 55618622.
Update libyuv to r826.

TEST=try bots
R=niklas.enbom@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5038 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/DEPS b/DEPS
index 6bf74cb..205ba4e 100644
--- a/DEPS
+++ b/DEPS
@@ -72,7 +72,7 @@
     Var("chromium_trunk") + "/deps/third_party/libvpx@225010",
 
   "third_party/libyuv":
-    (Var("googlecode_url") % "libyuv") + "/trunk@723",
+    (Var("googlecode_url") % "libyuv") + "/trunk@826",
 
   "third_party/opus":
     Var("chromium_trunk") + "/src/third_party/opus@185405",
diff --git a/talk/app/webrtc/localaudiosource.cc b/talk/app/webrtc/localaudiosource.cc
index 3663aac..2cd472a 100644
--- a/talk/app/webrtc/localaudiosource.cc
+++ b/talk/app/webrtc/localaudiosource.cc
@@ -53,7 +53,9 @@
     "googHighpassFilter";
 const char MediaConstraintsInterface::kTypingNoiseDetection[] =
     "googTypingNoiseDetection";
-const char MediaConstraintsInterface::kInternalAecDump[] = "internalAecDump";
+const char MediaConstraintsInterface::kAudioMirroring[] = "googAudioMirroring";
+// TODO(perkj): Remove kInternalAecDump once its not used by Chrome.
+const char MediaConstraintsInterface::kInternalAecDump[] = "deprecatedAecDump";
 
 namespace {
 
@@ -90,10 +92,10 @@
       options->noise_suppression.Set(value);
     else if (iter->key == MediaConstraintsInterface::kHighpassFilter)
       options->highpass_filter.Set(value);
-    else if (iter->key == MediaConstraintsInterface::kInternalAecDump)
-      options->aec_dump.Set(value);
     else if (iter->key == MediaConstraintsInterface::kTypingNoiseDetection)
       options->typing_detection.Set(value);
+    else if (iter->key == MediaConstraintsInterface::kAudioMirroring)
+      options->stereo_swapping.Set(value);
     else
       success = false;
   }
@@ -103,14 +105,16 @@
 }  // namespace
 
 talk_base::scoped_refptr<LocalAudioSource> LocalAudioSource::Create(
+    const PeerConnectionFactoryInterface::Options& options,
     const MediaConstraintsInterface* constraints) {
   talk_base::scoped_refptr<LocalAudioSource> source(
       new talk_base::RefCountedObject<LocalAudioSource>());
-  source->Initialize(constraints);
+  source->Initialize(options, constraints);
   return source;
 }
 
 void LocalAudioSource::Initialize(
+    const PeerConnectionFactoryInterface::Options& options,
     const MediaConstraintsInterface* constraints) {
   if (!constraints)
     return;
@@ -119,12 +123,14 @@
   // constraints.
   FromConstraints(constraints->GetOptional(), &options_);
 
-  cricket::AudioOptions options;
-  if (!FromConstraints(constraints->GetMandatory(), &options)) {
+  cricket::AudioOptions audio_options;
+  if (!FromConstraints(constraints->GetMandatory(), &audio_options)) {
     source_state_ = kEnded;
     return;
   }
-  options_.SetAll(options);
+  options_.SetAll(audio_options);
+  if (options.enable_aec_dump)
+    options_.aec_dump.Set(true);
   source_state_ = kLive;
 }
 
diff --git a/talk/app/webrtc/localaudiosource.h b/talk/app/webrtc/localaudiosource.h
index e0fda03..fb769ed 100644
--- a/talk/app/webrtc/localaudiosource.h
+++ b/talk/app/webrtc/localaudiosource.h
@@ -30,6 +30,7 @@
 
 #include "talk/app/webrtc/mediastreaminterface.h"
 #include "talk/app/webrtc/notifier.h"
+#include "talk/app/webrtc/peerconnectioninterface.h"
 #include "talk/base/scoped_ptr.h"
 #include "talk/media/base/mediachannel.h"
 
@@ -44,6 +45,7 @@
  public:
   // Creates an instance of LocalAudioSource.
   static talk_base::scoped_refptr<LocalAudioSource> Create(
+      const PeerConnectionFactoryInterface::Options& options,
       const MediaConstraintsInterface* constraints);
 
   virtual SourceState state() const { return source_state_; }
@@ -58,7 +60,8 @@
   }
 
  private:
-  void Initialize(const MediaConstraintsInterface* constraints);
+  void Initialize(const PeerConnectionFactoryInterface::Options& options,
+                  const MediaConstraintsInterface* constraints);
 
   cricket::AudioOptions options_;
   SourceState source_state_;
diff --git a/talk/app/webrtc/localaudiosource_unittest.cc b/talk/app/webrtc/localaudiosource_unittest.cc
index ae07787..f8880e0 100644
--- a/talk/app/webrtc/localaudiosource_unittest.cc
+++ b/talk/app/webrtc/localaudiosource_unittest.cc
@@ -39,6 +39,7 @@
 using webrtc::LocalAudioSource;
 using webrtc::MediaConstraintsInterface;
 using webrtc::MediaSourceInterface;
+using webrtc::PeerConnectionFactoryInterface;
 
 TEST(LocalAudioSourceTest, SetValidOptions) {
   webrtc::FakeConstraints constraints;
@@ -52,7 +53,8 @@
   constraints.AddOptional(MediaConstraintsInterface::kHighpassFilter, true);
 
   talk_base::scoped_refptr<LocalAudioSource> source =
-      LocalAudioSource::Create(&constraints);
+      LocalAudioSource::Create(PeerConnectionFactoryInterface::Options(),
+                               &constraints);
 
   bool value;
   EXPECT_TRUE(source->options().echo_cancellation.Get(&value));
@@ -72,7 +74,8 @@
 TEST(LocalAudioSourceTest, OptionNotSet) {
   webrtc::FakeConstraints constraints;
   talk_base::scoped_refptr<LocalAudioSource> source =
-      LocalAudioSource::Create(&constraints);
+      LocalAudioSource::Create(PeerConnectionFactoryInterface::Options(),
+                               &constraints);
   bool value;
   EXPECT_FALSE(source->options().highpass_filter.Get(&value));
 }
@@ -83,7 +86,8 @@
   constraints.AddOptional(MediaConstraintsInterface::kEchoCancellation, true);
 
   talk_base::scoped_refptr<LocalAudioSource> source =
-      LocalAudioSource::Create(&constraints);
+      LocalAudioSource::Create(PeerConnectionFactoryInterface::Options(),
+                               &constraints);
 
   bool value;
   EXPECT_TRUE(source->options().echo_cancellation.Get(&value));
@@ -96,7 +100,8 @@
   constraints.AddOptional("invalidKey", false);
 
   talk_base::scoped_refptr<LocalAudioSource> source =
-      LocalAudioSource::Create(&constraints);
+      LocalAudioSource::Create(PeerConnectionFactoryInterface::Options(),
+                               &constraints);
 
   EXPECT_EQ(MediaSourceInterface::kLive, source->state());
   bool value;
@@ -110,7 +115,8 @@
   constraints.AddMandatory("invalidKey", false);
 
   talk_base::scoped_refptr<LocalAudioSource> source =
-      LocalAudioSource::Create(&constraints);
+      LocalAudioSource::Create(PeerConnectionFactoryInterface::Options(),
+                               &constraints);
 
   EXPECT_EQ(MediaSourceInterface::kEnded, source->state());
   bool value;
diff --git a/talk/app/webrtc/mediaconstraintsinterface.h b/talk/app/webrtc/mediaconstraintsinterface.h
index 48022dd..97d5cf6 100644
--- a/talk/app/webrtc/mediaconstraintsinterface.h
+++ b/talk/app/webrtc/mediaconstraintsinterface.h
@@ -81,6 +81,7 @@
   static const char kNoiseSuppression[];  // googNoiseSuppression
   static const char kHighpassFilter[];  // googHighpassFilter
   static const char kTypingNoiseDetection[];  // googTypingNoiseDetection
+  static const char kAudioMirroring[];  // googAudioMirroring
 
   // Google-specific constraint keys for a local video source
   static const char kNoiseReduction[];  // googNoiseReduction
@@ -106,6 +107,8 @@
   static const char kEnableDtlsSrtp[];  // Enable DTLS-SRTP
   // Temporary pseudo-constraints used to enable DataChannels
   static const char kEnableRtpDataChannels[];  // Enable RTP DataChannels
+  // TODO(perkj): Remove kEnableSctpDataChannels once Chrome use
+  // PeerConnectionFactory::SetOptions.
   static const char kEnableSctpDataChannels[];  // Enable SCTP DataChannels
 
   // The prefix of internal-only constraints whose JS set values should be
@@ -116,9 +119,8 @@
   // line flags. So they are prefixed with "internal" so JS values will be
   // removed.
   // Used by a local audio source.
+  // TODO(perkj): Remove once Chrome use PeerConnectionFactory::SetOptions.
   static const char kInternalAecDump[];  // internalAecDump
-  // Used for disabling security and use plain RTP.
-  static const char kInternalDisableEncryption[];  // internalDisableEncryption
 
  protected:
   // Dtor protected as objects shouldn't be deleted via this interface
diff --git a/talk/app/webrtc/mediastreamsignaling.cc b/talk/app/webrtc/mediastreamsignaling.cc
index 771a4e8..ef9f3e0 100644
--- a/talk/app/webrtc/mediastreamsignaling.cc
+++ b/talk/app/webrtc/mediastreamsignaling.cc
@@ -267,6 +267,10 @@
   }
   scoped_refptr<DataChannel> channel(
       data_channel_factory_->CreateDataChannel(label, &config));
+  if (!channel.get()) {
+    LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
+    return false;
+  }
   data_channels_[label] = channel;
   stream_observer_->OnAddDataChannel(channel);
   // It's immediately ready to use.
diff --git a/talk/app/webrtc/peerconnection.cc b/talk/app/webrtc/peerconnection.cc
index 7fafad7..de88f88 100644
--- a/talk/app/webrtc/peerconnection.cc
+++ b/talk/app/webrtc/peerconnection.cc
@@ -317,7 +317,8 @@
   stats_.set_session(session_.get());
 
   // Initialize the WebRtcSession. It creates transport channels etc.
-  if (!session_->Initialize(constraints, dtls_identity_service))
+  if (!session_->Initialize(factory_->options(), constraints,
+                            dtls_identity_service))
     return false;
 
   // Register PeerConnection as receiver of local ice candidates.
diff --git a/talk/app/webrtc/peerconnection_unittest.cc b/talk/app/webrtc/peerconnection_unittest.cc
index 9de6ec9..76d9cd7 100644
--- a/talk/app/webrtc/peerconnection_unittest.cc
+++ b/talk/app/webrtc/peerconnection_unittest.cc
@@ -157,8 +157,8 @@
       // Disable highpass filter so that we can get all the test audio frames.
       constraints.AddMandatory(
           MediaConstraintsInterface::kHighpassFilter, false);
-      talk_base::scoped_refptr<webrtc::LocalAudioSource> source =
-          webrtc::LocalAudioSource::Create(&constraints);
+      talk_base::scoped_refptr<webrtc::AudioSourceInterface> source =
+          peer_connection_factory_->CreateAudioSource(&constraints);
       // TODO(perkj): Test audio source when it is implemented. Currently audio
       // always use the default input.
       talk_base::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
diff --git a/talk/app/webrtc/peerconnectionfactory.cc b/talk/app/webrtc/peerconnectionfactory.cc
index 7d30fab..e8b8f63 100644
--- a/talk/app/webrtc/peerconnectionfactory.cc
+++ b/talk/app/webrtc/peerconnectionfactory.cc
@@ -261,7 +261,7 @@
 PeerConnectionFactory::CreateAudioSource_s(
     const MediaConstraintsInterface* constraints) {
   talk_base::scoped_refptr<LocalAudioSource> source(
-      LocalAudioSource::Create(constraints));
+      LocalAudioSource::Create(options_, constraints));
   return source;
 }
 
diff --git a/talk/app/webrtc/peerconnectionfactory.h b/talk/app/webrtc/peerconnectionfactory.h
index 7faf609..dff885d 100644
--- a/talk/app/webrtc/peerconnectionfactory.h
+++ b/talk/app/webrtc/peerconnectionfactory.h
@@ -40,6 +40,10 @@
 class PeerConnectionFactory : public PeerConnectionFactoryInterface,
                               public talk_base::MessageHandler {
  public:
+  virtual void SetOptions(const Options& options) {
+    options_ = options;
+  }
+
   virtual talk_base::scoped_refptr<PeerConnectionInterface>
       CreatePeerConnection(
           const PeerConnectionInterface::IceServers& configuration,
@@ -77,6 +81,7 @@
   virtual cricket::ChannelManager* channel_manager();
   virtual talk_base::Thread* signaling_thread();
   virtual talk_base::Thread* worker_thread();
+  const Options& options() const { return options_; }
 
  protected:
   PeerConnectionFactory();
@@ -109,6 +114,7 @@
   bool owns_ptrs_;
   talk_base::Thread* signaling_thread_;
   talk_base::Thread* worker_thread_;
+  Options options_;
   talk_base::scoped_refptr<PortAllocatorFactoryInterface> allocator_factory_;
   // External Audio device used for audio playback.
   talk_base::scoped_refptr<AudioDeviceModule> default_adm_;
diff --git a/talk/app/webrtc/peerconnectioninterface.h b/talk/app/webrtc/peerconnectioninterface.h
index bd86f3e..a127dad 100644
--- a/talk/app/webrtc/peerconnectioninterface.h
+++ b/talk/app/webrtc/peerconnectioninterface.h
@@ -390,6 +390,19 @@
 // argument.
 class PeerConnectionFactoryInterface : public talk_base::RefCountInterface {
  public:
+  class Options {
+   public:
+    Options() :
+      enable_aec_dump(false),
+      disable_encryption(false),
+      disable_sctp_data_channels(false) {
+    }
+    bool enable_aec_dump;
+    bool disable_encryption;
+    bool disable_sctp_data_channels;
+  };
+
+  virtual void SetOptions(const Options& options) = 0;
   virtual talk_base::scoped_refptr<PeerConnectionInterface>
      CreatePeerConnection(
          const PeerConnectionInterface::IceServers& configuration,
diff --git a/talk/app/webrtc/statscollector.cc b/talk/app/webrtc/statscollector.cc
index 42ae662..db7cac4 100644
--- a/talk/app/webrtc/statscollector.cc
+++ b/talk/app/webrtc/statscollector.cc
@@ -82,6 +82,15 @@
     "googFrameRateDecoded";
 const char StatsReport::kStatsValueNameFrameRateOutput[] =
     "googFrameRateOutput";
+const char StatsReport::kStatsValueNameDecodeMs[] = "googDecodeMs";
+const char StatsReport::kStatsValueNameMaxDecodeMs[] = "googMaxDecodeMs";
+const char StatsReport::kStatsValueNameCurrentDelayMs[] = "googCurrentDelayMs";
+const char StatsReport::kStatsValueNameTargetDelayMs[] = "googTargetDelayMs";
+const char StatsReport::kStatsValueNameJitterBufferMs[] = "googJitterBufferMs";
+const char StatsReport::kStatsValueNameMinPlayoutDelayMs[] =
+    "googMinPlayoutDelayMs";
+const char StatsReport::kStatsValueNameRenderDelayMs[] = "googRenderDelayMs";
+
 const char StatsReport::kStatsValueNameFrameRateInput[] = "googFrameRateInput";
 const char StatsReport::kStatsValueNameFrameRateSent[] = "googFrameRateSent";
 const char StatsReport::kStatsValueNameFrameWidthReceived[] =
@@ -119,6 +128,7 @@
 
 const char StatsReport::kStatsReportTypeSession[] = "googLibjingleSession";
 const char StatsReport::kStatsReportTypeBwe[] = "VideoBwe";
+const char StatsReport::kStatsReportTypeRemoteSsrc[] = "remoteSsrc";
 const char StatsReport::kStatsReportTypeSsrc[] = "ssrc";
 const char StatsReport::kStatsReportTypeTrack[] = "googTrack";
 const char StatsReport::kStatsReportTypeIceCandidate[] = "iceCandidate";
@@ -241,6 +251,21 @@
                    info.framerate_decoded);
   report->AddValue(StatsReport::kStatsValueNameFrameRateOutput,
                    info.framerate_output);
+
+  report->AddValue(StatsReport::kStatsValueNameDecodeMs,
+                   info.decode_ms);
+  report->AddValue(StatsReport::kStatsValueNameMaxDecodeMs,
+                   info.max_decode_ms);
+  report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
+                   info.current_delay_ms);
+  report->AddValue(StatsReport::kStatsValueNameTargetDelayMs,
+                   info.target_delay_ms);
+  report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
+                   info.jitter_buffer_ms);
+  report->AddValue(StatsReport::kStatsValueNameMinPlayoutDelayMs,
+                   info.min_playout_delay_ms);
+  report->AddValue(StatsReport::kStatsValueNameRenderDelayMs,
+                   info.render_delay_ms);
 }
 
 void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
@@ -293,6 +318,18 @@
                    info.bucket_delay);
 }
 
+void ExtractRemoteStats(const cricket::MediaSenderInfo& info,
+                        StatsReport* report) {
+  report->timestamp = info.remote_stats[0].timestamp;
+  // TODO(hta): Extract some stats here.
+}
+
+void ExtractRemoteStats(const cricket::MediaReceiverInfo& info,
+                        StatsReport* report) {
+  report->timestamp = info.remote_stats[0].timestamp;
+  // TODO(hta): Extract some stats here.
+}
+
 uint32 ExtractSsrc(const cricket::VoiceReceiverInfo& info) {
   return info.ssrc;
 }
@@ -319,11 +356,20 @@
   for (; it != data.end(); ++it) {
     std::string id;
     uint32 ssrc = ExtractSsrc(*it);
-    StatsReport* report = collector->PrepareReport(ssrc, transport_id);
+    // Each object can result in 2 objects, a local and a remote object.
+    // TODO(hta): Handle the case of multiple SSRCs per object.
+    StatsReport* report = collector->PrepareLocalReport(ssrc, transport_id);
     if (!report) {
       continue;
     }
     ExtractStats(*it, report);
+    if (it->remote_stats.size() > 0) {
+      report = collector->PrepareRemoteReport(ssrc, transport_id);
+      if (!report) {
+        continue;
+      }
+      ExtractRemoteStats(*it, report);
+    }
   }
 };
 
@@ -406,8 +452,9 @@
   }
 }
 
-StatsReport* StatsCollector::PrepareReport(uint32 ssrc,
-                                           const std::string& transport_id) {
+StatsReport* StatsCollector::PrepareLocalReport(
+    uint32 ssrc,
+    const std::string& transport_id) {
   std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
   StatsMap::iterator it = reports_.find(StatsId(
       StatsReport::kStatsReportTypeSsrc, ssrc_id));
@@ -427,10 +474,8 @@
                            &track_id);
   }
 
-  StatsReport* report = &reports_[
-      StatsId(StatsReport::kStatsReportTypeSsrc, ssrc_id)];
-  report->id = StatsId(StatsReport::kStatsReportTypeSsrc, ssrc_id);
-  report->type = StatsReport::kStatsReportTypeSsrc;
+  StatsReport* report = GetOrCreateReport(StatsReport::kStatsReportTypeSsrc,
+                                          ssrc_id);
 
   // Clear out stats from previous GatherStats calls if any.
   if (report->timestamp != stats_gathering_started_) {
@@ -446,6 +491,44 @@
   return report;
 }
 
+StatsReport* StatsCollector::PrepareRemoteReport(
+    uint32 ssrc,
+    const std::string& transport_id) {
+  std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
+  StatsMap::iterator it = reports_.find(StatsId(
+      StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id));
+
+  std::string track_id;
+  if (it == reports_.end()) {
+    if (!session()->GetTrackIdBySsrc(ssrc, &track_id)) {
+      LOG(LS_WARNING) << "The SSRC " << ssrc
+                      << " is not associated with a track";
+      return NULL;
+    }
+  } else {
+    // Keeps the old track id since we want to report the stats for inactive
+    // tracks.
+    ExtractValueFromReport(it->second,
+                           StatsReport::kStatsValueNameTrackId,
+                           &track_id);
+  }
+
+  StatsReport* report = GetOrCreateReport(
+      StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id);
+
+  // Clear out stats from previous GatherStats calls if any.
+  // The timestamp will be added later. Zero it for debugging.
+  report->values.clear();
+  report->timestamp = 0;
+
+  report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
+  report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
+  // Add the mapping of SSRC to transport.
+  report->AddValue(StatsReport::kStatsValueNameTransportId,
+                   transport_id);
+  return report;
+}
+
 std::string StatsCollector::AddOneCertificateReport(
     const talk_base::SSLCertificate* cert, const std::string& issuer_id) {
   // TODO(bemasc): Move this computation to a helper class that caches these
@@ -592,6 +675,9 @@
                           info.local_candidate.address().ToString());
           report.AddValue(StatsReport::kStatsValueNameRemoteAddress,
                           info.remote_candidate.address().ToString());
+          report.AddValue(StatsReport::kStatsValueNameRtt, info.rtt);
+          report.AddValue(StatsReport::kStatsValueNameTransportType,
+                          info.local_candidate.protocol());
           reports_[report.id] = report;
         }
       }
@@ -668,4 +754,19 @@
   return true;
 }
 
+StatsReport* StatsCollector::GetOrCreateReport(const std::string& type,
+                                               const std::string& id) {
+  std::string statsid = StatsId(type, id);
+  StatsReport* report = NULL;
+  std::map<std::string, StatsReport>::iterator it = reports_.find(statsid);
+  if (it == reports_.end()) {
+    report = &reports_[statsid];  // Create new element.
+    report->id = statsid;
+    report->type = type;
+  } else {
+    report = &reports_[statsid];
+  }
+  return report;
+}
+
 }  // namespace webrtc
diff --git a/talk/app/webrtc/statscollector.h b/talk/app/webrtc/statscollector.h
index c34b5a0..01da059 100644
--- a/talk/app/webrtc/statscollector.h
+++ b/talk/app/webrtc/statscollector.h
@@ -65,9 +65,11 @@
   // |reports|.
   bool GetStats(MediaStreamTrackInterface* track, StatsReports* reports);
 
-  WebRtcSession* session() { return session_; }
-  // Prepare an SSRC report for the given ssrc. Used internally.
-  StatsReport* PrepareReport(uint32 ssrc, const std::string& transport);
+  // Prepare an SSRC report for the given ssrc. Used internally
+  // in the ExtractStatsFromList template.
+  StatsReport* PrepareLocalReport(uint32 ssrc, const std::string& transport);
+  // Prepare an SSRC report for the given remote ssrc. Used internally.
+  StatsReport* PrepareRemoteReport(uint32 ssrc, const std::string& transport);
   // Extracts the ID of a Transport belonging to an SSRC. Used internally.
   bool GetTransportIdFromProxy(const std::string& proxy,
                                std::string* transport_id);
@@ -88,9 +90,12 @@
   void ExtractVideoInfo();
   double GetTimeNow();
   void BuildSsrcToTransportId();
+  WebRtcSession* session() { return session_; }
+  webrtc::StatsReport* GetOrCreateReport(const std::string& type,
+                                         const std::string& id);
 
   // A map from the report id to the report.
-  std::map<std::string, webrtc::StatsReport> reports_;
+  std::map<std::string, StatsReport> reports_;
   // Raw pointer to the session the statistics are gathered from.
   WebRtcSession* session_;
   double stats_gathering_started_;
diff --git a/talk/app/webrtc/statscollector_unittest.cc b/talk/app/webrtc/statscollector_unittest.cc
index d9cde5d..66a5ee0 100644
--- a/talk/app/webrtc/statscollector_unittest.cc
+++ b/talk/app/webrtc/statscollector_unittest.cc
@@ -58,6 +58,10 @@
 const char kNotFound[] = "NOT FOUND";
 const char kNoReports[] = "NO REPORTS";
 
+// Constant names for track identification.
+const char kTrackId[] = "somename";
+const uint32 kSsrcOfTrack = 1234;
+
 class MockWebRtcSession : public webrtc::WebRtcSession {
  public:
   explicit MockWebRtcSession(cricket::ChannelManager* channel_manager)
@@ -207,11 +211,37 @@
           new cricket::ChannelManager(media_engine_,
                                       new cricket::FakeDeviceManager(),
                                       talk_base::Thread::Current())),
-      session_(channel_manager_.get()) {
+      session_(channel_manager_.get()),
+      track_id_(kTrackId) {
     // By default, we ignore session GetStats calls.
     EXPECT_CALL(session_, GetStats(_)).WillRepeatedly(Return(false));
   }
 
+  // This creates a standard setup with a transport called "trspname"
+  // having one transport channel
+  // and the specified virtual connection name.
+  void InitSessionStats(const std::string vc_name) {
+    const std::string kTransportName("trspname");
+    cricket::TransportStats transport_stats;
+    cricket::TransportChannelStats channel_stats;
+    channel_stats.component = 1;
+    transport_stats.content_name = kTransportName;
+    transport_stats.channel_stats.push_back(channel_stats);
+
+    session_stats_.transport_stats[kTransportName] = transport_stats;
+    session_stats_.proxy_to_transport[vc_name] = kTransportName;
+  }
+
+  // Adds a track with a given SSRC into the stats.
+  void AddVideoTrackStats() {
+    stream_ = webrtc::MediaStream::Create("streamlabel");
+    track_= webrtc::VideoTrack::Create(kTrackId, NULL);
+    stream_->AddTrack(track_);
+    EXPECT_CALL(session_, GetTrackIdBySsrc(kSsrcOfTrack, _))
+      .WillRepeatedly(DoAll(SetArgPointee<1>(track_id_),
+                            Return(true)));
+  }
+
   void TestCertificateReports(const talk_base::FakeSSLCertificate& local_cert,
                               const std::vector<std::string>& local_ders,
                               const talk_base::FakeSSLCertificate& remote_cert,
@@ -283,9 +313,14 @@
     EXPECT_NE(kNotFound, remote_certificate_id);
     CheckCertChainReports(reports, remote_ders, remote_certificate_id);
   }
+
   cricket::FakeMediaEngine* media_engine_;
   talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_;
   MockWebRtcSession session_;
+  cricket::SessionStats session_stats_;
+  talk_base::scoped_refptr<webrtc::MediaStream> stream_;
+  talk_base::scoped_refptr<webrtc::VideoTrack> track_;
+  std::string track_id_;
 };
 
 // This test verifies that 64-bit counters are passed successfully.
@@ -297,17 +332,13 @@
   webrtc::StatsReports reports;  // returned values.
   cricket::VideoSenderInfo video_sender_info;
   cricket::VideoMediaInfo stats_read;
-  const uint32 kSsrcOfTrack = 1234;
-  const std::string kNameOfTrack("somename");
   // The number of bytes must be larger than 0xFFFFFFFF for this test.
   const int64 kBytesSent = 12345678901234LL;
   const std::string kBytesSentString("12345678901234");
 
   stats.set_session(&session_);
-  talk_base::scoped_refptr<webrtc::MediaStream> stream(
-      webrtc::MediaStream::Create("streamlabel"));
-  stream->AddTrack(webrtc::VideoTrack::Create(kNameOfTrack, NULL));
-  stats.AddStream(stream);
+  AddVideoTrackStats();
+  stats.AddStream(stream_);
 
   // Construct a stats value to read.
   video_sender_info.ssrcs.push_back(1234);
@@ -319,9 +350,6 @@
   EXPECT_CALL(*media_channel, GetStats(_))
     .WillOnce(DoAll(SetArgPointee<0>(stats_read),
                     Return(true)));
-  EXPECT_CALL(session_, GetTrackIdBySsrc(kSsrcOfTrack, _))
-    .WillOnce(DoAll(SetArgPointee<1>(kNameOfTrack),
-                    Return(true)));
   stats.UpdateStats();
   stats.GetStats(NULL, &reports);
   std::string result = ExtractSsrcStatsValue(reports, "bytesSent");
@@ -339,16 +367,12 @@
   cricket::VideoMediaInfo stats_read;
   // Set up an SSRC just to test that we get both kinds of stats back: SSRC and
   // BWE.
-  const uint32 kSsrcOfTrack = 1234;
-  const std::string kNameOfTrack("somename");
   const int64 kBytesSent = 12345678901234LL;
   const std::string kBytesSentString("12345678901234");
 
   stats.set_session(&session_);
-  talk_base::scoped_refptr<webrtc::MediaStream> stream(
-      webrtc::MediaStream::Create("streamlabel"));
-  stream->AddTrack(webrtc::VideoTrack::Create(kNameOfTrack, NULL));
-  stats.AddStream(stream);
+  AddVideoTrackStats();
+  stats.AddStream(stream_);
 
   // Construct a stats value to read.
   video_sender_info.ssrcs.push_back(1234);
@@ -365,9 +389,7 @@
   EXPECT_CALL(*media_channel, GetStats(_))
     .WillOnce(DoAll(SetArgPointee<0>(stats_read),
                     Return(true)));
-  EXPECT_CALL(session_, GetTrackIdBySsrc(kSsrcOfTrack, _))
-    .WillOnce(DoAll(SetArgPointee<1>(kNameOfTrack),
-                    Return(true)));
+
   stats.UpdateStats();
   stats.GetStats(NULL, &reports);
   std::string result = ExtractSsrcStatsValue(reports, "bytesSent");
@@ -417,13 +439,8 @@
   MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
   cricket::VideoChannel video_channel(talk_base::Thread::Current(),
       media_engine_, media_channel, &session_, "", false, NULL);
-  const std::string kTrackId("somename");
-  talk_base::scoped_refptr<webrtc::MediaStream> stream(
-      webrtc::MediaStream::Create("streamlabel"));
-  talk_base::scoped_refptr<webrtc::VideoTrack> track =
-      webrtc::VideoTrack::Create(kTrackId, NULL);
-  stream->AddTrack(track);
-  stats.AddStream(stream);
+  AddVideoTrackStats();
+  stats.AddStream(stream_);
 
   stats.set_session(&session_);
 
@@ -449,13 +466,8 @@
   MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
   cricket::VideoChannel video_channel(talk_base::Thread::Current(),
       media_engine_, media_channel, &session_, "", false, NULL);
-  const std::string kTrackId("somename");
-  talk_base::scoped_refptr<webrtc::MediaStream> stream(
-      webrtc::MediaStream::Create("streamlabel"));
-  talk_base::scoped_refptr<webrtc::VideoTrack> track =
-      webrtc::VideoTrack::Create(kTrackId, NULL);
-  stream->AddTrack(track);
-  stats.AddStream(stream);
+  AddVideoTrackStats();
+  stats.AddStream(stream_);
 
   stats.set_session(&session_);
 
@@ -464,7 +476,6 @@
   // Constructs an ssrc stats update.
   cricket::VideoSenderInfo video_sender_info;
   cricket::VideoMediaInfo stats_read;
-  const uint32 kSsrcOfTrack = 1234;
   const int64 kBytesSent = 12345678901234LL;
 
   // Construct a stats value to read.
@@ -477,23 +488,20 @@
   EXPECT_CALL(*media_channel, GetStats(_))
     .WillOnce(DoAll(SetArgPointee<0>(stats_read),
                     Return(true)));
-  EXPECT_CALL(session_, GetTrackIdBySsrc(kSsrcOfTrack, _))
-    .WillOnce(DoAll(SetArgPointee<1>(kTrackId),
-                    Return(true)));
 
   stats.UpdateStats();
   stats.GetStats(NULL, &reports);
-  // |reports| should contain one session report, one track report, and one ssrc
-  // report.
-  EXPECT_EQ((size_t)3, reports.size());
+  // |reports| should contain at least one session report, one track report,
+  // and one ssrc report.
+  EXPECT_LE((size_t)3, reports.size());
   const webrtc::StatsReport* track_report = FindNthReportByType(
       reports, webrtc::StatsReport::kStatsReportTypeTrack, 1);
   EXPECT_FALSE(track_report == NULL);
 
-  stats.GetStats(track, &reports);
-  // |reports| should contain one session report, one track report, and one ssrc
-  // report.
-  EXPECT_EQ((size_t)3, reports.size());
+  stats.GetStats(track_, &reports);
+  // |reports| should contain at least one session report, one track report,
+  // and one ssrc report.
+  EXPECT_LE((size_t)3, reports.size());
   track_report = FindNthReportByType(
       reports, webrtc::StatsReport::kStatsReportTypeTrack, 1);
   EXPECT_FALSE(track_report == NULL);
@@ -516,13 +524,8 @@
   const std::string kVcName("vcname");
   cricket::VideoChannel video_channel(talk_base::Thread::Current(),
       media_engine_, media_channel, &session_, kVcName, false, NULL);
-  const std::string kTrackId("somename");
-  talk_base::scoped_refptr<webrtc::MediaStream> stream(
-      webrtc::MediaStream::Create("streamlabel"));
-  talk_base::scoped_refptr<webrtc::VideoTrack> track =
-      webrtc::VideoTrack::Create(kTrackId, NULL);
-  stream->AddTrack(track);
-  stats.AddStream(stream);
+  AddVideoTrackStats();
+  stats.AddStream(stream_);
 
   stats.set_session(&session_);
 
@@ -531,7 +534,6 @@
   // Constructs an ssrc stats update.
   cricket::VideoSenderInfo video_sender_info;
   cricket::VideoMediaInfo stats_read;
-  const uint32 kSsrcOfTrack = 1234;
   const int64 kBytesSent = 12345678901234LL;
 
   // Construct a stats value to read.
@@ -544,23 +546,10 @@
   EXPECT_CALL(*media_channel, GetStats(_))
     .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
                           Return(true)));
-  EXPECT_CALL(session_, GetTrackIdBySsrc(kSsrcOfTrack, _))
-    .WillOnce(DoAll(SetArgPointee<1>(kTrackId),
-                    Return(true)));
 
-  // Instruct the session to return stats containing the transport channel.
-  const std::string kTransportName("trspname");
-  cricket::SessionStats session_stats;
-  cricket::TransportStats transport_stats;
-  cricket::TransportChannelStats channel_stats;
-  channel_stats.component = 1;
-  transport_stats.content_name = kTransportName;
-  transport_stats.channel_stats.push_back(channel_stats);
-
-  session_stats.transport_stats[kTransportName] = transport_stats;
-  session_stats.proxy_to_transport[kVcName] = kTransportName;
+  InitSessionStats(kVcName);
   EXPECT_CALL(session_, GetStats(_))
-    .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats),
+    .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
                           Return(true)));
 
   stats.UpdateStats();
@@ -575,6 +564,78 @@
   ASSERT_FALSE(transport_report == NULL);
 }
 
+// This test verifies that a remote stats object will not be created for
+// an outgoing SSRC where remote stats are not returned.
+TEST_F(StatsCollectorTest, RemoteSsrcInfoIsAbsent) {
+  webrtc::StatsCollector stats;  // Implementation under test.
+  MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
+  // The content_name known by the video channel.
+  const std::string kVcName("vcname");
+  cricket::VideoChannel video_channel(talk_base::Thread::Current(),
+      media_engine_, media_channel, &session_, kVcName, false, NULL);
+  AddVideoTrackStats();
+  stats.AddStream(stream_);
+
+  stats.set_session(&session_);
+
+  EXPECT_CALL(session_, video_channel())
+    .WillRepeatedly(ReturnNull());
+
+  stats.UpdateStats();
+  webrtc::StatsReports reports;
+  stats.GetStats(NULL, &reports);
+  const webrtc::StatsReport* remote_report = FindNthReportByType(reports,
+      webrtc::StatsReport::kStatsReportTypeRemoteSsrc, 1);
+  EXPECT_TRUE(remote_report == NULL);
+}
+
+// This test verifies that a remote stats object will be created for
+// an outgoing SSRC where stats are returned.
+TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) {
+  webrtc::StatsCollector stats;  // Implementation under test.
+  MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
+  // The content_name known by the video channel.
+  const std::string kVcName("vcname");
+  cricket::VideoChannel video_channel(talk_base::Thread::Current(),
+      media_engine_, media_channel, &session_, kVcName, false, NULL);
+  AddVideoTrackStats();
+  stats.AddStream(stream_);
+
+  stats.set_session(&session_);
+
+  webrtc::StatsReports reports;
+
+  // Instruct the session to return stats containing the transport channel.
+  InitSessionStats(kVcName);
+  EXPECT_CALL(session_, GetStats(_))
+    .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
+                          Return(true)));
+
+  // Constructs an ssrc stats update.
+  cricket::VideoMediaInfo stats_read;
+
+  cricket::SsrcReceiverInfo remote_ssrc_stats;
+  remote_ssrc_stats.timestamp = 12345.678;
+  remote_ssrc_stats.ssrc = kSsrcOfTrack;
+  cricket::VideoSenderInfo video_sender_info;
+  video_sender_info.ssrcs.push_back(kSsrcOfTrack);
+  video_sender_info.remote_stats.push_back(remote_ssrc_stats);
+  stats_read.senders.push_back(video_sender_info);
+
+  EXPECT_CALL(session_, video_channel())
+    .WillRepeatedly(Return(&video_channel));
+  EXPECT_CALL(*media_channel, GetStats(_))
+    .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
+                          Return(true)));
+
+  stats.UpdateStats();
+  stats.GetStats(NULL, &reports);
+  const webrtc::StatsReport* remote_report = FindNthReportByType(reports,
+      webrtc::StatsReport::kStatsReportTypeRemoteSsrc, 1);
+  EXPECT_FALSE(remote_report == NULL);
+  EXPECT_NE(0, remote_report->timestamp);
+}
+
 // This test verifies that all chained certificates are correctly
 // reported
 TEST_F(StatsCollectorTest, ChainedCertificateReportsCreated) {
@@ -638,6 +699,7 @@
   EXPECT_CALL(session_, GetStats(_))
     .WillOnce(DoAll(SetArgPointee<0>(session_stats),
                     Return(true)));
+
   EXPECT_CALL(session_, video_channel())
     .WillRepeatedly(ReturnNull());
 
@@ -712,5 +774,4 @@
   ASSERT_EQ(kNotFound, remote_certificate_id);
 }
 
-
 }  // namespace
diff --git a/talk/app/webrtc/statstypes.h b/talk/app/webrtc/statstypes.h
index fb8c15b..e76aa86 100644
--- a/talk/app/webrtc/statstypes.h
+++ b/talk/app/webrtc/statstypes.h
@@ -88,6 +88,10 @@
   // The |id| field is the SSRC in decimal form of the rtp stream.
   static const char kStatsReportTypeSsrc[];
 
+  // StatsReport of |type| = "remoteSsrc" is statistics for a specific
+  // rtp stream, generated by the remote end of the connection.
+  static const char kStatsReportTypeRemoteSsrc[];
+
   // StatsReport of |type| = "googTrack" is statistics for a specific media
   // track. The |id| field is the track id.
   static const char kStatsReportTypeTrack[];
@@ -137,6 +141,13 @@
   static const char kStatsValueNameFrameRateReceived[];
   static const char kStatsValueNameFrameRateDecoded[];
   static const char kStatsValueNameFrameRateOutput[];
+  static const char kStatsValueNameDecodeMs[];
+  static const char kStatsValueNameMaxDecodeMs[];
+  static const char kStatsValueNameCurrentDelayMs[];
+  static const char kStatsValueNameTargetDelayMs[];
+  static const char kStatsValueNameJitterBufferMs[];
+  static const char kStatsValueNameMinPlayoutDelayMs[];
+  static const char kStatsValueNameRenderDelayMs[];
   static const char kStatsValueNameFrameRateInput[];
   static const char kStatsValueNameFrameRateSent[];
   static const char kStatsValueNameFrameWidthReceived[];
diff --git a/talk/app/webrtc/test/fakeconstraints.h b/talk/app/webrtc/test/fakeconstraints.h
index 927432d..b23007e 100644
--- a/talk/app/webrtc/test/fakeconstraints.h
+++ b/talk/app/webrtc/test/fakeconstraints.h
@@ -119,7 +119,6 @@
   }
 
   void SetAllowDtlsSctpDataChannels() {
-    SetMandatory(MediaConstraintsInterface::kEnableSctpDataChannels, true);
     SetMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, true);
   }
 
diff --git a/talk/app/webrtc/webrtcsdp_unittest.cc b/talk/app/webrtc/webrtcsdp_unittest.cc
index 6f2e388..777a707 100644
--- a/talk/app/webrtc/webrtcsdp_unittest.cc
+++ b/talk/app/webrtc/webrtcsdp_unittest.cc
@@ -282,7 +282,7 @@
     "a=ice-ufrag:ufrag_data\r\n"
     "a=ice-pwd:pwd_data\r\n"
     "a=mid:data_content_name\r\n"
-    "a=sctpmap:5000 webrtc-datachannel 65536\r\n";
+    "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
 
 static const char kSdpSctpDataChannelWithCandidatesString[] =
     "m=application 2345 DTLS/SCTP 5000\r\n"
@@ -297,7 +297,7 @@
     "a=ice-ufrag:ufrag_data\r\n"
     "a=ice-pwd:pwd_data\r\n"
     "a=mid:data_content_name\r\n"
-    "a=sctpmap:5000 webrtc-datachannel 65536\r\n";
+    "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
 
 
 // One candidate reference string as per W3c spec.
diff --git a/talk/app/webrtc/webrtcsession.cc b/talk/app/webrtc/webrtcsession.cc
index 74d1488..69a47c4 100644
--- a/talk/app/webrtc/webrtcsession.cc
+++ b/talk/app/webrtc/webrtcsession.cc
@@ -68,10 +68,7 @@
 // line flag. So it is prefixed with kInternalConstraintPrefix so JS values
 // will be removed.
 const char MediaConstraintsInterface::kEnableSctpDataChannels[] =
-    "internalSctpDataChannels";
-
-const char MediaConstraintsInterface::kInternalDisableEncryption[] =
-    "internalDisableEncryption";
+    "deprecatedSctpDataChannels";
 
 // Error messages
 const char kSetLocalSdpFailed[] = "SetLocalDescription failed: ";
@@ -458,6 +455,7 @@
 }
 
 bool WebRtcSession::Initialize(
+    const PeerConnectionFactoryInterface::Options& options,
     const MediaConstraintsInterface* constraints,
     DTLSIdentityServiceInterface* dtls_identity_service) {
   // TODO(perkj): Take |constraints| into consideration. Return false if not all
@@ -476,19 +474,16 @@
   }
 
   // Enable creation of RTP data channels if the kEnableRtpDataChannels is set.
-  // It takes precendence over the kEnableSctpDataChannels constraint.
+  // It takes precendence over the disable_sctp_data_channels
+  // PeerConnectionFactoryInterface::Options.
   if (FindConstraint(
       constraints, MediaConstraintsInterface::kEnableRtpDataChannels,
       &value, NULL) && value) {
     LOG(LS_INFO) << "Allowing RTP data engine.";
     data_channel_type_ = cricket::DCT_RTP;
   } else {
-    bool sctp_enabled = FindConstraint(
-        constraints,
-        MediaConstraintsInterface::kEnableSctpDataChannels,
-        &value, NULL) && value;
     // DTLS has to be enabled to use SCTP.
-    if (sctp_enabled && dtls_enabled_) {
+    if (!options.disable_sctp_data_channels && dtls_enabled_) {
       LOG(LS_INFO) << "Allowing SCTP data engine.";
       data_channel_type_ = cricket::DCT_SCTP;
     }
@@ -520,11 +515,7 @@
   webrtc_session_desc_factory_->SignalIdentityReady.connect(
       this, &WebRtcSession::OnIdentityReady);
 
-  // Disable encryption if kDisableEncryption is set.
-  if (FindConstraint(
-         constraints,
-         MediaConstraintsInterface::kInternalDisableEncryption,
-         &value, NULL) && value) {
+  if (options.disable_encryption) {
     webrtc_session_desc_factory_->set_secure(cricket::SEC_DISABLED);
   }
 
diff --git a/talk/app/webrtc/webrtcsession.h b/talk/app/webrtc/webrtcsession.h
index 12e2291..dde33ca 100644
--- a/talk/app/webrtc/webrtcsession.h
+++ b/talk/app/webrtc/webrtcsession.h
@@ -110,7 +110,8 @@
                 MediaStreamSignaling* mediastream_signaling);
   virtual ~WebRtcSession();
 
-  bool Initialize(const MediaConstraintsInterface* constraints,
+  bool Initialize(const PeerConnectionFactoryInterface::Options& options,
+                  const MediaConstraintsInterface* constraints,
                   DTLSIdentityServiceInterface* dtls_identity_service);
   // Deletes the voice, video and data channel and changes the session state
   // to STATE_RECEIVEDTERMINATE.
diff --git a/talk/app/webrtc/webrtcsession_unittest.cc b/talk/app/webrtc/webrtcsession_unittest.cc
index 493294f..ecbba18 100644
--- a/talk/app/webrtc/webrtcsession_unittest.cc
+++ b/talk/app/webrtc/webrtcsession_unittest.cc
@@ -81,6 +81,7 @@
 using webrtc::IceCandidateCollection;
 using webrtc::JsepIceCandidate;
 using webrtc::JsepSessionDescription;
+using webrtc::PeerConnectionFactoryInterface;
 using webrtc::PeerConnectionInterface;
 using webrtc::SessionDescriptionInterface;
 using webrtc::StreamCollection;
@@ -317,7 +318,8 @@
     EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew,
         observer_.ice_gathering_state_);
 
-    EXPECT_TRUE(session_->Initialize(constraints_.get(), identity_service));
+    EXPECT_TRUE(session_->Initialize(options_, constraints_.get(),
+                                     identity_service));
   }
 
   void InitWithDtmfCodec() {
@@ -919,6 +921,7 @@
   cricket::TestStunServer stun_server_;
   talk_base::FakeNetworkManager network_manager_;
   cricket::BasicPortAllocator allocator_;
+  PeerConnectionFactoryInterface::Options options_;
   talk_base::scoped_ptr<FakeConstraints> constraints_;
   FakeMediaStreamSignaling mediastream_signaling_;
   talk_base::scoped_ptr<WebRtcSessionForTest> session_;
@@ -1932,9 +1935,7 @@
 }
 
 TEST_F(WebRtcSessionTest, VerifyNoCryptoParamsInSDP) {
-  constraints_.reset(new FakeConstraints());
-  constraints_->AddOptional(
-      webrtc::MediaConstraintsInterface::kInternalDisableEncryption, true);
+  options_.disable_encryption = true;
   Init(NULL);
   mediastream_signaling_.SendAudioVideoStream1();
   scoped_ptr<SessionDescriptionInterface> offer(
@@ -2424,9 +2425,7 @@
 
 // This test verifies the crypto parameter when security is disabled.
 TEST_F(WebRtcSessionTest, TestCryptoAfterSetLocalDescriptionWithDisabled) {
-  constraints_.reset(new FakeConstraints());
-  constraints_->AddOptional(
-      webrtc::MediaConstraintsInterface::kInternalDisableEncryption, true);
+  options_.disable_encryption = true;
   Init(NULL);
   mediastream_signaling_.SendAudioVideoStream1();
   talk_base::scoped_ptr<SessionDescriptionInterface> offer(
@@ -2567,8 +2566,8 @@
   constraints_.reset(new FakeConstraints());
   constraints_->AddOptional(
       webrtc::MediaConstraintsInterface::kEnableRtpDataChannels, true);
-  constraints_->AddOptional(
-    webrtc::MediaConstraintsInterface::kEnableSctpDataChannels, true);
+  options_.disable_sctp_data_channels = false;
+
   InitWithDtls(false);
 
   SetLocalDescriptionWithDataChannel();
@@ -2578,9 +2577,6 @@
 TEST_F(WebRtcSessionTest, TestCreateOfferWithSctpEnabledWithoutStreams) {
   MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
 
-  constraints_.reset(new FakeConstraints());
-  constraints_->AddOptional(
-      webrtc::MediaConstraintsInterface::kEnableSctpDataChannels, true);
   InitWithDtls(false);
 
   talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL));
@@ -2591,9 +2587,6 @@
 TEST_F(WebRtcSessionTest, TestCreateAnswerWithSctpInOfferAndNoStreams) {
   MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
   SetFactoryDtlsSrtp();
-  constraints_.reset(new FakeConstraints());
-  constraints_->AddOptional(
-      webrtc::MediaConstraintsInterface::kEnableSctpDataChannels, true);
   InitWithDtls(false);
 
   // Create remote offer with SCTP.
@@ -2613,8 +2606,6 @@
 TEST_F(WebRtcSessionTest, TestSctpDataChannelWithoutDtls) {
   constraints_.reset(new FakeConstraints());
   constraints_->AddOptional(
-      webrtc::MediaConstraintsInterface::kEnableSctpDataChannels, true);
-  constraints_->AddOptional(
       webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, false);
   InitWithDtls(false);
 
@@ -2625,24 +2616,26 @@
 TEST_F(WebRtcSessionTest, TestSctpDataChannelWithDtls) {
   MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
 
-  constraints_.reset(new FakeConstraints());
-  constraints_->AddOptional(
-      webrtc::MediaConstraintsInterface::kEnableSctpDataChannels, true);
   InitWithDtls(false);
 
   SetLocalDescriptionWithDataChannel();
   EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type());
 }
 
+TEST_F(WebRtcSessionTest, TestDisableSctpDataChannels) {
+  MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
+  options_.disable_sctp_data_channels = true;
+  InitWithDtls(false);
+
+  SetLocalDescriptionWithDataChannel();
+  EXPECT_EQ(cricket::DCT_NONE, data_engine_->last_channel_type());
+}
+
 TEST_F(WebRtcSessionTest, TestSctpDataChannelSendPortParsing) {
   MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
   const int new_send_port = 9998;
   const int new_recv_port = 7775;
 
-  constraints_.reset(new FakeConstraints());
-  constraints_->AddOptional(
-      webrtc::MediaConstraintsInterface::kEnableSctpDataChannels, true);
-
   InitWithDtls(false);
   SetFactoryDtlsSrtp();
 
diff --git a/talk/base/atomicops.h b/talk/base/atomicops.h
index 94ade69..068cd5f 100644
--- a/talk/base/atomicops.h
+++ b/talk/base/atomicops.h
@@ -79,7 +79,7 @@
   FixedSizeLockFreeQueue() : pushed_count_(0),
                              popped_count_(0),
                              capacity_(0),
-                             data_(NULL) {}
+                             data_() {}
   // Constructs an empty queue with the given capacity.
   FixedSizeLockFreeQueue(size_t capacity) : pushed_count_(0),
                                             popped_count_(0),
@@ -157,7 +157,7 @@
   volatile Atomic32 pushed_count_;
   volatile Atomic32 popped_count_;
   size_t capacity_;
-  talk_base::scoped_array<T> data_;
+  talk_base::scoped_ptr<T[]> data_;
   DISALLOW_COPY_AND_ASSIGN(FixedSizeLockFreeQueue);
 };
 
diff --git a/talk/base/buffer.h b/talk/base/buffer.h
index 311cfad..4709633 100644
--- a/talk/base/buffer.h
+++ b/talk/base/buffer.h
@@ -88,7 +88,7 @@
   }
   void SetCapacity(size_t capacity) {
     if (capacity > capacity_) {
-      talk_base::scoped_array<char> data(new char[capacity]);
+      talk_base::scoped_ptr<char[]> data(new char[capacity]);
       memcpy(data.get(), data_.get(), length_);
       data_.swap(data);
       capacity_ = capacity;
@@ -109,7 +109,7 @@
     SetData(data, length);
   }
 
-  scoped_array<char> data_;
+  scoped_ptr<char[]> data_;
   size_t length_;
   size_t capacity_;
 };
diff --git a/talk/base/common.h b/talk/base/common.h
index b9aeca4..6350baf 100644
--- a/talk/base/common.h
+++ b/talk/base/common.h
@@ -25,7 +25,7 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef TALK_BASE_COMMON_H_
+#ifndef TALK_BASE_COMMON_H_  // NOLINT
 #define TALK_BASE_COMMON_H_
 
 #include "talk/base/basictypes.h"
@@ -64,7 +64,7 @@
 #define strnicmp(x, y, n) strncasecmp(x, y, n)
 #define stricmp(x, y) strcasecmp(x, y)
 
-// TODO: Remove this. std::max should be used everywhere in the code.
+// TODO(fbarchard): Remove this. std::max should be used everywhere in the code.
 // NOMINMAX must be defined where we include <windows.h>.
 #define stdmax(x, y) std::max(x, y)
 #else
@@ -181,9 +181,28 @@
 #if defined(WIN32)
 #define OVERRIDE override
 #elif defined(__clang__)
+// Clang defaults to C++03 and warns about using override. Squelch that.
+// Intentionally no push/pop here so all users of OVERRIDE ignore the warning
+// too. This is like passing -Wno-c++11-extensions, except that GCC won't die
+// (because it won't see this pragma).
+#pragma clang diagnostic ignored "-Wc++11-extensions"
 #define OVERRIDE override
 #else
 #define OVERRIDE
 #endif
 
-#endif  // TALK_BASE_COMMON_H_
+// Annotate a function indicating the caller must examine the return value.
+// Use like:
+//   int foo() WARN_UNUSED_RESULT;
+// To explicitly ignore a result, see |ignore_result()| in <base/basictypes.h>.
+// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and
+// libjingle are merged.
+#if !defined(WARN_UNUSED_RESULT)
+#if defined(COMPILER_GCC)
+#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define WARN_UNUSED_RESULT
+#endif
+#endif  // WARN_UNUSED_RESULT
+
+#endif  // TALK_BASE_COMMON_H_    // NOLINT
diff --git a/talk/base/compile_assert.h b/talk/base/compile_assert.h
new file mode 100644
index 0000000..7252d08
--- /dev/null
+++ b/talk/base/compile_assert.h
@@ -0,0 +1,99 @@
+/*
+ * libjingle
+ * Copyright 2013, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// COMPILE_ASSERT macro, borrowed from google3/base/macros.h.
+#ifndef TALK_BASE_COMPILE_ASSERT_H_
+#define TALK_BASE_COMPILE_ASSERT_H_
+
+// The COMPILE_ASSERT macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+//   COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
+//                  content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+//   COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and
+// libjingle are merged.
+#if !defined(COMPILE_ASSERT)
+template <bool>
+struct CompileAssert {
+};
+
+#define COMPILE_ASSERT(expr, msg) \
+  typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]  // NOLINT
+#endif  // COMPILE_ASSERT
+
+// Implementation details of COMPILE_ASSERT:
+//
+// - COMPILE_ASSERT works by defining an array type that has -1
+//   elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+//     #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+//   does not work, as gcc supports variable-length arrays whose sizes
+//   are determined at run-time (this is gcc's extension and not part
+//   of the C++ standard).  As a result, gcc fails to reject the
+//   following code with the simple definition:
+//
+//     int foo;
+//     COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
+//                               // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+//   expr is a compile-time constant.  (Template arguments must be
+//   determined at compile-time.)
+//
+// - The outer parentheses in CompileAssert<(bool(expr))> are necessary
+//   to work around a bug in gcc 3.4.4 and 4.0.1.  If we had written
+//
+//     CompileAssert<bool(expr)>
+//
+//   instead, these compilers will refuse to compile
+//
+//     COMPILE_ASSERT(5 > 0, some_message);
+//
+//   (They seem to think the ">" in "5 > 0" marks the end of the
+//   template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+//     ((expr) ? 1 : -1).
+//
+//   This is to avoid running into a bug in MS VC 7.1, which
+//   causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+
+#endif  // TALK_BASE_COMPILE_ASSERT_H_
diff --git a/talk/base/constructormagic.h b/talk/base/constructormagic.h
index 8b1f7ff..3023044 100644
--- a/talk/base/constructormagic.h
+++ b/talk/base/constructormagic.h
@@ -2,26 +2,26 @@
  * libjingle
  * Copyright 2004--2005, Google Inc.
  *
- * Redistribution and use in source and binary forms, with or without 
+ * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
- *  1. Redistributions of source code must retain the above copyright notice, 
+ *  1. Redistributions of source code must retain the above copyright notice,
  *     this list of conditions and the following disclaimer.
  *  2. Redistributions in binary form must reproduce the above copyright notice,
  *     this list of conditions and the following disclaimer in the documentation
  *     and/or other materials provided with the distribution.
- *  3. The name of the author may not be used to endorse or promote products 
+ *  3. The name of the author may not be used to endorse or promote products
  *     derived from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
@@ -32,7 +32,10 @@
   void operator=(const TypeName&)
 
 // A macro to disallow the evil copy constructor and operator= functions
-// This should be used in the private: declarations for a class
+// This should be used in the private: declarations for a class.
+// Undefine this, just in case. Some third-party includes have their own
+// version.
+#undef DISALLOW_COPY_AND_ASSIGN
 #define DISALLOW_COPY_AND_ASSIGN(TypeName)    \
   TypeName(const TypeName&);                    \
   DISALLOW_ASSIGN(TypeName)
diff --git a/talk/base/cpumonitor.cc b/talk/base/cpumonitor.cc
index 0a70887..e9b481f 100644
--- a/talk/base/cpumonitor.cc
+++ b/talk/base/cpumonitor.cc
@@ -210,7 +210,7 @@
   } else {
     if (nt_query_system_information) {
       ULONG returned_length = 0;
-      scoped_array<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> processor_info(
+      scoped_ptr<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[]> processor_info(
           new SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[cpus_]);
       nt_query_system_information(
           ::SystemProcessorPerformanceInformation,
@@ -281,6 +281,13 @@
   const uint64 cpu_times = nice + system + user;
   const uint64 total_times = cpu_times + idle;
 #endif  // defined(LINUX) || defined(ANDROID)
+
+#if defined(__native_client__)
+  // TODO(ryanpetrie): Implement this via PPAPI when it's available.
+  const uint64 cpu_times = 0;
+  const uint64 total_times = 0;
+#endif  // defined(__native_client__)
+
   system_.prev_load_time_ = timenow;
   system_.prev_load_ = UpdateCpuLoad(total_times,
                                      cpu_times * cpus_,
@@ -359,6 +366,12 @@
       (usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * kNumMicrosecsPerSec +
       usage.ru_utime.tv_usec + usage.ru_stime.tv_usec;
 #endif  // defined(LINUX) || defined(ANDROID)
+
+#if defined(__native_client__)
+  // TODO(ryanpetrie): Implement this via PPAPI when it's available.
+  const uint64 cpu_times = 0;
+#endif  // defined(__native_client__)
+
   process_.prev_load_time_ = timenow;
   process_.prev_load_ = UpdateCpuLoad(total_times,
                                      cpu_times,
diff --git a/talk/base/helpers.cc b/talk/base/helpers.cc
index bda940b..b10a3f7 100644
--- a/talk/base/helpers.cc
+++ b/talk/base/helpers.cc
@@ -239,7 +239,7 @@
                         const char* table, int table_size,
                         std::string* str) {
   str->clear();
-  scoped_array<uint8> bytes(new uint8[len]);
+  scoped_ptr<uint8[]> bytes(new uint8[len]);
   if (!Rng().Generate(bytes.get(), len)) {
     LOG(LS_ERROR) << "Failed to generate random string!";
     return false;
diff --git a/talk/base/macutils.cc b/talk/base/macutils.cc
index c73b0fa..28f96e2 100644
--- a/talk/base/macutils.cc
+++ b/talk/base/macutils.cc
@@ -43,7 +43,7 @@
   size_t maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str16),
                                                     kCFStringEncodingUTF8)
                   + 1;
-  scoped_array<char> buffer(new char[maxlen]);
+  scoped_ptr<char[]> buffer(new char[maxlen]);
   if (!buffer || !CFStringGetCString(str16, buffer.get(), maxlen,
                                      kCFStringEncodingUTF8))
     return false;
diff --git a/talk/base/messagedigest.cc b/talk/base/messagedigest.cc
index 6136ae2..d91d067 100644
--- a/talk/base/messagedigest.cc
+++ b/talk/base/messagedigest.cc
@@ -85,7 +85,7 @@
 }
 
 std::string ComputeDigest(MessageDigest* digest, const std::string& input) {
-  scoped_array<char> output(new char[digest->Size()]);
+  scoped_ptr<char[]> output(new char[digest->Size()]);
   ComputeDigest(digest, input.data(), input.size(),
                 output.get(), digest->Size());
   return hex_encode(output.get(), digest->Size());
@@ -120,7 +120,7 @@
   }
   // Copy the key to a block-sized buffer to simplify padding.
   // If the key is longer than a block, hash it and use the result instead.
-  scoped_array<uint8> new_key(new uint8[block_len]);
+  scoped_ptr<uint8[]> new_key(new uint8[block_len]);
   if (key_len > block_len) {
     ComputeDigest(digest, key, key_len, new_key.get(), block_len);
     memset(new_key.get() + digest->Size(), 0, block_len - digest->Size());
@@ -129,13 +129,13 @@
     memset(new_key.get() + key_len, 0, block_len - key_len);
   }
   // Set up the padding from the key, salting appropriately for each padding.
-  scoped_array<uint8> o_pad(new uint8[block_len]), i_pad(new uint8[block_len]);
+  scoped_ptr<uint8[]> o_pad(new uint8[block_len]), i_pad(new uint8[block_len]);
   for (size_t i = 0; i < block_len; ++i) {
     o_pad[i] = 0x5c ^ new_key[i];
     i_pad[i] = 0x36 ^ new_key[i];
   }
   // Inner hash; hash the inner padding, and then the input buffer.
-  scoped_array<uint8> inner(new uint8[digest->Size()]);
+  scoped_ptr<uint8[]> inner(new uint8[digest->Size()]);
   digest->Update(i_pad.get(), block_len);
   digest->Update(input, in_len);
   digest->Finish(inner.get(), digest->Size());
@@ -158,7 +158,7 @@
 
 std::string ComputeHmac(MessageDigest* digest, const std::string& key,
                         const std::string& input) {
-  scoped_array<char> output(new char[digest->Size()]);
+  scoped_ptr<char[]> output(new char[digest->Size()]);
   ComputeHmac(digest, key.data(), key.size(),
               input.data(), input.size(), output.get(), digest->Size());
   return hex_encode(output.get(), digest->Size());
diff --git a/talk/base/move.h b/talk/base/move.h
new file mode 100644
index 0000000..0cd1dcf
--- /dev/null
+++ b/talk/base/move.h
@@ -0,0 +1,207 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_WEBRTC_FILES_TALK_BASE_MOVE_H_
+#define THIRD_PARTY_WEBRTC_FILES_TALK_BASE_MOVE_H_
+
+// Macro with the boilerplate that makes a type move-only in C++03.
+//
+// USAGE
+//
+// This macro should be used instead of DISALLOW_COPY_AND_ASSIGN to create
+// a "move-only" type.  Unlike DISALLOW_COPY_AND_ASSIGN, this macro should be
+// the first line in a class declaration.
+//
+// A class using this macro must call .Pass() (or somehow be an r-value already)
+// before it can be:
+//
+//   * Passed as a function argument
+//   * Used as the right-hand side of an assignment
+//   * Returned from a function
+//
+// Each class will still need to define their own "move constructor" and "move
+// operator=" to make this useful.  Here's an example of the macro, the move
+// constructor, and the move operator= from the scoped_ptr class:
+//
+//  template <typename T>
+//  class scoped_ptr {
+//     MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
+//   public:
+//    scoped_ptr(RValue& other) : ptr_(other.release()) { }
+//    scoped_ptr& operator=(RValue& other) {
+//      swap(other);
+//      return *this;
+//    }
+//  };
+//
+// Note that the constructor must NOT be marked explicit.
+//
+// For consistency, the second parameter to the macro should always be RValue
+// unless you have a strong reason to do otherwise.  It is only exposed as a
+// macro parameter so that the move constructor and move operator= don't look
+// like they're using a phantom type.
+//
+//
+// HOW THIS WORKS
+//
+// For a thorough explanation of this technique, see:
+//
+//   http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor
+//
+// The summary is that we take advantage of 2 properties:
+//
+//   1) non-const references will not bind to r-values.
+//   2) C++ can apply one user-defined conversion when initializing a
+//      variable.
+//
+// The first lets us disable the copy constructor and assignment operator
+// by declaring private version of them with a non-const reference parameter.
+//
+// For l-values, direct initialization still fails like in
+// DISALLOW_COPY_AND_ASSIGN because the copy constructor and assignment
+// operators are private.
+//
+// For r-values, the situation is different. The copy constructor and
+// assignment operator are not viable due to (1), so we are trying to call
+// a non-existent constructor and non-existing operator= rather than a private
+// one.  Since we have not committed an error quite yet, we can provide an
+// alternate conversion sequence and a constructor.  We add
+//
+//   * a private struct named "RValue"
+//   * a user-defined conversion "operator RValue()"
+//   * a "move constructor" and "move operator=" that take the RValue& as
+//     their sole parameter.
+//
+// Only r-values will trigger this sequence and execute our "move constructor"
+// or "move operator=."  L-values will match the private copy constructor and
+// operator= first giving a "private in this context" error.  This combination
+// gives us a move-only type.
+//
+// For signaling a destructive transfer of data from an l-value, we provide a
+// method named Pass() which creates an r-value for the current instance
+// triggering the move constructor or move operator=.
+//
+// Other ways to get r-values is to use the result of an expression like a
+// function call.
+//
+// Here's an example with comments explaining what gets triggered where:
+//
+//    class Foo {
+//      MOVE_ONLY_TYPE_FOR_CPP_03(Foo, RValue);
+//
+//     public:
+//       ... API ...
+//       Foo(RValue other);           // Move constructor.
+//       Foo& operator=(RValue rhs);  // Move operator=
+//    };
+//
+//    Foo MakeFoo();  // Function that returns a Foo.
+//
+//    Foo f;
+//    Foo f_copy(f);  // ERROR: Foo(Foo&) is private in this context.
+//    Foo f_assign;
+//    f_assign = f;   // ERROR: operator=(Foo&) is private in this context.
+//
+//
+//    Foo f(MakeFoo());      // R-value so alternate conversion executed.
+//    Foo f_copy(f.Pass());  // R-value so alternate conversion executed.
+//    f = f_copy.Pass();     // R-value so alternate conversion executed.
+//
+//
+// IMPLEMENTATION SUBTLETIES WITH RValue
+//
+// The RValue struct is just a container for a pointer back to the original
+// object. It should only ever be created as a temporary, and no external
+// class should ever declare it or use it in a parameter.
+//
+// It is tempting to want to use the RValue type in function parameters, but
+// excluding the limited usage here for the move constructor and move
+// operator=, doing so would mean that the function could take both r-values
+// and l-values equially which is unexpected.  See COMPARED To Boost.Move for
+// more details.
+//
+// An alternate, and incorrect, implementation of the RValue class used by
+// Boost.Move makes RValue a fieldless child of the move-only type. RValue&
+// is then used in place of RValue in the various operators.  The RValue& is
+// "created" by doing *reinterpret_cast<RValue*>(this).  This has the appeal
+// of never creating a temporary RValue struct even with optimizations
+// disabled.  Also, by virtue of inheritance you can treat the RValue
+// reference as if it were the move-only type itself.  Unfortunately,
+// using the result of this reinterpret_cast<> is actually undefined behavior
+// due to C++98 5.2.10.7. In certain compilers (e.g., NaCl) the optimizer
+// will generate non-working code.
+//
+// In optimized builds, both implementations generate the same assembly so we
+// choose the one that adheres to the standard.
+//
+//
+// COMPARED TO C++11
+//
+// In C++11, you would implement this functionality using an r-value reference
+// and our .Pass() method would be replaced with a call to std::move().
+//
+// This emulation also has a deficiency where it uses up the single
+// user-defined conversion allowed by C++ during initialization.  This can
+// cause problems in some API edge cases.  For instance, in scoped_ptr, it is
+// impossible to make a function "void Foo(scoped_ptr<Parent> p)" accept a
+// value of type scoped_ptr<Child> even if you add a constructor to
+// scoped_ptr<> that would make it look like it should work.  C++11 does not
+// have this deficiency.
+//
+//
+// COMPARED TO Boost.Move
+//
+// Our implementation similar to Boost.Move, but we keep the RValue struct
+// private to the move-only type, and we don't use the reinterpret_cast<> hack.
+//
+// In Boost.Move, RValue is the boost::rv<> template.  This type can be used
+// when writing APIs like:
+//
+//   void MyFunc(boost::rv<Foo>& f)
+//
+// that can take advantage of rv<> to avoid extra copies of a type.  However you
+// would still be able to call this version of MyFunc with an l-value:
+//
+//   Foo f;
+//   MyFunc(f);  // Uh oh, we probably just destroyed |f| w/o calling Pass().
+//
+// unless someone is very careful to also declare a parallel override like:
+//
+//   void MyFunc(const Foo& f)
+//
+// that would catch the l-values first.  This was declared unsafe in C++11 and
+// a C++11 compiler will explicitly fail MyFunc(f).  Unfortunately, we cannot
+// ensure this in C++03.
+//
+// Since we have no need for writing such APIs yet, our implementation keeps
+// RValue private and uses a .Pass() method to do the conversion instead of
+// trying to write a version of "std::move()." Writing an API like std::move()
+// would require the RValue struct to be public.
+//
+//
+// CAVEATS
+//
+// If you include a move-only type as a field inside a class that does not
+// explicitly declare a copy constructor, the containing class's implicit
+// copy constructor will change from Containing(const Containing&) to
+// Containing(Containing&).  This can cause some unexpected errors.
+//
+//   http://llvm.org/bugs/show_bug.cgi?id=11528
+//
+// The workaround is to explicitly declare your copy constructor.
+//
+#define MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \
+ private: \
+  struct rvalue_type { \
+    explicit rvalue_type(type* object) : object(object) {} \
+    type* object; \
+  }; \
+  type(type&); \
+  void operator=(type&); \
+ public: \
+  operator rvalue_type() { return rvalue_type(this); } \
+  type Pass() { return type(rvalue_type(this)); } \
+ private:
+
+#endif  // THIRD_PARTY_WEBRTC_FILES_TALK_BASE_MOVE_H_
diff --git a/talk/base/natserver.cc b/talk/base/natserver.cc
index ef85f74..3ad378c 100644
--- a/talk/base/natserver.cc
+++ b/talk/base/natserver.cc
@@ -149,7 +149,7 @@
 
   // Forward this packet to the internal address.
   // First prepend the address in a quasi-STUN format.
-  scoped_array<char> real_buf(new char[size + kNATEncodedIPv6AddressSize]);
+  scoped_ptr<char[]> real_buf(new char[size + kNATEncodedIPv6AddressSize]);
   size_t addrlength = PackAddressForNAT(real_buf.get(),
                                         size + kNATEncodedIPv6AddressSize,
                                         remote_addr);
diff --git a/talk/base/natsocketfactory.cc b/talk/base/natsocketfactory.cc
index 1686f20..395069e 100644
--- a/talk/base/natsocketfactory.cc
+++ b/talk/base/natsocketfactory.cc
@@ -154,7 +154,7 @@
       return socket_->SendTo(data, size, addr);
     }
     // This array will be too large for IPv4 packets, but only by 12 bytes.
-    scoped_array<char> buf(new char[size + kNATEncodedIPv6AddressSize]);
+    scoped_ptr<char[]> buf(new char[size + kNATEncodedIPv6AddressSize]);
     size_t addrlength = PackAddressForNAT(buf.get(),
                                           size + kNATEncodedIPv6AddressSize,
                                           addr);
diff --git a/talk/base/nethelpers.cc b/talk/base/nethelpers.cc
index eebc6cf..05e02c9 100644
--- a/talk/base/nethelpers.cc
+++ b/talk/base/nethelpers.cc
@@ -109,7 +109,7 @@
     return false;
   }
   DWORD protbuff_size = 4096;
-  scoped_array<char> protocols;
+  scoped_ptr<char[]> protocols;
   LPWSAPROTOCOL_INFOW protocol_infos = NULL;
   int requested_protocols[2] = {AF_INET6, 0};
 
diff --git a/talk/base/network.cc b/talk/base/network.cc
index cbfcb5f..d4dda13 100644
--- a/talk/base/network.cc
+++ b/talk/base/network.cc
@@ -316,7 +316,7 @@
   NetworkMap current_networks;
   // MSDN recommends a 15KB buffer for the first try at GetAdaptersAddresses.
   size_t buffer_size = 16384;
-  scoped_array<char> adapter_info(new char[buffer_size]);
+  scoped_ptr<char[]> adapter_info(new char[buffer_size]);
   PIP_ADAPTER_ADDRESSES adapter_addrs =
       reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get());
   int adapter_flags = (GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_ANYCAST |
diff --git a/talk/base/network_unittest.cc b/talk/base/network_unittest.cc
index ce19120..e11e78d 100644
--- a/talk/base/network_unittest.cc
+++ b/talk/base/network_unittest.cc
@@ -120,7 +120,8 @@
   EXPECT_FALSE(IsIgnoredNetwork(network_manager, include_me));
 }
 
-TEST_F(NetworkTest, TestCreateNetworks) {
+// Test is failing on Windows opt: b/11288214
+TEST_F(NetworkTest, DISABLED_TestCreateNetworks) {
   BasicNetworkManager manager;
   NetworkManager::NetworkList result = GetNetworks(manager, true);
   // We should be able to bind to any addresses we find.
diff --git a/talk/base/physicalsocketserver.cc b/talk/base/physicalsocketserver.cc
index 21d6eab..891330a 100644
--- a/talk/base/physicalsocketserver.cc
+++ b/talk/base/physicalsocketserver.cc
@@ -534,6 +534,9 @@
         *slevel = IPPROTO_TCP;
         *sopt = TCP_NODELAY;
         break;
+      case OPT_DSCP:
+        LOG(LS_WARNING) << "Socket::OPT_DSCP not supported.";
+        return -1;
       default:
         ASSERT(false);
         return -1;
diff --git a/talk/base/scoped_ptr.h b/talk/base/scoped_ptr.h
index 5a8364e..c12948b 100644
--- a/talk/base/scoped_ptr.h
+++ b/talk/base/scoped_ptr.h
@@ -1,34 +1,102 @@
-//  (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
-//  Copyright (c) 2001, 2002 Peter Dimov
-//
-//  Permission to copy, use, modify, sell and distribute this software
-//  is granted provided this copyright notice appears in all copies.
-//  This software is provided "as is" without express or implied
-//  warranty, and with no claim as to its suitability for any purpose.
-//
-//  See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation.
-//
+// Borrowed from chromium.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
 
-//  scoped_ptr mimics a built-in pointer except that it guarantees deletion
-//  of the object pointed to, either on destruction of the scoped_ptr or via
-//  an explicit reset(). scoped_ptr is a simple solution for simple needs;
-//  use shared_ptr or std::auto_ptr if your needs are more complex.
+// Scopers help you manage ownership of a pointer, helping you easily manage the
+// a pointer within a scope, and automatically destroying the pointer at the
+// end of a scope.  There are two main classes you will use, which correspond
+// to the operators new/delete and new[]/delete[].
+//
+// Example usage (scoped_ptr<T>):
+//   {
+//     scoped_ptr<Foo> foo(new Foo("wee"));
+//   }  // foo goes out of scope, releasing the pointer with it.
+//
+//   {
+//     scoped_ptr<Foo> foo;          // No pointer managed.
+//     foo.reset(new Foo("wee"));    // Now a pointer is managed.
+//     foo.reset(new Foo("wee2"));   // Foo("wee") was destroyed.
+//     foo.reset(new Foo("wee3"));   // Foo("wee2") was destroyed.
+//     foo->Method();                // Foo::Method() called.
+//     foo.get()->Method();          // Foo::Method() called.
+//     SomeFunc(foo.release());      // SomeFunc takes ownership, foo no longer
+//                                   // manages a pointer.
+//     foo.reset(new Foo("wee4"));   // foo manages a pointer again.
+//     foo.reset();                  // Foo("wee4") destroyed, foo no longer
+//                                   // manages a pointer.
+//   }  // foo wasn't managing a pointer, so nothing was destroyed.
+//
+// Example usage (scoped_ptr<T[]>):
+//   {
+//     scoped_ptr<Foo[]> foo(new Foo[100]);
+//     foo.get()->Method();  // Foo::Method on the 0th element.
+//     foo[10].Method();     // Foo::Method on the 10th element.
+//   }
+//
+// These scopers also implement part of the functionality of C++11 unique_ptr
+// in that they are "movable but not copyable."  You can use the scopers in
+// the parameter and return types of functions to signify ownership transfer
+// in to and out of a function.  When calling a function that has a scoper
+// as the argument type, it must be called with the result of an analogous
+// scoper's Pass() function or another function that generates a temporary;
+// passing by copy will NOT work.  Here is an example using scoped_ptr:
+//
+//   void TakesOwnership(scoped_ptr<Foo> arg) {
+//     // Do something with arg
+//   }
+//   scoped_ptr<Foo> CreateFoo() {
+//     // No need for calling Pass() because we are constructing a temporary
+//     // for the return value.
+//     return scoped_ptr<Foo>(new Foo("new"));
+//   }
+//   scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
+//     return arg.Pass();
+//   }
+//
+//   {
+//     scoped_ptr<Foo> ptr(new Foo("yay"));  // ptr manages Foo("yay").
+//     TakesOwnership(ptr.Pass());           // ptr no longer owns Foo("yay").
+//     scoped_ptr<Foo> ptr2 = CreateFoo();   // ptr2 owns the return Foo.
+//     scoped_ptr<Foo> ptr3 =                // ptr3 now owns what was in ptr2.
+//         PassThru(ptr2.Pass());            // ptr2 is correspondingly NULL.
+//   }
+//
+// Notice that if you do not call Pass() when returning from PassThru(), or
+// when invoking TakesOwnership(), the code will not compile because scopers
+// are not copyable; they only implement move semantics which require calling
+// the Pass() function to signify a destructive transfer of state. CreateFoo()
+// is different though because we are constructing a temporary on the return
+// line and thus can avoid needing to call Pass().
+//
+// Pass() properly handles upcast in initialization, i.e. you can use a
+// scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
+//
+//   scoped_ptr<Foo> foo(new Foo());
+//   scoped_ptr<FooParent> parent(foo.Pass());
+//
+// PassAs<>() should be used to upcast return value in return statement:
+//
+//   scoped_ptr<Foo> CreateFoo() {
+//     scoped_ptr<FooChild> result(new FooChild());
+//     return result.PassAs<Foo>();
+//   }
+//
+// Note that PassAs<>() is implemented only for scoped_ptr<T>, but not for
+// scoped_ptr<T[]>. This is because casting array pointers may not be safe.
 
-//  scoped_ptr_malloc added in by Google.  When one of
-//  these goes out of scope, instead of doing a delete or delete[], it
-//  calls free().  scoped_ptr_malloc<char> is likely to see much more
-//  use than any other specializations.
-
-//  release() added in by Google. Use this to conditionally
-//  transfer ownership of a heap-allocated object to the caller, usually on
-//  method success.
 #ifndef TALK_BASE_SCOPED_PTR_H__
 #define TALK_BASE_SCOPED_PTR_H__
 
 #include <cstddef>             // for std::ptrdiff_t
 #include <stdlib.h>            // for free() decl
 
+#include <algorithm>  // For std::swap().
+
 #include "talk/base/common.h"  // for ASSERT
+#include "talk/base/compile_assert.h"  // for COMPILE_ASSERT
+#include "talk/base/move.h"    // for MOVE_ONLY_TYPE_FOR_CPP_03
+#include "talk/base/template_util.h"    // for is_convertible, is_array
 
 #ifdef _WIN32
 namespace std { using ::ptrdiff_t; };
@@ -36,242 +104,495 @@
 
 namespace talk_base {
 
-template <typename T>
-class scoped_ptr {
- private:
-
-  T* ptr;
-
-  scoped_ptr(scoped_ptr const &);
-  scoped_ptr & operator=(scoped_ptr const &);
-
- public:
-
-  typedef T element_type;
-
-  explicit scoped_ptr(T* p = NULL): ptr(p) {}
-
-  ~scoped_ptr() {
-    typedef char type_must_be_complete[sizeof(T)];
+// Function object which deletes its parameter, which must be a pointer.
+// If C is an array type, invokes 'delete[]' on the parameter; otherwise,
+// invokes 'delete'. The default deleter for scoped_ptr<T>.
+template <class T>
+struct DefaultDeleter {
+  DefaultDeleter() {}
+  template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) {
+    // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor
+    // if U* is implicitly convertible to T* and U is not an array type.
+    //
+    // Correct implementation should use SFINAE to disable this
+    // constructor. However, since there are no other 1-argument constructors,
+    // using a COMPILE_ASSERT() based on is_convertible<> and requiring
+    // complete types is simpler and will cause compile failures for equivalent
+    // misuses.
+    //
+    // Note, the is_convertible<U*, T*> check also ensures that U is not an
+    // array. T is guaranteed to be a non-array, so any U* where U is an array
+    // cannot convert to T*.
+    enum { T_must_be_complete = sizeof(T) };
+    enum { U_must_be_complete = sizeof(U) };
+    COMPILE_ASSERT((talk_base::is_convertible<U*, T*>::value),
+                   U_ptr_must_implicitly_convert_to_T_ptr);
+  }
+  inline void operator()(T* ptr) const {
+    enum { type_must_be_complete = sizeof(T) };
     delete ptr;
   }
-
-  void reset(T* p = NULL) {
-    typedef char type_must_be_complete[sizeof(T)];
-
-    if (ptr != p) {
-      T* obj = ptr;
-      ptr = p;
-      // Delete last, in case obj destructor indirectly results in ~scoped_ptr
-      delete obj;
-    }
-  }
-
-  T& operator*() const {
-    ASSERT(ptr != NULL);
-    return *ptr;
-  }
-
-  T* operator->() const  {
-    ASSERT(ptr != NULL);
-    return ptr;
-  }
-
-  T* get() const  {
-    return ptr;
-  }
-
-  void swap(scoped_ptr & b) {
-    T* tmp = b.ptr;
-    b.ptr = ptr;
-    ptr = tmp;
-  }
-
-  T* release() {
-    T* tmp = ptr;
-    ptr = NULL;
-    return tmp;
-  }
-
-  T** accept() {
-    if (ptr) {
-      delete ptr;
-      ptr = NULL;
-    }
-    return &ptr;
-  }
-
-  T** use() {
-    return &ptr;
-  }
-
-  // Allow scoped_ptr<T> to be used in boolean expressions, but not
-  // implicitly convertible to a real bool (which is dangerous).
-  // Borrowed from chromium's scoped_ptr implementation.
-  typedef T* scoped_ptr::*Testable;
-  operator Testable() const { return ptr ? &scoped_ptr::ptr : NULL; }
-
 };
 
-template<typename T> inline
-void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) {
-  a.swap(b);
-}
-
-
-
-
-//  scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
-//  is guaranteed, either on destruction of the scoped_array or via an explicit
-//  reset(). Use shared_array or std::vector if your needs are more complex.
-
-template<typename T>
-class scoped_array {
- private:
-
-  T* ptr;
-
-  scoped_array(scoped_array const &);
-  scoped_array & operator=(scoped_array const &);
-
- public:
-
-  typedef T element_type;
-
-  explicit scoped_array(T* p = NULL) : ptr(p) {}
-
-  ~scoped_array() {
-    typedef char type_must_be_complete[sizeof(T)];
+// Specialization of DefaultDeleter for array types.
+template <class T>
+struct DefaultDeleter<T[]> {
+  inline void operator()(T* ptr) const {
+    enum { type_must_be_complete = sizeof(T) };
     delete[] ptr;
   }
 
-  void reset(T* p = NULL) {
-    typedef char type_must_be_complete[sizeof(T)];
+ private:
+  // Disable this operator for any U != T because it is undefined to execute
+  // an array delete when the static type of the array mismatches the dynamic
+  // type.
+  //
+  // References:
+  //   C++98 [expr.delete]p3
+  //   http://cplusplus.github.com/LWG/lwg-defects.html#938
+  template <typename U> void operator()(U* array) const;
+};
 
-    if (ptr != p) {
-      T* arr = ptr;
-      ptr = p;
-      // Delete last, in case arr destructor indirectly results in ~scoped_array
-      delete [] arr;
+template <class T, int n>
+struct DefaultDeleter<T[n]> {
+  // Never allow someone to declare something like scoped_ptr<int[10]>.
+  COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type);
+};
+
+// Function object which invokes 'free' on its parameter, which must be
+// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
+//
+// scoped_ptr<int, talk_base::FreeDeleter> foo_ptr(
+//     static_cast<int*>(malloc(sizeof(int))));
+struct FreeDeleter {
+  inline void operator()(void* ptr) const {
+    free(ptr);
+  }
+};
+
+namespace internal {
+
+// Minimal implementation of the core logic of scoped_ptr, suitable for
+// reuse in both scoped_ptr and its specializations.
+template <class T, class D>
+class scoped_ptr_impl {
+ public:
+  explicit scoped_ptr_impl(T* p) : data_(p) { }
+
+  // Initializer for deleters that have data parameters.
+  scoped_ptr_impl(T* p, const D& d) : data_(p, d) {}
+
+  // Templated constructor that destructively takes the value from another
+  // scoped_ptr_impl.
+  template <typename U, typename V>
+  scoped_ptr_impl(scoped_ptr_impl<U, V>* other)
+      : data_(other->release(), other->get_deleter()) {
+    // We do not support move-only deleters.  We could modify our move
+    // emulation to have talk_base::subtle::move() and
+    // talk_base::subtle::forward()
+    // functions that are imperfect emulations of their C++11 equivalents,
+    // but until there's a requirement, just assume deleters are copyable.
+  }
+
+  template <typename U, typename V>
+  void TakeState(scoped_ptr_impl<U, V>* other) {
+    // See comment in templated constructor above regarding lack of support
+    // for move-only deleters.
+    reset(other->release());
+    get_deleter() = other->get_deleter();
+  }
+
+  ~scoped_ptr_impl() {
+    if (data_.ptr != NULL) {
+      // Not using get_deleter() saves one function call in non-optimized
+      // builds.
+      static_cast<D&>(data_)(data_.ptr);
     }
   }
 
-  T& operator[](std::ptrdiff_t i) const {
-    ASSERT(ptr != NULL);
-    ASSERT(i >= 0);
-    return ptr[i];
+  void reset(T* p) {
+    // This is a self-reset, which is no longer allowed: http://crbug.com/162971
+    if (p != NULL && p == data_.ptr)
+      abort();
+
+    // Note that running data_.ptr = p can lead to undefined behavior if
+    // get_deleter()(get()) deletes this. In order to pevent this, reset()
+    // should update the stored pointer before deleting its old value.
+    //
+    // However, changing reset() to use that behavior may cause current code to
+    // break in unexpected ways. If the destruction of the owned object
+    // dereferences the scoped_ptr when it is destroyed by a call to reset(),
+    // then it will incorrectly dispatch calls to |p| rather than the original
+    // value of |data_.ptr|.
+    //
+    // During the transition period, set the stored pointer to NULL while
+    // deleting the object. Eventually, this safety check will be removed to
+    // prevent the scenario initially described from occuring and
+    // http://crbug.com/176091 can be closed.
+    T* old = data_.ptr;
+    data_.ptr = NULL;
+    if (old != NULL)
+      static_cast<D&>(data_)(old);
+    data_.ptr = p;
   }
 
-  T* get() const {
-    return ptr;
-  }
+  T* get() const { return data_.ptr; }
 
-  void swap(scoped_array & b) {
-    T* tmp = b.ptr;
-    b.ptr = ptr;
-    ptr = tmp;
+  D& get_deleter() { return data_; }
+  const D& get_deleter() const { return data_; }
+
+  void swap(scoped_ptr_impl& p2) {
+    // Standard swap idiom: 'using std::swap' ensures that std::swap is
+    // present in the overload set, but we call swap unqualified so that
+    // any more-specific overloads can be used, if available.
+    using std::swap;
+    swap(static_cast<D&>(data_), static_cast<D&>(p2.data_));
+    swap(data_.ptr, p2.data_.ptr);
   }
 
   T* release() {
-    T* tmp = ptr;
-    ptr = NULL;
-    return tmp;
+    T* old_ptr = data_.ptr;
+    data_.ptr = NULL;
+    return old_ptr;
   }
 
   T** accept() {
-    if (ptr) {
-      delete [] ptr;
-      ptr = NULL;
-    }
-    return &ptr;
+    reset(NULL);
+    return &(data_.ptr);
   }
 
-  // Allow scoped_array<T> to be used in boolean expressions, but not
-  // implicitly convertible to a real bool (which is dangerous).
-  // Borrowed from chromium's scoped_array implementation.
-  typedef T* scoped_array::*Testable;
-  operator Testable() const { return ptr ? &scoped_array::ptr : NULL; }
+  T** use() {
+    return &(data_.ptr);
+  }
+
+ private:
+  // Needed to allow type-converting constructor.
+  template <typename U, typename V> friend class scoped_ptr_impl;
+
+  // Use the empty base class optimization to allow us to have a D
+  // member, while avoiding any space overhead for it when D is an
+  // empty class.  See e.g. http://www.cantrip.org/emptyopt.html for a good
+  // discussion of this technique.
+  struct Data : public D {
+    explicit Data(T* ptr_in) : ptr(ptr_in) {}
+    Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {}
+    T* ptr;
+  };
+
+  Data data_;
+
+  DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl);
 };
 
-template<class T> inline
-void swap(scoped_array<T>& a, scoped_array<T>& b) {
-  a.swap(b);
-}
+}  // namespace internal
 
-// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
-// second template argument, the function used to free the object.
-
-template<typename T, void (*FF)(T*) = free> class scoped_ptr_malloc {
- private:
-
-  T* ptr;
-
-  scoped_ptr_malloc(scoped_ptr_malloc const &);
-  scoped_ptr_malloc & operator=(scoped_ptr_malloc const &);
+// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
+// automatically deletes the pointer it holds (if any).
+// That is, scoped_ptr<T> owns the T object that it points to.
+// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.
+// Also like T*, scoped_ptr<T> is thread-compatible, and once you
+// dereference it, you get the thread safety guarantees of T.
+//
+// The size of scoped_ptr is small. On most compilers, when using the
+// DefaultDeleter, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters will
+// increase the size proportional to whatever state they need to have. See
+// comments inside scoped_ptr_impl<> for details.
+//
+// Current implementation targets having a strict subset of  C++11's
+// unique_ptr<> features. Known deficiencies include not supporting move-only
+// deleteres, function pointers as deleters, and deleters with reference
+// types.
+template <class T, class D = talk_base::DefaultDeleter<T> >
+class scoped_ptr {
+  MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
 
  public:
-
+  // The element and deleter types.
   typedef T element_type;
+  typedef D deleter_type;
 
-  explicit scoped_ptr_malloc(T* p = 0): ptr(p) {}
+  // Constructor.  Defaults to initializing with NULL.
+  scoped_ptr() : impl_(NULL) { }
 
-  ~scoped_ptr_malloc() {
-    FF(ptr);
+  // Constructor.  Takes ownership of p.
+  explicit scoped_ptr(element_type* p) : impl_(p) { }
+
+  // Constructor.  Allows initialization of a stateful deleter.
+  scoped_ptr(element_type* p, const D& d) : impl_(p, d) { }
+
+  // Constructor.  Allows construction from a scoped_ptr rvalue for a
+  // convertible type and deleter.
+  //
+  // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct
+  // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor
+  // has different post-conditions if D is a reference type. Since this
+  // implementation does not support deleters with reference type,
+  // we do not need a separate move constructor allowing us to avoid one
+  // use of SFINAE. You only need to care about this if you modify the
+  // implementation of scoped_ptr.
+  template <typename U, typename V>
+  scoped_ptr(scoped_ptr<U, V> other) : impl_(&other.impl_) {
+    COMPILE_ASSERT(!talk_base::is_array<U>::value, U_cannot_be_an_array);
   }
 
-  void reset(T* p = 0) {
-    if (ptr != p) {
-      FF(ptr);
-      ptr = p;
-    }
+  // Constructor.  Move constructor for C++03 move emulation of this type.
+  scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { }
+
+  // operator=.  Allows assignment from a scoped_ptr rvalue for a convertible
+  // type and deleter.
+  //
+  // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
+  // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated
+  // form has different requirements on for move-only Deleters. Since this
+  // implementation does not support move-only Deleters, we do not need a
+  // separate move assignment operator allowing us to avoid one use of SFINAE.
+  // You only need to care about this if you modify the implementation of
+  // scoped_ptr.
+  template <typename U, typename V>
+  scoped_ptr& operator=(scoped_ptr<U, V> rhs) {
+    COMPILE_ASSERT(!talk_base::is_array<U>::value, U_cannot_be_an_array);
+    impl_.TakeState(&rhs.impl_);
+    return *this;
   }
 
-  T& operator*() const {
-    ASSERT(ptr != 0);
-    return *ptr;
-  }
+  // Reset.  Deletes the currently owned object, if any.
+  // Then takes ownership of a new object, if given.
+  void reset(element_type* p = NULL) { impl_.reset(p); }
 
-  T* operator->() const {
-    ASSERT(ptr != 0);
-    return ptr;
+  // Accessors to get the owned object.
+  // operator* and operator-> will assert() if there is no current object.
+  element_type& operator*() const {
+    ASSERT(impl_.get() != NULL);
+    return *impl_.get();
   }
-
-  T* get() const {
-    return ptr;
+  element_type* operator->() const  {
+    ASSERT(impl_.get() != NULL);
+    return impl_.get();
   }
+  element_type* get() const { return impl_.get(); }
 
-  void swap(scoped_ptr_malloc & b) {
-    T* tmp = b.ptr;
-    b.ptr = ptr;
-    ptr = tmp;
-  }
+  // Access to the deleter.
+  deleter_type& get_deleter() { return impl_.get_deleter(); }
+  const deleter_type& get_deleter() const { return impl_.get_deleter(); }
 
-  T* release() {
-    T* tmp = ptr;
-    ptr = 0;
-    return tmp;
-  }
-
-  T** accept() {
-    if (ptr) {
-      FF(ptr);
-      ptr = 0;
-    }
-    return &ptr;
-  }
-
-  // Allow scoped_ptr_malloc<T> to be used in boolean expressions, but not
+  // Allow scoped_ptr<element_type> to be used in boolean expressions, but not
   // implicitly convertible to a real bool (which is dangerous).
-  // Borrowed from chromium's scoped_ptr_malloc implementation.
-  typedef T* scoped_ptr_malloc::*Testable;
-  operator Testable() const { return ptr ? &scoped_ptr_malloc::ptr : NULL; }
+  //
+  // Note that this trick is only safe when the == and != operators
+  // are declared explicitly, as otherwise "scoped_ptr1 ==
+  // scoped_ptr2" will compile but do the wrong thing (i.e., convert
+  // to Testable and then do the comparison).
+ private:
+  typedef talk_base::internal::scoped_ptr_impl<element_type, deleter_type>
+      scoped_ptr::*Testable;
+
+ public:
+  operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; }
+
+  // Comparison operators.
+  // These return whether two scoped_ptr refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(const element_type* p) const { return impl_.get() == p; }
+  bool operator!=(const element_type* p) const { return impl_.get() != p; }
+
+  // Swap two scoped pointers.
+  void swap(scoped_ptr& p2) {
+    impl_.swap(p2.impl_);
+  }
+
+  // Release a pointer.
+  // The return value is the current pointer held by this object.
+  // If this object holds a NULL pointer, the return value is NULL.
+  // After this operation, this object will hold a NULL pointer,
+  // and will not own the object any more.
+  element_type* release() WARN_UNUSED_RESULT {
+    return impl_.release();
+  }
+
+  // Delete the currently held pointer and return a pointer
+  // to allow overwriting of the current pointer address.
+  element_type** accept() WARN_UNUSED_RESULT {
+    return impl_.accept();
+  }
+
+  // Return a pointer to the current pointer address.
+  element_type** use() WARN_UNUSED_RESULT {
+    return impl_.use();
+  }
+
+  // C++98 doesn't support functions templates with default parameters which
+  // makes it hard to write a PassAs() that understands converting the deleter
+  // while preserving simple calling semantics.
+  //
+  // Until there is a use case for PassAs() with custom deleters, just ignore
+  // the custom deleter.
+  template <typename PassAsType>
+  scoped_ptr<PassAsType> PassAs() {
+    return scoped_ptr<PassAsType>(Pass());
+  }
+
+ private:
+  // Needed to reach into |impl_| in the constructor.
+  template <typename U, typename V> friend class scoped_ptr;
+  talk_base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
+
+  // Forbidden for API compatibility with std::unique_ptr.
+  explicit scoped_ptr(int disallow_construction_from_null);
+
+  // Forbid comparison of scoped_ptr types.  If U != T, it totally
+  // doesn't make sense, and if U == T, it still doesn't make sense
+  // because you should never have the same object owned by two different
+  // scoped_ptrs.
+  template <class U> bool operator==(scoped_ptr<U> const& p2) const;
+  template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
 };
 
-template<typename T, void (*FF)(T*)> inline
-void swap(scoped_ptr_malloc<T,FF>& a, scoped_ptr_malloc<T,FF>& b) {
-  a.swap(b);
+template <class T, class D>
+class scoped_ptr<T[], D> {
+  MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
+
+ public:
+  // The element and deleter types.
+  typedef T element_type;
+  typedef D deleter_type;
+
+  // Constructor.  Defaults to initializing with NULL.
+  scoped_ptr() : impl_(NULL) { }
+
+  // Constructor. Stores the given array. Note that the argument's type
+  // must exactly match T*. In particular:
+  // - it cannot be a pointer to a type derived from T, because it is
+  //   inherently unsafe in the general case to access an array through a
+  //   pointer whose dynamic type does not match its static type (eg., if
+  //   T and the derived types had different sizes access would be
+  //   incorrectly calculated). Deletion is also always undefined
+  //   (C++98 [expr.delete]p3). If you're doing this, fix your code.
+  // - it cannot be NULL, because NULL is an integral expression, not a
+  //   pointer to T. Use the no-argument version instead of explicitly
+  //   passing NULL.
+  // - it cannot be const-qualified differently from T per unique_ptr spec
+  //   (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting
+  //   to work around this may use implicit_cast<const T*>().
+  //   However, because of the first bullet in this comment, users MUST
+  //   NOT use implicit_cast<Base*>() to upcast the static type of the array.
+  explicit scoped_ptr(element_type* array) : impl_(array) { }
+
+  // Constructor.  Move constructor for C++03 move emulation of this type.
+  scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { }
+
+  // operator=.  Move operator= for C++03 move emulation of this type.
+  scoped_ptr& operator=(RValue rhs) {
+    impl_.TakeState(&rhs.object->impl_);
+    return *this;
+  }
+
+  // Reset.  Deletes the currently owned array, if any.
+  // Then takes ownership of a new object, if given.
+  void reset(element_type* array = NULL) { impl_.reset(array); }
+
+  // Accessors to get the owned array.
+  element_type& operator[](size_t i) const {
+    ASSERT(impl_.get() != NULL);
+    return impl_.get()[i];
+  }
+  element_type* get() const { return impl_.get(); }
+
+  // Access to the deleter.
+  deleter_type& get_deleter() { return impl_.get_deleter(); }
+  const deleter_type& get_deleter() const { return impl_.get_deleter(); }
+
+  // Allow scoped_ptr<element_type> to be used in boolean expressions, but not
+  // implicitly convertible to a real bool (which is dangerous).
+ private:
+  typedef talk_base::internal::scoped_ptr_impl<element_type, deleter_type>
+      scoped_ptr::*Testable;
+
+ public:
+  operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; }
+
+  // Comparison operators.
+  // These return whether two scoped_ptr refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(element_type* array) const { return impl_.get() == array; }
+  bool operator!=(element_type* array) const { return impl_.get() != array; }
+
+  // Swap two scoped pointers.
+  void swap(scoped_ptr& p2) {
+    impl_.swap(p2.impl_);
+  }
+
+  // Release a pointer.
+  // The return value is the current pointer held by this object.
+  // If this object holds a NULL pointer, the return value is NULL.
+  // After this operation, this object will hold a NULL pointer,
+  // and will not own the object any more.
+  element_type* release() WARN_UNUSED_RESULT {
+    return impl_.release();
+  }
+
+  // Delete the currently held pointer and return a pointer
+  // to allow overwriting of the current pointer address.
+  element_type** accept() WARN_UNUSED_RESULT {
+    return impl_.accept();
+  }
+
+  // Return a pointer to the current pointer address.
+  element_type** use() WARN_UNUSED_RESULT {
+    return impl_.use();
+  }
+
+ private:
+  // Force element_type to be a complete type.
+  enum { type_must_be_complete = sizeof(element_type) };
+
+  // Actually hold the data.
+  talk_base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
+
+  // Disable initialization from any type other than element_type*, by
+  // providing a constructor that matches such an initialization, but is
+  // private and has no definition. This is disabled because it is not safe to
+  // call delete[] on an array whose static type does not match its dynamic
+  // type.
+  template <typename U> explicit scoped_ptr(U* array);
+  explicit scoped_ptr(int disallow_construction_from_null);
+
+  // Disable reset() from any type other than element_type*, for the same
+  // reasons as the constructor above.
+  template <typename U> void reset(U* array);
+  void reset(int disallow_reset_from_null);
+
+  // Forbid comparison of scoped_ptr types.  If U != T, it totally
+  // doesn't make sense, and if U == T, it still doesn't make sense
+  // because you should never have the same object owned by two different
+  // scoped_ptrs.
+  template <class U> bool operator==(scoped_ptr<U> const& p2) const;
+  template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
+};
+
+}  // namespace talk_base
+
+// Free functions
+template <class T, class D>
+void swap(talk_base::scoped_ptr<T, D>& p1, talk_base::scoped_ptr<T, D>& p2) {
+  p1.swap(p2);
 }
 
-} // namespace talk_base
+template <class T, class D>
+bool operator==(T* p1, const talk_base::scoped_ptr<T, D>& p2) {
+  return p1 == p2.get();
+}
+
+template <class T, class D>
+bool operator!=(T* p1, const talk_base::scoped_ptr<T, D>& p2) {
+  return p1 != p2.get();
+}
+
+// A function to convert T* into talk_base::scoped_ptr<T>
+// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for talk_base::scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+talk_base::scoped_ptr<T> make_scoped_ptr(T* ptr) {
+  return talk_base::scoped_ptr<T>(ptr);
+}
 
 #endif  // #ifndef TALK_BASE_SCOPED_PTR_H__
diff --git a/talk/base/socket_unittest.cc b/talk/base/socket_unittest.cc
index eafab81..a9c4dbb 100644
--- a/talk/base/socket_unittest.cc
+++ b/talk/base/socket_unittest.cc
@@ -693,8 +693,8 @@
 
   // Create test data.
   const size_t kDataSize = 1024 * 1024;
-  scoped_array<char> send_buffer(new char[kDataSize]);
-  scoped_array<char> recv_buffer(new char[kDataSize]);
+  scoped_ptr<char[]> send_buffer(new char[kDataSize]);
+  scoped_ptr<char[]> recv_buffer(new char[kDataSize]);
   size_t send_pos = 0, recv_pos = 0;
   for (size_t i = 0; i < kDataSize; ++i) {
     send_buffer[i] = static_cast<char>(i % 256);
@@ -934,7 +934,7 @@
   scoped_ptr<TestClient> client(
       new TestClient(AsyncUDPSocket::Create(ss_, empty)));
   int test_packet_size = 1200;
-  talk_base::scoped_array<char> test_packet(new char[test_packet_size]);
+  talk_base::scoped_ptr<char[]> test_packet(new char[test_packet_size]);
   // Init the test packet just to avoid memcheck warning.
   memset(test_packet.get(), 0, test_packet_size);
   // Set the send buffer size to the same size as the test packet to have a
diff --git a/talk/base/sslidentity_unittest.cc b/talk/base/sslidentity_unittest.cc
index e425df2..b63b8b9 100644
--- a/talk/base/sslidentity_unittest.cc
+++ b/talk/base/sslidentity_unittest.cc
@@ -57,7 +57,7 @@
 class SSLIdentityTest : public testing::Test {
  public:
   SSLIdentityTest() :
-      identity1_(NULL), identity2_(NULL) {
+      identity1_(), identity2_() {
   }
 
   ~SSLIdentityTest() {
diff --git a/talk/base/stream.cc b/talk/base/stream.cc
index 996908d..c1cf907 100644
--- a/talk/base/stream.cc
+++ b/talk/base/stream.cc
@@ -166,7 +166,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 StreamTap::StreamTap(StreamInterface* stream, StreamInterface* tap)
-    : StreamAdapterInterface(stream), tap_(NULL), tap_result_(SR_SUCCESS),
+    : StreamAdapterInterface(stream), tap_(), tap_result_(SR_SUCCESS),
         tap_error_(0) {
   AttachTap(tap);
 }
diff --git a/talk/base/stream.h b/talk/base/stream.h
index 457396c..4571def 100644
--- a/talk/base/stream.h
+++ b/talk/base/stream.h
@@ -691,7 +691,7 @@
                                  size_t offset, size_t* bytes_written);
 
   StreamState state_;  // keeps the opened/closed state of the stream
-  scoped_array<char> buffer_;  // the allocated buffer
+  scoped_ptr<char[]> buffer_;  // the allocated buffer
   size_t buffer_length_;  // size of the allocated buffer
   size_t data_length_;  // amount of readable data in the buffer
   size_t read_position_;  // offset to the readable data
diff --git a/talk/base/systeminfo.cc b/talk/base/systeminfo.cc
index ec18658..ff331ac 100644
--- a/talk/base/systeminfo.cc
+++ b/talk/base/systeminfo.cc
@@ -74,7 +74,7 @@
   // Determine buffer size, allocate and get processor information.
   // Size can change between calls (unlikely), so a loop is done.
   DWORD return_length = 0;
-  scoped_array<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> infos;
+  scoped_ptr<SYSTEM_LOGICAL_PROCESSOR_INFORMATION[]> infos;
   while (!glpi(infos.get(), &return_length)) {
     if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
       infos.reset(new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[
@@ -183,6 +183,8 @@
   if (!sysctlbyname("machdep.cpu.stepping", &sysctl_value, &length, NULL, 0)) {
     cpu_stepping_ = static_cast<int>(sysctl_value);
   }
+#elif defined(__native_client__)
+  // TODO(ryanpetrie): Implement this via PPAPI when it's available.
 #else  // LINUX || ANDROID
   ProcCpuInfo proc_info;
   if (proc_info.LoadFromSystem()) {
diff --git a/talk/base/template_util.h b/talk/base/template_util.h
new file mode 100644
index 0000000..5cc4ba4
--- /dev/null
+++ b/talk/base/template_util.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TALK_BASE_TEMPLATE_UTIL_H_
+#define TALK_BASE_TEMPLATE_UTIL_H_
+
+#include <cstddef>  // For size_t.
+
+namespace talk_base {
+
+// template definitions from tr1
+
+template<class T, T v>
+struct integral_constant {
+  static const T value = v;
+  typedef T value_type;
+  typedef integral_constant<T, v> type;
+};
+
+template <class T, T v> const T integral_constant<T, v>::value;
+
+typedef integral_constant<bool, true> true_type;
+typedef integral_constant<bool, false> false_type;
+
+template <class T> struct is_pointer : false_type {};
+template <class T> struct is_pointer<T*> : true_type {};
+
+template <class T, class U> struct is_same : public false_type {};
+template <class T> struct is_same<T,T> : true_type {};
+
+template<class> struct is_array : public false_type {};
+template<class T, size_t n> struct is_array<T[n]> : public true_type {};
+template<class T> struct is_array<T[]> : public true_type {};
+
+template <class T> struct is_non_const_reference : false_type {};
+template <class T> struct is_non_const_reference<T&> : true_type {};
+template <class T> struct is_non_const_reference<const T&> : false_type {};
+
+template <class T> struct is_void : false_type {};
+template <> struct is_void<void> : true_type {};
+
+namespace internal {
+
+// Types YesType and NoType are guaranteed such that sizeof(YesType) <
+// sizeof(NoType).
+typedef char YesType;
+
+struct NoType {
+  YesType dummy[2];
+};
+
+// This class is an implementation detail for is_convertible, and you
+// don't need to know how it works to use is_convertible. For those
+// who care: we declare two different functions, one whose argument is
+// of type To and one with a variadic argument list. We give them
+// return types of different size, so we can use sizeof to trick the
+// compiler into telling us which function it would have chosen if we
+// had called it with an argument of type From.  See Alexandrescu's
+// _Modern C++ Design_ for more details on this sort of trick.
+
+struct ConvertHelper {
+  template <typename To>
+  static YesType Test(To);
+
+  template <typename To>
+  static NoType Test(...);
+
+  template <typename From>
+  static From& Create();
+};
+
+// Used to determine if a type is a struct/union/class. Inspired by Boost's
+// is_class type_trait implementation.
+struct IsClassHelper {
+  template <typename C>
+  static YesType Test(void(C::*)(void));
+
+  template <typename C>
+  static NoType Test(...);
+};
+
+}  // namespace internal
+
+// Inherits from true_type if From is convertible to To, false_type otherwise.
+//
+// Note that if the type is convertible, this will be a true_type REGARDLESS
+// of whether or not the conversion would emit a warning.
+template <typename From, typename To>
+struct is_convertible
+    : integral_constant<bool,
+                        sizeof(internal::ConvertHelper::Test<To>(
+                                   internal::ConvertHelper::Create<From>())) ==
+                        sizeof(internal::YesType)> {
+};
+
+template <typename T>
+struct is_class
+    : integral_constant<bool,
+                        sizeof(internal::IsClassHelper::Test<T>(0)) ==
+                            sizeof(internal::YesType)> {
+};
+
+}  // namespace talk_base
+
+#endif  // TALK_BASE_TEMPLATE_UTIL_H_
diff --git a/talk/base/win32filesystem.cc b/talk/base/win32filesystem.cc
index 42c0388..5caeac2 100644
--- a/talk/base/win32filesystem.cc
+++ b/talk/base/win32filesystem.cc
@@ -111,7 +111,7 @@
                               &token_user_size);
 
   // Get the TOKEN_USER structure.
-  scoped_array<char> token_user_bytes(new char[token_user_size]);
+  scoped_ptr<char[]> token_user_bytes(new char[token_user_size]);
   PTOKEN_USER token_user = reinterpret_cast<PTOKEN_USER>(
       token_user_bytes.get());
   memset(token_user, 0, token_user_size);
@@ -137,7 +137,7 @@
       GetLengthSid(token_user->User.Sid);
 
   // Allocate it.
-  scoped_array<char> acl_bytes(new char[acl_size]);
+  scoped_ptr<char[]> acl_bytes(new char[acl_size]);
   PACL acl = reinterpret_cast<PACL>(acl_bytes.get());
   memset(acl, 0, acl_size);
   if (!::InitializeAcl(acl, acl_size, ACL_REVISION)) {
@@ -440,7 +440,7 @@
 Pathname Win32Filesystem::GetCurrentDirectory() {
   Pathname cwd;
   int path_len = 0;
-  scoped_array<wchar_t> path;
+  scoped_ptr<wchar_t[]> path;
   do {
     int needed = ::GetCurrentDirectory(path_len, path.get());
     if (needed == 0) {
diff --git a/talk/base/win32regkey.cc b/talk/base/win32regkey.cc
index cb98caf..403fdc0 100644
--- a/talk/base/win32regkey.cc
+++ b/talk/base/win32regkey.cc
@@ -160,7 +160,7 @@
   ASSERT(full_key_name != NULL);
 
   DWORD byte_count = 0;
-  scoped_array<byte> buffer;
+  scoped_ptr<byte[]> buffer;
   HRESULT hr = GetValueStaticHelper(full_key_name, value_name,
                                     REG_BINARY, buffer.accept(), &byte_count);
   if (SUCCEEDED(hr)) {
@@ -179,7 +179,7 @@
   ASSERT(full_key_name != NULL);
 
   DWORD byte_count = 0;
-  scoped_array<byte> buffer;
+  scoped_ptr<byte[]> buffer;
   HRESULT hr = GetValueStaticHelper(full_key_name, value_name,
                                     REG_BINARY, buffer.accept(), &byte_count);
   if (SUCCEEDED(hr)) {
@@ -206,7 +206,7 @@
   ASSERT(full_key_name != NULL);
   ASSERT(value != NULL);
 
-  scoped_array<wchar_t> buffer;
+  scoped_ptr<wchar_t[]> buffer;
   HRESULT hr = RegKey::GetValue(full_key_name, value_name, buffer.accept());
   if (SUCCEEDED(hr)) {
     value->assign(buffer.get());
diff --git a/talk/base/win32socketserver.cc b/talk/base/win32socketserver.cc
index 55128e7..9566669 100644
--- a/talk/base/win32socketserver.cc
+++ b/talk/base/win32socketserver.cc
@@ -620,6 +620,9 @@
       *slevel = IPPROTO_TCP;
       *sopt = TCP_NODELAY;
       break;
+    case OPT_DSCP:
+      LOG(LS_WARNING) << "Socket::OPT_DSCP not supported.";
+      return -1;
     default:
       ASSERT(false);
       return -1;
diff --git a/talk/examples/call/callclient.cc b/talk/examples/call/callclient.cc
index 66c4b6f..afbdd29 100644
--- a/talk/examples/call/callclient.cc
+++ b/talk/examples/call/callclient.cc
@@ -396,7 +396,7 @@
       transport_protocol_(cricket::ICEPROTO_HYBRID),
       sdes_policy_(cricket::SEC_DISABLED),
       dtls_policy_(cricket::SEC_DISABLED),
-      ssl_identity_(NULL),
+      ssl_identity_(),
       show_roster_messages_(false) {
   xmpp_client_->SignalStateChange.connect(this, &CallClient::OnStateChange);
   my_status_.set_caps_node(caps_node);
diff --git a/talk/examples/chat/chatapp.cc b/talk/examples/chat/chatapp.cc
index 1b59910..59b1c69 100644
--- a/talk/examples/chat/chatapp.cc
+++ b/talk/examples/chat/chatapp.cc
@@ -38,10 +38,10 @@
 
 ChatApp::ChatApp(buzz::XmppClient* xmpp_client, talk_base::Thread* main_thread)
   : xmpp_client_(xmpp_client),
-    presence_out_task_(NULL),
-    presence_receive_task_(NULL),
-    message_send_task_(NULL),
-    message_received_task_(NULL),
+    presence_out_task_(),
+    presence_receive_task_(),
+    message_send_task_(),
+    message_received_task_(),
     console_task_(new buzz::ConsoleTask(main_thread)),
     ui_state_(STATE_BASE) {
   xmpp_client_->SignalStateChange.connect(this, &ChatApp::OnStateChange);
diff --git a/talk/examples/peerconnection/client/linux/main_wnd.h b/talk/examples/peerconnection/client/linux/main_wnd.h
index c23c116..5a44640 100644
--- a/talk/examples/peerconnection/client/linux/main_wnd.h
+++ b/talk/examples/peerconnection/client/linux/main_wnd.h
@@ -110,7 +110,7 @@
     }
 
    protected:
-    talk_base::scoped_array<uint8> image_;
+    talk_base::scoped_ptr<uint8[]> image_;
     int width_;
     int height_;
     GtkMainWnd* main_wnd_;
diff --git a/talk/examples/peerconnection/client/main_wnd.h b/talk/examples/peerconnection/client/main_wnd.h
index 0ed0f14..6d2bf3e 100644
--- a/talk/examples/peerconnection/client/main_wnd.h
+++ b/talk/examples/peerconnection/client/main_wnd.h
@@ -147,7 +147,7 @@
 
     HWND wnd_;
     BITMAPINFO bmi_;
-    talk_base::scoped_array<uint8> image_;
+    talk_base::scoped_ptr<uint8[]> image_;
     CRITICAL_SECTION buffer_lock_;
     talk_base::scoped_refptr<webrtc::VideoTrackInterface> rendered_track_;
   };
diff --git a/talk/media/base/cpuid.cc b/talk/media/base/cpuid.cc
index 9fd7865..bd87d2e 100644
--- a/talk/media/base/cpuid.cc
+++ b/talk/media/base/cpuid.cc
@@ -51,8 +51,8 @@
 bool IsCoreIOrBetter() {
 #if !defined(DISABLE_YUV) && (defined(__i386__) || defined(__x86_64__) || \
     defined(_M_IX86) || defined(_M_X64))
-  int cpu_info[4];
-  libyuv::CpuId(cpu_info, 0);  // Function 0: Vendor ID
+  uint32 cpu_info[4];
+  libyuv::CpuId(0, 0, &cpu_info[0]);  // Function 0: Vendor ID
   if (cpu_info[1] == 0x756e6547 && cpu_info[3] == 0x49656e69 &&
       cpu_info[2] == 0x6c65746e) {  // GenuineIntel
     // Detect CPU Family and Model
@@ -62,7 +62,7 @@
     // 13:12 - Processor Type
     // 19:16 - Extended Model
     // 27:20 - Extended Family
-    libyuv::CpuId(cpu_info, 1);  // Function 1: Family and Model
+    libyuv::CpuId(1, 0, &cpu_info[0]);  // Function 1: Family and Model
     int family = ((cpu_info[0] >> 8) & 0x0f) | ((cpu_info[0] >> 16) & 0xff0);
     int model = ((cpu_info[0] >> 4) & 0x0f) | ((cpu_info[0] >> 12) & 0xf0);
     // CpuFamily | CpuModel |  Name
diff --git a/talk/media/base/fakevideocapturer.h b/talk/media/base/fakevideocapturer.h
index 5a33265..8dc69c3 100644
--- a/talk/media/base/fakevideocapturer.h
+++ b/talk/media/base/fakevideocapturer.h
@@ -101,7 +101,7 @@
     frame.time_stamp = initial_unix_timestamp_ + next_timestamp_;
     next_timestamp_ += 33333333;  // 30 fps
 
-    talk_base::scoped_array<char> data(new char[size]);
+    talk_base::scoped_ptr<char[]> data(new char[size]);
     frame.data = data.get();
     // Copy something non-zero into the buffer so Validate wont complain that
     // the frame is all duplicate.
diff --git a/talk/media/base/mediachannel.h b/talk/media/base/mediachannel.h
index f90265c..3dc9c56 100644
--- a/talk/media/base/mediachannel.h
+++ b/talk/media/base/mediachannel.h
@@ -162,29 +162,51 @@
   void SetAll(const AudioOptions& change) {
     echo_cancellation.SetFrom(change.echo_cancellation);
     auto_gain_control.SetFrom(change.auto_gain_control);
+    rx_auto_gain_control.SetFrom(change.rx_auto_gain_control);
     noise_suppression.SetFrom(change.noise_suppression);
     highpass_filter.SetFrom(change.highpass_filter);
     stereo_swapping.SetFrom(change.stereo_swapping);
     typing_detection.SetFrom(change.typing_detection);
+    aecm_generate_comfort_noise.SetFrom(change.aecm_generate_comfort_noise);
     conference_mode.SetFrom(change.conference_mode);
     adjust_agc_delta.SetFrom(change.adjust_agc_delta);
     experimental_agc.SetFrom(change.experimental_agc);
     experimental_aec.SetFrom(change.experimental_aec);
     aec_dump.SetFrom(change.aec_dump);
+    tx_agc_target_dbov.SetFrom(change.tx_agc_target_dbov);
+    tx_agc_digital_compression_gain.SetFrom(
+        change.tx_agc_digital_compression_gain);
+    tx_agc_limiter.SetFrom(change.tx_agc_limiter);
+    rx_agc_target_dbov.SetFrom(change.rx_agc_target_dbov);
+    rx_agc_digital_compression_gain.SetFrom(
+        change.rx_agc_digital_compression_gain);
+    rx_agc_limiter.SetFrom(change.rx_agc_limiter);
+    recording_sample_rate.SetFrom(change.recording_sample_rate);
+    playout_sample_rate.SetFrom(change.playout_sample_rate);
   }
 
   bool operator==(const AudioOptions& o) const {
     return echo_cancellation == o.echo_cancellation &&
         auto_gain_control == o.auto_gain_control &&
+        rx_auto_gain_control == o.rx_auto_gain_control &&
         noise_suppression == o.noise_suppression &&
         highpass_filter == o.highpass_filter &&
         stereo_swapping == o.stereo_swapping &&
         typing_detection == o.typing_detection &&
+        aecm_generate_comfort_noise == o.aecm_generate_comfort_noise &&
         conference_mode == o.conference_mode &&
         experimental_agc == o.experimental_agc &&
         experimental_aec == o.experimental_aec &&
         adjust_agc_delta == o.adjust_agc_delta &&
-        aec_dump == o.aec_dump;
+        aec_dump == o.aec_dump &&
+        tx_agc_target_dbov == o.tx_agc_target_dbov &&
+        tx_agc_digital_compression_gain == o.tx_agc_digital_compression_gain &&
+        tx_agc_limiter == o.tx_agc_limiter &&
+        rx_agc_target_dbov == o.rx_agc_target_dbov &&
+        rx_agc_digital_compression_gain == o.rx_agc_digital_compression_gain &&
+        rx_agc_limiter == o.rx_agc_limiter &&
+        recording_sample_rate == o.recording_sample_rate &&
+        playout_sample_rate == o.playout_sample_rate;
   }
 
   std::string ToString() const {
@@ -192,15 +214,27 @@
     ost << "AudioOptions {";
     ost << ToStringIfSet("aec", echo_cancellation);
     ost << ToStringIfSet("agc", auto_gain_control);
+    ost << ToStringIfSet("rx_agc", rx_auto_gain_control);
     ost << ToStringIfSet("ns", noise_suppression);
     ost << ToStringIfSet("hf", highpass_filter);
     ost << ToStringIfSet("swap", stereo_swapping);
     ost << ToStringIfSet("typing", typing_detection);
+    ost << ToStringIfSet("comfort_noise", aecm_generate_comfort_noise);
     ost << ToStringIfSet("conference", conference_mode);
     ost << ToStringIfSet("agc_delta", adjust_agc_delta);
     ost << ToStringIfSet("experimental_agc", experimental_agc);
     ost << ToStringIfSet("experimental_aec", experimental_aec);
     ost << ToStringIfSet("aec_dump", aec_dump);
+    ost << ToStringIfSet("tx_agc_target_dbov", tx_agc_target_dbov);
+    ost << ToStringIfSet("tx_agc_digital_compression_gain",
+        tx_agc_digital_compression_gain);
+    ost << ToStringIfSet("tx_agc_limiter", tx_agc_limiter);
+    ost << ToStringIfSet("rx_agc_target_dbov", rx_agc_target_dbov);
+    ost << ToStringIfSet("rx_agc_digital_compression_gain",
+        rx_agc_digital_compression_gain);
+    ost << ToStringIfSet("rx_agc_limiter", rx_agc_limiter);
+    ost << ToStringIfSet("recording_sample_rate", recording_sample_rate);
+    ost << ToStringIfSet("playout_sample_rate", playout_sample_rate);
     ost << "}";
     return ost.str();
   }
@@ -210,6 +244,8 @@
   Settable<bool> echo_cancellation;
   // Audio processing to adjust the sensitivity of the local mic dynamically.
   Settable<bool> auto_gain_control;
+  // Audio processing to apply gain to the remote audio.
+  Settable<bool> rx_auto_gain_control;
   // Audio processing to filter out background noise.
   Settable<bool> noise_suppression;
   // Audio processing to remove background noise of lower frequencies.
@@ -218,11 +254,21 @@
   Settable<bool> stereo_swapping;
   // Audio processing to detect typing.
   Settable<bool> typing_detection;
+  Settable<bool> aecm_generate_comfort_noise;
   Settable<bool> conference_mode;
   Settable<int> adjust_agc_delta;
   Settable<bool> experimental_agc;
   Settable<bool> experimental_aec;
   Settable<bool> aec_dump;
+  // Note that tx_agc_* only applies to non-experimental AGC.
+  Settable<uint16> tx_agc_target_dbov;
+  Settable<uint16> tx_agc_digital_compression_gain;
+  Settable<bool> tx_agc_limiter;
+  Settable<uint16> rx_agc_target_dbov;
+  Settable<uint16> rx_agc_digital_compression_gain;
+  Settable<bool> rx_agc_limiter;
+  Settable<uint32> recording_sample_rate;
+  Settable<uint32> playout_sample_rate;
 };
 
 // Options that can be applied to a VideoMediaChannel or a VideoMediaEngine.
@@ -244,12 +290,13 @@
     video_adapt_third.SetFrom(change.video_adapt_third);
     video_noise_reduction.SetFrom(change.video_noise_reduction);
     video_three_layers.SetFrom(change.video_three_layers);
-    video_enable_camera_list.SetFrom(change.video_enable_camera_list);
     video_one_layer_screencast.SetFrom(change.video_one_layer_screencast);
     video_high_bitrate.SetFrom(change.video_high_bitrate);
     video_watermark.SetFrom(change.video_watermark);
     video_temporal_layer_screencast.SetFrom(
         change.video_temporal_layer_screencast);
+    video_temporal_layer_realtime.SetFrom(
+        change.video_temporal_layer_realtime);
     video_leaky_bucket.SetFrom(change.video_leaky_bucket);
     cpu_overuse_detection.SetFrom(change.cpu_overuse_detection);
     conference_mode.SetFrom(change.conference_mode);
@@ -269,11 +316,11 @@
         video_adapt_third == o.video_adapt_third &&
         video_noise_reduction == o.video_noise_reduction &&
         video_three_layers == o.video_three_layers &&
-        video_enable_camera_list == o.video_enable_camera_list &&
         video_one_layer_screencast == o.video_one_layer_screencast &&
         video_high_bitrate == o.video_high_bitrate &&
         video_watermark == o.video_watermark &&
         video_temporal_layer_screencast == o.video_temporal_layer_screencast &&
+        video_temporal_layer_realtime == o.video_temporal_layer_realtime &&
         video_leaky_bucket == o.video_leaky_bucket &&
         cpu_overuse_detection == o.cpu_overuse_detection &&
         conference_mode == o.conference_mode &&
@@ -295,12 +342,13 @@
     ost << ToStringIfSet("video adapt third", video_adapt_third);
     ost << ToStringIfSet("noise reduction", video_noise_reduction);
     ost << ToStringIfSet("3 layers", video_three_layers);
-    ost << ToStringIfSet("camera list", video_enable_camera_list);
     ost << ToStringIfSet("1 layer screencast", video_one_layer_screencast);
     ost << ToStringIfSet("high bitrate", video_high_bitrate);
     ost << ToStringIfSet("watermark", video_watermark);
     ost << ToStringIfSet("video temporal layer screencast",
                          video_temporal_layer_screencast);
+    ost << ToStringIfSet("video temporal layer realtime",
+                         video_temporal_layer_realtime);
     ost << ToStringIfSet("leaky bucket", video_leaky_bucket);
     ost << ToStringIfSet("cpu overuse detection", cpu_overuse_detection);
     ost << ToStringIfSet("conference mode", conference_mode);
@@ -326,8 +374,6 @@
   Settable<bool> video_noise_reduction;
   // Experimental: Enable multi layer?
   Settable<bool> video_three_layers;
-  // Experimental: Enable camera list?
-  Settable<bool> video_enable_camera_list;
   // Experimental: Enable one layer screencast?
   Settable<bool> video_one_layer_screencast;
   // Experimental: Enable WebRtc higher bitrate?
@@ -336,6 +382,8 @@
   Settable<bool> video_watermark;
   // Experimental: Enable WebRTC layered screencast.
   Settable<bool> video_temporal_layer_screencast;
+  // Experimental: Enable WebRTC temporal layer strategy for realtime video.
+  Settable<bool> video_temporal_layer_realtime;
   // Enable WebRTC leaky bucket when sending media packets.
   Settable<bool> video_leaky_bucket;
   // Enable WebRTC Cpu Overuse Detection, which is a new version of the CPU
@@ -513,15 +561,68 @@
   SEND_MICROPHONE
 };
 
-struct VoiceSenderInfo {
-  VoiceSenderInfo()
+// The stats information is structured as follows:
+// Media are represented by either MediaSenderInfo or MediaReceiverInfo.
+// Media contains a vector of SSRC infos that are exclusively used by this
+// media. (SSRCs shared between media streams can't be represented.)
+
+// Information about an SSRC.
+// This data may be locally recorded, or received in an RTCP SR or RR.
+struct SsrcSenderInfo {
+  SsrcSenderInfo()
       : ssrc(0),
-        bytes_sent(0),
+    timestamp(0) {
+  }
+  uint32 ssrc;
+  double timestamp;  // NTP timestamp, represented as seconds since epoch.
+};
+
+struct SsrcReceiverInfo {
+  SsrcReceiverInfo()
+      : ssrc(0),
+        timestamp(0) {
+  }
+  uint32 ssrc;
+  double timestamp;
+};
+
+struct MediaSenderInfo {
+  MediaSenderInfo()
+      : bytes_sent(0),
         packets_sent(0),
         packets_lost(0),
         fraction_lost(0.0),
+        rtt_ms(0) {
+  }
+  int64 bytes_sent;
+  int packets_sent;
+  int packets_lost;
+  float fraction_lost;
+  int rtt_ms;
+  std::string codec_name;
+  std::vector<SsrcSenderInfo> local_stats;
+  std::vector<SsrcReceiverInfo> remote_stats;
+};
+
+struct MediaReceiverInfo {
+  MediaReceiverInfo()
+      : bytes_rcvd(0),
+        packets_rcvd(0),
+        packets_lost(0),
+        fraction_lost(0.0) {
+  }
+  int64 bytes_rcvd;
+  int packets_rcvd;
+  int packets_lost;
+  float fraction_lost;
+  std::vector<SsrcReceiverInfo> local_stats;
+  std::vector<SsrcSenderInfo> remote_stats;
+};
+
+struct VoiceSenderInfo : public MediaSenderInfo {
+  VoiceSenderInfo()
+      : ssrc(0),
         ext_seqnum(0),
-        rtt_ms(0),
         jitter_ms(0),
         audio_level(0),
         aec_quality_min(0.0),
@@ -533,13 +634,7 @@
   }
 
   uint32 ssrc;
-  std::string codec_name;
-  int64 bytes_sent;
-  int packets_sent;
-  int packets_lost;
-  float fraction_lost;
   int ext_seqnum;
-  int rtt_ms;
   int jitter_ms;
   int audio_level;
   float aec_quality_min;
@@ -550,13 +645,9 @@
   bool typing_noise_detected;
 };
 
-struct VoiceReceiverInfo {
+struct VoiceReceiverInfo : public MediaReceiverInfo {
   VoiceReceiverInfo()
       : ssrc(0),
-        bytes_rcvd(0),
-        packets_rcvd(0),
-        packets_lost(0),
-        fraction_lost(0.0),
         ext_seqnum(0),
         jitter_ms(0),
         jitter_buffer_ms(0),
@@ -567,10 +658,6 @@
   }
 
   uint32 ssrc;
-  int64 bytes_rcvd;
-  int packets_rcvd;
-  int packets_lost;
-  float fraction_lost;
   int ext_seqnum;
   int jitter_ms;
   int jitter_buffer_ms;
@@ -581,16 +668,11 @@
   float expand_rate;
 };
 
-struct VideoSenderInfo {
+struct VideoSenderInfo : public MediaSenderInfo {
   VideoSenderInfo()
-      : bytes_sent(0),
-        packets_sent(0),
-        packets_cached(0),
-        packets_lost(0),
-        fraction_lost(0.0),
+      : packets_cached(0),
         firs_rcvd(0),
         nacks_rcvd(0),
-        rtt_ms(0),
         frame_width(0),
         frame_height(0),
         framerate_input(0),
@@ -602,15 +684,9 @@
 
   std::vector<uint32> ssrcs;
   std::vector<SsrcGroup> ssrc_groups;
-  std::string codec_name;
-  int64 bytes_sent;
-  int packets_sent;
   int packets_cached;
-  int packets_lost;
-  float fraction_lost;
   int firs_rcvd;
   int nacks_rcvd;
-  int rtt_ms;
   int frame_width;
   int frame_height;
   int framerate_input;
@@ -620,13 +696,9 @@
   int adapt_reason;
 };
 
-struct VideoReceiverInfo {
+struct VideoReceiverInfo : public MediaReceiverInfo {
   VideoReceiverInfo()
-      : bytes_rcvd(0),
-        packets_rcvd(0),
-        packets_lost(0),
-        packets_concealed(0),
-        fraction_lost(0.0),
+      : packets_concealed(0),
         firs_sent(0),
         nacks_sent(0),
         frame_width(0),
@@ -635,17 +707,19 @@
         framerate_decoded(0),
         framerate_output(0),
         framerate_render_input(0),
-        framerate_render_output(0) {
+        framerate_render_output(0),
+        decode_ms(0),
+        max_decode_ms(0),
+        jitter_buffer_ms(0),
+        min_playout_delay_ms(0),
+        render_delay_ms(0),
+        target_delay_ms(0),
+        current_delay_ms(0) {
   }
 
   std::vector<uint32> ssrcs;
   std::vector<SsrcGroup> ssrc_groups;
-  int64 bytes_rcvd;
-  // vector<int> layer_bytes_rcvd;
-  int packets_rcvd;
-  int packets_lost;
   int packets_concealed;
-  float fraction_lost;
   int firs_sent;
   int nacks_sent;
   int frame_width;
@@ -657,31 +731,42 @@
   int framerate_render_input;
   // Framerate that the renderer reports.
   int framerate_render_output;
+
+  // All stats below are gathered per-VideoReceiver, but some will be correlated
+  // across MediaStreamTracks.  NOTE(hta): when sinking stats into per-SSRC
+  // structures, reflect this in the new layout.
+
+  // Current frame decode latency.
+  int decode_ms;
+  // Maximum observed frame decode latency.
+  int max_decode_ms;
+  // Jitter (network-related) latency.
+  int jitter_buffer_ms;
+  // Requested minimum playout latency.
+  int min_playout_delay_ms;
+  // Requested latency to account for rendering delay.
+  int render_delay_ms;
+  // Target overall delay: network+decode+render, accounting for
+  // min_playout_delay_ms.
+  int target_delay_ms;
+  // Current overall delay, possibly ramping towards target_delay_ms.
+  int current_delay_ms;
 };
 
-struct DataSenderInfo {
+struct DataSenderInfo : public MediaSenderInfo {
   DataSenderInfo()
-      : ssrc(0),
-        bytes_sent(0),
-        packets_sent(0) {
+      : ssrc(0) {
   }
 
   uint32 ssrc;
-  std::string codec_name;
-  int64 bytes_sent;
-  int packets_sent;
 };
 
-struct DataReceiverInfo {
+struct DataReceiverInfo : public MediaReceiverInfo {
   DataReceiverInfo()
-      : ssrc(0),
-        bytes_rcvd(0),
-        packets_rcvd(0) {
+      : ssrc(0) {
   }
 
   uint32 ssrc;
-  int64 bytes_rcvd;
-  int packets_rcvd;
 };
 
 struct BandwidthEstimationInfo {
diff --git a/talk/media/base/videocapturer.cc b/talk/media/base/videocapturer.cc
index acab19d..900a6f1 100644
--- a/talk/media/base/videocapturer.cc
+++ b/talk/media/base/videocapturer.cc
@@ -373,7 +373,7 @@
   // TODO(fbarchard): Avoid scale and convert if muted.
   // Temporary buffer is scoped here so it will persist until i420_frame.Init()
   // makes a copy of the frame, converting to I420.
-  talk_base::scoped_array<uint8> temp_buffer;
+  talk_base::scoped_ptr<uint8[]> temp_buffer;
   // YUY2 can be scaled vertically using an ARGB scaler.  Aspect ratio is only
   // a problem on OSX.  OSX always converts webcams to YUY2 or UYVY.
   bool can_scale =
diff --git a/talk/media/base/videocommon.cc b/talk/media/base/videocommon.cc
index 5dd45d7..b051d52 100644
--- a/talk/media/base/videocommon.cc
+++ b/talk/media/base/videocommon.cc
@@ -153,12 +153,15 @@
 
 // Compute size to crop video frame to.
 // If cropped_format_* is 0, return the frame_* size as is.
-void ComputeCrop(int cropped_format_width,
-                 int cropped_format_height,
+void ComputeCrop(int cropped_format_width, int cropped_format_height,
                  int frame_width, int frame_height,
                  int pixel_width, int pixel_height,
                  int rotation,
                  int* cropped_width, int* cropped_height) {
+  // Transform screen crop to camera space if rotated.
+  if (rotation == 90 || rotation == 270) {
+    std::swap(cropped_format_width, cropped_format_height);
+  }
   ASSERT(cropped_format_width >= 0);
   ASSERT(cropped_format_height >= 0);
   ASSERT(frame_width > 0);
@@ -182,39 +185,26 @@
       static_cast<float>(frame_height * pixel_height);
   float crop_aspect = static_cast<float>(cropped_format_width) /
       static_cast<float>(cropped_format_height);
-  int new_frame_width = frame_width;
-  int new_frame_height = frame_height;
-  if (rotation == 90 || rotation == 270) {
-    frame_aspect = 1.0f / frame_aspect;
-    new_frame_width = frame_height;
-    new_frame_height = frame_width;
-  }
-
   // kAspectThresh is the maximum aspect ratio difference that we'll accept
-  // for cropping.  The value 1.33 is based on 4:3 being cropped to 16:9.
+  // for cropping.  The value 1.34 allows cropping from 4:3 to 16:9.
   // Set to zero to disable cropping entirely.
   // TODO(fbarchard): crop to multiple of 16 width for better performance.
-  const float kAspectThresh = 16.f / 9.f / (4.f / 3.f) + 0.01f;  // 1.33
+  const float kAspectThresh = 1.34f;
   // Wide aspect - crop horizontally
   if (frame_aspect > crop_aspect &&
       frame_aspect < crop_aspect * kAspectThresh) {
     // Round width down to multiple of 4 to avoid odd chroma width.
     // Width a multiple of 4 allows a half size image to have chroma channel
-    // that avoids rounding errors.  lmi and webrtc have odd width limitations.
-    new_frame_width = static_cast<int>((crop_aspect * frame_height *
+    // that avoids rounding errors.
+    frame_width = static_cast<int>((crop_aspect * frame_height *
         pixel_height) / pixel_width + 0.5f) & ~3;
-  } else if (crop_aspect > frame_aspect &&
-             crop_aspect < frame_aspect * kAspectThresh) {
-    new_frame_height = static_cast<int>((frame_width * pixel_width) /
+  } else if (frame_aspect < crop_aspect &&
+             frame_aspect > crop_aspect / kAspectThresh) {
+    frame_height = static_cast<int>((frame_width * pixel_width) /
         (crop_aspect * pixel_height) + 0.5f) & ~1;
   }
-
-  *cropped_width = new_frame_width;
-  *cropped_height = new_frame_height;
-  if (rotation == 90 || rotation == 270) {
-    *cropped_width = new_frame_height;
-    *cropped_height = new_frame_width;
-  }
+  *cropped_width = frame_width;
+  *cropped_height = frame_height;
 }
 
 // Compute the frame size that makes pixels square pixel aspect ratio.
diff --git a/talk/media/base/videocommon_unittest.cc b/talk/media/base/videocommon_unittest.cc
index 9122843..455a47b 100644
--- a/talk/media/base/videocommon_unittest.cc
+++ b/talk/media/base/videocommon_unittest.cc
@@ -276,6 +276,15 @@
   EXPECT_EQ(640, cropped_width);
   EXPECT_EQ(480, cropped_height);
 
+  // Request 9:16 from VGA rotated (portrait).  Expect crop.
+  ComputeCrop(360, 640,  // Crop size 9:16
+              640, 480,  // Frame is 3:4 portrait
+              1, 1,  // Normal 1:1 pixels
+              90,
+              &cropped_width, &cropped_height);
+  EXPECT_EQ(640, cropped_width);
+  EXPECT_EQ(360, cropped_height);
+
   // Cropped size 0x0.  Expect no cropping.
   // This is used when adding multiple capturers
   ComputeCrop(0, 0,  // Crop size 0x0
diff --git a/talk/media/base/videoframe_unittest.h b/talk/media/base/videoframe_unittest.h
index f70e567..361c195c 100644
--- a/talk/media/base/videoframe_unittest.h
+++ b/talk/media/base/videoframe_unittest.h
@@ -157,7 +157,7 @@
                         prefix.c_str(), frame.GetWidth(), frame.GetHeight());
     size_t out_size = cricket::VideoFrame::SizeOf(frame.GetWidth(),
                                                   frame.GetHeight());
-    talk_base::scoped_array<uint8> out(new uint8[out_size]);
+    talk_base::scoped_ptr<uint8[]> out(new uint8[out_size]);
     frame.CopyToBuffer(out.get(), out_size);
     return DumpSample(filename, out.get(), out_size);
   }
@@ -514,7 +514,7 @@
     T frame1, frame2;
     ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
     size_t buf_size = kWidth * kHeight * 2;
-    talk_base::scoped_array<uint8> buf(new uint8[buf_size + kAlignment]);
+    talk_base::scoped_ptr<uint8[]> buf(new uint8[buf_size + kAlignment]);
     uint8* y = ALIGNP(buf.get(), kAlignment);
     uint8* u = y + kWidth * kHeight;
     uint8* v = u + (kWidth / 2) * kHeight;
@@ -535,7 +535,7 @@
     T frame1, frame2;
     ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
     size_t buf_size = kWidth * kHeight * 2;
-    talk_base::scoped_array<uint8> buf(new uint8[buf_size + kAlignment]);
+    talk_base::scoped_ptr<uint8[]> buf(new uint8[buf_size + kAlignment]);
     uint8* yuy2 = ALIGNP(buf.get(), kAlignment);
     EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.GetYPlane(), frame1.GetYPitch(),
                                     frame1.GetUPlane(), frame1.GetUPitch(),
@@ -552,7 +552,7 @@
     T frame1, frame2;
     ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
     size_t buf_size = kWidth * kHeight * 2;
-    talk_base::scoped_array<uint8> buf(new uint8[buf_size + kAlignment + 1]);
+    talk_base::scoped_ptr<uint8[]> buf(new uint8[buf_size + kAlignment + 1]);
     uint8* yuy2 = ALIGNP(buf.get(), kAlignment) + 1;
     EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.GetYPlane(), frame1.GetYPitch(),
                                     frame1.GetUPlane(), frame1.GetUPitch(),
@@ -718,7 +718,7 @@
   void ConstructRGB565() {
     T frame1, frame2;
     size_t out_size = kWidth * kHeight * 2;
-    talk_base::scoped_array<uint8> outbuf(new uint8[out_size + kAlignment]);
+    talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
     uint8 *out = ALIGNP(outbuf.get(), kAlignment);
     T frame;
     ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
@@ -734,7 +734,7 @@
   void ConstructARGB1555() {
     T frame1, frame2;
     size_t out_size = kWidth * kHeight * 2;
-    talk_base::scoped_array<uint8> outbuf(new uint8[out_size + kAlignment]);
+    talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
     uint8 *out = ALIGNP(outbuf.get(), kAlignment);
     T frame;
     ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
@@ -750,7 +750,7 @@
   void ConstructARGB4444() {
     T frame1, frame2;
     size_t out_size = kWidth * kHeight * 2;
-    talk_base::scoped_array<uint8> outbuf(new uint8[out_size + kAlignment]);
+    talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
     uint8 *out = ALIGNP(outbuf.get(), kAlignment);
     T frame;
     ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
@@ -769,7 +769,7 @@
   #define TEST_BYR(NAME, BAYER)                                                \
   void NAME() {                                                                \
     size_t bayer_size = kWidth * kHeight;                                      \
-    talk_base::scoped_array<uint8> bayerbuf(new uint8[                         \
+    talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[                         \
         bayer_size + kAlignment]);                                             \
     uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment);                         \
     T frame1, frame2;                                                          \
@@ -994,7 +994,7 @@
     }
     // Convert back to ARGB.
     size_t out_size = 4;
-    talk_base::scoped_array<uint8> outbuf(new uint8[out_size + kAlignment]);
+    talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
     uint8 *out = ALIGNP(outbuf.get(), kAlignment);
 
     EXPECT_EQ(out_size, frame.ConvertToRgbBuffer(cricket::FOURCC_ARGB,
@@ -1031,7 +1031,7 @@
     }
     // Convert back to ARGB
     size_t out_size = 10 * 4;
-    talk_base::scoped_array<uint8> outbuf(new uint8[out_size + kAlignment]);
+    talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
     uint8 *out = ALIGNP(outbuf.get(), kAlignment);
 
     EXPECT_EQ(out_size, frame.ConvertToRgbBuffer(cricket::FOURCC_ARGB,
@@ -1162,7 +1162,7 @@
 
     // Allocate a buffer with end page aligned.
     const int kPadToHeapSized = 16 * 1024 * 1024;
-    talk_base::scoped_array<uint8> page_buffer(
+    talk_base::scoped_ptr<uint8[]> page_buffer(
         new uint8[((data_size + kPadToHeapSized + 4095) & ~4095)]);
     uint8* data_ptr = page_buffer.get();
     if (!data_ptr) {
@@ -1427,7 +1427,7 @@
 
     int astride = kWidth * bpp + rowpad;
     size_t out_size = astride * kHeight;
-    talk_base::scoped_array<uint8> outbuf(new uint8[out_size + kAlignment + 1]);
+    talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment + 1]);
     memset(outbuf.get(), 0, out_size + kAlignment + 1);
     uint8 *outtop = ALIGNP(outbuf.get(), kAlignment);
     uint8 *out = outtop;
@@ -1841,7 +1841,7 @@
   void ConvertToI422Buffer() {
     T frame1, frame2;
     size_t out_size = kWidth * kHeight * 2;
-    talk_base::scoped_array<uint8> buf(new uint8[out_size + kAlignment]);
+    talk_base::scoped_ptr<uint8[]> buf(new uint8[out_size + kAlignment]);
     uint8* y = ALIGNP(buf.get(), kAlignment);
     uint8* u = y + kWidth * kHeight;
     uint8* v = u + (kWidth / 2) * kHeight;
@@ -1865,7 +1865,7 @@
   #define TEST_TOBYR(NAME, BAYER)                                              \
   void NAME() {                                                                \
     size_t bayer_size = kWidth * kHeight;                                      \
-    talk_base::scoped_array<uint8> bayerbuf(new uint8[                         \
+    talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[                         \
         bayer_size + kAlignment]);                                             \
     uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment);                         \
     T frame;                                                                   \
@@ -1894,7 +1894,7 @@
   }                                                                            \
   void NAME##Unaligned() {                                                     \
     size_t bayer_size = kWidth * kHeight;                                      \
-    talk_base::scoped_array<uint8> bayerbuf(new uint8[                         \
+    talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[                         \
         bayer_size + 1 + kAlignment]);                                         \
     uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment) + 1;                     \
     T frame;                                                                   \
@@ -1931,7 +1931,7 @@
   #define TEST_BYRTORGB(NAME, BAYER)                                           \
   void NAME() {                                                                \
     size_t bayer_size = kWidth * kHeight;                                      \
-    talk_base::scoped_array<uint8> bayerbuf(new uint8[                         \
+    talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[                         \
         bayer_size + kAlignment]);                                             \
     uint8 *bayer1 = ALIGNP(bayerbuf.get(), kAlignment);                        \
     for (int i = 0; i < kWidth * kHeight; ++i) {                               \
@@ -1947,7 +1947,7 @@
                              kWidth * 4,                                       \
                              kWidth, kHeight);                                 \
     }                                                                          \
-    talk_base::scoped_array<uint8> bayer2buf(new uint8[                        \
+    talk_base::scoped_ptr<uint8[]> bayer2buf(new uint8[                        \
         bayer_size + kAlignment]);                                             \
     uint8 *bayer2 = ALIGNP(bayer2buf.get(), kAlignment);                       \
     libyuv::ARGBToBayer##BAYER(reinterpret_cast<uint8*>(ms->GetBuffer()),      \
@@ -2010,7 +2010,7 @@
     ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight,
                           &frame));
     size_t out_size = kWidth * kHeight * 3 / 2;
-    talk_base::scoped_array<uint8> out(new uint8[out_size]);
+    talk_base::scoped_ptr<uint8[]> out(new uint8[out_size]);
     for (int i = 0; i < repeat_; ++i) {
       EXPECT_EQ(out_size, frame.CopyToBuffer(out.get(), out_size));
     }
@@ -2056,7 +2056,7 @@
 
   void CopyToBuffer1Pixel() {
     size_t out_size = 3;
-    talk_base::scoped_array<uint8> out(new uint8[out_size + 1]);
+    talk_base::scoped_ptr<uint8[]> out(new uint8[out_size + 1]);
     memset(out.get(), 0xfb, out_size + 1);  // Fill buffer
     uint8 pixel[3] = { 1, 2, 3 };
     T frame;
diff --git a/talk/media/devices/carbonvideorenderer.h b/talk/media/devices/carbonvideorenderer.h
index e091186..6c52fcf 100644
--- a/talk/media/devices/carbonvideorenderer.h
+++ b/talk/media/devices/carbonvideorenderer.h
@@ -57,7 +57,7 @@
   static OSStatus DrawEventHandler(EventHandlerCallRef handler,
                                    EventRef event,
                                    void* data);
-  talk_base::scoped_array<uint8> image_;
+  talk_base::scoped_ptr<uint8[]> image_;
   talk_base::CriticalSection image_crit_;
   int image_width_;
   int image_height_;
diff --git a/talk/media/devices/gdivideorenderer.cc b/talk/media/devices/gdivideorenderer.cc
index c8024b7..9633eb6 100755
--- a/talk/media/devices/gdivideorenderer.cc
+++ b/talk/media/devices/gdivideorenderer.cc
@@ -98,7 +98,7 @@
   void OnRenderFrame(const VideoFrame* frame);
 
   BITMAPINFO bmi_;
-  talk_base::scoped_array<uint8> image_;
+  talk_base::scoped_ptr<uint8[]> image_;
   talk_base::scoped_ptr<WindowThread> window_thread_;
   // The initial position of the window.
   int initial_x_;
diff --git a/talk/media/devices/gtkvideorenderer.h b/talk/media/devices/gtkvideorenderer.h
index 6276b51..744c19f 100755
--- a/talk/media/devices/gtkvideorenderer.h
+++ b/talk/media/devices/gtkvideorenderer.h
@@ -56,7 +56,7 @@
   // Check if the window has been closed.
   bool IsClosed() const;
 
-  talk_base::scoped_array<uint8> image_;
+  talk_base::scoped_ptr<uint8[]> image_;
   GtkWidget* window_;
   GtkWidget* draw_area_;
   // The initial position of the window.
diff --git a/talk/media/devices/macdevicemanager.cc b/talk/media/devices/macdevicemanager.cc
index 10d85a0..e92408e 100644
--- a/talk/media/devices/macdevicemanager.cc
+++ b/talk/media/devices/macdevicemanager.cc
@@ -120,7 +120,7 @@
   }
 
   size_t num_devices = propsize / sizeof(AudioDeviceID);
-  talk_base::scoped_array<AudioDeviceID> device_ids(
+  talk_base::scoped_ptr<AudioDeviceID[]> device_ids(
       new AudioDeviceID[num_devices]);
 
   err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
diff --git a/talk/media/sctp/sctpdataengine.h b/talk/media/sctp/sctpdataengine.h
index cadf78c..d09b152 100644
--- a/talk/media/sctp/sctpdataengine.h
+++ b/talk/media/sctp/sctpdataengine.h
@@ -56,7 +56,7 @@
 namespace cricket {
 // The highest stream ID (Sid) that SCTP allows, and the number of streams we
 // tell SCTP we're going to use.
-const uint32 kMaxSctpSid = USHRT_MAX;
+const uint32 kMaxSctpSid = 1023;
 
 // A DataEngine that interacts with usrsctp.
 //
diff --git a/talk/media/sctp/sctputils.cc b/talk/media/sctp/sctputils.cc
index c33c64e..4073905 100644
--- a/talk/media/sctp/sctputils.cc
+++ b/talk/media/sctp/sctputils.cc
@@ -35,7 +35,7 @@
 namespace cricket {
 
 // Format defined at
-// http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
+// http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-00#section-6.1
 
 static const uint8 DATA_CHANNEL_OPEN_MESSAGE_TYPE = 0x03;
 
@@ -73,16 +73,17 @@
     LOG(LS_WARNING) << "Could not read OPEN message channel type.";
     return false;
   }
-  uint16 reliability_param;
-  if (!buffer.ReadUInt16(&reliability_param)) {
-    LOG(LS_WARNING) << "Could not read OPEN message reliabilility param.";
-    return false;
-  }
+
   uint16 priority;
   if (!buffer.ReadUInt16(&priority)) {
     LOG(LS_WARNING) << "Could not read OPEN message reliabilility prioirty.";
     return false;
   }
+  uint32 reliability_param;
+  if (!buffer.ReadUInt32(&reliability_param)) {
+    LOG(LS_WARNING) << "Could not read OPEN message reliabilility param.";
+    return false;
+  }
   uint16 label_length;
   if (!buffer.ReadUInt16(&label_length)) {
     LOG(LS_WARNING) << "Could not read OPEN message label length.";
@@ -116,10 +117,11 @@
     case DCOMCT_ORDERED_PARTIAL_RTXS:
     case DCOMCT_UNORDERED_PARTIAL_RTXS:
       config->maxRetransmits = reliability_param;
-
+      break;
     case DCOMCT_ORDERED_PARTIAL_TIME:
     case DCOMCT_UNORDERED_PARTIAL_TIME:
       config->maxRetransmitTime = reliability_param;
+      break;
   }
 
   return true;
@@ -130,11 +132,9 @@
     const webrtc::DataChannelInit& config,
     talk_base::Buffer* payload) {
   // Format defined at
-  // http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
-  // TODO(pthatcher)
-
+  // http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-00#section-6.1
   uint8 channel_type = 0;
-  uint16 reliability_param = 0;
+  uint32 reliability_param = 0;
   uint16 priority = 0;
   if (config.ordered) {
     if (config.maxRetransmits > -1) {
@@ -163,8 +163,8 @@
       talk_base::ByteBuffer::ORDER_NETWORK);
   buffer.WriteUInt8(DATA_CHANNEL_OPEN_MESSAGE_TYPE);
   buffer.WriteUInt8(channel_type);
-  buffer.WriteUInt16(reliability_param);
   buffer.WriteUInt16(priority);
+  buffer.WriteUInt32(reliability_param);
   buffer.WriteUInt16(static_cast<uint16>(label.length()));
   buffer.WriteUInt16(static_cast<uint16>(config.protocol.length()));
   buffer.WriteString(label);
diff --git a/talk/media/sctp/sctputils_unittest.cc b/talk/media/sctp/sctputils_unittest.cc
index 1cc9a70..70f67b8 100644
--- a/talk/media/sctp/sctputils_unittest.cc
+++ b/talk/media/sctp/sctputils_unittest.cc
@@ -37,7 +37,7 @@
                                const webrtc::DataChannelInit& config) {
     uint8 message_type;
     uint8 channel_type;
-    uint16 reliability;
+    uint32 reliability;
     uint16 priority;
     uint16 label_length;
     uint16 protocol_length;
@@ -57,15 +57,15 @@
                 channel_type);
     }
 
-    ASSERT_TRUE(buffer.ReadUInt16(&reliability));
+    ASSERT_TRUE(buffer.ReadUInt16(&priority));
+
+    ASSERT_TRUE(buffer.ReadUInt32(&reliability));
     if (config.maxRetransmits > -1 || config.maxRetransmitTime > -1) {
       EXPECT_EQ(config.maxRetransmits > -1 ?
                     config.maxRetransmits : config.maxRetransmitTime,
-                reliability);
+                static_cast<int>(reliability));
     }
 
-    ASSERT_TRUE(buffer.ReadUInt16(&priority));
-
     ASSERT_TRUE(buffer.ReadUInt16(&label_length));
     ASSERT_TRUE(buffer.ReadUInt16(&protocol_length));
     EXPECT_EQ(label.size(), label_length);
@@ -86,13 +86,14 @@
   config.protocol = "y";
 
   talk_base::Buffer packet;
-  ASSERT(cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
+  ASSERT_TRUE(
+      cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
 
   VerifyOpenMessageFormat(packet, input_label, config);
 
   std::string output_label;
   webrtc::DataChannelInit output_config;
-  ASSERT(cricket::ParseDataChannelOpenMessage(
+  ASSERT_TRUE(cricket::ParseDataChannelOpenMessage(
       packet, &output_label, &output_config));
 
   EXPECT_EQ(input_label, output_label);
@@ -110,19 +111,21 @@
   config.protocol = "y";
 
   talk_base::Buffer packet;
-  ASSERT(cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
+  ASSERT_TRUE(
+      cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
 
   VerifyOpenMessageFormat(packet, input_label, config);
 
   std::string output_label;
   webrtc::DataChannelInit output_config;
-  ASSERT(cricket::ParseDataChannelOpenMessage(
+  ASSERT_TRUE(cricket::ParseDataChannelOpenMessage(
       packet, &output_label, &output_config));
 
   EXPECT_EQ(input_label, output_label);
   EXPECT_EQ(config.protocol, output_config.protocol);
   EXPECT_EQ(config.ordered, output_config.ordered);
   EXPECT_EQ(config.maxRetransmitTime, output_config.maxRetransmitTime);
+  EXPECT_EQ(-1, output_config.maxRetransmits);
 }
 
 TEST_F(SctpUtilsTest, WriteParseOpenMessageWithMaxRetransmits) {
@@ -132,17 +135,19 @@
   config.protocol = "y";
 
   talk_base::Buffer packet;
-  ASSERT(cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
+  ASSERT_TRUE(
+      cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
 
   VerifyOpenMessageFormat(packet, input_label, config);
 
   std::string output_label;
   webrtc::DataChannelInit output_config;
-  ASSERT(cricket::ParseDataChannelOpenMessage(
+  ASSERT_TRUE(cricket::ParseDataChannelOpenMessage(
       packet, &output_label, &output_config));
 
   EXPECT_EQ(input_label, output_label);
   EXPECT_EQ(config.protocol, output_config.protocol);
   EXPECT_EQ(config.ordered, output_config.ordered);
   EXPECT_EQ(config.maxRetransmits, output_config.maxRetransmits);
+  EXPECT_EQ(-1, output_config.maxRetransmitTime);
 }
diff --git a/talk/media/webrtc/fakewebrtcvideoengine.h b/talk/media/webrtc/fakewebrtcvideoengine.h
index 31de172..0b68728 100644
--- a/talk/media/webrtc/fakewebrtcvideoengine.h
+++ b/talk/media/webrtc/fakewebrtcvideoengine.h
@@ -1046,7 +1046,14 @@
     return 0;
   }
   WEBRTC_STUB(EnableColorEnhancement, (const int, const bool));
-
+#ifdef USE_WEBRTC_DEV_BRANCH
+  WEBRTC_VOID_STUB(RegisterPreEncodeCallback,
+                   (int, webrtc::I420FrameCallback*));
+  WEBRTC_VOID_STUB(DeRegisterPreEncodeCallback, (int));
+  WEBRTC_VOID_STUB(RegisterPreRenderCallback,
+                   (int, webrtc::I420FrameCallback*));
+  WEBRTC_VOID_STUB(DeRegisterPreRenderCallback, (int));
+#endif
   // webrtc::ViEExternalCodec
   WEBRTC_FUNC(RegisterExternalSendCodec,
       (const int channel, const unsigned char pl_type, webrtc::VideoEncoder*,
diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h
index c3cd786..9696518 100644
--- a/talk/media/webrtc/fakewebrtcvoiceengine.h
+++ b/talk/media/webrtc/fakewebrtcvoiceengine.h
@@ -87,6 +87,8 @@
           fec(false),
           nack(false),
           media_processor_registered(false),
+          rx_agc_enabled(false),
+          rx_agc_mode(webrtc::kAgcDefault),
           cn8_type(13),
           cn16_type(105),
           dtmf_type(106),
@@ -95,6 +97,7 @@
           send_ssrc(0),
           level_header_ext_(-1) {
       memset(&send_codec, 0, sizeof(send_codec));
+      memset(&rx_agc_config, 0, sizeof(rx_agc_config));
     }
     bool external_transport;
     bool send;
@@ -107,6 +110,9 @@
     bool fec;
     bool nack;
     bool media_processor_registered;
+    bool rx_agc_enabled;
+    webrtc::AgcModes rx_agc_mode;
+    webrtc::AgcConfig rx_agc_config;
     int cn8_type;
     int cn16_type;
     int dtmf_type;
@@ -144,6 +150,8 @@
         send_fail_channel_(-1),
         fail_start_recording_microphone_(false),
         recording_microphone_(false),
+        recording_sample_rate_(-1),
+        playout_sample_rate_(-1),
         media_processor_(NULL) {
     memset(&agc_config_, 0, sizeof(agc_config_));
   }
@@ -584,10 +592,22 @@
   WEBRTC_STUB(AudioDeviceControl, (unsigned int, unsigned int, unsigned int));
   WEBRTC_STUB(SetLoudspeakerStatus, (bool enable));
   WEBRTC_STUB(GetLoudspeakerStatus, (bool& enabled));
-  WEBRTC_STUB(SetRecordingSampleRate, (unsigned int samples_per_sec));
-  WEBRTC_STUB_CONST(RecordingSampleRate, (unsigned int* samples_per_sec));
-  WEBRTC_STUB(SetPlayoutSampleRate, (unsigned int samples_per_sec));
-  WEBRTC_STUB_CONST(PlayoutSampleRate, (unsigned int* samples_per_sec));
+  WEBRTC_FUNC(SetRecordingSampleRate, (unsigned int samples_per_sec)) {
+    recording_sample_rate_ = samples_per_sec;
+    return 0;
+  }
+  WEBRTC_FUNC_CONST(RecordingSampleRate, (unsigned int* samples_per_sec)) {
+    *samples_per_sec = recording_sample_rate_;
+    return 0;
+  }
+  WEBRTC_FUNC(SetPlayoutSampleRate, (unsigned int samples_per_sec)) {
+    playout_sample_rate_ = samples_per_sec;
+    return 0;
+  }
+  WEBRTC_FUNC_CONST(PlayoutSampleRate, (unsigned int* samples_per_sec)) {
+    *samples_per_sec = playout_sample_rate_;
+    return 0;
+  }
   WEBRTC_STUB(EnableBuiltInAEC, (bool enable));
   virtual bool BuiltInAECIsEnabled() const { return true; }
 
@@ -841,12 +861,27 @@
   WEBRTC_STUB(SetRxNsStatus, (int channel, bool enable, webrtc::NsModes mode));
   WEBRTC_STUB(GetRxNsStatus, (int channel, bool& enabled,
                               webrtc::NsModes& mode));
-  WEBRTC_STUB(SetRxAgcStatus, (int channel, bool enable,
-                               webrtc::AgcModes mode));
-  WEBRTC_STUB(GetRxAgcStatus, (int channel, bool& enabled,
-                               webrtc::AgcModes& mode));
-  WEBRTC_STUB(SetRxAgcConfig, (int channel, webrtc::AgcConfig config));
-  WEBRTC_STUB(GetRxAgcConfig, (int channel, webrtc::AgcConfig& config));
+  WEBRTC_FUNC(SetRxAgcStatus, (int channel, bool enable,
+                               webrtc::AgcModes mode)) {
+    channels_[channel]->rx_agc_enabled = enable;
+    channels_[channel]->rx_agc_mode = mode;
+    return 0;
+  }
+  WEBRTC_FUNC(GetRxAgcStatus, (int channel, bool& enabled,
+                               webrtc::AgcModes& mode)) {
+    enabled = channels_[channel]->rx_agc_enabled;
+    mode = channels_[channel]->rx_agc_mode;
+    return 0;
+  }
+
+  WEBRTC_FUNC(SetRxAgcConfig, (int channel, webrtc::AgcConfig config)) {
+    channels_[channel]->rx_agc_config = config;
+    return 0;
+  }
+  WEBRTC_FUNC(GetRxAgcConfig, (int channel, webrtc::AgcConfig& config)) {
+    config = channels_[channel]->rx_agc_config;
+    return 0;
+  }
 
   WEBRTC_STUB(RegisterRxVadObserver, (int, webrtc::VoERxVadCallback&));
   WEBRTC_STUB(DeRegisterRxVadObserver, (int channel));
@@ -996,6 +1031,8 @@
   int send_fail_channel_;
   bool fail_start_recording_microphone_;
   bool recording_microphone_;
+  int recording_sample_rate_;
+  int playout_sample_rate_;
   DtmfInfo dtmf_info_;
   webrtc::VoEMediaProcess* media_processor_;
 };
diff --git a/talk/media/webrtc/webrtcvideoengine.cc b/talk/media/webrtc/webrtcvideoengine.cc
index 3f4667d..05f8b2b 100644
--- a/talk/media/webrtc/webrtcvideoengine.cc
+++ b/talk/media/webrtc/webrtcvideoengine.cc
@@ -309,6 +309,13 @@
        : video_channel_(video_channel),
          framerate_(0),
          bitrate_(0),
+         decode_ms_(0),
+         max_decode_ms_(0),
+         current_delay_ms_(0),
+         target_delay_ms_(0),
+         jitter_buffer_ms_(0),
+         min_playout_delay_ms_(0),
+         render_delay_ms_(0),
          firs_requested_(0) {
   }
 
@@ -323,23 +330,42 @@
     framerate_ = framerate;
     bitrate_ = bitrate;
   }
+
+  virtual void DecoderTiming(int decode_ms,
+                             int max_decode_ms,
+                             int current_delay_ms,
+                             int target_delay_ms,
+                             int jitter_buffer_ms,
+                             int min_playout_delay_ms,
+                             int render_delay_ms) {
+    talk_base::CritScope cs(&crit_);
+    decode_ms_ = decode_ms;
+    max_decode_ms_ = max_decode_ms;
+    current_delay_ms_ = current_delay_ms;
+    target_delay_ms_ = target_delay_ms;
+    jitter_buffer_ms_ = jitter_buffer_ms;
+    min_playout_delay_ms_ = min_playout_delay_ms;
+    render_delay_ms_ = render_delay_ms;
+  }
+
   virtual void RequestNewKeyFrame(const int videoChannel) {
     talk_base::CritScope cs(&crit_);
     ASSERT(video_channel_ == videoChannel);
     ++firs_requested_;
   }
 
-  int framerate() const {
+  // Populate |rinfo| based on previously-set data in |*this|.
+  void ExportTo(VideoReceiverInfo* rinfo) {
     talk_base::CritScope cs(&crit_);
-    return framerate_;
-  }
-  int bitrate() const {
-    talk_base::CritScope cs(&crit_);
-    return bitrate_;
-  }
-  int firs_requested() const {
-    talk_base::CritScope cs(&crit_);
-    return firs_requested_;
+    rinfo->firs_sent = firs_requested_;
+    rinfo->framerate_rcvd = framerate_;
+    rinfo->decode_ms = decode_ms_;
+    rinfo->max_decode_ms = max_decode_ms_;
+    rinfo->current_delay_ms = current_delay_ms_;
+    rinfo->target_delay_ms = target_delay_ms_;
+    rinfo->jitter_buffer_ms = jitter_buffer_ms_;
+    rinfo->min_playout_delay_ms = min_playout_delay_ms_;
+    rinfo->render_delay_ms = render_delay_ms_;
   }
 
  private:
@@ -347,6 +373,13 @@
   int video_channel_;
   int framerate_;
   int bitrate_;
+  int decode_ms_;
+  int max_decode_ms_;
+  int current_delay_ms_;
+  int target_delay_ms_;
+  int jitter_buffer_ms_;
+  int min_playout_delay_ms_;
+  int render_delay_ms_;
   int firs_requested_;
 };
 
@@ -2303,14 +2336,13 @@
     rinfo.packets_lost = -1;
     rinfo.packets_concealed = -1;
     rinfo.fraction_lost = -1;  // from SentRTCP
-    rinfo.firs_sent = channel->decoder_observer()->firs_requested();
     rinfo.nacks_sent = -1;
     rinfo.frame_width = channel->render_adapter()->width();
     rinfo.frame_height = channel->render_adapter()->height();
-    rinfo.framerate_rcvd = channel->decoder_observer()->framerate();
     int fps = channel->render_adapter()->framerate();
     rinfo.framerate_decoded = fps;
     rinfo.framerate_output = fps;
+    channel->decoder_observer()->ExportTo(&rinfo);
 
     // Get sent RTCP statistics.
     uint16 s_fraction_lost;
diff --git a/talk/media/webrtc/webrtcvideoengine_unittest.cc b/talk/media/webrtc/webrtcvideoengine_unittest.cc
index 9537673..9fbbbe4 100644
--- a/talk/media/webrtc/webrtcvideoengine_unittest.cc
+++ b/talk/media/webrtc/webrtcvideoengine_unittest.cc
@@ -118,7 +118,7 @@
     }
     cricket::WebRtcVideoFrame frame;
     size_t size = width * height * 3 / 2;  // I420
-    talk_base::scoped_array<uint8> pixel(new uint8[size]);
+    talk_base::scoped_ptr<uint8[]> pixel(new uint8[size]);
     if (!frame.Init(cricket::FOURCC_I420,
                     width, height, width, height,
                     pixel.get(), size, 1, 1, 0, 0, 0)) {
@@ -138,7 +138,7 @@
     }
     cricket::WebRtcVideoFrame frame;
     size_t size = width * height * 3 / 2;  // I420
-    talk_base::scoped_array<uint8> pixel(new uint8[size]);
+    talk_base::scoped_ptr<uint8[]> pixel(new uint8[size]);
     if (!frame.Init(cricket::FOURCC_I420,
                     width, height, width, height,
                     pixel.get(), size, 1, 1, 0, timestamp, 0)) {
@@ -1161,7 +1161,8 @@
 }
 
 
-TEST_F(WebRtcVideoEngineTestFake, SendReceiveBitratesStats) {
+// Disabled since its flaky: b/11288120
+TEST_F(WebRtcVideoEngineTestFake, DISABLED_SendReceiveBitratesStats) {
   EXPECT_TRUE(SetupEngine());
   cricket::VideoOptions options;
   options.conference_mode.Set(true);
diff --git a/talk/media/webrtc/webrtcvideoframe.h b/talk/media/webrtc/webrtcvideoframe.h
index 18475a6..e023234 100644
--- a/talk/media/webrtc/webrtcvideoframe.h
+++ b/talk/media/webrtc/webrtcvideoframe.h
@@ -55,7 +55,7 @@
   const webrtc::VideoFrame* frame() const;
 
  private:
-  talk_base::scoped_array<char> data_;
+  talk_base::scoped_ptr<char[]> data_;
   size_t length_;
   webrtc::VideoFrame video_frame_;
 };
diff --git a/talk/media/webrtc/webrtcvideoframe_unittest.cc b/talk/media/webrtc/webrtcvideoframe_unittest.cc
index 2f0decb..ebc345e 100644
--- a/talk/media/webrtc/webrtcvideoframe_unittest.cc
+++ b/talk/media/webrtc/webrtcvideoframe_unittest.cc
@@ -53,7 +53,7 @@
     captured_frame.height = frame_height;
     captured_frame.data_size = (frame_width * frame_height) +
         ((frame_width + 1) / 2) * ((frame_height + 1) / 2) * 2;
-    talk_base::scoped_array<uint8> captured_frame_buffer(
+    talk_base::scoped_ptr<uint8[]> captured_frame_buffer(
         new uint8[captured_frame.data_size]);
     captured_frame.data = captured_frame_buffer.get();
 
diff --git a/talk/media/webrtc/webrtcvie.h b/talk/media/webrtc/webrtcvie.h
index 9550962..50cc5d7 100644
--- a/talk/media/webrtc/webrtcvie.h
+++ b/talk/media/webrtc/webrtcvie.h
@@ -45,6 +45,7 @@
 #include "webrtc/video_engine/include/vie_network.h"
 #include "webrtc/video_engine/include/vie_render.h"
 #include "webrtc/video_engine/include/vie_rtp_rtcp.h"
+#include "webrtc/video_engine/new_include/frame_callback.h"
 
 namespace cricket {
 
diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc
index 83cbdaf..121dd46 100644
--- a/talk/media/webrtc/webrtcvoiceengine.cc
+++ b/talk/media/webrtc/webrtcvoiceengine.cc
@@ -528,7 +528,7 @@
   // Save the default AGC configuration settings. This must happen before
   // calling SetOptions or the default will be overwritten.
   if (voe_wrapper_->processing()->GetAgcConfig(default_agc_config_) == -1) {
-    LOG_RTCERR0(GetAGCConfig);
+    LOG_RTCERR0(GetAgcConfig);
     return false;
   }
 
@@ -686,6 +686,10 @@
   webrtc::AgcModes agc_mode = webrtc::kAgcAdaptiveAnalog;
   webrtc::NsModes ns_mode = webrtc::kNsHighSuppression;
   bool aecm_comfort_noise = false;
+  if (options.aecm_generate_comfort_noise.Get(&aecm_comfort_noise)) {
+    LOG(LS_VERBOSE) << "Comfort noise explicitly set to "
+                    << aecm_comfort_noise << " (default is false).";
+  }
 
 #if defined(IOS)
   // On iOS, VPIO provides built-in EC and AGC.
@@ -713,6 +717,9 @@
     if (voep->SetEcStatus(echo_cancellation, ec_mode) == -1) {
       LOG_RTCERR2(SetEcStatus, echo_cancellation, ec_mode);
       return false;
+    } else {
+      LOG(LS_VERBOSE) << "Echo control set to " << echo_cancellation
+                      << " with mode " << ec_mode;
     }
 #if !defined(ANDROID)
     // TODO(ajm): Remove the error return on Android from webrtc.
@@ -734,6 +741,38 @@
     if (voep->SetAgcStatus(auto_gain_control, agc_mode) == -1) {
       LOG_RTCERR2(SetAgcStatus, auto_gain_control, agc_mode);
       return false;
+    } else {
+      LOG(LS_VERBOSE) << "Auto gain set to " << auto_gain_control
+                      << " with mode " << agc_mode;
+    }
+  }
+
+  if (options.tx_agc_target_dbov.IsSet() ||
+      options.tx_agc_digital_compression_gain.IsSet() ||
+      options.tx_agc_limiter.IsSet()) {
+    // Override default_agc_config_. Generally, an unset option means "leave
+    // the VoE bits alone" in this function, so we want whatever is set to be
+    // stored as the new "default". If we didn't, then setting e.g.
+    // tx_agc_target_dbov would reset digital compression gain and limiter
+    // settings.
+    // Also, if we don't update default_agc_config_, then adjust_agc_delta
+    // would be an offset from the original values, and not whatever was set
+    // explicitly.
+    default_agc_config_.targetLeveldBOv =
+        options.tx_agc_target_dbov.GetWithDefaultIfUnset(
+            default_agc_config_.targetLeveldBOv);
+    default_agc_config_.digitalCompressionGaindB =
+        options.tx_agc_digital_compression_gain.GetWithDefaultIfUnset(
+            default_agc_config_.digitalCompressionGaindB);
+    default_agc_config_.limiterEnable =
+        options.tx_agc_limiter.GetWithDefaultIfUnset(
+            default_agc_config_.limiterEnable);
+    if (voe_wrapper_->processing()->SetAgcConfig(default_agc_config_) == -1) {
+      LOG_RTCERR3(SetAgcConfig,
+                  default_agc_config_.targetLeveldBOv,
+                  default_agc_config_.digitalCompressionGaindB,
+                  default_agc_config_.limiterEnable);
+      return false;
     }
   }
 
@@ -742,6 +781,9 @@
     if (voep->SetNsStatus(noise_suppression, ns_mode) == -1) {
       LOG_RTCERR2(SetNsStatus, noise_suppression, ns_mode);
       return false;
+    } else {
+      LOG(LS_VERBOSE) << "Noise suppression set to " << noise_suppression
+                      << " with mode " << ns_mode;
     }
   }
 
@@ -799,6 +841,20 @@
     }
   }
 
+  uint32 recording_sample_rate;
+  if (options.recording_sample_rate.Get(&recording_sample_rate)) {
+    if (voe_wrapper_->hw()->SetRecordingSampleRate(recording_sample_rate)) {
+      LOG_RTCERR1(SetRecordingSampleRate, recording_sample_rate);
+    }
+  }
+
+  uint32 playout_sample_rate;
+  if (options.playout_sample_rate.Get(&playout_sample_rate)) {
+    if (voe_wrapper_->hw()->SetPlayoutSampleRate(playout_sample_rate)) {
+      LOG_RTCERR1(SetPlayoutSampleRate, playout_sample_rate);
+    }
+  }
+
 
   return true;
 }
@@ -1136,6 +1192,18 @@
     }
   }
 
+  // Allow trace options to override the trace filter. We default
+  // it to log_filter_ (as a translation of libjingle log levels)
+  // elsewhere, but this allows clients to explicitly set webrtc
+  // log levels.
+  std::vector<std::string>::iterator tracefilter =
+      std::find(opts.begin(), opts.end(), "tracefilter");
+  if (tracefilter != opts.end() && ++tracefilter != opts.end()) {
+    if (!tracing_->SetTraceFilter(talk_base::FromString<int>(*tracefilter))) {
+      LOG_RTCERR1(SetTraceFilter, *tracefilter);
+    }
+  }
+
   // Set AEC dump file
   std::vector<std::string>::iterator recordEC =
       std::find(opts.begin(), opts.end(), "recordEC");
@@ -1587,6 +1655,56 @@
     // Will be interpreted when appropriate.
   }
 
+  // Receiver-side auto gain control happens per channel, so set it here from
+  // options. Note that, like conference mode, setting it on the engine won't
+  // have the desired effect, since voice channels don't inherit options from
+  // the media engine when those options are applied per-channel.
+  bool rx_auto_gain_control;
+  if (options.rx_auto_gain_control.Get(&rx_auto_gain_control)) {
+    if (engine()->voe()->processing()->SetRxAgcStatus(
+            voe_channel(), rx_auto_gain_control,
+            webrtc::kAgcFixedDigital) == -1) {
+      LOG_RTCERR1(SetRxAgcStatus, rx_auto_gain_control);
+      return false;
+    } else {
+      LOG(LS_VERBOSE) << "Rx auto gain set to " << rx_auto_gain_control
+                      << " with mode " << webrtc::kAgcFixedDigital;
+    }
+  }
+  if (options.rx_agc_target_dbov.IsSet() ||
+      options.rx_agc_digital_compression_gain.IsSet() ||
+      options.rx_agc_limiter.IsSet()) {
+    webrtc::AgcConfig config;
+    // If only some of the options are being overridden, get the current
+    // settings for the channel and bail if they aren't available.
+    if (!options.rx_agc_target_dbov.IsSet() ||
+        !options.rx_agc_digital_compression_gain.IsSet() ||
+        !options.rx_agc_limiter.IsSet()) {
+      if (engine()->voe()->processing()->GetRxAgcConfig(
+              voe_channel(), config) != 0) {
+        LOG(LS_ERROR) << "Failed to get default rx agc configuration for "
+                      << "channel " << voe_channel() << ". Since not all rx "
+                      << "agc options are specified, unable to safely set rx "
+                      << "agc options.";
+        return false;
+      }
+    }
+    config.targetLeveldBOv =
+        options.rx_agc_target_dbov.GetWithDefaultIfUnset(
+            config.targetLeveldBOv);
+    config.digitalCompressionGaindB =
+        options.rx_agc_digital_compression_gain.GetWithDefaultIfUnset(
+            config.digitalCompressionGaindB);
+    config.limiterEnable = options.rx_agc_limiter.GetWithDefaultIfUnset(
+        config.limiterEnable);
+    if (engine()->voe()->processing()->SetRxAgcConfig(
+            voe_channel(), config) == -1) {
+      LOG_RTCERR4(SetRxAgcConfig, voe_channel(), config.targetLeveldBOv,
+                  config.digitalCompressionGaindB, config.limiterEnable);
+      return false;
+    }
+  }
+
   LOG(LS_INFO) << "Set voice channel options.  Current options: "
                << options_.ToString();
   return true;
diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
index acefc38..2e52c8f 100644
--- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc
+++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
@@ -55,9 +55,10 @@
   }
 };
 
-class NullVoETraceWrapper : public cricket::VoETraceWrapper {
+class FakeVoETraceWrapper : public cricket::VoETraceWrapper {
  public:
   virtual int SetTraceFilter(const unsigned int filter) {
+    filter_ = filter;
     return 0;
   }
   virtual int SetTraceFile(const char* fileNameUTF8) {
@@ -66,6 +67,7 @@
   virtual int SetTraceCallback(webrtc::TraceCallback* callback) {
     return 0;
   }
+  unsigned int filter_;
 };
 
 class WebRtcVoiceEngineTestFake : public testing::Test {
@@ -102,9 +104,10 @@
   WebRtcVoiceEngineTestFake()
       : voe_(kAudioCodecs, ARRAY_SIZE(kAudioCodecs)),
         voe_sc_(kAudioCodecs, ARRAY_SIZE(kAudioCodecs)),
+        trace_wrapper_(new FakeVoETraceWrapper()),
         engine_(new FakeVoEWrapper(&voe_),
                 new FakeVoEWrapper(&voe_sc_),
-                new NullVoETraceWrapper()),
+                trace_wrapper_),
         channel_(NULL), soundclip_(NULL) {
     options_conference_.conference_mode.Set(true);
     options_adjust_agc_.adjust_agc_delta.Set(-10);
@@ -277,6 +280,7 @@
  protected:
   cricket::FakeWebRtcVoiceEngine voe_;
   cricket::FakeWebRtcVoiceEngine voe_sc_;
+  FakeVoETraceWrapper* trace_wrapper_;
   cricket::WebRtcVoiceEngine engine_;
   cricket::VoiceMediaChannel* channel_;
   cricket::SoundclipMedia* soundclip_;
@@ -1873,6 +1877,84 @@
   EXPECT_FALSE(voe_.GetPlayout(channel_num));
 }
 
+TEST_F(WebRtcVoiceEngineTestFake, TxAgcConfigViaOptions) {
+  EXPECT_TRUE(SetupEngine());
+  webrtc::AgcConfig agc_config;
+  EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
+  EXPECT_EQ(0, agc_config.targetLeveldBOv);
+
+  cricket::AudioOptions options;
+  options.tx_agc_target_dbov.Set(3);
+  options.tx_agc_digital_compression_gain.Set(9);
+  options.tx_agc_limiter.Set(true);
+  options.auto_gain_control.Set(true);
+  EXPECT_TRUE(engine_.SetOptions(options));
+
+  EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
+  EXPECT_EQ(3, agc_config.targetLeveldBOv);
+  EXPECT_EQ(9, agc_config.digitalCompressionGaindB);
+  EXPECT_TRUE(agc_config.limiterEnable);
+
+  // Check interaction with adjust_agc_delta. Both should be respected, for
+  // backwards compatibility.
+  options.adjust_agc_delta.Set(-10);
+  EXPECT_TRUE(engine_.SetOptions(options));
+
+  EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
+  EXPECT_EQ(13, agc_config.targetLeveldBOv);
+}
+
+TEST_F(WebRtcVoiceEngineTestFake, RxAgcConfigViaOptions) {
+  EXPECT_TRUE(SetupEngine());
+  int channel_num = voe_.GetLastChannel();
+  cricket::AudioOptions options;
+  options.rx_agc_target_dbov.Set(6);
+  options.rx_agc_digital_compression_gain.Set(0);
+  options.rx_agc_limiter.Set(true);
+  options.rx_auto_gain_control.Set(true);
+  EXPECT_TRUE(channel_->SetOptions(options));
+
+  webrtc::AgcConfig agc_config;
+  EXPECT_EQ(0, engine_.voe()->processing()->GetRxAgcConfig(
+      channel_num, agc_config));
+  EXPECT_EQ(6, agc_config.targetLeveldBOv);
+  EXPECT_EQ(0, agc_config.digitalCompressionGaindB);
+  EXPECT_TRUE(agc_config.limiterEnable);
+}
+
+TEST_F(WebRtcVoiceEngineTestFake, SampleRatesViaOptions) {
+  EXPECT_TRUE(SetupEngine());
+  cricket::AudioOptions options;
+  options.recording_sample_rate.Set(48000u);
+  options.playout_sample_rate.Set(44100u);
+  EXPECT_TRUE(engine_.SetOptions(options));
+
+  unsigned int recording_sample_rate, playout_sample_rate;
+  EXPECT_EQ(0, voe_.RecordingSampleRate(&recording_sample_rate));
+  EXPECT_EQ(0, voe_.PlayoutSampleRate(&playout_sample_rate));
+  EXPECT_EQ(48000u, recording_sample_rate);
+  EXPECT_EQ(44100u, playout_sample_rate);
+}
+
+TEST_F(WebRtcVoiceEngineTestFake, TraceFilterViaTraceOptions) {
+  EXPECT_TRUE(SetupEngine());
+  engine_.SetLogging(talk_base::LS_INFO, "");
+  EXPECT_EQ(
+      // Info:
+      webrtc::kTraceStateInfo | webrtc::kTraceInfo |
+      // Warning:
+      webrtc::kTraceTerseInfo | webrtc::kTraceWarning |
+      // Error:
+      webrtc::kTraceError | webrtc::kTraceCritical,
+      static_cast<int>(trace_wrapper_->filter_));
+  // Now set it explicitly
+  std::string filter =
+      "tracefilter " + talk_base::ToString(webrtc::kTraceDefault);
+  engine_.SetLogging(talk_base::LS_VERBOSE, filter.c_str());
+  EXPECT_EQ(static_cast<unsigned int>(webrtc::kTraceDefault),
+            trace_wrapper_->filter_);
+}
+
 // Test that we can set the outgoing SSRC properly.
 // SSRC is set in SetupEngine by calling AddSendStream.
 TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrc) {
diff --git a/talk/p2p/base/dtlstransportchannel_unittest.cc b/talk/p2p/base/dtlstransportchannel_unittest.cc
index 6a4e5ad..c6e2804 100644
--- a/talk/p2p/base/dtlstransportchannel_unittest.cc
+++ b/talk/p2p/base/dtlstransportchannel_unittest.cc
@@ -233,7 +233,7 @@
 
   void SendPackets(size_t channel, size_t size, size_t count, bool srtp) {
     ASSERT(channel < channels_.size());
-    talk_base::scoped_array<char> packet(new char[size]);
+    talk_base::scoped_ptr<char[]> packet(new char[size]);
     size_t sent = 0;
     do {
       // Fill the packet with a known value and a sequence number to check
diff --git a/talk/p2p/base/p2ptransportchannel_unittest.cc b/talk/p2p/base/p2ptransportchannel_unittest.cc
index e3cddc0..07cfeaa 100644
--- a/talk/p2p/base/p2ptransportchannel_unittest.cc
+++ b/talk/p2p/base/p2ptransportchannel_unittest.cc
@@ -57,6 +57,11 @@
 // Addresses on the public internet.
 static const SocketAddress kPublicAddrs[2] =
     { SocketAddress("11.11.11.11", 0), SocketAddress("22.22.22.22", 0) };
+// IPv6 Addresses on the public internet.
+static const SocketAddress kIPv6PublicAddrs[2] = {
+    SocketAddress("2400:4030:1:2c00:be30:abcd:efab:cdef", 0),
+    SocketAddress("2620:0:1000:1b03:2e41:38ff:fea6:f2a4", 0)
+};
 // For configuring multihomed clients.
 static const SocketAddress kAlternateAddrs[2] =
     { SocketAddress("11.11.11.101", 0), SocketAddress("22.22.22.202", 0) };
@@ -1413,6 +1418,34 @@
             GetEndpoint(1)->cd1_.ch_->DefaultDscpValue());
 }
 
+// Verify IPv6 connection is preferred over IPv4.
+TEST_F(P2PTransportChannelTest, TestIPv6Connections) {
+  AddAddress(0, kIPv6PublicAddrs[0]);
+  AddAddress(0, kPublicAddrs[0]);
+  AddAddress(1, kIPv6PublicAddrs[1]);
+  AddAddress(1, kPublicAddrs[1]);
+
+  SetAllocationStepDelay(0, kMinimumStepDelay);
+  SetAllocationStepDelay(1, kMinimumStepDelay);
+
+  // Enable IPv6
+  SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_IPV6);
+  SetAllocatorFlags(1, cricket::PORTALLOCATOR_ENABLE_IPV6);
+
+  CreateChannels(1);
+
+  EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() &&
+                   ep2_ch1()->readable() && ep2_ch1()->writable(),
+                   1000);
+  EXPECT_TRUE(
+      ep1_ch1()->best_connection() && ep2_ch1()->best_connection() &&
+      LocalCandidate(ep1_ch1())->address().EqualIPs(kIPv6PublicAddrs[0]) &&
+      RemoteCandidate(ep1_ch1())->address().EqualIPs(kIPv6PublicAddrs[1]));
+
+  TestSendRecv(1);
+  DestroyChannels();
+}
+
 // Test what happens when we have 2 users behind the same NAT. This can lead
 // to interesting behavior because the STUN server will only give out the
 // address of the outermost NAT.
diff --git a/talk/p2p/base/port_unittest.cc b/talk/p2p/base/port_unittest.cc
index d3e02ac..1cc3049 100644
--- a/talk/p2p/base/port_unittest.cc
+++ b/talk/p2p/base/port_unittest.cc
@@ -215,7 +215,7 @@
  public:
   TestChannel(Port* p1, Port* p2)
       : ice_mode_(ICEMODE_FULL), src_(p1), dst_(p2), complete_count_(0),
-	conn_(NULL), remote_request_(NULL), nominated_(false) {
+	conn_(NULL), remote_request_(), nominated_(false) {
     src_->SignalPortComplete.connect(
         this, &TestChannel::OnPortComplete);
     src_->SignalUnknownAddress.connect(this, &TestChannel::OnUnknownAddress);
diff --git a/talk/p2p/base/pseudotcp.cc b/talk/p2p/base/pseudotcp.cc
index b647fbf..56aa5b0 100644
--- a/talk/p2p/base/pseudotcp.cc
+++ b/talk/p2p/base/pseudotcp.cc
@@ -539,7 +539,7 @@
 
   uint32 now = Now();
 
-  talk_base::scoped_array<uint8> buffer(new uint8[MAX_PACKET]);
+  talk_base::scoped_ptr<uint8[]> buffer(new uint8[MAX_PACKET]);
   long_to_bytes(m_conv, buffer.get());
   long_to_bytes(seq, buffer.get() + 4);
   long_to_bytes(m_rcv_nxt, buffer.get() + 8);
diff --git a/talk/p2p/base/stun.cc b/talk/p2p/base/stun.cc
index 2a0f6d9..38fc96e 100644
--- a/talk/p2p/base/stun.cc
+++ b/talk/p2p/base/stun.cc
@@ -188,7 +188,7 @@
 
   // Getting length of the message to calculate Message Integrity.
   size_t mi_pos = current_pos;
-  talk_base::scoped_array<char> temp_data(new char[current_pos]);
+  talk_base::scoped_ptr<char[]> temp_data(new char[current_pos]);
   memcpy(temp_data.get(), data, current_pos);
   if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
     // Stun message has other attributes after message integrity.
diff --git a/talk/p2p/base/stunport.cc b/talk/p2p/base/stunport.cc
index 5e0e500..b440bf4 100644
--- a/talk/p2p/base/stunport.cc
+++ b/talk/p2p/base/stunport.cc
@@ -287,8 +287,13 @@
   if (server_addr_.IsUnresolved()) {
     ResolveStunAddress();
   } else if (socket_->GetState() == talk_base::AsyncPacketSocket::STATE_BOUND) {
-    if (server_addr_.family() == ip().family()) {
+    // Check if |server_addr_| is compatible with the port's ip.
+    if (IsCompatibleAddress(server_addr_)) {
       requests_.Send(new StunBindingRequest(this, true, server_addr_));
+    } else {
+      // Since we can't send stun messages to the server, we should mark this
+      // port ready.
+      OnStunBindingOrResolveRequestFailed();
     }
   }
 }
diff --git a/talk/p2p/base/testturnserver.h b/talk/p2p/base/testturnserver.h
index 32251c8..7a3c83f 100644
--- a/talk/p2p/base/testturnserver.h
+++ b/talk/p2p/base/testturnserver.h
@@ -47,8 +47,7 @@
                  const talk_base::SocketAddress& udp_int_addr,
                  const talk_base::SocketAddress& udp_ext_addr)
       : server_(thread) {
-    server_.AddInternalSocket(talk_base::AsyncUDPSocket::Create(
-        thread->socketserver(), udp_int_addr), PROTO_UDP);
+    AddInternalSocket(udp_int_addr, cricket::PROTO_UDP);
     server_.SetExternalSocketFactory(new talk_base::BasicPacketSocketFactory(),
         udp_ext_addr);
     server_.set_realm(kTestRealm);
@@ -62,6 +61,23 @@
 
   TurnServer* server() { return &server_; }
 
+  void AddInternalSocket(const talk_base::SocketAddress& int_addr,
+                         ProtocolType proto) {
+    talk_base::Thread* thread = talk_base::Thread::Current();
+    if (proto == cricket::PROTO_UDP) {
+      server_.AddInternalSocket(talk_base::AsyncUDPSocket::Create(
+          thread->socketserver(), int_addr), proto);
+    } else if (proto == cricket::PROTO_TCP) {
+      // For TCP we need to create a server socket which can listen for incoming
+      // new connections.
+      talk_base::AsyncSocket* socket =
+          thread->socketserver()->CreateAsyncSocket(SOCK_STREAM);
+      socket->Bind(int_addr);
+      socket->Listen(5);
+      server_.AddInternalServerSocket(socket, proto);
+    }
+  }
+
  private:
   // For this test server, succeed if the password is the same as the username.
   // Obviously, do not use this in a production environment.
diff --git a/talk/p2p/base/turnport.cc b/talk/p2p/base/turnport.cc
index 35e51fc..880af839 100644
--- a/talk/p2p/base/turnport.cc
+++ b/talk/p2p/base/turnport.cc
@@ -206,6 +206,14 @@
     return;
   }
 
+  // If protocol family of server address doesn't match with local, return.
+  if (!IsCompatibleAddress(server_address_.address)) {
+    LOG(LS_ERROR) << "Server IP address family does not match with "
+                  << "local host address family type";
+    OnAllocateError();
+    return;
+  }
+
   if (!server_address_.address.port()) {
     // We will set default TURN port, if no port is set in the address.
     server_address_.address.SetPort(TURN_DEFAULT_PORT);
diff --git a/talk/p2p/base/turnport_unittest.cc b/talk/p2p/base/turnport_unittest.cc
index 726175c..11e2213 100644
--- a/talk/p2p/base/turnport_unittest.cc
+++ b/talk/p2p/base/turnport_unittest.cc
@@ -53,11 +53,17 @@
 
 static const SocketAddress kLocalAddr1("11.11.11.11", 0);
 static const SocketAddress kLocalAddr2("22.22.22.22", 0);
+static const SocketAddress kLocalIPv6Addr(
+    "2401:fa00:4:1000:be30:5bff:fee5:c3", 0);
 static const SocketAddress kTurnUdpIntAddr("99.99.99.3",
                                            cricket::TURN_SERVER_PORT);
 static const SocketAddress kTurnTcpIntAddr("99.99.99.4",
                                            cricket::TURN_SERVER_PORT);
 static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0);
+static const SocketAddress kTurnUdpIPv6IntAddr(
+    "2400:4030:1:2c00:be30:abcd:efab:cdef", cricket::TURN_SERVER_PORT);
+static const SocketAddress kTurnUdpIPv6ExtAddr(
+  "2620:0:1000:1b03:2e41:38ff:fea6:f2a4", 0);
 
 static const char kIceUfrag1[] = "TESTICEUFRAG0001";
 static const char kIceUfrag2[] = "TESTICEUFRAG0002";
@@ -71,6 +77,8 @@
     kTurnUdpIntAddr, cricket::PROTO_UDP);
 static const cricket::ProtocolAddress kTurnTcpProtoAddr(
     kTurnTcpIntAddr, cricket::PROTO_TCP);
+static const cricket::ProtocolAddress kTurnUdpIPv6ProtoAddr(
+    kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
 
 class TurnPortTest : public testing::Test,
                      public sigslot::has_slots<> {
@@ -130,9 +138,15 @@
   void CreateTurnPort(const std::string& username,
                       const std::string& password,
                       const cricket::ProtocolAddress& server_address) {
+    CreateTurnPort(kLocalAddr1, username, password, server_address);
+  }
+  void CreateTurnPort(const talk_base::SocketAddress& local_address,
+                      const std::string& username,
+                      const std::string& password,
+                      const cricket::ProtocolAddress& server_address) {
     cricket::RelayCredentials credentials(username, password);
     turn_port_.reset(TurnPort::Create(main_, &socket_factory_, &network_,
-                                 kLocalAddr1.ipaddr(), 0, 0,
+                                 local_address.ipaddr(), 0, 0,
                                  kIceUfrag1, kIcePwd1,
                                  server_address, credentials));
     turn_port_->SignalPortComplete.connect(this,
@@ -265,10 +279,7 @@
 }
 
 TEST_F(TurnPortTest, TestTurnTcpAllocate) {
-  talk_base::AsyncSocket* tcp_server_socket =
-      CreateServerSocket(kTurnTcpIntAddr);
-  turn_server_.server()->AddInternalServerSocket(
-      tcp_server_socket, cricket::PROTO_TCP);
+  turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
   EXPECT_EQ(0, turn_port_->SetOption(talk_base::Socket::OPT_SNDBUF, 10*1024));
   turn_port_->PrepareAddress();
@@ -298,10 +309,7 @@
 
 // Test that we can establish a TCP connection with TURN server.
 TEST_F(TurnPortTest, TestTurnTcpConnection) {
-  talk_base::AsyncSocket* tcp_server_socket =
-      CreateServerSocket(kTurnTcpIntAddr);
-  turn_server_.server()->AddInternalServerSocket(
-      tcp_server_socket, cricket::PROTO_TCP);
+  turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
   TestTurnConnection();
 }
@@ -327,19 +335,44 @@
   TestTurnConnection();
 }
 
-// Do a TURN allocation, establish a connection, and send some data.
+// Do a TURN allocation, establish a UDP connection, and send some data.
 TEST_F(TurnPortTest, TestTurnSendDataTurnUdpToUdp) {
   // Create ports and prepare addresses.
   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
   TestTurnSendData();
 }
 
+// Do a TURN allocation, establish a TCP connection, and send some data.
 TEST_F(TurnPortTest, TestTurnSendDataTurnTcpToUdp) {
-  talk_base::AsyncSocket* tcp_server_socket =
-      CreateServerSocket(kTurnTcpIntAddr);
-  turn_server_.server()->AddInternalServerSocket(
-      tcp_server_socket, cricket::PROTO_TCP);
+  turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
   // Create ports and prepare addresses.
   CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
   TestTurnSendData();
 }
+
+// Test TURN fails to make a connection from IPv6 address to a server which has
+// IPv4 address.
+TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv4) {
+  turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
+  CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword,
+                 kTurnUdpProtoAddr);
+  turn_port_->PrepareAddress();
+  ASSERT_TRUE_WAIT(turn_error_, kTimeout);
+  EXPECT_TRUE(turn_port_->Candidates().empty());
+}
+
+// Test TURN make a connection from IPv6 address to a server which has
+// IPv6 intenal address. But in this test external address is a IPv4 address,
+// hence allocated address will be a IPv4 address.
+TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv6ExtenalIPv4) {
+  turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
+  CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword,
+                 kTurnUdpIPv6ProtoAddr);
+  turn_port_->PrepareAddress();
+  EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+  ASSERT_EQ(1U, turn_port_->Candidates().size());
+  EXPECT_EQ(kTurnUdpExtAddr.ipaddr(),
+            turn_port_->Candidates()[0].address().ipaddr());
+  EXPECT_NE(0, turn_port_->Candidates()[0].address().port());
+}
+
diff --git a/talk/p2p/client/basicportallocator.cc b/talk/p2p/client/basicportallocator.cc
index a728d98..9f10d33 100644
--- a/talk/p2p/client/basicportallocator.cc
+++ b/talk/p2p/client/basicportallocator.cc
@@ -708,7 +708,7 @@
       config_(config),
       state_(kInit),
       flags_(flags),
-      udp_socket_(NULL),
+      udp_socket_(),
       phase_(0) {
 }
 
diff --git a/talk/p2p/client/fakeportallocator.h b/talk/p2p/client/fakeportallocator.h
index 2368948..5375e50 100644
--- a/talk/p2p/client/fakeportallocator.h
+++ b/talk/p2p/client/fakeportallocator.h
@@ -32,7 +32,7 @@
         factory_(factory),
         network_("network", "unittest",
                  talk_base::IPAddress(INADDR_LOOPBACK), 8),
-        port_(NULL), running_(false),
+        port_(), running_(false),
         port_config_count_(0) {
     network_.AddIP(talk_base::IPAddress(INADDR_LOOPBACK));
   }
diff --git a/talk/p2p/client/portallocator_unittest.cc b/talk/p2p/client/portallocator_unittest.cc
index 1ee97f1..6966e44 100644
--- a/talk/p2p/client/portallocator_unittest.cc
+++ b/talk/p2p/client/portallocator_unittest.cc
@@ -50,6 +50,8 @@
 using talk_base::Thread;
 
 static const SocketAddress kClientAddr("11.11.11.11", 0);
+static const SocketAddress kClientIPv6Addr(
+    "2401:fa00:4:1000:be30:5bff:fee5:c3", 0);
 static const SocketAddress kNatAddr("77.77.77.77", talk_base::NAT_SERVER_PORT);
 static const SocketAddress kRemoteClientAddr("22.22.22.22", 0);
 static const SocketAddress kStunAddr("99.99.99.1", cricket::STUN_SERVER_PORT);
@@ -740,6 +742,36 @@
   EXPECT_EQ(1U, candidates_.size());
 }
 
+// This test verifies allocator can use IPv6 addresses along with IPv4.
+TEST_F(PortAllocatorTest, TestEnableIPv6Addresses) {
+  allocator().set_flags(allocator().flags() |
+                        cricket::PORTALLOCATOR_DISABLE_RELAY |
+                        cricket::PORTALLOCATOR_ENABLE_IPV6 |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+                        cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+  AddInterface(kClientIPv6Addr);
+  AddInterface(kClientAddr);
+  allocator_->set_step_delay(cricket::kMinimumStepDelay);
+  EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  ASSERT_EQ_WAIT(4U, ports_.size(), kDefaultAllocationTimeout);
+  EXPECT_EQ(4U, candidates_.size());
+  EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+  EXPECT_PRED5(CheckCandidate, candidates_[0],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp",
+      kClientIPv6Addr);
+  EXPECT_PRED5(CheckCandidate, candidates_[1],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp",
+      kClientAddr);
+  EXPECT_PRED5(CheckCandidate, candidates_[2],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp",
+      kClientIPv6Addr);
+  EXPECT_PRED5(CheckCandidate, candidates_[3],
+      cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp",
+      kClientAddr);
+  EXPECT_EQ(4U, candidates_.size());
+}
+
 // Test that the httpportallocator correctly maintains its lists of stun and
 // relay servers, by never allowing an empty list.
 TEST(HttpPortAllocatorTest, TestHttpPortAllocatorHostLists) {
diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc
index db169be..9c9847f 100644
--- a/talk/session/media/channel.cc
+++ b/talk/session/media/channel.cc
@@ -399,7 +399,6 @@
       writable_(false),
       rtp_ready_to_send_(false),
       rtcp_ready_to_send_(false),
-      optimistic_data_send_(false),
       was_ever_writable_(false),
       local_content_direction_(MD_INACTIVE),
       remote_content_direction_(MD_INACTIVE),
@@ -670,7 +669,7 @@
   // transport.
   TransportChannel* channel = (!rtcp || rtcp_mux_filter_.IsActive()) ?
       transport_channel_ : rtcp_transport_channel_;
-  if (!channel || (!optimistic_data_send_ && !channel->writable())) {
+  if (!channel || !channel->writable()) {
     return false;
   }
 
diff --git a/talk/session/media/channel.h b/talk/session/media/channel.h
index 3a627ed..51fb575 100644
--- a/talk/session/media/channel.h
+++ b/talk/session/media/channel.h
@@ -97,10 +97,6 @@
     return rtcp_transport_channel_;
   }
   bool enabled() const { return enabled_; }
-  // Set to true to have the channel optimistically allow data to be sent even
-  // when the channel isn't fully writable.
-  void set_optimistic_data_send(bool value) { optimistic_data_send_ = value; }
-  bool optimistic_data_send() const { return optimistic_data_send_; }
 
   // This function returns true if we are using SRTP.
   bool secure() const { return srtp_filter_.IsActive(); }
@@ -362,7 +358,6 @@
   bool writable_;
   bool rtp_ready_to_send_;
   bool rtcp_ready_to_send_;
-  bool optimistic_data_send_;
   bool was_ever_writable_;
   MediaContentDirection local_content_direction_;
   MediaContentDirection remote_content_direction_;
diff --git a/talk/session/media/channel_unittest.cc b/talk/session/media/channel_unittest.cc
index 24ece06..0273907 100644
--- a/talk/session/media/channel_unittest.cc
+++ b/talk/session/media/channel_unittest.cc
@@ -496,11 +496,6 @@
     // overridden in specialized classes
   }
 
-  void SetOptimisticDataSend(bool optimistic_data_send) {
-    channel1_->set_optimistic_data_send(optimistic_data_send);
-    channel2_->set_optimistic_data_send(optimistic_data_send);
-  }
-
   // Creates a cricket::SessionDescription with one MediaContent and one stream.
   // kPcmuCodec is used as audio codec and kH264Codec is used as video codec.
   cricket::SessionDescription* CreateSessionDescriptionWithStream(uint32 ssrc) {
@@ -1394,19 +1389,8 @@
     EXPECT_TRUE(CheckNoRtp1());
     EXPECT_TRUE(CheckNoRtp2());
 
-    // Lose writability, with optimistic send
-    SetOptimisticDataSend(true);
+    // Lose writability, which should fail.
     GetTransport1()->SetWritable(false);
-    EXPECT_TRUE(media_channel1_->sending());
-    EXPECT_TRUE(SendRtp1());
-    EXPECT_TRUE(SendRtp2());
-    EXPECT_TRUE(CheckRtp1());
-    EXPECT_TRUE(CheckRtp2());
-    EXPECT_TRUE(CheckNoRtp1());
-    EXPECT_TRUE(CheckNoRtp2());
-
-    // Check again with optimistic send off, which should fail.
-    SetOptimisticDataSend(false);
     EXPECT_FALSE(SendRtp1());
     EXPECT_TRUE(SendRtp2());
     EXPECT_TRUE(CheckRtp1());
@@ -1426,13 +1410,7 @@
     GetTransport1()->SetDestination(NULL);
     EXPECT_TRUE(media_channel1_->sending());
 
-    // Should fail regardless of optimistic send at this point.
-    SetOptimisticDataSend(true);
-    EXPECT_FALSE(SendRtp1());
-    EXPECT_TRUE(SendRtp2());
-    EXPECT_TRUE(CheckRtp1());
-    EXPECT_TRUE(CheckNoRtp2());
-    SetOptimisticDataSend(false);
+    // Should fail also.
     EXPECT_FALSE(SendRtp1());
     EXPECT_TRUE(SendRtp2());
     EXPECT_TRUE(CheckRtp1());
diff --git a/talk/session/media/mediasession.cc b/talk/session/media/mediasession.cc
index ea23591..ae3fb57 100644
--- a/talk/session/media/mediasession.cc
+++ b/talk/session/media/mediasession.cc
@@ -46,7 +46,7 @@
 #ifdef HAVE_SCTP
 #include "talk/media/sctp/sctpdataengine.h"
 #else
-static const uint32 kMaxSctpSid = USHRT_MAX;
+static const uint32 kMaxSctpSid = 1023;
 #endif
 
 namespace {
diff --git a/talk/session/media/mediasession_unittest.cc b/talk/session/media/mediasession_unittest.cc
index 850d67f..ceb2bcd 100644
--- a/talk/session/media/mediasession_unittest.cc
+++ b/talk/session/media/mediasession_unittest.cc
@@ -882,8 +882,8 @@
   answer_opts.data_channel_type = cricket::DCT_RTP;
   offer_opts.data_channel_type = cricket::DCT_RTP;
 
-  talk_base::scoped_ptr<SessionDescription> offer(NULL);
-  talk_base::scoped_ptr<SessionDescription> answer(NULL);
+  talk_base::scoped_ptr<SessionDescription> offer;
+  talk_base::scoped_ptr<SessionDescription> answer;
 
   offer_opts.rtcp_mux_enabled = true;
   answer_opts.rtcp_mux_enabled = true;
diff --git a/talk/sound/alsasoundsystem.cc b/talk/sound/alsasoundsystem.cc
index de9e2d6..7a8857c 100644
--- a/talk/sound/alsasoundsystem.cc
+++ b/talk/sound/alsasoundsystem.cc
@@ -342,7 +342,7 @@
   }
 
   AlsaStream stream_;
-  talk_base::scoped_array<char> buffer_;
+  talk_base::scoped_ptr<char[]> buffer_;
   size_t buffer_size_;
 
   DISALLOW_COPY_AND_ASSIGN(AlsaInputStream);
diff --git a/talk/xmllite/xmlbuilder.cc b/talk/xmllite/xmlbuilder.cc
index 486b6d5..f71e542 100644
--- a/talk/xmllite/xmlbuilder.cc
+++ b/talk/xmllite/xmlbuilder.cc
@@ -37,7 +37,7 @@
 
 XmlBuilder::XmlBuilder() :
   pelCurrent_(NULL),
-  pelRoot_(NULL),
+  pelRoot_(),
   pvParents_(new std::vector<XmlElement *>()) {
 }
 
diff --git a/talk/xmpp/xmppclient.cc b/talk/xmpp/xmppclient.cc
index 9c49a9c..8927dad 100644
--- a/talk/xmpp/xmppclient.cc
+++ b/talk/xmpp/xmppclient.cc
@@ -46,8 +46,8 @@
 
   explicit Private(XmppClient* client) :
     client_(client),
-    socket_(NULL),
-    engine_(NULL),
+    socket_(),
+    engine_(),
     proxy_port_(0),
     pre_engine_error_(XmppEngine::ERROR_NONE),
     pre_engine_subcode_(0),
diff --git a/talk/xmpp/xmppengineimpl.cc b/talk/xmpp/xmppengineimpl.cc
index 8bcea02..d4c9c7d 100644
--- a/talk/xmpp/xmppengineimpl.cc
+++ b/talk/xmpp/xmppengineimpl.cc
@@ -58,12 +58,12 @@
       encrypted_(false),
       error_code_(ERROR_NONE),
       subcode_(0),
-      stream_error_(NULL),
+      stream_error_(),
       raised_reset_(false),
       output_handler_(NULL),
       session_handler_(NULL),
       iq_entries_(new IqEntryVector()),
-      sasl_handler_(NULL),
+      sasl_handler_(),
       output_(new std::stringstream()) {
   for (int i = 0; i < HL_COUNT; i+= 1) {
     stanza_handlers_[i].reset(new StanzaHandlerVector());
diff --git a/talk/xmpp/xmpplogintask.cc b/talk/xmpp/xmpplogintask.cc
index eec943b..b3a2047 100644
--- a/talk/xmpp/xmpplogintask.cc
+++ b/talk/xmpp/xmpplogintask.cc
@@ -66,11 +66,11 @@
   pelStanza_(NULL),
   isStart_(false),
   iqId_(STR_EMPTY),
-  pelFeatures_(NULL),
+  pelFeatures_(),
   fullJid_(STR_EMPTY),
   streamId_(STR_EMPTY),
   pvecQueuedStanzas_(new std::vector<XmlElement *>()),
-  sasl_mech_(NULL) {
+  sasl_mech_() {
 }
 
 XmppLoginTask::~XmppLoginTask() {