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

git-svn-id: http://libjingle.googlecode.com/svn/trunk@100 dd674b97-3498-5ee5-1854-bdd07cd0ff33
diff --git a/CHANGELOG b/CHANGELOG
index 16d7ed6..cacbc90 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,10 @@
 Libjingle
 
+0.6.5 - Dec 12, 2011
+  - Add IPv6 support in SocketAddress.
+  - Change PeerConnectionFactory inteface.
+  - Bug fixes.
+
 0.6.4 - Nov 30, 2011
   - Branch app/webrtc to app/webrtcv1.
   - Add more base unit tests.
diff --git a/talk/app/webrtc/peerconnectionfactory.cc b/talk/app/webrtc/peerconnectionfactory.cc
index 1b40c14..a3dac39 100644
--- a/talk/app/webrtc/peerconnectionfactory.cc
+++ b/talk/app/webrtc/peerconnectionfactory.cc
@@ -35,22 +35,18 @@
 namespace webrtc {
 
 PeerConnectionFactory::PeerConnectionFactory(
-    cricket::PortAllocator* port_allocator,
     cricket::MediaEngineInterface* media_engine,
     cricket::DeviceManagerInterface* device_manager,
     talk_base::Thread* worker_thread)
     : initialized_(false),
-      port_allocator_(port_allocator),
       channel_manager_(new cricket::ChannelManager(media_engine,
                                                    device_manager,
                                                    worker_thread)) {
 }
 
 PeerConnectionFactory::PeerConnectionFactory(
-    cricket::PortAllocator* port_allocator,
     talk_base::Thread* worker_thread)
     : initialized_(false),
-      port_allocator_(port_allocator),
       channel_manager_(new cricket::ChannelManager(worker_thread)) {
 }
 
@@ -64,11 +60,12 @@
 }
 
 PeerConnection* PeerConnectionFactory::CreatePeerConnection(
+    cricket::PortAllocator* port_allocator,
     talk_base::Thread* signaling_thread) {
   PeerConnectionProxy* pc = NULL;
   if (initialized_) {
     pc =  new PeerConnectionProxy(
-        port_allocator_.get(), channel_manager_.get(), signaling_thread);
+        port_allocator, channel_manager_.get(), signaling_thread);
     if (!pc->Init()) {
       LOG(LERROR) << "Error in initializing PeerConnection";
       delete pc;
diff --git a/talk/app/webrtc/peerconnectionfactory.h b/talk/app/webrtc/peerconnectionfactory.h
index 7c65e05..ea509d6 100644
--- a/talk/app/webrtc/peerconnectionfactory.h
+++ b/talk/app/webrtc/peerconnectionfactory.h
@@ -51,21 +51,20 @@
 
 class PeerConnectionFactory {
  public:
-  PeerConnectionFactory(cricket::PortAllocator* port_allocator,
-                        cricket::MediaEngineInterface* media_engine,
+  PeerConnectionFactory(cricket::MediaEngineInterface* media_engine,
                         cricket::DeviceManagerInterface* device_manager,
                         talk_base::Thread* worker_thread);
-  PeerConnectionFactory(cricket::PortAllocator* port_allocator,
-                        talk_base::Thread* worker_thread);
+  PeerConnectionFactory(talk_base::Thread* worker_thread);
 
   virtual ~PeerConnectionFactory();
   bool Initialize();
 
-  PeerConnection* CreatePeerConnection(talk_base::Thread* signaling_thread);
+  PeerConnection* CreatePeerConnection(
+      cricket::PortAllocator* port_allocator,
+      talk_base::Thread* signaling_thread);
 
  private:
   bool initialized_;
-  talk_base::scoped_ptr<cricket::PortAllocator> port_allocator_;
   talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_;
 };
 
diff --git a/talk/app/webrtc/webrtcsession_unittest.cc b/talk/app/webrtc/webrtcsession_unittest.cc
index 7a07614..85339c0 100644
--- a/talk/app/webrtc/webrtcsession_unittest.cc
+++ b/talk/app/webrtc/webrtcsession_unittest.cc
@@ -36,10 +36,10 @@
 #include "talk/base/fakenetwork.h"
 #include "talk/base/scoped_ptr.h"
 #include "talk/base/thread.h"
+#include "talk/p2p/base/fakesession.h"
 #include "talk/p2p/base/portallocator.h"
 #include "talk/p2p/base/sessiondescription.h"
 #include "talk/p2p/client/fakeportallocator.h"
-#include "talk/session/phone/fakesession.h"
 #include "talk/session/phone/mediasessionclient.h"
 
 class WebRtcSessionTest
diff --git a/talk/app/webrtcv1/peerconnectionfactory.cc b/talk/app/webrtcv1/peerconnectionfactory.cc
index ab2e0d5..7bf2f89 100644
--- a/talk/app/webrtcv1/peerconnectionfactory.cc
+++ b/talk/app/webrtcv1/peerconnectionfactory.cc
@@ -35,22 +35,18 @@
 namespace webrtc {
 
 PeerConnectionFactory::PeerConnectionFactory(
-    cricket::PortAllocator* port_allocator,
     cricket::MediaEngineInterface* media_engine,
     cricket::DeviceManagerInterface* device_manager,
     talk_base::Thread* worker_thread)
     : initialized_(false),
-      port_allocator_(port_allocator),
       channel_manager_(new cricket::ChannelManager(media_engine,
                                                    device_manager,
                                                    worker_thread)) {
 }
 
 PeerConnectionFactory::PeerConnectionFactory(
-    cricket::PortAllocator* port_allocator,
     talk_base::Thread* worker_thread)
     : initialized_(false),
-      port_allocator_(port_allocator),
       channel_manager_(new cricket::ChannelManager(worker_thread)) {
 }
 
@@ -64,11 +60,12 @@
 }
 
 PeerConnection* PeerConnectionFactory::CreatePeerConnection(
+    cricket::PortAllocator* port_allocator,
     talk_base::Thread* signaling_thread) {
   PeerConnectionProxy* pc = NULL;
   if (initialized_) {
     pc =  new PeerConnectionProxy(
-        port_allocator_.get(), channel_manager_.get(), signaling_thread);
+        port_allocator, channel_manager_.get(), signaling_thread);
     if (!pc->Init()) {
       LOG(LERROR) << "Error in initializing PeerConnection";
       delete pc;
diff --git a/talk/app/webrtcv1/peerconnectionfactory.h b/talk/app/webrtcv1/peerconnectionfactory.h
index 7c65e05..ea509d6 100644
--- a/talk/app/webrtcv1/peerconnectionfactory.h
+++ b/talk/app/webrtcv1/peerconnectionfactory.h
@@ -51,21 +51,20 @@
 
 class PeerConnectionFactory {
  public:
-  PeerConnectionFactory(cricket::PortAllocator* port_allocator,
-                        cricket::MediaEngineInterface* media_engine,
+  PeerConnectionFactory(cricket::MediaEngineInterface* media_engine,
                         cricket::DeviceManagerInterface* device_manager,
                         talk_base::Thread* worker_thread);
-  PeerConnectionFactory(cricket::PortAllocator* port_allocator,
-                        talk_base::Thread* worker_thread);
+  PeerConnectionFactory(talk_base::Thread* worker_thread);
 
   virtual ~PeerConnectionFactory();
   bool Initialize();
 
-  PeerConnection* CreatePeerConnection(talk_base::Thread* signaling_thread);
+  PeerConnection* CreatePeerConnection(
+      cricket::PortAllocator* port_allocator,
+      talk_base::Thread* signaling_thread);
 
  private:
   bool initialized_;
-  talk_base::scoped_ptr<cricket::PortAllocator> port_allocator_;
   talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_;
 };
 
diff --git a/talk/app/webrtcv1/webrtcsession_unittest.cc b/talk/app/webrtcv1/webrtcsession_unittest.cc
index c8940d6..2c23d6a 100644
--- a/talk/app/webrtcv1/webrtcsession_unittest.cc
+++ b/talk/app/webrtcv1/webrtcsession_unittest.cc
@@ -36,10 +36,10 @@
 #include "talk/base/fakenetwork.h"
 #include "talk/base/scoped_ptr.h"
 #include "talk/base/thread.h"
+#include "talk/p2p/base/fakesession.h"
 #include "talk/p2p/base/portallocator.h"
 #include "talk/p2p/base/sessiondescription.h"
 #include "talk/p2p/client/fakeportallocator.h"
-#include "talk/session/phone/fakesession.h"
 #include "talk/session/phone/mediasessionclient.h"
 
 class WebRtcSessionTest
diff --git a/talk/base/autodetectproxy.cc b/talk/base/autodetectproxy.cc
index f79926d..37faa4d 100644
--- a/talk/base/autodetectproxy.cc
+++ b/talk/base/autodetectproxy.cc
@@ -107,7 +107,7 @@
                       proxy().address.hostname(),
                       sizeof address_hostname);
 
-    uint32 address_ip = proxy().address.ip();
+    IPAddress address_ip = proxy().address.ipaddr();
 
     uint16 address_port = proxy().address.port();
 
diff --git a/talk/base/basicpacketsocketfactory.cc b/talk/base/basicpacketsocketfactory.cc
index 42721ba..d1da08e 100644
--- a/talk/base/basicpacketsocketfactory.cc
+++ b/talk/base/basicpacketsocketfactory.cc
@@ -157,7 +157,8 @@
   } else {
     // Otherwise, try to find a port in the provided range.
     for (int port = min_port; ret < 0 && port <= max_port; ++port) {
-      ret = socket->Bind(talk_base::SocketAddress(local_address.ip(), port));
+      ret = socket->Bind(talk_base::SocketAddress(local_address.ipaddr(),
+                                                  port));
     }
   }
   return ret;
diff --git a/talk/base/fakenetwork.h b/talk/base/fakenetwork.h
index 67df88a..c5ae4b6 100644
--- a/talk/base/fakenetwork.h
+++ b/talk/base/fakenetwork.h
@@ -52,7 +52,7 @@
   void AddInterface(const SocketAddress& iface) {
     // ensure a unique name for the interface
     SocketAddress address("test" + talk_base::ToString(next_index_++), 0);
-    address.SetResolvedIP(iface.ip());
+    address.SetResolvedIP(iface.ipaddr());
     ifaces_.push_back(address);
     DoUpdateNetworks();
   }
@@ -89,7 +89,8 @@
     std::vector<Network*> networks;
     for (std::vector<SocketAddress>::iterator it = ifaces_.begin();
          it != ifaces_.end(); ++it) {
-      networks.push_back(new Network(it->hostname(), it->hostname(), it->ip()));
+      networks.push_back(new Network(it->hostname(), it->hostname(),
+                                     it->ipaddr()));
     }
     MergeNetworkList(networks, true);
   }
diff --git a/talk/base/fileutils.cc b/talk/base/fileutils.cc
index 4504d29..7b0d348 100644
--- a/talk/base/fileutils.cc
+++ b/talk/base/fileutils.cc
@@ -154,15 +154,17 @@
 #endif
 }
 
-scoped_ptr<FilesystemInterface> Filesystem::default_filesystem_;
+FilesystemInterface* Filesystem::default_filesystem_ = NULL;
+
 FilesystemInterface *Filesystem::EnsureDefaultFilesystem() {
-  if (!default_filesystem_.get())
+  if (!default_filesystem_) {
 #ifdef WIN32
-    default_filesystem_.reset(new Win32Filesystem());
+    default_filesystem_ = new Win32Filesystem();
 #else
-    default_filesystem_.reset(new UnixFilesystem());
+    default_filesystem_ = new UnixFilesystem();
 #endif
-    return default_filesystem_.get();
+  }
+  return default_filesystem_;
 }
 
 bool FilesystemInterface::CopyFolder(const Pathname &old_path,
diff --git a/talk/base/fileutils.h b/talk/base/fileutils.h
index 644516d..186c963 100644
--- a/talk/base/fileutils.h
+++ b/talk/base/fileutils.h
@@ -285,18 +285,18 @@
 class Filesystem {
  public:
   static FilesystemInterface *default_filesystem() {
-    ASSERT(default_filesystem_.get() != NULL);
-    return default_filesystem_.get();
+    ASSERT(default_filesystem_ != NULL);
+    return default_filesystem_;
   }
 
   static void set_default_filesystem(FilesystemInterface *filesystem) {
-    default_filesystem_.reset(filesystem);
+    default_filesystem_ = filesystem;
   }
 
   static FilesystemInterface *swap_default_filesystem(
       FilesystemInterface *filesystem) {
-    FilesystemInterface *cur = default_filesystem_.release();
-    default_filesystem_.reset(filesystem);
+    FilesystemInterface *cur = default_filesystem_;
+    default_filesystem_ = filesystem;
     return cur;
   }
 
@@ -425,7 +425,7 @@
   }
 
  private:
-  static scoped_ptr<FilesystemInterface> default_filesystem_;
+  static FilesystemInterface* default_filesystem_;
 
   static FilesystemInterface *EnsureDefaultFilesystem();
   DISALLOW_IMPLICIT_CONSTRUCTORS(Filesystem);
@@ -455,4 +455,3 @@
 }  // namespace talk_base
 
 #endif  // TALK_BASE_FILEUTILS_H_
-
diff --git a/talk/base/firewallsocketserver.cc b/talk/base/firewallsocketserver.cc
index a99c72e..71385f8 100644
--- a/talk/base/firewallsocketserver.cc
+++ b/talk/base/firewallsocketserver.cc
@@ -177,11 +177,11 @@
     const Rule& r = rules_[i];
     if ((r.p != p) && (r.p != FP_ANY))
       continue;
-    if ((r.src.ip() != src.ip()) && !r.src.IsAny())
+    if ((r.src.ipaddr() != src.ipaddr()) && !r.src.IsAny())
       continue;
     if ((r.src.port() != src.port()) && (r.src.port() != 0))
       continue;
-    if ((r.dst.ip() != dst.ip()) && !r.dst.IsAny())
+    if ((r.dst.ipaddr() != dst.ipaddr()) && !r.dst.IsAny())
       continue;
     if ((r.dst.port() != dst.port()) && (r.dst.port() != 0))
       continue;
diff --git a/talk/base/helpers.cc b/talk/base/helpers.cc
index 1abaa2d..855305e 100644
--- a/talk/base/helpers.cc
+++ b/talk/base/helpers.cc
@@ -205,8 +205,8 @@
 
 // This round about way of creating a global RNG is to safe-guard against
 // indeterminant static initialization order.
-scoped_ptr<RandomGenerator>& GetGlobalRng() {
-  static scoped_ptr<RandomGenerator> g_rng(new SecureRandomGenerator());
+RandomGenerator*& GetGlobalRng() {
+  static RandomGenerator* g_rng = new SecureRandomGenerator();
   return g_rng;
 }
 
@@ -218,9 +218,9 @@
 
 void SetRandomTestMode(bool test) {
   if (!test) {
-    GetGlobalRng().reset(new SecureRandomGenerator());
+    GetGlobalRng() = new SecureRandomGenerator();
   } else {
-    GetGlobalRng().reset(new TestRandomGenerator());
+    GetGlobalRng() = new TestRandomGenerator();
   }
 }
 
diff --git a/talk/base/macasyncsocket.cc b/talk/base/macasyncsocket.cc
index e31be57..4924333 100644
--- a/talk/base/macasyncsocket.cc
+++ b/talk/base/macasyncsocket.cc
@@ -328,9 +328,11 @@
   }
 
   if (res) {
-    // Add this socket to the run loop
-    source_ = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket_, 0);
+    // Add this socket to the run loop, at priority 1 so that it will be
+    // queued behind any pending signals.
+    source_ = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket_, 1);
     res = (source_ != NULL);
+    if (!res) errno = EINVAL;
   }
 
   if (res) {
diff --git a/talk/base/macsocketserver.cc b/talk/base/macsocketserver.cc
index 154b83d..5b2ec03 100644
--- a/talk/base/macsocketserver.cc
+++ b/talk/base/macsocketserver.cc
@@ -41,6 +41,47 @@
   ASSERT(found == 1);
 }
 
+bool MacBaseSocketServer::SetPosixSignalHandler(int signum,
+                                                void (*handler)(int)) {
+  Dispatcher* dispatcher = signal_dispatcher();
+  if (!PhysicalSocketServer::SetPosixSignalHandler(signum, handler)) {
+    return false;
+  }
+
+  // Only register the FD once, when the first custom handler is installed.
+  if (!dispatcher && (dispatcher = signal_dispatcher())) {
+    CFFileDescriptorContext ctx = { 0 };
+    ctx.info = this;
+
+    CFFileDescriptorRef desc = CFFileDescriptorCreate(
+        kCFAllocatorDefault,
+        dispatcher->GetDescriptor(),
+        false,
+        &MacBaseSocketServer::FileDescriptorCallback,
+        &ctx);
+    if (!desc) {
+      return false;
+    }
+
+    CFFileDescriptorEnableCallBacks(desc, kCFFileDescriptorReadCallBack);
+    CFRunLoopSourceRef ref =
+        CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, desc, 0);
+
+    if (!ref) {
+      CFRelease(desc);
+      return false;
+    }
+
+    CFRunLoopAddSource(CFRunLoopGetCurrent(), ref, kCFRunLoopCommonModes);
+    CFRelease(desc);
+    CFRelease(ref);
+  }
+
+  return true;
+}
+
+// Used to disable socket events from waking our message queue when
+// process_io is false.  Does not disable signal event handling though.
 void MacBaseSocketServer::EnableSocketCallbacks(bool enable) {
   for (std::set<MacAsyncSocket*>::iterator it = sockets().begin();
        it != sockets().end(); ++it) {
@@ -52,6 +93,21 @@
   }
 }
 
+void MacBaseSocketServer::FileDescriptorCallback(CFFileDescriptorRef fd,
+                                                 CFOptionFlags flags,
+                                                 void* context) {
+  MacBaseSocketServer* this_ss =
+      reinterpret_cast<MacBaseSocketServer*>(context);
+  ASSERT(this_ss);
+  Dispatcher* signal_dispatcher = this_ss->signal_dispatcher();
+  ASSERT(signal_dispatcher);
+
+  signal_dispatcher->OnPreEvent(DE_READ);
+  signal_dispatcher->OnEvent(DE_READ, 0);
+  CFFileDescriptorEnableCallBacks(fd, kCFFileDescriptorReadCallBack);
+}
+
+
 ///////////////////////////////////////////////////////////////////////////////
 // MacCFSocketServer
 ///////////////////////////////////////////////////////////////////////////////
@@ -225,6 +281,9 @@
 // MacCarbonAppSocketServer
 ///////////////////////////////////////////////////////////////////////////////
 
+// Carbon is deprecated for x64.  Switch to Cocoa
+#if !defined(__x86_64__)
+
 MacCarbonAppSocketServer::MacCarbonAppSocketServer()
     : event_queue_(GetCurrentEventQueue()) {
   // Install event handler
@@ -296,6 +355,7 @@
   }
   ReleaseEvent(wake_up);
 }
+#endif
 
 ///////////////////////////////////////////////////////////////////////////////
 // MacNotificationsSocketServer
diff --git a/talk/base/macsocketserver.h b/talk/base/macsocketserver.h
index 6a4a729..53118b8 100644
--- a/talk/base/macsocketserver.h
+++ b/talk/base/macsocketserver.h
@@ -31,6 +31,9 @@
   void RegisterSocket(MacAsyncSocket* socket);
   void UnregisterSocket(MacAsyncSocket* socket);
 
+  // PhysicalSocketServer Overrides
+  virtual bool SetPosixSignalHandler(int signum, void (*handler)(int));
+
  protected:
   void EnableSocketCallbacks(bool enable);
   const std::set<MacAsyncSocket*>& sockets() {
@@ -38,6 +41,10 @@
   }
 
  private:
+  static void FileDescriptorCallback(CFFileDescriptorRef ref,
+                                     CFOptionFlags flags,
+                                     void* context);
+
   std::set<MacAsyncSocket*> sockets_;
 };
 
diff --git a/talk/base/nat_unittest.cc b/talk/base/nat_unittest.cc
index 3a2c778..a7fc3b1 100644
--- a/talk/base/nat_unittest.cc
+++ b/talk/base/nat_unittest.cc
@@ -195,7 +195,9 @@
 
   SocketAddress int_addr("127.0.0.1", 0);
   std::string ext_ip1 = "127.0.0.1";
-  std::string ext_ip2 = SocketAddress::IPToString(networks[0]->ip());
+  std::string ext_ip2 = networks[0]->ip().ToString();
+
+  LOG(LS_INFO) << "selected ip " << ext_ip2;
 
   SocketAddress ext_addrs[4] = {
       SocketAddress(ext_ip1, 0),
@@ -226,11 +228,11 @@
       new PhysicalSocketServer());
 
   SocketAddress int_addr, ext_addrs[4];
-  int_addr.SetIP(int_vss->GetNextIP());
-  ext_addrs[0].SetIP(ext_vss->GetNextIP());
-  ext_addrs[1].SetIP(ext_vss->GetNextIP());
-  ext_addrs[2].SetIP(ext_addrs[0].ip());
-  ext_addrs[3].SetIP(ext_addrs[1].ip());
+  int_addr.SetIP(IPAddress(int_vss->GetNextIP()));
+  ext_addrs[0].SetIP(IPAddress(ext_vss->GetNextIP()));
+  ext_addrs[1].SetIP(IPAddress(ext_vss->GetNextIP()));
+  ext_addrs[2].SetIP(ext_addrs[0].ipaddr());
+  ext_addrs[3].SetIP(ext_addrs[1].ipaddr());
 
   TestBindings(int_vss, int_addr, ext_vss, ext_addrs);
   TestFilters(int_vss, int_addr, ext_vss, ext_addrs);
diff --git a/talk/base/network.cc b/talk/base/network.cc
index d6ecbbf..9d1a83d 100644
--- a/talk/base/network.cc
+++ b/talk/base/network.cc
@@ -166,7 +166,7 @@
     struct sockaddr_in* inaddr =
         reinterpret_cast<struct sockaddr_in*>(&ptr->ifr_ifru.ifru_addr);
     if (inaddr->sin_family == AF_INET) {
-      uint32 ip = ntohl(inaddr->sin_addr.s_addr);
+      IPAddress ip(inaddr->sin_addr);
       scoped_ptr<Network> network(
           new Network(ptr->ifr_name, ptr->ifr_name, ip));
       network->set_ignored(IsIgnoredNetwork(*network));
@@ -201,6 +201,8 @@
 
   scoped_array<char> buf(new char[len]);
   IP_ADAPTER_INFO *infos = reinterpret_cast<IP_ADAPTER_INFO *>(buf.get());
+  // TODO: GetAdaptersInfo is IPv4 only. Replace with GetAddressesInfo when
+  // IPv6 support is needed in Network.
   DWORD ret = GetAdaptersInfo(infos, &len);
   if (ret != NO_ERROR) {
     LOG_ERR_EX(LS_ERROR, ret) << "GetAdaptersInfo failed";
@@ -225,12 +227,13 @@
     name = ost.str();
     count++;
 #endif  // !_DEBUG
-
-    scoped_ptr<Network> network(new Network(name, info->Description,
-        SocketAddress::StringToIP(info->IpAddressList.IpAddress.String)));
-    network->set_ignored(IsIgnoredNetwork(*network));
-    if (include_ignored || !network->ignored()) {
-      networks->push_back(network.release());
+    IPAddress ip;
+    if (IPFromString(info->IpAddressList.IpAddress.String, &ip)) {
+      scoped_ptr<Network> network(new Network(name, info->Description, ip));
+      network->set_ignored(IsIgnoredNetwork(*network));
+      if (include_ignored || !network->ignored()) {
+        networks->push_back(network.release());
+      }
     }
   }
 
@@ -257,7 +260,10 @@
 #endif
 
   // Ignore any networks with a 0.x.y.z IP
-  return (network.ip() < 0x01000000);
+  if (network.ip().family() == AF_INET) {
+    return (network.ip().v4AddressAsHostOrderInteger() < 0x01000000);
+  }
+  return false;
 }
 
 void BasicNetworkManager::StartUpdating() {
@@ -312,7 +318,8 @@
   }
 }
 
-Network::Network(const std::string& name, const std::string& desc, uint32 ip)
+Network::Network(const std::string& name, const std::string& desc,
+                 const IPAddress& ip)
     : name_(name), description_(desc), ip_(ip), ignored_(false),
       uniform_numerator_(0), uniform_denominator_(0),
       exponential_numerator_(0), exponential_denominator_(0) {
@@ -323,7 +330,7 @@
   // Print out the first space-terminated token of the network desc, plus
   // the IP address.
   ss << "Net[" << description_.substr(0, description_.find(' '))
-     << ":" << SocketAddress::IPToString(ip_) << "]";
+     << ":" << ip_ << "]";
   return ss.str();
 }
 
diff --git a/talk/base/network.h b/talk/base/network.h
index 10b4bec..bb5f15d 100644
--- a/talk/base/network.h
+++ b/talk/base/network.h
@@ -34,6 +34,7 @@
 #include <vector>
 
 #include "talk/base/basictypes.h"
+#include "talk/base/ipaddress.h"
 #include "talk/base/messagehandler.h"
 #include "talk/base/sigslot.h"
 
@@ -135,7 +136,10 @@
 // Represents a Unix-type network interface, with a name and single address.
 class Network {
  public:
-  Network(const std::string& name, const std::string& description, uint32 ip);
+  Network() : ip_(INADDR_ANY) {}
+
+  Network(const std::string& name, const std::string& description,
+          const IPAddress& ip);
 
   // Returns the index of this network.  This is considered the primary key
   // that identifies each network.
@@ -146,8 +150,8 @@
   const std::string& description() const { return description_; }
 
   // Identifies the current IP address used by this network.
-  uint32 ip() const { return ip_; }
-  void set_ip(uint32 ip) { ip_ = ip; }
+  const IPAddress& ip() const { return ip_; }
+  void set_ip(const IPAddress& ip) { ip_ = ip; }
 
   // Indicates whether this network should be ignored, perhaps because
   // the IP is 0, or the interface is one we know is invalid.
@@ -162,7 +166,7 @@
 
   std::string name_;
   std::string description_;
-  uint32 ip_;
+  IPAddress ip_;
   bool ignored_;
   SessionList sessions_;
   double uniform_numerator_;
diff --git a/talk/base/network_unittest.cc b/talk/base/network_unittest.cc
index 4bec4a3..d48abbb 100644
--- a/talk/base/network_unittest.cc
+++ b/talk/base/network_unittest.cc
@@ -32,9 +32,11 @@
 namespace talk_base {
 
 // A network that should not be ignored.
-static const Network kNetwork1("test1", "Test Network Adapter 1", 0x12345678);
+static const Network kNetwork1("test1", "Test Network Adapter 1",
+                               IPAddress(0x12345678));
 // A network that should be ignored (IP is 0.1.0.4).
-static const Network kNetwork2("test2", "Test Network Adapter 2", 0x00010004);
+static const Network kNetwork2("test2", "Test Network Adapter 2",
+                               IPAddress(0x00010004));
 
 class NetworkTest : public testing::Test, public sigslot::has_slots<>  {
  public:
@@ -56,6 +58,13 @@
     return BasicNetworkManager::IsIgnoredNetwork(network);
   }
 
+  NetworkManager::NetworkList GetNetworks(
+      const BasicNetworkManager& network_manager, bool include_ignored) {
+    NetworkManager::NetworkList list;
+    network_manager.CreateNetworks(include_ignored, &list);
+    return list;
+  }
+
  protected:
   bool callback_called_;
 };
@@ -64,7 +73,7 @@
 TEST_F(NetworkTest, TestNetworkConstruct) {
   EXPECT_EQ("test1", kNetwork1.name());
   EXPECT_EQ("Test Network Adapter 1", kNetwork1.description());
-  EXPECT_EQ(0x12345678U, kNetwork1.ip());
+  EXPECT_EQ(IPAddress(0x12345678U), kNetwork1.ip());
   EXPECT_FALSE(kNetwork1.ignored());
 }
 
@@ -74,6 +83,41 @@
   EXPECT_TRUE(IsIgnoredNetwork(kNetwork2));
 }
 
+TEST_F(NetworkTest, TestCreateNetworks) {
+  BasicNetworkManager manager;
+  NetworkManager::NetworkList result = GetNetworks(manager, true);
+  // We should be able to bind to any addresses we find.
+  // (Excluding IPv6 link-local for now, as we don't (yet) record scope ids.)
+  NetworkManager::NetworkList::iterator it;
+  for (it = result.begin();
+       it != result.end();
+       ++it) {
+    sockaddr_storage storage;
+    memset(&storage, 0, sizeof(storage));
+    IPAddress ip = (*it)->ip();
+    // This condition excludes FE80::/16, i.e. IPv6 link-local addresses. These
+    // require their scope id to be known. Remove when scope ids are supported.
+    if (!(ip.family() == AF_INET6 && IPIsPrivate(ip) && !IPIsLoopback(ip))) {
+      SocketAddress bindaddress(ip, 0);
+      // TODO: Make this use talk_base::AsyncSocket once it supports IPv6.
+      int fd = socket(ip.family(), SOCK_STREAM, IPPROTO_TCP);
+      if (fd > 0) {
+        size_t ipsize = bindaddress.ToSockAddrStorage(&storage);
+        EXPECT_GE(ipsize, 0U);
+        int success = ::bind(fd,
+                             reinterpret_cast<sockaddr*>(&storage),
+                             ipsize);
+        EXPECT_EQ(0, success);
+#ifdef WIN32
+        closesocket(fd);
+#else
+        close(fd);
+#endif
+      }
+    }
+  }
+}
+
 // Test that UpdateNetworks succeeds.
 TEST_F(NetworkTest, TestUpdateNetworks) {
   BasicNetworkManager manager;
diff --git a/talk/base/physicalsocketserver.cc b/talk/base/physicalsocketserver.cc
index f18e4ae..10d534f 100644
--- a/talk/base/physicalsocketserver.cc
+++ b/talk/base/physicalsocketserver.cc
@@ -1409,6 +1409,10 @@
   return true;
 }
 
