Update to libjingle 0.6.1.

  - Add dummydevicemanager.
  - Remove underscores from the files names for app/webrtc folder.
  - Remove PeerConnection OnLocalStreamInitialized callback.
  - Fix webrtcjson.cc numeric locale formatting issue.
  - Don't start playout until the local content has been set.

Review URL: http://webrtc-codereview.appspot.com/149003/



git-svn-id: http://libjingle.googlecode.com/svn/trunk@85 dd674b97-3498-5ee5-1854-bdd07cd0ff33
diff --git a/CHANGELOG b/CHANGELOG
index d5c6d59..f846076 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,12 @@
 Libjingle
 
+0.6.1 - Sep 15, 2011
+  - Add dummydevicemanager.
+  - Remove underscores from the files names for app/webrtc folder.
+  - Remove PeerConnection OnLocalStreamInitialized callback.
+  - Fix webrtcjson.cc numeric locale formatting issue.
+  - Don't start playout until the local content has been set.
+
 0.6.0 - Sep 13, 2011
   - Add pub sub support
   - Add unit tests
diff --git a/talk/app/webrtc/peerconnection.h b/talk/app/webrtc/peerconnection.h
index 15c34b4..62c2504 100644
--- a/talk/app/webrtc/peerconnection.h
+++ b/talk/app/webrtc/peerconnection.h
@@ -51,14 +51,6 @@
   // serialized signaling message
   virtual void OnSignalingMessage(const std::string& msg) = 0;
 
-  // Triggered when a local stream has been added and initialized
-  // TODO: This callback was added intense to give the client a
-  // chance to set the capture device. It doesn't map to any JS callback. Once
-  // we figure out a better way to set video capture device, we should remove
-  // this callback.
-  virtual void OnLocalStreamInitialized(const std::string& stream_id,
-      bool video) = 0;
-
   // Triggered when a remote peer accepts a media connection.
   virtual void OnAddStream(const std::string& stream_id, bool video) = 0;
 
@@ -88,8 +80,7 @@
   virtual bool SignalingMessage(const std::string& msg) = 0;
 
   // Asynchronously adds a local stream device to the peer
-  // connection. The operation is complete when
-  // PeerConnectionObserver::OnLocalStreamInitialized is called.
+  // connection.
   virtual bool AddStream(const std::string& stream_id, bool video) = 0;
 
   // Asynchronously removes a local stream device from the peer
diff --git a/talk/app/webrtc/peerconnectionfactory.cc b/talk/app/webrtc/peerconnectionfactory.cc
index 0930bde..1b40c14 100644
--- a/talk/app/webrtc/peerconnectionfactory.cc
+++ b/talk/app/webrtc/peerconnectionfactory.cc
@@ -27,7 +27,7 @@
 
 #include "talk/app/webrtc/peerconnectionfactory.h"
 
-#include "talk/app/webrtc/peerconnection_proxy.h"
+#include "talk/app/webrtc/peerconnectionproxy.h"
 #include "talk/base/logging.h"
 #include "talk/p2p/client/basicportallocator.h"
 #include "talk/session/phone/channelmanager.h"
@@ -37,7 +37,7 @@
 PeerConnectionFactory::PeerConnectionFactory(
     cricket::PortAllocator* port_allocator,
     cricket::MediaEngineInterface* media_engine,
-    cricket::DeviceManager* device_manager,
+    cricket::DeviceManagerInterface* device_manager,
     talk_base::Thread* worker_thread)
     : initialized_(false),
       port_allocator_(port_allocator),
@@ -58,7 +58,7 @@
 }
 
 bool PeerConnectionFactory::Initialize() {
-  ASSERT(channel_manager_.get());
+  ASSERT(channel_manager_.get() != NULL);
   initialized_ = channel_manager_->Init();
   return initialized_;
 }
diff --git a/talk/app/webrtc/peerconnection_impl.cc b/talk/app/webrtc/peerconnectionimpl.cc
similarity index 93%
rename from talk/app/webrtc/peerconnection_impl.cc
rename to talk/app/webrtc/peerconnectionimpl.cc
index f16f3f2..28e4685 100644
--- a/talk/app/webrtc/peerconnection_impl.cc
+++ b/talk/app/webrtc/peerconnectionimpl.cc
@@ -25,9 +25,9 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "talk/app/webrtc/peerconnection_impl.h"
+#include "talk/app/webrtc/peerconnectionimpl.h"
 
-#include "talk/app/webrtc/webrtc_json.h"
+#include "talk/app/webrtc/webrtcjson.h"
 #include "talk/app/webrtc/webrtcsession.h"
 #include "talk/base/basicpacketsocketfactory.h"
 #include "talk/base/helpers.h"
@@ -108,9 +108,6 @@
     session->SignalRemoveStream.connect(
         this,
         &PeerConnectionImpl::OnRemoveStream);
-    session->SignalRtcMediaChannelCreated.connect(
-        this,
-        &PeerConnectionImpl::OnRtcMediaChannelCreated);
     session->SignalLocalDescription.connect(
         this,
         &PeerConnectionImpl::OnLocalDescription);
@@ -210,13 +207,6 @@
   }
 }
 
-void PeerConnectionImpl::OnRtcMediaChannelCreated(const std::string& stream_id,
-                                                  bool video) {
-  if (event_callback_) {
-    event_callback_->OnLocalStreamInitialized(stream_id, video);
-  }
-}
-
 PeerConnectionImpl::ReadyState PeerConnectionImpl::GetReadyState() {
   ReadyState ready_state;
   cricket::BaseSession::State state = session_->state();
diff --git a/talk/app/webrtc/peerconnection_impl.h b/talk/app/webrtc/peerconnectionimpl.h
similarity index 93%
rename from talk/app/webrtc/peerconnection_impl.h
rename to talk/app/webrtc/peerconnectionimpl.h
index 4c004ec..6ff2f25 100644
--- a/talk/app/webrtc/peerconnection_impl.h
+++ b/talk/app/webrtc/peerconnectionimpl.h
@@ -25,8 +25,8 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef TALK_APP_WEBRTC_PEERCONNECTION_IMPL_H_
-#define TALK_APP_WEBRTC_PEERCONNECTION_IMPL_H_
+#ifndef TALK_APP_WEBRTC_PEERCONNECTIONIMPL_H_
+#define TALK_APP_WEBRTC_PEERCONNECTIONIMPL_H_
 
 #include <string>
 #include <vector>
@@ -80,8 +80,6 @@
       const cricket::SessionDescription* desc,
       const std::vector<cricket::Candidate>& candidates);
   void OnFailedCall();
-  void OnRtcMediaChannelCreated(const std::string& stream_id,
-                                bool video);
   bool Init();
 
  private:
@@ -96,4 +94,4 @@
 
 }  // namespace webrtc
 
-#endif  // TALK_APP_WEBRTC_PEERCONNECTION_IMPL_H_
+#endif  // TALK_APP_WEBRTC_PEERCONNECTIONIMPL_H_
diff --git a/talk/app/webrtc/peerconnection_proxy.cc b/talk/app/webrtc/peerconnectionproxy.cc
similarity index 98%
rename from talk/app/webrtc/peerconnection_proxy.cc
rename to talk/app/webrtc/peerconnectionproxy.cc
index 6591151..fca3ad4 100644
--- a/talk/app/webrtc/peerconnection_proxy.cc
+++ b/talk/app/webrtc/peerconnectionproxy.cc
@@ -25,9 +25,9 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "talk/app/webrtc/peerconnection_proxy.h"
+#include "talk/app/webrtc/peerconnectionproxy.h"
 
