Update libjingle to 61168196

R=mallinath@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5502 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java b/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java
index 2a06ff4..3bf128e 100644
--- a/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java
+++ b/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java
@@ -668,7 +668,7 @@
     offeringExpectations.expectMessage(expectedBinaryMessage, true);
     assertTrue(answeringExpectations.dataChannel.send(
         new DataChannel.Buffer(
-            ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 } ), true)));
+            ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 }), true)));
     offeringExpectations.waitForAllExpectationsToBeSatisfied();
 
     offeringExpectations.expectStateChange(DataChannel.State.CLOSING);
diff --git a/talk/app/webrtc/localaudiosource.cc b/talk/app/webrtc/localaudiosource.cc
index 7ac59fc..ab9ae4f 100644
--- a/talk/app/webrtc/localaudiosource.cc
+++ b/talk/app/webrtc/localaudiosource.cc
@@ -70,6 +70,9 @@
       options->experimental_agc.Set(value);
     else if (iter->key == MediaConstraintsInterface::kNoiseSuppression)
       options->noise_suppression.Set(value);
+    else if (iter->key ==
+          MediaConstraintsInterface::kExperimentalNoiseSuppression)
+      options->experimental_ns.Set(value);
     else if (iter->key == MediaConstraintsInterface::kHighpassFilter)
       options->highpass_filter.Set(value);
     else if (iter->key == MediaConstraintsInterface::kTypingNoiseDetection)
diff --git a/talk/app/webrtc/mediaconstraintsinterface.cc b/talk/app/webrtc/mediaconstraintsinterface.cc
index 2512932..63d2be0 100644
--- a/talk/app/webrtc/mediaconstraintsinterface.cc
+++ b/talk/app/webrtc/mediaconstraintsinterface.cc
@@ -56,6 +56,8 @@
     "googAutoGainControl2";
 const char MediaConstraintsInterface::kNoiseSuppression[] =
     "googNoiseSuppression";
+const char MediaConstraintsInterface::kExperimentalNoiseSuppression[] =
+    "googNoiseSuppression2";
 const char MediaConstraintsInterface::kHighpassFilter[] =
     "googHighpassFilter";
 const char MediaConstraintsInterface::kTypingNoiseDetection[] =
diff --git a/talk/app/webrtc/mediaconstraintsinterface.h b/talk/app/webrtc/mediaconstraintsinterface.h
index 7a207e4..fae065c 100644
--- a/talk/app/webrtc/mediaconstraintsinterface.h
+++ b/talk/app/webrtc/mediaconstraintsinterface.h
@@ -79,6 +79,7 @@
   static const char kAutoGainControl[];  // googAutoGainControl
   static const char kExperimentalAutoGainControl[];  // googAutoGainControl2
   static const char kNoiseSuppression[];  // googNoiseSuppression
+  static const char kExperimentalNoiseSuppression[];  // googNoiseSuppression2
   static const char kHighpassFilter[];  // googHighpassFilter
   static const char kTypingNoiseDetection[];  // googTypingNoiseDetection
   static const char kAudioMirroring[];  // googAudioMirroring
diff --git a/talk/app/webrtc/mediastreamhandler.cc b/talk/app/webrtc/mediastreamhandler.cc
index 932d55e..a94eef3 100644
--- a/talk/app/webrtc/mediastreamhandler.cc
+++ b/talk/app/webrtc/mediastreamhandler.cc
@@ -114,7 +114,7 @@
   // adapter owned by this class.
   cricket::AudioRenderer* renderer = audio_track_->GetRenderer() ?
       audio_track_->GetRenderer() : sink_adapter_.get();
-  ASSERT(renderer);
+  ASSERT(renderer != NULL);
   provider_->SetAudioSend(ssrc(), audio_track_->enabled(), options, renderer);
 }
 
diff --git a/talk/app/webrtc/peerconnection_unittest.cc b/talk/app/webrtc/peerconnection_unittest.cc
index edf79f5..1b6d73d 100644
--- a/talk/app/webrtc/peerconnection_unittest.cc
+++ b/talk/app/webrtc/peerconnection_unittest.cc
@@ -1269,7 +1269,12 @@
 }
 
 // This test sets up a call between two parties with audio, video and data.
+// TODO(jiayl): fix the flakiness on Windows and reenable. Issue 2891.
+#if defined(WIN32)
+TEST_F(JsepPeerConnectionP2PTestClient, DISABLED_LocalP2PTestDataChannel) {
+#else
 TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestDataChannel) {
+#endif
   FakeConstraints setup_constraints;
   setup_constraints.SetAllowRtpDataChannels();
   ASSERT_TRUE(CreateTestClients(&setup_constraints, &setup_constraints));
diff --git a/talk/app/webrtc/statscollector.cc b/talk/app/webrtc/statscollector.cc
index 7e1e7ee..2efc11b 100644
--- a/talk/app/webrtc/statscollector.cc
+++ b/talk/app/webrtc/statscollector.cc
@@ -83,6 +83,8 @@
     "googFingerprintAlgorithm";
 const char StatsReport::kStatsValueNameFirsReceived[] = "googFirsReceived";
 const char StatsReport::kStatsValueNameFirsSent[] = "googFirsSent";
+const char StatsReport::kStatsValueNameFrameHeightInput[] =
+    "googFrameHeightInput";
 const char StatsReport::kStatsValueNameFrameHeightReceived[] =
     "googFrameHeightReceived";
 const char StatsReport::kStatsValueNameFrameHeightSent[] =
@@ -104,6 +106,8 @@
 
 const char StatsReport::kStatsValueNameFrameRateInput[] = "googFrameRateInput";
 const char StatsReport::kStatsValueNameFrameRateSent[] = "googFrameRateSent";
+const char StatsReport::kStatsValueNameFrameWidthInput[] =
+    "googFrameWidthInput";
 const char StatsReport::kStatsValueNameFrameWidthReceived[] =
     "googFrameWidthReceived";
 const char StatsReport::kStatsValueNameFrameWidthSent[] = "googFrameWidthSent";
@@ -117,6 +121,8 @@
     "googLocalCertificateId";
 const char StatsReport::kStatsValueNameNacksReceived[] = "googNacksReceived";
 const char StatsReport::kStatsValueNameNacksSent[] = "googNacksSent";
+const char StatsReport::kStatsValueNameNetEqExpandRate[] =
+    "googNetEqExpandRate";
 const char StatsReport::kStatsValueNamePacketsReceived[] = "packetsReceived";
 const char StatsReport::kStatsValueNamePacketsSent[] = "packetsSent";
 const char StatsReport::kStatsValueNamePacketsLost[] = "packetsLost";
@@ -215,6 +221,8 @@
                    info.bytes_rcvd);
   report->AddValue(StatsReport::kStatsValueNameJitterReceived,
                    info.jitter_ms);
+  report->AddValue(StatsReport::kStatsValueNameNetEqExpandRate,
+                   talk_base::ToString<float>(info.expand_rate));
   report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
                    info.packets_rcvd);
   report->AddValue(StatsReport::kStatsValueNamePacketsLost,
@@ -295,10 +303,14 @@
                    info.firs_rcvd);
   report->AddValue(StatsReport::kStatsValueNameNacksReceived,
                    info.nacks_rcvd);
+  report->AddValue(StatsReport::kStatsValueNameFrameWidthInput,
+                   info.input_frame_width);
+  report->AddValue(StatsReport::kStatsValueNameFrameHeightInput,
+                   info.input_frame_height);
   report->AddValue(StatsReport::kStatsValueNameFrameWidthSent,
-                   info.frame_width);
+                   info.send_frame_width);
   report->AddValue(StatsReport::kStatsValueNameFrameHeightSent,
-                   info.frame_height);
+                   info.send_frame_height);
   report->AddValue(StatsReport::kStatsValueNameFrameRateInput,
                    info.framerate_input);
   report->AddValue(StatsReport::kStatsValueNameFrameRateSent,
diff --git a/talk/app/webrtc/statstypes.h b/talk/app/webrtc/statstypes.h
index 6890f9e..9110da3 100644
--- a/talk/app/webrtc/statstypes.h
+++ b/talk/app/webrtc/statstypes.h
@@ -143,6 +143,7 @@
   static const char kStatsValueNameEchoReturnLossEnhancement[];
   static const char kStatsValueNameFirsReceived[];
   static const char kStatsValueNameFirsSent[];
+  static const char kStatsValueNameFrameHeightInput[];
   static const char kStatsValueNameFrameHeightReceived[];
   static const char kStatsValueNameFrameHeightSent[];
   static const char kStatsValueNameFrameRateReceived[];
@@ -157,11 +158,13 @@
   static const char kStatsValueNameRenderDelayMs[];
   static const char kStatsValueNameFrameRateInput[];
   static const char kStatsValueNameFrameRateSent[];
+  static const char kStatsValueNameFrameWidthInput[];
   static const char kStatsValueNameFrameWidthReceived[];
   static const char kStatsValueNameFrameWidthSent[];
   static const char kStatsValueNameJitterReceived[];
   static const char kStatsValueNameNacksReceived[];
   static const char kStatsValueNameNacksSent[];
+  static const char kStatsValueNameNetEqExpandRate[];
   static const char kStatsValueNameRtt[];
   static const char kStatsValueNameAvailableSendBandwidth[];
   static const char kStatsValueNameAvailableReceiveBandwidth[];
diff --git a/talk/base/asyncinvoker-inl.h b/talk/base/asyncinvoker-inl.h
new file mode 100644
index 0000000..c4afd3a
--- /dev/null
+++ b/talk/base/asyncinvoker-inl.h
@@ -0,0 +1,101 @@
+/*
+ * libjingle
+ * Copyright 2014 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.
+ */
+
+#ifndef TALK_BASE_ASYNCINVOKER_INL_H_
+#define TALK_BASE_ASYNCINVOKER_INL_H_
+
+#include "talk/base/criticalsection.h"
+#include "talk/base/messagehandler.h"
+#include "talk/base/sigslot.h"
+#include "talk/base/thread.h"
+
+namespace talk_base {
+
+// Helper class for AsyncInvoker. Runs a functor on a message queue or thread
+// and doesn't execute the callback when finished if the calling thread ends.
+template <class ReturnT, class FunctorT>
+class AsyncFunctorMessageHandler
+    : public FunctorMessageHandler<ReturnT, FunctorT>,
+      public sigslot::has_slots<> {
+  typedef AsyncFunctorMessageHandler<ReturnT, FunctorT> ThisT;
+ public:
+  explicit AsyncFunctorMessageHandler(const FunctorT& functor)
+      : FunctorMessageHandler<ReturnT, FunctorT>(functor),
+        thread_(Thread::Current()),
+        shutting_down_(false) {
+    thread_->SignalQueueDestroyed.connect(this, &ThisT::OnThreadDestroyed);
+  }
+
+  virtual ~AsyncFunctorMessageHandler() {
+    CritScope cs(&running_crit_);
+    shutting_down_ = true;
+  }
+
+  virtual void OnMessage(Message* msg) {
+    CritScope cs(&running_crit_);
+    if (!shutting_down_) {
+      FunctorMessageHandler<ReturnT, FunctorT>::OnMessage(msg);
+    }
+  }
+
+  // Returns the thread that initiated the async call.
+  Thread* thread() const { return thread_; }
+
+  // Wraps a callback so that it won't execute if |thread_| goes away.
+  void WrapCallback(Callback0<void> cb) {
+    this->SetCallback(
+        Callback0<void>(Bind(&ThisT::MaybeRunCallback, this, cb)));
+  }
+
+ private:
+  void OnThreadDestroyed() {
+    CritScope cs(&thread_crit_);
+    thread_ = NULL;
+    this->SetCallback(Callback0<void>());  // Clear out the callback.
+  }
+
+  void MaybeRunCallback(Callback0<void> cb) {
+#ifdef _DEBUG
+    ASSERT(running_crit_.CurrentThreadIsOwner());
+#endif
+    CritScope cs(&thread_crit_);
+    if (thread_ && !shutting_down_) {
+      cb();
+    }
+  }
+
+  FunctorT functor_;
+  Thread* thread_;
+  CriticalSection thread_crit_;
+  CriticalSection running_crit_;
+  bool shutting_down_;
+};
+
+}  // namespace talk_base
+
+
+#endif  // TALK_BASE_ASYNCINVOKER_INL_H_
diff --git a/talk/base/asyncinvoker.cc b/talk/base/asyncinvoker.cc
new file mode 100644
index 0000000..63171be
--- /dev/null
+++ b/talk/base/asyncinvoker.cc
@@ -0,0 +1,78 @@
+/*
+ * libjingle
+ * Copyright 2014 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.
+ */
+
+#include "talk/base/asyncinvoker.h"
+
+namespace talk_base {
+
+// Synchronously execute all outstanding calls we own pending
+// on |thread|. Optionally filter by message id.
+void AsyncInvoker::Flush(Thread* thread, uint32 id /*= MQID_ANY*/) {
+  // Run this on |thread| to reduce the number of context switches.
+  if (Thread::Current() != thread) {
+    thread->Invoke<void>(Bind(&AsyncInvoker::Flush, this, thread, id));
+    return;
+  }
+
+  // Make a copy of handlers_, since it'll be modified by
+  // callbacks to RemoveHandler when each is done executing.
+  crit_.Enter();
+  std::vector<MessageHandler*> handlers(handlers_.collection());
+  crit_.Leave();
+  MessageList removed;
+  for (size_t i = 0; i < handlers.size(); ++i) {
+    removed.clear();
+    thread->Clear(handlers[i], id, &removed);
+    if (!removed.empty()) {
+      // Since each message gets its own handler with AsyncInvoker,
+      // we expect a maximum of one removed.
+      ASSERT(removed.size() == 1);
+      // This handler was pending on this thread, so run it now.
+      const Message& msg = removed.front();
+      thread->Send(msg.phandler,
+                   msg.message_id,
+                   msg.pdata);
+    }
+  }
+}
+
+void AsyncInvoker::InvokeHandler(Thread* thread, MessageHandler* handler,
+                                 uint32 id) {
+  {
+    CritScope cs(&crit_);
+    handlers_.PushBack(handler);
+  }
+  thread->Post(handler, id);
+}
+
+void AsyncInvoker::RemoveHandler(MessageHandler* handler) {
+  CritScope cs(&crit_);
+  handlers_.Remove(handler);
+  delete handler;
+}
+
+}  // namespace talk_base
diff --git a/talk/base/asyncinvoker.h b/talk/base/asyncinvoker.h
new file mode 100644
index 0000000..fabdbdc
--- /dev/null
+++ b/talk/base/asyncinvoker.h
@@ -0,0 +1,167 @@
+/*
+ * libjingle
+ * Copyright 2014 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.
+ */
+
+#ifndef TALK_BASE_ASYNCINVOKER_H_
+#define TALK_BASE_ASYNCINVOKER_H_
+
+#include "talk/base/asyncinvoker-inl.h"
+#include "talk/base/bind.h"
+#include "talk/base/scopedptrcollection.h"
+#include "talk/base/thread.h"
+
+namespace talk_base {
+
+// Invokes function objects (aka functors) asynchronously on a Thread, and
+// owns the lifetime of calls (ie, when this object is destroyed, calls in
+// flight are cancelled). AsyncInvoker can optionally execute a user-specified
+// function when the asynchronous call is complete, or operates in
+// fire-and-forget mode otherwise.
+//
+// AsyncInvoker does not own the thread it calls functors on.
+//
+// A note about async calls and object lifetimes: users should
+// be mindful of object lifetimes when calling functions asynchronously and
+// ensure objects used by the function _cannot_ be deleted between the
+// invocation and execution of the functor. AsyncInvoker is designed to
+// help: any calls in flight will be cancelled when the AsyncInvoker used to
+// make the call is destructed, and any calls executing will be allowed to
+// complete before AsyncInvoker destructs.
+//
+// The easiest way to ensure lifetimes are handled correctly is to create a
+// class that owns the Thread and AsyncInvoker objects, and then call its
+// methods asynchronously as needed.
+//
+// Example:
+//   class MyClass {
+//    public:
+//     void FireAsyncTaskWithResult(Thread* thread, int x) {
+//       // Specify a callback to get the result upon completion.
+//       invoker_.AsyncInvoke<int>(
+//           thread, Bind(&MyClass::AsyncTaskWithResult, this, x),
+//           &MyClass::OnTaskComplete, this);
+//     }
+//     void FireAnotherAsyncTask(Thread* thread) {
+//       // No callback specified means fire-and-forget.
+//       invoker_.AsyncInvoke<void>(
+//           thread, Bind(&MyClass::AnotherAsyncTask, this));
+//
+//    private:
+//     int AsyncTaskWithResult(int x) {
+//       // Some long running process...
+//       return x * x;
+//     }
+//     void AnotherAsyncTask() {
+//       // Some other long running process...
+//     }
+//     void OnTaskComplete(int result) { result_ = result; }
+//
+//     AsyncInvoker invoker_;
+//     int result_;
+//   };
+class AsyncInvoker {
+ public:
+  // Call |functor| asynchronously on |thread|, with no callback upon
+  // completion. Returns immediately.
+  template <class ReturnT, class FunctorT>
+  void AsyncInvoke(Thread* thread,
+                   const FunctorT& functor,
+                   uint32 id = 0) {
+    FunctorMessageHandler<ReturnT, FunctorT>* handler =
+        new FunctorMessageHandler<ReturnT, FunctorT>(functor);
+    handler->SetCallback(Bind(&AsyncInvoker::RemoveHandler, this, handler));
+    InvokeHandler(thread, handler, id);
+  }
+
+  // Call |functor| asynchronously on |thread|, calling |callback| when done.
+  template <class ReturnT, class FunctorT, class HostT>
+  void AsyncInvoke(Thread* thread,
+                   const FunctorT& functor,
+                   void (HostT::*callback)(ReturnT),
+                   HostT* callback_host,
+                   uint32 id = 0) {
+    AsyncFunctorMessageHandler<ReturnT, FunctorT>* handler =
+        new AsyncFunctorMessageHandler<ReturnT, FunctorT>(functor);
+    handler->WrapCallback(
+        Bind(&AsyncInvoker::OnAsyncCallCompleted<ReturnT, FunctorT, HostT>,
+             this, handler, callback, callback_host));
+    InvokeHandler(thread, handler, id);
+  }
+
+  // Call |functor| asynchronously on |thread|, calling |callback| when done.
+  // Overloaded for void return.
+  template <class ReturnT, class FunctorT, class HostT>
+  void AsyncInvoke(Thread* thread,
+                   const FunctorT& functor,
+                   void (HostT::*callback)(),
+                   HostT* callback_host,
+                   uint32 id = 0) {
+    AsyncFunctorMessageHandler<void, FunctorT>* handler =
+        new AsyncFunctorMessageHandler<ReturnT, FunctorT>(functor);
+    handler->WrapCallback(
+        Bind(&AsyncInvoker::OnAsyncVoidCallCompleted<FunctorT, HostT>,
+             this, handler, callback, callback_host));
+    InvokeHandler(thread, handler, id);
+  }
+
+  // Synchronously execute on |thread| all outstanding calls we own
+  // that are pending on |thread|, and wait for calls to complete
+  // before returning. Optionally filter by message id.
+  // The destructor will not wait for outstanding calls, so if that
+  // behavior is desired, call Flush() before destroying this object.
+  void Flush(Thread* thread, uint32 id = MQID_ANY);
+
+ private:
+  void InvokeHandler(Thread* thread, MessageHandler* handler, uint32 id);
+  void RemoveHandler(MessageHandler* handler);
+
+  template <class ReturnT, class FunctorT, class HostT>
+  void OnAsyncCallCompleted(
+      AsyncFunctorMessageHandler<ReturnT, FunctorT>* handler,
+      void (HostT::*callback)(ReturnT),
+      HostT* callback_host) {
+    AsyncInvoke<void>(handler->thread(),
+                Bind(callback, callback_host, handler->result()));
+    RemoveHandler(handler);
+  }
+
+  template <class FunctorT, class HostT>
+  void OnAsyncVoidCallCompleted(
+      AsyncFunctorMessageHandler<void, FunctorT>* handler,
+      void (HostT::*callback)(),
+      HostT* callback_host) {
+    AsyncInvoke<void>(handler->thread(), Bind(callback, callback_host));
+    RemoveHandler(handler);
+  }
+
+  CriticalSection crit_;
+  ScopedPtrCollection<MessageHandler> handlers_;
+};
+
+}  // namespace talk_base
+
+
+#endif  // TALK_BASE_ASYNCINVOKER_H_
diff --git a/talk/base/bind.h b/talk/base/bind.h
index 622cc67..5b4eaac 100644
--- a/talk/base/bind.h
+++ b/talk/base/bind.h
@@ -84,6 +84,18 @@
   ObjectT* object_;
 };
 