+Dispatcher* PhysicalSocketServer::signal_dispatcher() {
+  return signal_dispatcher_.get();
+}
+
 bool PhysicalSocketServer::InstallSignal(int signum, void (*handler)(int)) {
   struct sigaction act;
   // It doesn't really matter what we set this mask to.
diff --git a/talk/base/physicalsocketserver.h b/talk/base/physicalsocketserver.h
index aeb8348..1b7a298 100644
--- a/talk/base/physicalsocketserver.h
+++ b/talk/base/physicalsocketserver.h
@@ -2,26 +2,26 @@
  * libjingle
  * Copyright 2004--2005, Google Inc.
  *
- * Redistribution and use in source and binary forms, with or without 
+ * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
- *  1. Redistributions of source code must retain the above copyright notice, 
+ *  1. Redistributions of source code must retain the above copyright notice,
  *     this list of conditions and the following disclaimer.
  *  2. Redistributions in binary form must reproduce the above copyright notice,
  *     this list of conditions and the following disclaimer in the documentation
  *     and/or other materials provided with the distribution.
- *  3. The name of the author may not be used to endorse or promote products 
+ *  3. The name of the author may not be used to endorse or promote products
  *     derived from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
@@ -73,7 +73,7 @@
 
 // A socket server that provides the real sockets of the underlying OS.
 class PhysicalSocketServer : public SocketServer {
-public:
+ public:
   PhysicalSocketServer();
   virtual ~PhysicalSocketServer();
 
@@ -104,10 +104,13 @@
   // Dispatching signals on multiple PhysicalSocketServers is not reliable.
   // The signal mask is not modified. It is the caller's responsibily to
   // maintain it as desired.
-  bool SetPosixSignalHandler(int signum, void (*handler)(int));
+  virtual bool SetPosixSignalHandler(int signum, void (*handler)(int));
+
+ protected:
+  Dispatcher* signal_dispatcher();
 #endif
 
-private:
+ private:
   typedef std::vector<Dispatcher*> DispatcherList;
   typedef std::vector<size_t*> IteratorList;
 
diff --git a/talk/base/proxydetect.cc b/talk/base/proxydetect.cc
index 66213ee..4bfae29 100644
--- a/talk/base/proxydetect.cc
+++ b/talk/base/proxydetect.cc
@@ -233,7 +233,9 @@
       m = 0;
     uint32 mask = (m == 0) ? 0 : (~0UL) << (32 - m);
     SocketAddress addr(url.host(), 0);
-    return !addr.IsUnresolved() && ((addr.ip() & mask) == (ip & mask));
+    // TODO: Support IPv6 proxyitems. This code block is IPv4 only anyway.
+    return !addr.IsUnresolved() &&
+        ((addr.ipaddr().v4AddressAsHostOrderInteger() & mask) == (ip & mask));
   }
 
   // .foo.com
diff --git a/talk/base/proxyserver.cc b/talk/base/proxyserver.cc
index 3cdf598..d764fd7 100644
--- a/talk/base/proxyserver.cc
+++ b/talk/base/proxyserver.cc
@@ -36,7 +36,7 @@
 ProxyServer::ProxyServer(
     SocketFactory* int_factory, const SocketAddress& int_addr,
     SocketFactory* ext_factory, const SocketAddress& ext_ip)
-    : ext_factory_(ext_factory), ext_ip_(ext_ip.ip(), 0),  // strip off any port
+    : ext_factory_(ext_factory), ext_ip_(ext_ip.ipaddr(), 0),  // strip off port
       server_socket_(int_factory->CreateAsyncSocket(SOCK_STREAM)) {
   server_socket_->Bind(int_addr);
   server_socket_->Listen(5);
diff --git a/talk/base/socket_unittest.cc b/talk/base/socket_unittest.cc
index d5c4a3b..8d5b3c5 100644
--- a/talk/base/socket_unittest.cc
+++ b/talk/base/socket_unittest.cc
@@ -37,7 +37,7 @@
 namespace talk_base {
 
 static const SocketAddress kEmptyAddr;
-static const SocketAddress kLoopbackAddr(INADDR_LOOPBACK, 0);
+static const SocketAddress kLoopbackAddr(IPAddress(INADDR_LOOPBACK), 0);
 
 void SocketTest::TestConnect() {
   testing::StreamSink sink;
@@ -153,7 +153,7 @@
   // Attempt connect to a non-existent socket.
   // We don't connect to the server socket created above, since on
   // MacOS it takes about 75 seconds to get back an error!
-  SocketAddress bogus_addr(INADDR_LOOPBACK, 65535);
+  SocketAddress bogus_addr(IPAddress(INADDR_LOOPBACK), 65535);
   EXPECT_EQ(0, client->Connect(bogus_addr));
 
   // Wait for connection to fail (ECONNREFUSED).
@@ -664,7 +664,7 @@
     SocketAddress addr4;
     EXPECT_EQ(3, client2->SendTo("foo", 3, addr1));
     EXPECT_TRUE(client1->CheckNextPacket("foo", 3, &addr4));
-    EXPECT_EQ(addr4.ip(), addr2.ip());
+    EXPECT_EQ(addr4.ipaddr(), addr2.ipaddr());
 
     SocketAddress addr5;
     EXPECT_EQ(6, client1->SendTo("bizbaz", 6, addr4));
diff --git a/talk/base/socketaddress.cc b/talk/base/socketaddress.cc
index 71ed674..42143f5 100644
--- a/talk/base/socketaddress.cc
+++ b/talk/base/socketaddress.cc
@@ -362,7 +362,7 @@
   return true;
 }
 
-static void ToSockAddrStorageHelper(sockaddr_storage* addr,
+static size_t ToSockAddrStorageHelper(sockaddr_storage* addr,
                                     IPAddress ip, int port) {
   memset(addr, 0, sizeof(sockaddr_storage));
   addr->ss_family = ip.family();
@@ -370,19 +370,22 @@
     sockaddr_in6* saddr = reinterpret_cast<sockaddr_in6*>(addr);
     saddr->sin6_addr = ip.ipv6_address();
     saddr->sin6_port = HostToNetwork16(port);
-  } else {
+    return sizeof(sockaddr_in6);
+  } else if (addr->ss_family == AF_INET) {
     sockaddr_in* saddr = reinterpret_cast<sockaddr_in*>(addr);
     saddr->sin_addr = ip.ipv4_address();
     saddr->sin_port = HostToNetwork16(port);
+    return sizeof(sockaddr_in);
   }
+  return 0;
 }
 
-void SocketAddress::ToDualStackSockAddrStorage(sockaddr_storage *addr) const {
-  ToSockAddrStorageHelper(addr, ip_.AsIPv6Address(), port_);
+size_t SocketAddress::ToDualStackSockAddrStorage(sockaddr_storage *addr) const {
+  return ToSockAddrStorageHelper(addr, ip_.AsIPv6Address(), port_);
 }
 
-void SocketAddress::ToSockAddrStorage(sockaddr_storage* addr) const {
-  ToSockAddrStorageHelper(addr, ip_, port_);
+size_t SocketAddress::ToSockAddrStorage(sockaddr_storage* addr) const {
+  return ToSockAddrStorageHelper(addr, ip_, port_);
 }
 
 std::string SocketAddress::IPToString(uint32 ip_as_host_order_integer) {
@@ -437,27 +440,6 @@
   return "";
 }
 
-bool SocketAddress::GetLocalIPs(std::vector<uint32>& ips) {
-  ips.clear();
-
-  const std::string hostname = GetHostname();
-  if (hostname.empty())
-    return false;
-
-  int errcode;
-  if (hostent* pHost = SafeGetHostByName(hostname.c_str(), &errcode)) {
-    for (size_t i = 0; pHost->h_addr_list[i]; ++i) {
-      uint32 ip =
-        NetworkToHost32(*reinterpret_cast<uint32 *>(pHost->h_addr_list[i]));
-      ips.push_back(ip);
-    }
-    FreeHostEnt(pHost);
-    return !ips.empty();
-  }
-  LOG(LS_ERROR) << "gethostbyname err: " << errcode;
-  return false;
-}
-
 bool SocketAddress::GetLocalIPs(std::vector<IPAddress>* ips) {
   if (!ips) {
     return false;
diff --git a/talk/base/socketaddress.h b/talk/base/socketaddress.h
index 2272b53..3ebf556 100644
--- a/talk/base/socketaddress.h
+++ b/talk/base/socketaddress.h
@@ -191,8 +191,10 @@
   // Dual stack version always sets family to AF_INET6, and maps v4 addresses.
   // The other version doesn't map, and outputs an AF_INET address for
   // v4 or mapped addresses, and AF_INET6 addresses for others.
-  void ToDualStackSockAddrStorage(sockaddr_storage* saddr) const;
-  void ToSockAddrStorage(sockaddr_storage* saddr) const;
+  // Returns the size of the sockaddr_in or sockaddr_in6 structure that is
+  // written to the sockaddr_storage, or zero on failure.
+  size_t ToDualStackSockAddrStorage(sockaddr_storage* saddr) const;
+  size_t ToSockAddrStorage(sockaddr_storage* saddr) const;
 
   // Converts the IP address given in 'compact form' into dotted form.
   // IP is given as an integer in host byte order. V4 only, to be deprecated.
@@ -210,16 +212,12 @@
   static bool StringToIP(const std::string& str, IPAddress* ip);
 
   // Get a list of the local machine's ip addresses.
-  // TODO: Deprecate this function.
-  static bool GetLocalIPs(std::vector<uint32>& ips);
+  // TODO: Move to nethelpers or similar (doesn't belong in socketaddress).
+  static bool GetLocalIPs(std::vector<IPAddress>* ips);
 
  private:
   // Get local machine's hostname.
   static std::string GetHostname();
-  // Get a list of the local machine's ip addresses.
-  // TODO: Remove this (and the other GetLocalIPs method).
-  static bool GetLocalIPs(std::vector<IPAddress>* ips);
-
   std::string hostname_;
   IPAddress ip_;
   uint16 port_;
diff --git a/talk/base/socketaddress_unittest.cc b/talk/base/socketaddress_unittest.cc
index d19c723..fcfd89c 100644
--- a/talk/base/socketaddress_unittest.cc
+++ b/talk/base/socketaddress_unittest.cc
@@ -50,16 +50,16 @@
 TEST(SocketAddressTest, TestDefaultCtor) {
   SocketAddress addr;
   EXPECT_FALSE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0U, addr.ip());
+  EXPECT_EQ(IPAddress(INADDR_ANY), addr.ipaddr());
   EXPECT_EQ(0, addr.port());
   EXPECT_EQ("", addr.hostname());
   EXPECT_EQ("0.0.0.0:0", addr.ToString());
 }
 
 TEST(SocketAddressTest, TestIPPortCtor) {
-  SocketAddress addr(0x01020304, 5678);
+  SocketAddress addr(IPAddress(0x01020304), 5678);
   EXPECT_FALSE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0x01020304U, addr.ip());
+  EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("", addr.hostname());
   EXPECT_EQ("1.2.3.4:5678", addr.ToString());
@@ -68,7 +68,7 @@
 TEST(SocketAddressTest, TestIPv4StringPortCtor) {
   SocketAddress addr("1.2.3.4", 5678);
   EXPECT_FALSE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0x01020304U, addr.ip());
+  EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("1.2.3.4", addr.hostname());
   EXPECT_EQ("1.2.3.4:5678", addr.ToString());
@@ -89,7 +89,7 @@
   // inet_addr doesn't handle this address properly.
   SocketAddress addr("255.255.255.255", 5678);
   EXPECT_FALSE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0xFFFFFFFFU, addr.ip());
+  EXPECT_EQ(IPAddress(0xFFFFFFFFU), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("255.255.255.255", addr.hostname());
   EXPECT_EQ("255.255.255.255:5678", addr.ToString());
@@ -98,7 +98,7 @@
 TEST(SocketAddressTest, TestHostnamePortCtor) {
   SocketAddress addr("a.b.com", 5678);
   EXPECT_TRUE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0U, addr.ip());
+  EXPECT_EQ(IPAddress(INADDR_ANY), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("a.b.com", addr.hostname());
   EXPECT_EQ("a.b.com:5678", addr.ToString());
@@ -108,7 +108,7 @@
   SocketAddress from("1.2.3.4", 5678);
   SocketAddress addr(from);
   EXPECT_FALSE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0x01020304U, addr.ip());
+  EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("1.2.3.4", addr.hostname());
   EXPECT_EQ("1.2.3.4:5678", addr.ToString());
@@ -116,49 +116,49 @@
 
 TEST(SocketAddressTest, TestAssign) {
   SocketAddress from("1.2.3.4", 5678);
-  SocketAddress addr(0x88888888, 9999);
+  SocketAddress addr(IPAddress(0x88888888), 9999);
   addr = from;
   EXPECT_FALSE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0x01020304U, addr.ip());
+  EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("1.2.3.4", addr.hostname());
   EXPECT_EQ("1.2.3.4:5678", addr.ToString());
 }
 
 TEST(SocketAddressTest, TestSetIPPort) {
-  SocketAddress addr(0x88888888, 9999);
-  addr.SetIP(0x01020304);
+  SocketAddress addr(IPAddress(0x88888888), 9999);
+  addr.SetIP(IPAddress(0x01020304));
   addr.SetPort(5678);
   EXPECT_FALSE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0x01020304U, addr.ip());
+  EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("", addr.hostname());
   EXPECT_EQ("1.2.3.4:5678", addr.ToString());
 }
 
 TEST(SocketAddressTest, TestSetIPFromString) {
-  SocketAddress addr(0x88888888, 9999);
+  SocketAddress addr(IPAddress(0x88888888), 9999);
   addr.SetIP("1.2.3.4");
   addr.SetPort(5678);
   EXPECT_FALSE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0x01020304U, addr.ip());
+  EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("1.2.3.4", addr.hostname());
   EXPECT_EQ("1.2.3.4:5678", addr.ToString());
 }
 
 TEST(SocketAddressTest, TestSetIPFromHostname) {
-  SocketAddress addr(0x88888888, 9999);
+  SocketAddress addr(IPAddress(0x88888888), 9999);
   addr.SetIP("a.b.com");
   addr.SetPort(5678);
   EXPECT_TRUE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0U, addr.ip());
+  EXPECT_EQ(IPAddress(INADDR_ANY), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("a.b.com", addr.hostname());
   EXPECT_EQ("a.b.com:5678", addr.ToString());
-  addr.SetResolvedIP(0x01020304);
+  addr.SetResolvedIP(IPAddress(0x01020304));
   EXPECT_FALSE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0x01020304U, addr.ip());
+  EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr());
   EXPECT_EQ("a.b.com", addr.hostname());
   EXPECT_EQ("a.b.com:5678", addr.ToString());
 }
@@ -167,7 +167,7 @@
   SocketAddress addr;
   EXPECT_TRUE(addr.FromString("1.2.3.4:5678"));
   EXPECT_FALSE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0x01020304U, addr.ip());
+  EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("1.2.3.4", addr.hostname());
   EXPECT_EQ("1.2.3.4:5678", addr.ToString());
@@ -186,7 +186,7 @@
   SocketAddress addr;
   EXPECT_TRUE(addr.FromString("a.b.com:5678"));
   EXPECT_TRUE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0U, addr.ip());
+  EXPECT_EQ(IPAddress(INADDR_ANY), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("a.b.com", addr.hostname());
   EXPECT_EQ("a.b.com:5678", addr.ToString());
@@ -198,7 +198,7 @@
   from.ToSockAddr(&addr_in);
   EXPECT_TRUE(addr.FromSockAddr(addr_in));
   EXPECT_FALSE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0x01020304U, addr.ip());
+  EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("", addr.hostname());
   EXPECT_EQ("1.2.3.4:5678", addr.ToString());
@@ -210,7 +210,7 @@
   from.ToSockAddrStorage(&addr_storage);
   EXPECT_TRUE(SocketAddressFromSockAddrStorage(addr_storage, &addr));
   EXPECT_FALSE(addr.IsUnresolvedIP());
-  EXPECT_EQ(0x01020304U, addr.ip());
+  EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("", addr.hostname());
   EXPECT_EQ("1.2.3.4:5678", addr.ToString());
@@ -239,7 +239,7 @@
   EXPECT_TRUE(addr.Read_(buf, sizeof(buf)));
   EXPECT_FALSE(addr.IsUnresolvedIP());
   EXPECT_EQ(AF_INET, addr.ipaddr().family());