-#include "talk/app/webrtc/peerconnection_impl.h"
+#include "talk/app/webrtc/peerconnectionimpl.h"
 #include "talk/base/logging.h"
 
 namespace webrtc {
diff --git a/talk/app/webrtc/peerconnection_proxy.h b/talk/app/webrtc/peerconnectionproxy.h
similarity index 95%
rename from talk/app/webrtc/peerconnection_proxy.h
rename to talk/app/webrtc/peerconnectionproxy.h
index 6e7fa6c..e83b4ec 100644
--- a/talk/app/webrtc/peerconnection_proxy.h
+++ b/talk/app/webrtc/peerconnectionproxy.h
@@ -25,8 +25,8 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef TALK_APP_WEBRTC_PEERCONNECTION_PROXY_H_
-#define TALK_APP_WEBRTC_PEERCONNECTION_PROXY_H_
+#ifndef TALK_APP_WEBRTC_PEERCONNECTIONPROXY_H_
+#define TALK_APP_WEBRTC_PEERCONNECTIONPROXY_H_
 
 #include <string>
 
@@ -78,4 +78,4 @@
 };
 }
 
-#endif  // TALK_APP_WEBRTC_PEERCONNECTION_PROXY_H_
+#endif  // TALK_APP_WEBRTC_PEERCONNECTIONPROXY_H_
diff --git a/talk/app/webrtc/webrtc.scons b/talk/app/webrtc/webrtc.scons
index 2394e69..271d413 100644
--- a/talk/app/webrtc/webrtc.scons
+++ b/talk/app/webrtc/webrtc.scons
@@ -8,11 +8,10 @@
   env,
   name = 'webrtc',
   srcs = [
-    # TODO: remove underscores from filenames
-    'peerconnection_impl.cc',
-    'peerconnection_proxy.cc',
+    'peerconnectionimpl.cc',
+    'peerconnectionproxy.cc',
     'peerconnectionfactory.cc',
-    'webrtc_json.cc',
+    'webrtcjson.cc',
     'webrtcsession.cc',
   ],
 )
@@ -26,13 +25,14 @@
     'webrtcsession_unittest.cc',
   ],
   libs = [
-    'srtp',
     'base',
+    'expat',
     'jpeg',
     'json',
     'webrtc',
     'p2p',
     'phone',
+    'srtp',
     'xmpp',
     'xmllite',
     'yuvscaler'
@@ -47,6 +47,7 @@
     'IOKit',
     'QTKit',
   ],