+template <class FunctorT, class R>
+class Functor0 {
+ public:
+  explicit Functor0(const FunctorT& functor)
+      : functor_(functor) {}
+  R operator()() const {
+    return functor_(); }
+ private:
+  FunctorT functor_;
+};
+
+
 #define FP_T(x) R (ObjectT::*x)()
 
 template <class ObjectT, class R>
@@ -104,6 +116,16 @@
 }
 
 #undef FP_T
+#define FP_T(x) R (*x)()
+
+template <class R>
+Functor0<FP_T(NONAME), R>
+Bind(FP_T(function)) {
+  return Functor0<FP_T(NONAME), R>(
+      function);
+}
+
+#undef FP_T
 
 template <class ObjectT, class MethodT, class R,
           class P1>
@@ -121,6 +143,21 @@
   P1 p1_;
 };
 
+template <class FunctorT, class R,
+          class P1>
+class Functor1 {
+ public:
+  Functor1(const FunctorT& functor, P1 p1)
+      : functor_(functor),
+      p1_(p1) {}
+  R operator()() const {
+    return functor_(p1_); }
+ private:
+  FunctorT functor_;
+  P1 p1_;
+};
+
+
 #define FP_T(x) R (ObjectT::*x)(P1)
 
 template <class ObjectT, class R,
@@ -145,6 +182,18 @@
 }
 
 #undef FP_T
+#define FP_T(x) R (*x)(P1)
+
+template <class R,
+          class P1>
+Functor1<FP_T(NONAME), R, P1>
+Bind(FP_T(function),
+     typename detail::identity<P1>::type p1) {
+  return Functor1<FP_T(NONAME), R, P1>(
+      function, p1);
+}
+
+#undef FP_T
 
 template <class ObjectT, class MethodT, class R,
           class P1,
@@ -166,6 +215,24 @@
   P2 p2_;
 };
 
+template <class FunctorT, class R,
+          class P1,
+          class P2>
+class Functor2 {
+ public:
+  Functor2(const FunctorT& functor, P1 p1, P2 p2)
+      : functor_(functor),
+      p1_(p1),
+      p2_(p2) {}
+  R operator()() const {
+    return functor_(p1_, p2_); }
+ private:
+  FunctorT functor_;
+  P1 p1_;
+  P2 p2_;
+};
+
+
 #define FP_T(x) R (ObjectT::*x)(P1, P2)
 
 template <class ObjectT, class R,
@@ -194,6 +261,20 @@
 }
 
 #undef FP_T
+#define FP_T(x) R (*x)(P1, P2)
+
+template <class R,
+          class P1,
+          class P2>
+Functor2<FP_T(NONAME), R, P1, P2>
+Bind(FP_T(function),
+     typename detail::identity<P1>::type p1,
+     typename detail::identity<P2>::type p2) {
+  return Functor2<FP_T(NONAME), R, P1, P2>(
+      function, p1, p2);
+}
+
+#undef FP_T
 
 template <class ObjectT, class MethodT, class R,
           class P1,
@@ -219,6 +300,27 @@
   P3 p3_;
 };
 
+template <class FunctorT, class R,
+          class P1,
+          class P2,
+          class P3>
+class Functor3 {
+ public:
+  Functor3(const FunctorT& functor, P1 p1, P2 p2, P3 p3)
+      : functor_(functor),
+      p1_(p1),
+      p2_(p2),
+      p3_(p3) {}
+  R operator()() const {
+    return functor_(p1_, p2_, p3_); }
+ private:
+  FunctorT functor_;
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+};
+
+
 #define FP_T(x) R (ObjectT::*x)(P1, P2, P3)
 
 template <class ObjectT, class R,
@@ -251,6 +353,22 @@
 }
 
 #undef FP_T
+#define FP_T(x) R (*x)(P1, P2, P3)
+
+template <class R,
+          class P1,
+          class P2,
+          class P3>
+Functor3<FP_T(NONAME), R, P1, P2, P3>
+Bind(FP_T(function),
+     typename detail::identity<P1>::type p1,
+     typename detail::identity<P2>::type p2,
+     typename detail::identity<P3>::type p3) {
+  return Functor3<FP_T(NONAME), R, P1, P2, P3>(
+      function, p1, p2, p3);
+}
+
+#undef FP_T
 
 template <class ObjectT, class MethodT, class R,
           class P1,
@@ -280,6 +398,30 @@
   P4 p4_;
 };
 
+template <class FunctorT, class R,
+          class P1,
+          class P2,
+          class P3,
+          class P4>
+class Functor4 {
+ public:
+  Functor4(const FunctorT& functor, P1 p1, P2 p2, P3 p3, P4 p4)
+      : functor_(functor),
+      p1_(p1),
+      p2_(p2),
+      p3_(p3),
+      p4_(p4) {}
+  R operator()() const {
+    return functor_(p1_, p2_, p3_, p4_); }
+ private:
+  FunctorT functor_;
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+};
+
+
 #define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4)
 
 template <class ObjectT, class R,
@@ -316,6 +458,24 @@
 }
 
 #undef FP_T
+#define FP_T(x) R (*x)(P1, P2, P3, P4)
+
+template <class R,
+          class P1,
+          class P2,
+          class P3,
+          class P4>
+Functor4<FP_T(NONAME), R, P1, P2, P3, P4>
+Bind(FP_T(function),
+     typename detail::identity<P1>::type p1,
+     typename detail::identity<P2>::type p2,
+     typename detail::identity<P3>::type p3,
+     typename detail::identity<P4>::type p4) {
+  return Functor4<FP_T(NONAME), R, P1, P2, P3, P4>(
+      function, p1, p2, p3, p4);
+}
+
+#undef FP_T
 
 template <class ObjectT, class MethodT, class R,
           class P1,
@@ -349,6 +509,33 @@
   P5 p5_;
 };
 
+template <class FunctorT, class R,
+          class P1,
+          class P2,
+          class P3,
+          class P4,
+          class P5>
+class Functor5 {
+ public:
+  Functor5(const FunctorT& functor, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
+      : functor_(functor),
+      p1_(p1),
+      p2_(p2),
+      p3_(p3),
+      p4_(p4),
+      p5_(p5) {}
+  R operator()() const {
+    return functor_(p1_, p2_, p3_, p4_, p5_); }
+ private:
+  FunctorT functor_;
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+  P5 p5_;
+};
+
+
 #define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4, P5)
 
 template <class ObjectT, class R,
@@ -389,6 +576,26 @@
 }
 
 #undef FP_T
+#define FP_T(x) R (*x)(P1, P2, P3, P4, P5)
+
+template <class R,
+          class P1,
+          class P2,
+          class P3,
+          class P4,
+          class P5>
+Functor5<FP_T(NONAME), R, P1, P2, P3, P4, P5>
+Bind(FP_T(function),
+     typename detail::identity<P1>::type p1,
+     typename detail::identity<P2>::type p2,
+     typename detail::identity<P3>::type p3,
+     typename detail::identity<P4>::type p4,
+     typename detail::identity<P5>::type p5) {
+  return Functor5<FP_T(NONAME), R, P1, P2, P3, P4, P5>(
+      function, p1, p2, p3, p4, p5);
+}
+
+#undef FP_T
 
 }  // namespace talk_base
 
diff --git a/talk/base/bind.h.pump b/talk/base/bind.h.pump
index 7f4c39e..2ebb895 100644
--- a/talk/base/bind.h.pump
+++ b/talk/base/bind.h.pump
@@ -91,6 +91,24 @@
 
 };
 
+template <class FunctorT, class R$for j [[,
+          class P$j]]>
+class Functor$i {
+ public:
+  $if i == 0 [[explicit ]]
+Functor$i(const FunctorT& functor$for j [[, P$j p$j]])
+      : functor_(functor)$for j [[,
+      p$(j)_(p$j)]] {}
+  R operator()() const {
+    return functor_($for j , [[p$(j)_]]); }
+ private:
+  FunctorT functor_;$for j [[
+
+  P$j p$(j)_;]]
+
+};
+
+
 #define FP_T(x) R (ObjectT::*x)($for j , [[P$j]])
 
 template <class ObjectT, class R$for j [[,
@@ -115,6 +133,18 @@
 }
 
 #undef FP_T
+#define FP_T(x) R (*x)($for j , [[P$j]])
+
+template <class R$for j [[,
+          class P$j]]>
+Functor$i<FP_T(NONAME), R$for j [[, P$j]]>
+Bind(FP_T(function)$for j [[,
+     typename detail::identity<P$j>::type p$j]]) {
+  return Functor$i<FP_T(NONAME), R$for j [[, P$j]]>(
+      function$for j [[, p$j]]);
+}
+
+#undef FP_T
 
 ]]
 
diff --git a/talk/base/bind_unittest.cc b/talk/base/bind_unittest.cc
index 81bbddd..78ac278 100644
--- a/talk/base/bind_unittest.cc
+++ b/talk/base/bind_unittest.cc
@@ -43,6 +43,10 @@
   mutable int call_count;
 };
 
+int Return42() { return 42; }
+int Negate(int a) { return -a; }
+int Multiply(int a, int b) { return a * b; }
+
 }  // namespace
 
 TEST(BindTest, BindToMethod) {
@@ -71,4 +75,10 @@
   EXPECT_EQ(8, object.call_count);
 }
 
+TEST(BindTest, BindToFunction) {
+  EXPECT_EQ(42, Bind(&Return42)());
+  EXPECT_EQ(3, Bind(&Negate, -3)());
+  EXPECT_EQ(56, Bind(&Multiply, 8, 7)());
+}
+
 }  // namespace talk_base