-  EXPECT_EQ(0x01020304U, addr.ip());
+  EXPECT_EQ(IPAddress(0x01020304U), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("", addr.hostname());
   EXPECT_EQ("1.2.3.4:5678", addr.ToString());
@@ -266,7 +266,7 @@
   EXPECT_EQ(0, error);
   EXPECT_FALSE(addr.IsUnresolvedIP());
   EXPECT_TRUE(addr.IsLoopbackIP());
-  EXPECT_EQ(0x7F000001U, addr.ip());
+  EXPECT_EQ(IPAddress(INADDR_LOOPBACK), addr.ipaddr());
   EXPECT_EQ(5678, addr.port());
   EXPECT_EQ("localhost", addr.hostname());
   EXPECT_EQ("localhost:5678", addr.ToString());
diff --git a/talk/base/task.cc b/talk/base/task.cc
index ad17438..c37797c 100644
--- a/talk/base/task.cc
+++ b/talk/base/task.cc
@@ -197,22 +197,15 @@
 }
 
 std::string Task::GetStateName(int state) const {
-  static const std::string STR_BLOCKED("BLOCKED");
-  static const std::string STR_INIT("INIT");
-  static const std::string STR_START("START");
-  static const std::string STR_DONE("DONE");
-  static const std::string STR_ERROR("ERROR");
-  static const std::string STR_RESPONSE("RESPONSE");
-  static const std::string STR_HUH("??");
   switch (state) {
-    case STATE_BLOCKED: return STR_BLOCKED;
-    case STATE_INIT: return STR_INIT;
-    case STATE_START: return STR_START;
-    case STATE_DONE: return STR_DONE;
-    case STATE_ERROR: return STR_ERROR;
-    case STATE_RESPONSE: return STR_RESPONSE;
+    case STATE_BLOCKED: return "BLOCKED";
+    case STATE_INIT: return "INIT";
+    case STATE_START: return "START";
+    case STATE_DONE: return "DONE";
+    case STATE_ERROR: return "ERROR";
+    case STATE_RESPONSE: return "RESPONSE";
   }
-  return STR_HUH;
+  return "??";
 }
 
 int Task::Process(int state) {
diff --git a/talk/base/virtualsocket_unittest.cc b/talk/base/virtualsocket_unittest.cc
index 6b2ae99..1c44fe7 100644
--- a/talk/base/virtualsocket_unittest.cc
+++ b/talk/base/virtualsocket_unittest.cc
@@ -56,7 +56,7 @@
 };
 
 TEST_F(VirtualSocketServerTest, basic) {
-  SocketAddress addr1(0, 5000);
+  SocketAddress addr1(IPAddress(INADDR_ANY), 5000);
   AsyncSocket* socket = ss_->CreateAsyncSocket(SOCK_DGRAM);
   socket->Bind(addr1);
   addr1 = socket->GetLocalAddress();
@@ -80,7 +80,8 @@
     SocketAddress addr4;
     EXPECT_EQ(3, client2->SendTo("foo", 3, addr1));
     EXPECT_TRUE(client1->CheckNextPacket("foo", 3, &addr4));
-    EXPECT_EQ(addr4.ip(), addr2.ip() + 1);
+    EXPECT_EQ(addr4.ipaddr().v4AddressAsHostOrderInteger(),
+              addr2.ipaddr().v4AddressAsHostOrderInteger() + 1);
     EXPECT_EQ(addr4.port(), addr2.port() + 1);
 
     SocketAddress addr5;
@@ -618,8 +619,8 @@
 TEST_F(VirtualSocketServerTest, bandwidth) {
   AsyncSocket* send_socket = ss_->CreateAsyncSocket(SOCK_DGRAM);
   AsyncSocket* recv_socket = ss_->CreateAsyncSocket(SOCK_DGRAM);
-  ASSERT_EQ(0, send_socket->Bind(SocketAddress(0, 1000)));
-  ASSERT_EQ(0, recv_socket->Bind(SocketAddress(0, 1000)));
+  ASSERT_EQ(0, send_socket->Bind(SocketAddress(IPAddress(INADDR_ANY), 1000)));
+  ASSERT_EQ(0, recv_socket->Bind(SocketAddress(IPAddress(INADDR_ANY), 1000)));
   ASSERT_EQ(0, send_socket->Connect(recv_socket->GetLocalAddress()));
 
   uint32 bandwidth = 64 * 1024;
@@ -653,8 +654,8 @@
 
   AsyncSocket* send_socket = ss_->CreateAsyncSocket(SOCK_DGRAM);
   AsyncSocket* recv_socket = ss_->CreateAsyncSocket(SOCK_DGRAM);
-  ASSERT_EQ(0, send_socket->Bind(SocketAddress(0, 1000)));
-  ASSERT_EQ(0, recv_socket->Bind(SocketAddress(0, 1000)));
+  ASSERT_EQ(0, send_socket->Bind(SocketAddress(IPAddress(INADDR_ANY), 1000)));
+  ASSERT_EQ(0, recv_socket->Bind(SocketAddress(IPAddress(INADDR_ANY), 1000)));
   ASSERT_EQ(0, send_socket->Connect(recv_socket->GetLocalAddress()));
 
   Thread* pthMain = Thread::Current();
diff --git a/talk/base/virtualsocketserver.cc b/talk/base/virtualsocketserver.cc
index 77614b2..c9c9f0b 100644
--- a/talk/base/virtualsocketserver.cc
+++ b/talk/base/virtualsocketserver.cc
@@ -608,7 +608,7 @@
                               const SocketAddress& addr) {
   ASSERT(NULL != socket);
   // Address must be completely specified at this point
-  ASSERT(addr.ip() != 0);
+  ASSERT(!IPIsAny(addr.ipaddr()));
   ASSERT(addr.port() != 0);
 
   AddressMap::value_type entry(addr, socket);
@@ -618,8 +618,9 @@
 int VirtualSocketServer::Bind(VirtualSocket* socket, SocketAddress* addr) {
   ASSERT(NULL != socket);
 
-  if (addr->ip() == 0) {
-    addr->SetIP(GetNextIP());
+  if (IPIsAny(addr->ipaddr())) {
+    // TODO: An IPv6-ish version of this?
+    addr->SetIP(IPAddress(GetNextIP()));
   }
 
   if (addr->port() == 0) {
diff --git a/talk/examples/call/call_main.cc b/talk/examples/call/call_main.cc
index 748936b..077869c 100644
--- a/talk/examples/call/call_main.cc
+++ b/talk/examples/call/call_main.cc
@@ -216,6 +216,7 @@
       "Disable or enable encryption: disable, enable, require.");
   DEFINE_string(tls, "enable",
       "Disable or enable tls: disable, enable, require.");
+  DEFINE_bool(allowplain, false, "Allow plain authentication");
   DEFINE_bool(testserver, false, "Use test server");
   DEFINE_int(portallocator, 0, "Filter out unwanted connection types.");
   DEFINE_string(filterhost, NULL, "Filter out the host from all candidates.");
@@ -240,6 +241,7 @@
   bool debug = FLAG_d;
   std::string protocol = FLAG_protocol;
   bool test_server = FLAG_testserver;
+  bool allow_plain = FLAG_allowplain;
   std::string tls = FLAG_tls;
   int32 portallocator_flags = FLAG_portallocator;
   std::string pmuc_domain = FLAG_pmuc;
@@ -314,11 +316,9 @@
   xcs.set_user(jid.node());
   xcs.set_resource("call");
   xcs.set_host(jid.domain());
-
-  bool allow_plain = (test_server) ? true : false;
   xcs.set_allow_plain(allow_plain);
 
-  if(test_server || tls == "disable") {
+  if(tls == "disable") {
     xcs.set_use_tls(buzz::TLS_DISABLED);
   } else if (tls == "enable") {
     xcs.set_use_tls(buzz::TLS_ENABLED);
@@ -332,6 +332,7 @@
   if (test_server) {
     pass.password() = jid.node();
     xcs.set_allow_plain(true);
+    xcs.set_use_tls(buzz::TLS_DISABLED);
     xcs.set_test_server_domain("google.com");
   }
   xcs.set_pass(talk_base::CryptString(pass));
diff --git a/talk/libjingle.scons b/talk/libjingle.scons
index 3d0463a..0ec1f59 100644
--- a/talk/libjingle.scons
+++ b/talk/libjingle.scons
@@ -233,6 +233,7 @@
                "session/phone/mediaengine.cc",
                "session/phone/mediamessages.cc",
                "session/phone/mediamonitor.cc",
+               "session/phone/mediarecorder.cc",
                "session/phone/mediasession.cc",
                "session/phone/mediasessionclient.cc",
                "session/phone/rtpdump.cc",
@@ -534,15 +535,23 @@
                 "srtp",
               ],
               srcs = [
+                "session/phone/channel_unittest.cc",
+                "session/phone/channelmanager_unittest.cc",
                 "session/phone/codec_unittest.cc",
                 "session/phone/currentspeakermonitor_unittest.cc",
+                "session/phone/devicemanager_unittest.cc",
+                "session/phone/dummydevicemanager_unittest.cc",
                 "session/phone/filemediaengine_unittest.cc",
                 "session/phone/filevideocapturer_unittest.cc",
+                "session/phone/mediarecorder_unittest.cc",
                 "session/phone/mediamessages_unittest.cc",
                 "session/phone/mediasession_unittest.cc",
+                "session/phone/mediasessionclient_unittest.cc",
+                "session/phone/rtcpmuxfilter_unittest.cc",
                 "session/phone/rtpdump_unittest.cc",
                 "session/phone/rtputils_unittest.cc",
                 "session/phone/srtpfilter_unittest.cc",
+                "session/phone/ssrcmuxfilter_unittest.cc",
                 "session/phone/testutils.cc",
                 "session/phone/videocapturer_unittest.cc",
                 "session/phone/videocommon_unittest.cc",
diff --git a/talk/p2p/base/constants.cc b/talk/p2p/base/constants.cc
index 6123fc1..4d65f5b 100644
--- a/talk/p2p/base/constants.cc
+++ b/talk/p2p/base/constants.cc
@@ -104,7 +104,7 @@
 const char NS_JINGLE_RTP[] = "urn:xmpp:jingle:apps:rtp:1";
 const buzz::StaticQName QN_JINGLE_RTP_CONTENT =
     { NS_JINGLE_RTP, LN_DESCRIPTION };
-const buzz::StaticQName QN_JINGLE_SSRC = { NS_EMPTY, "ssrc" };
+const buzz::StaticQName QN_SSRC = { NS_EMPTY, "ssrc" };
 const buzz::StaticQName QN_JINGLE_RTP_PAYLOADTYPE =
     { NS_JINGLE_RTP, LN_PAYLOADTYPE };
 const buzz::StaticQName QN_JINGLE_RTP_BANDWIDTH =
@@ -202,40 +202,24 @@
 const char STR_TERMINATE_UNKNOWN_ERROR[] = "unknown-error";
 
 // Draft view and notify messages.
-const buzz::StaticQName QN_JINGLE_DRAFT_CONTENT_NAME =
-    { cricket::NS_EMPTY, "name" };
 const char STR_JINGLE_DRAFT_CONTENT_NAME_VIDEO[] = "video";
 const char STR_JINGLE_DRAFT_CONTENT_NAME_AUDIO[] = "audio";
-const buzz::StaticQName QN_JINGLE_DRAFT_NOTIFY = { NS_JINGLE_DRAFT, "notify" };
-const buzz::StaticQName QN_JINGLE_DRAFT_SOURCE = { NS_JINGLE_DRAFT, "source" };
-const buzz::StaticQName QN_JINGLE_DRAFT_SOURCE_NICK =
-    { cricket::NS_EMPTY, "nick" };
-const buzz::StaticQName QN_JINGLE_DRAFT_SOURCE_NAME =
-    { cricket::NS_EMPTY, "name" };
-const buzz::StaticQName QN_JINGLE_DRAFT_SOURCE_USAGE =
-    { cricket::NS_EMPTY, "usage" };
-const buzz::StaticQName QN_JINGLE_DRAFT_SOURCE_STATE =
-    { cricket::NS_EMPTY, "state" };
-const char STR_JINGLE_DRAFT_SOURCE_STATE_REMOVED[] = "removed";
-const buzz::StaticQName QN_JINGLE_DRAFT_SOURCE_SSRC =
-    { NS_JINGLE_DRAFT, "ssrc" };
+const buzz::StaticQName QN_NICK = { cricket::NS_EMPTY, "nick" };
+const buzz::StaticQName QN_TYPE = { cricket::NS_EMPTY, "type" };
 const buzz::StaticQName QN_JINGLE_DRAFT_VIEW = { NS_JINGLE_DRAFT, "view" };
-const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_TYPE =
-    { cricket::NS_EMPTY, "type" };
 const char STR_JINGLE_DRAFT_VIEW_TYPE_NONE[] = "none";
 const char STR_JINGLE_DRAFT_VIEW_TYPE_STATIC[] = "static";
-const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_SSRC =
-    { cricket::NS_EMPTY, "ssrc" };
-const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_PARAMS =
-    { NS_JINGLE_DRAFT, "params" };
-const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_PARAMS_WIDTH =
-    { cricket::NS_EMPTY, "width" };
-const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_PARAMS_HEIGHT =
-    { cricket::NS_EMPTY, "height" };
-const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_PARAMS_FRAMERATE =
-    { cricket::NS_EMPTY, "framerate" };
-const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_PARAMS_PREFERENCE =
-    { cricket::NS_EMPTY, "preference" };
+const buzz::StaticQName QN_JINGLE_DRAFT_PARAMS = { NS_JINGLE_DRAFT, "params" };
+const buzz::StaticQName QN_JINGLE_DRAFT_STREAMS = { NS_JINGLE_DRAFT, "streams" };
+const buzz::StaticQName QN_JINGLE_DRAFT_STREAM = { NS_JINGLE_DRAFT, "stream" };
+const buzz::StaticQName QN_DISPLAY = { cricket::NS_EMPTY, "display" };
+const buzz::StaticQName QN_CNAME = { cricket::NS_EMPTY, "cname" };
+const buzz::StaticQName QN_JINGLE_DRAFT_SSRC = { NS_JINGLE_DRAFT, "ssrc" };
+const buzz::StaticQName QN_JINGLE_DRAFT_SSRC_GROUP =
+    { NS_JINGLE_DRAFT, "ssrc-group" };
+const buzz::StaticQName QN_SEMANTICS = { cricket::NS_EMPTY, "semantics" };
+const buzz::StaticQName QN_JINGLE_LEGACY_NOTIFY = { NS_JINGLE_DRAFT, "notify" };
+const buzz::StaticQName QN_JINGLE_LEGACY_SOURCE = { NS_JINGLE_DRAFT, "source" };
 
 // old stuff
 #ifdef FEATURE_ENABLE_VOICEMAIL
diff --git a/talk/p2p/base/constants.h b/talk/p2p/base/constants.h
index 0a53345..0c84dd6 100644
--- a/talk/p2p/base/constants.h
+++ b/talk/p2p/base/constants.h
@@ -97,9 +97,6 @@
 extern const buzz::StaticQName QN_CLOCKRATE;
 extern const buzz::StaticQName QN_BITRATE;
 extern const buzz::StaticQName QN_CHANNELS;
-extern const buzz::StaticQName QN_WIDTH;
-extern const buzz::StaticQName QN_HEIGHT;
-extern const buzz::StaticQName QN_FRAMERATE;
 extern const buzz::StaticQName QN_PARAMETER;
 extern const char LN_NAME[];
 extern const char LN_VALUE[];
@@ -125,7 +122,7 @@
 
 extern const char NS_JINGLE_RTP[];
 extern const buzz::StaticQName QN_JINGLE_RTP_CONTENT;
-extern const buzz::StaticQName QN_JINGLE_SSRC;
+extern const buzz::StaticQName QN_SSRC;
 extern const buzz::StaticQName QN_JINGLE_RTP_PAYLOADTYPE;
 extern const buzz::StaticQName QN_JINGLE_RTP_BANDWIDTH;
 extern const buzz::StaticQName QN_JINGLE_RTCP_MUX;
@@ -213,28 +210,26 @@
 extern const char STR_TERMINATE_UNKNOWN_ERROR[];
 
 // Draft view and notify messages.
-extern const buzz::StaticQName QN_JINGLE_DRAFT_CONTENT_NAME;
 extern const char STR_JINGLE_DRAFT_CONTENT_NAME_VIDEO[];
 extern const char STR_JINGLE_DRAFT_CONTENT_NAME_AUDIO[];
-extern const buzz::StaticQName QN_JINGLE_DRAFT_NOTIFY;
-extern const buzz::StaticQName QN_JINGLE_DRAFT_SOURCE;
-extern const buzz::StaticQName QN_JINGLE_DRAFT_SOURCE_NICK;
-extern const buzz::StaticQName QN_JINGLE_DRAFT_SOURCE_NAME;
-extern const buzz::StaticQName QN_JINGLE_DRAFT_SOURCE_USAGE;
-extern const buzz::StaticQName QN_JINGLE_DRAFT_SOURCE_STATE;
-extern const char STR_JINGLE_DRAFT_SOURCE_STATE_REMOVED[];
-extern const buzz::StaticQName QN_JINGLE_DRAFT_SOURCE_SSRC;
+extern const buzz::StaticQName QN_NICK;
+extern const buzz::StaticQName QN_TYPE;
 extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW;
-extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_NAME;
-extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_TYPE;
 extern const char STR_JINGLE_DRAFT_VIEW_TYPE_NONE[];
 extern const char STR_JINGLE_DRAFT_VIEW_TYPE_STATIC[];
-extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_SSRC;
-extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_PARAMS;
-extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_PARAMS_WIDTH;
-extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_PARAMS_HEIGHT;
-extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_PARAMS_FRAMERATE;
-extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW_PARAMS_PREFERENCE;
+extern const buzz::StaticQName QN_JINGLE_DRAFT_PARAMS;
+extern const buzz::StaticQName QN_WIDTH;
+extern const buzz::StaticQName QN_HEIGHT;
+extern const buzz::StaticQName QN_FRAMERATE;
+extern const buzz::StaticQName QN_JINGLE_DRAFT_STREAM;
+extern const buzz::StaticQName QN_JINGLE_DRAFT_STREAMS;
+extern const buzz::StaticQName QN_DISPLAY;
+extern const buzz::StaticQName QN_CNAME;
+extern const buzz::StaticQName QN_JINGLE_DRAFT_SSRC;
+extern const buzz::StaticQName QN_JINGLE_DRAFT_SSRC_GROUP;
+extern const buzz::StaticQName QN_SEMANTICS;
+extern const buzz::StaticQName QN_JINGLE_LEGACY_NOTIFY;
+extern const buzz::StaticQName QN_JINGLE_LEGACY_SOURCE;
 
 // old stuff
 #ifdef FEATURE_ENABLE_VOICEMAIL
diff --git a/talk/p2p/base/p2ptransportchannel_unittest.cc b/talk/p2p/base/p2ptransportchannel_unittest.cc
index 109b04f..ae5ab62 100644
--- a/talk/p2p/base/p2ptransportchannel_unittest.cc
+++ b/talk/p2p/base/p2ptransportchannel_unittest.cc
@@ -384,9 +384,9 @@
         } else if (config == BLOCK_ALL_BUT_OUTGOING_HTTP) {
           // Block all TCP to/from the endpoint except 80/443 out
           fw()->AddRule(true, talk_base::FP_TCP, kPublicAddrs[endpoint],
-                        SocketAddress(0, 80));
+                        SocketAddress(talk_base::IPAddress(INADDR_ANY), 80));
           fw()->AddRule(true, talk_base::FP_TCP, kPublicAddrs[endpoint],
-                        SocketAddress(0, 443));
+                        SocketAddress(talk_base::IPAddress(INADDR_ANY), 443));
           fw()->AddRule(false, talk_base::FP_TCP, talk_base::FD_ANY,
                         kPublicAddrs[endpoint]);
         } else if (config == PROXY_HTTPS) {
diff --git a/talk/p2p/base/parsing.cc b/talk/p2p/base/parsing.cc
index a54d379..f302956 100644
--- a/talk/p2p/base/parsing.cc
+++ b/talk/p2p/base/parsing.cc
@@ -91,6 +91,18 @@
   return NULL;
 }
 
+const buzz::XmlElement* GetXmlElement(const XmlElements& elems,
+                                      const buzz::QName& name) {
+  for (XmlElements::const_iterator iter = elems.begin();
+       iter != elems.end(); ++iter) {
+    const buzz::XmlElement* elem = *iter;
+    if (elem->Name() == name) {
+      return elem;
+    }
+  }
+  return NULL;
+}
+
 bool RequireXmlChild(const buzz::XmlElement* parent,
                      const std::string& name,
                      const buzz::XmlElement** child,
@@ -120,6 +132,14 @@
   }
 }
 
+void AddXmlAttrIfNonEmpty(buzz::XmlElement* elem,
+                          const buzz::QName name,
+                          const std::string& value) {
+  if (!value.empty()) {
+    elem->AddAttr(name, value);
+  }
+}
+
 void AddXmlChildren(buzz::XmlElement* parent,
                     const std::vector<buzz::XmlElement*>& children) {
   for (std::vector<buzz::XmlElement*>::const_iterator iter = children.begin();
diff --git a/talk/p2p/base/parsing.h b/talk/p2p/base/parsing.h
index 7931431..589d9d7 100644
--- a/talk/p2p/base/parsing.h
+++ b/talk/p2p/base/parsing.h
@@ -112,6 +112,9 @@
 
 const buzz::XmlElement* GetXmlChild(const buzz::XmlElement* parent,
                                     const std::string& name);
+const buzz::XmlElement* GetXmlElement(const XmlElements& elems,
+                                      const buzz::QName& name);
+
 bool RequireXmlChild(const buzz::XmlElement* parent,
                      const std::string& name,
                      const buzz::XmlElement** child,
@@ -120,6 +123,9 @@
                     const buzz::QName& name,
                     std::string* value,
                     ParseError* error);
+void AddXmlAttrIfNonEmpty(buzz::XmlElement* elem,
+                          const buzz::QName name,
+                          const std::string& value);
 void AddXmlChildren(buzz::XmlElement* parent,
                     const std::vector<buzz::XmlElement*>& children);
 void CopyXmlChildren(const buzz::XmlElement* source, buzz::XmlElement* dest);
diff --git a/talk/p2p/base/port.cc b/talk/p2p/base/port.cc
index bb4ab26..a016f63 100644
--- a/talk/p2p/base/port.cc
+++ b/talk/p2p/base/port.cc
@@ -126,7 +126,7 @@
 
 Port::Port(talk_base::Thread* thread, const std::string& type,
            talk_base::PacketSocketFactory* factory, talk_base::Network* network,
-           uint32 ip, int min_port, int max_port)
+           const talk_base::IPAddress& ip, int min_port, int max_port)
     : thread_(thread),
       factory_(factory),
       type_(type),
@@ -351,7 +351,7 @@
   StunAddressAttribute* addr_attr =
       StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
   addr_attr->SetPort(addr.port());
-  addr_attr->SetIP(addr.ip());
+  addr_attr->SetIP(addr.ipaddr());
   response.AddAttribute(addr_attr);
 
   // Send the response message.
@@ -528,11 +528,8 @@
 }
 
 const Candidate& Connection::local_candidate() const {
-  if (local_candidate_index_ < port_->candidates().size())
-    return port_->candidates()[local_candidate_index_];
-  ASSERT(false);
-  static Candidate foo;
-  return foo;
+  ASSERT(local_candidate_index_ < port_->candidates().size());
+  return port_->candidates()[local_candidate_index_];
 }
 
 void Connection::set_read_state(ReadState value) {
diff --git a/talk/p2p/base/port.h b/talk/p2p/base/port.h
index 8304146..396fce0 100644
--- a/talk/p2p/base/port.h
+++ b/talk/p2p/base/port.h
@@ -77,7 +77,7 @@
  public:
   Port(talk_base::Thread* thread, const std::string& type,
        talk_base::PacketSocketFactory* factory, talk_base::Network* network,
-       uint32 ip, int min_port, int max_port);
+       const talk_base::IPAddress& ip, int min_port, int max_port);
   virtual ~Port();
 
   // The thread on which this port performs its I/O.
@@ -241,7 +241,7 @@
   talk_base::PacketSocketFactory* factory_;
   std::string type_;
   talk_base::Network* network_;
-  uint32 ip_;
+  talk_base::IPAddress ip_;
   int min_port_;
   int max_port_;
   uint32 generation_;
diff --git a/talk/p2p/base/port_unittest.cc b/talk/p2p/base/port_unittest.cc
index 4bb7fd3..1bdac3d 100644
--- a/talk/p2p/base/port_unittest.cc
+++ b/talk/p2p/base/port_unittest.cc
@@ -157,7 +157,8 @@
       : main_(talk_base::Thread::Current()),
         pss_(new talk_base::PhysicalSocketServer),
         ss_(new talk_base::VirtualSocketServer(pss_.get())),
-        ss_scope_(ss_.get()), network_("unittest", "unittest", 0),
+        ss_scope_(ss_.get()),
+        network_("unittest", "unittest", talk_base::IPAddress(INADDR_ANY)),
         socket_factory_(talk_base::Thread::Current()),
         nat_factory1_(ss_.get(), kNatAddr1),
         nat_factory2_(ss_.get(), kNatAddr2),
@@ -241,7 +242,8 @@
   }
   UDPPort* CreateUdpPort(const SocketAddress& addr,
                          PacketSocketFactory* socket_factory) {
-    return UDPPort::Create(main_, socket_factory, &network_, addr.ip(), 0, 0);
+    return UDPPort::Create(main_, socket_factory, &network_,
+                           addr.ipaddr(), 0, 0);
   }
   TCPPort* CreateTcpPort(const SocketAddress& addr) {
     return CreateTcpPort(addr, &socket_factory_);
@@ -249,19 +251,19 @@
   TCPPort* CreateTcpPort(const SocketAddress& addr,
                          PacketSocketFactory* socket_factory) {
     return TCPPort::Create(main_, socket_factory, &network_,
-                           addr.ip(), 0, 0, true);
+                           addr.ipaddr(), 0, 0, true);
   }
   StunPort* CreateStunPort(const SocketAddress& addr,
                            talk_base::PacketSocketFactory* factory) {
     return StunPort::Create(main_, factory, &network_,
-                            addr.ip(), 0, 0, kStunAddr);
+                            addr.ipaddr(), 0, 0, kStunAddr);
   }
   RelayPort* CreateRelayPort(const SocketAddress& addr,
                              ProtocolType int_proto, ProtocolType ext_proto) {
     std::string user = talk_base::CreateRandomString(16);
     std::string pass = talk_base::CreateRandomString(16);
     RelayPort* port = RelayPort::Create(main_, &socket_factory_, &network_,
-                                        addr.ip(), 0, 0, user, pass, "");
+                                        addr.ipaddr(), 0, 0, user, pass, "");
     SocketAddress addrs[] =
         { kRelayUdpIntAddr, kRelayTcpIntAddr, kRelaySslTcpIntAddr };
     port->AddServerAddress(ProtocolAddress(addrs[int_proto], int_proto));
diff --git a/talk/p2p/base/relayport.cc b/talk/p2p/base/relayport.cc
index 76bd5ff..c6c066a 100644
--- a/talk/p2p/base/relayport.cc
+++ b/talk/p2p/base/relayport.cc
@@ -187,9 +187,9 @@
 
 RelayPort::RelayPort(
     talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
-    talk_base::Network* network, uint32 ip, int min_port, int max_port,
-    const std::string& username, const std::string& password,
-    const std::string& magic_cookie)
+    talk_base::Network* network, const talk_base::IPAddress& ip,
+    int min_port, int max_port, const std::string& username,
+    const std::string& password, const std::string& magic_cookie)
     : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port),
       ready_(false),
       magic_cookie_(magic_cookie),
@@ -554,7 +554,7 @@
 
   StunAddressAttribute* addr_attr =
       StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
-  addr_attr->SetIP(addr.ip());
+  addr_attr->SetIP(addr.ipaddr());
   addr_attr->SetPort(addr.port());
   request.AddAttribute(addr_attr);
 
@@ -702,7 +702,7 @@
     return;
   }
 
-  talk_base::SocketAddress remote_addr2(addr_attr->ip(), addr_attr->port());
+  talk_base::SocketAddress remote_addr2(addr_attr->ipaddr(), addr_attr->port());
 
   const StunByteStringAttribute* data_attr = msg.GetByteString(STUN_ATTR_DATA);
   if (!data_attr) {
@@ -764,7 +764,7 @@
   } else if (addr_attr->family() != 1) {
     LOG(INFO) << "Mapped address has bad family";
   } else {
-    talk_base::SocketAddress addr(addr_attr->ip(), addr_attr->port());
+    talk_base::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
     entry_->OnConnect(addr, connection_);
   }
 
diff --git a/talk/p2p/base/relayport.h b/talk/p2p/base/relayport.h
index 62bb758..2137606 100644
--- a/talk/p2p/base/relayport.h
+++ b/talk/p2p/base/relayport.h
@@ -55,9 +55,9 @@
   // RelayPort doesn't yet do anything fancy in the ctor.
   static RelayPort* Create(
       talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
-      talk_base::Network* network, uint32 ip, int min_port, int max_port,
-      const std::string& username, const std::string& password,
-      const std::string& magic_cookie) {
+      talk_base::Network* network, const talk_base::IPAddress& ip,
+      int min_port, int max_port, const std::string& username,
+      const std::string& password, const std::string& magic_cookie) {
     return new RelayPort(thread, factory, network, ip, min_port, max_port,
                          username, password, magic_cookie);
   }
@@ -85,9 +85,9 @@
 
  protected:
   RelayPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
-            talk_base::Network*, uint32 ip, int min_port, int max_port,
-            const std::string& username, const std::string& password,
-            const std::string& magic_cookie);
+            talk_base::Network*, const talk_base::IPAddress& ip,
+            int min_port, int max_port, const std::string& username,
+            const std::string& password, const std::string& magic_cookie);
   bool Init();
 
   void SetReady();
diff --git a/talk/p2p/base/relayport_unittest.cc b/talk/p2p/base/relayport_unittest.cc
index 67fb238..688e635 100644
--- a/talk/p2p/base/relayport_unittest.cc
+++ b/talk/p2p/base/relayport_unittest.cc
@@ -65,12 +65,13 @@
         virtual_socket_server_(new talk_base::VirtualSocketServer(
             physical_socket_server_.get())),
         ss_scope_(virtual_socket_server_.get()),
-        network_("unittest", "unittest", 0),
+        network_("unittest", "unittest", talk_base::IPAddress(INADDR_ANY)),
         socket_factory_(talk_base::Thread::Current()),
         username_(talk_base::CreateRandomString(16)),
         password_(talk_base::CreateRandomString(16)),
         relay_port_(cricket::RelayPort::Create(main_, &socket_factory_,
-                                               &network_, kLocalAddress.ip(),
+                                               &network_,
+                                               kLocalAddress.ipaddr(),
                                                0, 0, username_, password_, "")),
         relay_server_(new cricket::RelayServer(main_)) {
   }
diff --git a/talk/p2p/base/relayserver.cc b/talk/p2p/base/relayserver.cc
index 554337f..b17da5b 100644
--- a/talk/p2p/base/relayserver.cc
+++ b/talk/p2p/base/relayserver.cc
@@ -444,7 +444,7 @@
 
   StunAddressAttribute* addr_attr =
       StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
-  addr_attr->SetIP(ext_addr.ip());
+  addr_attr->SetIP(ext_addr.ipaddr());
   addr_attr->SetPort(ext_addr.port());
   response.AddAttribute(addr_attr);
 
@@ -478,7 +478,7 @@
     return;
   }
 
-  talk_base::SocketAddress ext_addr(addr_attr->ip(), addr_attr->port());
+  talk_base::SocketAddress ext_addr(addr_attr->ipaddr(), addr_attr->port());
   RelayServerConnection* ext_conn =
       int_conn->binding()->GetExternalConnection(ext_addr);
   if (!ext_conn) {
@@ -620,7 +620,7 @@
 
   StunAddressAttribute* addr_attr =
       StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2);
-  addr_attr->SetIP(from_addr.ip());
+  addr_attr->SetIP(from_addr.ipaddr());
   addr_attr->SetPort(from_addr.port());
   msg.AddAttribute(addr_attr);
 
diff --git a/talk/p2p/base/relayserver_unittest.cc b/talk/p2p/base/relayserver_unittest.cc
index 1528eb4..0f96e27 100644
--- a/talk/p2p/base/relayserver_unittest.cc
+++ b/talk/p2p/base/relayserver_unittest.cc
@@ -174,7 +174,7 @@
   static void AddDestinationAttr(StunMessage* msg, const SocketAddress& addr) {
     StunAddressAttribute* attr =
         StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
-    attr->SetIP(addr.ip());
+    attr->SetIP(addr.ipaddr());
     attr->SetPort(addr.port());
     msg->AddAttribute(attr);
   }
@@ -263,7 +263,7 @@
   ASSERT_TRUE(mapped_addr != NULL);
   EXPECT_EQ(1, mapped_addr->family());
   EXPECT_EQ(server_ext_addr.port(), mapped_addr->port());
-  EXPECT_EQ(server_ext_addr.ip(), mapped_addr->ip());
+  EXPECT_EQ(server_ext_addr.ipaddr(), mapped_addr->ipaddr());
 
   const StunUInt32Attribute* res_lifetime_attr =
       res->GetUInt32(STUN_ATTR_LIFETIME);
@@ -293,7 +293,7 @@
   ASSERT_TRUE(mapped_addr != NULL);
   EXPECT_EQ(1, mapped_addr->family());
   EXPECT_EQ(server_ext_addr.port(), mapped_addr->port());
-  EXPECT_EQ(server_ext_addr.ip(), mapped_addr->ip());
+  EXPECT_EQ(server_ext_addr.ipaddr(), mapped_addr->ipaddr());
 
   const StunUInt32Attribute* lifetime_attr =
       res->GetUInt32(STUN_ATTR_LIFETIME);
@@ -330,7 +330,7 @@
       res->GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
   ASSERT_TRUE(src_addr != NULL);
   EXPECT_EQ(1, src_addr->family());
-  EXPECT_EQ(client2_addr.ip(), src_addr->ip());
+  EXPECT_EQ(client2_addr.ipaddr(), src_addr->ipaddr());
   EXPECT_EQ(client2_addr.port(), src_addr->port());
 
   EXPECT_TRUE(Receive2() == NULL);
@@ -498,7 +498,7 @@
         res->GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
     ASSERT_TRUE(src_addr != NULL);
     EXPECT_EQ(1, src_addr->family());
-    EXPECT_EQ(client2_addr.ip(), src_addr->ip());
+    EXPECT_EQ(client2_addr.ipaddr(), src_addr->ipaddr());
     EXPECT_EQ(client2_addr.port(), src_addr->port());
 
     const StunByteStringAttribute* recv_data =
diff --git a/talk/p2p/base/session.cc b/talk/p2p/base/session.cc
index ab4d83f..9891ee2 100644
--- a/talk/p2p/base/session.cc
+++ b/talk/p2p/base/session.cc
@@ -737,8 +737,8 @@
     case ACTION_TRANSPORT_ACCEPT:
       valid = OnTransportAcceptMessage(msg, &error);
       break;
-    case ACTION_UPDATE:
-      valid = OnUpdateMessage(msg, &error);
+    case ACTION_DESCRIPTION_INFO:
+      valid = OnDescriptionInfoMessage(msg, &error);
       break;
     default:
       valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST,
@@ -946,7 +946,7 @@
   return true;
 }
 
-bool Session::OnUpdateMessage(const SessionMessage& msg,
+bool Session::OnDescriptionInfoMessage(const SessionMessage& msg,
                               MessageError* error) {
   if (!CheckState(STATE_INPROGRESS, error))
     return false;
@@ -972,12 +972,14 @@
   }
 
   // Merge the updates into the remote description.
+  // TODO: Merge streams instead of overwriting.
   for (it = updated_contents.begin(); it != updated_contents.end(); ++it) {
     LOG(LS_INFO) << "Updating content " << it->name;
     remote_description()->RemoveContentByName(it->name);
     remote_description()->AddContent(it->name, it->type, it->description);
   }
 
+  // TODO: Add an argument that shows what streams were changed.
   SignalRemoteDescriptionUpdate(this);
 
   return true;
diff --git a/talk/p2p/base/session.h b/talk/p2p/base/session.h
index c968f5d..f3b6f25 100644
--- a/talk/p2p/base/session.h
+++ b/talk/p2p/base/session.h
@@ -562,7 +562,7 @@
   bool OnTerminateMessage(const SessionMessage& msg, MessageError* error);
   bool OnTransportInfoMessage(const SessionMessage& msg, MessageError* error);
   bool OnTransportAcceptMessage(const SessionMessage& msg, MessageError* error);
-  bool OnUpdateMessage(const SessionMessage& msg, MessageError* error);
+  bool OnDescriptionInfoMessage(const SessionMessage& msg, MessageError* error);
   bool OnRedirectError(const SessionRedirect& redirect, SessionError* error);
 
   // Verifies that we are in the appropriate state to receive this message.
diff --git a/talk/p2p/base/session_unittest.cc b/talk/p2p/base/session_unittest.cc
index e6f0d43..e663113 100644
--- a/talk/p2p/base/session_unittest.cc
+++ b/talk/p2p/base/session_unittest.cc
@@ -567,7 +567,7 @@
         port_offset_(port_offset),
         ports_(kNumPorts),
         address_("127.0.0.1", 0),
-        network_("network", "unittest", address_.ip()),
+        network_("network", "unittest", address_.ipaddr()),
         socket_factory_(talk_base::Thread::Current()),
         running_(false),
         port_(28653) {
@@ -583,7 +583,7 @@
       int index = port_offset_ + i;
       ports_[i] = cricket::UDPPort::Create(
           talk_base::Thread::Current(), &socket_factory_,
-          &network_, address_.ip(), GetPort(index), GetPort(index));
+          &network_, address_.ipaddr(), GetPort(index), GetPort(index));
       ports_[i]->set_username_fragment(GetUsername(index));
       ports_[i]->set_password(GetPassword(index));
       AddPort(ports_[i]);
@@ -1027,7 +1027,7 @@
         session->CreateChannel(content_name_a, channel_name_a));
     chan_b = new ChannelHandler(
         session->CreateChannel(content_name_b, channel_name_b));
-    if (chan_aa == NULL && chan_bb == NULL) {
+    if (!channel_name_aa.empty() && !channel_name_bb.empty()) {
       chan_aa = new ChannelHandler(
           session->CreateChannel(content_name_a, channel_name_aa));
       chan_bb = new ChannelHandler(
@@ -2065,14 +2065,12 @@
 // initiates to a client with protocol Y, they end up speaking protocol Z.
 
 // Gingle => Gingle = Gingle (with other content)
-// Disabled due to flakey pulse builds
-TEST_F(SessionTest, DISABLED_GingleToGingleOtherContent) {
+TEST_F(SessionTest, GingleToGingleOtherContent) {
   TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
 }
 
 // Gingle => Gingle = Gingle (with audio content)
-// Disabled due to flakey pulse builds
-TEST_F(SessionTest, DISABLED_GingleToGingleAudioContent) {
+TEST_F(SessionTest, GingleToGingleAudioContent) {
   TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
 }
 
@@ -2199,8 +2197,7 @@
   TestRejection(PROTOCOL_JINGLE);
 }
 
-// Disabled due to flakey pulse builds
-TEST_F(SessionTest, DISABLED_GingleGoodRedirect) {
+TEST_F(SessionTest, GingleGoodRedirect) {
   TestGoodRedirect(PROTOCOL_GINGLE);
 }
 
diff --git a/talk/p2p/base/sessionmessages.cc b/talk/p2p/base/sessionmessages.cc
index 840d1a6..96f91d1 100644
--- a/talk/p2p/base/sessionmessages.cc
+++ b/talk/p2p/base/sessionmessages.cc
@@ -73,9 +73,9 @@
   if (type == JINGLE_ACTION_TRANSPORT_ACCEPT)
     return ACTION_TRANSPORT_ACCEPT;
   if (type == JINGLE_ACTION_DESCRIPTION_INFO)
-    return ACTION_UPDATE;
+    return ACTION_DESCRIPTION_INFO;
   if (type == GINGLE_ACTION_UPDATE)
-    return ACTION_UPDATE;
+    return ACTION_DESCRIPTION_INFO;
 
   return ACTION_UNKNOWN;
 }
diff --git a/talk/p2p/base/sessionmessages.h b/talk/p2p/base/sessionmessages.h
index 214fa8c..1486f0c 100644
--- a/talk/p2p/base/sessionmessages.h
+++ b/talk/p2p/base/sessionmessages.h
@@ -62,7 +62,7 @@
   ACTION_TRANSPORT_INFO,
   ACTION_TRANSPORT_ACCEPT,
 
-  ACTION_UPDATE,
+  ACTION_DESCRIPTION_INFO,
 };
 
 // Abstraction of a <jingle> element within an <iq> stanza, per XMPP
diff --git a/talk/p2p/base/stun.cc b/talk/p2p/base/stun.cc
index fab14af..3b3fad4 100644
--- a/talk/p2p/base/stun.cc
+++ b/talk/p2p/base/stun.cc
@@ -347,6 +347,7 @@
   uint8 family;
   // We don't expect IPv6 address here because IPv6 addresses would
   // not pass the attribute size check in StunAttribute::Create().
+  // TODO: Support IPv6 addresses.
   if (!buf->ReadUInt8(&family) || family != STUN_ADDRESS_IPV4) {
     return false;
   }
@@ -354,9 +355,10 @@
 
   if (!buf->ReadUInt16(&port_))
     return false;
-
-  if (!buf->ReadUInt32(&ip_))
+  uint32 ip;
+  if (!buf->ReadUInt32(&ip))
     return false;
+  SetIP(talk_base::IPAddress(ip));
 
   return true;
 }
@@ -368,7 +370,7 @@
   buf->WriteUInt8(0);
   buf->WriteUInt8(family_);
   buf->WriteUInt16(port_);
-  buf->WriteUInt32(ip_);
+  buf->WriteUInt32(ip_.v4AddressAsHostOrderInteger());
 }
 
 StunXorAddressAttribute::StunXorAddressAttribute(uint16 type)
@@ -380,7 +382,8 @@
     return false;
 
   SetPort(port() ^ (kStunMagicCookie >> 16));
-  SetIP(ip() ^ kStunMagicCookie);
+  uint32 ip = ipaddr().v4AddressAsHostOrderInteger();
+  SetIP(talk_base::IPAddress(ip ^ kStunMagicCookie));
 
   return true;
 }