+  win_link_flags = [('', '/nodefaultlib:libcmt')[env.Bit('debug')]],
   lin_libs = [
     'rt',
     'dl',
diff --git a/talk/app/webrtc/webrtc_json.cc b/talk/app/webrtc/webrtcjson.cc
similarity index 89%
rename from talk/app/webrtc/webrtc_json.cc
rename to talk/app/webrtc/webrtcjson.cc
index d0e0256..1662e23 100644
--- a/talk/app/webrtc/webrtc_json.cc
+++ b/talk/app/webrtc/webrtcjson.cc
@@ -25,7 +25,7 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "talk/app/webrtc/webrtc_json.h"
+#include "talk/app/webrtc/webrtcjson.h"
 
 #include <stdio.h>
 #include <string>
@@ -33,40 +33,13 @@
 #include "talk/base/json.h"
 #include "talk/base/logging.h"
 #include "talk/base/stringutils.h"
-#include "talk/session/phone/mediasessionclient.h"
 #include "talk/session/phone/codec.h"
+#include "talk/session/phone/mediasessionclient.h"
 
 namespace webrtc {
 static const int kIceComponent = 1;
 static const int kIceFoundation = 1;
 
-bool GetStunServer(const Json::Value& value, StunServiceDetails* stunServer) {
-  if (value.type() != Json::objectValue && value.type() != Json::nullValue) {
-    LOG(LS_WARNING) << "Failed to parse stun values";
-    return false;
-  }
-
-  Json::Value stun;
-  if (GetValueFromJsonObject(value, "stun_service", &stun)) {
-    if (stun.type() == Json::objectValue) {
-      if (!GetStringFromJsonObject(stun, "host", &stunServer->host) ||
-          !GetStringFromJsonObject(stun, "service", &stunServer->service) ||
-          !GetStringFromJsonObject(stun, "protocol", &stunServer->protocol)) {
-        LOG(LS_WARNING) << "Failed to parse JSON value: "
-                        << value.toStyledString();
-        return false;
-      }
-    } else {
-      LOG(LS_WARNING) << "Failed to find the stun_service member.";
-      return false;
-    }
-  } else {
-    LOG(LS_WARNING) << "Wrong ValueType. Expect Json::objectValue).";
-    return false;
-  }
-  return true;
-}
-
 bool GetJsonSignalingMessage(
     const cricket::SessionDescription* sdp,
     const std::vector<cricket::Candidate>& candidates,
@@ -90,8 +63,9 @@
   Json::Value signal;
   Append(&signal, "media", media);
 
-  // now serialize
+  // Now serialize.
   *signaling_message = Serialize(signal);
+
   return true;
 }
 
@@ -191,7 +165,7 @@
       Append(&candidate, "foundation", kIceFoundation);
       Append(&candidate, "generation", iter->generation());
       Append(&candidate, "proto", iter->protocol());
-      Append(&candidate, "priority", iter->preference());
+      Append(&candidate, "priority", iter->preference_str());
       Append(&candidate, "ip", iter->address().IPAsString());
       Append(&candidate, "port", iter->address().PortAsString());
       Append(&candidate, "type", iter->type());
@@ -344,10 +318,10 @@
       return false;
     cand.set_protocol(proto);
 
-    double priority;
-    if (!GetDoubleFromJsonObject(*iter, "priority", &priority))
+    std::string priority;
+    if (!GetStringFromJsonObject(*iter, "priority", &priority))
       return false;
-    cand.set_preference_str(talk_base::ToString(priority));
+    cand.set_preference_str(priority);
 
     std::string str;
     talk_base::SocketAddress addr;
@@ -390,7 +364,7 @@
 std::vector<Json::Value> ReadValues(
     const Json::Value& value, const std::string& key) {
   std::vector<Json::Value> objects;
-  for (size_t i = 0; i < value[key].size(); ++i) {
+  for (Json::Value::ArrayIndex i = 0; i < value[key].size(); ++i) {
     objects.push_back(value[key][i]);
   }
   return objects;
@@ -412,7 +386,6 @@
   return value[key].asDouble();
 }
 
-// Add values
 void Append(Json::Value* object, const std::string& key, bool value) {
   (*object)[key] = Json::Value(value);
 }
@@ -420,19 +393,16 @@
 void Append(Json::Value* object, const std::string& key, char * value) {
   (*object)[key] = Json::Value(value);
 }
-void Append(Json::Value* object, const std::string& key, double value) {
-  (*object)[key] = Json::Value(value);
-}
-void Append(Json::Value* object, const std::string& key, float value) {
-  (*object)[key] = Json::Value(value);
-}
+
 void Append(Json::Value* object, const std::string& key, int value) {
   (*object)[key] = Json::Value(value);
 }
+
 void Append(Json::Value* object, const std::string& key,
             const std::string& value) {
   (*object)[key] = Json::Value(value);
 }
+
 void Append(Json::Value* object, const std::string& key, uint32 value) {
   (*object)[key] = Json::Value(value);
 }
diff --git a/talk/app/webrtc/webrtc_json.h b/talk/app/webrtc/webrtcjson.h
similarity index 91%
rename from talk/app/webrtc/webrtc_json.h
rename to talk/app/webrtc/webrtcjson.h
index b57adf0..906326d 100644
--- a/talk/app/webrtc/webrtc_json.h
+++ b/talk/app/webrtc/webrtcjson.h
@@ -25,8 +25,8 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef TALK_APP_WEBRTC_WEBRTC_JSON_H_
-#define TALK_APP_WEBRTC_WEBRTC_JSON_H_
+#ifndef TALK_APP_WEBRTC_WEBRTCJSON_H_
+#define TALK_APP_WEBRTC_WEBRTCJSON_H_
 
 #include <string>
 
@@ -35,8 +35,8 @@
 #else
 #include "third_party/jsoncpp/json.h"
 #endif
-#include "talk/session/phone/codec.h"
 #include "talk/p2p/base/candidate.h"
+#include "talk/session/phone/codec.h"
 
 namespace Json {
 class Value;
@@ -49,12 +49,6 @@
 class SessionDescription;
 }
 
-struct StunServiceDetails {
-  std::string host;
-  std::string service;
-  std::string protocol;
-};
-
 namespace webrtc {
 
 std::vector<Json::Value> ReadValues(const Json::Value& value,
@@ -98,12 +92,8 @@
 double ReadDouble(const Json::Value& value, const std::string& key);
 uint32 ReadUInt(const Json::Value& value, const std::string& key);
 
-// Add values
 void Append(Json::Value* object, const std::string& key, bool value);
-
 void Append(Json::Value* object, const std::string& key, char * value);
-void Append(Json::Value* object, const std::string& key, double value);
-void Append(Json::Value* object, const std::string& key, float value);
 void Append(Json::Value* object, const std::string& key, int value);
 void Append(Json::Value* object, const std::string& key,
             const std::string& value);
@@ -115,4 +105,4 @@
             const std::vector<Json::Value>& values);
 }
 
-#endif  // TALK_APP_WEBRTC_WEBRTC_JSON_H_
+#endif  // TALK_APP_WEBRTC_WEBRTCJSON_H_
diff --git a/talk/app/webrtc/webrtcsession.cc b/talk/app/webrtc/webrtcsession.cc
index d8046c4..1048828 100644
--- a/talk/app/webrtc/webrtcsession.cc
+++ b/talk/app/webrtc/webrtcsession.cc
@@ -132,9 +132,6 @@
   ASSERT(voice_channel != NULL);
   stream_info->channel = voice_channel;
 
-  if (!incoming()) {
-    SignalRtcMediaChannelCreated(stream_id, false);
-  }
   return true;
 }
 
@@ -149,9 +146,6 @@
   ASSERT(video_channel != NULL);
   stream_info->channel = video_channel;
 
-  if (!incoming()) {
-    SignalRtcMediaChannelCreated(stream_id, true);
-  }
   return true;
 }
 
@@ -457,17 +451,33 @@
   if (!incoming()) {
     // Trigger OnAddStream callback at the initiator
     const cricket::ContentInfo* video_content = GetFirstVideoContent(desc);
-    if (video_content) {
-      SignalAddStream(video_content->name, true);
+    if (video_content && !SendSignalAddStream(true)) {
+      LOG(LERROR) << "Video stream unexpected in answer.";
+      return false;
     } else {
       const cricket::ContentInfo* audio_content = GetFirstAudioContent(desc);
-      if (audio_content)
-        SignalAddStream(audio_content->name, false);
+      if (audio_content && !SendSignalAddStream(false)) {
+        LOG(LERROR) << "Audio stream unexpected in answer.";
+        return false;
+      }
     }
   }
   return true;
 }
 
+// Send the SignalAddStream with the stream_id based on the content type.
+bool WebRtcSession::SendSignalAddStream(bool video) {
+  StreamMap::const_iterator iter;
+  for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
+    StreamInfo* sinfo = (*iter);
+    if (sinfo->video == video) {
+      SignalAddStream(sinfo->stream_id, video);
+      return true;
+    }
+  }
+  return false;
+}
+
 cricket::SessionDescription* WebRtcSession::CreateOffer() {
   cricket::SessionDescription* offer = new cricket::SessionDescription();
   StreamMap::iterator iter;
diff --git a/talk/app/webrtc/webrtcsession.h b/talk/app/webrtc/webrtcsession.h
index bbddb07..11e389e 100644
--- a/talk/app/webrtc/webrtcsession.h
+++ b/talk/app/webrtc/webrtcsession.h
@@ -106,10 +106,6 @@
   // message from the remote peer with the candidates port equal to 0.
   sigslot::signal2<const std::string&, bool> SignalRemoveStream;
 
-  // This signal occurs when audio/video channel has been created for the
-  // new added stream.
-  sigslot::signal2<const std::string&, bool> SignalRtcMediaChannelCreated;
-
   // This signal occurs when the local candidate is ready
   sigslot::signal2<const cricket::SessionDescription*,
       const std::vector<cricket::Candidate>&> SignalLocalDescription;
@@ -186,6 +182,7 @@
 
   bool SetVideoCapture(bool capture);
   void EnableAllStreams();
+  bool SendSignalAddStream(bool video);
 
   cricket::Transport* transport_;
   cricket::ChannelManager* channel_manager_;
diff --git a/talk/app/webrtc/webrtcsession_unittest.cc b/talk/app/webrtc/webrtcsession_unittest.cc
index 648a5d6..7a07614 100644
--- a/talk/app/webrtc/webrtcsession_unittest.cc
+++ b/talk/app/webrtc/webrtcsession_unittest.cc
@@ -50,7 +50,6 @@
     kNone,
     kOnAddStream,
     kOnRemoveStream,
-    kOnRtcMediaChannelCreated,
     kOnLocalDescription,
     kOnFailedCall,
   };
@@ -84,12 +83,6 @@
     last_stream_id_ = stream_id;
     last_was_video_ = video;
   }
-  void OnRtcMediaChannelCreated(const std::string& stream_id,
-                                        bool video) {
-    callback_ids_.push_back(kOnRtcMediaChannelCreated);
-    last_stream_id_ = stream_id;
-    last_was_video_ = video;
-  }
   void OnLocalDescription(
       const cricket::SessionDescription* desc,
       const std::vector<cricket::Candidate>& candidates) {
@@ -183,8 +176,6 @@
     session_->SignalAddStream.connect(this, &WebRtcSessionTest::OnAddStream);
     session_->SignalRemoveStream.connect(this,
         &WebRtcSessionTest::OnRemoveStream);
-    session_->SignalRtcMediaChannelCreated.connect(this,
-        &WebRtcSessionTest::OnRtcMediaChannelCreated);
     session_->SignalLocalDescription.connect(this,
         &WebRtcSessionTest::OnLocalDescription);
     session_->SignalFailedCall.connect(this, &WebRtcSessionTest::OnFailedCall);
@@ -234,9 +225,6 @@
     if (!session_->CreateVoiceChannel(stream_id)) {
       return false;
     }
-    if (!WaitForCallback(kOnRtcMediaChannelCreated, 1000)) {
-      return false;
-    }
     return true;
   }
 
@@ -244,9 +232,6 @@
     if (!session_->CreateVideoChannel(stream_id)) {
       return false;
     }
-    if (!WaitForCallback(kOnRtcMediaChannelCreated, 1000)) {
-      return false;
-    }
     return true;
   }
 