diff --git a/talk/base/callback.h b/talk/base/callback.h
new file mode 100644
index 0000000..e772768
--- /dev/null
+++ b/talk/base/callback.h
@@ -0,0 +1,291 @@
+// This file was GENERATED by command:
+//     pump.py callback.h.pump
+// DO NOT EDIT BY HAND!!!
+
+/*
+ * libjingle
+ * Copyright 2012 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.
+ */
+
+// To generate callback.h from callback.h.pump, execute:
+// /home/build/google3/third_party/gtest/scripts/pump.py callback.h.pump
+
+// Callbacks are callable object containers. They can hold a function pointer
+// or a function object and behave like a value type. Internally, data is
+// reference-counted, making copies and pass-by-value inexpensive.
+//
+// Callbacks are typed using template arguments.  The format is:
+//   CallbackN<ReturnType, ParamType1, ..., ParamTypeN>
+// where N is the number of arguments supplied to the callable object.
+// Callbacks are invoked using operator(), just like a function or a function
+// object. Default-constructed callbacks are "empty," and executing an empty
+// callback does nothing. A callback can be made empty by assigning it from
+// a default-constructed callback.
+//
+// Callbacks are similar in purpose to std::function (which isn't available on
+// all platforms we support) and a lightweight alternative to sigslots. Since
+// they effectively hide the type of the object they call, they're useful in
+// breaking dependencies between objects that need to interact with one another.
+// Notably, they can hold the results of Bind(), std::bind*, etc, without
+// needing
+// to know the resulting object type of those calls.
+//
+// Sigslots, on the other hand, provide a fuller feature set, such as multiple
+// subscriptions to a signal, optional thread-safety, and lifetime tracking of
+// slots. When these features are needed, choose sigslots.
+//
+// Example:
+//   int sqr(int x) { return x * x; }
+//   struct AddK {
+//     int k;
+//     int operator()(int x) const { return x + k; }
+//   } add_k = {5};
+//
+//   Callback1<int, int> my_callback;
+//   cout << my_callback.empty() << endl;  // true
+//
+//   my_callback = Callback1<int, int>(&sqr);
+//   cout << my_callback.empty() << endl;  // false
+//   cout << my_callback(3) << endl;  // 9
+//
+//   my_callback = Callback1<int, int>(add_k);
+//   cout << my_callback(10) << endl;  // 15
+//
+//   my_callback = Callback1<int, int>();
+//   cout << my_callback.empty() << endl;  // true
+
+#ifndef TALK_BASE_CALLBACK_H_
+#define TALK_BASE_CALLBACK_H_
+
+#include "talk/base/logging.h"
+#include "talk/base/refcount.h"
+#include "talk/base/scoped_ref_ptr.h"
+
+namespace talk_base {
+
+template <class R>
+class Callback0 {
+ public:
+  // Default copy operations are appropriate for this class.
+  Callback0() {}
+  template <class T> Callback0(const T& functor)
+      : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+  R operator()() {
+    if (empty()) {
+      LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
+      return R();
+    }
+    return helper_->Run();
+  }
+  bool empty() const { return !helper_; }
+
+ private:
+  struct Helper : RefCountInterface {
+    virtual ~Helper() {}
+    virtual R Run() = 0;
+  };
+  template <class T> struct HelperImpl : Helper {
+    explicit HelperImpl(const T& functor) : functor_(functor) {}
+    virtual R Run() {
+      return functor_();
+    }
+    T functor_;
+  };
+  scoped_refptr<Helper> helper_;
+};
+
+template <class R,
+          class P1>
+class Callback1 {
+ public:
+  // Default copy operations are appropriate for this class.
+  Callback1() {}
+  template <class T> Callback1(const T& functor)
+      : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+  R operator()(P1 p1) {
+    if (empty()) {
+      LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
+      return R();
+    }
+    return helper_->Run(p1);
+  }
+  bool empty() const { return !helper_; }
+
+ private:
+  struct Helper : RefCountInterface {
+    virtual ~Helper() {}
+    virtual R Run(P1 p1) = 0;
+  };
+  template <class T> struct HelperImpl : Helper {
+    explicit HelperImpl(const T& functor) : functor_(functor) {}
+    virtual R Run(P1 p1) {
+      return functor_(p1);
+    }
+    T functor_;
+  };
+  scoped_refptr<Helper> helper_;
+};
+
+template <class R,
+          class P1,
+          class P2>
+class Callback2 {
+ public:
+  // Default copy operations are appropriate for this class.
+  Callback2() {}
+  template <class T> Callback2(const T& functor)
+      : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+  R operator()(P1 p1, P2 p2) {
+    if (empty()) {
+      LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
+      return R();
+    }
+    return helper_->Run(p1, p2);
+  }
+  bool empty() const { return !helper_; }
+
+ private:
+  struct Helper : RefCountInterface {
+    virtual ~Helper() {}
+    virtual R Run(P1 p1, P2 p2) = 0;
+  };
+  template <class T> struct HelperImpl : Helper {
+    explicit HelperImpl(const T& functor) : functor_(functor) {}
+    virtual R Run(P1 p1, P2 p2) {
+      return functor_(p1, p2);
+    }
+    T functor_;
+  };
+  scoped_refptr<Helper> helper_;
+};
+
+template <class R,
+          class P1,
+          class P2,
+          class P3>
+class Callback3 {
+ public:
+  // Default copy operations are appropriate for this class.
+  Callback3() {}
+  template <class T> Callback3(const T& functor)
+      : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+  R operator()(P1 p1, P2 p2, P3 p3) {
+    if (empty()) {
+      LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
+      return R();
+    }
+    return helper_->Run(p1, p2, p3);
+  }
+  bool empty() const { return !helper_; }
+
+ private:
+  struct Helper : RefCountInterface {
+    virtual ~Helper() {}
+    virtual R Run(P1 p1, P2 p2, P3 p3) = 0;
+  };
+  template <class T> struct HelperImpl : Helper {
+    explicit HelperImpl(const T& functor) : functor_(functor) {}
+    virtual R Run(P1 p1, P2 p2, P3 p3) {
+      return functor_(p1, p2, p3);
+    }
+    T functor_;
+  };
+  scoped_refptr<Helper> helper_;
+};
+
+template <class R,
+          class P1,
+          class P2,
+          class P3,
+          class P4>
+class Callback4 {
+ public:
+  // Default copy operations are appropriate for this class.
+  Callback4() {}
+  template <class T> Callback4(const T& functor)
+      : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+  R operator()(P1 p1, P2 p2, P3 p3, P4 p4) {
+    if (empty()) {
+      LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
+      return R();
+    }
+    return helper_->Run(p1, p2, p3, p4);
+  }
+  bool empty() const { return !helper_; }
+
+ private:
+  struct Helper : RefCountInterface {
+    virtual ~Helper() {}
+    virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4) = 0;
+  };
+  template <class T> struct HelperImpl : Helper {
+    explicit HelperImpl(const T& functor) : functor_(functor) {}
+    virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4) {
+      return functor_(p1, p2, p3, p4);
+    }
+    T functor_;
+  };
+  scoped_refptr<Helper> helper_;
+};
+
+template <class R,
+          class P1,
+          class P2,
+          class P3,
+          class P4,
+          class P5>
+class Callback5 {
+ public:
+  // Default copy operations are appropriate for this class.
+  Callback5() {}
+  template <class T> Callback5(const T& functor)
+      : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+  R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
+    if (empty()) {
+      LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
+      return R();
+    }
+    return helper_->Run(p1, p2, p3, p4, p5);
+  }
+  bool empty() const { return !helper_; }
+
+ private:
+  struct Helper : RefCountInterface {
+    virtual ~Helper() {}
+    virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) = 0;
+  };
+  template <class T> struct HelperImpl : Helper {
+    explicit HelperImpl(const T& functor) : functor_(functor) {}
+    virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
+      return functor_(p1, p2, p3, p4, p5);
+    }
+    T functor_;
+  };
+  scoped_refptr<Helper> helper_;
+};
+}  // namespace talk_base
+
+
+#endif  // TALK_BASE_CALLBACK_H_
diff --git a/talk/base/callback.h.pump b/talk/base/callback.h.pump
new file mode 100644
index 0000000..ae9ab87
--- /dev/null
+++ b/talk/base/callback.h.pump
@@ -0,0 +1,123 @@
+/*
+ * libjingle
+ * Copyright 2012 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.
+ */
+
+// To generate callback.h from callback.h.pump, execute:
+// /home/build/google3/third_party/gtest/scripts/pump.py callback.h.pump
+
+// Callbacks are callable object containers. They can hold a function pointer
+// or a function object and behave like a value type. Internally, data is
+// reference-counted, making copies and pass-by-value inexpensive.
+//
+// Callbacks are typed using template arguments.  The format is:
+//   CallbackN<ReturnType, ParamType1, ..., ParamTypeN>
+// where N is the number of arguments supplied to the callable object.
+// Callbacks are invoked using operator(), just like a function or a function
+// object. Default-constructed callbacks are "empty," and executing an empty
+// callback does nothing. A callback can be made empty by assigning it from
+// a default-constructed callback.
+//
+// Callbacks are similar in purpose to std::function (which isn't available on
+// all platforms we support) and a lightweight alternative to sigslots. Since
+// they effectively hide the type of the object they call, they're useful in
+// breaking dependencies between objects that need to interact with one another.
+// Notably, they can hold the results of Bind(), std::bind*, etc, without needing
+// to know the resulting object type of those calls.
+//
+// Sigslots, on the other hand, provide a fuller feature set, such as multiple
+// subscriptions to a signal, optional thread-safety, and lifetime tracking of
+// slots. When these features are needed, choose sigslots.
+//
+// Example:
+//   int sqr(int x) { return x * x; }
+//   struct AddK {
+//     int k;
+//     int operator()(int x) const { return x + k; }
+//   } add_k = {5};
+//
+//   Callback1<int, int> my_callback;
+//   cout << my_callback.empty() << endl;  // true
+//
+//   my_callback = Callback1<int, int>(&sqr);
+//   cout << my_callback.empty() << endl;  // false
+//   cout << my_callback(3) << endl;  // 9
+//
+//   my_callback = Callback1<int, int>(add_k);
+//   cout << my_callback(10) << endl;  // 15
+//
+//   my_callback = Callback1<int, int>();
+//   cout << my_callback.empty() << endl;  // true
+
+#ifndef TALK_BASE_CALLBACK_H_
+#define TALK_BASE_CALLBACK_H_
+
+#include "talk/base/logging.h"
+#include "talk/base/refcount.h"
+#include "talk/base/scoped_ref_ptr.h"
+
+namespace talk_base {
+
+$var n = 5
+$range i 0..n
+$for i [[
+$range j 1..i
+
+template <class R$for j [[,
+          class P$j]]>
+class Callback$i {
+ public:
+  // Default copy operations are appropriate for this class.
+  Callback$i() {}
+  template <class T> Callback$i(const T& functor)
+      : helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
+  R operator()($for j , [[P$j p$j]]) {
+    if (empty()) {
+      LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
+      return R();
+    }
+    return helper_->Run($for j , [[p$j]]);
+  }
+  bool empty() const { return !helper_; }
+
+ private:
+  struct Helper : RefCountInterface {
+    virtual ~Helper() {}
+    virtual R Run($for j , [[P$j p$j]]) = 0;
+  };
+  template <class T> struct HelperImpl : Helper {
+    explicit HelperImpl(const T& functor) : functor_(functor) {}
+    virtual R Run($for j , [[P$j p$j]]) {
+      return functor_($for j , [[p$j]]);
+    }
+    T functor_;
+  };
+  scoped_refptr<Helper> helper_;
+};
+
+]]
+}  // namespace talk_base
+
+#endif  // TALK_BASE_CALLBACK_H_
\ No newline at end of file
diff --git a/talk/base/callback_unittest.cc b/talk/base/callback_unittest.cc
new file mode 100644
index 0000000..c7ca00f
--- /dev/null
+++ b/talk/base/callback_unittest.cc
@@ -0,0 +1,98 @@
+/*
+ * libjingle
+ * Copyright 2004--2011, 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.
+ */
+
+#include "talk/base/bind.h"
+#include "talk/base/callback.h"
+#include "talk/base/gunit.h"
+
+namespace talk_base {
+
+namespace {
+
+void f() {}
+int g() { return 42; }
+int h(int x) { return x * x; }
+void i(int& x) { x *= x; }  // NOLINT: Testing refs
+
+struct BindTester {
+  int a() { return 24; }
+  int b(int x) const { return x * x; }
+};
+
+}  // namespace
+
+TEST(CallbackTest, VoidReturn) {
+  Callback0<void> cb;
+  EXPECT_TRUE(cb.empty());
+  cb();  // Executing an empty callback should not crash.
+  cb = Callback0<void>(&f);
+  EXPECT_FALSE(cb.empty());
+  cb();
+}
+
+TEST(CallbackTest, IntReturn) {
+  Callback0<int> cb;
+  EXPECT_TRUE(cb.empty());
+  cb = Callback0<int>(&g);
+  EXPECT_FALSE(cb.empty());
+  EXPECT_EQ(42, cb());
+  EXPECT_EQ(42, cb());
+}
+
+TEST(CallbackTest, OneParam) {
+  Callback1<int, int> cb1(&h);
+  EXPECT_FALSE(cb1.empty());
+  EXPECT_EQ(9, cb1(-3));
+  EXPECT_EQ(100, cb1(10));
+
+  // Try clearing a callback.
+  cb1 = Callback1<int, int>();
+  EXPECT_TRUE(cb1.empty());
+
+  // Try a callback with a ref parameter.
+  Callback1<void, int&> cb2(&i);
+  int x = 3;
+  cb2(x);
+  EXPECT_EQ(9, x);
+  cb2(x);
+  EXPECT_EQ(81, x);
+}
+
+TEST(CallbackTest, WithBind) {
+  BindTester t;
+  Callback0<int> cb1 = Bind(&BindTester::a, &t);
+  EXPECT_EQ(24, cb1());
+  EXPECT_EQ(24, cb1());
+  cb1 = Bind(&BindTester::b, &t, 10);
+  EXPECT_EQ(100, cb1());
+  EXPECT_EQ(100, cb1());
+  cb1 = Bind(&BindTester::b, &t, 5);
+  EXPECT_EQ(25, cb1());
+  EXPECT_EQ(25, cb1());
+}
+
+}  // namespace talk_base
diff --git a/talk/base/messagehandler.h b/talk/base/messagehandler.h
index 913edf8..8b9e5f6 100644
--- a/talk/base/messagehandler.h
+++ b/talk/base/messagehandler.h
@@ -28,6 +28,7 @@
 #ifndef TALK_BASE_MESSAGEHANDLER_H_
 #define TALK_BASE_MESSAGEHANDLER_H_
 
+#include "talk/base/callback.h"
 #include "talk/base/constructormagic.h"
 
 namespace talk_base {
@@ -38,16 +39,52 @@
 
 class MessageHandler {
  public:
+  virtual ~MessageHandler();
   virtual void OnMessage(Message* msg) = 0;
 
  protected:
   MessageHandler() {}
-  virtual ~MessageHandler();
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MessageHandler);
 };
 