@@ -392,7 +395,7 @@
   buf->WriteUInt8(0);
   buf->WriteUInt8(family());
   buf->WriteUInt16(port() ^ (kStunMagicCookie >> 16));
-  buf->WriteUInt32(ip() ^ kStunMagicCookie);
+  buf->WriteUInt32(ipaddr().v4AddressAsHostOrderInteger() ^ kStunMagicCookie);
 }
 
 StunUInt32Attribute::StunUInt32Attribute(uint16 type)
diff --git a/talk/p2p/base/stun.h b/talk/p2p/base/stun.h
index efc5f2c..87687b1 100644
--- a/talk/p2p/base/stun.h
+++ b/talk/p2p/base/stun.h
@@ -36,6 +36,7 @@
 
 #include "talk/base/basictypes.h"
 #include "talk/base/bytebuffer.h"
+#include "talk/base/ipaddress.h"
 
 namespace cricket {
 
@@ -206,6 +207,7 @@
 };
 
 // Implements STUN/TURN attributes that record an Internet address.
+// TODO: IPv6 support, and use the SocketAddress class.
 class StunAddressAttribute : public StunAttribute {
 public:
   explicit StunAddressAttribute(uint16 type);
@@ -214,10 +216,10 @@
 
   StunAddressFamily family() const { return family_; }
   uint16 port() const { return port_; }
-  uint32 ip() const { return ip_; }
+  talk_base::IPAddress ipaddr() const { return ip_; }
 
   void SetFamily(StunAddressFamily family);
-  void SetIP(uint32 ip) { ip_ = ip; }
+  void SetIP(const talk_base::IPAddress& ip) { ip_ = ip; }
   void SetPort(uint16 port) { port_ = port; }
 
   virtual bool Read(talk_base::ByteBuffer* buf);
@@ -226,7 +228,7 @@
 private:
   StunAddressFamily family_;
   uint16 port_;
-  uint32 ip_;
+  talk_base::IPAddress ip_;
 };
 
 // Implements STUN/TURN attributes that record an Internet address.
diff --git a/talk/p2p/base/stun_unittest.cc b/talk/p2p/base/stun_unittest.cc
index 16dc26c..34b6059 100644
--- a/talk/p2p/base/stun_unittest.cc
+++ b/talk/p2p/base/stun_unittest.cc
@@ -158,12 +158,12 @@
   EXPECT_TRUE(addr != NULL);
   EXPECT_EQ(1, addr->family());
   EXPECT_EQ(13, addr->port());
-  EXPECT_EQ(17U, addr->ip());
+  EXPECT_EQ(talk_base::IPAddress(17U), addr->ipaddr());
 
   StunAddressAttribute* addr2 =
       StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
   addr2->SetPort(13);
-  addr2->SetIP(17);
+  addr2->SetIP(talk_base::IPAddress(17U));
   msg2.AddAttribute(addr2);
 
   const StunByteStringAttribute* bytes = msg.GetByteString(STUN_ATTR_USERNAME);
@@ -239,22 +239,22 @@
   EXPECT_TRUE(addr != NULL);
   EXPECT_EQ(1, addr->family());
   EXPECT_EQ(13, addr->port());
-  EXPECT_EQ(17U, addr->ip());
+  EXPECT_EQ(talk_base::IPAddress(17U), addr->ipaddr());
 
   addr2 = StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
   addr2->SetPort(13);
-  addr2->SetIP(17);
+  addr2->SetIP(talk_base::IPAddress(17U));
   msg2.AddAttribute(addr2);
 
   addr = msg.GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
   EXPECT_TRUE(addr != NULL);
   EXPECT_EQ(1, addr->family());
   EXPECT_EQ(13, addr->port());
-  EXPECT_EQ(17U, addr->ip());
+  EXPECT_EQ(talk_base::IPAddress(17U), addr->ipaddr());
 
   addr2 = StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS2);
   addr2->SetPort(13);
-  addr2->SetIP(17);
+  addr2->SetIP(talk_base::IPAddress(17U));
   msg2.AddAttribute(addr2);
 
   bytes = msg.GetByteString(STUN_ATTR_DATA);
@@ -306,7 +306,7 @@
   EXPECT_TRUE(addr != NULL);
   EXPECT_EQ(1, addr->family());
   EXPECT_EQ(13, addr->port());
-  EXPECT_EQ(17U, addr->ip());
+  EXPECT_EQ(talk_base::IPAddress(17U), addr->ipaddr());
 
   const StunUInt32Attribute* uval = msg.GetUInt32(STUN_ATTR_LIFETIME);
   EXPECT_TRUE(uval != NULL);
@@ -324,11 +324,11 @@
   EXPECT_TRUE(addr != NULL);
   EXPECT_EQ(1, addr->family());
   EXPECT_EQ(13, addr->port());
-  EXPECT_EQ(17U, addr->ip());
+  EXPECT_EQ(talk_base::IPAddress(17U), addr->ipaddr());
 
   addr = msg.GetAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
   EXPECT_TRUE(addr != NULL);
   EXPECT_EQ(1, addr->family());
   EXPECT_EQ(13, addr->port());
-  EXPECT_EQ(17U, addr->ip());
+  EXPECT_EQ(talk_base::IPAddress(17U), addr->ipaddr());
 }
diff --git a/talk/p2p/base/stunport.cc b/talk/p2p/base/stunport.cc
index ba797ff..7328b99 100644
--- a/talk/p2p/base/stunport.cc
+++ b/talk/p2p/base/stunport.cc
@@ -66,7 +66,7 @@
     } else if (addr_attr->family() != 1) {
       LOG(LS_ERROR) << "Binding address has bad family";
     } else {
-      talk_base::SocketAddress addr(addr_attr->ip(), addr_attr->port());
+      talk_base::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
       port_->AddAddress(addr, "udp", true);
     }
 
@@ -127,7 +127,7 @@
 StunPort::StunPort(talk_base::Thread* thread,
                    talk_base::PacketSocketFactory* factory,
                    talk_base::Network* network,
-                   uint32 ip, int min_port, int max_port,
+                   const talk_base::IPAddress& ip, int min_port, int max_port,
                    const talk_base::SocketAddress& server_addr)
     : Port(thread, STUN_PORT_TYPE, factory, network, ip, min_port, max_port),
       server_addr_(server_addr),
diff --git a/talk/p2p/base/stunport.h b/talk/p2p/base/stunport.h
index 26f46a5..c74ad4d 100644
--- a/talk/p2p/base/stunport.h
+++ b/talk/p2p/base/stunport.h
@@ -49,7 +49,8 @@
   static StunPort* Create(talk_base::Thread* thread,
                           talk_base::PacketSocketFactory* factory,
                           talk_base::Network* network,
-                          uint32 ip, int min_port, int max_port,
+                          const talk_base::IPAddress& ip,
+                          int min_port, int max_port,
                           const talk_base::SocketAddress& server_addr) {
     StunPort* port = new StunPort(thread, factory, network,
                                   ip, min_port, max_port, server_addr);
@@ -88,7 +89,8 @@
 
  protected:
   StunPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
-           talk_base::Network* network, uint32 ip, int min_port, int max_port,
+           talk_base::Network* network, const talk_base::IPAddress& ip,
+           int min_port, int max_port,
            const talk_base::SocketAddress& server_addr);
   bool Init();
 
diff --git a/talk/p2p/base/stunport_unittest.cc b/talk/p2p/base/stunport_unittest.cc
index 6dd1ee4..3d830ba 100644
--- a/talk/p2p/base/stunport_unittest.cc
+++ b/talk/p2p/base/stunport_unittest.cc
@@ -48,7 +48,7 @@
                      public sigslot::has_slots<> {
  public:
   StunPortTest()
-      : network_("unittest", "unittest", 0),
+      : network_("unittest", "unittest", talk_base::IPAddress(INADDR_ANY)),
         socket_factory_(talk_base::Thread::Current()),
         stun_server_(new cricket::TestStunServer(
           talk_base::Thread::Current(), kStunAddr)),
@@ -62,7 +62,7 @@
   void CreateStunPort(const talk_base::SocketAddress& server_addr) {
     stun_port_.reset(cricket::StunPort::Create(
         talk_base::Thread::Current(), &socket_factory_, &network_,
-        kLocalAddr.ip(), 0, 0, server_addr));
+        kLocalAddr.ipaddr(), 0, 0, server_addr));
     stun_port_->SignalAddressReady.connect(this,
         &StunPortTest::OnAddressReady);
     stun_port_->SignalAddressError.connect(this,
diff --git a/talk/p2p/base/stunserver.cc b/talk/p2p/base/stunserver.cc
index f34fd2d..8a5d447 100644
--- a/talk/p2p/base/stunserver.cc
+++ b/talk/p2p/base/stunserver.cc
@@ -96,7 +96,7 @@
     mapped_addr = StunAttribute::CreateAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
   }
   mapped_addr->SetPort(remote_addr.port());
-  mapped_addr->SetIP(remote_addr.ip());
+  mapped_addr->SetIP(remote_addr.ipaddr());
   response.AddAttribute(mapped_addr);
 
   // TODO: Add username and message-integrity.
diff --git a/talk/p2p/base/stunserver_unittest.cc b/talk/p2p/base/stunserver_unittest.cc
index a475101..b7f2f00 100644
--- a/talk/p2p/base/stunserver_unittest.cc
+++ b/talk/p2p/base/stunserver_unittest.cc
@@ -99,11 +99,10 @@
   EXPECT_TRUE(mapped_addr != NULL);
   EXPECT_EQ(1, mapped_addr->family());
   EXPECT_EQ(client_addr.port(), mapped_addr->port());
-  if (mapped_addr->ip() != client_addr.ip()) {
+  if (mapped_addr->ipaddr() != client_addr.ipaddr()) {
     LOG(LS_WARNING) << "Warning: mapped IP ("
-                    << talk_base::SocketAddress::IPToString(
-                           mapped_addr->ip()).c_str()
-                    << ") != local IP (" << client_addr.IPAsString().c_str()
+                    << mapped_addr->ipaddr()
+                    << ") != local IP (" << client_addr.ipaddr()
                     << ")";
   }
 
diff --git a/talk/p2p/base/tcpport.cc b/talk/p2p/base/tcpport.cc
index 555ba73..4db4761 100644
--- a/talk/p2p/base/tcpport.cc
+++ b/talk/p2p/base/tcpport.cc
@@ -35,7 +35,7 @@
 
 TCPPort::TCPPort(talk_base::Thread* thread,
                  talk_base::PacketSocketFactory* factory,
-                 talk_base::Network* network, uint32 ip,
+                 talk_base::Network* network, const talk_base::IPAddress& ip,
                  int min_port, int max_port, bool allow_listen)
     : Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port),
       incoming_only_(false),
@@ -218,7 +218,7 @@
     }
   } else {
     // Incoming connections should match the network address.
-    ASSERT(socket_->GetLocalAddress().ip() == port->ip_);
+    ASSERT(socket_->GetLocalAddress().ipaddr() == port->ip_);
   }
 
   if (socket_) {
diff --git a/talk/p2p/base/tcpport.h b/talk/p2p/base/tcpport.h
index 8345b12..5ce917d 100644
--- a/talk/p2p/base/tcpport.h
+++ b/talk/p2p/base/tcpport.h
@@ -50,7 +50,8 @@
   static TCPPort* Create(talk_base::Thread* thread,
                          talk_base::PacketSocketFactory* factory,
                          talk_base::Network* network,
-                         uint32 ip, int min_port, int max_port,
+                         const talk_base::IPAddress& ip,
+                         int min_port, int max_port,
                          bool allow_listen) {
     TCPPort* port = new TCPPort(thread, factory, network,
                                 ip, min_port, max_port, allow_listen);
@@ -73,8 +74,8 @@
 
  protected:
   TCPPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
-          talk_base::Network* network, uint32 ip, int min_port, int max_port,
-          bool allow_listen);
+          talk_base::Network* network, const talk_base::IPAddress& ip,
+          int min_port, int max_port, bool allow_listen);
   bool Init();
 
   // Handles sending using the local TCP socket.
diff --git a/talk/p2p/base/udpport.cc b/talk/p2p/base/udpport.cc
index 8355b00..311fb45 100644
--- a/talk/p2p/base/udpport.cc
+++ b/talk/p2p/base/udpport.cc
@@ -38,7 +38,7 @@
 UDPPort::UDPPort(talk_base::Thread* thread,
                  talk_base::PacketSocketFactory* factory,
                  talk_base::Network* network,
-                 uint32 ip, int min_port, int max_port)
+                 const talk_base::IPAddress& ip, int min_port, int max_port)
     : Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port),
       socket_(NULL),
       error_(0) {
diff --git a/talk/p2p/base/udpport.h b/talk/p2p/base/udpport.h
index d74d4a3..5d767bb 100644
--- a/talk/p2p/base/udpport.h
+++ b/talk/p2p/base/udpport.h
@@ -48,7 +48,8 @@
   static UDPPort* Create(talk_base::Thread* thread,
                          talk_base::PacketSocketFactory* factory,
                          talk_base::Network* network,
-                         uint32 ip, int min_port, int max_port) {
+                         const talk_base::IPAddress& ip,
+                         int min_port, int max_port) {
     UDPPort* port = new UDPPort(thread, factory, network,
                                 ip, min_port, max_port);
     if (!port->Init()) {
@@ -68,7 +69,8 @@
 
  protected:
   UDPPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
-          talk_base::Network* network, uint32 ip, int min_port, int max_port);
+          talk_base::Network* network, const talk_base::IPAddress& ip,
+          int min_port, int max_port);
   bool Init();
 
   // Handles sending using the local UDP socket.
diff --git a/talk/p2p/client/basicportallocator.cc b/talk/p2p/client/basicportallocator.cc
index 51d069e..ec13b86 100644
--- a/talk/p2p/client/basicportallocator.cc
+++ b/talk/p2p/client/basicportallocator.cc
@@ -154,7 +154,7 @@
 
   BasicPortAllocatorSession* session_;
   talk_base::Network* network_;
-  uint32 ip_;
+  talk_base::IPAddress ip_;
   PortConfiguration* config_;
   bool running_;
   int step_;
diff --git a/talk/p2p/client/portallocator_unittest.cc b/talk/p2p/client/portallocator_unittest.cc
index 9c7db4d..be3a4e1 100644
--- a/talk/p2p/client/portallocator_unittest.cc
+++ b/talk/p2p/client/portallocator_unittest.cc
@@ -104,7 +104,7 @@
                              const std::string& proto,
                              const SocketAddress& addr) {
     return (c.name() == name && c.type() == type &&
-        c.protocol() == proto && c.address().ip() == addr.ip() &&
+        c.protocol() == proto && c.address().ipaddr() == addr.ipaddr() &&
         (addr.port() == 0 || (c.address().port() == addr.port())));
   }
   static bool CheckPort(const talk_base::SocketAddress& addr,
diff --git a/talk/session/phone/call.cc b/talk/session/phone/call.cc
index e01e937..4b2e229 100644
--- a/talk/session/phone/call.cc
+++ b/talk/session/phone/call.cc
@@ -151,7 +151,7 @@
 
   XmlElements elems;
   WriteError error;
-  if (!WriteViewRequest(CN_VIDEO, view_request, &elems, &error)) {
+  if (!WriteJingleViewRequest(CN_VIDEO, view_request, &elems, &error)) {
     LOG(LS_ERROR) << "Couldn't write out view request: " << error.text;
     return false;
   }
diff --git a/talk/session/phone/channel.cc b/talk/session/phone/channel.cc
index 42506dd..90d917d 100644
--- a/talk/session/phone/channel.cc
+++ b/talk/session/phone/channel.cc
@@ -559,6 +559,8 @@
   return ret;
 }
 
+// TODO: Check all of the ssrcs in all of the streams in
+// the content, and not just the first one.
 bool BaseChannel::SetSsrcMux_w(bool enable,
                                const MediaContentDescription* content,
                                ContentAction action,
@@ -567,12 +569,12 @@
   if (action == CA_OFFER) {
     ret = ssrc_filter_.SetOffer(enable, src);
     if (ret && src == CS_REMOTE) {  // if received offer with ssrc
-      ret = ssrc_filter_.AddStream(content->ssrc());
+      ret = ssrc_filter_.AddStream(content->first_ssrc());
     }
   } else if (action == CA_ANSWER) {
     ret = ssrc_filter_.SetAnswer(enable, src);
     if (ret && src == CS_REMOTE && ssrc_filter_.IsActive()) {
-      ret = ssrc_filter_.AddStream(content->ssrc());
+      ret = ssrc_filter_.AddStream(content->first_ssrc());
     }
   }
   return ret;
@@ -838,9 +840,10 @@
   ASSERT(audio != NULL);
 
   bool ret;
-  if (audio->ssrc_set()) {
-    media_channel()->SetSendSsrc(audio->ssrc());
-    LOG(LS_INFO) << "Set send ssrc for audio: " << audio->ssrc();
+  if (audio->has_ssrcs()) {
+    // TODO: Handle multiple streams and ssrcs here.
+    media_channel()->SetSendSsrc(audio->first_ssrc());
+    LOG(LS_INFO) << "Set send ssrc for audio: " << audio->first_ssrc();
   }
   // Set local SRTP parameters (what we will encrypt with).
   ret = SetSrtp_w(audio->cryptos(), action, CS_LOCAL);
@@ -850,7 +853,7 @@
   }
   // Set SSRC mux filter
   if (ret) {
-    ret = SetSsrcMux_w(audio->ssrc_set(), content, action, CS_LOCAL);
+    ret = SetSsrcMux_w(audio->has_ssrcs(), content, action, CS_LOCAL);
   }
   // Set local audio codecs (what we want to receive).
   if (ret) {
@@ -889,7 +892,7 @@
   }
   // Set SSRC mux filter
   if (ret) {
-    ret = SetSsrcMux_w(audio->ssrc_set(), content, action, CS_REMOTE);
+    ret = SetSsrcMux_w(audio->has_ssrcs(), content, action, CS_REMOTE);
   }
 
   // Set remote video codecs (what the other side wants to receive).
@@ -1201,9 +1204,10 @@
   ASSERT(video != NULL);
 
   bool ret;
-  if (video->ssrc_set()) {
-    media_channel()->SetSendSsrc(video->ssrc());
-    LOG(LS_INFO) << "Set send ssrc for video: " << video->ssrc();
+  if (video->has_ssrcs()) {
+    // TODO: Handle multiple streams and ssrcs here.
+    media_channel()->SetSendSsrc(video->first_ssrc());
+    LOG(LS_INFO) << "Set send ssrc for video: " << video->first_ssrc();
   }
   // Set local SRTP parameters (what we will encrypt with).
   ret = SetSrtp_w(video->cryptos(), action, CS_LOCAL);
@@ -1213,7 +1217,7 @@
   }
   // Set SSRC mux filter
   if (ret) {
-    ret = SetSsrcMux_w(video->ssrc_set(), content, action, CS_LOCAL);
+    ret = SetSsrcMux_w(video->has_ssrcs(), content, action, CS_LOCAL);
   }
 
   // Set local video codecs (what we want to receive).
@@ -1253,7 +1257,7 @@
   }
   // Set SSRC mux filter
   if (ret) {
-    ret = SetSsrcMux_w(video->ssrc_set(), content, action, CS_REMOTE);
+    ret = SetSsrcMux_w(video->has_ssrcs(), content, action, CS_REMOTE);
   }
   // Set remote video codecs (what the other side wants to receive).
   if (ret) {
diff --git a/talk/session/phone/devicemanager_unittest.cc b/talk/session/phone/devicemanager_unittest.cc
index 91afdc8..a64eab9 100644
--- a/talk/session/phone/devicemanager_unittest.cc
+++ b/talk/session/phone/devicemanager_unittest.cc
@@ -29,11 +29,12 @@
 #include "talk/base/win32.h"
 #include <objbase.h>
 #endif
+#include "talk/base/fileutils.h"
 #include "talk/base/gunit.h"
 #include "talk/base/logging.h"
-#include "talk/base/stream.h"
-#include "talk/base/fileutils.h"
 #include "talk/base/pathutils.h"
+#include "talk/base/scoped_ptr.h"
+#include "talk/base/stream.h"
 #include "talk/session/phone/devicemanager.h"
 #include "talk/session/phone/v4llookup.h"
 
@@ -42,50 +43,47 @@
 #include "talk/base/fileutils_mock.h"
 #endif  // LINUX
 
+#include "talk/session/phone/devicemanager.h"
+
 using talk_base::Pathname;
 using talk_base::FileTimeType;
+using talk_base::scoped_ptr;
 using cricket::Device;
+using cricket::DeviceManager;
+using cricket::DeviceManagerFactory;
+using cricket::DeviceManagerInterface;
 
 // Test that we startup/shutdown properly.
 TEST(DeviceManagerTest, StartupShutdown) {
-  cricket::DeviceManager dm;
-  EXPECT_FALSE(dm.initialized());
-  EXPECT_TRUE(dm.Init());
-  EXPECT_TRUE(dm.initialized());
-  dm.Terminate();
-  EXPECT_FALSE(dm.initialized());
+  scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
+  EXPECT_TRUE(dm->Init());
+  dm->Terminate();
 }
 
 // Test CoInitEx behavior
 #ifdef WIN32
 TEST(DeviceManagerTest, CoInitialize) {
-  cricket::DeviceManager dm;
+  scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
   std::vector<Device> devices;
   // Ensure that calls to video device work if COM is not yet initialized.
-  EXPECT_FALSE(dm.initialized());
-  EXPECT_TRUE(dm.Init());
-  EXPECT_TRUE(dm.initialized());
-  EXPECT_TRUE(dm.GetVideoCaptureDevices(&devices));
-  dm.Terminate();
+  EXPECT_TRUE(dm->Init());
+  EXPECT_TRUE(dm->GetVideoCaptureDevices(&devices));
+  dm->Terminate();
   // Ensure that the ref count is correct.
   EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED));
   CoUninitialize();
   // Ensure that Init works in COINIT_APARTMENTTHREADED setting.
-  EXPECT_FALSE(dm.initialized());
   EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
-  EXPECT_TRUE(dm.Init());
-  EXPECT_TRUE(dm.initialized());
-  dm.Terminate();
+  EXPECT_TRUE(dm->Init());
+  dm->Terminate();
   CoUninitialize();
   // Ensure that the ref count is correct.
   EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
   CoUninitialize();
   // Ensure that Init works in COINIT_MULTITHREADED setting.
-  EXPECT_FALSE(dm.initialized());
   EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED));
-  EXPECT_TRUE(dm.Init());
-  EXPECT_TRUE(dm.initialized());
-  dm.Terminate();
+  EXPECT_TRUE(dm->Init());
+  dm->Terminate();
   CoUninitialize();
   // Ensure that the ref count is correct.
   EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED));
@@ -95,52 +93,52 @@
 
 // Test enumerating devices (although we may not find any).
 TEST(DeviceManagerTest, GetDevices) {
-  cricket::DeviceManager dm;
+  scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
   std::vector<Device> audio_ins, audio_outs, video_ins;
   std::vector<cricket::Device> video_in_devs;
   cricket::Device def_video;
-  EXPECT_TRUE(dm.Init());
-  EXPECT_TRUE(dm.GetAudioInputDevices(&audio_ins));
-  EXPECT_TRUE(dm.GetAudioOutputDevices(&audio_outs));
-  EXPECT_TRUE(dm.GetVideoCaptureDevices(&video_ins));
-  EXPECT_TRUE(dm.GetVideoCaptureDevices(&video_in_devs));
+  EXPECT_TRUE(dm->Init());
+  EXPECT_TRUE(dm->GetAudioInputDevices(&audio_ins));
+  EXPECT_TRUE(dm->GetAudioOutputDevices(&audio_outs));
+  EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
+  EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_in_devs));
   EXPECT_EQ(video_ins.size(), video_in_devs.size());
   // If we have any video devices, we should be able to pick a default.