diff --git a/talk/base/asynchttprequest.cc b/talk/base/asynchttprequest.cc
index 1e05d82..68f6100 100644
--- a/talk/base/asynchttprequest.cc
+++ b/talk/base/asynchttprequest.cc
@@ -29,7 +29,10 @@
 
 namespace talk_base {
 
-enum { MSG_TIMEOUT = SignalThread::ST_MSG_FIRST_AVAILABLE };
+enum {
+  MSG_TIMEOUT = SignalThread::ST_MSG_FIRST_AVAILABLE,
+  MSG_LAUNCH_REQUEST
+};
 static const int kDefaultHTTPTimeout = 30 * 1000;  // 30 sec
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -37,10 +40,16 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 AsyncHttpRequest::AsyncHttpRequest(const std::string &user_agent)
-    : firewall_(NULL), port_(80), secure_(false),
-      timeout_(kDefaultHTTPTimeout), fail_redirect_(false),
+    : start_delay_(0),
+      firewall_(NULL),
+      port_(80),
+      secure_(false),
+      timeout_(kDefaultHTTPTimeout),
+      fail_redirect_(false),
       factory_(Thread::Current()->socketserver(), user_agent),
-      pool_(&factory_), client_(user_agent.c_str(), &pool_), error_(HE_NONE)  {
+      pool_(&factory_),
+      client_(user_agent.c_str(), &pool_),
+      error_(HE_NONE) {
   client_.SignalHttpClientComplete.connect(this,
       &AsyncHttpRequest::OnComplete);
 }
@@ -49,22 +58,11 @@
 }
 
 void AsyncHttpRequest::OnWorkStart() {
-  factory_.SetProxy(proxy_);
-  if (secure_)
-    factory_.UseSSL(host_.c_str());
-
-  bool transparent_proxy = (port_ == 80) &&
-           ((proxy_.type == PROXY_HTTPS) || (proxy_.type == PROXY_UNKNOWN));
-  if (transparent_proxy) {
-    client_.set_proxy(proxy_);
+  if (start_delay_ <= 0) {
+    LaunchRequest();
+  } else {
+    Thread::Current()->PostDelayed(start_delay_, this, MSG_LAUNCH_REQUEST);
   }
-  client_.set_fail_redirect(fail_redirect_);
-  client_.set_server(SocketAddress(host_, port_));
-
-  LOG(LS_INFO) << "HttpRequest start: " << host_ + client_.request().path;
-
-  Thread::Current()->PostDelayed(timeout_, this, MSG_TIMEOUT);
-  client_.start();
 }
 
 void AsyncHttpRequest::OnWorkStop() {
@@ -91,14 +89,19 @@
 }
 
 void AsyncHttpRequest::OnMessage(Message* message) {
-  if (message->message_id != MSG_TIMEOUT) {
+  switch (message->message_id) {
+   case MSG_TIMEOUT:
+    LOG(LS_INFO) << "HttpRequest timed out";
+    client_.reset();
+    worker()->Quit();
+    break;
+   case MSG_LAUNCH_REQUEST:
+    LaunchRequest();
+    break;
+   default:
     SignalThread::OnMessage(message);
-    return;
+    break;
   }
-
-  LOG(LS_INFO) << "HttpRequest timed out";
-  client_.reset();
-  worker()->Quit();
 }
 
 void AsyncHttpRequest::DoWork() {
@@ -108,4 +111,23 @@
   Thread::Current()->ProcessMessages(kForever);
 }
 
+void AsyncHttpRequest::LaunchRequest() {
+  factory_.SetProxy(proxy_);
+  if (secure_)
+    factory_.UseSSL(host_.c_str());
+
+  bool transparent_proxy = (port_ == 80) &&
+           ((proxy_.type == PROXY_HTTPS) || (proxy_.type == PROXY_UNKNOWN));
+  if (transparent_proxy) {
+    client_.set_proxy(proxy_);
+  }
+  client_.set_fail_redirect(fail_redirect_);
+  client_.set_server(SocketAddress(host_, port_));
+
+  LOG(LS_INFO) << "HttpRequest start: " << host_ + client_.request().path;
+
+  Thread::Current()->PostDelayed(timeout_, this, MSG_TIMEOUT);
+  client_.start();
+}
+
 }  // namespace talk_base
diff --git a/talk/base/asynchttprequest.h b/talk/base/asynchttprequest.h
index f5d7f46..a1e8aa0 100644
--- a/talk/base/asynchttprequest.h
+++ b/talk/base/asynchttprequest.h
@@ -50,6 +50,11 @@
   explicit AsyncHttpRequest(const std::string &user_agent);
   ~AsyncHttpRequest();
 
+  // If start_delay is less than or equal to zero, this starts immediately.
+  // Start_delay defaults to zero.
+  int start_delay() const { return start_delay_; }
+  void set_start_delay(int delay) { start_delay_ = delay; }
+
   void set_proxy(const ProxyInfo& proxy) {
     proxy_ = proxy;
   }
@@ -93,6 +98,9 @@
   virtual void DoWork();
 
  private:
+  void LaunchRequest();
+
+  int start_delay_;
   ProxyInfo proxy_;
   FirewallManager* firewall_;
   std::string host_;
diff --git a/talk/base/asynchttprequest_unittest.cc b/talk/base/asynchttprequest_unittest.cc
index e8db1e0..b7a8a03 100644
--- a/talk/base/asynchttprequest_unittest.cc
+++ b/talk/base/asynchttprequest_unittest.cc
@@ -65,10 +65,13 @@
                              public sigslot::has_slots<> {
  public:
   AsyncHttpRequestTest()
-      : done_(false), server_(Thread::Current(), kServerAddr) {
+      : started_(false),
+        done_(false),
+        server_(Thread::Current(), kServerAddr) {
     server_.SignalHttpRequest.connect(this, &AsyncHttpRequestTest::OnRequest);
   }
 
+  bool started() const { return started_; }
   bool done() const { return done_; }
 
   AsyncHttpRequest* CreateGetRequest(const std::string& host, int port,
@@ -105,6 +108,8 @@
 
  protected:
   void OnRequest(HttpServer* server, HttpServerTransaction* t) {
+    started_ = true;
+
     if (t->request.path == kServerGetPath) {
       t->response.set_success("text/plain", new MemoryStream(kServerResponse));
     } else if (t->request.path == kServerPostPath) {
@@ -131,6 +136,7 @@
   }
 
  private:
+  bool started_;
   bool done_;
   TestHttpServer server_;
 };
@@ -139,7 +145,9 @@
   AsyncHttpRequest* req = CreateGetRequest(
       kServerHostnameAddr.hostname(), server().address().port(),
       kServerGetPath);
+  EXPECT_FALSE(started());
   req->Start();
+  EXPECT_TRUE_WAIT(started(), 100);  // Should have started by now.
   EXPECT_TRUE_WAIT(done(), 5000);
   std::string response;
   EXPECT_EQ(200U, req->response().scode);
@@ -188,4 +196,23 @@
   req->Destroy(true);
 }
 
+TEST_F(AsyncHttpRequestTest, TestGetSuccessDelay) {
+  AsyncHttpRequest* req = CreateGetRequest(
+      kServerHostnameAddr.hostname(), server().address().port(),
+      kServerGetPath);
+  req->set_start_delay(10);  // Delay 10ms.
+  req->Start();
+  Thread::SleepMs(5);
+  EXPECT_FALSE(started());  // Should not have started immediately.
+  EXPECT_TRUE_WAIT(started(), 200);  // Should have started by now.
+  EXPECT_TRUE_WAIT(done(), 5000);
+  std::string response;
+  EXPECT_EQ(200U, req->response().scode);
+  ASSERT_TRUE(req->response().document.get() != NULL);
+  req->response().document->Rewind();
+  req->response().document->ReadLine(&response);
+  EXPECT_EQ(kServerResponse, response);
+  req->Release();
+}
+
 }  // namespace talk_base
diff --git a/talk/base/json.h b/talk/base/json.h
index 5685503..d8cee35 100644
--- a/talk/base/json.h
+++ b/talk/base/json.h
@@ -31,7 +31,11 @@
 #include <string>
 #include <vector>
 
+#ifdef JSONCPP_RELATIVE_PATH
+#include "json/json.h"
+#else
 #include "third_party/jsoncpp/json.h"
+#endif
 
 // TODO: Move to talk_base namespace
 
diff --git a/talk/base/testechoserver.h b/talk/base/testechoserver.h
index 0b645d1..2c65167 100644
--- a/talk/base/testechoserver.h
+++ b/talk/base/testechoserver.h
@@ -1,5 +1,29 @@
-// Copyright 2008 Google Inc. All Rights Reserved.
-
+/*
+ * 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.
+ */
 
 #ifndef TALK_BASE_TESTECHOSERVER_H_
 #define TALK_BASE_TESTECHOSERVER_H_
diff --git a/talk/libjingle.scons b/talk/libjingle.scons
index 5e029b0..358f817 100644
--- a/talk/libjingle.scons
+++ b/talk/libjingle.scons
@@ -90,6 +90,10 @@
                  "pthread",
                  "rt",
                ],
+               'mac_libs': [
+                 "-lcrypto",
+                 "-lssl",
+               ],
              },
              mac_srcs = [
                "base/macasyncsocket.cc",
@@ -225,13 +229,13 @@
                "xmllite/xmlparser.cc",
                "xmllite/xmlprinter.cc",
                "xmpp/constants.cc",
+               "xmpp/hangoutpubsubclient.cc",
                "xmpp/iqtask.cc",
                "xmpp/jid.cc",
-               "xmpp/pubsubtasks.cc",
-               "xmpp/pubsubclient.cc",
-               "xmpp/hangoutpubsubclient.cc",
                "xmpp/mucroomconfigtask.cc",
                "xmpp/mucroomlookuptask.cc",
+               "xmpp/pubsubclient.cc",
+               "xmpp/pubsubtasks.cc",
                "xmpp/ratelimitmanager.cc",
                "xmpp/receivetask.cc",
                "xmpp/saslmechanism.cc",
diff --git a/talk/session/phone/channel.cc b/talk/session/phone/channel.cc
index 32ff5c1..f41c2ad 100644
--- a/talk/session/phone/channel.cc
+++ b/talk/session/phone/channel.cc
@@ -87,7 +87,8 @@
       enabled_(false),
       writable_(false),
       was_ever_writable_(false),
-      has_codec_(false),
+      has_local_content_(false),
+      has_remote_content_(false),
       muted_(false) {
   ASSERT(worker_thread_ == talk_base::Thread::Current());
   media_channel_->SetInterface(this);
@@ -750,16 +751,16 @@
 }
 
 void VoiceChannel::ChangeState() {
-  // render incoming data if we are the active call
-  // we receive data on the default channel and multiplexed streams
-  bool recv = enabled();
+  // Render incoming data if we're the active call, and we have the local
+  // content. We receive data on the default channel and multiplexed streams.
+  bool recv = enabled() && has_local_content();
   if (!media_channel()->SetPlayout(recv)) {
     SendLastMediaError();
   }
-
-  // Send outgoing data if we are the active call and we know their codec, and
-  // we have had some form of connectivity.
-  bool send = enabled() && has_codec() && was_ever_writable();
+    
+  // Send outgoing data if we're the active call, we have the remote content,
+  // and we have had some form of connectivity.
+  bool send = enabled() && has_remote_content() && was_ever_writable();
   SendFlags send_flag = send ? SEND_MICROPHONE : SEND_NOTHING;
   if (!media_channel()->SetSend(send_flag)) {
     LOG(LS_ERROR) << "Failed to SetSend " << send_flag << " on voice channel";
@@ -807,6 +808,12 @@
     ret = media_channel()->SetRecvRtpHeaderExtensions(
         audio->rtp_header_extensions());
   }
+  if (ret) {
+    set_has_local_content(true);
+    ChangeState();
+  } else {
+    LOG(LS_WARNING) << "Failed to set local voice description";
+  }
   return ret;
 }
 
@@ -847,8 +854,10 @@
 
   // update state
   if (ret) {
-    set_has_codec(true);
+    set_has_remote_content(true);
     ChangeState();
+  } else {
+    LOG(LS_WARNING) << "Failed to set remote voice description";
   }
   return ret;
 }
@@ -1056,17 +1065,17 @@
 }
 
 void VideoChannel::ChangeState() {
-  // render incoming data if we are the active call
-  // we receive data on the default channel and multiplexed streams
-  bool recv = enabled();
+  // Render incoming data if we're the active call, and we have the local
+  // content. We receive data on the default channel and multiplexed streams.
+  bool recv = enabled() && has_local_content();
   if (!media_channel()->SetRender(recv)) {
     LOG(LS_ERROR) << "Failed to SetRender on video channel";
     // TODO: Report error back to server.
   }
 
-  // Send outgoing data if we are the active call and we know their codec, and
-  // we have had some form of connectivity.
-  bool send = enabled() && has_codec() && was_ever_writable();
+  // Send outgoing data if we're the active call, we have the remote content,
+  // and we have had some form of connectivity.
+  bool send = enabled() && has_remote_content() && was_ever_writable();
   if (!media_channel()->SetSend(send)) {
     LOG(LS_ERROR) << "Failed to SetSend on video channel";
     // TODO: Report error back to server.
@@ -1127,6 +1136,12 @@
     ret = media_channel()->SetRecvRtpHeaderExtensions(
         video->rtp_header_extensions());
   }
+  if (ret) {
+    set_has_local_content(true);
+    ChangeState();
+  } else {
+    LOG(LS_WARNING) << "Failed to set local video description";
+  }
   return ret;
 }
 