+// Helper class to facilitate executing a functor on a thread.
+template <class ReturnT, class FunctorT>
+class FunctorMessageHandler : public MessageHandler {
+ public:
+  explicit FunctorMessageHandler(const FunctorT& functor)
+      : functor_(functor) {}
+  virtual void OnMessage(Message* msg) {
+    result_ = functor_();
+    if (!callback_.empty()) callback_();
+  }
+  const ReturnT& result() const { return result_; }
+  void SetCallback(const Callback0<void>& callback) { callback_ = callback; }
+ private:
+  FunctorT functor_;
+  ReturnT result_;
+  Callback0<void> callback_;
+};
+
+// Specialization for ReturnT of void.
+template <class FunctorT>
+class FunctorMessageHandler<void, FunctorT> : public MessageHandler {
+ public:
+  explicit FunctorMessageHandler(const FunctorT& functor)
+      : functor_(functor) {}
+  virtual void OnMessage(Message* msg) {
+    functor_();
+    if (!callback_.empty()) callback_();
+  }
+  void result() const {}
+  void SetCallback(const Callback0<void>& callback) { callback_ = callback; }
+ private:
+  FunctorT functor_;
+  Callback0<void> callback_;
+};
+
+
 } // namespace talk_base
 
 #endif // TALK_BASE_MESSAGEHANDLER_H_
diff --git a/talk/base/scopedptrcollection.h b/talk/base/scopedptrcollection.h
new file mode 100644
index 0000000..ec2726e
--- /dev/null
+++ b/talk/base/scopedptrcollection.h
@@ -0,0 +1,77 @@
+/*
+ * libjingle
+ * Copyright 2014 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.
+ */
+
+// Stores a collection of pointers that are deleted when the container is
+// destructed.
+
+#ifndef TALK_BASE_SCOPEDPTRCOLLECTION_H_
+#define TALK_BASE_SCOPEDPTRCOLLECTION_H_
+
+#include <algorithm>
+#include <vector>
+
+#include "talk/base/basictypes.h"
+#include "talk/base/constructormagic.h"
+
+namespace talk_base {
+
+template<class T>
+class ScopedPtrCollection {
+ public:
+  typedef std::vector<T*> VectorT;
+
+  ScopedPtrCollection() { }
+  ~ScopedPtrCollection() {
+    for (typename VectorT::iterator it = collection_.begin();
+         it != collection_.end(); ++it) {
+      delete *it;
+    }
+  }
+
+  const VectorT& collection() const { return collection_; }
+  void Reserve(size_t size) {
+    collection_.reserve(size);
+  }
+  void PushBack(T* t) {
+    collection_.push_back(t);
+  }
+
+  // Remove |t| from the collection without deleting it.
+  void Remove(T* t) {
+    collection_.erase(std::remove(collection_.begin(), collection_.end(), t),
+                      collection_.end());
+  }
+
+ private:
+  VectorT collection_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPtrCollection);
+};
+
+}  // namespace talk_base
+
+#endif  // TALK_BASE_SCOPEDPTRCOLLECTION_H_
diff --git a/talk/base/scopedptrcollection_unittest.cc b/talk/base/scopedptrcollection_unittest.cc
new file mode 100644
index 0000000..dd9002e
--- /dev/null
+++ b/talk/base/scopedptrcollection_unittest.cc
@@ -0,0 +1,90 @@
+/*
+ * libjingle
+ * Copyright 2014 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.
+ */
+
+#include "talk/base/scopedptrcollection.h"
+#include "talk/base/gunit.h"
+
+namespace talk_base {
+
+namespace {
+
+class InstanceCounter {
+ public:
+  explicit InstanceCounter(int* num_instances)
+      : num_instances_(num_instances) {
+    ++(*num_instances_);
+  }
+  ~InstanceCounter() {
+    --(*num_instances_);
+  }
+
+ private:
+  int* num_instances_;
+
+  DISALLOW_COPY_AND_ASSIGN(InstanceCounter);
+};
+
+}  // namespace
+
+class ScopedPtrCollectionTest : public testing::Test {
+ protected:
+  ScopedPtrCollectionTest()
+      : num_instances_(0),
+      collection_(new ScopedPtrCollection<InstanceCounter>()) {
+  }
+
+  int num_instances_;
+  scoped_ptr<ScopedPtrCollection<InstanceCounter> > collection_;
+};
+
+TEST_F(ScopedPtrCollectionTest, PushBack) {
+  EXPECT_EQ(0u, collection_->collection().size());
+  EXPECT_EQ(0, num_instances_);
+  const int kNum = 100;
+  for (int i = 0; i < kNum; ++i) {
+    collection_->PushBack(new InstanceCounter(&num_instances_));
+  }
+  EXPECT_EQ(static_cast<size_t>(kNum), collection_->collection().size());
+  EXPECT_EQ(kNum, num_instances_);
+  collection_.reset();
+  EXPECT_EQ(0, num_instances_);
+}
+
+TEST_F(ScopedPtrCollectionTest, Remove) {
+  InstanceCounter* ic = new InstanceCounter(&num_instances_);
+  collection_->PushBack(ic);
+  EXPECT_EQ(1u, collection_->collection().size());
+  collection_->Remove(ic);
+  EXPECT_EQ(1, num_instances_);
+  collection_.reset();
+  EXPECT_EQ(1, num_instances_);
+  delete ic;
+  EXPECT_EQ(0, num_instances_);
+}
+
+
+}  // namespace talk_base
diff --git a/talk/base/thread.h b/talk/base/thread.h
index 4dc09f6..316f041 100644
--- a/talk/base/thread.h
+++ b/talk/base/thread.h
@@ -223,33 +223,6 @@
   void Join();
 
  private:
-  // Helper class to facilitate executing a functor on a thread.
-  template <class ReturnT, class FunctorT>
-  class FunctorMessageHandler : public MessageHandler {
-   public:
-    explicit FunctorMessageHandler(const FunctorT& functor)
-        : functor_(functor) {}
-    virtual void OnMessage(Message* msg) {
-      result_ = functor_();
-    }
-    const ReturnT& result() const { return result_; }
-   private:
-    FunctorT functor_;
-    ReturnT result_;
-  };
-
-  // Specialization for ReturnT of void.
-  template <class FunctorT>
-  class FunctorMessageHandler<void, FunctorT> : public MessageHandler {
-   public:
-    explicit FunctorMessageHandler(const FunctorT& functor)
-        : functor_(functor) {}
-    virtual void OnMessage(Message* msg) { functor_(); }
-    void result() const {}
-   private:
-    FunctorT functor_;
-  };
-
   static void *PreRun(void *pv);
 
   // ThreadManager calls this instead WrapCurrent() because
diff --git a/talk/base/thread_unittest.cc b/talk/base/thread_unittest.cc
index 896fbab..ddf6326 100644
--- a/talk/base/thread_unittest.cc
+++ b/talk/base/thread_unittest.cc
@@ -25,6 +25,7 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "talk/base/asyncinvoker.h"
 #include "talk/base/asyncudpsocket.h"
 #include "talk/base/event.h"
 #include "talk/base/gunit.h"
@@ -150,16 +151,22 @@
 };
 
 // Function objects to test Thread::Invoke.