-  EXPECT_TRUE(dm.GetVideoCaptureDevice(
+  EXPECT_TRUE(dm->GetVideoCaptureDevice(
       cricket::DeviceManagerInterface::kDefaultDeviceName, &def_video)
       != video_ins.empty());
 }
 
 // Test that we return correct ids for default and bogus devices.
 TEST(DeviceManagerTest, GetAudioDeviceIds) {
-  cricket::DeviceManager dm;
+  scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
   Device device;
-  EXPECT_TRUE(dm.Init());
-  EXPECT_TRUE(dm.GetAudioInputDevice(
+  EXPECT_TRUE(dm->Init());
+  EXPECT_TRUE(dm->GetAudioInputDevice(
       cricket::DeviceManagerInterface::kDefaultDeviceName, &device));
   EXPECT_EQ("-1", device.id);
-  EXPECT_TRUE(dm.GetAudioOutputDevice(
+  EXPECT_TRUE(dm->GetAudioOutputDevice(
       cricket::DeviceManagerInterface::kDefaultDeviceName, &device));
   EXPECT_EQ("-1", device.id);
-  EXPECT_FALSE(dm.GetAudioInputDevice("_NOT A REAL DEVICE_", &device));
-  EXPECT_FALSE(dm.GetAudioOutputDevice("_NOT A REAL DEVICE_", &device));
+  EXPECT_FALSE(dm->GetAudioInputDevice("_NOT A REAL DEVICE_", &device));
+  EXPECT_FALSE(dm->GetAudioOutputDevice("_NOT A REAL DEVICE_", &device));
 }
 
 // Test that we get the video capture device by name properly.
 TEST(DeviceManagerTest, GetVideoDeviceIds) {
-  cricket::DeviceManager dm;
+  scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
   Device device;
-  EXPECT_TRUE(dm.Init());
-  EXPECT_FALSE(dm.GetVideoCaptureDevice("_NOT A REAL DEVICE_", &device));
+  EXPECT_TRUE(dm->Init());
+  EXPECT_FALSE(dm->GetVideoCaptureDevice("_NOT A REAL DEVICE_", &device));
   std::vector<Device> video_ins;
-  EXPECT_TRUE(dm.GetVideoCaptureDevices(&video_ins));
+  EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
   if (!video_ins.empty()) {
     // Get the default device with the parameter kDefaultDeviceName.
-    EXPECT_TRUE(dm.GetVideoCaptureDevice(
+    EXPECT_TRUE(dm->GetVideoCaptureDevice(
         cricket::DeviceManagerInterface::kDefaultDeviceName, &device));
 
     // Get the first device with the parameter video_ins[0].name.
-    EXPECT_TRUE(dm.GetVideoCaptureDevice(video_ins[0].name, &device));
+    EXPECT_TRUE(dm->GetVideoCaptureDevice(video_ins[0].name, &device));
     EXPECT_EQ(device.name, video_ins[0].name);
     EXPECT_EQ(device.id, video_ins[0].id);
   }
@@ -148,15 +146,15 @@
 
 TEST(DeviceManagerTest, VerifyDevicesListsAreCleared) {
   const std::string imaginary("_NOT A REAL DEVICE_");
-  cricket::DeviceManager dm;
+  scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
   std::vector<Device> audio_ins, audio_outs, video_ins;
   audio_ins.push_back(Device(imaginary, imaginary));
   audio_outs.push_back(Device(imaginary, imaginary));
   video_ins.push_back(Device(imaginary, imaginary));
-  EXPECT_TRUE(dm.Init());
-  EXPECT_TRUE(dm.GetAudioInputDevices(&audio_ins));
-  EXPECT_TRUE(dm.GetAudioOutputDevices(&audio_outs));
-  EXPECT_TRUE(dm.GetVideoCaptureDevices(&video_ins));
+  EXPECT_TRUE(dm->Init());
+  EXPECT_TRUE(dm->GetAudioInputDevices(&audio_ins));
+  EXPECT_TRUE(dm->GetAudioOutputDevices(&audio_outs));
+  EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
   for (size_t i = 0; i < audio_ins.size(); ++i) {
     EXPECT_NE(imaginary, audio_ins[i].name);
   }
@@ -168,6 +166,57 @@
   }
 }
 
+static bool CompareDeviceList(std::vector<Device>& devices,
+    const char* const device_list[], int list_size) {
+  if (list_size != static_cast<int>(devices.size())) {
+    return false;
+  }
+  for (int i = 0; i < list_size; ++i) {
+    if (devices[i].name.compare(device_list[i]) != 0) {
+      return false;
+    }
+  }
+  return true;
+}
+
+TEST(DeviceManagerTest, VerifyFilterDevices) {
+  static const char* const kTotalDevicesName[] = {
+      "Google Camera Adapters are tons of fun.",
+      "device1",
+      "device2",
+      "device3",
+      "device4",
+      "device5",
+      "Google Camera Adapter 0",
+      "Google Camera Adapter 1",
+  };
+  static const char* const kFilteredDevicesName[] = {
+      "device2",
+      "device4",
+      "Google Camera Adapter",
+      NULL,
+  };
+  static const char* const kDevicesName[] = {
+      "device1",
+      "device3",
+      "device5",
+  };
+  std::vector<Device> devices;
+  for (int i = 0; i < ARRAY_SIZE(kTotalDevicesName); ++i) {
+    devices.push_back(Device(kTotalDevicesName[i], i));
+  }
+  EXPECT_TRUE(CompareDeviceList(devices, kTotalDevicesName,
+                                ARRAY_SIZE(kTotalDevicesName)));
+  // Return false if given NULL as the exclusion list.
+  EXPECT_TRUE(DeviceManager::FilterDevices(&devices, NULL));
+  // The devices should not change.
+  EXPECT_TRUE(CompareDeviceList(devices, kTotalDevicesName,
+                                ARRAY_SIZE(kTotalDevicesName)));
+  EXPECT_TRUE(DeviceManager::FilterDevices(&devices, kFilteredDevicesName));
+  EXPECT_TRUE(CompareDeviceList(devices, kDevicesName,
+                                ARRAY_SIZE(kDevicesName)));
+}
+
 #ifdef LINUX
 class FakeV4LLookup : public cricket::V4LLookup {
  public:
@@ -202,10 +251,10 @@
                                       "Video Device 2"));
   talk_base::FilesystemScope fs(new talk_base::FakeFileSystem(files));
 
-  cricket::DeviceManager dm;
+  scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
   std::vector<Device> video_ins;
-  EXPECT_TRUE(dm.Init());
-  EXPECT_TRUE(dm.GetVideoCaptureDevices(&video_ins));
+  EXPECT_TRUE(dm->Init());
+  EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
   EXPECT_EQ(2u, video_ins.size());
   EXPECT_EQ("Video Device 1", video_ins.at(0).name);
   EXPECT_EQ("Video Device 2", video_ins.at(1).name);
@@ -231,10 +280,10 @@
           "param1: value1\nname:   Video Device 2\n param2: value2\n"));
   talk_base::FilesystemScope fs(new talk_base::FakeFileSystem(files));
 
-  cricket::DeviceManager dm;
+  scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
   std::vector<Device> video_ins;
-  EXPECT_TRUE(dm.Init());
-  EXPECT_TRUE(dm.GetVideoCaptureDevices(&video_ins));
+  EXPECT_TRUE(dm->Init());
+  EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
   EXPECT_EQ(2u, video_ins.size());
   EXPECT_EQ("Video Device 1", video_ins.at(0).name);
   EXPECT_EQ("Video Device 2", video_ins.at(1).name);
@@ -252,10 +301,10 @@
   files.push_back(talk_base::FakeFileSystem::File("/dev/video5", ""));
   talk_base::FilesystemScope fs(new talk_base::FakeFileSystem(files));
 
-  cricket::DeviceManager dm;
+  scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
   std::vector<Device> video_ins;
-  EXPECT_TRUE(dm.Init());
-  EXPECT_TRUE(dm.GetVideoCaptureDevices(&video_ins));
+  EXPECT_TRUE(dm->Init());
+  EXPECT_TRUE(dm->GetVideoCaptureDevices(&video_ins));
   EXPECT_EQ(2u, video_ins.size());
   EXPECT_EQ("/dev/video0", video_ins.at(0).name);
   EXPECT_EQ("/dev/video5", video_ins.at(1).name);
diff --git a/talk/session/phone/linuxdevicemanager.cc b/talk/session/phone/linuxdevicemanager.cc
index 5ebf9e3..6bad677 100644
--- a/talk/session/phone/linuxdevicemanager.cc
+++ b/talk/session/phone/linuxdevicemanager.cc
@@ -83,7 +83,7 @@
     "surround50:",
     "surround51:",
     "surround71:",
-    "iec958:"       // S/PDIF
+    "iec958:",      // S/PDIF
 #endif
     NULL,
 };
diff --git a/talk/session/phone/mediamessages.cc b/talk/session/phone/mediamessages.cc
index 9031351..c40b03f 100644
--- a/talk/session/phone/mediamessages.cc
+++ b/talk/session/phone/mediamessages.cc
@@ -31,9 +31,12 @@
 
 #include "talk/session/phone/mediamessages.h"
 
+#include "talk/base/logging.h"
 #include "talk/base/stringencode.h"
 #include "talk/p2p/base/constants.h"
+#include "talk/p2p/base/parsing.h"
 #include "talk/session/phone/mediasessionclient.h"
+#include "talk/session/phone/streamparams.h"
 #include "talk/xmllite/xmlelement.h"
 
 namespace cricket {
@@ -96,19 +99,15 @@
 bool ParseNamedSource(const buzz::XmlElement* source_elem,
                       NamedSource* named_source,
                       ParseError* error) {
-  named_source->nick = source_elem->Attr(QN_JINGLE_DRAFT_SOURCE_NICK);
+  named_source->nick = source_elem->Attr(QN_NICK);
   if (named_source->nick.empty()) {
     return BadParse("Missing or invalid nick.", error);
   }
 
-  named_source->name = source_elem->Attr(QN_JINGLE_DRAFT_SOURCE_NAME);
-  named_source->usage = source_elem->Attr(QN_JINGLE_DRAFT_SOURCE_USAGE);
-  named_source->removed =
-      STR_JINGLE_DRAFT_SOURCE_STATE_REMOVED ==
-      source_elem->Attr(QN_JINGLE_DRAFT_SOURCE_STATE);
+  named_source->name = source_elem->Attr(QN_NAME);
 
   const buzz::XmlElement* ssrc_elem =
-      source_elem->FirstNamed(QN_JINGLE_DRAFT_SOURCE_SSRC);
+      source_elem->FirstNamed(QN_JINGLE_DRAFT_SSRC);
   if (ssrc_elem != NULL && !ssrc_elem->BodyText().empty()) {
     uint32 ssrc;
     if (!ParseSsrc(ssrc_elem->BodyText(), &ssrc)) {
@@ -126,8 +125,8 @@
                                  const std::string& type) {
   buzz::XmlElement* view_elem =
       new buzz::XmlElement(QN_JINGLE_DRAFT_VIEW, true);
-  view_elem->AddAttr(QN_JINGLE_DRAFT_CONTENT_NAME, name);
-  view_elem->SetAttr(QN_JINGLE_DRAFT_VIEW_TYPE, type);
+  view_elem->AddAttr(QN_NAME, name);
+  view_elem->SetAttr(QN_TYPE, type);
   return view_elem;
 }
 
@@ -144,16 +143,13 @@
                                             const StaticVideoView& view) {
   buzz::XmlElement* view_elem =
       CreateVideoViewElem(content_name, STR_JINGLE_DRAFT_VIEW_TYPE_STATIC);
-  AddXmlAttr(view_elem, QN_JINGLE_DRAFT_VIEW_SSRC, view.ssrc);
+  AddXmlAttr(view_elem, QN_SSRC, view.ssrc);
 
-  buzz::XmlElement* params_elem = new buzz::XmlElement(
-      QN_JINGLE_DRAFT_VIEW_PARAMS);
-  AddXmlAttr(params_elem, QN_JINGLE_DRAFT_VIEW_PARAMS_WIDTH, view.width);
-  AddXmlAttr(params_elem, QN_JINGLE_DRAFT_VIEW_PARAMS_HEIGHT, view.height);
-  AddXmlAttr(params_elem, QN_JINGLE_DRAFT_VIEW_PARAMS_FRAMERATE,
-             view.framerate);
-  AddXmlAttr(params_elem, QN_JINGLE_DRAFT_VIEW_PARAMS_PREFERENCE,
-             view.preference);
+  buzz::XmlElement* params_elem = new buzz::XmlElement(QN_JINGLE_DRAFT_PARAMS);
+  AddXmlAttr(params_elem, QN_WIDTH, view.width);
+  AddXmlAttr(params_elem, QN_HEIGHT, view.height);
+  AddXmlAttr(params_elem, QN_FRAMERATE, view.framerate);
+  AddXmlAttr(params_elem, QN_PREFERENCE, view.preference);
   view_elem->AddElement(params_elem);
 
   return view_elem;
@@ -200,10 +196,60 @@
   RemoveSourceBySsrc(ssrc, &video_);
 }
 
-bool WriteViewRequest(const std::string& content_name,
-                      const ViewRequest& request,
-                      XmlElements* elems,
-                      WriteError* error) {
+bool IsJingleViewRequest(const XmlElements& action_elems) {
+  return GetXmlElement(action_elems, QN_JINGLE_DRAFT_VIEW) != NULL;
+}
+
+bool ParseStaticVideoView(const buzz::XmlElement* view_elem,
+                          StaticVideoView* view,
+                          ParseError* error) {
+  if (!ParseSsrc(view_elem->Attr(QN_SSRC), &(view->ssrc))) {
+    return BadParse("Invalid or missing view ssrc.", error);
+  }
+
+  const buzz::XmlElement* params_elem =
+      view_elem->FirstNamed(QN_JINGLE_DRAFT_PARAMS);
+  if (params_elem) {
+    view->width = GetXmlAttr(params_elem, QN_WIDTH, 0);
+    view->height = GetXmlAttr(params_elem, QN_HEIGHT, 0);
+    view->framerate = GetXmlAttr(params_elem, QN_FRAMERATE, 0);
+    view->preference = GetXmlAttr(params_elem, QN_PREFERENCE, 0);
+  } else {
+    return BadParse("Missing view params.", error);
+  }
+
+  return true;
+}
+
+bool ParseJingleViewRequest(const XmlElements& action_elems,
+                            ViewRequest* view_request,
+                            ParseError* error) {
+  for (XmlElements::const_iterator iter = action_elems.begin();
+       iter != action_elems.end(); ++iter) {
+    const buzz::XmlElement* view_elem = *iter;
+    if (view_elem->Name() == QN_JINGLE_DRAFT_VIEW) {
+      std::string type = view_elem->Attr(QN_TYPE);
+      if (STR_JINGLE_DRAFT_VIEW_TYPE_NONE == type) {
+        view_request->static_video_views.clear();
+        return true;
+      } else if (STR_JINGLE_DRAFT_VIEW_TYPE_STATIC == type) {
+        StaticVideoView static_video_view(0, 0, 0, 0);
+        if (!ParseStaticVideoView(view_elem, &static_video_view, error)) {
+          return false;
+        }
+        view_request->static_video_views.push_back(static_video_view);
+      } else {
+        LOG(LS_INFO) << "Ingnoring unknown view type: " << type;
+      }
+    }
+  }
+  return true;
+}
+
+bool WriteJingleViewRequest(const std::string& content_name,
+                            const ViewRequest& request,
+                            XmlElements* elems,
+                            WriteError* error) {
   if (request.static_video_views.empty()) {
     elems->push_back(CreateNoneVideoViewElem(content_name));
   } else {
@@ -217,7 +263,7 @@
 }
 
 bool IsSourcesNotify(const buzz::XmlElement* action_elem) {
-  return action_elem->FirstNamed(QN_JINGLE_DRAFT_NOTIFY) != NULL;
+  return action_elem->FirstNamed(QN_JINGLE_LEGACY_NOTIFY) != NULL;
 }
 
 bool ParseSourcesNotify(const buzz::XmlElement* action_elem,
@@ -225,14 +271,14 @@
                         MediaSources* sources,
                         ParseError* error) {
   for (const buzz::XmlElement* notify_elem =
-           action_elem->FirstNamed(QN_JINGLE_DRAFT_NOTIFY);
+           action_elem->FirstNamed(QN_JINGLE_LEGACY_NOTIFY);
        notify_elem != NULL;
-       notify_elem = notify_elem->NextNamed(QN_JINGLE_DRAFT_NOTIFY)) {
-    std::string content_name = notify_elem->Attr(QN_JINGLE_DRAFT_CONTENT_NAME);
+       notify_elem = notify_elem->NextNamed(QN_JINGLE_LEGACY_NOTIFY)) {
+    std::string content_name = notify_elem->Attr(QN_NAME);
     for (const buzz::XmlElement* source_elem =
-             notify_elem->FirstNamed(QN_JINGLE_DRAFT_SOURCE);
+             notify_elem->FirstNamed(QN_JINGLE_LEGACY_SOURCE);
          source_elem != NULL;
-         source_elem = source_elem->NextNamed(QN_JINGLE_DRAFT_SOURCE)) {
+         source_elem = source_elem->NextNamed(QN_JINGLE_LEGACY_SOURCE)) {
       NamedSource named_source;
       if (!ParseNamedSource(source_elem, &named_source, error)) {
         return false;
@@ -258,4 +304,150 @@
   return true;
 }
 
+bool ParseSsrcAsLegacyStream(const buzz::XmlElement* desc_elem,
+                             std::vector<StreamParams>* streams,
+                             ParseError* error) {
+  const std::string ssrc_str = desc_elem->Attr(QN_SSRC);
+  if (!ssrc_str.empty()) {
+    uint32 ssrc;
+    if (!ParseSsrc(ssrc_str, &ssrc)) {
+      return BadParse("Missing or invalid ssrc.", error);
+    }
+
+    streams->push_back(StreamParams::CreateLegacy(ssrc));
+  }
+  return true;
+}
+
+bool ParseSsrcs(const buzz::XmlElement* parent_elem,
+                std::vector<uint32>* ssrcs,
+                ParseError* error) {
+  for (const buzz::XmlElement* ssrc_elem =
+           parent_elem->FirstNamed(QN_JINGLE_DRAFT_SSRC);
+       ssrc_elem != NULL;
+       ssrc_elem = ssrc_elem->NextNamed(QN_JINGLE_DRAFT_SSRC)) {
+    uint32 ssrc;
+    if (!ParseSsrc(ssrc_elem->BodyText(), &ssrc)) {
+      return BadParse("Missing or invalid ssrc.", error);
+    }
+
+    ssrcs->push_back(ssrc);
+  }
+  return true;
+}
+
+bool ParseSsrcGroups(const buzz::XmlElement* parent_elem,
+                     std::vector<SsrcGroup>* ssrc_groups,
+                     ParseError* error) {
+  for (const buzz::XmlElement* group_elem =
+           parent_elem->FirstNamed(QN_JINGLE_DRAFT_SSRC_GROUP);
+       group_elem != NULL;
+       group_elem = group_elem->NextNamed(QN_JINGLE_DRAFT_SSRC_GROUP)) {
+    std::string semantics = group_elem->Attr(QN_SEMANTICS);
+    std::vector<uint32> ssrcs;
+    if (!ParseSsrcs(group_elem, &ssrcs, error)) {
+      return false;
+    }
+    ssrc_groups->push_back(SsrcGroup(semantics, ssrcs));
+  }
+  return true;
+}
+
+bool ParseJingleStream(const buzz::XmlElement* stream_elem,
+                       std::vector<StreamParams>* streams,
+                       ParseError* error) {
+  StreamParams stream;
+  stream.nick = stream_elem->Attr(QN_NICK);
+  stream.name = stream_elem->Attr(QN_NAME);
+  stream.type = stream_elem->Attr(QN_TYPE);
+  stream.display = stream_elem->Attr(QN_DISPLAY);
+  stream.cname = stream_elem->Attr(QN_CNAME);
+  if (!ParseSsrcs(stream_elem, &(stream.ssrcs), error)) {
+    return false;
+  }
+  std::vector<SsrcGroup> ssrc_groups;
+  if (!ParseSsrcGroups(stream_elem, &(stream.ssrc_groups), error)) {
+    return false;
+  }
+  streams->push_back(stream);
+  return true;
+}
+
+bool HasJingleStreams(const buzz::XmlElement* desc_elem) {
+  const buzz::XmlElement* streams_elem =
+      desc_elem->FirstNamed(QN_JINGLE_DRAFT_STREAMS);
+  return (streams_elem != NULL);
+}
+
+bool ParseJingleStreams(const buzz::XmlElement* desc_elem,
+                        std::vector<StreamParams>* streams,
+                        ParseError* error) {
+  const buzz::XmlElement* streams_elem =
+      desc_elem->FirstNamed(QN_JINGLE_DRAFT_STREAMS);
+  if (streams_elem == NULL) {
+    return BadParse("Missing streams element.", error);
+  }
+  for (const buzz::XmlElement* stream_elem =
+           streams_elem->FirstNamed(QN_JINGLE_DRAFT_STREAM);
+       stream_elem != NULL;
+       stream_elem = stream_elem->NextNamed(QN_JINGLE_DRAFT_STREAM)) {
+    if (!ParseJingleStream(stream_elem, streams, error)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void WriteSsrcs(const std::vector<uint32>& ssrcs,
+                buzz::XmlElement* parent_elem) {
+  for (std::vector<uint32>::const_iterator ssrc = ssrcs.begin();
+       ssrc != ssrcs.end(); ++ssrc) {
+    buzz::XmlElement* ssrc_elem =
+        new buzz::XmlElement(QN_JINGLE_DRAFT_SSRC, false);
+    SetXmlBody(ssrc_elem, *ssrc);
+
+    parent_elem->AddElement(ssrc_elem);
+  }
+}
+
+void WriteSsrcGroups(const std::vector<SsrcGroup>& groups,
+                     buzz::XmlElement* parent_elem) {
+  for (std::vector<SsrcGroup>::const_iterator group = groups.begin();
+       group != groups.end(); ++group) {
+    buzz::XmlElement* group_elem =
+        new buzz::XmlElement(QN_JINGLE_DRAFT_SSRC_GROUP, false);
+    AddXmlAttrIfNonEmpty(group_elem, QN_SEMANTICS, group->semantics);
+    WriteSsrcs(group->ssrcs, group_elem);
+
+    parent_elem->AddElement(group_elem);
+  }
+}
+
+void WriteJingleStream(const StreamParams& stream,
+                       buzz::XmlElement* parent_elem) {
+  buzz::XmlElement* stream_elem =
+      new buzz::XmlElement(QN_JINGLE_DRAFT_STREAM, false);
+  AddXmlAttrIfNonEmpty(stream_elem, QN_NICK, stream.nick);
+  AddXmlAttrIfNonEmpty(stream_elem, QN_NAME, stream.name);
+  AddXmlAttrIfNonEmpty(stream_elem, QN_TYPE, stream.type);
+  AddXmlAttrIfNonEmpty(stream_elem, QN_DISPLAY, stream.display);
+  AddXmlAttrIfNonEmpty(stream_elem, QN_CNAME, stream.cname);
+  WriteSsrcs(stream.ssrcs, stream_elem);
+  WriteSsrcGroups(stream.ssrc_groups, stream_elem);
+
+  parent_elem->AddElement(stream_elem);
+}
+
+void WriteJingleStreams(const std::vector<StreamParams>& streams,
+                        buzz::XmlElement* parent_elem) {
+  buzz::XmlElement* streams_elem =
+      new buzz::XmlElement(QN_JINGLE_DRAFT_STREAMS, true);
+  for (std::vector<StreamParams>::const_iterator stream = streams.begin();
+       stream != streams.end(); ++stream) {
+    WriteJingleStream(*stream, streams_elem);
+  }
+
+  parent_elem->AddElement(streams_elem);
+}
+
 }  // namespace cricket
diff --git a/talk/session/phone/mediamessages.h b/talk/session/phone/mediamessages.h
index 541572f..11b9e89 100644
--- a/talk/session/phone/mediamessages.h
+++ b/talk/session/phone/mediamessages.h
@@ -45,6 +45,8 @@
 
 namespace cricket {
 
+struct StreamParams;
+
 // In a <notify> message, there are number of sources with names.
 // This represents one such named source.
 struct NamedSource {
@@ -57,7 +59,6 @@
 
   std::string nick;
   std::string name;
-  std::string usage;
   uint32 ssrc;
   bool ssrc_set;
   bool removed;
@@ -123,18 +124,29 @@
 
 typedef std::vector<StaticVideoView> StaticVideoViews;
 
-// Represents a whole <view> message, which contains many views.
+// Represents a whole view request message, which contains many views.
 struct ViewRequest {
   StaticVideoViews static_video_views;
 };
 
+// If the elems of a parent (usually <jingle>) constitute a view request.
+bool IsJingleViewRequest(const XmlElements& elems);
+
+// Parses a view request from jingle contents (<view>s).  If it
+// fails, returns false and fills an error message.
+bool ParseJingleViewRequest(const XmlElements& elems,
+                            ViewRequest* view_request,
+                            ParseError* error);
+
 // Serializes a view request to XML.  If it fails, returns false and
 // fills in an error message.
-bool WriteViewRequest(const std::string& content_name,
-                      const ViewRequest& view,
-                      XmlElements* elems,
-                      WriteError* error);
+bool WriteJingleViewRequest(const std::string& content_name,
+                            const ViewRequest& view,
+                            XmlElements* elems,
+                            WriteError* error);
 
+// TODO: Get rid of legacy source notify and replace with
+// description-info as soon as reflector is capable of sending it.
 bool IsSourcesNotify(const buzz::XmlElement* action_elem);
 
 // Parses a notify message from XML.  If it fails, returns false and
@@ -145,6 +157,19 @@
                         MediaSources* sources,
                         ParseError* error);
 
+// If the given elem has <streams>.
+bool HasJingleStreams(const buzz::XmlElement* desc_elem);
+
+// Parses streams from a jingle <description>.  If it fails, returns
+// false and fills an error message.
+bool ParseJingleStreams(const buzz::XmlElement* desc_elem,
+                        std::vector<StreamParams>* streams,
+                        ParseError* error);
+
+// Write a <streams> element to the parent_elem.
+void WriteJingleStreams(const std::vector<StreamParams>& streams,
+                        buzz::XmlElement* parent_elem);
+
 }  // namespace cricket
 
 #endif  // TALK_SESSION_PHONE_MEDIAMESSAGES_H_
diff --git a/talk/session/phone/mediamessages_unittest.cc b/talk/session/phone/mediamessages_unittest.cc
index e5ae12f..0290c02 100644
--- a/talk/session/phone/mediamessages_unittest.cc
+++ b/talk/session/phone/mediamessages_unittest.cc
@@ -81,7 +81,6 @@
   static std::string NotifyAddXml(const std::string& content_name,
                                   const std::string& nick,
                                   const std::string& name,
-                                  const std::string& usage,
                                   const std::string& ssrc) {
     return "<notify xmlns='google:jingle'"
            "  name='" + content_name + "'"
@@ -89,7 +88,6 @@
            "  <source"
            "    nick='" + nick + "'"
            "    name='" + name + "'"
-           "    usage='" + usage + "'"
            "  >"
            "    <ssrc>" + ssrc + "</ssrc>"
            "  </source>"
@@ -129,19 +127,56 @@
            "</notify>";
   }
 
-  static std::string NotifyExplicitRemoveXml(const std::string& content_name,
-                                             const std::string& nick,
-                                             const std::string& ssrc) {
-    return "<notify xmlns='google:jingle'"
-           "  name='" + content_name + "'"
+  static cricket::StreamParams CreateStream(const std::string& nick,
+                                            const std::string& name,
+                                            uint32 ssrc1,
+                                            uint32 ssrc2,
+                                            const std::string& semantics,
+                                            const std::string& type,
+                                            const std::string& display) {
+    StreamParams stream;
+    stream.nick = nick;
+    stream.name = name;
+    stream.ssrcs.push_back(ssrc1);
+    stream.ssrcs.push_back(ssrc2);
+    stream.ssrc_groups.push_back(
+        cricket::SsrcGroup(semantics, stream.ssrcs));
+    stream.type = type;
+    stream.display = display;
+    return stream;
+  }
+
+  static std::string StreamsXml(const std::string& stream1,
+                               const std::string& stream2) {
+    return "<streams xmlns='google:jingle'>"
+           + stream1
+           + stream2 +
+           "</streams>";
+  }
+
+
+  static std::string StreamXml(const std::string& nick,
+                               const std::string& name,
+                               const std::string& ssrc1,
+                               const std::string& ssrc2,
+                               const std::string& semantics,
+                               const std::string& type,
+                               const std::string& display) {
+    return "<stream"
+           " nick='" + nick + "'"
+           " name='" + name + "'"
+           " type='" + type + "'"
+           " display='" + display + "'"
            ">"
-           "  <source"
-           "    nick='" + nick + "'"
-           "    state='removed'"
-           "  >"
-           "    <ssrc>" + ssrc + "</ssrc>"
-           "  </source>"
-           "</notify>";
+           "<ssrc>" + ssrc1 + "</ssrc>"
+           "<ssrc>" + ssrc2 + "</ssrc>"
+           "<ssrc-group"
+           "  semantics='" + semantics + "'"
+           ">"
+           "<ssrc>" + ssrc1 + "</ssrc>"
+           "<ssrc>" + ssrc2 + "</ssrc>"
+           "</ssrc-group>"
+           "</stream>";
   }
 
   static cricket::SessionDescription* CreateMediaSessionDescription(
@@ -161,7 +196,7 @@
 }  // anonymous namespace
 
 // Test serializing/deserializing an empty <view> message.
-TEST_F(MediaMessagesTest, ViewNoneToXml) {
+TEST_F(MediaMessagesTest, ViewNoneToFromXml) {
   talk_base::scoped_ptr<buzz::XmlElement> expected_view_elem(
       buzz::XmlElement::ForStr(kViewVideoNoneXml));
 
@@ -169,15 +204,22 @@
   cricket::XmlElements actual_view_elems;
   cricket::WriteError error;
 
-  ASSERT_TRUE(cricket::WriteViewRequest(
+  EXPECT_FALSE(cricket::IsJingleViewRequest(actual_view_elems));
+  ASSERT_TRUE(cricket::WriteJingleViewRequest(
       "video1", view_request, &actual_view_elems, &error));
 
   ASSERT_EQ(1U, actual_view_elems.size());
   EXPECT_EQ(expected_view_elem->Str(), actual_view_elems[0]->Str());
+
+  cricket::ParseError parse_error;
+  EXPECT_TRUE(cricket::IsJingleViewRequest(actual_view_elems));
+  ASSERT_TRUE(cricket::ParseJingleViewRequest(
+      actual_view_elems, &view_request, &parse_error));
+  EXPECT_EQ(0U, view_request.static_video_views.size());
 }
 
 // Test serializing/deserializing an a simple vga <view> message.
-TEST_F(MediaMessagesTest, ViewVgaToXml) {
+TEST_F(MediaMessagesTest, ViewVgaToFromXml) {
   talk_base::scoped_ptr<buzz::XmlElement> expected_view_elem1(
       buzz::XmlElement::ForStr(ViewVideoStaticVgaXml("1234")));
   talk_base::scoped_ptr<buzz::XmlElement> expected_view_elem2(
@@ -192,12 +234,37 @@
   view_request.static_video_views.push_back(
       cricket::StaticVideoView(2468, 640, 480, 30));
 
-  ASSERT_TRUE(cricket::WriteViewRequest(
+  ASSERT_TRUE(cricket::WriteJingleViewRequest(
       "video1", view_request, &actual_view_elems, &error));
 
   ASSERT_EQ(2U, actual_view_elems.size());
   EXPECT_EQ(expected_view_elem1->Str(), actual_view_elems[0]->Str());
   EXPECT_EQ(expected_view_elem2->Str(), actual_view_elems[1]->Str());
+
+  view_request.static_video_views.clear();
+  cricket::ParseError parse_error;
+  EXPECT_TRUE(cricket::IsJingleViewRequest(actual_view_elems));
+  ASSERT_TRUE(cricket::ParseJingleViewRequest(
+      actual_view_elems, &view_request, &parse_error));
+  EXPECT_EQ(2U, view_request.static_video_views.size());
+  EXPECT_EQ(1234U, view_request.static_video_views[0].ssrc);
+  EXPECT_EQ(640, view_request.static_video_views[0].width);
+  EXPECT_EQ(480, view_request.static_video_views[0].height);
+  EXPECT_EQ(30, view_request.static_video_views[0].framerate);
+  EXPECT_EQ(2468U, view_request.static_video_views[1].ssrc);
+}
+
+// Test deserializing bad view XML.
+TEST_F(MediaMessagesTest, ParseBadViewXml) {
+  talk_base::scoped_ptr<buzz::XmlElement> view_elem(
+      buzz::XmlElement::ForStr(ViewVideoStaticVgaXml("not-an-ssrc")));
+  XmlElements view_elems;
+  view_elems.push_back(view_elem.get());
+
+  cricket::ViewRequest view_request;
+  cricket::ParseError parse_error;
+  ASSERT_FALSE(cricket::ParseJingleViewRequest(
+      view_elems, &view_request, &parse_error));
 }
 
 // Test serializing/deserializing an empty session-info message.
@@ -232,22 +299,19 @@
       new buzz::XmlElement(cricket::QN_JINGLE));
   action_elem->AddElement(
       buzz::XmlElement::ForStr(NotifyAddXml(
-          "video1", "Joe", "Facetime", "", "1234")));
+          "video1", "Joe", "Facetime", "1234")));
   action_elem->AddElement(
       buzz::XmlElement::ForStr(NotifyAddXml(
-          "video1", "Bob", "Microsoft Word", "screencast", "2468")));
+          "video1", "Bob", "Microsoft Word", "2468")));
   action_elem->AddElement(
       buzz::XmlElement::ForStr(NotifyAddXml(
-          "video1", "Bob", "", "", "3692")));
+          "video1", "Bob", "", "3692")));
   action_elem->AddElement(
       buzz::XmlElement::ForStr(NotifyImplicitRemoveXml(
           "audio1", "Joe")));
   action_elem->AddElement(
-      buzz::XmlElement::ForStr(NotifyExplicitRemoveXml(
-          "audio1", "Joe", "1234")));
-  action_elem->AddElement(
       buzz::XmlElement::ForStr(NotifyAddXml(
-          "audio1", "Bob", "", "", "3692")));
+          "audio1", "Bob", "", "3692")));
   action_elem->AddElement(
       buzz::XmlElement::ForStr(NotifyTwoSourceXml(
           "video1", "Joe", "1234", "Bob", "2468")));
@@ -261,18 +325,16 @@
                                           &sources, &error));
 
   ASSERT_EQ(5U, sources.video().size());
-  ASSERT_EQ(3U, sources.audio().size());
+  ASSERT_EQ(2U, sources.audio().size());
 
   EXPECT_EQ("Joe", sources.video()[0].nick);
   EXPECT_EQ("Facetime", sources.video()[0].name);
-  EXPECT_EQ("", sources.video()[0].usage);
   EXPECT_EQ(1234U, sources.video()[0].ssrc);
   EXPECT_TRUE(sources.video()[0].ssrc_set);
   EXPECT_FALSE(sources.video()[0].removed);
 
   EXPECT_EQ("Bob", sources.video()[1].nick);
   EXPECT_EQ("Microsoft Word", sources.video()[1].name);
-  EXPECT_EQ("screencast", sources.video()[1].usage);
   EXPECT_EQ(2468U, sources.video()[1].ssrc);
   EXPECT_TRUE(sources.video()[1].ssrc_set);
   EXPECT_FALSE(sources.video()[0].removed);
@@ -281,7 +343,6 @@
   EXPECT_EQ(3692U, sources.video()[2].ssrc);
   EXPECT_TRUE(sources.video()[2].ssrc_set);
   EXPECT_EQ("", sources.video()[2].name);
-  EXPECT_EQ("", sources.video()[2].usage);
   EXPECT_FALSE(sources.video()[0].removed);
 
   EXPECT_EQ("Joe", sources.video()[3].nick);
@@ -293,16 +354,6 @@
   EXPECT_EQ("Joe", sources.audio()[0].nick);
   EXPECT_FALSE(sources.audio()[0].ssrc_set);
   EXPECT_FALSE(sources.video()[0].removed);
-
-  EXPECT_EQ("Joe", sources.audio()[1].nick);
-  EXPECT_TRUE(sources.audio()[1].ssrc_set);
-  EXPECT_EQ(1234U, sources.audio()[1].ssrc);
-  EXPECT_TRUE(sources.audio()[1].removed);
-
-  EXPECT_EQ("Bob", sources.audio()[2].nick);
-  EXPECT_EQ(3692U, sources.audio()[2].ssrc);
-  EXPECT_TRUE(sources.audio()[2].ssrc_set);
-  EXPECT_FALSE(sources.audio()[2].removed);
 }
 
 // Test serializing/deserializing a malformed <notify> message.
@@ -314,7 +365,7 @@
   talk_base::scoped_ptr<buzz::XmlElement> action_elem(
       new buzz::XmlElement(cricket::QN_JINGLE));
   action_elem->AddElement(
-      buzz::XmlElement::ForStr(NotifyAddXml("video1", "Joe", "", "", "XYZ")));
+      buzz::XmlElement::ForStr(NotifyAddXml("video1", "Joe", "", "XYZ")));
   EXPECT_TRUE(cricket::IsSourcesNotify(action_elem.get()));
   EXPECT_FALSE(cricket::ParseSourcesNotify(
       action_elem.get(), remote_description_.get(), &sources, &error));
@@ -322,10 +373,69 @@
   // Bad nick
   action_elem.reset(new buzz::XmlElement(cricket::QN_JINGLE));
   action_elem->AddElement(
-      buzz::XmlElement::ForStr(NotifyAddXml("video1", "", "", "", "1234")));
+      buzz::XmlElement::ForStr(NotifyAddXml("video1", "", "", "1234")));
   EXPECT_TRUE(cricket::IsSourcesNotify(action_elem.get()));
   EXPECT_FALSE(cricket::ParseSourcesNotify(
       action_elem.get(), remote_description_.get(), &sources, &error));
 }
 
+// Test serializing/deserializing typical streams xml.
+TEST_F(MediaMessagesTest, StreamsToFromXml) {
+  talk_base::scoped_ptr<buzz::XmlElement> expected_streams_elem(
+      buzz::XmlElement::ForStr(
+          StreamsXml(
+              StreamXml("nick1", "name1", "101", "102",
+                        "semantics1", "type1", "display1"),
+              StreamXml("nick2", "name2", "201", "202",
+                        "semantics2", "type2", "display2"))));
+
+  std::vector<cricket::StreamParams> expected_streams;
+  expected_streams.push_back(CreateStream("nick1", "name1", 101U, 102U,
+                                          "semantics1", "type1", "display1"));
+  expected_streams.push_back(CreateStream("nick2", "name2", 201U, 202U,
+                                          "semantics2", "type2", "display2"));
+
+  talk_base::scoped_ptr<buzz::XmlElement> actual_desc_elem(
+      new buzz::XmlElement(QN_JINGLE_RTP_CONTENT));
+  cricket::WriteJingleStreams(expected_streams, actual_desc_elem.get());
+
+  const buzz::XmlElement* actual_streams_elem =
+      actual_desc_elem->FirstNamed(QN_JINGLE_DRAFT_STREAMS);
+  ASSERT_TRUE(actual_streams_elem != NULL);
+  EXPECT_EQ(expected_streams_elem->Str(), actual_streams_elem->Str());
+
+  talk_base::scoped_ptr<buzz::XmlElement> expected_desc_elem(
+      new buzz::XmlElement(QN_JINGLE_RTP_CONTENT));
+  expected_desc_elem->AddElement(new buzz::XmlElement(
+      *expected_streams_elem));
+  std::vector<cricket::StreamParams> actual_streams;
+  cricket::ParseError parse_error;
+
+  EXPECT_TRUE(cricket::HasJingleStreams(expected_desc_elem.get()));
+  ASSERT_TRUE(cricket::ParseJingleStreams(
+      expected_desc_elem.get(), &actual_streams, &parse_error));
+  EXPECT_EQ(2U, actual_streams.size());
+  EXPECT_EQ(expected_streams[0], actual_streams[0]);
+  EXPECT_EQ(expected_streams[1], actual_streams[1]);
+}
+
+// Test deserializing bad streams xml.
+TEST_F(MediaMessagesTest, StreamsFromBadXml) {
+  talk_base::scoped_ptr<buzz::XmlElement> streams_elem(
+      buzz::XmlElement::ForStr(
+          StreamsXml(
+              StreamXml("nick1", "name1", "101", "not-an-ssrc",
+                        "semantics1", "type1", "display1"),
+              StreamXml("nick2", "name2", "202", "not-an-ssrc",
+                        "semantics2", "type2", "display2"))));
+  talk_base::scoped_ptr<buzz::XmlElement> desc_elem(
+      new buzz::XmlElement(QN_JINGLE_RTP_CONTENT));
+  desc_elem->AddElement(new buzz::XmlElement(*streams_elem));
+
+  std::vector<cricket::StreamParams> actual_streams;
+  cricket::ParseError parse_error;
+  ASSERT_FALSE(cricket::ParseJingleStreams(
+      desc_elem.get(), &actual_streams, &parse_error));
+}
+
 }  // namespace cricket