@@ -1161,8 +1176,10 @@
         video->rtp_header_extensions());
   }
   if (ret) {
-    set_has_codec(true);
+    set_has_remote_content(true);
     ChangeState();
+  } else {
+    LOG(LS_WARNING) << "Failed to set remote video description";
   }
   return ret;
 }
diff --git a/talk/session/phone/channel.h b/talk/session/phone/channel.h
index 157999d..a35ed86 100644
--- a/talk/session/phone/channel.h
+++ b/talk/session/phone/channel.h
@@ -164,8 +164,10 @@
   void set_rtcp_transport_channel(TransportChannel* transport);
   bool writable() const { return writable_; }
   bool was_ever_writable() const { return was_ever_writable_; }
-  bool has_codec() const { return has_codec_; }
-  void set_has_codec(bool has_codec) { has_codec_ = has_codec; }
+  bool has_local_content() const { return has_local_content_; }
+  bool has_remote_content() const { return has_remote_content_; }
+  void set_has_local_content(bool has) { has_local_content_ = has; }
+  void set_has_remote_content(bool has) { has_remote_content_ = has; }
   bool muted() const { return muted_; }
   talk_base::Thread* signaling_thread() { return session_->signaling_thread(); }
   SrtpFilter* srtp_filter() { return &srtp_filter_; }
@@ -276,7 +278,8 @@
   bool enabled_;
   bool writable_;
   bool was_ever_writable_;
-  bool has_codec_;
+  bool has_local_content_;
+  bool has_remote_content_;
   bool muted_;
 };
 