-struct Functor1 {
+struct FunctorA {
   int operator()() { return 42; }
 };
-class Functor2 {
+class FunctorB {
  public:
-  explicit Functor2(bool* flag) : flag_(flag) {}
+  explicit FunctorB(bool* flag) : flag_(flag) {}
   void operator()() { if (flag_) *flag_ = true; }
  private:
   bool* flag_;
 };
+struct FunctorC {
+  int operator()() {
+    Thread::Current()->ProcessMessages(50);
+    return 24;
+  }
+};
 
 // See: https://code.google.com/p/webrtc/issues/detail?id=2409
 TEST(ThreadTest, DISABLED_Main) {
@@ -289,9 +296,9 @@
   Thread thread;
   thread.Start();
   // Try calling functors.
-  EXPECT_EQ(42, thread.Invoke<int>(Functor1()));
+  EXPECT_EQ(42, thread.Invoke<int>(FunctorA()));
   bool called = false;
-  Functor2 f2(&called);
+  FunctorB f2(&called);
   thread.Invoke<void>(f2);
   EXPECT_TRUE(called);
   // Try calling bare functions.
@@ -303,6 +310,152 @@
   thread.Invoke<void>(&LocalFuncs::Func2);
 }
 
+class AsyncInvokeTest : public testing::Test {
+ public:
+  void IntCallback(int value) {
+    EXPECT_EQ(expected_thread_, Thread::Current());
+    int_value_ = value;
+  }
+  void AsyncInvokeIntCallback(AsyncInvoker* invoker, Thread* thread) {
+    expected_thread_ = thread;
+    invoker->AsyncInvoke(thread, FunctorC(),
+                         &AsyncInvokeTest::IntCallback,
+                         static_cast<AsyncInvokeTest*>(this));
+    invoke_started_.Set();
+  }
+  void SetExpectedThreadForIntCallback(Thread* thread) {
+    expected_thread_ = thread;
+  }
+
+ protected:
+  enum { kWaitTimeout = 1000 };
+  AsyncInvokeTest()
+      : int_value_(0),
+        invoke_started_(true, false),
+        expected_thread_(NULL) {}
+
+  int int_value_;
+  Event invoke_started_;
+  Thread* expected_thread_;
+};
+
+TEST_F(AsyncInvokeTest, FireAndForget) {
+  AsyncInvoker invoker;
+  // Create and start the thread.
+  Thread thread;
+  thread.Start();
+  // Try calling functor.
+  bool called = false;
+  invoker.AsyncInvoke<void>(&thread, FunctorB(&called));
+  EXPECT_TRUE_WAIT(called, kWaitTimeout);
+}
+
+TEST_F(AsyncInvokeTest, WithCallback) {
+  AsyncInvoker invoker;
+  // Create and start the thread.
+  Thread thread;
+  thread.Start();
+  // Try calling functor.
+  SetExpectedThreadForIntCallback(Thread::Current());
+  invoker.AsyncInvoke(&thread, FunctorA(),
+                      &AsyncInvokeTest::IntCallback,
+                      static_cast<AsyncInvokeTest*>(this));
+  EXPECT_EQ_WAIT(42, int_value_, kWaitTimeout);
+}
+
+TEST_F(AsyncInvokeTest, CancelInvoker) {
+  // Create and start the thread.
+  Thread thread;
+  thread.Start();
+  // Try destroying invoker during call.
+  {
+    AsyncInvoker invoker;
+    invoker.AsyncInvoke(&thread, FunctorC(),
+                        &AsyncInvokeTest::IntCallback,
+                        static_cast<AsyncInvokeTest*>(this));
+  }
+  // With invoker gone, callback should be cancelled.
+  Thread::Current()->ProcessMessages(kWaitTimeout);
+  EXPECT_EQ(0, int_value_);
+}
+
+TEST_F(AsyncInvokeTest, CancelCallingThread) {
+  AsyncInvoker invoker;
+  { // Create and start the thread.
+    Thread thread;
+    thread.Start();
+    // Try calling functor.
+    thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
+                             static_cast<AsyncInvokeTest*>(this),
+                             &invoker, Thread::Current()));
+    // Wait for the call to begin.
+    ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
+  }
+  // Calling thread is gone. Return message shouldn't happen.
+  Thread::Current()->ProcessMessages(kWaitTimeout);
+  EXPECT_EQ(0, int_value_);
+}
+
+TEST_F(AsyncInvokeTest, KillInvokerBeforeExecute) {
+  Thread thread;
+  thread.Start();
+  {
+    AsyncInvoker invoker;
+    // Try calling functor.
+    thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
+                             static_cast<AsyncInvokeTest*>(this),
+                             &invoker, Thread::Current()));
+    // Wait for the call to begin.
+    ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
+  }
+  // Invoker is destroyed. Function should not execute.
+  Thread::Current()->ProcessMessages(kWaitTimeout);
+  EXPECT_EQ(0, int_value_);
+}
+
+TEST_F(AsyncInvokeTest, Flush) {
+  AsyncInvoker invoker;
+  bool flag1 = false;
+  bool flag2 = false;
+  // Queue two async calls to the current thread.
+  invoker.AsyncInvoke<void>(Thread::Current(),
+                            FunctorB(&flag1));
+  invoker.AsyncInvoke<void>(Thread::Current(),
+                            FunctorB(&flag2));
+  // Because we haven't pumped messages, these should not have run yet.
+  EXPECT_FALSE(flag1);
+  EXPECT_FALSE(flag2);
+  // Force them to run now.
+  invoker.Flush(Thread::Current());
+  EXPECT_TRUE(flag1);
+  EXPECT_TRUE(flag2);
+}
+
+TEST_F(AsyncInvokeTest, FlushWithIds) {
+  AsyncInvoker invoker;
+  bool flag1 = false;
+  bool flag2 = false;
+  // Queue two async calls to the current thread, one with a message id.
+  invoker.AsyncInvoke<void>(Thread::Current(),
+                            FunctorB(&flag1),
+                            5);
+  invoker.AsyncInvoke<void>(Thread::Current(),
+                            FunctorB(&flag2));
+  // Because we haven't pumped messages, these should not have run yet.
+  EXPECT_FALSE(flag1);
+  EXPECT_FALSE(flag2);
+  // Execute pending calls with id == 5.
+  invoker.Flush(Thread::Current(), 5);
+  EXPECT_TRUE(flag1);
+  EXPECT_FALSE(flag2);
+  flag1 = false;
+  // Execute all pending calls. The id == 5 call should not execute again.
+  invoker.Flush(Thread::Current());
+  EXPECT_FALSE(flag1);
+  EXPECT_TRUE(flag2);
+}
+
+
 #ifdef WIN32
 class ComThreadTest : public testing::Test, public MessageHandler {
  public:
diff --git a/talk/libjingle.gyp b/talk/libjingle.gyp
index bde7ee0..3904a0f 100755
--- a/talk/libjingle.gyp
+++ b/talk/libjingle.gyp
@@ -260,6 +260,8 @@
         'base/asyncfile.h',
         'base/asynchttprequest.cc',
         'base/asynchttprequest.h',
+        'base/asyncinvoker.cc',
+        'base/asyncinvoker.h',
         'base/asyncpacketsocket.h',
         'base/asyncresolverinterface.h',
         'base/asyncsocket.cc',
@@ -282,6 +284,7 @@
         'base/bytebuffer.cc',
         'base/bytebuffer.h',
         'base/byteorder.h',
+        'base/callback.h',
         'base/checks.cc',
         'base/checks.h',
         'base/common.cc',
@@ -383,6 +386,7 @@
         'base/scoped_autorelease_pool.h',
         'base/scoped_ptr.h',
         'base/scoped_ref_ptr.h',
+        'base/scopedptrcollection.h',
         'base/sec_buffer.h',
         'base/sha1.cc',
         'base/sha1.h',
diff --git a/talk/libjingle.scons b/talk/libjingle.scons
index d879cc2..dc5e9a0 100644
--- a/talk/libjingle.scons
+++ b/talk/libjingle.scons
@@ -154,6 +154,7 @@
              srcs = [
                "base/asyncfile.cc",
                "base/asynchttprequest.cc",
+               "base/asyncinvoker.cc",
                "base/asyncsocket.cc",
                "base/asynctcpsocket.cc",
                "base/asyncudpsocket.cc",
@@ -540,6 +541,7 @@
                 "base/buffer_unittest.cc",
                 "base/bytebuffer_unittest.cc",
                 "base/byteorder_unittest.cc",
+                "base/callback_unittest.cc",
                 "base/cpumonitor_unittest.cc",
                 "base/crc32_unittest.cc",
                 "base/event_unittest.cc",
@@ -569,6 +571,7 @@
                 "base/ratetracker_unittest.cc",
                 "base/referencecountedsingletonfactory_unittest.cc",
                 "base/rollingaccumulator_unittest.cc",
+                "base/scopedptrcollection_unittest.cc",
                 "base/sha1digest_unittest.cc",
                 "base/sharedexclusivelock_unittest.cc",
                 "base/signalthread_unittest.cc",
diff --git a/talk/libjingle_tests.gyp b/talk/libjingle_tests.gyp
index e36a369..038fb4f 100755
--- a/talk/libjingle_tests.gyp
+++ b/talk/libjingle_tests.gyp
@@ -120,6 +120,7 @@
         'base/buffer_unittest.cc',
         'base/bytebuffer_unittest.cc',
         'base/byteorder_unittest.cc',
+        'base/callback_unittest.cc',
         'base/cpumonitor_unittest.cc',
         'base/crc32_unittest.cc',
         'base/event_unittest.cc',
@@ -148,6 +149,7 @@
         'base/ratetracker_unittest.cc',
         'base/referencecountedsingletonfactory_unittest.cc',
         'base/rollingaccumulator_unittest.cc',
+        'base/scopedptrcollection_unittest.cc',
         'base/sha1digest_unittest.cc',
         'base/sharedexclusivelock_unittest.cc',
         'base/signalthread_unittest.cc',
diff --git a/talk/media/base/mediachannel.h b/talk/media/base/mediachannel.h
index c2ea26f..ef87c9e 100644
--- a/talk/media/base/mediachannel.h
+++ b/talk/media/base/mediachannel.h
@@ -168,6 +168,7 @@
     adjust_agc_delta.SetFrom(change.adjust_agc_delta);
     experimental_agc.SetFrom(change.experimental_agc);
     experimental_aec.SetFrom(change.experimental_aec);
+    experimental_ns.SetFrom(change.experimental_ns);
     aec_dump.SetFrom(change.aec_dump);
     experimental_acm.SetFrom(change.experimental_acm);
     tx_agc_target_dbov.SetFrom(change.tx_agc_target_dbov);
@@ -195,6 +196,7 @@
         conference_mode == o.conference_mode &&
         experimental_agc == o.experimental_agc &&
         experimental_aec == o.experimental_aec &&
+        experimental_ns == o.experimental_ns &&
         adjust_agc_delta == o.adjust_agc_delta &&
         aec_dump == o.aec_dump &&
         experimental_acm == o.experimental_acm &&
@@ -224,6 +226,7 @@
     ost << ToStringIfSet("agc_delta", adjust_agc_delta);
     ost << ToStringIfSet("experimental_agc", experimental_agc);
     ost << ToStringIfSet("experimental_aec", experimental_aec);
+    ost << ToStringIfSet("experimental_ns", experimental_ns);
     ost << ToStringIfSet("aec_dump", aec_dump);
     ost << ToStringIfSet("experimental_acm", experimental_acm);
     ost << ToStringIfSet("tx_agc_target_dbov", tx_agc_target_dbov);
@@ -261,6 +264,7 @@
   Settable<int> adjust_agc_delta;
   Settable<bool> experimental_agc;
   Settable<bool> experimental_aec;
+  Settable<bool> experimental_ns;
   Settable<bool> aec_dump;
   Settable<bool> experimental_acm;
   // Note that tx_agc_* only applies to non-experimental AGC.
@@ -763,8 +767,10 @@
       : packets_cached(0),
         firs_rcvd(0),
         nacks_rcvd(0),
-        frame_width(0),
-        frame_height(0),
+        input_frame_width(0),
+        input_frame_height(0),
+        send_frame_width(0),
+        send_frame_height(0),
         framerate_input(0),
         framerate_sent(0),
         nominal_bitrate(0),
@@ -780,8 +786,10 @@
   int packets_cached;
   int firs_rcvd;
   int nacks_rcvd;
-  int frame_width;
-  int frame_height;
+  int input_frame_width;
+  int input_frame_height;
+  int send_frame_width;
+  int send_frame_height;
   int framerate_input;
   int framerate_sent;
   int nominal_bitrate;
diff --git a/talk/media/base/videoadapter.cc b/talk/media/base/videoadapter.cc
index 3cd6cac..29be805 100644
--- a/talk/media/base/videoadapter.cc
+++ b/talk/media/base/videoadapter.cc
@@ -162,8 +162,9 @@
 VideoAdapter::VideoAdapter()
     : output_num_pixels_(INT_MAX),
       scale_third_(false),
-      frames_(0),
-      adapted_frames_(0),
+      frames_in_(0),
+      frames_out_(0),
+      frames_scaled_(0),
       adaption_changes_(0),
       previous_width_(0),
       previous_height_(0),
@@ -177,9 +178,13 @@
 
 void VideoAdapter::SetInputFormat(const VideoFormat& format) {
   talk_base::CritScope cs(&critical_section_);
+  int64 old_input_interval = input_format_.interval;
   input_format_ = format;
   output_format_.interval = talk_base::_max(
       output_format_.interval, input_format_.interval);
+  if (old_input_interval != input_format_.interval) {
+    LOG(LS_INFO) << "VAdapt Input Interval: " << input_format_.interval;
+  }
 }
 
 void CoordinatedVideoAdapter::SetInputFormat(const VideoFormat& format) {
@@ -207,10 +212,14 @@
 
 void VideoAdapter::SetOutputFormat(const VideoFormat& format) {
   talk_base::CritScope cs(&critical_section_);
+  int64 old_output_interval = output_format_.interval;
   output_format_ = format;
   output_num_pixels_ = output_format_.width * output_format_.height;
   output_format_.interval = talk_base::_max(
       output_format_.interval, input_format_.interval);
+  if (old_output_interval != output_format_.interval) {
+    LOG(LS_INFO) << "VAdapt Output Interval: " << output_format_.interval;
+  }
 }
 
 const VideoFormat& VideoAdapter::input_format() {
@@ -245,7 +254,7 @@
   if (!in_frame || !out_frame) {
     return false;
   }
-  ++frames_;
+  ++frames_in_;
 
   // Update input to actual frame dimensions.
   VideoFormat format(static_cast<int>(in_frame->GetWidth()),
@@ -273,6 +282,23 @@
     }
   }
   if (should_drop) {
+    // Show VAdapt log every 90 frames dropped. (3 seconds)
+    // TODO(fbarchard): Consider GetLogSeverity() to change interval to less
+    // for LS_VERBOSE and more for LS_INFO.
+    bool show = (frames_in_ - frames_out_) % 90 == 0;
+
+    if (show) {
+      // TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed
+      // in default calls.
+      LOG(LS_INFO) << "VAdapt Drop Frame: " << frames_scaled_
+                   << " / " << frames_out_
+                   << " / " << frames_in_
+                   << " Changes: " << adaption_changes_
+                   << " Input: " << in_frame->GetWidth()
+                   << "x" << in_frame->GetHeight()
+                   << " i" << input_format_.interval
+                   << " Output: i" << output_format_.interval;
+    }
     *out_frame = NULL;
     return true;
   }
@@ -289,19 +315,22 @@
   }
 
   if (!StretchToOutputFrame(in_frame)) {
+    LOG(LS_VERBOSE) << "VAdapt Stretch Failed.";
     return false;
   }
 
   *out_frame = output_frame_.get();
 
-  // Show VAdapt log every 300 frames. (10 seconds)
-  // TODO(fbarchard): Consider GetLogSeverity() to change interval to less
-  // for LS_VERBOSE and more for LS_INFO.
-  bool show = frames_ % 300 == 0;
+  ++frames_out_;
   if (in_frame->GetWidth() != (*out_frame)->GetWidth() ||
       in_frame->GetHeight() != (*out_frame)->GetHeight()) {
-    ++adapted_frames_;
+    ++frames_scaled_;
   }
+  // Show VAdapt log every 90 frames output. (3 seconds)
+  // TODO(fbarchard): Consider GetLogSeverity() to change interval to less
+  // for LS_VERBOSE and more for LS_INFO.
+  bool show = (frames_out_) % 90 == 0;
+
   // TODO(fbarchard): LOG the previous output resolution and track input
   // resolution changes as well.  Consider dropping the statistics into their
   // own class which could be queried publically.
@@ -315,14 +344,17 @@
   if (show) {
     // TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed
     // in default calls.
-    LOG(LS_INFO) << "VAdapt Frame: " << adapted_frames_
-                 << " / " << frames_
+    LOG(LS_INFO) << "VAdapt Frame: " << frames_scaled_
+                 << " / " << frames_out_
+                 << " / " << frames_in_
                  << " Changes: " << adaption_changes_
                  << " Input: " << in_frame->GetWidth()
                  << "x" << in_frame->GetHeight()
+                 << " i" << input_format_.interval
                  << " Scale: " << scale
                  << " Output: " << (*out_frame)->GetWidth()
                  << "x" << (*out_frame)->GetHeight()
+                 << " i" << output_format_.interval
                  << " Changed: " << (changed ? "true" : "false");
   }
   previous_width_ = (*out_frame)->GetWidth();
diff --git a/talk/media/base/videoadapter.h b/talk/media/base/videoadapter.h
index 272df72..6b1cdc5 100644
--- a/talk/media/base/videoadapter.h
+++ b/talk/media/base/videoadapter.h
@@ -87,8 +87,9 @@
   VideoFormat output_format_;
   int output_num_pixels_;
   bool scale_third_;  // True if adapter allows scaling to 1/3 and 2/3.
-  int frames_;  // Number of input frames.
-  int adapted_frames_;  // Number of frames scaled.
+  int frames_in_;  // Number of input frames.
+  int frames_out_;  // Number of output frames.
+  int frames_scaled_;  // Number of frames scaled.
   int adaption_changes_;  // Number of changes in scale factor.
   size_t previous_width_;  // Previous adapter output width.
   size_t previous_height_;  // Previous adapter output height.
diff --git a/talk/media/base/videoengine_unittest.h b/talk/media/base/videoengine_unittest.h
index b667cb0..e1c4a7d 100644
--- a/talk/media/base/videoengine_unittest.h
+++ b/talk/media/base/videoengine_unittest.h
@@ -790,8 +790,8 @@
     EXPECT_EQ(0.0, info.senders[0].fraction_lost);
     EXPECT_EQ(0, info.senders[0].firs_rcvd);
     EXPECT_EQ(0, info.senders[0].nacks_rcvd);
-    EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
-    EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
+    EXPECT_EQ(DefaultCodec().width, info.senders[0].send_frame_width);
+    EXPECT_EQ(DefaultCodec().height, info.senders[0].send_frame_height);
     EXPECT_GT(info.senders[0].framerate_input, 0);
     EXPECT_GT(info.senders[0].framerate_sent, 0);
 
@@ -848,8 +848,8 @@
     EXPECT_EQ(0.0, info.senders[0].fraction_lost);
     EXPECT_EQ(0, info.senders[0].firs_rcvd);
     EXPECT_EQ(0, info.senders[0].nacks_rcvd);
-    EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
-    EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
+    EXPECT_EQ(DefaultCodec().width, info.senders[0].send_frame_width);
+    EXPECT_EQ(DefaultCodec().height, info.senders[0].send_frame_height);
     EXPECT_GT(info.senders[0].framerate_input, 0);
     EXPECT_GT(info.senders[0].framerate_sent, 0);
 
@@ -918,12 +918,12 @@
         info.senders[0].packets_sent + info.senders[1].packets_sent);
     EXPECT_EQ(1U, info.senders[0].ssrcs().size());
     EXPECT_EQ(1234U, info.senders[0].ssrcs()[0]);
-    EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
-    EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
+    EXPECT_EQ(DefaultCodec().width, info.senders[0].send_frame_width);
+    EXPECT_EQ(DefaultCodec().height, info.senders[0].send_frame_height);
     EXPECT_EQ(1U, info.senders[1].ssrcs().size());
     EXPECT_EQ(5678U, info.senders[1].ssrcs()[0]);
-    EXPECT_EQ(kTestWidth, info.senders[1].frame_width);
-    EXPECT_EQ(kTestHeight, info.senders[1].frame_height);
+    EXPECT_EQ(kTestWidth, info.senders[1].send_frame_width);
+    EXPECT_EQ(kTestHeight, info.senders[1].send_frame_height);
     // The capturer must be unregistered here as it runs out of it's scope next.
     EXPECT_TRUE(channel_->SetCapturer(5678, NULL));
   }
diff --git a/talk/media/devices/v4llookup.cc b/talk/media/devices/v4llookup.cc
index ff128a4..e1ef9fe 100644
--- a/talk/media/devices/v4llookup.cc
+++ b/talk/media/devices/v4llookup.cc
@@ -50,10 +50,10 @@
 
           is_v4l2 = true;
         } else {
-          LOG(LS_ERROR) << "VIDIOC_QUERYCAP failed for " << device_path;
+          LOG_ERRNO(LS_ERROR) << "VIDIOC_QUERYCAP failed for " << device_path;
         }
       } else {
-        LOG(LS_ERROR) << "Failed to open " << device_path;
+        LOG_ERRNO(LS_ERROR) << "Failed to open " << device_path;
       }
     }
   }
diff --git a/talk/media/webrtc/fakewebrtcvideocapturemodule.h b/talk/media/webrtc/fakewebrtcvideocapturemodule.h
index 5628e01..d63e710 100644
--- a/talk/media/webrtc/fakewebrtcvideocapturemodule.h
+++ b/talk/media/webrtc/fakewebrtcvideocapturemodule.h
@@ -83,13 +83,18 @@
   virtual int32_t RegisterCaptureDataCallback(
       webrtc::VideoCaptureDataCallback& callback) {
     callback_ = &callback;
+    return 0;
   }