diff --git a/talk/session/phone/mediasession.cc b/talk/session/phone/mediasession.cc
index 9bb83e6..05875b5 100644
--- a/talk/session/phone/mediasession.cc
+++ b/talk/session/phone/mediasession.cc
@@ -233,8 +233,12 @@
       }
       uint32 ssrc = GenerateSsrc(*current_params);
       // TODO: Generate the more complex types of stream_params.
-      StreamParams stream_param(stream_it->name, ssrc, cname,
-                                stream_it->sync_label);
+
+      StreamParams stream_param;
+      stream_param.name = stream_it->name;
+      stream_param.ssrcs.push_back(ssrc);
+      stream_param.cname = cname;
+      stream_param.sync_label = stream_it->sync_label;
       content_description->AddStream(stream_param);
 
       // Store the new StreamParams in current_params.
@@ -303,8 +307,8 @@
     }
 
     if (options.streams.empty()) {
-      // TODO: Remove this legacy ssrc when all apps use StreamParams.
-      audio->set_ssrc(talk_base::CreateRandomNonZeroId());
+      // TODO: Remove this legacy stream when all apps use StreamParams.
+      audio->AddLegacyStream(talk_base::CreateRandomNonZeroId());
     }
     audio->set_rtcp_mux(true);
     audio->set_lang(lang_);
@@ -355,8 +359,8 @@
     }
 
     if (options.streams.empty()) {
-      // TODO: Remove this legacy ssrc when all apps use StreamParams.
-      video->set_ssrc(talk_base::CreateRandomNonZeroId());
+      // TODO: Remove this legacy stream when all apps use StreamParams.
+      video->AddLegacyStream(talk_base::CreateRandomNonZeroId());
     }
     video->set_bandwidth(options.video_bandwidth);
     video->set_rtcp_mux(true);
@@ -429,8 +433,8 @@
     }
 
     if (options.streams.empty()) {
-      // TODO: Remove this legacy ssrc when all apps use StreamParams.
-      audio_accept->set_ssrc(talk_base::CreateRandomNonZeroId());
+      // TODO: Remove this legacy stream when all apps use StreamParams.
+      audio_accept->AddLegacyStream(talk_base::CreateRandomNonZeroId());
     }
     audio_accept->set_rtcp_mux(audio_offer->rtcp_mux());
 
@@ -493,8 +497,8 @@
     }
 
     if (options.streams.empty()) {
-      // TODO: Remove this legacy ssrc when all apps use StreamParams.
-      video_accept->set_ssrc(talk_base::CreateRandomNonZeroId());
+      // TODO: Remove this legacy stream when all apps use StreamParams.
+      video_accept->AddLegacyStream(talk_base::CreateRandomNonZeroId());
     }
     video_accept->set_bandwidth(options.video_bandwidth);
     video_accept->set_rtcp_mux(video_offer->rtcp_mux());
@@ -579,5 +583,3 @@
 }
 
 }  // namespace cricket
-
-
diff --git a/talk/session/phone/mediasession.h b/talk/session/phone/mediasession.h
index ea4acd7..127a7ed 100644
--- a/talk/session/phone/mediasession.h
+++ b/talk/session/phone/mediasession.h
@@ -114,23 +114,15 @@
 class MediaContentDescription : public ContentDescription {
  public:
   MediaContentDescription()
-      : ssrc_(0),
-        ssrc_set_(false),
-        rtcp_mux_(false),
+      : rtcp_mux_(false),
         bandwidth_(kAutoBandwidth),
         crypto_required_(false),
-        rtp_header_extensions_set_(false) {
+        rtp_header_extensions_set_(false),
+        multistream_(false) {
   }
 
   virtual MediaType type() const = 0;
 
-  uint32 ssrc() const { return ssrc_; }
-  bool ssrc_set() const { return ssrc_set_; }
-  void set_ssrc(uint32 ssrc) {
-    ssrc_ = ssrc;
-    ssrc_set_ = true;
-  }
-
   bool rtcp_mux() const { return rtcp_mux_; }
   void set_rtcp_mux(bool mux) { rtcp_mux_ = mux; }
 
@@ -165,22 +157,46 @@
   bool rtp_header_extensions_set() const {
     return rtp_header_extensions_set_;
   }
+  // True iff the client supports multiple streams.
+  void set_multistream(bool multistream) { multistream_ = multistream; }
+  bool multistream() const { return multistream_;  }
   const StreamParamsVec& streams() const {
     return streams_;
   }
+  // TODO: Remove this by giving mediamessage.cc access
+  // to MediaContentDescription
+  StreamParamsVec& mutable_streams() {
+    return streams_;
+  }
   void AddStream(const StreamParams& stream) {
     streams_.push_back(stream);
   }
+  // Legacy streams have an ssrc, but nothing else.
+  void AddLegacyStream(uint32 ssrc) {
+    streams_.push_back(StreamParams::CreateLegacy(ssrc));
+  }
+
+  uint32 first_ssrc() const {
+    if (streams_.empty()) {
+      return 0;
+    }
+    return streams_[0].first_ssrc();
+  }
+  bool has_ssrcs() const {
+    if (streams_.empty()) {
+      return false;
+    }
+    return streams_[0].has_ssrcs();
+  }
 
  protected:
-  uint32 ssrc_;
-  bool ssrc_set_;
   bool rtcp_mux_;
   int bandwidth_;
   std::vector<CryptoParams> cryptos_;
   bool crypto_required_;
   std::vector<RtpHeaderExtension> rtp_header_extensions_;
   bool rtp_header_extensions_set_;
+  bool multistream_;
   StreamParamsVec streams_;
 };
 
@@ -285,5 +301,3 @@
 }  // namespace cricket
 
 #endif  // TALK_SESSION_PHONE_MEDIASESSION_H_
-
-
diff --git a/talk/session/phone/mediasession_unittest.cc b/talk/session/phone/mediasession_unittest.cc
index 8b083a3..36fedc6 100644
--- a/talk/session/phone/mediasession_unittest.cc
+++ b/talk/session/phone/mediasession_unittest.cc
@@ -137,10 +137,13 @@
     ssrc_groups.push_back(fec_group2);
     ssrc_groups.push_back(fec_group3);
 
-    StreamParams simulcast_params(kVideoTrack1,
-                                  MAKE_VECTOR(kSimulcastParamsSsrc),
-                                  ssrc_groups, "Video_SIM_FEC",
-                                  kMediaStream1);
+    StreamParams simulcast_params;
+    simulcast_params.name = kVideoTrack1;
+    simulcast_params.ssrcs = MAKE_VECTOR(kSimulcastParamsSsrc);
+    simulcast_params.ssrc_groups = ssrc_groups;
+    simulcast_params.cname = "Video_SIM_FEC";
+    simulcast_params.sync_label = kMediaStream1;
+
     StreamParamsVec video_streams;
     video_streams.push_back(simulcast_params);
 
@@ -178,7 +181,7 @@
       static_cast<const AudioContentDescription*>(ac->description);
   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
   EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
-  EXPECT_NE(0U, acd->ssrc());                   // a random nonzero ssrc
+  EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
   ASSERT_CRYPTO(acd, false, 2U, CS_AES_CM_128_HMAC_SHA1_32);
@@ -204,13 +207,13 @@
       static_cast<const VideoContentDescription*>(vc->description);
   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
   EXPECT_EQ(f1_.audio_codecs(), acd->codecs());
-  EXPECT_NE(0U, acd->ssrc());                   // a random nonzero ssrc
+  EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
   ASSERT_CRYPTO(acd, false, 2U, CS_AES_CM_128_HMAC_SHA1_32);
   EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
   EXPECT_EQ(f1_.video_codecs(), vcd->codecs());
-  EXPECT_NE(0U, vcd->ssrc());                   // a random nonzero ssrc
+  EXPECT_NE(0U, vcd->first_ssrc());             // a random nonzero ssrc
   EXPECT_EQ(kAutoBandwidth, vcd->bandwidth());  // default bandwidth (auto)
   EXPECT_TRUE(vcd->rtcp_mux());                 // rtcp-mux defaults on
   ASSERT_CRYPTO(vcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
@@ -234,7 +237,7 @@
       static_cast<const AudioContentDescription*>(ac->description);
   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
   EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
-  EXPECT_NE(0U, acd->ssrc());                   // a random nonzero ssrc
+  EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // negotiated auto bw
   EXPECT_TRUE(acd->rtcp_mux());                 // negotiated rtcp-mux
   ASSERT_CRYPTO(acd, false, 1U, CS_AES_CM_128_HMAC_SHA1_32);
@@ -263,12 +266,12 @@
   EXPECT_EQ(MEDIA_TYPE_AUDIO, acd->type());
   EXPECT_EQ(MAKE_VECTOR(kAudioCodecsAnswer), acd->codecs());
   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // negotiated auto bw
-  EXPECT_NE(0U, acd->ssrc());                   // a random nonzero ssrc
+  EXPECT_NE(0U, acd->first_ssrc());             // a random nonzero ssrc
   EXPECT_TRUE(acd->rtcp_mux());                 // negotiated rtcp-mux
   ASSERT_CRYPTO(acd, false, 1U, CS_AES_CM_128_HMAC_SHA1_32);
   EXPECT_EQ(MEDIA_TYPE_VIDEO, vcd->type());
   EXPECT_EQ(MAKE_VECTOR(kVideoCodecsAnswer), vcd->codecs());
-  EXPECT_NE(0U, vcd->ssrc());                    // a random nonzero ssrc
+  EXPECT_NE(0U, vcd->first_ssrc());             // a random nonzero ssrc
   EXPECT_TRUE(vcd->rtcp_mux());                 // negotiated rtcp-mux
   ASSERT_CRYPTO(vcd, false, 1U, CS_AES_CM_128_HMAC_SHA1_80);
 }
@@ -324,7 +327,6 @@
   ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
   EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
 
-  EXPECT_EQ(0U, acd->ssrc());                   // 0- not used.
   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
   ASSERT_CRYPTO(acd, false, 2U, CS_AES_CM_128_HMAC_SHA1_32);
@@ -337,7 +339,6 @@
   ASSERT_EQ(1U, video_streams.size());
   EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
   EXPECT_EQ(kVideoTrack1, video_streams[0].name);
-  EXPECT_EQ(0U, vcd->ssrc());                   // 0- not used.
   EXPECT_EQ(kAutoBandwidth, vcd->bandwidth());  // default bandwidth (auto)
   EXPECT_TRUE(vcd->rtcp_mux());                 // rtcp-mux defaults on
 
@@ -429,7 +430,6 @@
   ASSERT_EQ(1U, audio_streams[1].ssrcs.size());
   EXPECT_NE(0U, audio_streams[1].ssrcs[0]);
 
-  EXPECT_EQ(0U, acd->ssrc());                   // 0- not used.
   EXPECT_EQ(kAutoBandwidth, acd->bandwidth());  // default bandwidth (auto)
   EXPECT_TRUE(acd->rtcp_mux());                 // rtcp-mux defaults on
 
@@ -440,7 +440,6 @@
   ASSERT_EQ(1U, video_streams.size());
   EXPECT_EQ(video_streams[0].cname, audio_streams[0].cname);
   EXPECT_EQ(kVideoTrack1, video_streams[0].name);
-  EXPECT_EQ(0U, vcd->ssrc());                   // 0- not used.
   EXPECT_EQ(kAutoBandwidth, vcd->bandwidth());  // default bandwidth (auto)
   EXPECT_TRUE(vcd->rtcp_mux());                 // rtcp-mux defaults on
 
diff --git a/talk/session/phone/mediasessionclient.cc b/talk/session/phone/mediasessionclient.cc
index f20b0f0..c7d8c88 100644
--- a/talk/session/phone/mediasessionclient.cc
+++ b/talk/session/phone/mediasessionclient.cc
@@ -36,6 +36,7 @@
 #include "talk/p2p/base/constants.h"
 #include "talk/p2p/base/parsing.h"
 #include "talk/session/phone/cryptoparams.h"
+#include "talk/session/phone/mediamessages.h"
 #include "talk/session/phone/srtpfilter.h"
 #include "talk/xmpp/constants.h"
 #include "talk/xmllite/qname.h"
@@ -198,6 +199,8 @@
   return session;
 }
 
+// TODO: Move all of the parsing and writing functions into
+// mediamessages.cc, with unit tests.
 bool ParseGingleAudioCodec(const buzz::XmlElement* element, AudioCodec* out) {
   int id = GetXmlAttr(element, QN_ID, -1);
   if (id < 0)
@@ -225,26 +228,30 @@
   return true;
 }
 
-uint32 parse_ssrc(const std::string& ssrc) {
-  // TODO: Return an error rather than defaulting to 0.
-  uint32 default_ssrc = 0U;
-  return talk_base::FromString(default_ssrc, ssrc);
+// Parses an ssrc string as a legacy stream.  If it fails, returns
+// false and fills an error message.
+bool ParseSsrcAsLegacyStream(const std::string& ssrc_str,
+                             std::vector<StreamParams>* streams,
+                             ParseError* error) {
+  if (!ssrc_str.empty()) {
+    uint32 ssrc;
+    if (!talk_base::FromString(ssrc_str, &ssrc)) {
+      return BadParse("Missing or invalid ssrc.", error);
+    }
+
+    streams->push_back(StreamParams::CreateLegacy(ssrc));
+  }
+  return true;
 }
 
 void ParseGingleSsrc(const buzz::XmlElement* parent_elem,
                      const buzz::QName& name,
-                     MediaContentDescription* content) {
+                     MediaContentDescription* media) {
   const buzz::XmlElement* ssrc_elem = parent_elem->FirstNamed(name);
   if (ssrc_elem) {
-    content->set_ssrc(parse_ssrc(ssrc_elem->BodyText()));
-  }
-}
-
-void ParseJingleSsrc(const buzz::XmlElement* desc_elem,
-                     MediaContentDescription* content) {
-  const std::string ssrc = desc_elem->Attr(QN_JINGLE_SSRC);
-  if (!ssrc.empty()) {
-    content->set_ssrc(parse_ssrc(ssrc));
+    ParseError error;
+    ParseSsrcAsLegacyStream(
+        ssrc_elem->BodyText(), &(media->mutable_streams()), &error);
   }
 }
 
@@ -454,6 +461,23 @@
   return true;
 }
 
+bool ParseJingleStreamsOrLegacySsrc(const buzz::XmlElement* desc_elem,
+                                    MediaContentDescription* media,
+                                    ParseError* error) {
+  if (HasJingleStreams(desc_elem)) {
+    if (!ParseJingleStreams(desc_elem, &(media->mutable_streams()), error)) {
+      return false;
+    }
+  } else {
+    const std::string ssrc_str = desc_elem->Attr(QN_SSRC);
+    if (!ParseSsrcAsLegacyStream(
+            ssrc_str, &(media->mutable_streams()), error)) {
+      return false;
+    }
+  }
+  return true;
+}
+
 bool ParseJingleAudioContent(const buzz::XmlElement* content_elem,
                              const ContentDescription** content,
                              ParseError* error) {
@@ -469,12 +493,13 @@
     }
   }
 
-  ParseJingleSsrc(content_elem, audio);
+  if (!ParseJingleStreamsOrLegacySsrc(content_elem, audio, error)) {
+    return false;
+  }
 
   if (!ParseJingleEncryption(content_elem, audio, error)) {
     return false;
   }
-  // TODO: Figure out how to integrate SSRC into Jingle.
   *content = audio;
   return true;
 }
@@ -494,13 +519,14 @@
     }
   }
 
-  ParseJingleSsrc(content_elem, video);
+  if (!ParseJingleStreamsOrLegacySsrc(content_elem, video, error)) {
+    return false;
+  }
   ParseBandwidth(content_elem, video);
 
   if (!ParseJingleEncryption(content_elem, video, error)) {
     return false;
   }
-  // TODO: Figure out how to integrate SSRC into Jingle.
   *content = video;
   return true;
 }
@@ -625,9 +651,9 @@
        codec != audio->codecs().end(); ++codec) {
     elem->AddElement(CreateGingleAudioCodecElem(*codec));
   }
-  if (audio->ssrc_set()) {
+  if (audio->has_ssrcs()) {
     elem->AddElement(CreateGingleSsrcElem(
-        QN_GINGLE_AUDIO_SRCID, audio->ssrc()));
+        QN_GINGLE_AUDIO_SRCID, audio->first_ssrc()));
   }
 
   const CryptoParamsVec& cryptos = audio->cryptos();
@@ -649,9 +675,9 @@
        codec != video->codecs().end(); ++codec) {
     elem->AddElement(CreateGingleVideoCodecElem(*codec));
   }