diff --git a/talk/session/phone/dummydevicemanager.h b/talk/session/phone/dummydevicemanager.h
new file mode 100644
index 0000000..18bc63b
--- /dev/null
+++ b/talk/session/phone/dummydevicemanager.h
@@ -0,0 +1,51 @@
+/*
+ * libjingle
+ * Copyright 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.
+ */
+
+#ifndef TALK_SESSION_PHONE_DUMMYDEVICEMANAGER_H_
+#define TALK_SESSION_PHONE_DUMMYDEVICEMANAGER_H_
+
+#include <vector>
+
+#include "talk/session/phone/fakedevicemanager.h"
+#include "talk/session/phone/mediacommon.h"
+
+namespace cricket {
+
+class DummyDeviceManager : public FakeDeviceManager {
+ public:
+  DummyDeviceManager() {
+    std::vector<std::string> devices;
+    devices.push_back(DeviceManagerInterface::kDefaultDeviceName);
+    SetAudioInputDevices(devices);
+    SetAudioOutputDevices(devices);
+    SetVideoCaptureDevices(devices);
+  }
+};
+
+}  // namespace cricket
+
+#endif  // TALK_SESSION_PHONE_DUMMYDEVICEMANAGER_H_
diff --git a/talk/session/phone/fakedevicemanager.h b/talk/session/phone/fakedevicemanager.h
new file mode 100644
index 0000000..c096007
--- /dev/null
+++ b/talk/session/phone/fakedevicemanager.h
@@ -0,0 +1,161 @@
+/*
+ * libjingle
+ * Copyright 2008--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.
+ */
+
+#ifndef TALK_SESSION_PHONE_FAKEDEVICEMANAGER_H_
+#define TALK_SESSION_PHONE_FAKEDEVICEMANAGER_H_
+
+#include <string>
+#include <vector>
+
+#include "talk/session/phone/devicemanager.h"
+#include "talk/session/phone/mediacommon.h"
+
+namespace cricket {
+
+class FakeDeviceManager : public DeviceManagerInterface {
+ public:
+  FakeDeviceManager() {}
+  virtual bool Init() {
+    return true;
+  }
+  virtual void Terminate() {
+  }
+  virtual int GetCapabilities() {
+    std::vector<Device> devices;
+    int caps = VIDEO_RECV;
+    if (!input_devices_.empty()) {
+      caps |= AUDIO_SEND;
+    }
+    if (!output_devices_.empty()) {
+      caps |= AUDIO_RECV;
+    }
+    if (!vidcap_devices_.empty()) {
+      caps |= VIDEO_SEND;
+    }
+    return caps;
+  }
+  virtual bool GetAudioInputDevices(std::vector<Device>* devs) {
+    *devs = input_devices_;
+    return true;
+  }
+  virtual bool GetAudioOutputDevices(std::vector<Device>* devs) {
+    *devs = output_devices_;
+    return true;
+  }
+  virtual bool GetAudioInputDevice(const std::string& name, Device* out) {
+    return GetAudioDevice(true, name, out);
+  }
+  virtual bool GetAudioOutputDevice(const std::string& name, Device* out) {
+    return GetAudioDevice(false, name, out);
+  }
+  virtual bool GetVideoCaptureDevices(std::vector<Device>* devs) {
+    *devs = vidcap_devices_;
+    return true;
+  }
+
+  virtual bool GetDefaultVideoCaptureDevice(Device* device) {
+    if (vidcap_devices_.empty()) {
+      return false;
+    }
+    *device = vidcap_devices_[0];
+    return true;
+  }
+
+#ifdef OSX
+  bool QtKitToSgDevice(const std::string& qtkit_name, Device* out) {
+    out->name = qtkit_name;
+    out->id = "sg:" + qtkit_name;
+    return true;
+  }
+#endif
+
+  void SetAudioInputDevices(const std::vector<std::string>& devices) {
+    input_devices_.clear();
+    for (size_t i = 0; i < devices.size(); ++i) {
+      input_devices_.push_back(Device(devices[i], i));
+    }
+    SignalDevicesChange();
+  }
+  void SetAudioOutputDevices(const std::vector<std::string>& devices) {
+    output_devices_.clear();
+    for (size_t i = 0; i < devices.size(); ++i) {
+      output_devices_.push_back(Device(devices[i], i));
+    }
+    SignalDevicesChange();
+  }
+  void SetVideoCaptureDevices(const std::vector<std::string>& devices) {
+    vidcap_devices_.clear();
+    for (size_t i = 0; i < devices.size(); ++i) {
+      vidcap_devices_.push_back(Device(devices[i], i));
+    }
+    SignalDevicesChange();
+  }
+  virtual bool GetVideoCaptureDevice(const std::string& name,
+                                     Device* out) {
+    if (vidcap_devices_.empty())
+      return false;
+
+    // If the name is empty, return the default device.
+    if (name.empty() || name == kDefaultDeviceName) {
+      *out = vidcap_devices_[0];
+      return true;
+    }
+
+    return FindDeviceByName(vidcap_devices_, name, out);
+  }
+  bool GetAudioDevice(bool is_input, const std::string& name,
+                      Device* out) {
+    // If the name is empty, return the default device.
+    if (name.empty() || name == kDefaultDeviceName) {
+      *out = Device(name, -1);
+      return true;
+    }
+
+    return FindDeviceByName((is_input ? input_devices_ : output_devices_),
+                            name, out);
+  }
+  static bool FindDeviceByName(const std::vector<Device>& devices,
+                               const std::string& name,
+                               Device* out) {
+    for (std::vector<Device>::const_iterator it = devices.begin();
+         it != devices.end(); ++it) {
+      if (name == it->name) {
+        *out = *it;
+        return true;
+      }
+    }
+    return false;
+  }
+ private:
+  std::vector<Device> input_devices_;
+  std::vector<Device> output_devices_;
+  std::vector<Device> vidcap_devices_;
+};
+
+}  // namespace cricket
+
+#endif  // TALK_SESSION_PHONE_FAKEDEVICEMANAGER_H_
diff --git a/talk/session/phone/videocommon.h b/talk/session/phone/videocommon.h
index 27a2e90..995e800 100644
--- a/talk/session/phone/videocommon.h
+++ b/talk/session/phone/videocommon.h
@@ -65,6 +65,7 @@
   FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'),
   FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'),
   FOURCC_M420 = FOURCC('M', '4', '2', '0'),
+  FOURCC_Q420 = FOURCC('Q', '4', '2', '0'),
   FOURCC_24BG = FOURCC('2', '4', 'B', 'G'),
   FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'),
   FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'),
diff --git a/talk/session/phone/webrtcvideoengine.h b/talk/session/phone/webrtcvideoengine.h
index dc69a83..bb6b9c8 100644
--- a/talk/session/phone/webrtcvideoengine.h
+++ b/talk/session/phone/webrtcvideoengine.h
@@ -36,7 +36,7 @@
 #include "talk/session/phone/channel.h"
 #include "talk/session/phone/webrtccommon.h"
 #ifdef WEBRTC_RELATIVE_PATH
-#include "voice_engine/main/interface/vie_base.h"
+#include "video_engine/main/interface/vie_base.h"
 #else
 #include "third_party/webrtc/files/include/vie_base.h"
 #endif  // WEBRTC_RELATIVE_PATH