-  virtual void DeRegisterCaptureDataCallback() { callback_ = NULL; }
-  virtual void RegisterCaptureCallback(webrtc::VideoCaptureFeedBack& callback) {
-    // Not implemented.
+  virtual int32_t DeRegisterCaptureDataCallback() {
+    callback_ = NULL;
+    return 0;
   }
-  virtual void DeRegisterCaptureCallback() {
-    // Not implemented.
+  virtual int32_t RegisterCaptureCallback(
+      webrtc::VideoCaptureFeedBack& callback) {
+    return -1;  // not implemented
+  }
+  virtual int32_t DeRegisterCaptureCallback() {
+    return 0;
   }
   virtual int32_t SetCaptureDelay(int32_t delay) {
     delay_ = delay;
diff --git a/talk/media/webrtc/webrtcvideoengine.cc b/talk/media/webrtc/webrtcvideoengine.cc
index 178d538..d2e73ea 100644
--- a/talk/media/webrtc/webrtcvideoengine.cc
+++ b/talk/media/webrtc/webrtcvideoengine.cc
@@ -2300,8 +2300,18 @@
       sinfo.firs_rcvd = -1;
       sinfo.nacks_rcvd = -1;
       sinfo.rtt_ms = -1;
-      sinfo.frame_width = static_cast<int>(channel_stream_info->width());
-      sinfo.frame_height = static_cast<int>(channel_stream_info->height());
+      sinfo.input_frame_width = static_cast<int>(channel_stream_info->width());
+      sinfo.input_frame_height =
+          static_cast<int>(channel_stream_info->height());
+      webrtc::VideoCodec vie_codec;
+      if (engine()->vie()->codec()->GetSendCodec(channel_id, vie_codec) == 0) {
+        sinfo.send_frame_width = vie_codec.width;
+        sinfo.send_frame_height = vie_codec.height;
+      } else {
+        sinfo.send_frame_width = -1;
+        sinfo.send_frame_height = -1;
+        LOG_RTCERR1(GetSendCodec, channel_id);
+      }
       sinfo.framerate_input = channel_stream_info->framerate();
       sinfo.framerate_sent = send_channel->encoder_observer()->framerate();
       sinfo.nominal_bitrate = send_channel->encoder_observer()->bitrate();
diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc
index 4ad2ff5..f1030bd 100644
--- a/talk/media/webrtc/webrtcvoiceengine.cc
+++ b/talk/media/webrtc/webrtcvoiceengine.cc
@@ -229,6 +229,7 @@
   options.adjust_agc_delta.Set(0);
   options.experimental_agc.Set(false);
   options.experimental_aec.Set(false);
+  options.experimental_ns.Set(false);
   options.aec_dump.Set(false);
   options.experimental_acm.Set(false);
   return options;
@@ -717,6 +718,7 @@
   options.typing_detection.Set(false);
   options.experimental_agc.Set(false);
   options.experimental_aec.Set(false);
+  options.experimental_ns.Set(false);
 #endif
 
   LOG(LS_INFO) << "Applying audio options: " << options.ToString();
@@ -804,6 +806,25 @@
     }
   }
 
+#ifdef USE_WEBRTC_DEV_BRANCH
+  bool experimental_ns;
+  if (options.experimental_ns.Get(&experimental_ns)) {
+    webrtc::AudioProcessing* audioproc =
+        voe_wrapper_->base()->audio_processing();
+    // We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine
+    // returns NULL on audio_processing().
+    if (audioproc) {
+      if (audioproc->EnableExperimentalNs(experimental_ns) == -1) {
+        LOG_RTCERR1(EnableExperimentalNs, experimental_ns);
+        return false;
+      }
+    } else {
+      LOG(LS_VERBOSE) << "Experimental noise suppression set to "
+                      << experimental_ns;
+    }
+  }
+#endif  // USE_WEBRTC_DEV_BRANCH
+
   bool highpass_filter;
   if (options.highpass_filter.Get(&highpass_filter)) {
     if (voep->EnableHighPassFilter(highpass_filter) == -1) {
diff --git a/talk/p2p/base/stunport.cc b/talk/p2p/base/stunport.cc
index def3c9b..cee2fc4 100644
--- a/talk/p2p/base/stunport.cc
+++ b/talk/p2p/base/stunport.cc
@@ -328,7 +328,7 @@
     // related address is local socket address.
     set_related_address(socket_->GetLocalAddress());
     AddAddress(stun_addr, socket_->GetLocalAddress(), UDP_PROTOCOL_NAME,
-               STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_PRFLX, false);
+               STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, false);
   }
   SetResult(true);
 }
diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc
index 9a76d51..bc6bd09 100644
--- a/talk/session/media/channel.cc
+++ b/talk/session/media/channel.cc
@@ -27,6 +27,7 @@
 
 #include "talk/session/media/channel.h"
 
+#include "talk/base/bind.h"
 #include "talk/base/buffer.h"
 #include "talk/base/byteorder.h"
 #include "talk/base/common.h"
@@ -42,44 +43,17 @@
 
 namespace cricket {
 
+using talk_base::Bind;
+
 enum {
-  MSG_ENABLE = 1,
-  MSG_DISABLE,
-  MSG_MUTESTREAM,
-  MSG_ISSTREAMMUTED,
-  MSG_SETREMOTECONTENT,
-  MSG_SETLOCALCONTENT,
-  MSG_EARLYMEDIATIMEOUT,
-  MSG_CANINSERTDTMF,
-  MSG_INSERTDTMF,
-  MSG_GETSTATS,
-  MSG_SETRENDERER,
-  MSG_ADDRECVSTREAM,
-  MSG_REMOVERECVSTREAM,
-  MSG_ADDSENDSTREAM,
-  MSG_REMOVESENDSTREAM,
-  MSG_SETRINGBACKTONE,
-  MSG_PLAYRINGBACKTONE,
-  MSG_ADDSCREENCAST,
-  MSG_REMOVESCREENCAST,
-  MSG_SENDINTRAFRAME,
-  MSG_REQUESTINTRAFRAME,
+  MSG_EARLYMEDIATIMEOUT = 1,
   MSG_SCREENCASTWINDOWEVENT,
   MSG_RTPPACKET,
   MSG_RTCPPACKET,
   MSG_CHANNEL_ERROR,
-  MSG_SETCHANNELOPTIONS,
-  MSG_SCALEVOLUME,
-  MSG_HANDLEVIEWREQUEST,
   MSG_READYTOSENDDATA,
-  MSG_SENDDATA,
   MSG_DATARECEIVED,
-  MSG_SETCAPTURER,
-  MSG_ISSCREENCASTING,
-  MSG_GETSCREENCASTDETAILS,
-  MSG_SETSCREENCASTFACTORY,
   MSG_FIRSTPACKETRECEIVED,
-  MSG_SESSION_ERROR,
 };
 
 // Value specified in RFC 5764.
@@ -112,133 +86,11 @@
   return new NullScreenCapturerFactory();
 }
 
-struct SetContentData : public talk_base::MessageData {
-  SetContentData(const MediaContentDescription* content,
-                 ContentAction action,
-                 std::string* error_desc)
-      : content(content),
-        action(action),
-        error_desc(error_desc),
-        result(false) {
-  }
-  const MediaContentDescription* content;
-  ContentAction action;
-  std::string* error_desc;
-  bool result;
-};
-
-struct SetBandwidthData : public talk_base::MessageData {
-  explicit SetBandwidthData(int value) : value(value), result(false) {}
-  int value;
-  bool result;
-};
-
-struct SetRingbackToneMessageData : public talk_base::MessageData {
-  SetRingbackToneMessageData(const void* b, int l)
-      : buf(b),
-        len(l),
-        result(false) {
-  }
-  const void* buf;
-  int len;
-  bool result;
-};
-
-struct PlayRingbackToneMessageData : public talk_base::MessageData {
-  PlayRingbackToneMessageData(uint32 s, bool p, bool l)
-      : ssrc(s),
-        play(p),
-        loop(l),
-        result(false) {
-  }
-  uint32 ssrc;
-  bool play;
-  bool loop;
-  bool result;
-};
-typedef talk_base::TypedMessageData<bool> BoolMessageData;
-struct DtmfMessageData : public talk_base::MessageData {
-  DtmfMessageData(uint32 ssrc, int event, int duration, int flags)
-      : ssrc(ssrc),
-        event(event),
-        duration(duration),
-        flags(flags),
-        result(false) {
-  }
-  uint32 ssrc;
-  int event;
-  int duration;
-  int flags;
-  bool result;
-};
-struct ScaleVolumeMessageData : public talk_base::MessageData {
-  ScaleVolumeMessageData(uint32 s, double l, double r)
-      : ssrc(s),
-        left(l),
-        right(r),
-        result(false) {
-  }
-  uint32 ssrc;
-  double left;
-  double right;
-  bool result;
-};
-
-struct VoiceStatsMessageData : public talk_base::MessageData {
-  explicit VoiceStatsMessageData(VoiceMediaInfo* stats)
-      : result(false),
-        stats(stats) {
-  }
-  bool result;
-  VoiceMediaInfo* stats;
-};
-
-struct VideoStatsMessageData : public talk_base::MessageData {
-  explicit VideoStatsMessageData(VideoMediaInfo* stats)
-      : result(false),
-        stats(stats) {
-  }
-  bool result;
-  VideoMediaInfo* stats;
-};
-
 struct PacketMessageData : public talk_base::MessageData {
   talk_base::Buffer packet;
   talk_base::DiffServCodePoint dscp;
 };
 
-struct AudioRenderMessageData: public talk_base::MessageData {
-  AudioRenderMessageData(uint32 s, AudioRenderer* r, bool l)
-      : ssrc(s), renderer(r), is_local(l), result(false) {}
-  uint32 ssrc;
-  AudioRenderer* renderer;
-  bool is_local;
-  bool result;
-};
-
-struct VideoRenderMessageData : public talk_base::MessageData {
-  VideoRenderMessageData(uint32 s, VideoRenderer* r) : ssrc(s), renderer(r) {}
-  uint32 ssrc;
-  VideoRenderer* renderer;
-};
-
-struct AddScreencastMessageData : public talk_base::MessageData {
-  AddScreencastMessageData(uint32 s, const ScreencastId& id)
-      : ssrc(s),
-        window_id(id),
-        result(NULL) {
-  }
-  uint32 ssrc;
-  ScreencastId window_id;
-  VideoCapturer* result;
-};
-
-struct RemoveScreencastMessageData : public talk_base::MessageData {
-  explicit RemoveScreencastMessageData(uint32 s) : ssrc(s), result(false) {}
-  uint32 ssrc;
-  bool result;
-};
-
 struct ScreencastEventMessageData : public talk_base::MessageData {
   ScreencastEventMessageData(uint32 s, talk_base::WindowEvent we)
       : ssrc(s),
@@ -248,15 +100,6 @@
   talk_base::WindowEvent event;
 };
 
-struct ViewRequestMessageData : public talk_base::MessageData {
-  explicit ViewRequestMessageData(const ViewRequest& r)
-      : request(r),
-        result(false) {
-  }
-  ViewRequest request;
-  bool result;
-};
-
 struct VoiceChannelErrorMessageData : public talk_base::MessageData {
   VoiceChannelErrorMessageData(uint32 in_ssrc,
                                VoiceMediaChannel::Error in_error)
@@ -286,78 +129,9 @@
   DataMediaChannel::Error error;
 };
 
-struct SessionErrorMessageData : public talk_base::MessageData {
-  SessionErrorMessageData(cricket::BaseSession::Error error,
-                          const std::string& error_desc)
-      : error_(error),
-        error_desc_(error_desc) {}
 
-  BaseSession::Error error_;
-  std::string error_desc_;
-};
-
-struct SsrcMessageData : public talk_base::MessageData {
-  explicit SsrcMessageData(uint32 ssrc) : ssrc(ssrc), result(false) {}
-  uint32 ssrc;
-  bool result;
-};
-
-struct StreamMessageData : public talk_base::MessageData {
-  explicit StreamMessageData(const StreamParams& in_sp)
-      : sp(in_sp),
-        result(false) {
-  }
-  StreamParams sp;
-  bool result;
-};
-
-struct MuteStreamData : public talk_base::MessageData {
-  MuteStreamData(uint32 ssrc, bool mute)
-      : ssrc(ssrc), mute(mute), result(false) {}
-  uint32 ssrc;
-  bool mute;
-  bool result;
-};
-
-struct AudioOptionsMessageData : public talk_base::MessageData {
-  explicit AudioOptionsMessageData(const AudioOptions& options)
-      : options(options),
-        result(false) {
-  }
-  AudioOptions options;
-  bool result;
-};
-
-struct VideoOptionsMessageData : public talk_base::MessageData {
-  explicit VideoOptionsMessageData(const VideoOptions& options)
-      : options(options),
-        result(false) {
-  }
-  VideoOptions options;
-  bool result;
-};
-
-struct SetCapturerMessageData : public talk_base::MessageData {
-  SetCapturerMessageData(uint32 s, VideoCapturer* c)
-      : ssrc(s),
-        capturer(c),
-        result(false) {
-  }
-  uint32 ssrc;
-  VideoCapturer* capturer;
-  bool result;
-};
-
-struct IsScreencastingMessageData : public talk_base::MessageData {
-  IsScreencastingMessageData()
-      : result(false) {
-  }
-  bool result;
-};
-
-struct VideoChannel::ScreencastDetailsMessageData :
-    public talk_base::MessageData {
-  explicit ScreencastDetailsMessageData(uint32 s)
+struct VideoChannel::ScreencastDetailsData {
+  explicit ScreencastDetailsData(uint32 s)
       : ssrc(s), fps(0), screencast_max_pixels(0) {
   }
   uint32 ssrc;
@@ -365,14 +139,6 @@
   int screencast_max_pixels;
 };
 
-struct SetScreenCaptureFactoryMessageData : public talk_base::MessageData {
-  explicit SetScreenCaptureFactoryMessageData(
-      VideoChannel::ScreenCapturerFactory* f)
-      : screencapture_factory(f) {
-  }
-  VideoChannel::ScreenCapturerFactory* screencapture_factory;
-};
-
 static const char* PacketType(bool rtcp) {
   return (!rtcp) ? "RTP" : "RTCP";
 }
@@ -430,7 +196,7 @@
   Deinit();
   StopConnectionMonitor();
   FlushRtcpMessages();  // Send any outstanding RTCP packets.
-  Clear();  // eats any outstanding messages or packets
+  worker_thread_->Clear(this);  // eats any outstanding messages or packets
   // We must destroy the media channel before the transport channel, otherwise
   // the media channel may try to send on the dead transport channel. NULLing
   // is not an effective strategy since the sends will come on another thread.
@@ -478,63 +244,51 @@
   media_channel_->SetInterface(NULL);
 }
 
-// Can be called from thread other than worker thread
 bool BaseChannel::Enable(bool enable) {
-  Send(enable ? MSG_ENABLE : MSG_DISABLE);
+  worker_thread_->Invoke<void>(Bind(
+      enable ? &BaseChannel::EnableMedia_w : &BaseChannel::DisableMedia_w,
+      this));
   return true;
 }
 