-  if (video->ssrc_set()) {
+  if (video->has_ssrcs()) {
     elem->AddElement(CreateGingleSsrcElem(
-        QN_GINGLE_VIDEO_SRCID, video->ssrc()));
+        QN_GINGLE_VIDEO_SRCID, video->first_ssrc()));
   }
   if (video->bandwidth() != kAutoBandwidth) {
     elem->AddElement(CreateBandwidthElem(QN_GINGLE_VIDEO_BANDWIDTH,
@@ -712,15 +738,19 @@
   return elem;
 }
 
-void WriteJingleSsrc(const MediaContentDescription* media,
-                     buzz::XmlElement* elem) {
-  // TODO: Right now, we have an ssrc=0 to mean "let the
-  // server choose".  In Jingle, it would make the most sense to just
-  // leave off the attribute.  But then we can't have an ssrc of 0.
-  // Once we have initiator-choosen ssrcs, we can remove this check
-  // and write out ssrc=0.
-  if (media->ssrc_set() && (media->ssrc() != 0)) {
-    AddXmlAttr(elem, QN_JINGLE_SSRC, media->ssrc());
+void WriteLegacyJingleSsrc(const MediaContentDescription* media,
+                           buzz::XmlElement* elem) {
+  if (media->has_ssrcs()) {
+    AddXmlAttr(elem, QN_SSRC, media->first_ssrc());
+  }
+}
+
+void WriteJingleStreamsOrLegacySsrc(const MediaContentDescription* media,
+                                    buzz::XmlElement* desc_elem) {
+  if (!media->multistream()) {
+    WriteLegacyJingleSsrc(media, desc_elem);
+  } else {
+    WriteJingleStreams(media->streams(), desc_elem);
   }
 }
 
@@ -730,7 +760,7 @@
       new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true);
 
   elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_AUDIO);
-  WriteJingleSsrc(audio, elem);
+  WriteJingleStreamsOrLegacySsrc(audio, elem);
 
   for (AudioCodecs::const_iterator codec = audio->codecs().begin();
        codec != audio->codecs().end(); ++codec) {
@@ -755,7 +785,7 @@
       new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true);
 
   elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_VIDEO);
-  WriteJingleSsrc(video, elem);
+  WriteJingleStreamsOrLegacySsrc(video, elem);
 
   for (VideoCodecs::const_iterator codec = video->codecs().begin();
        codec != video->codecs().end(); ++codec) {
diff --git a/talk/session/phone/ssrcmuxfilter.cc b/talk/session/phone/ssrcmuxfilter.cc
index 76245f2..2f3e1f2 100644
--- a/talk/session/phone/ssrcmuxfilter.cc
+++ b/talk/session/phone/ssrcmuxfilter.cc
@@ -35,6 +35,8 @@
 
 namespace cricket {
 
+static const uint32 kSsrc01 = 0x01;
+
 SsrcMuxFilter::SsrcMuxFilter()
     : state_(ST_INIT),
       enabled_(false) {
@@ -88,10 +90,16 @@
     if (!GetRtcpType(data, len, &pl_type)) return false;
     if (pl_type == kRtcpTypeSR || pl_type == kRtcpTypeRR) {
       // Getting SSRC from the report packets.
-      GetRtcpSsrc(data, len, &ssrc);
+      if (!GetRtcpSsrc(data, len, &ssrc)) return false;
+      if (ssrc == kSsrc01) {
+        // SSRC 1 has a special meaning and indicates generic feedback on
+        // some systems and should never be dropped.  If it is forwarded
+        // incorrectly it will be ignored by lower layers anyway.
+        return true;
+      }
     } else {
       // All other RTCP packets are handled by the all channels.
-      // TODO - Add SSRC parsing to all RTCP messages.
+      // TODO: Add SSRC parsing to all RTCP messages.
       LOG(LS_INFO) << "Non RTCP report packet received for demux.";
       return true;
     }
diff --git a/talk/session/phone/streamparams.h b/talk/session/phone/streamparams.h
index 527d9b7..ec4b380 100644
--- a/talk/session/phone/streamparams.h
+++ b/talk/session/phone/streamparams.h
@@ -52,6 +52,7 @@
   SsrcGroup(const std::string& usage, const std::vector<uint32>& ssrcs)
       : semantics(usage), ssrcs(ssrcs) {
   }
+
   bool operator==(const SsrcGroup& other) const {
     return (semantics == other.semantics && ssrcs == other.ssrcs);
   }
@@ -64,38 +65,48 @@
 };
 
 struct StreamParams {
-  StreamParams(const std::string& name,
-               const std::vector<uint32>& ssrcs,
-               const std::vector<SsrcGroup>& ssrc_groups,
-               const std::string& cname,
-               const std::string& sync_label)
-      : name(name),
-        ssrcs(ssrcs),
-        ssrc_groups(ssrc_groups),
-        cname(cname),
-        sync_label(sync_label) {
-  }
-  StreamParams(const std::string& name,
-               uint32 ssrc,
-               const std::string& cname,
-               const std::string& sync_label)
-      : name(name),
-        cname(cname),
-        sync_label(sync_label) {
-    ssrcs.push_back(ssrc);
+  static StreamParams CreateLegacy(uint32 ssrc) {
+    StreamParams stream;
+    stream.ssrcs.push_back(ssrc);
+    return stream;
   }
   bool operator==(const StreamParams& other) const {
-    return (name == other.name && ssrcs == other.ssrcs &&
-        ssrc_groups == other.ssrc_groups && cname == other.cname &&
-        sync_label == sync_label);
+    return (nick == other.nick &&
+            name == other.name &&
+            ssrcs == other.ssrcs &&
+            ssrc_groups == other.ssrc_groups &&
+            type == other.type &&
+            display == other.display &&
+            cname == other.cname &&
+            sync_label == sync_label);
   }
   bool operator!=(const StreamParams &other) const {
     return !(*this == other);
   }
 
-  std::string name;  // Unique name of this source.
+  uint32 first_ssrc() const {
+    if (ssrcs.empty()) {
+      return 0;
+    }
+
+    return ssrcs[0];
+  }
+  bool has_ssrcs() const {
+    return !ssrcs.empty();
+  }
+
+  // Resource of the MUC jid of the participant of with this stream.
+  // For 1:1 calls, should be left empty (which means remote streams
+  // and local streams should not be mixed together).
+  std::string nick;
+  // Unique name of this source (unique per-nick, not for all nicks)
+  std::string name;
   std::vector<uint32> ssrcs;  // All SSRCs for this source
   std::vector<SsrcGroup> ssrc_groups;  // e.g. FID, FEC, SIM
+  // Examples: "camera", "screencast"
+  std::string type;
+  // Friendly name describing stream
+  std::string display;
   std::string cname;  // RTCP CNAME
   std::string sync_label;  // Friendly name of cname.
 };
diff --git a/talk/session/phone/webrtcvideoengine.cc b/talk/session/phone/webrtcvideoengine.cc
index 3460e49..046ae5f 100644
--- a/talk/session/phone/webrtcvideoengine.cc
+++ b/talk/session/phone/webrtcvideoengine.cc
@@ -33,6 +33,7 @@
 
 #include "talk/session/phone/webrtcvideoengine.h"
 
+#include "talk/base/basictypes.h"
 #include "talk/base/common.h"
 #include "talk/base/buffer.h"
 #include "talk/base/byteorder.h"
@@ -53,7 +54,8 @@
 
 static const int kDefaultLogSeverity = talk_base::LS_WARNING;
 
-static const int kMinVideoBitrate = 300;
+static const int kMinVideoBitrate = 100;
+static const int kStartVideoBitrate = 300;
 static const int kMaxVideoBitrate = 2000;
 
 static const int kVideoMtu = 1200;
@@ -772,9 +774,9 @@
     out_codec.maxFramerate = in_codec.framerate;
 
   // Init the codec with the default bandwidth options.
-  out_codec.maxBitrate = kMaxVideoBitrate;
-  out_codec.startBitrate = kMinVideoBitrate;
   out_codec.minBitrate = kMinVideoBitrate;
+  out_codec.startBitrate = kStartVideoBitrate;
+  out_codec.maxBitrate = kMaxVideoBitrate;
 
   return true;
 }
@@ -946,6 +948,7 @@
       render_started_(false),
       muted_(false),
       send_min_bitrate_(kMinVideoBitrate),
+      send_start_bitrate_(kStartVideoBitrate),
       send_max_bitrate_(kMaxVideoBitrate),
       local_stream_info_(new LocalStreamInfo()) {
   engine->RegisterChannel(this);
@@ -1171,7 +1174,8 @@
         kDefaultNumberOfTemporalLayers;
   }
 
-  if (!SetSendCodec(codec, send_min_bitrate_, send_max_bitrate_)) {
+  if (!SetSendCodec(
+      codec, send_min_bitrate_, send_start_bitrate_, send_max_bitrate_)) {
     return false;
   }
 
@@ -1420,21 +1424,25 @@
     return true;
   }
 
-  int min_bitrate = kMinVideoBitrate;
-  int max_bitrate = kMaxVideoBitrate;
+  int min_bitrate;
+  int start_bitrate;
+  int max_bitrate;
   if (autobw) {
-    // Use the default values as min
+    // Use the default values for min bitrate.
     min_bitrate = kMinVideoBitrate;
     // Use the default value or the bps for the max
     max_bitrate = (bps <= 0) ? kMaxVideoBitrate : (bps / 1000);
+    // Maximum start bitrate can be kStartVideoBitrate.
+    start_bitrate = talk_base::_min(kStartVideoBitrate, max_bitrate);
   } else {
     // Use the default start or the bps as the target bitrate.
-    int target_bitrate = (bps <= 0) ? kMinVideoBitrate : (bps / 1000);
+    int target_bitrate = (bps <= 0) ? kStartVideoBitrate : (bps / 1000);
     min_bitrate = target_bitrate;
+    start_bitrate = target_bitrate;
     max_bitrate = target_bitrate;
   }
 
-  if (!SetSendCodec(*send_codec_, min_bitrate, max_bitrate)) {
+  if (!SetSendCodec(*send_codec_, min_bitrate, start_bitrate, max_bitrate)) {
     return false;
   }
 
@@ -1467,6 +1475,23 @@
   // Update local stream statistics.
   local_stream_info_->UpdateFrame(frame->GetWidth(), frame->GetHeight());
 
+  // If the captured video format is smaller than what we asked for, reset send
+  // codec on video engine.
+  if (send_codec_.get() != NULL &&
+      frame->GetWidth() < send_codec_->width &&
+      frame->GetHeight() < send_codec_->height) {
+    LOG(LS_INFO) << "Captured video frame size changed to: "
+                 << frame->GetWidth() << "x" << frame->GetHeight();
+    webrtc::VideoCodec new_codec = *send_codec_;
+    new_codec.width = frame->GetWidth();
+    new_codec.height = frame->GetHeight();
+    if (!SetSendCodec(
+        new_codec, send_min_bitrate_, send_start_bitrate_, send_max_bitrate_)) {
+      LOG(LS_WARNING) << "Failed to switch to new frame size: "
+                      << frame->GetWidth() << "x" << frame->GetHeight();
+    }
+  }
+  
   // Blacken the frame if video is muted.
   const VideoFrame* frame_out = frame;
   talk_base::scoped_ptr<VideoFrame> black_frame;
@@ -1543,10 +1568,12 @@
 }
 
 bool WebRtcVideoMediaChannel::SetSendCodec(const webrtc::VideoCodec& codec,
-    int min_bitrate, int max_bitrate) {
+                                           int min_bitrate,
+                                           int start_bitrate,
+                                           int max_bitrate) {
   // Make a copy of the codec
   webrtc::VideoCodec target_codec = codec;
-  target_codec.startBitrate = min_bitrate;
+  target_codec.startBitrate = start_bitrate;
   target_codec.minBitrate = min_bitrate;
   target_codec.maxBitrate = max_bitrate;
 
@@ -1558,6 +1585,7 @@
   // Reset the send_codec_ only if SetSendCodec is success.
   send_codec_.reset(new webrtc::VideoCodec(target_codec));
   send_min_bitrate_ = min_bitrate;
+  send_start_bitrate_ = start_bitrate;
   send_max_bitrate_ = max_bitrate;
 
   return true;
diff --git a/talk/session/phone/webrtcvideoengine.h b/talk/session/phone/webrtcvideoengine.h
index eb2caa9..be8c5f0 100644
--- a/talk/session/phone/webrtcvideoengine.h
+++ b/talk/session/phone/webrtcvideoengine.h
@@ -267,7 +267,9 @@
   bool EnableNack();
   bool SetNackFec(int red_payload_type, int fec_payload_type);
   bool SetSendCodec(const webrtc::VideoCodec& codec,
-      int min_bitrate, int max_bitrate);
+                    int min_bitrate,
+                    int start_bitrate,
+                    int max_bitrate);
   bool ResetRecvCodecs(int channel);
 
   WebRtcVideoEngine* engine_;
@@ -279,6 +281,7 @@
   bool render_started_;
   bool muted_;  // Flag to tell if we need to mute video.
   int send_min_bitrate_;
+  int send_start_bitrate_;
   int send_max_bitrate_;
   talk_base::scoped_ptr<webrtc::VideoCodec> send_codec_;
   talk_base::scoped_ptr<WebRtcRenderAdapter> remote_renderer_;
diff --git a/talk/session/phone/webrtcvideoengine_unittest.cc b/talk/session/phone/webrtcvideoengine_unittest.cc
index 0c1fa4b..ad11f20 100644
--- a/talk/session/phone/webrtcvideoengine_unittest.cc
+++ b/talk/session/phone/webrtcvideoengine_unittest.cc
@@ -34,6 +34,7 @@
 #include "talk/session/phone/videoengine_unittest.h"
 #include "talk/session/phone/webrtcvideocapturer.h"
 #include "talk/session/phone/webrtcvideoengine.h"
+#include "talk/session/phone/webrtcvideoframe.h"
 #include "talk/session/phone/webrtcvoiceengine.h"
 
 // Tests for the WebRtcVideoEngine/VideoChannel code.
@@ -47,7 +48,8 @@
     &kUlpFecCodec
 };
 
-static const unsigned int kMinBandwidthKbps = 300;
+static const unsigned int kMinBandwidthKbps = 100;
+static const unsigned int kStartBandwidthKbps = 300;
 static const unsigned int kMaxBandwidthKbps = 2000;
 
 class FakeViEWrapper : public cricket::ViEWrapper {
@@ -171,7 +173,7 @@
   EXPECT_EQ(kVP8Codec.height, gcodec.height);
   EXPECT_STREQ(kVP8Codec.name.c_str(), gcodec.plName);
   EXPECT_EQ(kMinBandwidthKbps, gcodec.minBitrate);
-  EXPECT_EQ(kMinBandwidthKbps, gcodec.startBitrate);
+  EXPECT_EQ(kStartBandwidthKbps, gcodec.startBitrate);
   EXPECT_EQ(kMaxBandwidthKbps, gcodec.maxBitrate);
   // TODO: Check HybridNackFecStatus.
   // TODO: Check RTCP, PLI, TMMBR.
@@ -250,6 +252,40 @@
   EXPECT_EQ(0, gcodec.plType);
 }
 
+// Test that send codec is reset if the captured frame is smaller.
+TEST_F(WebRtcVideoEngineTestFake, ResetSendCodecOnSmallerFrame) {
+  EXPECT_TRUE(SetupEngine());
+  int channel_num = vie_.GetLastChannel();
+
+  const int old_w = 640;
+  const int old_h = 400;
+  const int new_w = 160;
+  const int new_h = 100;
+
+  // Set send codec and start sending.
+  cricket::VideoCodec codec(kVP8Codec);
+  codec.width = old_w;
+  codec.height = old_h;
+  std::vector<cricket::VideoCodec> codec_list;
+  codec_list.push_back(codec);
+  EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
+  EXPECT_TRUE(channel_->SetSend(true));
+
+  // Capture a smaller frame.
+  cricket::WebRtcVideoFrame frame;
+  uint8 pixel[new_w * new_h * 3 / 2] = { 0 };  // I420
+  EXPECT_TRUE(frame.Init(cricket::FOURCC_I420, new_w, new_h, new_w, new_h,
+                         pixel, sizeof(pixel), 1, 1, 0, 0, 0));
+  EXPECT_TRUE(channel_->SendFrame(0, &frame));
+
+  // Verify the send codec has been reset to the new format.
+  webrtc::VideoCodec gcodec;
+  EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
+  EXPECT_EQ(kVP8Codec.id, gcodec.plType);
+  EXPECT_EQ(new_w, gcodec.width);
+  EXPECT_EQ(new_h, gcodec.height);
+}
+
 // Test that we set our inbound codecs properly.
 TEST_F(WebRtcVideoEngineTestFake, SetRecvCodecs) {
   EXPECT_TRUE(SetupEngine());
@@ -367,7 +403,7 @@
   EXPECT_EQ(kVP8Codec.id, gcodec.plType);
   EXPECT_STREQ(kVP8Codec.name.c_str(), gcodec.plName);
   EXPECT_EQ(kMinBandwidthKbps, gcodec.minBitrate);
-  EXPECT_EQ(kMinBandwidthKbps, gcodec.startBitrate);
+  EXPECT_EQ(kStartBandwidthKbps, gcodec.startBitrate);
   EXPECT_EQ(kMaxBandwidthKbps, gcodec.maxBitrate);
 }
 
@@ -382,7 +418,7 @@
   EXPECT_EQ(kVP8Codec.id, gcodec.plType);
   EXPECT_STREQ(kVP8Codec.name.c_str(), gcodec.plName);
   EXPECT_EQ(kMinBandwidthKbps, gcodec.minBitrate);
-  EXPECT_EQ(kMinBandwidthKbps, gcodec.startBitrate);
+  EXPECT_EQ(kStartBandwidthKbps, gcodec.startBitrate);
   EXPECT_EQ(768U, gcodec.maxBitrate);
 }
 
diff --git a/talk/session/phone/webrtcvideoframe.cc b/talk/session/phone/webrtcvideoframe.cc
index e12771d..2562ed5 100644
--- a/talk/session/phone/webrtcvideoframe.cc
+++ b/talk/session/phone/webrtcvideoframe.cc
@@ -27,14 +27,10 @@
 
 #include "talk/session/phone/webrtcvideoframe.h"
 
+#include "libyuv/planar_functions.h"
 #include "talk/base/logging.h"
 #include "talk/session/phone/videocapturer.h"
 #include "talk/session/phone/videocommon.h"
-#ifdef WEBRTC_RELATIVE_PATH
-#include "common_video/vplib/main/interface/vplib.h"
-#else
-#include "third_party/webrtc/files/include/vplib.h"
-#endif
 
 namespace cricket {
 
@@ -217,10 +213,11 @@
   return needed;
 }
 
+// TODO: Refactor into base class and share with lmi
 size_t WebRtcVideoFrame::ConvertToRgbBuffer(uint32 to_fourcc,
                                             uint8* buffer,
                                             size_t size,
-                                            size_t pitch_rgb) const {
+                                            size_t stride_rgb) const {
   if (!video_frame_.Buffer()) {
     return 0;
   }
@@ -231,29 +228,44 @@
   // explanation of pitch and why this is the amount of space we need.
   // TODO: increase to stride * height to allow padding to be used
   // to overwrite for efficiency.
-  size_t needed = pitch_rgb * (height - 1) + 4 * width;
+  size_t needed = stride_rgb * (height - 1) + 4 * width;
 
   if (needed > size) {
     LOG(LS_WARNING) << "RGB buffer is not large enough";
-    return 0;
+    return needed;
   }
 
-  webrtc::VideoType to_type = webrtc::kUnknown;
+  // TODO: Use libyuv::ConvertFromI420
   switch (to_fourcc) {
     case FOURCC_ARGB:
-      to_type = webrtc::kARGB;
+      libyuv::I420ToARGB(
+          GetYPlane(), GetYPitch(),
+          GetUPlane(), GetUPitch(),
+          GetVPlane(), GetVPitch(),
+          buffer, stride_rgb, width, height);
       break;
+
+    case FOURCC_BGRA:
+      libyuv::I420ToBGRA(
+          GetYPlane(), GetYPitch(),
+          GetUPlane(), GetUPitch(),
+          GetVPlane(), GetVPitch(),
+          buffer, stride_rgb, width, height);
+      break;
+
+    case FOURCC_ABGR:
+      libyuv::I420ToABGR(
+          GetYPlane(), GetYPitch(),
+          GetUPlane(), GetUPitch(),
+          GetVPlane(), GetVPitch(),
+          buffer, stride_rgb, width, height);
+      break;
+
     default:
+      needed = 0;
       LOG(LS_WARNING) << "RGB type not supported: " << to_fourcc;
-      return 0;
+      break;
   }
-
-  if (to_type != webrtc::kUnknown) {
-    // TODO: Use libyuv::ConvertFromI420
-    webrtc::ConvertFromI420(to_type, video_frame_.Buffer(),
-                            width, height, buffer);
-  }
-
   return needed;
 }
 
diff --git a/talk/session/phone/webrtcvideoframe_unittest.cc b/talk/session/phone/webrtcvideoframe_unittest.cc
index 7b057e5..c4526c0 100644
--- a/talk/session/phone/webrtcvideoframe_unittest.cc
+++ b/talk/session/phone/webrtcvideoframe_unittest.cc
@@ -57,8 +57,10 @@
 // Re-evaluate once WebRTC switches to libyuv
 // TEST_LMIVIDEOFRAME(ConstructYuy2AllSizes)
 // TODO: WebRtcVideoFrame currently only supports ARGB output.
-// TEST_WEBRTCVIDEOFRAME(ConvertToBGRABuffer)
-// TEST_WEBRTCVIDEOFRAME(ConvertToABGRBuffer)
+#ifdef HAVE_YUV
+TEST_WEBRTCVIDEOFRAME(ConvertToBGRABuffer)
+TEST_WEBRTCVIDEOFRAME(ConvertToABGRBuffer)
+#endif
 TEST_WEBRTCVIDEOFRAME(ConvertToARGBBuffer)
 //TEST_WEBRTCVIDEOFRAME(ConvertToYUY2Buffer)
 //TEST_WEBRTCVIDEOFRAME(ConvertToI422Buffer)
diff --git a/talk/session/phone/webrtcvoiceengine.cc b/talk/session/phone/webrtcvoiceengine.cc
index cfe7345..561c13c 100644
--- a/talk/session/phone/webrtcvoiceengine.cc
+++ b/talk/session/phone/webrtcvoiceengine.cc
@@ -1410,9 +1410,8 @@
     }
   }
 
-// This api is currently present but nonfunctional in WebRTC VoiceEngine.
 // This api call is not available in iOS version of VoiceEngine currently.
-#if 0  // !defined(IOS) && !defined(ANDROID)
+#if !defined(IOS) && !defined(ANDROID)
   if (engine()->voe()->rtp()->SetRTPAudioLevelIndicationStatus(
       voe_channel(), enable, id) == -1) {
     LOG_RTCERR3(SetRTPAudioLevelIndicationStatus, voe_channel(), enable, id);
diff --git a/talk/session/phone/webrtcvoiceengine_unittest.cc b/talk/session/phone/webrtcvoiceengine_unittest.cc
index b1b1783..6bcc04e 100644
--- a/talk/session/phone/webrtcvoiceengine_unittest.cc
+++ b/talk/session/phone/webrtcvoiceengine_unittest.cc
@@ -4,11 +4,11 @@
 
 #include "talk/base/byteorder.h"
 #include "talk/base/gunit.h"
+#include "talk/p2p/base/fakesession.h"
 #include "talk/session/phone/channel.h"
 #include "talk/session/phone/fakemediaengine.h"
 #include "talk/session/phone/fakemediaprocessor.h"
 #include "talk/session/phone/fakertp.h"
-#include "talk/session/phone/fakesession.h"
 #include "talk/session/phone/fakewebrtcvoiceengine.h"
 #include "talk/session/phone/webrtcvoiceengine.h"
 
@@ -558,9 +558,8 @@
   EXPECT_FALSE(enable);
 }
 
-// TODO: Re-enable this test once audio level status is restored.
 // Test that we support setting certain send header extensions.