diff --git a/talk/session/phone/webrtcvoiceengine.cc b/talk/session/phone/webrtcvoiceengine.cc
index 561b025..9135fb3 100644
--- a/talk/session/phone/webrtcvoiceengine.cc
+++ b/talk/session/phone/webrtcvoiceengine.cc
@@ -243,7 +243,7 @@
   int ncodecs = voe_wrapper_->codec()->NumOfCodecs();
   for (int i = 0; i < ncodecs; ++i) {
     webrtc::CodecInst voe_codec;
-    if (voe_wrapper_->codec()->GetCodec(i, voe_codec) >= 0) {
+    if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) {
       // Skip uncompressed formats.
       if (_stricmp(voe_codec.plname, kL16CodecName) == 0) {
         continue;
@@ -729,7 +729,7 @@
   int ncodecs = voe_wrapper_->codec()->NumOfCodecs();
   for (int i = 0; i < ncodecs; ++i) {
     webrtc::CodecInst voe_codec;
-    if (voe_wrapper_->codec()->GetCodec(i, voe_codec) >= 0) {
+    if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) {
       AudioCodec codec(voe_codec.pltype, voe_codec.plname, voe_codec.plfreq,
                        voe_codec.rate, voe_codec.channels, 0);
       // Allow arbitrary rates for ISAC to be specified.
@@ -836,11 +836,12 @@
   static const char* kTracesToIgnore[] = {
     "\tfailed to GetReportBlockInformation",
     "GetRecCodec() failed to get received codec",
-    "GetRemoteRTCPData() failed to retrieve sender info for remote side",
-    "GetRTPStatistics() failed to measure RTT since no RTP packets have been received yet",  // NOLINT
+    "GetRemoteRTCPData() failed to measure statistics dueto lack of received RTP and/or RTCP packets",  // NOLINT
+    "GetRemoteRTCPData() failed to retrieve sender info for remoteside",
+    "GetRTPStatistics() failed to measure RTT since noRTP packets have been received yet",  // NOLINT
     "GetRTPStatistics() failed to read RTP statistics from the RTP/RTCP module",
-    "GetRTPStatistics() failed to retrieve RTT from the RTP/RTCP module",
-    "RTCPReceiver::SenderInfoReceived No received SR",
+    "GetRTPStatistics() failed to retrieve RTT fromthe RTP/RTCP module",
+    "webrtc::RTCPReceiver::SenderInfoReceived No received SR",
     "StatisticsRTP() no statisitics availble",
     NULL
   };
@@ -1033,14 +1034,7 @@
   SetSendSsrc(talk_base::CreateRandomNonZeroId());
 
   // Reset all recv codecs; they will be enabled via SetRecvCodecs.
-  int ncodecs = engine->voe()->codec()->NumOfCodecs();
-  for (int i = 0; i < ncodecs; ++i) {
-    webrtc::CodecInst voe_codec;
-    if (engine->voe()->codec()->GetCodec(i, voe_codec) >= 0) {
-      voe_codec.pltype = -1;
-      engine->voe()->codec()->SetRecPayloadType(voe_channel(), voe_codec);
-    }
-  }
+  ResetRecvCodecs(voe_channel());
 }
 
 WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() {
@@ -1437,6 +1431,24 @@
     return false;
   }
 
+  // Use the same recv payload types as our default channel.
+  ResetRecvCodecs(channel);
+  int ncodecs = engine()->voe()->codec()->NumOfCodecs();
+  for (int i = 0; i < ncodecs; ++i) {
+    webrtc::CodecInst voe_codec;
+    if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) {
+      voe_codec.rate = 0;  // Needed to make GetRecPayloadType work for ISAC
+      if (engine()->voe()->codec()->GetRecPayloadType(
+          voe_channel(), voe_codec) != -1) {
+        if (engine()->voe()->codec()->SetRecPayloadType(
+            channel, voe_codec) == -1) {
+          LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
+          return false;
+        }
+      }
+    }
+  }
+
   if (mux_channels_.empty() && playout_) {
     // This is the first stream in a multi user meeting. We can now
     // disable playback of the default stream. This since the default
@@ -1950,6 +1962,22 @@
   return true;
 }
 
+bool WebRtcVoiceMediaChannel::ResetRecvCodecs(int channel) {
+  int ncodecs = engine()->voe()->codec()->NumOfCodecs();
+  for (int i = 0; i < ncodecs; ++i) {
+    webrtc::CodecInst voe_codec;
+    if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) {
+      voe_codec.pltype = -1;
+      if (engine()->voe()->codec()->SetRecPayloadType(
+          channel, voe_codec) == -1) {
+        LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
 bool WebRtcVoiceMediaChannel::SetPlayout(int channel, bool playout) {
   if (playout) {
     LOG(LS_INFO) << "Starting playout for channel #" << channel;
diff --git a/talk/session/phone/webrtcvoiceengine.h b/talk/session/phone/webrtcvoiceengine.h
index 2f2ab13..66c9785 100644
--- a/talk/session/phone/webrtcvoiceengine.h
+++ b/talk/session/phone/webrtcvoiceengine.h
@@ -298,6 +298,7 @@
                        const std::vector<AudioCodec>& all_codecs,
                        webrtc::CodecInst* send_codec);
   bool EnableRtcp(int channel);
+  bool ResetRecvCodecs(int channel);
   bool SetPlayout(int channel, bool playout);
   static uint32 ParseSsrc(const void* data, size_t len, bool rtcp);
   static Error WebRtcErrorToChannelError(int err_code);
diff --git a/talk/session/phone/webrtcvoiceengine_unittest.cc b/talk/session/phone/webrtcvoiceengine_unittest.cc
index 768f1fd..f4e437f 100644
--- a/talk/session/phone/webrtcvoiceengine_unittest.cc
+++ b/talk/session/phone/webrtcvoiceengine_unittest.cc
@@ -244,6 +244,32 @@
   EXPECT_FALSE(channel_->SetRecvCodecs(codecs));
 }
 
+// Test that changes to recv codecs are applied to all streams.
+TEST_F(WebRtcVoiceEngineTest, SetRecvCodecsWithMultipleStreams) {
+  EXPECT_TRUE(SetupEngine());
+  std::vector<cricket::AudioCodec> codecs;
+  codecs.push_back(kIsacCodec);
+  codecs.push_back(kPcmuCodec);
+  codecs.push_back(kTelephoneEventCodec);
+  codecs[0].id = 106;  // collide with existing telephone-event
+  codecs[2].id = 126;
+  EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
+  EXPECT_TRUE(channel_->AddStream(2));
+  int channel_num2 = voe_.GetLastChannel();
+  webrtc::CodecInst gcodec;
+  talk_base::strcpyn(gcodec.plname, ARRAY_SIZE(gcodec.plname), "ISAC");
+  gcodec.plfreq = 16000;
+  EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num2, gcodec));
+  EXPECT_EQ(106, gcodec.pltype);
+  EXPECT_STREQ("ISAC", gcodec.plname);
+  talk_base::strcpyn(gcodec.plname, ARRAY_SIZE(gcodec.plname),
+      "telephone-event");
+  gcodec.plfreq = 8000;
+  EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num2, gcodec));
+  EXPECT_EQ(126, gcodec.pltype);
+  EXPECT_STREQ("telephone-event", gcodec.plname);
+}
+
 // Test that we apply codecs properly.
 TEST_F(WebRtcVoiceEngineTest, SetSendCodecs) {
   EXPECT_TRUE(SetupEngine());
@@ -584,6 +610,64 @@
   EXPECT_FALSE(voe_.GetPlayout(channel_num));
 }
 
+// Test that we can add and remove streams, and do proper send/playout.
+// We can receive on multiple streams, but will only send on one.
+TEST_F(WebRtcVoiceEngineTest, SendAndPlayoutWithMultipleStreams) {
+  EXPECT_TRUE(SetupEngine());
+  int channel_num1 = voe_.GetLastChannel();
+
+  // Start playout on the default channel.
+  EXPECT_TRUE(channel_->SetPlayout(true));
+  EXPECT_TRUE(voe_.GetPlayout(channel_num1));
+
+  // Adding another stream should disable playout on the default channel.
+  EXPECT_TRUE(channel_->AddStream(2));
+  int channel_num2 = voe_.GetLastChannel();
+  std::vector<cricket::AudioCodec> codecs;
+  codecs.push_back(kPcmuCodec);
+  EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+  EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
+  EXPECT_TRUE(voe_.GetSend(channel_num1));
+  EXPECT_FALSE(voe_.GetSend(channel_num2));
+
+  // Make sure only the new channel is played out.
+  EXPECT_FALSE(voe_.GetPlayout(channel_num1));
+  EXPECT_TRUE(voe_.GetPlayout(channel_num2));
+
+  // Adding yet another stream should have stream 2 and 3 enabled for playout.
+  EXPECT_TRUE(channel_->AddStream(3));
+  int channel_num3 = voe_.GetLastChannel();
+  EXPECT_FALSE(voe_.GetPlayout(channel_num1));
+  EXPECT_TRUE(voe_.GetPlayout(channel_num2));
+  EXPECT_TRUE(voe_.GetPlayout(channel_num3));
+  EXPECT_FALSE(voe_.GetSend(channel_num3));
+
+  // Stop sending.
+  EXPECT_TRUE(channel_->SetSend(cricket::SEND_NOTHING));
+  EXPECT_FALSE(voe_.GetSend(channel_num1));
+  EXPECT_FALSE(voe_.GetSend(channel_num2));
+  EXPECT_FALSE(voe_.GetSend(channel_num3));
+
+  // Stop playout.
+  EXPECT_TRUE(channel_->SetPlayout(false));
+  EXPECT_FALSE(voe_.GetPlayout(channel_num1));
+  EXPECT_FALSE(voe_.GetPlayout(channel_num2));
+  EXPECT_FALSE(voe_.GetPlayout(channel_num3));
+
+  // Restart playout and make sure the default channel still is not played out.
+  EXPECT_TRUE(channel_->SetPlayout(true));
+  EXPECT_FALSE(voe_.GetPlayout(channel_num1));
+  EXPECT_TRUE(voe_.GetPlayout(channel_num2));
+  EXPECT_TRUE(voe_.GetPlayout(channel_num3));
+
+  // Now remove the new streams and verify that the default channel is
+  // played out again.
+  EXPECT_TRUE(channel_->RemoveStream(3));
+  EXPECT_TRUE(channel_->RemoveStream(2));
+
+  EXPECT_TRUE(voe_.GetPlayout(channel_num1));
+}
+
 // Test that we can set the devices to use.
 TEST_F(WebRtcVoiceEngineTest, SetDevices) {
   EXPECT_TRUE(SetupEngine());
@@ -758,73 +842,6 @@
   EXPECT_EQ(0x99U, send_ssrc);
 }
 
-// Test that we can properly receive packets.
-TEST_F(WebRtcVoiceEngineTest, Recv) {
-  EXPECT_TRUE(SetupEngine());
-  int channel_num = voe_.GetLastChannel();
-  DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
-  EXPECT_TRUE(voe_.CheckPacket(channel_num, kPcmuFrame,
-                                      sizeof(kPcmuFrame)));
-}
-
-// Test that we can add and remove streams, and do proper send/playout.
-// We can receive on multiple streams, but will only send on one.
-TEST_F(WebRtcVoiceEngineTest, SendAndPlayoutWithMultipleStreams) {
-  EXPECT_TRUE(SetupEngine());
-  int channel_num1 = voe_.GetLastChannel();
-
-  // Start playout on the default channel.
-  EXPECT_TRUE(channel_->SetPlayout(true));
-  EXPECT_TRUE(voe_.GetPlayout(channel_num1));
-
-  // Adding another stream should disable playout on the default channel.
-  EXPECT_TRUE(channel_->AddStream(2));
-  int channel_num2 = voe_.GetLastChannel();
-  std::vector<cricket::AudioCodec> codecs;
-  codecs.push_back(kPcmuCodec);
-  EXPECT_TRUE(channel_->SetSendCodecs(codecs));
-  EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
-  EXPECT_TRUE(voe_.GetSend(channel_num1));
-  EXPECT_FALSE(voe_.GetSend(channel_num2));
-
-  // Make sure only the new channel is played out.
-  EXPECT_FALSE(voe_.GetPlayout(channel_num1));
-  EXPECT_TRUE(voe_.GetPlayout(channel_num2));
-
-  // Adding yet another stream should have stream 2 and 3 enabled for playout.
-  EXPECT_TRUE(channel_->AddStream(3));
-  int channel_num3 = voe_.GetLastChannel();
-  EXPECT_FALSE(voe_.GetPlayout(channel_num1));
-  EXPECT_TRUE(voe_.GetPlayout(channel_num2));
-  EXPECT_TRUE(voe_.GetPlayout(channel_num3));
-  EXPECT_FALSE(voe_.GetSend(channel_num3));
-
-  // Stop sending.
-  EXPECT_TRUE(channel_->SetSend(cricket::SEND_NOTHING));
-  EXPECT_FALSE(voe_.GetSend(channel_num1));
-  EXPECT_FALSE(voe_.GetSend(channel_num2));
-  EXPECT_FALSE(voe_.GetSend(channel_num3));
-
-  // Stop playout.
-  EXPECT_TRUE(channel_->SetPlayout(false));
-  EXPECT_FALSE(voe_.GetPlayout(channel_num1));
-  EXPECT_FALSE(voe_.GetPlayout(channel_num2));
-  EXPECT_FALSE(voe_.GetPlayout(channel_num3));
-
-  // Restart playout and make sure the default channel still is not played out.
-  EXPECT_TRUE(channel_->SetPlayout(true));
-  EXPECT_FALSE(voe_.GetPlayout(channel_num1));
-  EXPECT_TRUE(voe_.GetPlayout(channel_num2));
-  EXPECT_TRUE(voe_.GetPlayout(channel_num3));
-
-  // Now remove the new streams and verify that the default channel is
-  // played out again.
-  EXPECT_TRUE(channel_->RemoveStream(3));
-  EXPECT_TRUE(channel_->RemoveStream(2));
-
-  EXPECT_TRUE(voe_.GetPlayout(channel_num1));
-}
-
 // Test that we can set the outgoing SSRC properly with multiple streams.
 TEST_F(WebRtcVoiceEngineTest, SetSendSsrcWithMultipleStreams) {
   EXPECT_TRUE(SetupEngine());
@@ -839,11 +856,13 @@
   EXPECT_EQ(0x99U, send_ssrc);
 }
 
-// Test that we properly handle failures to add a stream.
-TEST_F(WebRtcVoiceEngineTest, AddStreamFail) {
+// Test that we can properly receive packets.
+TEST_F(WebRtcVoiceEngineTest, Recv) {
   EXPECT_TRUE(SetupEngine());
-  voe_.set_fail_create_channel(true);
-  EXPECT_FALSE(channel_->AddStream(2));
+  int channel_num = voe_.GetLastChannel();
+  DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
+  EXPECT_TRUE(voe_.CheckPacket(channel_num, kPcmuFrame,
+                                      sizeof(kPcmuFrame)));
 }
 
 // Test that we can properly receive packets on multiple streams.
@@ -888,6 +907,13 @@
   EXPECT_TRUE(channel_->RemoveStream(1));
 }
 
+// Test that we properly handle failures to add a stream.
+TEST_F(WebRtcVoiceEngineTest, AddStreamFail) {
+  EXPECT_TRUE(SetupEngine());
+  voe_.set_fail_create_channel(true);
+  EXPECT_FALSE(channel_->AddStream(2));
+}
+
 // Test that we properly clean up any streams that were added, even if
 // not explicitly removed.
 TEST_F(WebRtcVoiceEngineTest, StreamCleanup) {