-// Can be called from thread other than worker thread
 bool BaseChannel::MuteStream(uint32 ssrc, bool mute) {
-  MuteStreamData data(ssrc, mute);
-  Send(MSG_MUTESTREAM, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&BaseChannel::MuteStream_w, this, ssrc, mute));
 }
 
 bool BaseChannel::IsStreamMuted(uint32 ssrc) {
-  SsrcMessageData data(ssrc);
-  Send(MSG_ISSTREAMMUTED, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&BaseChannel::IsStreamMuted_w, this, ssrc));
 }
 
 bool BaseChannel::AddRecvStream(const StreamParams& sp) {
-  StreamMessageData data(sp);
-  Send(MSG_ADDRECVSTREAM, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&BaseChannel::AddRecvStream_w, this, sp));
 }
 
 bool BaseChannel::RemoveRecvStream(uint32 ssrc) {
-  SsrcMessageData data(ssrc);
-  Send(MSG_REMOVERECVSTREAM, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&BaseChannel::RemoveRecvStream_w, this, ssrc));
 }
 
 bool BaseChannel::AddSendStream(const StreamParams& sp) {
-  StreamMessageData data(sp);
-  Send(MSG_ADDSENDSTREAM, &data);
-  return data.result;
+  return InvokeOnWorker(
+      Bind(&MediaChannel::AddSendStream, media_channel(), sp));
 }
 
 bool BaseChannel::RemoveSendStream(uint32 ssrc) {
-  SsrcMessageData data(ssrc);
-  Send(MSG_REMOVESENDSTREAM, &data);
-  return data.result;
+  return InvokeOnWorker(
+      Bind(&MediaChannel::RemoveSendStream, media_channel(), ssrc));
 }
 
 bool BaseChannel::SetLocalContent(const MediaContentDescription* content,
                                   ContentAction action,
                                   std::string* error_desc) {
-  SetContentData data(content, action, error_desc);
-  Send(MSG_SETLOCALCONTENT, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&BaseChannel::SetLocalContent_w,
+                             this, content, action, error_desc));
 }
 
 bool BaseChannel::SetRemoteContent(const MediaContentDescription* content,
                                    ContentAction action,
                                    std::string* error_desc) {
-  SetContentData data(content, action, error_desc);
-  Send(MSG_SETREMOTECONTENT, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&BaseChannel::SetRemoteContent_w,
+                             this, content, action, error_desc));
 }
 
 void BaseChannel::StartConnectionMonitor(int cms) {
@@ -955,9 +709,12 @@
     if (!SetupDtlsSrtp(false)) {
       const std::string error_desc =
           "Couldn't set up DTLS-SRTP on RTP channel.";
-      SessionErrorMessageData data(BaseSession::ERROR_TRANSPORT, error_desc);
       // Sent synchronously.
-      signaling_thread()->Send(this, MSG_SESSION_ERROR, &data);
+      signaling_thread()->Invoke<void>(Bind(
+          &SetSessionError,
+          session_,
+          BaseSession::ERROR_TRANSPORT,
+          error_desc));
       return;
     }
 
@@ -965,9 +722,12 @@
       if (!SetupDtlsSrtp(true)) {
         const std::string error_desc =
             "Couldn't set up DTLS-SRTP on RTCP channel";
-        SessionErrorMessageData data(BaseSession::ERROR_TRANSPORT, error_desc);
         // Sent synchronously.
-        signaling_thread()->Send(this, MSG_SESSION_ERROR, &data);
+        signaling_thread()->Invoke<void>(Bind(
+            &SetSessionError,
+            session_,
+            BaseSession::ERROR_TRANSPORT,
+            error_desc));
         return;
       }
     }
@@ -1217,16 +977,6 @@
   return media_channel()->RemoveRecvStream(ssrc);
 }
 
-bool BaseChannel::AddSendStream_w(const StreamParams& sp) {
-  ASSERT(worker_thread() == talk_base::Thread::Current());
-  return media_channel()->AddSendStream(sp);
-}
-
-bool BaseChannel::RemoveSendStream_w(uint32 ssrc) {
-  ASSERT(worker_thread() == talk_base::Thread::Current());
-  return media_channel()->RemoveSendStream(ssrc);
-}
-
 bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
                                        ContentAction action,
                                        std::string* error_desc) {
@@ -1435,57 +1185,6 @@
 
 void BaseChannel::OnMessage(talk_base::Message *pmsg) {
   switch (pmsg->message_id) {
-    case MSG_ENABLE:
-      EnableMedia_w();
-      break;
-    case MSG_DISABLE:
-      DisableMedia_w();
-      break;
-    case MSG_MUTESTREAM: {
-      MuteStreamData* data = static_cast<MuteStreamData*>(pmsg->pdata);
-      data->result = MuteStream_w(data->ssrc, data->mute);
-      break;
-    }
-    case MSG_ISSTREAMMUTED: {
-      SsrcMessageData* data = static_cast<SsrcMessageData*>(pmsg->pdata);
-      data->result = IsStreamMuted_w(data->ssrc);
-      break;
-    }
-    case MSG_SETLOCALCONTENT: {
-      SetContentData* data = static_cast<SetContentData*>(pmsg->pdata);
-      data->result = SetLocalContent_w(data->content,
-                                       data->action,
-                                       data->error_desc);
-      break;
-    }
-    case MSG_SETREMOTECONTENT: {
-      SetContentData* data = static_cast<SetContentData*>(pmsg->pdata);
-      data->result = SetRemoteContent_w(data->content,
-                                        data->action,
-                                        data->error_desc);
-      break;
-    }
-    case MSG_ADDRECVSTREAM: {
-      StreamMessageData* data = static_cast<StreamMessageData*>(pmsg->pdata);
-      data->result = AddRecvStream_w(data->sp);
-      break;
-    }
-    case MSG_REMOVERECVSTREAM: {
-      SsrcMessageData* data = static_cast<SsrcMessageData*>(pmsg->pdata);
-      data->result = RemoveRecvStream_w(data->ssrc);
-      break;
-    }
-    case MSG_ADDSENDSTREAM: {
-      StreamMessageData* data = static_cast<StreamMessageData*>(pmsg->pdata);
-      data->result = AddSendStream_w(data->sp);
-      break;
-    }
-    case MSG_REMOVESENDSTREAM: {
-      SsrcMessageData* data = static_cast<SsrcMessageData*>(pmsg->pdata);
-      data->result = RemoveSendStream_w(data->ssrc);
-      break;
-    }
-
     case MSG_RTPPACKET:
     case MSG_RTCPPACKET: {
       PacketMessageData* data = static_cast<PacketMessageData*>(pmsg->pdata);
@@ -1497,41 +1196,18 @@
       SignalFirstPacketReceived(this);
       break;
     }
-    case MSG_SESSION_ERROR: {
-      SessionErrorMessageData* data = static_cast<SessionErrorMessageData*>
-          (pmsg->pdata);
-      SetSessionError(session_, data->error_, data->error_desc_);
-      break;
-    }
   }
 }
 
-void BaseChannel::Send(uint32 id, talk_base::MessageData *pdata) {
-  worker_thread_->Send(this, id, pdata);
-}
-
-void BaseChannel::Post(uint32 id, talk_base::MessageData *pdata) {
-  worker_thread_->Post(this, id, pdata);
-}
-
-void BaseChannel::PostDelayed(int cmsDelay, uint32 id,
-                              talk_base::MessageData *pdata) {
-  worker_thread_->PostDelayed(cmsDelay, this, id, pdata);
-}
-
-void BaseChannel::Clear(uint32 id, talk_base::MessageList* removed) {
-  worker_thread_->Clear(this, id, removed);
-}
-
 void BaseChannel::FlushRtcpMessages() {
   // Flush all remaining RTCP messages. This should only be called in
   // destructor.
   ASSERT(talk_base::Thread::Current() == worker_thread_);
   talk_base::MessageList rtcp_messages;
-  Clear(MSG_RTCPPACKET, &rtcp_messages);
+  worker_thread_->Clear(this, MSG_RTCPPACKET, &rtcp_messages);
   for (talk_base::MessageList::iterator it = rtcp_messages.begin();
        it != rtcp_messages.end(); ++it) {
-    Send(MSG_RTCPPACKET, it->pdata);
+    worker_thread_->Send(this, MSG_RTCPPACKET, it->pdata);
   }
 }
 
@@ -1570,21 +1246,17 @@
 }
 
 bool VoiceChannel::SetRemoteRenderer(uint32 ssrc, AudioRenderer* renderer) {
-  AudioRenderMessageData data(ssrc, renderer, false);
-  Send(MSG_SETRENDERER, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&VoiceMediaChannel::SetRemoteRenderer,
+                             media_channel(), ssrc, renderer));
 }
 
 bool VoiceChannel::SetLocalRenderer(uint32 ssrc, AudioRenderer* renderer) {
-  AudioRenderMessageData data(ssrc, renderer, true);
-  Send(MSG_SETRENDERER, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&VoiceMediaChannel::SetLocalRenderer,
+                             media_channel(), ssrc, renderer));
 }
 
 bool VoiceChannel::SetRingbackTone(const void* buf, int len) {
-  SetRingbackToneMessageData data(buf, len);
-  Send(MSG_SETRINGBACKTONE, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&VoiceChannel::SetRingbackTone_w, this, buf, len));
 }
 
 // TODO(juberti): Handle early media the right way. We should get an explicit
@@ -1595,17 +1267,17 @@
 void VoiceChannel::SetEarlyMedia(bool enable) {
   if (enable) {
     // Start the early media timeout
-    PostDelayed(kEarlyMediaTimeout, MSG_EARLYMEDIATIMEOUT);
+    worker_thread()->PostDelayed(kEarlyMediaTimeout, this,
+                                MSG_EARLYMEDIATIMEOUT);
   } else {
     // Stop the timeout if currently going.
-    Clear(MSG_EARLYMEDIATIMEOUT);
+    worker_thread()->Clear(this, MSG_EARLYMEDIATIMEOUT);
   }
 }
 
 bool VoiceChannel::PlayRingbackTone(uint32 ssrc, bool play, bool loop) {
-  PlayRingbackToneMessageData data(ssrc, play, loop);
-  Send(MSG_PLAYRINGBACKTONE, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&VoiceChannel::PlayRingbackTone_w,
+                             this, ssrc, play, loop));
 }
 
 bool VoiceChannel::PressDTMF(int digit, bool playout) {
@@ -1618,27 +1290,24 @@
 }
 
 bool VoiceChannel::CanInsertDtmf() {
-  BoolMessageData data(false);
-  Send(MSG_CANINSERTDTMF, &data);
-  return data.data();
+  return InvokeOnWorker(Bind(&VoiceMediaChannel::CanInsertDtmf,
+                             media_channel()));
 }
 
 bool VoiceChannel::InsertDtmf(uint32 ssrc, int event_code, int duration,
                               int flags) {
-  DtmfMessageData data(ssrc, event_code, duration, flags);
-  Send(MSG_INSERTDTMF, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&VoiceChannel::InsertDtmf_w, this,
+                             ssrc, event_code, duration, flags));
 }
 
 bool VoiceChannel::SetOutputScaling(uint32 ssrc, double left, double right) {
-  ScaleVolumeMessageData data(ssrc, left, right);
-  Send(MSG_SCALEVOLUME, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&VoiceMediaChannel::SetOutputScaling,
+                             media_channel(), ssrc, left, right));
 }
+
 bool VoiceChannel::GetStats(VoiceMediaInfo* stats) {
-  VoiceStatsMessageData data(stats);
-  Send(MSG_GETSTATS, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&VoiceMediaChannel::GetStats,
+                             media_channel(), stats));
 }
 
 void VoiceChannel::StartMediaMonitor(int cms) {
@@ -1855,10 +1524,6 @@
   }
 }
 
-bool VoiceChannel::CanInsertDtmf_w() {
-  return media_channel()->CanInsertDtmf();
-}
-
 bool VoiceChannel::InsertDtmf_w(uint32 ssrc, int event, int duration,
                                 int flags) {
   if (!enabled()) {
@@ -1868,74 +1533,16 @@
   return media_channel()->InsertDtmf(ssrc, event, duration, flags);
 }
 
-bool VoiceChannel::SetOutputScaling_w(uint32 ssrc, double left, double right) {
-  return media_channel()->SetOutputScaling(ssrc, left, right);
-}
-
-bool VoiceChannel::GetStats_w(VoiceMediaInfo* stats) {
-  return media_channel()->GetStats(stats);
-}
-
 bool VoiceChannel::SetChannelOptions(const AudioOptions& options) {
-  AudioOptionsMessageData data(options);
-  Send(MSG_SETCHANNELOPTIONS, &data);
-  return data.result;
-}
-
-bool VoiceChannel::SetChannelOptions_w(const AudioOptions& options) {
-  return media_channel()->SetOptions(options);
-}
-
-bool VoiceChannel::SetRenderer_w(uint32 ssrc, AudioRenderer* renderer,
-                                 bool is_local) {
-  if (is_local)
-    return media_channel()->SetLocalRenderer(ssrc, renderer);
-
-  return media_channel()->SetRemoteRenderer(ssrc, renderer);
+  return InvokeOnWorker(Bind(&VoiceMediaChannel::SetOptions,
+                             media_channel(), options));
 }
 
 void VoiceChannel::OnMessage(talk_base::Message *pmsg) {
   switch (pmsg->message_id) {
-    case MSG_SETRINGBACKTONE: {
-      SetRingbackToneMessageData* data =
-          static_cast<SetRingbackToneMessageData*>(pmsg->pdata);
-      data->result = SetRingbackTone_w(data->buf, data->len);
-      break;
-    }
-    case MSG_PLAYRINGBACKTONE: {
-      PlayRingbackToneMessageData* data =
-          static_cast<PlayRingbackToneMessageData*>(pmsg->pdata);
-      data->result = PlayRingbackTone_w(data->ssrc, data->play, data->loop);
-      break;
-    }
     case MSG_EARLYMEDIATIMEOUT:
       HandleEarlyMediaTimeout();
       break;
-    case MSG_CANINSERTDTMF: {
-      BoolMessageData* data =
-          static_cast<BoolMessageData*>(pmsg->pdata);
-      data->data() = CanInsertDtmf_w();
-      break;
-    }
-    case MSG_INSERTDTMF: {
-      DtmfMessageData* data =
-          static_cast<DtmfMessageData*>(pmsg->pdata);
-      data->result = InsertDtmf_w(data->ssrc, data->event, data->duration,
-                                  data->flags);
-      break;
-    }
-    case MSG_SCALEVOLUME: {
-      ScaleVolumeMessageData* data =
-          static_cast<ScaleVolumeMessageData*>(pmsg->pdata);
-      data->result = SetOutputScaling_w(data->ssrc, data->left, data->right);
-      break;
-    }
-    case MSG_GETSTATS: {
-      VoiceStatsMessageData* data =
-          static_cast<VoiceStatsMessageData*>(pmsg->pdata);
-      data->result = GetStats_w(data->stats);
-      break;
-    }
     case MSG_CHANNEL_ERROR: {
       VoiceChannelErrorMessageData* data =
           static_cast<VoiceChannelErrorMessageData*>(pmsg->pdata);
@@ -1943,18 +1550,6 @@
       delete data;
       break;
     }
-    case MSG_SETCHANNELOPTIONS: {
-      AudioOptionsMessageData* data =
-          static_cast<AudioOptionsMessageData*>(pmsg->pdata);
-      data->result = SetChannelOptions_w(data->options);
-      break;
-    }
-    case MSG_SETRENDERER: {
-      AudioRenderMessageData* data =
-          static_cast<AudioRenderMessageData*>(pmsg->pdata);
-      data->result = SetRenderer_w(data->ssrc, data->renderer, data->is_local);
-      break;
-    }
     default:
       BaseChannel::OnMessage(pmsg);
       break;
@@ -2068,68 +1663,65 @@
 }
 
 bool VideoChannel::SetRenderer(uint32 ssrc, VideoRenderer* renderer) {
-  VideoRenderMessageData data(ssrc, renderer);
-  Send(MSG_SETRENDERER, &data);
+  worker_thread()->Invoke<void>(Bind(
+      &VideoMediaChannel::SetRenderer, media_channel(), ssrc, renderer));
   return true;
 }
 
 bool VideoChannel::ApplyViewRequest(const ViewRequest& request) {
-  ViewRequestMessageData data(request);
-  Send(MSG_HANDLEVIEWREQUEST, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&VideoChannel::ApplyViewRequest_w, this, request));
 }
 
 VideoCapturer* VideoChannel::AddScreencast(
     uint32 ssrc, const ScreencastId& id) {
-  AddScreencastMessageData data(ssrc, id);
-  Send(MSG_ADDSCREENCAST, &data);
-  return data.result;
+  return worker_thread()->Invoke<VideoCapturer*>(Bind(
+      &VideoChannel::AddScreencast_w, this, ssrc, id));
 }
 
 bool VideoChannel::SetCapturer(uint32 ssrc, VideoCapturer* capturer) {
-  SetCapturerMessageData data(ssrc, capturer);
-  Send(MSG_SETCAPTURER, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&VideoMediaChannel::SetCapturer,
+                             media_channel(), ssrc, capturer));
 }
 
 bool VideoChannel::RemoveScreencast(uint32 ssrc) {
-  RemoveScreencastMessageData data(ssrc);
-  Send(MSG_REMOVESCREENCAST, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&VideoChannel::RemoveScreencast_w, this, ssrc));
 }
 
 bool VideoChannel::IsScreencasting() {
-  IsScreencastingMessageData data;
-  Send(MSG_ISSCREENCASTING, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&VideoChannel::IsScreencasting_w, this));
 }
 
 int VideoChannel::GetScreencastFps(uint32 ssrc) {
-  ScreencastDetailsMessageData data(ssrc);
-  Send(MSG_GETSCREENCASTDETAILS, &data);
+  ScreencastDetailsData data(ssrc);
+  worker_thread()->Invoke<void>(Bind(
+      &VideoChannel::GetScreencastDetails_w, this, &data));
   return data.fps;
 }
 
 int VideoChannel::GetScreencastMaxPixels(uint32 ssrc) {
-  ScreencastDetailsMessageData data(ssrc);
-  Send(MSG_GETSCREENCASTDETAILS, &data);
+  ScreencastDetailsData data(ssrc);
+  worker_thread()->Invoke<void>(Bind(
+      &VideoChannel::GetScreencastDetails_w, this, &data));
   return data.screencast_max_pixels;
 }
 
 bool VideoChannel::SendIntraFrame() {
-  Send(MSG_SENDINTRAFRAME);
+  worker_thread()->Invoke<void>(Bind(
+      &VideoMediaChannel::SendIntraFrame, media_channel()));
   return true;
 }
 
 bool VideoChannel::RequestIntraFrame() {
-  Send(MSG_REQUESTINTRAFRAME);
+  worker_thread()->Invoke<void>(Bind(
+      &VideoMediaChannel::RequestIntraFrame, media_channel()));
   return true;
 }
 
 void VideoChannel::SetScreenCaptureFactory(
     ScreenCapturerFactory* screencapture_factory) {
-  SetScreenCaptureFactoryMessageData data(screencapture_factory);
-  Send(MSG_SETSCREENCASTFACTORY, &data);
+  worker_thread()->Invoke<void>(Bind(
+      &VideoChannel::SetScreenCaptureFactory_w,
+      this, screencapture_factory));
 }
 
 void VideoChannel::ChangeState() {
@@ -2153,9 +1745,8 @@
 }
 
 bool VideoChannel::GetStats(VideoMediaInfo* stats) {
-  VideoStatsMessageData data(stats);
-  Send(MSG_GETSTATS, &data);
-  return data.result;
+  return InvokeOnWorker(Bind(&VideoMediaChannel::GetStats,
+                             media_channel(), stats));
 }
 
 void VideoChannel::StartMediaMonitor(int cms) {
@@ -2307,10 +1898,6 @@
   return ret;
 }
 