-TEST_F(WebRtcVoiceEngineTestFake, DISABLED_SetSendRtpHeaderExtensions) {
+TEST_F(WebRtcVoiceEngineTestFake, SetSendRtpHeaderExtensions) {
   EXPECT_TRUE(SetupEngine());
   std::vector<cricket::RtpHeaderExtension> extensions;
   int channel_num = voe_.GetLastChannel();
diff --git a/talk/xmllite/xmlelement.cc b/talk/xmllite/xmlelement.cc
index 6a0e8e8..7b208e6 100644
--- a/talk/xmllite/xmlelement.cc
+++ b/talk/xmllite/xmlelement.cc
@@ -521,7 +521,7 @@
 std::string
 XmlElement::Str() const {
   std::stringstream ss;
-  Print(&ss, NULL, 0);
+  XmlPrinter::PrintXml(&ss, this);
   return ss.str();
 }
 
@@ -532,12 +532,6 @@
   return builder.CreateElement();
 }
 
-void
-XmlElement::Print(
-    std::ostream * pout, std::string xmlns[], int xmlnsCount) const {
-  XmlPrinter::PrintXml(pout, this, xmlns, xmlnsCount);
-}
-
 XmlElement::~XmlElement() {
   XmlAttr * pattr;
   for (pattr = pFirstAttr_; pattr; ) {
diff --git a/talk/xmllite/xmlelement.h b/talk/xmllite/xmlelement.h
index f50985a..7cb30f3 100644
--- a/talk/xmllite/xmlelement.h
+++ b/talk/xmllite/xmlelement.h
@@ -223,8 +223,6 @@
   static XmlElement * ForStr(const std::string & str);
   std::string Str() const;
 
-  void Print(std::ostream * pout, std::string xmlns[], int xmlnsCount) const;
-
   bool IsCDATA() const { return cdata_; }
 
 protected:
diff --git a/talk/xmllite/xmlprinter.cc b/talk/xmllite/xmlprinter.cc
index 691419c..1350454 100644
--- a/talk/xmllite/xmlprinter.cc
+++ b/talk/xmllite/xmlprinter.cc
@@ -39,117 +39,111 @@
 
 class XmlPrinterImpl {
 public:
-  XmlPrinterImpl(std::ostream * pout,
-    const std::string * const xmlns, int xmlnsCount);
-  void PrintElement(const XmlElement * element);
-  void PrintQuotedValue(const std::string & text);
-  void PrintBodyText(const std::string & text);
-  void PrintCDATAText(const std::string & text);
+  XmlPrinterImpl(std::ostream* pout, XmlnsStack* ns_stack);
+  void PrintElement(const XmlElement* element);
+  void PrintQuotedValue(const std::string& text);
+  void PrintBodyText(const std::string& text);
+  void PrintCDATAText(const std::string& text);
 
 private:
   std::ostream *pout_;
-  XmlnsStack xmlnsStack_;
+  XmlnsStack* ns_stack_;
 };
 
-void
-XmlPrinter::PrintXml(std::ostream * pout, const XmlElement * element) {
-  PrintXml(pout, element, NULL, 0);
+void XmlPrinter::PrintXml(std::ostream* pout, const XmlElement* element) {
+  XmlnsStack ns_stack;
+  PrintXml(pout, element, &ns_stack);
 }
 
-void
-XmlPrinter::PrintXml(std::ostream * pout, const XmlElement * element,
-    const std::string * const xmlns, int xmlnsCount) {
-  XmlPrinterImpl printer(pout, xmlns, xmlnsCount);
+void XmlPrinter::PrintXml(std::ostream* pout, const XmlElement* element,
+                          XmlnsStack* ns_stack) {
+  XmlPrinterImpl printer(pout, ns_stack);
   printer.PrintElement(element);
 }
 
-XmlPrinterImpl::XmlPrinterImpl(std::ostream * pout,
-    const std::string * const xmlns, int xmlnsCount) :
-  pout_(pout),
-  xmlnsStack_() {
-  int i;
-  for (i = 0; i < xmlnsCount; i += 2) {
-    xmlnsStack_.AddXmlns(xmlns[i], xmlns[i + 1]);
-  }
+XmlPrinterImpl::XmlPrinterImpl(std::ostream* pout, XmlnsStack* ns_stack)
+    : pout_(pout),
+      ns_stack_(ns_stack) {
 }
 
-void
-XmlPrinterImpl::PrintElement(const XmlElement * element) {
-  xmlnsStack_.PushFrame();
+void XmlPrinterImpl::PrintElement(const XmlElement* element) {
+  ns_stack_->PushFrame();
 
   // first go through attrs of pel to add xmlns definitions
-  const XmlAttr * pattr;
-  for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) {
-    if (pattr->Name() == QN_XMLNS)
-      xmlnsStack_.AddXmlns(STR_EMPTY, pattr->Value());
-    else if (pattr->Name().Namespace() == NS_XMLNS)
-      xmlnsStack_.AddXmlns(pattr->Name().LocalPart(),
-        pattr->Value());
+  const XmlAttr* attr;
+  for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) {
+    if (attr->Name() == QN_XMLNS) {
+      ns_stack_->AddXmlns(STR_EMPTY, attr->Value());
+    } else if (attr->Name().Namespace() == NS_XMLNS) {
+      ns_stack_->AddXmlns(attr->Name().LocalPart(),
+                          attr->Value());
+    }
   }
 
   // then go through qnames to make sure needed xmlns definitons are added
-  std::vector<std::string> newXmlns;
+  std::vector<std::string> new_ns;
   std::pair<std::string, bool> prefix;
-  prefix = xmlnsStack_.AddNewPrefix(element->Name().Namespace(), false);
+  prefix = ns_stack_->AddNewPrefix(element->Name().Namespace(), false);
   if (prefix.second) {
-    newXmlns.push_back(prefix.first);
-    newXmlns.push_back(element->Name().Namespace());
+    new_ns.push_back(prefix.first);
+    new_ns.push_back(element->Name().Namespace());
   }
 
-  for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) {
-    prefix = xmlnsStack_.AddNewPrefix(pattr->Name().Namespace(), true);
+  for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) {
+    prefix = ns_stack_->AddNewPrefix(attr->Name().Namespace(), true);
     if (prefix.second) {
-      newXmlns.push_back(prefix.first);
-      newXmlns.push_back(pattr->Name().Namespace());
+      new_ns.push_back(prefix.first);
+      new_ns.push_back(attr->Name().Namespace());
     }
   }
 
   // print the element name
-  *pout_ << '<' << xmlnsStack_.FormatQName(element->Name(), false);
+  *pout_ << '<' << ns_stack_->FormatQName(element->Name(), false);
 
   // and the attributes
-  for (pattr = element->FirstAttr(); pattr; pattr = pattr->NextAttr()) {
-    *pout_ << ' ' << xmlnsStack_.FormatQName(pattr->Name(), true) << "=\"";
-    PrintQuotedValue(pattr->Value());
+  for (attr = element->FirstAttr(); attr; attr = attr->NextAttr()) {
+    *pout_ << ' ' << ns_stack_->FormatQName(attr->Name(), true) << "=\"";
+    PrintQuotedValue(attr->Value());
     *pout_ << '"';
   }
 
   // and the extra xmlns declarations
-  std::vector<std::string>::iterator i(newXmlns.begin());
-  while (i < newXmlns.end()) {
-    if (*i == STR_EMPTY)
+  std::vector<std::string>::iterator i(new_ns.begin());
+  while (i < new_ns.end()) {
+    if (*i == STR_EMPTY) {
       *pout_ << " xmlns=\"" << *(i + 1) << '"';
-    else
+    } else {
       *pout_ << " xmlns:" << *i << "=\"" << *(i + 1) << '"';
+    }
     i += 2;
   }
 
   // now the children
-  const XmlChild * pchild = element->FirstChild();
+  const XmlChild* child = element->FirstChild();
 
-  if (pchild == NULL)
+  if (child == NULL)
     *pout_ << "/>";
   else {
     *pout_ << '>';
-    while (pchild) {
-      if (pchild->IsText()) {
+    while (child) {
+      if (child->IsText()) {
         if (element->IsCDATA()) {
-          PrintCDATAText(pchild->AsText()->Text());
+          PrintCDATAText(child->AsText()->Text());
         } else {
-          PrintBodyText(pchild->AsText()->Text());
+          PrintBodyText(child->AsText()->Text());
         }
-      } else
-        PrintElement(pchild->AsElement());
-      pchild = pchild->NextChild();
+      } else {
+        PrintElement(child->AsElement());
+      }
+      child = child->NextChild();
     }
-    *pout_ << "</" << xmlnsStack_.FormatQName(element->Name(), false) << '>';
+    *pout_ << "</" << ns_stack_->FormatQName(element->Name(), false) << '>';
   }
 
-  xmlnsStack_.PopFrame();
+  ns_stack_->PopFrame();
 }
 
-void
-XmlPrinterImpl::PrintQuotedValue(const std::string & text) {
+void XmlPrinterImpl::PrintQuotedValue(const std::string& text) {
   size_t safe = 0;
   for (;;) {
     size_t unsafe = text.find_first_of("<>&\"", safe);
@@ -170,8 +164,7 @@
   }
 }
 
-void
-XmlPrinterImpl::PrintBodyText(const std::string & text) {
+void XmlPrinterImpl::PrintBodyText(const std::string& text) {
   size_t safe = 0;
   for (;;) {
     size_t unsafe = text.find_first_of("<>&", safe);
@@ -191,9 +184,8 @@
   }
 }
 
-void
-XmlPrinterImpl::PrintCDATAText(const std::string & text) {
+void XmlPrinterImpl::PrintCDATAText(const std::string& text) {
   *pout_ << "<![CDATA[" << text << "]]>";
 }
 
-}
+}  // namespace buzz
diff --git a/talk/xmllite/xmlprinter.h b/talk/xmllite/xmlprinter.h
index 96900d0..90cc255 100644
--- a/talk/xmllite/xmlprinter.h
+++ b/talk/xmllite/xmlprinter.h
@@ -2,48 +2,48 @@
  * libjingle
  * Copyright 2004--2005, Google Inc.
  *
- * Redistribution and use in source and binary forms, with or without 
+ * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
- *  1. Redistributions of source code must retain the above copyright notice, 
+ *  1. Redistributions of source code must retain the above copyright notice,
  *     this list of conditions and the following disclaimer.
  *  2. Redistributions in binary form must reproduce the above copyright notice,
  *     this list of conditions and the following disclaimer in the documentation
  *     and/or other materials provided with the distribution.
- *  3. The name of the author may not be used to endorse or promote products 
+ *  3. The name of the author may not be used to endorse or promote products
  *     derived from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef _xmlprinter_h_
-#define _xmlprinter_h_
+#ifndef TALK_XMLLITE_XMLPRINTER_H_
+#define TALK_XMLLITE_XMLPRINTER_H_
 
 #include <iosfwd>
 #include <string>
-#include "talk/base/scoped_ptr.h"
 
 namespace buzz {
 
 class XmlElement;
+class XmlnsStack;
 
 class XmlPrinter {
-public:
-  static void PrintXml(std::ostream * pout, const XmlElement * pelt);
+ public:
+  static void PrintXml(std::ostream* pout, const XmlElement* pelt);
 
-  static void PrintXml(std::ostream * pout, const XmlElement * pelt,
-    const std::string * const xmlns, int xmlnsCount);
+  static void PrintXml(std::ostream* pout, const XmlElement* pelt,
+                       XmlnsStack* ns_stack);
 };
 
-}
+}  // namespace buzz
 
-#endif
+#endif  // TALK_XMLLITE_XMLPRINTER_H_
diff --git a/talk/xmllite/xmlprinter_unittest.cc b/talk/xmllite/xmlprinter_unittest.cc
index 8ac7e04..60b0e42 100644
--- a/talk/xmllite/xmlprinter_unittest.cc
+++ b/talk/xmllite/xmlprinter_unittest.cc
@@ -25,24 +25,22 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <string>
+#include "talk/xmllite/xmlprinter.h"
+
 #include <sstream>
-#include <iostream>
+#include <string>
+
 #include "talk/base/common.h"
 #include "talk/base/gunit.h"
 #include "talk/xmllite/qname.h"
 #include "talk/xmllite/xmlelement.h"
-#include "talk/xmllite/xmlprinter.h"
+#include "talk/xmllite/xmlnsstack.h"
 
 using buzz::QName;
 using buzz::XmlElement;
+using buzz::XmlnsStack;
 using buzz::XmlPrinter;
 
-static std::string XmlPrinterTest_Ns[] = {
-  "gg", "google:test",
-  "", "nested:test",
-};
-
 TEST(XmlPrinterTest, TestBasicPrinting) {
   XmlElement elt(QName("google:test", "first"));
   std::stringstream ss;
@@ -55,7 +53,10 @@
   elt.AddElement(new XmlElement(QName("nested:test", "second")));
   std::stringstream ss;
 
-  XmlPrinter::PrintXml(&ss, &elt, XmlPrinterTest_Ns, 4);
+  XmlnsStack ns_stack;
+  ns_stack.AddXmlns("gg", "google:test");
+  ns_stack.AddXmlns("", "nested:test");
+
+  XmlPrinter::PrintXml(&ss, &elt, &ns_stack);
   EXPECT_EQ("<gg:first><second/></gg:first>", ss.str());
 }
-
diff --git a/talk/xmpp/xmppengineimpl.cc b/talk/xmpp/xmppengineimpl.cc
index 3edddf2..eb539d1 100644
--- a/talk/xmpp/xmppengineimpl.cc
+++ b/talk/xmpp/xmppengineimpl.cc
@@ -2,87 +2,83 @@
  * libjingle
  * Copyright 2004--2005, Google Inc.
  *
- * Redistribution and use in source and binary forms, with or without 
+ * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
- *  1. Redistributions of source code must retain the above copyright notice, 
+ *  1. Redistributions of source code must retain the above copyright notice,
  *     this list of conditions and the following disclaimer.
  *  2. Redistributions in binary form must reproduce the above copyright notice,
  *     this list of conditions and the following disclaimer in the documentation
  *     and/or other materials provided with the distribution.
- *  3. The name of the author may not be used to endorse or promote products 
+ *  3. The name of the author may not be used to endorse or promote products
  *     derived from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#define TRACK_ARRAY_ALLOC_PROBLEM
-
-#include <vector>
-#include <sstream>
-#include <algorithm>
-#include "talk/xmllite/xmlelement.h"
-#include "talk/base/common.h"
 #include "talk/xmpp/xmppengineimpl.h"
-#include "talk/xmpp/xmpplogintask.h"
-#include "talk/xmpp/constants.h"
+
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+#include "talk/base/common.h"
+#include "talk/xmllite/xmlelement.h"
 #include "talk/xmllite/xmlprinter.h"
+#include "talk/xmpp/constants.h"
 #include "talk/xmpp/saslhandler.h"
+#include "talk/xmpp/xmpplogintask.h"
 
 namespace buzz {
 
-static const std::string XMPP_CLIENT_NAMESPACES[] = {
-  "stream", "http://etherx.jabber.org/streams",
-  "", "jabber:client",
-};
-
-static const size_t XMPP_CLIENT_NAMESPACES_LEN = 4;
-
-XmppEngine * XmppEngine::Create() {
+XmppEngine* XmppEngine::Create() {
   return new XmppEngineImpl();
 }
 
 
-XmppEngineImpl::XmppEngineImpl() :
-    stanzaParseHandler_(this),
-    stanzaParser_(&stanzaParseHandler_),
-    engine_entered_(0),
-    password_(),
-    requested_resource_(STR_EMPTY),
-    tls_option_(buzz::TLS_REQUIRED),
-    login_task_(new XmppLoginTask(this)),
-    next_id_(0),
-    state_(STATE_START),
-    encrypted_(false),
-    error_code_(ERROR_NONE),
-    subcode_(0),
-    stream_error_(NULL),
-    raised_reset_(false),
-    output_handler_(NULL),
-    session_handler_(NULL),
-    iq_entries_(new IqEntryVector()),
-    sasl_handler_(NULL),
-    output_(new std::stringstream()) {
+XmppEngineImpl::XmppEngineImpl()
+    : stanza_parse_handler_(this),
+      stanza_parser_(&stanza_parse_handler_),
+      engine_entered_(0),
+      password_(),
+      requested_resource_(STR_EMPTY),
+      tls_option_(buzz::TLS_REQUIRED),
+      login_task_(new XmppLoginTask(this)),
+      next_id_(0),
+      state_(STATE_START),
+      encrypted_(false),
+      error_code_(ERROR_NONE),
+      subcode_(0),
+      stream_error_(NULL),
+      raised_reset_(false),
+      output_handler_(NULL),
+      session_handler_(NULL),
+      iq_entries_(new IqEntryVector()),
+      sasl_handler_(NULL),
+      output_(new std::stringstream()) {
   for (int i = 0; i < HL_COUNT; i+= 1) {
     stanza_handlers_[i].reset(new StanzaHandlerVector());
   }
+
+  xmlns_stack_.AddXmlns("stream", "http://etherx.jabber.org/streams");
+  xmlns_stack_.AddXmlns("", "jabber:client");
 }
 
 XmppEngineImpl::~XmppEngineImpl() {
   DeleteIqCookies();
 }
 
-XmppReturnStatus
-XmppEngineImpl::SetOutputHandler(XmppOutputHandler* output_handler) {
+XmppReturnStatus XmppEngineImpl::SetOutputHandler(
+    XmppOutputHandler* output_handler) {
   if (state_ != STATE_START)
     return XMPP_RETURN_BADSTATE;
 
@@ -91,8 +87,8 @@
   return XMPP_RETURN_OK;
 }
 
-XmppReturnStatus
-XmppEngineImpl::SetSessionHandler(XmppSessionHandler* session_handler) {
+XmppReturnStatus XmppEngineImpl::SetSessionHandler(
+    XmppSessionHandler* session_handler) {
   if (state_ != STATE_START)
     return XMPP_RETURN_BADSTATE;
 
@@ -101,21 +97,20 @@
   return XMPP_RETURN_OK;
 }
 
-XmppReturnStatus
-XmppEngineImpl::HandleInput(const char * bytes, size_t len) {
+XmppReturnStatus XmppEngineImpl::HandleInput(
+    const char* bytes, size_t len) {
   if (state_ < STATE_OPENING || state_ > STATE_OPEN)
     return XMPP_RETURN_BADSTATE;
 
   EnterExit ee(this);
 
   // TODO: The return value of the xml parser is not checked.
-  stanzaParser_.Parse(bytes, len, false);
+  stanza_parser_.Parse(bytes, len, false);
 
   return XMPP_RETURN_OK;
 }
 
-XmppReturnStatus
-XmppEngineImpl::ConnectionClosed(int subcode) {
+XmppReturnStatus XmppEngineImpl::ConnectionClosed(int subcode) {
   if (state_ != STATE_CLOSED) {
     EnterExit ee(this);
     // If told that connection closed and not already closed,
@@ -129,17 +124,16 @@
   return XMPP_RETURN_OK;
 }
 
-XmppReturnStatus
-XmppEngineImpl::SetTls(TlsOptions useTls) {
+XmppReturnStatus XmppEngineImpl::SetTls(TlsOptions useTls) {
   if (state_ != STATE_START)
     return XMPP_RETURN_BADSTATE;
   tls_option_ = useTls;
   return XMPP_RETURN_OK;
 }
 
-XmppReturnStatus
-XmppEngineImpl::SetTlsServer(const std::string & tls_server_hostname,
-                             const std::string & tls_server_domain) {
+XmppReturnStatus XmppEngineImpl::SetTlsServer(
+    const std::string& tls_server_hostname,
+    const std::string& tls_server_domain) {
   if (state_ != STATE_START)
     return XMPP_RETURN_BADSTATE;
 
@@ -149,13 +143,11 @@
   return XMPP_RETURN_OK;
 }
 
-TlsOptions
-XmppEngineImpl::GetTls() {
+TlsOptions XmppEngineImpl::GetTls() {
   return tls_option_;
 }
 
-XmppReturnStatus
-XmppEngineImpl::SetUser(const Jid & jid) {
+XmppReturnStatus XmppEngineImpl::SetUser(const Jid& jid) {
   if (state_ != STATE_START)
     return XMPP_RETURN_BADSTATE;
 
@@ -164,13 +156,11 @@
   return XMPP_RETURN_OK;
 }
 
-const Jid &
-XmppEngineImpl::GetUser() {
+const Jid& XmppEngineImpl::GetUser() {
   return user_jid_;
 }
 
-XmppReturnStatus
-XmppEngineImpl::SetSaslHandler(SaslHandler * sasl_handler) {
+XmppReturnStatus XmppEngineImpl::SetSaslHandler(SaslHandler* sasl_handler) {
   if (state_ != STATE_START)
     return XMPP_RETURN_BADSTATE;
 
@@ -178,8 +168,8 @@
   return XMPP_RETURN_OK;
 }
 
-XmppReturnStatus
-XmppEngineImpl::SetRequestedResource(const std::string & resource) {
+XmppReturnStatus XmppEngineImpl::SetRequestedResource(
+    const std::string& resource) {
   if (state_ != STATE_START)
     return XMPP_RETURN_BADSTATE;
 
@@ -188,14 +178,13 @@
   return XMPP_RETURN_OK;
 }
 
-const std::string &
-XmppEngineImpl::GetRequestedResource() {
+const std::string& XmppEngineImpl::GetRequestedResource() {
   return requested_resource_;
 }
 
-XmppReturnStatus
-XmppEngineImpl::AddStanzaHandler(XmppStanzaHandler * stanza_handler,
-                                 XmppEngine::HandlerLevel level) {
+XmppReturnStatus XmppEngineImpl::AddStanzaHandler(
+    XmppStanzaHandler* stanza_handler,
+    XmppEngine::HandlerLevel level) {
   if (state_ == STATE_CLOSED)
     return XMPP_RETURN_BADSTATE;
 
@@ -204,9 +193,8 @@
   return XMPP_RETURN_OK;
 }
 
-XmppReturnStatus
-XmppEngineImpl::RemoveStanzaHandler(XmppStanzaHandler * stanza_handler) {
-
+XmppReturnStatus XmppEngineImpl::RemoveStanzaHandler(
+    XmppStanzaHandler* stanza_handler) {
   bool found = false;
 
   for (int level = 0; level < HL_COUNT; level += 1) {
@@ -221,15 +209,13 @@
     }
   }
 
-  if (!found) {
+  if (!found)
     return XMPP_RETURN_BADARGUMENT;
-  }
 
   return XMPP_RETURN_OK;
 }
 
-XmppReturnStatus
-XmppEngineImpl::Connect() {
+XmppReturnStatus XmppEngineImpl::Connect() {
   if (state_ != STATE_START)
     return XMPP_RETURN_BADSTATE;
 
@@ -246,8 +232,7 @@
   return XMPP_RETURN_OK;
 }
 
-XmppReturnStatus
-XmppEngineImpl::SendStanza(const XmlElement * element) {
+XmppReturnStatus XmppEngineImpl::SendStanza(const XmlElement* element) {
   if (state_ == STATE_CLOSED)
     return XMPP_RETURN_BADSTATE;
 
@@ -264,8 +249,7 @@
   return XMPP_RETURN_OK;
 }
 
-XmppReturnStatus
-XmppEngineImpl::SendRaw(const std::string & text) {
+XmppReturnStatus XmppEngineImpl::SendRaw(const std::string& text) {
   if (state_ == STATE_CLOSED || login_task_.get())
     return XMPP_RETURN_BADSTATE;
 
@@ -276,16 +260,13 @@
   return XMPP_RETURN_OK;
 }
 
-std::string
-XmppEngineImpl::NextId() {
+std::string XmppEngineImpl::NextId() {
   std::stringstream ss;
   ss << next_id_++;
   return ss.str();
 }
 
-XmppReturnStatus
-XmppEngineImpl::Disconnect() {
-
+XmppReturnStatus XmppEngineImpl::Disconnect() {
   if (state_ != STATE_CLOSED) {
     EnterExit ee(this);
     if (state_ == STATE_OPEN)
@@ -296,14 +277,13 @@
   return XMPP_RETURN_OK;
 }
 
-void
-XmppEngineImpl::IncomingStart(const XmlElement * pelStart) {
+void XmppEngineImpl::IncomingStart(const XmlElement* start) {
   if (HasError() || raised_reset_)
     return;
 
   if (login_task_.get()) {
     // start-stream should go to login task
-    login_task_->IncomingStanza(pelStart, true);
+    login_task_->IncomingStanza(start, true);
     if (login_task_->IsDone())
       login_task_.reset();
   }
@@ -313,8 +293,7 @@
   }
 }
 
-void
-XmppEngineImpl::IncomingStanza(const XmlElement * stanza) {
+void XmppEngineImpl::IncomingStanza(const XmlElement* stanza) {
   if (HasError() || raised_reset_)
     return;
 
@@ -338,7 +317,7 @@
     for (int level = HL_SINGLE; level <= HL_ALL; level += 1) {
       for (size_t i = 0; i < stanza_handlers_[level]->size(); i += 1) {
         if ((*stanza_handlers_[level])[i]->HandleStanza(stanza))
-          goto Handled;
+          return;
       }
     }
 
@@ -346,29 +325,24 @@
     // Only do this for IQ stanzas as messages should probably just be dropped
     // and presence stanzas should certainly be dropped.
     std::string type = stanza->Attr(QN_TYPE);
-    if (stanza->Name() == QN_IQ && 
+    if (stanza->Name() == QN_IQ &&
         !(type == "error" || type == "result")) {
       SendStanzaError(stanza, XSE_FEATURE_NOT_IMPLEMENTED, STR_EMPTY);
     }
   }
-  Handled:
-    ; // handled - we're done
 }
 
-void
-XmppEngineImpl::IncomingEnd(bool isError) {
+void XmppEngineImpl::IncomingEnd(bool isError) {
   if (HasError() || raised_reset_)
     return;
 
   SignalError(isError ? ERROR_XML : ERROR_DOCUMENT_CLOSED, 0);
 }
 
-void
-XmppEngineImpl::InternalSendStart(const std::string & to) {
+void XmppEngineImpl::InternalSendStart(const std::string& to) {
   std::string hostname = tls_server_hostname_;
-  if (hostname.empty()) {
+  if (hostname.empty())
     hostname = to;
-  }
 
   // If not language is specified, the spec says use *
   std::string lang = lang_;
@@ -385,60 +359,51 @@
            << "xmlns=\"jabber:client\">\r\n";
 }
 
-void
-XmppEngineImpl::InternalSendStanza(const XmlElement * element) {
+void XmppEngineImpl::InternalSendStanza(const XmlElement* element) {
   // It should really never be necessary to set a FROM attribute on a stanza.
   // It is implied by the bind on the stream and if you get it wrong
   // (by flipping from/to on a message?) the server will close the stream.
   ASSERT(!element->HasAttr(QN_FROM));
 
-  // TODO: consider caching the XmlPrinter
-  XmlPrinter::PrintXml(output_.get(), element,
-            XMPP_CLIENT_NAMESPACES, XMPP_CLIENT_NAMESPACES_LEN);
+  XmlPrinter::PrintXml(output_.get(), element, &xmlns_stack_);
 }
 
-std::string
-XmppEngineImpl::ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) {
+std::string XmppEngineImpl::ChooseBestSaslMechanism(
+    const std::vector<std::string>& mechanisms, bool encrypted) {
   return sasl_handler_->ChooseBestSaslMechanism(mechanisms, encrypted);
 }
 
-SaslMechanism *
-XmppEngineImpl::GetSaslMechanism(const std::string & name) {
+SaslMechanism* XmppEngineImpl::GetSaslMechanism(const std::string& name) {
   return sasl_handler_->CreateSaslMechanism(name);
 }
 
-void
-XmppEngineImpl::SignalBound(const Jid & fullJid) {
+void XmppEngineImpl::SignalBound(const Jid& fullJid) {
   if (state_ == STATE_OPENING) {
     bound_jid_ = fullJid;
     state_ = STATE_OPEN;
   }
 }
 
-void
-XmppEngineImpl::SignalStreamError(const XmlElement * pelStreamError) {
+void XmppEngineImpl::SignalStreamError(const XmlElement* stream_error) {
   if (state_ != STATE_CLOSED) {
-    stream_error_.reset(new XmlElement(*pelStreamError));
+    stream_error_.reset(new XmlElement(*stream_error));
     SignalError(ERROR_STREAM, 0);
   }
 }
 
-void
-XmppEngineImpl::SignalError(Error errorCode, int subCode) {
+void XmppEngineImpl::SignalError(Error error_code, int sub_code) {
   if (state_ != STATE_CLOSED) {
-    error_code_ = errorCode;
-    subcode_ = subCode;
+    error_code_ = error_code;
+    subcode_ = sub_code;
     state_ = STATE_CLOSED;
   }
 }
 
-bool
-XmppEngineImpl::HasError() {
+bool XmppEngineImpl::HasError() {
   return error_code_ != ERROR_NONE;
 }
 
-void
-XmppEngineImpl::StartTls(const std::string & domain) {
+void XmppEngineImpl::StartTls(const std::string& domain) {
   if (output_handler_) {
     // As substitute for the real (login jid's) domain, we permit
     // verifying a tls_server_domain_ instead, if one was passed.
@@ -451,7 +416,7 @@
 }
 
 XmppEngineImpl::EnterExit::EnterExit(XmppEngineImpl* engine)
-  : engine_(engine),
+    : engine_(engine),
   state_(engine->state_),
   error_(engine->error_code_) {
   engine->engine_entered_ += 1;
@@ -482,17 +447,17 @@
    return;
 
  if (engine->raised_reset_) {
-   engine->stanzaParser_.Reset();
+   engine->stanza_parser_.Reset();
    engine->raised_reset_ = false;
  }
 
  if (engine->session_handler_) {
    if (engine->state_ != state_)
      engine->session_handler_->OnStateChange(engine->state_);
-     // Note: Handling of OnStateChange(CLOSED) should allow for the
-     // deletion of the engine, so no members should be accessed
-     // after this line.
+   // Note: Handling of OnStateChange(CLOSED) should allow for the
+   // deletion of the engine, so no members should be accessed
+   // after this line.
  }
 }
 
-}
+}  // namespace buzz
diff --git a/talk/xmpp/xmppengineimpl.h b/talk/xmpp/xmppengineimpl.h
index 931955d..1fdb2a0 100644
--- a/talk/xmpp/xmppengineimpl.h
+++ b/talk/xmpp/xmppengineimpl.h
@@ -25,8 +25,8 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef _xmppengineimpl_h_
-#define _xmppengineimpl_h_
+#ifndef TALK_XMPP_XMPPENGINEIMPL_H_
+#define TALK_XMPP_XMPPENGINEIMPL_H_
 
 #include <sstream>
 #include <vector>
@@ -50,7 +50,7 @@
 //! An application can listen for events and receive stanzas by
 //! registering an XmppStanzaHandler via AddStanzaHandler().
 class XmppEngineImpl : public XmppEngine {
-public:
+ public:
   XmppEngineImpl();
   virtual ~XmppEngineImpl();
 
@@ -60,7 +60,7 @@
   virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh);
 
   //! Provides socket input to the engine
-  virtual XmppReturnStatus HandleInput(const char * bytes, size_t len);
+  virtual XmppReturnStatus HandleInput(const char* bytes, size_t len);
 
   //! Advises the engine that the socket has closed
   virtual XmppReturnStatus ConnectionClosed(int subcode);
@@ -68,13 +68,13 @@
   // SESSION SETUP ---------------------------------------------------------
 
   //! Indicates the (bare) JID for the user to use.
-  virtual XmppReturnStatus SetUser(const Jid & jid);
+  virtual XmppReturnStatus SetUser(const Jid& jid);
 
   //! Get the login (bare) JID.
-  virtual const Jid & GetUser();
+  virtual const Jid& GetUser();
 
   //! Indicates the autentication to use.  Takes ownership of the object.
-  virtual XmppReturnStatus SetSaslHandler(SaslHandler * sasl_handler);
+  virtual XmppReturnStatus SetSaslHandler(SaslHandler* sasl_handler);
 
   //! Sets whether TLS will be used within the connection (default true).
   virtual XmppReturnStatus SetTls(TlsOptions useTls);
@@ -83,8 +83,8 @@
   //! This is for use in the case where a we want to allow a proxy to
   //! serve up its own certificate rather than one owned by the underlying
   //! domain.
-  virtual XmppReturnStatus SetTlsServer(const std::string & proxy_hostname,
-                                        const std::string & proxy_domain);
+  virtual XmppReturnStatus SetTlsServer(const std::string& proxy_hostname,
+                                        const std::string& proxy_domain);
 
   //! Gets whether TLS will be used within the connection.
   virtual TlsOptions GetTls();
@@ -95,10 +95,10 @@
   virtual XmppReturnStatus SetRequestedResource(const std::string& resource);
 
   //! Gets the request resource name.
-  virtual const std::string & GetRequestedResource();
+  virtual const std::string& GetRequestedResource();
 
   //! Sets language
-  virtual void SetLanguage(const std::string & lang) {
+  virtual void SetLanguage(const std::string& lang) {
     lang_ = lang;
   }
 
@@ -130,7 +130,7 @@
   //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM.
   //! Notice the stanza returned is owned by the XmppEngine and
   //! is deleted when the engine is destroyed.
-  virtual const XmlElement * GetStreamError() { return stream_error_.get(); }
+  virtual const XmlElement* GetStreamError() { return stream_error_.get(); }
 
   //! Closes down the connection.
   //! Sends CloseConnection to output, and disconnects and registered
@@ -150,14 +150,14 @@
   virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler);
 
   //! Sends a stanza to the server.
-  virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza);
+  virtual XmppReturnStatus SendStanza(const XmlElement* stanza);
 
   //! Sends raw text to the server
-  virtual XmppReturnStatus SendRaw(const std::string & text);
+  virtual XmppReturnStatus SendRaw(const std::string& text);
 
   //! Sends an iq to the server, and registers a callback for the result.
   //! Returns the cookie passed to the result handler.
-  virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
+  virtual XmppReturnStatus SendIq(const XmlElement* stanza,
                                   XmppIqHandler* iq_handler,
                                   XmppIqCookie* cookie);
 
@@ -169,55 +169,62 @@
   //! Forms and sends an error in response to the given stanza.
   //! Swaps to and from, sets type to "error", and adds error information
   //! based on the passed code.  Text is optional and may be STR_EMPTY.
-  virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
+  virtual XmppReturnStatus SendStanzaError(const XmlElement* pelOriginal,
                                            XmppStanzaError code,
-                                           const std::string & text);
+                                           const std::string& text);
 
   //! The fullly bound JID.
   //! This JID is only valid after binding has succeeded.  If the value
   //! is JID_NULL, the binding has not succeeded.
-  virtual const Jid & FullJid() { return bound_jid_; }
+  virtual const Jid& FullJid() { return bound_jid_; }
 
   //! The next unused iq id for this connection.
   //! Call this when building iq stanzas, to ensure that each iq
   //! gets its own unique id.
   virtual std::string NextId();
 
-private:
+ private:
   friend class XmppLoginTask;
   friend class XmppIqEntry;
 
-  void IncomingStanza(const XmlElement *pelStanza);
-  void IncomingStart(const XmlElement *pelStanza);
+  void IncomingStanza(const XmlElement *stanza);
+  void IncomingStart(const XmlElement *stanza);
   void IncomingEnd(bool isError);
 
-  void InternalSendStart(const std::string & domainName);
-  void InternalSendStanza(const XmlElement * pelStanza);
-  std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted);
-  SaslMechanism * GetSaslMechanism(const std::string & name);
-  void SignalBound(const Jid & fullJid);
-  void SignalStreamError(const XmlElement * pelStreamError);
+  void InternalSendStart(const std::string& domainName);
+  void InternalSendStanza(const XmlElement* stanza);
+  std::string ChooseBestSaslMechanism(
+      const std::vector<std::string>& mechanisms, bool encrypted);
+  SaslMechanism* GetSaslMechanism(const std::string& name);
+  void SignalBound(const Jid& fullJid);
+  void SignalStreamError(const XmlElement* streamError);
   void SignalError(Error errorCode, int subCode);
   bool HasError();
   void DeleteIqCookies();
-  bool HandleIqResponse(const XmlElement * element);
-  void StartTls(const std::string & domain);
+  bool HandleIqResponse(const XmlElement* element);
+  void StartTls(const std::string& domain);
   void RaiseReset() { raised_reset_ = true; }
 
   class StanzaParseHandler : public XmppStanzaParseHandler {
-  public:
-    StanzaParseHandler(XmppEngineImpl * outer) : outer_(outer) {}
+   public:
+    StanzaParseHandler(XmppEngineImpl* outer) : outer_(outer) {}
     virtual ~StanzaParseHandler() {}
-    virtual void StartStream(const XmlElement * pelStream)
-      { outer_->IncomingStart(pelStream); }
-    virtual void Stanza(const XmlElement * pelStanza)
-      { outer_->IncomingStanza(pelStanza); }
-    virtual void EndStream()
-      { outer_->IncomingEnd(false); }
-    virtual void XmlError()
-      { outer_->IncomingEnd(true); }
-  private:
-    XmppEngineImpl * const outer_;
+
+    virtual void StartStream(const XmlElement* stream) {
+      outer_->IncomingStart(stream);
+    }
+    virtual void Stanza(const XmlElement* stanza) {
+      outer_->IncomingStanza(stanza);
+    }
+    virtual void EndStream() {
+      outer_->IncomingEnd(false);
+    }
+    virtual void XmlError() {
+      outer_->IncomingEnd(true);
+    }
+
+   private:
+    XmppEngineImpl* const outer_;
   };
 
   class EnterExit {
@@ -234,9 +241,8 @@
   friend class StanzaParseHandler;
   friend class EnterExit;
 
-  StanzaParseHandler stanzaParseHandler_;
-  XmppStanzaParser stanzaParser_;
-
+  StanzaParseHandler stanza_parse_handler_;
+  XmppStanzaParser stanza_parser_;
 
   // state
   int engine_entered_;
@@ -260,6 +266,8 @@
   XmppOutputHandler* output_handler_;
   XmppSessionHandler* session_handler_;
 
+  XmlnsStack xmlns_stack_;
+
   typedef std::vector<XmppStanzaHandler*> StanzaHandlerVector;
   talk_base::scoped_ptr<StanzaHandlerVector> stanza_handlers_[HL_COUNT];
 
@@ -271,7 +279,6 @@
   talk_base::scoped_ptr<std::stringstream> output_;
 };
 
-}
+}  // namespace buzz
 
-
-#endif
+#endif  // TALK_XMPP_XMPPENGINEIMPL_H_