-void VideoChannel::SetRenderer_w(uint32 ssrc, VideoRenderer* renderer) {
-  media_channel()->SetRenderer(ssrc, renderer);
-}
-
 VideoCapturer* VideoChannel::AddScreencast_w(
     uint32 ssrc, const ScreencastId& id) {
   if (screencast_capturers_.find(ssrc) != screencast_capturers_.end()) {
@@ -2327,10 +1914,6 @@
   return screen_capturer;
 }
 
-bool VideoChannel::SetCapturer_w(uint32 ssrc, VideoCapturer* capturer) {
-  return media_channel()->SetCapturer(ssrc, capturer);
-}
-
 bool VideoChannel::RemoveScreencast_w(uint32 ssrc) {
   ScreencastMap::iterator iter = screencast_capturers_.find(ssrc);
   if (iter  == screencast_capturers_.end()) {
@@ -2346,8 +1929,8 @@
   return !screencast_capturers_.empty();
 }
 
-void VideoChannel::ScreencastDetails_w(
-    ScreencastDetailsMessageData* data) const {
+void VideoChannel::GetScreencastDetails_w(
+    ScreencastDetailsData* data) const {
   ScreencastMap::const_iterator iter = screencast_capturers_.find(data->ssrc);
   if (iter == screencast_capturers_.end()) {
     return;
@@ -2367,10 +1950,6 @@
   }
 }
 
-bool VideoChannel::GetStats_w(VideoMediaInfo* stats) {
-  return media_channel()->GetStats(stats);
-}
-
 void VideoChannel::OnScreencastWindowEvent_s(uint32 ssrc,
                                              talk_base::WindowEvent we) {
   ASSERT(signaling_thread() == talk_base::Thread::Current());
@@ -2378,41 +1957,12 @@
 }
 
 bool VideoChannel::SetChannelOptions(const VideoOptions &options) {
-  VideoOptionsMessageData data(options);
-  Send(MSG_SETCHANNELOPTIONS, &data);
-  return data.result;
-}
-
-bool VideoChannel::SetChannelOptions_w(const VideoOptions &options) {
-  return media_channel()->SetOptions(options);
+  return InvokeOnWorker(Bind(&VideoMediaChannel::SetOptions,
+                             media_channel(), options));
 }
 
 void VideoChannel::OnMessage(talk_base::Message *pmsg) {
   switch (pmsg->message_id) {
-    case MSG_SETRENDERER: {
-      const VideoRenderMessageData* data =
-          static_cast<VideoRenderMessageData*>(pmsg->pdata);
-      SetRenderer_w(data->ssrc, data->renderer);
-      break;
-    }
-    case MSG_ADDSCREENCAST: {
-      AddScreencastMessageData* data =
-          static_cast<AddScreencastMessageData*>(pmsg->pdata);
-      data->result = AddScreencast_w(data->ssrc, data->window_id);
-      break;
-    }
-    case MSG_SETCAPTURER: {
-      SetCapturerMessageData* data =
-          static_cast<SetCapturerMessageData*>(pmsg->pdata);
-      data->result = SetCapturer_w(data->ssrc, data->capturer);
-      break;
-    }
-    case MSG_REMOVESCREENCAST: {
-      RemoveScreencastMessageData* data =
-          static_cast<RemoveScreencastMessageData*>(pmsg->pdata);
-      data->result = RemoveScreencast_w(data->ssrc);
-      break;
-    }
     case MSG_SCREENCASTWINDOWEVENT: {
       const ScreencastEventMessageData* data =
           static_cast<ScreencastEventMessageData*>(pmsg->pdata);
@@ -2420,32 +1970,6 @@
       delete data;
       break;
     }
-    case  MSG_ISSCREENCASTING: {
-      IsScreencastingMessageData* data =
-          static_cast<IsScreencastingMessageData*>(pmsg->pdata);
-      data->result = IsScreencasting_w();
-      break;
-    }
-    case MSG_GETSCREENCASTDETAILS: {
-      ScreencastDetailsMessageData* data =
-          static_cast<ScreencastDetailsMessageData*>(pmsg->pdata);
-      ScreencastDetails_w(data);
-      break;
-    }
-    case MSG_SENDINTRAFRAME: {
-      SendIntraFrame_w();
-      break;
-    }
-    case MSG_REQUESTINTRAFRAME: {
-      RequestIntraFrame_w();
-      break;
-    }
-    case MSG_SETCHANNELOPTIONS: {
-      VideoOptionsMessageData* data =
-         static_cast<VideoOptionsMessageData*>(pmsg->pdata);
-      data->result = SetChannelOptions_w(data->options);
-      break;
-    }
     case MSG_CHANNEL_ERROR: {
       const VideoChannelErrorMessageData* data =
           static_cast<VideoChannelErrorMessageData*>(pmsg->pdata);
@@ -2453,24 +1977,6 @@
       delete data;
       break;
     }
-    case MSG_HANDLEVIEWREQUEST: {
-      ViewRequestMessageData* data =
-          static_cast<ViewRequestMessageData*>(pmsg->pdata);
-      data->result = ApplyViewRequest_w(data->request);
-      break;
-    }
-    case MSG_SETSCREENCASTFACTORY: {
-      SetScreenCaptureFactoryMessageData* data =
-          static_cast<SetScreenCaptureFactoryMessageData*>(pmsg->pdata);
-      SetScreenCaptureFactory_w(data->screencapture_factory);
-      break;
-    }
-    case MSG_GETSTATS: {
-      VideoStatsMessageData* data =
-          static_cast<VideoStatsMessageData*>(pmsg->pdata);
-      data->result = GetStats_w(data->stats);
-      break;
-    }
     default:
       BaseChannel::OnMessage(pmsg);
       break;
@@ -2516,9 +2022,8 @@
   if (!GetLocalSsrc(capturer, &ssrc)) {
     return;
   }
-  ScreencastEventMessageData* pdata =
-      new ScreencastEventMessageData(ssrc, we);
-  signaling_thread()->Post(this, MSG_SCREENCASTWINDOWEVENT, pdata);
+
+  OnScreencastWindowEvent(ssrc, we);
 }
 
 bool VideoChannel::GetLocalSsrc(const VideoCapturer* capturer, uint32* ssrc) {
@@ -2611,9 +2116,8 @@
 bool DataChannel::SendData(const SendDataParams& params,
                            const talk_base::Buffer& payload,
                            SendDataResult* result) {
-  SendDataMessageData message_data(params, &payload, result);
-  Send(MSG_SENDDATA, &message_data);
-  return message_data.succeeded;
+  return InvokeOnWorker(Bind(&DataMediaChannel::SendData,
+                             media_channel(), params, payload, result));
 }
 
 const ContentInfo* DataChannel::GetFirstContent(
@@ -2810,9 +2314,8 @@
     LOG(LS_ERROR) << "Failed to SetSend on data channel";
   }
 
-  // Post to trigger SignalReadyToSendData.
-  signaling_thread()->Post(this, MSG_READYTOSENDDATA,
-                           new DataChannelReadyToSendMessageData(send));
+  // Trigger SignalReadyToSendData asynchronously.
+  OnDataChannelReadyToSend(send);
 
   LOG(LS_INFO) << "Changing data state, recv=" << recv << " send=" << send;
 }
@@ -2827,13 +2330,6 @@
       delete data;
       break;
     }
-    case MSG_SENDDATA: {
-      SendDataMessageData* msg =
-          static_cast<SendDataMessageData*>(pmsg->pdata);
-      msg->succeeded = media_channel()->SendData(
-          msg->params, *(msg->payload), msg->result);
-      break;
-    }
     case MSG_DATARECEIVED: {
       DataReceivedMessageData* data =
           static_cast<DataReceivedMessageData*>(pmsg->pdata);
diff --git a/talk/session/media/channel.h b/talk/session/media/channel.h
index 91ea622..f3793cb 100644
--- a/talk/session/media/channel.h
+++ b/talk/session/media/channel.h
@@ -248,12 +248,6 @@
   SrtpFilter* srtp_filter() { return &srtp_filter_; }
   bool rtcp() const { return rtcp_; }
 
-  void Send(uint32 id, talk_base::MessageData* pdata = NULL);
-  void Post(uint32 id, talk_base::MessageData* pdata = NULL);
-  void PostDelayed(int cmsDelay, uint32 id = 0,
-                   talk_base::MessageData* pdata = NULL);
-  void Clear(uint32 id = talk_base::MQID_ANY,
-             talk_base::MessageList* removed = NULL);
   void FlushRtcpMessages();
 
   // NetworkInterface implementation, called by MediaEngine
@@ -346,6 +340,12 @@
   virtual void OnConnectionMonitorUpdate(SocketMonitor* monitor,
       const std::vector<ConnectionInfo>& infos) = 0;
 
+  // Helper function for invoking bool-returning methods on the worker thread.
+  template <class FunctorT>
+  bool InvokeOnWorker(const FunctorT& functor) {
+    return worker_thread_->Invoke<bool>(functor);
+  }
+
  private:
   sigslot::signal3<const void*, size_t, bool> SignalSendPacketPreCrypto;
   sigslot::signal3<const void*, size_t, bool> SignalSendPacketPostCrypto;
@@ -470,7 +470,6 @@
   bool SetRingbackTone_w(const void* buf, int len);
   bool PlayRingbackTone_w(uint32 ssrc, bool play, bool loop);
   void HandleEarlyMediaTimeout();
-  bool CanInsertDtmf_w();
   bool InsertDtmf_w(uint32 ssrc, int event, int duration, int flags);
   bool SetOutputScaling_w(uint32 ssrc, double left, double right);
   bool GetStats_w(VoiceMediaInfo* stats);
@@ -485,9 +484,6 @@
   void OnVoiceChannelError(uint32 ssrc, VoiceMediaChannel::Error error);
   void SendLastMediaError();
   void OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error);
-  // Configuration and setting.
-  bool SetChannelOptions_w(const AudioOptions& options);
-  bool SetRenderer_w(uint32 ssrc, AudioRenderer* renderer, bool is_local);
 
   static const int kEarlyMediaTimeout = 1000;
   bool received_media_;
@@ -557,7 +553,7 @@
 
  private:
   typedef std::map<uint32, VideoCapturer*> ScreencastMap;
-  struct ScreencastDetailsMessageData;
+  struct ScreencastDetailsData;
 
   // overrides from BaseChannel
   virtual void ChangeState();
@@ -568,22 +564,13 @@
   virtual bool SetRemoteContent_w(const MediaContentDescription* content,
                                   ContentAction action,
                                   std::string* error_desc);
-  void SendIntraFrame_w() {
-    media_channel()->SendIntraFrame();
-  }
-  void RequestIntraFrame_w() {
-    media_channel()->RequestIntraFrame();
-  }
-
   bool ApplyViewRequest_w(const ViewRequest& request);
-  void SetRenderer_w(uint32 ssrc, VideoRenderer* renderer);
 
   VideoCapturer* AddScreencast_w(uint32 ssrc, const ScreencastId& id);
-  bool SetCapturer_w(uint32 ssrc, VideoCapturer* capturer);
   bool RemoveScreencast_w(uint32 ssrc);
   void OnScreencastWindowEvent_s(uint32 ssrc, talk_base::WindowEvent we);
   bool IsScreencasting_w() const;
-  void ScreencastDetails_w(ScreencastDetailsMessageData* d) const;
+  void GetScreencastDetails_w(ScreencastDetailsData* d) const;
   void SetScreenCaptureFactory_w(
       ScreenCapturerFactory* screencapture_factory);
   bool GetStats_w(VideoMediaInfo* stats);
@@ -601,8 +588,6 @@
 
   void OnVideoChannelError(uint32 ssrc, VideoMediaChannel::Error error);
   void OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error);
-  // Configuration and setting.
-  bool SetChannelOptions_w(const VideoOptions& options);
 
   VoiceChannel* voice_channel_;
   VideoRenderer* renderer_;