[libjingle] 0.5.2

Tom Callaway spot at fedoraproject.org
Fri Apr 1 05:25:23 UTC 2011


commit b720a4c397c0060d6b2a1de6b888653fc0a4a625
Author: Tom "spot" Callaway <tcallawa at redhat.com>
Date:   Fri Apr 1 01:26:49 2011 -0400

    0.5.2

 .gitignore                                  |    1 +
 libjingle-0.5.2-chromium12-changes.patch    | 6829 +++++++++++++++++++++++++++
 libjingle-0.5.2-compilefix.patch            |   13 +
 libjingle-0.5.2-devicemanager-alsafix.patch |   30 +
 libjingle.spec                              |   16 +-
 sources                                     |    2 +-
 6 files changed, 6887 insertions(+), 4 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 8507512..9c6c477 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 libjingle-0.3.12.tar.gz
 /libjingle-0.5.1.zip
+/libjingle-0.5.2.zip
diff --git a/libjingle-0.5.2-chromium12-changes.patch b/libjingle-0.5.2-chromium12-changes.patch
new file mode 100644
index 0000000..a888023
--- /dev/null
+++ b/libjingle-0.5.2-chromium12-changes.patch
@@ -0,0 +1,6829 @@
+diff -upN libjingle-0.5.2/talk/base/asyncpacketsocket.cc.chromium12 libjingle-0.5.2/talk/base/asyncpacketsocket.cc
+--- libjingle-0.5.2/talk/base/asyncpacketsocket.cc.chromium12	2011-01-11 19:25:48.000000000 -0500
++++ libjingle-0.5.2/talk/base/asyncpacketsocket.cc	1969-12-31 19:00:00.000000000 -0500
+@@ -1,92 +0,0 @@
+-/*
+- * libjingle
+- * Copyright 2004--2005, Google Inc.
+- *
+- * Redistribution and use in source and binary forms, with or without 
+- * modification, are permitted provided that the following conditions are met:
+- *
+- *  1. Redistributions of source code must retain the above copyright notice, 
+- *     this list of conditions and the following disclaimer.
+- *  2. Redistributions in binary form must reproduce the above copyright notice,
+- *     this list of conditions and the following disclaimer in the documentation
+- *     and/or other materials provided with the distribution.
+- *  3. The name of the author may not be used to endorse or promote products 
+- *     derived from this software without specific prior written permission.
+- *
+- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
+- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+- */
+-
+-#if defined(_MSC_VER) && _MSC_VER < 1300
+-#pragma warning(disable:4786)
+-#endif
+-
+-#include "talk/base/asyncpacketsocket.h"
+-
+-namespace talk_base {
+-
+-AsyncPacketSocket::AsyncPacketSocket(AsyncSocket* socket) : socket_(socket) {
+-}
+-
+-AsyncPacketSocket::~AsyncPacketSocket() {
+-  delete socket_;
+-}
+-
+-SocketAddress AsyncPacketSocket::GetLocalAddress() const {
+-  return socket_->GetLocalAddress();
+-}
+-
+-SocketAddress AsyncPacketSocket::GetRemoteAddress() const {
+-  return socket_->GetRemoteAddress();
+-}
+-
+-int AsyncPacketSocket::Bind(const SocketAddress& addr) {
+-  return socket_->Bind(addr);
+-}
+-
+-int AsyncPacketSocket::Connect(const SocketAddress& addr) {
+-  return socket_->Connect(addr);
+-}
+-
+-int AsyncPacketSocket::Send(const void *pv, size_t cb) {
+-  return socket_->Send(pv, cb);
+-}
+-
+-int AsyncPacketSocket::SendTo(
+-    const void *pv, size_t cb, const SocketAddress& addr) {
+-  return socket_->SendTo(pv, cb, addr);
+-}
+-
+-int AsyncPacketSocket::Close() {
+-  return socket_->Close();
+-}
+-
+-Socket::ConnState AsyncPacketSocket::GetState() const {
+-  return socket_->GetState();
+-}
+-
+-int AsyncPacketSocket::GetOption(Socket::Option opt, int* value) {
+-  return socket_->GetOption(opt, value);
+-}
+-
+-int AsyncPacketSocket::SetOption(Socket::Option opt, int value) {
+-  return socket_->SetOption(opt, value);
+-}
+-
+-int AsyncPacketSocket::GetError() const {
+-  return socket_->GetError();
+-}
+-
+-void AsyncPacketSocket::SetError(int error) {
+-  return socket_->SetError(error);
+-}
+-
+-}  // namespace talk_base
+diff -upN libjingle-0.5.2/talk/base/asyncpacketsocket.h.chromium12 libjingle-0.5.2/talk/base/asyncpacketsocket.h
+--- libjingle-0.5.2/talk/base/asyncpacketsocket.h.chromium12	2011-01-11 19:25:48.000000000 -0500
++++ libjingle-0.5.2/talk/base/asyncpacketsocket.h	2011-03-30 21:51:32.694287001 -0400
+@@ -28,38 +28,61 @@
+ #ifndef TALK_BASE_ASYNCPACKETSOCKET_H_
+ #define TALK_BASE_ASYNCPACKETSOCKET_H_
+ 
+-#include "talk/base/asyncsocket.h"
++#include "talk/base/sigslot.h"
++#include "talk/base/socket.h"
+ 
+ namespace talk_base {
+ 
+-// Provides the ability to receive packets asynchronously.  Sends are not
++// Provides the ability to receive packets asynchronously. Sends are not
+ // buffered since it is acceptable to drop packets under high load.
+ class AsyncPacketSocket : public sigslot::has_slots<> {
+  public:
+-  explicit AsyncPacketSocket(AsyncSocket* socket);
+-  virtual ~AsyncPacketSocket();
++  AsyncPacketSocket() { }
++  virtual ~AsyncPacketSocket() { }
+ 
+-  // Relevant socket methods:
+-  virtual SocketAddress GetLocalAddress() const;
+-  virtual SocketAddress GetRemoteAddress() const;
+-  virtual int Bind(const SocketAddress& addr);
+-  virtual int Connect(const SocketAddress& addr);
+-  virtual int Send(const void *pv, size_t cb);
+-  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr);
+-  virtual int Close();
+-
+-  virtual Socket::ConnState GetState() const;
+-  virtual int GetOption(Socket::Option opt, int* value);
+-  virtual int SetOption(Socket::Option opt, int value);
+-  virtual int GetError() const;
+-  virtual void SetError(int error);
+-
+-  // Emitted each time a packet is read.
+-  sigslot::signal4<const char*, size_t,
+-                   const SocketAddress&, AsyncPacketSocket*> SignalReadPacket;
++  // Returns current local address. If port or IP address is not
++  // assigned yet, then they set to 0 in the result and |allocated| is
++  // set to false. Otherwise |allocated| is set to true.
++  virtual SocketAddress GetLocalAddress(bool* allocated) const = 0;
+ 
+- protected:
+-  AsyncSocket* socket_;
++  // Returns remote address. Returns zeroes if this is not a client TCP socket.
++  virtual SocketAddress GetRemoteAddress() const = 0;
++
++  // Send a packet.
++  virtual int Send(const void *pv, size_t cb) = 0;
++  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr) = 0;
++
++  // Close the socket.
++  virtual int Close() = 0;
++
++  // Returns current state of the socket.
++  virtual Socket::ConnState GetState() const = 0;
++
++  // Get/set options.
++  virtual int GetOption(Socket::Option opt, int* value) = 0;
++  virtual int SetOption(Socket::Option opt, int value) = 0;
++
++  // Get/Set current error.
++  // TODO: Do we really need SetError() here?
++  virtual int GetError() const = 0;
++  virtual void SetError(int error) = 0;
++
++  // Emitted after address for the socket is allocated.
++  sigslot::signal2<AsyncPacketSocket*, const SocketAddress&> SignalAddressReady;
++
++  // Emitted each time a packet is read. Used only for UDP and
++  // connected TCP sockets.
++  sigslot::signal4<AsyncPacketSocket*, const char*, size_t,
++                   const SocketAddress&> SignalReadPacket;
++
++  // Used only for connected TCP sockets.
++  sigslot::signal1<AsyncPacketSocket*> SignalConnect;
++  sigslot::signal2<AsyncPacketSocket*, int> SignalClose;
++
++  // Used only for listening TCP sockets.
++  sigslot::signal2<AsyncPacketSocket*, AsyncPacketSocket*> SignalNewConnection;
++
++ private:
+   DISALLOW_EVIL_CONSTRUCTORS(AsyncPacketSocket);
+ };
+ 
+diff -upN libjingle-0.5.2/talk/base/asynctcpsocket.cc.chromium12 libjingle-0.5.2/talk/base/asynctcpsocket.cc
+--- libjingle-0.5.2/talk/base/asynctcpsocket.cc.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/asynctcpsocket.cc	2011-03-30 21:51:32.694287001 -0400
+@@ -39,20 +39,30 @@
+ 
+ namespace talk_base {
+ 
+-const size_t MAX_PACKET_SIZE = 64 * 1024;
++static const size_t MAX_PACKET_SIZE = 64 * 1024;
+ 
+ typedef uint16 PacketLength;
+-const size_t PKT_LEN_SIZE = sizeof(PacketLength);
++static const size_t PKT_LEN_SIZE = sizeof(PacketLength);
+ 
+-const size_t BUF_SIZE = MAX_PACKET_SIZE + PKT_LEN_SIZE;
++static const size_t BUF_SIZE = MAX_PACKET_SIZE + PKT_LEN_SIZE;
+ 
+-AsyncTCPSocket* AsyncTCPSocket::Create(SocketFactory* factory) {
++static const int LISTEN_BACKLOG = 5;
++
++AsyncTCPSocket* AsyncTCPSocket::Create(SocketFactory* factory, bool listen) {
+   AsyncSocket* sock = factory->CreateAsyncSocket(SOCK_STREAM);
+-  return (sock) ? new AsyncTCPSocket(sock) : NULL;
++  // This will still return a socket even if we failed to listen on
++  // it. It is neccessary because even if we can't accept new
++  // connections on this socket, the corresponding port is still
++  // useful for outgoing connections.
++  //
++  // TODO: It might be better to pass listen() error to the
++  // upper layer and let it handle the problem.
++  return (sock) ? new AsyncTCPSocket(sock, listen) : NULL;
+ }
+ 
+-AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket)
+-    : AsyncPacketSocket(socket),
++AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket, bool listen)
++    : socket_(socket),
++      listen_(listen),
+       insize_(BUF_SIZE),
+       inpos_(0),
+       outsize_(BUF_SIZE),
+@@ -60,11 +70,17 @@ AsyncTCPSocket::AsyncTCPSocket(AsyncSock
+   inbuf_ = new char[insize_];
+   outbuf_ = new char[outsize_];
+ 
+-  ASSERT(socket_ != NULL);
++  ASSERT(socket_.get() != NULL);
+   socket_->SignalConnectEvent.connect(this, &AsyncTCPSocket::OnConnectEvent);
+   socket_->SignalReadEvent.connect(this, &AsyncTCPSocket::OnReadEvent);
+   socket_->SignalWriteEvent.connect(this, &AsyncTCPSocket::OnWriteEvent);
+   socket_->SignalCloseEvent.connect(this, &AsyncTCPSocket::OnCloseEvent);
++
++  if (listen_) {
++    if (socket_->Listen(LISTEN_BACKLOG) < 0) {
++      LOG(LS_ERROR) << "Listen() failed with error " << socket_->GetError();
++    }
++  }
+ }
+ 
+ AsyncTCPSocket::~AsyncTCPSocket() {
+@@ -72,6 +88,16 @@ AsyncTCPSocket::~AsyncTCPSocket() {
+   delete [] outbuf_;
+ }
+ 
++SocketAddress AsyncTCPSocket::GetLocalAddress(bool* allocated) const {
++  if (allocated)
++    *allocated = true;
++  return socket_->GetLocalAddress();
++}
++
++SocketAddress AsyncTCPSocket::GetRemoteAddress() const {
++  return socket_->GetRemoteAddress();
++}
++
+ int AsyncTCPSocket::Send(const void *pv, size_t cb) {
+   if (cb > MAX_PACKET_SIZE) {
+     socket_->SetError(EMSGSIZE);
+@@ -108,6 +134,30 @@ int AsyncTCPSocket::SendTo(const void *p
+   return -1;
+ }
+ 
++int AsyncTCPSocket::Close() {
++  return socket_->Close();
++}
++
++Socket::ConnState AsyncTCPSocket::GetState() const {
++  return socket_->GetState();
++}
++
++int AsyncTCPSocket::GetOption(Socket::Option opt, int* value) {
++  return socket_->GetOption(opt, value);
++}
++
++int AsyncTCPSocket::SetOption(Socket::Option opt, int value) {
++  return socket_->SetOption(opt, value);
++}
++
++int AsyncTCPSocket::GetError() const {
++  return socket_->GetError();
++}
++
++void AsyncTCPSocket::SetError(int error) {
++  return socket_->SetError(error);
++}
++
+ int AsyncTCPSocket::SendRaw(const void * pv, size_t cb) {
+   if (outpos_ + cb > outsize_) {
+     socket_->SetError(EMSGSIZE);
+@@ -134,7 +184,7 @@ void AsyncTCPSocket::ProcessInput(char *
+     if (len < PKT_LEN_SIZE + pkt_len)
+       return;
+ 
+-    SignalReadPacket(data + PKT_LEN_SIZE, pkt_len, remote_addr, this);
++    SignalReadPacket(this, data + PKT_LEN_SIZE, pkt_len, remote_addr);
+ 
+     len -= PKT_LEN_SIZE + pkt_len;
+     if (len > 0) {
+@@ -165,30 +215,46 @@ void AsyncTCPSocket::OnConnectEvent(Asyn
+ }
+ 
+ void AsyncTCPSocket::OnReadEvent(AsyncSocket* socket) {
+-  ASSERT(socket == socket_);
++  ASSERT(socket_.get() == socket);
+ 
+-  int len = socket_->Recv(inbuf_ + inpos_, insize_ - inpos_);
+-  if (len < 0) {
+-    // TODO: Do something better like forwarding the error to the user.
+-    if (!socket_->IsBlocking()) {
+-      LOG_ERR(LS_ERROR) << "recvfrom";
++  if (listen_) {
++    talk_base::SocketAddress address;
++    talk_base::AsyncSocket* new_socket = socket->Accept(&address);
++    if (!new_socket) {
++      // TODO: Do something better like forwarding the error
++      // to the user.
++      LOG(LS_ERROR) << "TCP accept failed with error " << socket_->GetError();
++      return;
+     }
+-    return;
+-  }
+ 
+-  inpos_ += len;
++    SignalNewConnection(this, new AsyncTCPSocket(new_socket, false));
+ 
+-  ProcessInput(inbuf_, inpos_);
++    // Prime a read event in case data is waiting.
++    new_socket->SignalReadEvent(new_socket);
++  } else {
++    int len = socket_->Recv(inbuf_ + inpos_, insize_ - inpos_);
++    if (len < 0) {
++      // TODO: Do something better like forwarding the error to the user.
++      if (!socket_->IsBlocking()) {
++        LOG(LS_ERROR) << "Recv() returned error: " << socket_->GetError();
++      }
++      return;
++    }
+ 
+-  if (inpos_ >= insize_) {
+-    LOG(INFO) << "input buffer overflow";
+-    ASSERT(false);
+-    inpos_ = 0;
++    inpos_ += len;
++
++    ProcessInput(inbuf_, inpos_);
++
++    if (inpos_ >= insize_) {
++      LOG(LS_ERROR) << "input buffer overflow";
++      ASSERT(false);
++      inpos_ = 0;
++    }
+   }
+ }
+ 
+ void AsyncTCPSocket::OnWriteEvent(AsyncSocket* socket) {
+-  ASSERT(socket == socket_);
++  ASSERT(socket_.get() == socket);
+ 
+   if (outpos_ > 0) {
+     Flush();
+diff -upN libjingle-0.5.2/talk/base/asynctcpsocket.h.chromium12 libjingle-0.5.2/talk/base/asynctcpsocket.h
+--- libjingle-0.5.2/talk/base/asynctcpsocket.h.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/asynctcpsocket.h	2011-03-30 21:51:32.695287001 -0400
+@@ -29,6 +29,7 @@
+ #define TALK_BASE_ASYNCTCPSOCKET_H_
+ 
+ #include "talk/base/asyncpacketsocket.h"
++#include "talk/base/scoped_ptr.h"
+ #include "talk/base/socketfactory.h"
+ 
+ namespace talk_base {
+@@ -38,15 +39,21 @@ namespace talk_base {
+ // buffer them in user space.
+ class AsyncTCPSocket : public AsyncPacketSocket {
+  public:
+-  static AsyncTCPSocket* Create(SocketFactory* factory);
+-  explicit AsyncTCPSocket(AsyncSocket* socket);
++  static AsyncTCPSocket* Create(SocketFactory* factory, bool listen);
++  explicit AsyncTCPSocket(AsyncSocket* socket, bool listen);
+   virtual ~AsyncTCPSocket();
+ 
+-  virtual int Send(const void* pv, size_t cb);
+-  virtual int SendTo(const void* pv, size_t cb, const SocketAddress& addr);
+-
+-  sigslot::signal1<AsyncTCPSocket*> SignalConnect;
+-  sigslot::signal2<AsyncTCPSocket*, int> SignalClose;
++  virtual SocketAddress GetLocalAddress(bool* allocated) const;
++  virtual SocketAddress GetRemoteAddress() const;
++  virtual int Send(const void *pv, size_t cb);
++  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr);
++  virtual int Close();
++
++  virtual Socket::ConnState GetState() const;
++  virtual int GetOption(Socket::Option opt, int* value);
++  virtual int SetOption(Socket::Option opt, int value);
++  virtual int GetError() const;
++  virtual void SetError(int error);
+ 
+  protected:
+   int SendRaw(const void* pv, size_t cb);
+@@ -61,8 +68,12 @@ class AsyncTCPSocket : public AsyncPacke
+   void OnWriteEvent(AsyncSocket* socket);
+   void OnCloseEvent(AsyncSocket* socket, int error);
+ 
++  scoped_ptr<AsyncSocket> socket_;
++  bool listen_;
+   char* inbuf_, * outbuf_;
+   size_t insize_, inpos_, outsize_, outpos_;
++
++  DISALLOW_EVIL_CONSTRUCTORS(AsyncTCPSocket);
+ };
+ 
+ }  // namespace talk_base
+diff -upN libjingle-0.5.2/talk/base/asyncudpsocket.cc.chromium12 libjingle-0.5.2/talk/base/asyncudpsocket.cc
+--- libjingle-0.5.2/talk/base/asyncudpsocket.cc.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/asyncudpsocket.cc	2011-03-30 21:51:32.695287001 -0400
+@@ -34,11 +34,23 @@
+ 
+ namespace talk_base {
+ 
+-const int BUF_SIZE = 64 * 1024;
++static const int BUF_SIZE = 64 * 1024;
++
++AsyncUDPSocket* AsyncUDPSocket::Create(SocketFactory* factory,
++                                       const SocketAddress& address) {
++  scoped_ptr<AsyncSocket> socket(factory->CreateAsyncSocket(SOCK_DGRAM));
++  if (!socket.get())
++    return NULL;
++  if (socket->Bind(address)) {
++    LOG(LS_INFO) << "Failed to bind UDP socket " << socket->GetError();
++    return NULL;
++  }
++  return new AsyncUDPSocket(socket.release());
++}
+ 
+ AsyncUDPSocket::AsyncUDPSocket(AsyncSocket* socket)
+-    : AsyncPacketSocket(socket) {
+-  ASSERT(socket_ != NULL);
++    : socket_(socket) {
++  ASSERT(socket_.get() != NULL);
+   size_ = BUF_SIZE;
+   buf_ = new char[size_];
+ 
+@@ -50,8 +62,51 @@ AsyncUDPSocket::~AsyncUDPSocket() {
+   delete [] buf_;
+ }
+ 
++SocketAddress AsyncUDPSocket::GetLocalAddress(bool* allocated) const {
++  if (allocated)
++    *allocated = true;
++  return socket_->GetLocalAddress();
++}
++
++SocketAddress AsyncUDPSocket::GetRemoteAddress() const {
++  return socket_->GetRemoteAddress();
++}
++
++int AsyncUDPSocket::Send(const void *pv, size_t cb) {
++  return socket_->Send(pv, cb);
++}
++
++int AsyncUDPSocket::SendTo(
++    const void *pv, size_t cb, const SocketAddress& addr) {
++  return socket_->SendTo(pv, cb, addr);
++}
++
++int AsyncUDPSocket::Close() {
++  return socket_->Close();
++}
++
++Socket::ConnState AsyncUDPSocket::GetState() const {
++  return socket_->GetState();
++}
++
++int AsyncUDPSocket::GetOption(Socket::Option opt, int* value) {
++  return socket_->GetOption(opt, value);
++}
++
++int AsyncUDPSocket::SetOption(Socket::Option opt, int value) {
++  return socket_->SetOption(opt, value);
++}
++
++int AsyncUDPSocket::GetError() const {
++  return socket_->GetError();
++}
++
++void AsyncUDPSocket::SetError(int error) {
++  return socket_->SetError(error);
++}
++
+ void AsyncUDPSocket::OnReadEvent(AsyncSocket* socket) {
+-  ASSERT(socket == socket_);
++  ASSERT(socket_.get() == socket);
+ 
+   SocketAddress remote_addr;
+   int len = socket_->RecvFrom(buf_, size_, &remote_addr);
+@@ -68,7 +123,7 @@ void AsyncUDPSocket::OnReadEvent(AsyncSo
+ 
+   // TODO: Make sure that we got all of the packet.
+   // If we did not, then we should resize our buffer to be large enough.
+-  SignalReadPacket(buf_, (size_t)len, remote_addr, this);
++  SignalReadPacket(this, buf_, (size_t)len, remote_addr);
+ }
+ 
+ }  // namespace talk_base
+diff -upN libjingle-0.5.2/talk/base/asyncudpsocket.h.chromium12 libjingle-0.5.2/talk/base/asyncudpsocket.h
+--- libjingle-0.5.2/talk/base/asyncudpsocket.h.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/asyncudpsocket.h	2011-03-30 21:51:32.695287001 -0400
+@@ -29,6 +29,7 @@
+ #define TALK_BASE_ASYNCUDPSOCKET_H_
+ 
+ #include "talk/base/asyncpacketsocket.h"
++#include "talk/base/scoped_ptr.h"
+ #include "talk/base/socketfactory.h"
+ 
+ namespace talk_base {
+@@ -39,26 +40,32 @@ class AsyncUDPSocket : public AsyncPacke
+  public:
+   // Creates a new socket for sending asynchronous UDP packets using an
+   // asynchronous socket from the given factory.
+-  static AsyncUDPSocket* Create(SocketFactory* factory) {
+-    AsyncSocket* sock = factory->CreateAsyncSocket(SOCK_DGRAM);
+-    return (sock) ? new AsyncUDPSocket(sock) : NULL;
+-  }
++  static AsyncUDPSocket* Create(SocketFactory* factory,
++                                const SocketAddress& address);
+   explicit AsyncUDPSocket(AsyncSocket* socket);
+   virtual ~AsyncUDPSocket();
+ 
++  virtual SocketAddress GetLocalAddress(bool* allocated) const;
++  virtual SocketAddress GetRemoteAddress() const;
++  virtual int Send(const void *pv, size_t cb);
++  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr);
++  virtual int Close();
++
++  virtual Socket::ConnState GetState() const;
++  virtual int GetOption(Socket::Option opt, int* value);
++  virtual int SetOption(Socket::Option opt, int value);
++  virtual int GetError() const;
++  virtual void SetError(int error);
++
+  private:
+   // Called when the underlying socket is ready to be read from.
+   void OnReadEvent(AsyncSocket* socket);
+ 
++  scoped_ptr<AsyncSocket> socket_;
+   char* buf_;
+   size_t size_;
+ };
+ 
+-// TODO: This is now deprecated. Remove it.
+-inline AsyncUDPSocket* CreateAsyncUDPSocket(SocketFactory* factory) {
+-  return AsyncUDPSocket::Create(factory);
+-}
+-
+ }  // namespace talk_base
+ 
+ #endif  // TALK_BASE_ASYNCUDPSOCKET_H_
+diff -upN libjingle-0.5.2/talk/base/basicpacketsocketfactory.cc.chromium12 libjingle-0.5.2/talk/base/basicpacketsocketfactory.cc
+--- libjingle-0.5.2/talk/base/basicpacketsocketfactory.cc.chromium12	2011-03-30 21:51:32.695287001 -0400
++++ libjingle-0.5.2/talk/base/basicpacketsocketfactory.cc	2011-03-30 21:51:32.695287001 -0400
+@@ -0,0 +1,159 @@
++/*
++ * libjingle
++ * Copyright 2011, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice,
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "talk/base/basicpacketsocketfactory.h"
++
++#include "talk/base/asyncudpsocket.h"
++#include "talk/base/asynctcpsocket.h"
++#include "talk/base/logging.h"
++#include "talk/base/socketadapters.h"
++#include "talk/base/thread.h"
++
++namespace talk_base {
++
++BasicPacketSocketFactory::BasicPacketSocketFactory(
++    Thread* thread)
++    : thread_(thread),
++      socket_factory_(NULL) {
++}
++
++BasicPacketSocketFactory::BasicPacketSocketFactory(
++    SocketFactory* socket_factory)
++    : thread_(NULL),
++      socket_factory_(socket_factory) {
++}
++
++BasicPacketSocketFactory::~BasicPacketSocketFactory() {
++}
++
++AsyncPacketSocket* BasicPacketSocketFactory::CreateUdpSocket(
++    const SocketAddress& address, int min_port, int max_port) {
++  // UDP sockets are simple.
++  talk_base::AsyncSocket* socket =
++      socket_factory()->CreateAsyncSocket(SOCK_DGRAM);
++  if (!socket) {
++    return NULL;
++  }
++  if (BindSocket(socket, address, min_port, max_port) < 0) {
++    LOG(LS_ERROR) << "UDP bind failed with error "
++                    << socket->GetError();
++    delete socket;
++    return NULL;
++  }
++  return new talk_base::AsyncUDPSocket(socket);
++}
++
++AsyncPacketSocket* BasicPacketSocketFactory::CreateServerTcpSocket(
++    const SocketAddress& local_address, int min_port, int max_port,
++    bool listen, bool ssl) {
++  talk_base::AsyncSocket* socket =
++      socket_factory()->CreateAsyncSocket(SOCK_STREAM);
++  if (!socket) {
++    return NULL;
++  }
++
++  if (BindSocket(socket, local_address, min_port, max_port) < 0) {
++    LOG(LS_ERROR) << "TCP bind failed with error "
++                  << socket->GetError();
++    delete socket;
++    return NULL;
++  }
++
++  // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket.
++  if (ssl) {
++    socket = new talk_base::AsyncSSLSocket(socket);
++  }
++
++  return new talk_base::AsyncTCPSocket(socket, true);
++}
++
++AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket(
++    const SocketAddress& local_address, const SocketAddress& remote_address,
++    const ProxyInfo& proxy_info, const std::string& user_agent, bool ssl) {
++  talk_base::AsyncSocket* socket =
++      socket_factory()->CreateAsyncSocket(SOCK_STREAM);
++  if (!socket) {
++    return NULL;
++  }
++
++  if (BindSocket(socket, local_address, 0, 0) < 0) {
++    LOG(LS_ERROR) << "TCP bind failed with error "
++                  << socket->GetError();
++    delete socket;
++    return NULL;
++  }
++
++  // If using a proxy, wrap the socket in a proxy socket.
++  if (proxy_info.type == talk_base::PROXY_SOCKS5) {
++    socket = new talk_base::AsyncSocksProxySocket(
++        socket, proxy_info.address, proxy_info.username, proxy_info.password);
++  } else if (proxy_info.type == talk_base::PROXY_HTTPS) {
++    socket = new talk_base::AsyncHttpsProxySocket(
++        socket, user_agent, proxy_info.address,
++        proxy_info.username, proxy_info.password);
++  }
++
++  // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket.
++  if (ssl) {
++    socket = new talk_base::AsyncSSLSocket(socket);
++  }
++
++  if (socket->Connect(remote_address) < 0) {
++    LOG(LS_ERROR) << "TCP connect failed with error "
++                  << socket->GetError();
++    delete socket;
++    return NULL;
++  }
++
++  // Finally, wrap that socket in a TCP packet socket.
++  return new talk_base::AsyncTCPSocket(socket, false);
++}
++
++int BasicPacketSocketFactory::BindSocket(
++    AsyncSocket* socket, const SocketAddress& local_address,
++    int min_port, int max_port) {
++  int ret = -1;
++  if (min_port == 0 && max_port == 0) {
++    // If there's no port range, let the OS pick a port for us.
++    ret = socket->Bind(local_address);
++  } 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));
++    }
++  }
++  return ret;
++}
++
++SocketFactory* BasicPacketSocketFactory::socket_factory() {
++  if (thread_)
++    return thread_->socketserver();
++  else
++    return socket_factory_;
++}
++
++}  // namespace talk_base
+diff -upN libjingle-0.5.2/talk/base/basicpacketsocketfactory.h.chromium12 libjingle-0.5.2/talk/base/basicpacketsocketfactory.h
+--- libjingle-0.5.2/talk/base/basicpacketsocketfactory.h.chromium12	2011-03-30 21:51:32.696287001 -0400
++++ libjingle-0.5.2/talk/base/basicpacketsocketfactory.h	2011-03-30 21:51:32.696287001 -0400
+@@ -0,0 +1,67 @@
++/*
++ * libjingle
++ * Copyright 2011, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice,
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef TALK_BASE_BASICPACKETSOCKETFACTORY_H_
++#define TALK_BASE_BASICPACKETSOCKETFACTORY_H_
++
++#include "talk/base/asyncsocket.h"
++#include "talk/base/packetsocketfactory.h"
++
++namespace talk_base {
++
++class AsyncSocket;
++class SocketFactory;
++class Thread;
++
++class BasicPacketSocketFactory : public PacketSocketFactory {
++ public:
++  explicit BasicPacketSocketFactory(Thread* thread);
++  explicit BasicPacketSocketFactory(SocketFactory* socket_factory);
++  virtual ~BasicPacketSocketFactory();
++
++  virtual AsyncPacketSocket* CreateUdpSocket(
++      const SocketAddress& local_address, int min_port, int max_port);
++  virtual AsyncPacketSocket* CreateServerTcpSocket(
++      const SocketAddress& local_address, int min_port, int max_port,
++      bool listen, bool ssl);
++  virtual AsyncPacketSocket* CreateClientTcpSocket(
++      const SocketAddress& local_address, const SocketAddress& remote_address,
++      const ProxyInfo& proxy_info, const std::string& user_agent, bool ssl);
++
++ private:
++  int BindSocket(AsyncSocket* socket, const SocketAddress& local_address,
++                 int min_port, int max_port);
++
++  SocketFactory* socket_factory();
++
++  Thread* thread_;
++  SocketFactory* socket_factory_;
++};
++
++}  // namespace talk_base
++
++#endif  // TALK_BASE_BASICPACKETSOCKETFACTORY_H_
+diff -upN libjingle-0.5.2/talk/base/basictypes.h.chromium12 libjingle-0.5.2/talk/base/basictypes.h
+--- libjingle-0.5.2/talk/base/basictypes.h.chromium12	2011-03-30 21:51:32.681287001 -0400
++++ libjingle-0.5.2/talk/base/basictypes.h	2011-03-30 21:51:32.696287001 -0400
+@@ -1,6 +1,6 @@
+ /*
+  * libjingle
+- * Copyright 2004--2005, Google Inc.
++ * Copyright 2011, Google Inc.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions are met:
+@@ -97,6 +97,12 @@ extern "C++" {
+   const int kForever = -1;
+ }
+ 
++// Detect compiler is for x86 or x64.
++#if defined(__x86_64__) || defined(_M_X64) || \
++    defined(__i386__) || defined(_M_IX86)
++#define CPU_X86 1
++#endif
++
+ #ifdef WIN32
+ #define alignof(t) __alignof(t)
+ #else  // !WIN32
+diff -upN libjingle-0.5.2/talk/base/linux.cc.chromium12 libjingle-0.5.2/talk/base/linux.cc
+--- libjingle-0.5.2/talk/base/linux.cc.chromium12	2011-03-30 21:51:32.691287001 -0400
++++ libjingle-0.5.2/talk/base/linux.cc	2011-03-30 21:51:32.696287001 -0400
+@@ -1,6 +1,30 @@
+-// Copyright 2008 Google Inc. All Rights Reserved.
++/*
++ * libjingle
++ * Copyright 2011, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice,
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
+ 
+-//
+ #include "talk/base/linux.h"
+ 
+ #ifdef LINUX
+@@ -25,25 +49,50 @@ ProcCpuInfo::~ProcCpuInfo() {
+ 
+ bool ProcCpuInfo::LoadFromSystem() {
+   ConfigParser procfs;
+-  if (!procfs.Open(kCpuInfoFile))
++  if (!procfs.Open(kCpuInfoFile)) {
+     return false;
++  }
+   return procfs.Parse(&cpu_info_);
+ };
+ 
+ bool ProcCpuInfo::GetNumCpus(int *num) {
+-  if (cpu_info_.size() == 0)
++  if (cpu_info_.size() == 0) {
+     return false;
++  }
+   *num = cpu_info_.size();
+   return true;
+ }
+ 
++bool ProcCpuInfo::GetNumPhysicalCpus(int *num) {
++  if (cpu_info_.size() == 0) {
++    return false;
++  }
++  int total_cores = 0;
++  int physical_id_prev = -1;
++  int cpus = static_cast<int>(cpu_info_.size());
++  for (int i = 0; i < cpus; ++i) {
++    int physical_id;
++    if (GetCpuIntValue(i, "physical id", &physical_id)) {
++      if (physical_id != physical_id_prev) {
++        physical_id_prev = physical_id;
++        int cores;
++        if (GetCpuIntValue(i, "cpu cores", &cores)) {
++          total_cores += cores;
++        }
++      }
++    }
++  }
++  return total_cores;
++}
++
+ bool ProcCpuInfo::GetCpuStringValue(int cpu_id, const std::string& key,
+                                     std::string *result) {
+   if (cpu_id >= static_cast<int>(cpu_info_.size()))
+     return false;
+   ConfigParser::SimpleMap::iterator iter = cpu_info_[cpu_id].find(key);
+-  if (iter == cpu_info_[cpu_id].end())
++  if (iter == cpu_info_[cpu_id].end()) {
+     return false;
++  }
+   *result = iter->second;
+   return true;
+ }
+@@ -67,8 +116,9 @@ ConfigParser::~ConfigParser() {}
+ 
+ bool ConfigParser::Open(const std::string& filename) {
+   FileStream *fs = new FileStream();
+-  if (!fs->Open(filename, "r"))
++  if (!fs->Open(filename, "r")) {
+     return false;
++  }
+   instream_.reset(fs);
+   return true;
+ }
+@@ -101,20 +151,24 @@ bool ConfigParser::ParseLine(std::string
+   // Parses the next line in the filestream and places the found key-value
+   // pair into key and val.
+   std::string line;
+-  if ((instream_->ReadLine(&line)) == EOF)
++  if ((instream_->ReadLine(&line)) == EOF) {
+     return false;
++  }
+   std::vector<std::string> tokens;
+-  if (2 != split(line, ':', &tokens))
++  if (2 != split(line, ':', &tokens)) {
+     return false;
++  }
+   // Removes whitespace at the end of Key name
+   size_t pos = tokens[0].length() - 1;
+-  while ((pos > 0) && isspace(tokens[0][pos]))
++  while ((pos > 0) && isspace(tokens[0][pos])) {
+     pos--;
++  }
+   tokens[0].erase(pos + 1);
+   // Removes whitespace at the start of value
+   pos = 0;
+-  while (pos < tokens[1].length() && isspace(tokens[1][pos]))
++  while (pos < tokens[1].length() && isspace(tokens[1][pos])) {
+     pos++;
++  }
+   tokens[1].erase(0, pos);
+   *key = tokens[0];
+   *value = tokens[1];
+diff -upN libjingle-0.5.2/talk/base/linux.h.chromium12 libjingle-0.5.2/talk/base/linux.h
+--- libjingle-0.5.2/talk/base/linux.h.chromium12	2011-03-30 21:51:32.691287001 -0400
++++ libjingle-0.5.2/talk/base/linux.h	2011-03-30 21:51:32.696287001 -0400
+@@ -1,5 +1,29 @@
+-// Copyright 2008 Google Inc. All Rights Reserved.
+-
++/*
++ * libjingle
++ * Copyright 2011, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice,
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
+ 
+ #ifndef TALK_BASE_LINUX_H_
+ #define TALK_BASE_LINUX_H_
+@@ -70,9 +94,12 @@ class ProcCpuInfo {
+   // returns false; if it succeeds, it returns true.
+   virtual bool LoadFromSystem();
+ 
+-  // Obtains the number of CPUs and places the value num.
++  // Obtains the number of logical CPU threads and places the value num.
+   virtual bool GetNumCpus(int *num);
+ 
++  // Obtains the number of physical CPU cores and places the value num.
++  virtual bool GetNumPhysicalCpus(int *num);
++
+   // Looks for the CPU proc item with the given name for the given CPU number
+   // and places the string value in result.
+   virtual bool GetCpuStringValue(int cpu_id, const std::string& key,
+diff -upN libjingle-0.5.2/talk/base/logging.cc.chromium12 libjingle-0.5.2/talk/base/logging.cc
+--- libjingle-0.5.2/talk/base/logging.cc.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/logging.cc	2011-03-30 21:51:32.697287001 -0400
+@@ -1,6 +1,6 @@
+ /*
+  * libjingle
+- * Copyright 2004--2005, Google Inc.
++ * Copyright 2011, Google Inc.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions are met:
+@@ -37,6 +37,10 @@
+ #elif defined(ANDROID)
+ #include <android/log.h>
+ static const char kLibjingle[] = "libjingle";
++// Android has a 1024 limit on log inputs. We use 60 chars as an
++// approx for the header/tag portion.
++// See android/system/core/liblog/logd_write.c
++static const int kMaxLogLineSize = 1024 - 60;
+ #endif  // OSX || ANDROID
+ 
+ #include <iostream>
+@@ -270,7 +274,7 @@ void LogMessage::ConfigureLogging(const 
+   int file_level = GetLogToStream();
+ 
+   std::vector<std::string> tokens;
+-  split(params, ' ', &tokens);
++  tokenize(params, ' ', &tokens);
+ 
+   for (size_t i = 0; i < tokens.size(); ++i) {
+     if (tokens[i].empty())
+@@ -429,6 +433,10 @@ void LogMessage::OutputToDebug(const std
+   switch (severity) {
+     case LS_SENSITIVE:
+       __android_log_write(ANDROID_LOG_INFO, kLibjingle, "SENSITIVE");
++      if (log_to_stderr) {
++        std::cerr << "SENSITIVE";
++        std::cerr.flush();
++      }
+       return;
+     case LS_VERBOSE:
+       prio = ANDROID_LOG_VERBOSE;
+@@ -445,8 +453,26 @@ void LogMessage::OutputToDebug(const std
+     default:
+       prio = ANDROID_LOG_UNKNOWN;
+   }
+-  // Use the size of the string in the format (str may have \0 in the middle).
+-  __android_log_print(prio, kLibjingle, "%.*s", str.size(), str.c_str());
++
++  int size = str.size();
++  int line = 0;
++  int idx = 0;
++  const int max_lines = size / kMaxLogLineSize + 1;
++  if (max_lines == 1) {
++    __android_log_print(prio, kLibjingle, "%.*s", size, str.c_str());
++  } else {
++    while (size > 0) {
++      const int len = std::min(size, kMaxLogLineSize);
++      // Use the size of the string in the format (str may have \0 in the
++      // middle).
++      __android_log_print(prio, kLibjingle, "[%d/%d] %.*s",
++                          line + 1, max_lines,
++                          len, str.c_str() + idx);
++      idx += len;
++      size -= len;
++      ++line;
++    }
++  }
+ #endif  // ANDROID
+   if (log_to_stderr) {
+     std::cerr << str;
+diff -upN libjingle-0.5.2/talk/base/Makefile.am.chromium12 libjingle-0.5.2/talk/base/Makefile.am
+--- libjingle-0.5.2/talk/base/Makefile.am.chromium12	2011-03-30 21:51:32.656287001 -0400
++++ libjingle-0.5.2/talk/base/Makefile.am	2011-03-30 21:53:50.328287005 -0400
+@@ -2,12 +2,12 @@ lib_LTLIBRARIES = libjinglebase.la
+ 
+ libjinglebase_la_SOURCES = asyncfile.cc \
+                             asynchttprequest.cc \
+-                            asyncpacketsocket.cc \
+                             asyncsocket.cc \
+                             asynctcpsocket.cc \
+                             asyncudpsocket.cc \
+                             autodetectproxy.cc \
+                             base64.cc \
++                            basicpacketsocketfactory.cc \
+                             bytebuffer.cc \
+                             checks.cc \
+                             common.cc \
+@@ -22,6 +22,7 @@ libjinglebase_la_SOURCES = asyncfile.cc 
+                             httpclient.cc \
+                             httpcommon.cc \
+                             httprequest.cc \
++                            latebindingsymboltable.cc \
+                             linux.cc \
+                             logging.cc \
+                             md5c.c \
+@@ -36,6 +37,7 @@ libjinglebase_la_SOURCES = asyncfile.cc 
+                             physicalsocketserver.cc \
+                             proxydetect.cc \
+                             proxyinfo.cc \
++                            ratetracker.cc \
+                             signalthread.cc \
+                             socketadapters.cc \
+                             socketaddress.cc \
+@@ -73,6 +75,7 @@ libjinglebase_include_HEADERS = asyncfil
+                             autodetectproxy.h \
+                             base64.h \
+                             basicdefs.h \
++                            basicpacketsocketfactory.h \
+                             basictypes.h \
+                             bytebuffer.h \
+                             byteorder.h \
+@@ -101,10 +104,12 @@ libjinglebase_include_HEADERS = asyncfil
+                             messagequeue.h \
+                             nethelpers.h \
+                             network.h \
++                            packetsocketfactory.h \
+                             pathutils.h \
+                             physicalsocketserver.h \
+                             proxydetect.h \
+                             proxyinfo.h \
++                            ratetracker.h \
+                             scoped_ptr.h \
+                             sec_buffer.h \
+                             signalthread.h \
+diff -upN libjingle-0.5.2/talk/base/nethelpers.cc.chromium12 libjingle-0.5.2/talk/base/nethelpers.cc
+--- libjingle-0.5.2/talk/base/nethelpers.cc.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/nethelpers.cc	2011-03-30 21:51:32.697287001 -0400
+@@ -25,6 +25,8 @@
+  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
++#include "config.h"
++
+ #include "talk/base/nethelpers.h"
+ 
+ #include "talk/base/byteorder.h"
+@@ -32,6 +34,11 @@
+ 
+ namespace talk_base {
+ 
++#if defined(LINUX) || defined(ANDROID)
++static const size_t kInitHostentLen = 1024;
++static const size_t kMaxHostentLen = kInitHostentLen * 8;
++#endif
++
+ // AsyncResolver
+ 
+ AsyncResolver::AsyncResolver() : result_(NULL), error_(0) {
+@@ -55,17 +62,16 @@ void AsyncResolver::OnWorkDone() {
+ // The functions below are used to do gethostbyname, but with an allocated
+ // instead of a static buffer.
+ hostent* SafeGetHostByName(const char* hostname, int* herrno) {
++  if (NULL == hostname || NULL == herrno) {
++    return NULL;
++  }
+   hostent* result = NULL;
+-#if defined(WIN32) || (defined(POSIX) && !defined(OSX))
++#if defined(WIN32)
+   // On Windows we have to allocate a buffer, and manually copy the hostent,
+   // along with its embedded pointers.
+   hostent* ent = gethostbyname(hostname);
+   if (!ent) {
+-#ifdef WIN32
+     *herrno = WSAGetLastError();
+-#else  // POSIX
+-    *herrno = h_errno;
+-#endif
+     return NULL;
+   }
+ 
+@@ -85,6 +91,9 @@ hostent* SafeGetHostByName(const char* h
+   total_len += sizeof(char*);
+ 
+   result = static_cast<hostent*>(malloc(total_len));
++  if (NULL == result) {
++    return NULL;
++  }
+   char* p = reinterpret_cast<char*>(result) + sizeof(hostent);
+ 
+   // Copy the hostent into it, along with its embedded pointers.
+@@ -114,7 +123,37 @@ hostent* SafeGetHostByName(const char* h
+   result->h_addr_list[num_addrs] = NULL;
+ 
+   *herrno = 0;
+-#elif defined(OSX)
++#elif defined(LINUX) || defined(ANDROID)
++  // gethostbyname() is not thread safe, so we need to call gethostbyname_r()
++  // which is a reentrant version of gethostbyname().
++  ASSERT(kInitHostentLen > sizeof(hostent));
++  size_t size = kInitHostentLen;
++  int ret;
++  void* buf = malloc(size);
++  if (NULL == buf) {
++    return NULL;
++  }
++  char* aux = static_cast<char*>(buf) + sizeof(hostent);
++  size_t aux_len = size - sizeof(hostent);
++  while ((ret = gethostbyname_r(hostname, reinterpret_cast<hostent*>(buf), aux,
++      aux_len, &result, herrno)) == ERANGE) {
++    size *= 2;
++    if (size > kMaxHostentLen) {
++      break;  // Just to be safe.
++    }
++    buf = realloc(buf, size);
++    if (NULL == buf) {
++      return NULL;
++    }
++    aux = static_cast<char*>(buf) + sizeof(hostent);
++    aux_len = size - sizeof(hostent);
++  }
++  if (ret != 0 || buf != result) {
++    free(buf);
++    return NULL;
++  }
++  *herrno = 0;
++#elif defined(OSX) || defined(IOS)
+   // Mac OS returns an object with everything allocated.
+   result = getipnodebyname(hostname, AF_INET, AI_DEFAULT, herrno);
+ #else
+@@ -126,10 +165,10 @@ hostent* SafeGetHostByName(const char* h
+ // This function should mirror the above function, and free any resources
+ // allocated by the above.
+ void FreeHostEnt(hostent* host) {
+-#if defined(WIN32) || (defined(POSIX) && !defined(OSX))
+-  free(host);
+-#elif defined(OSX)
++#if defined(OSX) || defined(IOS)
+   freehostent(host);
++#elif defined(WIN32) || defined(POSIX)
++  free(host);
+ #else
+ #error "I don't know how to free a hostent on your system."
+ #endif
+diff -upN libjingle-0.5.2/talk/base/packetsocketfactory.h.chromium12 libjingle-0.5.2/talk/base/packetsocketfactory.h
+--- libjingle-0.5.2/talk/base/packetsocketfactory.h.chromium12	2011-03-30 21:51:32.697287001 -0400
++++ libjingle-0.5.2/talk/base/packetsocketfactory.h	2011-03-30 21:51:32.697287001 -0400
+@@ -0,0 +1,57 @@
++/*
++ * libjingle
++ * Copyright 2011, Google Inc.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  1. Redistributions of source code must retain the above copyright notice,
++ *     this list of conditions and the following disclaimer.
++ *  2. Redistributions in binary form must reproduce the above copyright notice,
++ *     this list of conditions and the following disclaimer in the documentation
++ *     and/or other materials provided with the distribution.
++ *  3. The name of the author may not be used to endorse or promote products
++ *     derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
++ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef TALK_BASE_PACKETSOCKETFACTORY_H_
++#define TALK_BASE_PACKETSOCKETFACTORY_H_
++
++#include "talk/base/proxyinfo.h"
++
++namespace talk_base {
++
++class AsyncPacketSocket;
++
++class PacketSocketFactory {
++ public:
++  PacketSocketFactory() { }
++  virtual ~PacketSocketFactory() { }
++
++  virtual AsyncPacketSocket* CreateUdpSocket(
++      const SocketAddress& address, int min_port, int max_port) = 0;
++  virtual AsyncPacketSocket* CreateServerTcpSocket(
++      const SocketAddress& local_address, int min_port, int max_port,
++      bool listen, bool ssl) = 0;
++  virtual AsyncPacketSocket* CreateClientTcpSocket(
++      const SocketAddress& local_address, const SocketAddress& remote_address,
++      const ProxyInfo& proxy_info, const std::string& user_agent, bool ssl) = 0;
++
++ private:
++  DISALLOW_EVIL_CONSTRUCTORS(PacketSocketFactory);
++};
++
++}  // namespace talk_base
++
++#endif  // TALK_BASE_PACKETSOCKETFACTORY_H_
+diff -upN libjingle-0.5.2/talk/base/physicalsocketserver.cc.chromium12 libjingle-0.5.2/talk/base/physicalsocketserver.cc
+--- libjingle-0.5.2/talk/base/physicalsocketserver.cc.chromium12	2011-03-30 21:51:32.664287001 -0400
++++ libjingle-0.5.2/talk/base/physicalsocketserver.cc	2011-03-30 21:51:32.698287001 -0400
+@@ -216,7 +216,6 @@ class PhysicalSocket : public AsyncSocke
+     addr.ToSockAddr(&saddr);
+     int err = ::connect(s_, (sockaddr*)&saddr, sizeof(saddr));
+     UpdateLastError();
+-    //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] Connect(" << addr2.ToString() << ") Ret: " << err << " Error: " << error_;
+     if (err == 0) {
+       state_ = CS_CONNECTED;
+     } else if (IsBlockingError(error_)) {
+@@ -284,8 +283,8 @@ class PhysicalSocket : public AsyncSocke
+ #endif
+         );
+     UpdateLastError();
+-    //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] Send(" << cb << ") Ret: " << sent << " Error: " << error_;
+-    ASSERT(sent <= static_cast<int>(cb));  // We have seen minidumps where this may be false
++    // We have seen minidumps where this may be false.
++    ASSERT(sent <= static_cast<int>(cb));
+     if ((sent < 0) && IsBlockingError(error_)) {
+       enabled_events_ |= DE_WRITE;
+     }
+@@ -305,11 +304,11 @@ class PhysicalSocket : public AsyncSocke
+ #endif
+         (sockaddr*)&saddr, sizeof(saddr));
+     UpdateLastError();
+-    ASSERT(sent <= static_cast<int>(cb));  // We have seen minidumps where this may be false
++    // We have seen minidumps where this may be false.
++    ASSERT(sent <= static_cast<int>(cb));
+     if ((sent < 0) && IsBlockingError(error_)) {
+       enabled_events_ |= DE_WRITE;
+     }
+-    //LOG_F(LS_INFO) << cb << ":" << addr.ToString() << ":" << sent << ":" << error_;
+     return sent;
+   }
+ 
+@@ -387,7 +386,6 @@ class PhysicalSocket : public AsyncSocke
+       return 0;
+     int err = ::closesocket(s_);
+     UpdateLastError();
+-    //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] Close() Ret: " << err << " Error: " << error_;
+     s_ = INVALID_SOCKET;
+     state_ = CS_CLOSED;
+     enabled_events_ = 0;
+@@ -427,14 +425,14 @@ class PhysicalSocket : public AsyncSocke
+ 
+     ASSERT(false);
+     return -1;
+-#elif defined(OSX)
++#elif defined(IOS) || defined(OSX)
+     // No simple way to do this on Mac OS X.
+     // SIOCGIFMTU would work if we knew which interface would be used, but
+     // figuring that out is pretty complicated. For now we'll return an error
+     // and let the caller pick a default MTU.
+     error_ = EINVAL;
+     return -1;
+-#elif defined(LINUX)
++#elif defined(LINUX) || defined(ANDROID)
+     // Gets the path MTU.
+     int value;
+     socklen_t vlen = sizeof(value);
+@@ -482,7 +480,7 @@ class PhysicalSocket : public AsyncSocke
+         *slevel = IPPROTO_IP;
+         *sopt = IP_DONTFRAGMENT;
+         break;
+-#elif defined(OSX) || defined(BSD)
++#elif defined(IOS) || defined(OSX) || defined(BSD)
+         LOG(LS_WARNING) << "Socket::OPT_DONTFRAGMENT not supported.";
+         return -1;
+ #elif defined(POSIX)
+@@ -582,71 +580,43 @@ class EventDispatcher : public Dispatche
+   CriticalSection crit_;
+ };
+ 
+-// This is a class customized to use the self-pipe trick to deliver POSIX
+-// signals. This is the only safe, reliable, cross-platform way to do
+-// non-trivial things with a POSIX signal (until proper pselect()
+-// implementations become ubiquitous).
+-class PosixSignalDeliveryDispatcher : public Dispatcher {
++// These two classes use the self-pipe trick to deliver POSIX signals to our
++// select loop. This is the only safe, reliable, cross-platform way to do
++// non-trivial things with a POSIX signal in an event-driven program (until
++// proper pselect() implementations become ubiquitous).
++
++class PosixSignalHandler {
+  public:
+-  virtual ~PosixSignalDeliveryDispatcher() {
+-    close(afd_[0]);
+-    close(afd_[1]);
+-  }
++  // POSIX only specifies 32 signals, but in principle the system might have
++  // more and the programmer might choose to use them, so we size our array
++  // for 128.
++  static const int kNumPosixSignals = 128;
+ 
+-  virtual uint32 GetRequestedEvents() {
+-    return DE_READ;
+-  }
++  static PosixSignalHandler *Instance() { return &instance_; }
+ 
+-  virtual void OnPreEvent(uint32 ff) {
+-    // Events might get grouped if signals come very fast, so we read out up to
+-    // 16 bytes to make sure we keep the pipe empty.
+-    uint8 b[16];
+-    ssize_t ret = read(afd_[0], b, sizeof(b));
+-    if (ret < 0) {
+-      LOG_ERR(LS_WARNING) << "Error in read()";
+-    } else if (ret == 0) {
+-      LOG(LS_WARNING) << "Should have read at least one byte";
++  // Returns true if the given signal number is set.
++  bool IsSignalSet(int signum) const {
++    ASSERT(signum < ARRAY_SIZE(received_signal_));
++    if (signum < ARRAY_SIZE(received_signal_)) {
++      return received_signal_[signum];
++    } else {
++      return false;
+     }
+   }
+ 
+-  virtual void OnEvent(uint32 ff, int err) {
+-    for (int signum = 0; signum < ARRAY_SIZE(received_signal_); ++signum) {
+-      if (received_signal_[signum]) {
+-        received_signal_[signum] = false;
+-        HandlerMap::iterator i = handlers_.find(signum);
+-        if (i == handlers_.end()) {
+-          // This can happen if a signal is delivered to our process at around
+-          // the same time as we unset our handler for it. It is not an error
+-          // condidion, but it's unusual enough to be worth logging.
+-          LOG(LS_INFO) << "Received signal with no handler: " << signum;
+-        } else {
+-          // Otherwise, execute the handler.
+-          (*i->second)(signum);
+-        }
+-      }
++  // Clears the given signal number.
++  void ClearSignal(int signum) {
++    ASSERT(signum < ARRAY_SIZE(received_signal_));
++    if (signum < ARRAY_SIZE(received_signal_)) {
++      received_signal_[signum] = false;
+     }
+   }
+ 
+-  virtual int GetDescriptor() {
++  // Returns the file descriptor to monitor for signal events.
++  int GetDescriptor() const {
+     return afd_[0];
+   }
+ 
+-  virtual bool IsDescriptorClosed() {
+-    return false;
+-  }
+-
+-  void SetHandler(int signum, void (*handler)(int)) {
+-    handlers_[signum] = handler;
+-  }
+-
+-  void ClearHandler(int signum) {
+-    handlers_.erase(signum);
+-  }
+-
+-  bool HasHandlers() {
+-    return !handlers_.empty();
+-  }
+-
+   // This is called directly from our real signal handler, so it must be
+   // signal-handler-safe. That means it cannot assume anything about the
+   // user-level state of the process, since the handler could be executed at any
+@@ -658,7 +628,7 @@ class PosixSignalDeliveryDispatcher : pu
+     }
+     // Set a flag saying we've seen this signal.
+     received_signal_[signum] = true;
+-    // Tell the thread running our PhysicalSocketServer that we got a signal.
++    // Notify application code that we got a signal.
+     const uint8 b[1] = { 0 };
+     if (-1 == write(afd_[1], b, sizeof(b))) {
+       // Nothing we can do here. If there's an error somehow then there's
+@@ -670,49 +640,8 @@ class PosixSignalDeliveryDispatcher : pu
+     }
+   }
+ 
+-  // Sets a PhysicalSocketServer to own signal delivery, or fails if already
+-  // owned.
+-  bool SetOwner(PhysicalSocketServer *owner) {
+-    CritScope cs(&owner_critsec_);
+-    if (owner == owner_) {
+-      return true;
+-    } else if (owner_) {
+-      return false;
+-    } else {
+-      owner_ = owner;
+-      owner_->Add(this);
+-      return true;
+-    }
+-  }
+-
+-  bool IsOwner(PhysicalSocketServer *ss) {
+-    CritScope cs(&owner_critsec_);
+-    return owner_ == ss;
+-  }
+-
+-  void ClearOwner(PhysicalSocketServer *ss) {
+-    CritScope cs(&owner_critsec_);
+-    if (owner_ != ss) {
+-      return;
+-    }
+-    owner_->Remove(this);
+-    owner_ = NULL;
+-  }
+-
+-  // There is just a single global instance. (Signal handlers do not get any
+-  // sort of user-defined void * parameter, so they can't access anything that
+-  // isn't global.)
+-  static PosixSignalDeliveryDispatcher instance_;
+-
+  private:
+-  // POSIX only specifies 32 signals, but in principle the system might have
+-  // more and the programmer might choose to use them, so we size our array
+-  // for 128.
+-  static const int kNumPosixSignals = 128;
+-
+-  typedef std::map<int, void (*)(int)> HandlerMap;
+-
+-  PosixSignalDeliveryDispatcher() : owner_(NULL) {
++  PosixSignalHandler() {
+     if (pipe(afd_) < 0) {
+       LOG_ERR(LS_ERROR) << "pipe failed";
+       return;
+@@ -728,8 +657,30 @@ class PosixSignalDeliveryDispatcher : pu
+            sizeof(received_signal_));
+   }
+ 
++  ~PosixSignalHandler() {
++    int fd1 = afd_[0];
++    int fd2 = afd_[1];
++    // We clobber the stored file descriptor numbers here or else in principle
++    // a signal that happens to be delivered during application termination
++    // could erroneously write a zero byte to an unrelated file handle in
++    // OnPosixSignalReceived() if some other file happens to be opened later
++    // during shutdown and happens to be given the same file descriptor number
++    // as our pipe had. Unfortunately even with this precaution there is still a
++    // race where that could occur if said signal happens to be handled
++    // concurrently with this code and happens to have already read the value of
++    // afd_[1] from memory before we clobber it, but that's unlikely.
++    afd_[0] = -1;
++    afd_[1] = -1;
++    close(fd1);
++    close(fd2);
++  }
++
++  // There is just a single global instance. (Signal handlers do not get any
++  // sort of user-defined void * parameter, so they can't access anything that
++  // isn't global.)
++  static PosixSignalHandler instance_;
++
+   int afd_[2];
+-  HandlerMap handlers_;
+   // These are boolean flags that will be set in our signal handler and read
+   // and cleared from Wait(). There is a race involved in this, but it is
+   // benign. The signal handler sets the flag before signaling the pipe, so
+@@ -741,14 +692,83 @@ class PosixSignalDeliveryDispatcher : pu
+   // Volatile is not necessary here for correctness, but this data _is_ volatile
+   // so I've marked it as such.
+   volatile uint8 received_signal_[kNumPosixSignals];
++};
++
++PosixSignalHandler PosixSignalHandler::instance_;
++
++class PosixSignalDispatcher : public Dispatcher {
++ public:
++  PosixSignalDispatcher(PhysicalSocketServer *owner) : owner_(owner) {
++    owner_->Add(this);
++  }
++
++  virtual ~PosixSignalDispatcher() {
++    owner_->Remove(this);
++  }
++
++  virtual uint32 GetRequestedEvents() {
++    return DE_READ;
++  }
++
++  virtual void OnPreEvent(uint32 ff) {
++    // Events might get grouped if signals come very fast, so we read out up to
++    // 16 bytes to make sure we keep the pipe empty.
++    uint8 b[16];
++    ssize_t ret = read(GetDescriptor(), b, sizeof(b));
++    if (ret < 0) {
++      LOG_ERR(LS_WARNING) << "Error in read()";
++    } else if (ret == 0) {
++      LOG(LS_WARNING) << "Should have read at least one byte";
++    }
++  }
++
++  virtual void OnEvent(uint32 ff, int err) {
++    for (int signum = 0; signum < PosixSignalHandler::kNumPosixSignals;
++         ++signum) {
++      if (PosixSignalHandler::Instance()->IsSignalSet(signum)) {
++        PosixSignalHandler::Instance()->ClearSignal(signum);
++        HandlerMap::iterator i = handlers_.find(signum);
++        if (i == handlers_.end()) {
++          // This can happen if a signal is delivered to our process at around
++          // the same time as we unset our handler for it. It is not an error
++          // condition, but it's unusual enough to be worth logging.
++          LOG(LS_INFO) << "Received signal with no handler: " << signum;
++        } else {
++          // Otherwise, execute our handler.
++          (*i->second)(signum);
++        }
++      }
++    }
++  }
++
++  virtual int GetDescriptor() {
++    return PosixSignalHandler::Instance()->GetDescriptor();
++  }
++
++  virtual bool IsDescriptorClosed() {
++    return false;
++  }
++
++  void SetHandler(int signum, void (*handler)(int)) {
++    handlers_[signum] = handler;
++  }
++
++  void ClearHandler(int signum) {
++    handlers_.erase(signum);
++  }
++
++  bool HasHandlers() {
++    return !handlers_.empty();
++  }
++
++ private:
++  typedef std::map<int, void (*)(int)> HandlerMap;
++
++  HandlerMap handlers_;
+   // Our owner.
+   PhysicalSocketServer *owner_;
+-  // To synchronize ownership changes.
+-  CriticalSection owner_critsec_;
+ };
+ 
+-PosixSignalDeliveryDispatcher PosixSignalDeliveryDispatcher::instance_;
+-
+ class SocketDispatcher : public Dispatcher, public PhysicalSocket {
+  public:
+   explicit SocketDispatcher(PhysicalSocketServer *ss) : PhysicalSocket(ss) {
+@@ -994,9 +1014,16 @@ class SocketDispatcher : public Dispatch
+   bool signal_close_;
+   int signal_err_;
+ 
+-  SocketDispatcher(PhysicalSocketServer* ss) : PhysicalSocket(ss), id_(0), signal_close_(false) {
++  SocketDispatcher(PhysicalSocketServer* ss)
++      : PhysicalSocket(ss),
++        id_(0),
++        signal_close_(false) {
+   }
+-  SocketDispatcher(SOCKET s, PhysicalSocketServer* ss) : PhysicalSocket(ss, s), id_(0), signal_close_(false) {
++
++  SocketDispatcher(SOCKET s, PhysicalSocketServer* ss)
++      : PhysicalSocket(ss, s),
++        id_(0),
++        signal_close_(false) {
+   }
+ 
+   virtual ~SocketDispatcher() {
+@@ -1069,7 +1096,6 @@ class SocketDispatcher : public Dispatch
+       SignalReadEvent(this);
+     }
+     if (((ff & DE_CLOSE) != 0) && (id_ == cache_id)) {
+-      //LOG(INFO) << "SOCK[" << static_cast<int>(s_) << "] OnClose() Error: " << err;
+       signal_close_ = true;
+       signal_err_ = err;
+     }
+@@ -1134,7 +1160,7 @@ PhysicalSocketServer::~PhysicalSocketSer
+   WSACloseEvent(socket_ev_);
+ #endif
+ #ifdef POSIX
+-  PosixSignalDeliveryDispatcher::instance_.ClearOwner(this);
++  signal_dispatcher_.reset();
+ #endif
+   delete signal_wakeup_;
+   ASSERT(dispatchers_.empty());
+@@ -1355,7 +1381,7 @@ bool PhysicalSocketServer::Wait(int cmsW
+ }
+ 
+ static void GlobalSignalHandler(int signum) {
+-  PosixSignalDeliveryDispatcher::instance_.OnPosixSignalReceived(signum);
++  PosixSignalHandler::Instance()->OnPosixSignalReceived(signum);
+ }
+ 
+ bool PhysicalSocketServer::SetPosixSignalHandler(int signum,
+@@ -1366,19 +1392,17 @@ bool PhysicalSocketServer::SetPosixSigna
+     if (!InstallSignal(signum, handler)) {
+       return false;
+     }
+-    if (PosixSignalDeliveryDispatcher::instance_.IsOwner(this)) {
+-      PosixSignalDeliveryDispatcher::instance_.ClearHandler(signum);
+-      if (!PosixSignalDeliveryDispatcher::instance_.HasHandlers()) {
+-        PosixSignalDeliveryDispatcher::instance_.ClearOwner(this);
++    if (signal_dispatcher_.get()) {
++      signal_dispatcher_->ClearHandler(signum);
++      if (!signal_dispatcher_->HasHandlers()) {
++        signal_dispatcher_.reset();
+       }
+     }
+   } else {
+-    if (!PosixSignalDeliveryDispatcher::instance_.SetOwner(this)) {
+-      LOG(LS_ERROR) <<
+-        "Cannot do POSIX signal delivery on more than one PhysicalSocketServer";
+-      return false;
++    if (!signal_dispatcher_.get()) {
++      signal_dispatcher_.reset(new PosixSignalDispatcher(this));
+     }
+-    PosixSignalDeliveryDispatcher::instance_.SetHandler(signum, handler);
++    signal_dispatcher_->SetHandler(signum, handler);
+     if (!InstallSignal(signum, &GlobalSignalHandler)) {
+       return false;
+     }
+@@ -1439,7 +1463,9 @@ bool PhysicalSocketServer::Wait(int cmsW
+         if (disp->CheckSignalClose()) {
+           // We just signalled close, don't poll this socket
+         } else if (s != INVALID_SOCKET) {
+-          WSAEventSelect(s, events[0], FlagsToEvents(disp->GetRequestedEvents()));
++          WSAEventSelect(s,
++                         events[0],
++                         FlagsToEvents(disp->GetRequestedEvents()));
+         } else {
+           events.push_back(disp->GetWSAEvent());
+           event_owners.push_back(disp);
+@@ -1459,14 +1485,19 @@ bool PhysicalSocketServer::Wait(int cmsW
+     }
+ 
+     // Wait for one of the events to signal
+-    DWORD dw = WSAWaitForMultipleEvents(static_cast<DWORD>(events.size()), &events[0], false, cmsNext, false);
++    DWORD dw = WSAWaitForMultipleEvents(static_cast<DWORD>(events.size()),
++                                        &events[0],
++                                        false,
++                                        cmsNext,
++                                        false);
+ 
+ #if 0  // LOGGING
+     // we track this information purely for logging purposes.
+     last_tick_dispatch_count_++;
+     if (last_tick_dispatch_count_ >= 1000) {
+       int32 elapsed = TimeSince(last_tick_tracked_);
+-      LOG(INFO) << "PhysicalSocketServer took " << elapsed << "ms for 1000 events";
++      LOG(INFO) << "PhysicalSocketServer took " << elapsed
++                << "ms for 1000 events";
+ 
+       // If we get more than 1000 events in a second, we are spinning badly
+       // (normally it should take about 8-20 seconds).
+@@ -1510,20 +1541,30 @@ bool PhysicalSocketServer::Wait(int cmsW
+ 
+ #if LOGGING
+             {
+-              if ((wsaEvents.lNetworkEvents & FD_READ) && wsaEvents.iErrorCode[FD_READ_BIT] != 0) {
+-                LOG(WARNING) << "PhysicalSocketServer got FD_READ_BIT error " << wsaEvents.iErrorCode[FD_READ_BIT];
++              if ((wsaEvents.lNetworkEvents & FD_READ) &&
++                  wsaEvents.iErrorCode[FD_READ_BIT] != 0) {
++                LOG(WARNING) << "PhysicalSocketServer got FD_READ_BIT error "
++                             << wsaEvents.iErrorCode[FD_READ_BIT];
+               }
+-              if ((wsaEvents.lNetworkEvents & FD_WRITE) && wsaEvents.iErrorCode[FD_WRITE_BIT] != 0) {
+-                LOG(WARNING) << "PhysicalSocketServer got FD_WRITE_BIT error " << wsaEvents.iErrorCode[FD_WRITE_BIT];
++              if ((wsaEvents.lNetworkEvents & FD_WRITE) &&
++                  wsaEvents.iErrorCode[FD_WRITE_BIT] != 0) {
++                LOG(WARNING) << "PhysicalSocketServer got FD_WRITE_BIT error "
++                             << wsaEvents.iErrorCode[FD_WRITE_BIT];
+               }
+-              if ((wsaEvents.lNetworkEvents & FD_CONNECT) && wsaEvents.iErrorCode[FD_CONNECT_BIT] != 0) {
+-                LOG(WARNING) << "PhysicalSocketServer got FD_CONNECT_BIT error " << wsaEvents.iErrorCode[FD_CONNECT_BIT];
++              if ((wsaEvents.lNetworkEvents & FD_CONNECT) &&
++                  wsaEvents.iErrorCode[FD_CONNECT_BIT] != 0) {
++                LOG(WARNING) << "PhysicalSocketServer got FD_CONNECT_BIT error "
++                             << wsaEvents.iErrorCode[FD_CONNECT_BIT];
+               }
+-              if ((wsaEvents.lNetworkEvents & FD_ACCEPT) && wsaEvents.iErrorCode[FD_ACCEPT_BIT] != 0) {
+-                LOG(WARNING) << "PhysicalSocketServer got FD_ACCEPT_BIT error " << wsaEvents.iErrorCode[FD_ACCEPT_BIT];
++              if ((wsaEvents.lNetworkEvents & FD_ACCEPT) &&
++                  wsaEvents.iErrorCode[FD_ACCEPT_BIT] != 0) {
++                LOG(WARNING) << "PhysicalSocketServer got FD_ACCEPT_BIT error "
++                             << wsaEvents.iErrorCode[FD_ACCEPT_BIT];
+               }
+-              if ((wsaEvents.lNetworkEvents & FD_CLOSE) && wsaEvents.iErrorCode[FD_CLOSE_BIT] != 0) {
+-                LOG(WARNING) << "PhysicalSocketServer got FD_CLOSE_BIT error " << wsaEvents.iErrorCode[FD_CLOSE_BIT];
++              if ((wsaEvents.lNetworkEvents & FD_CLOSE) &&
++                  wsaEvents.iErrorCode[FD_CLOSE_BIT] != 0) {
++                LOG(WARNING) << "PhysicalSocketServer got FD_CLOSE_BIT error "
++                             << wsaEvents.iErrorCode[FD_CLOSE_BIT];
+               }
+             }
+ #endif
+diff -upN libjingle-0.5.2/talk/base/physicalsocketserver.h.chromium12 libjingle-0.5.2/talk/base/physicalsocketserver.h
+--- libjingle-0.5.2/talk/base/physicalsocketserver.h.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/physicalsocketserver.h	2011-03-30 21:51:32.698287001 -0400
+@@ -31,6 +31,7 @@
+ #include <vector>
+ 
+ #include "talk/base/asyncfile.h"
++#include "talk/base/scoped_ptr.h"
+ #include "talk/base/socketserver.h"
+ #include "talk/base/criticalsection.h"
+ 
+@@ -51,7 +52,7 @@ enum DispatcherEvent {
+ 
+ class Signaler;
+ #ifdef POSIX
+-class PosixSignalDeliveryDispatcher;
++class PosixSignalDispatcher;
+ #endif
+ 
+ class Dispatcher {
+@@ -99,9 +100,8 @@ public:
+   // manipulate user-level data structures.
+   // "handler" may be SIG_IGN, SIG_DFL, or a user-specified function, just like
+   // with signal(2).
+-  // Only one PhysicalSocketServer may have user-level signal handlers.
+-  // Attempting to install a signal handler for a PhysicalSocketServer when
+-  // another already owns some will fail.
++  // Only one PhysicalSocketServer should have user-level signal handlers.
++  // 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));
+@@ -113,8 +113,9 @@ private:
+ 
+ #ifdef POSIX
+   static bool InstallSignal(int signum, void (*handler)(int));
+-#endif
+ 
++  scoped_ptr<PosixSignalDispatcher> signal_dispatcher_;
++#endif
+   DispatcherList dispatchers_;
+   IteratorList iterators_;
+   Signaler* signal_wakeup_;
+diff -upN libjingle-0.5.2/talk/base/socketpool.cc.chromium12 libjingle-0.5.2/talk/base/socketpool.cc
+--- libjingle-0.5.2/talk/base/socketpool.cc.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/socketpool.cc	2011-03-30 21:51:32.699287001 -0400
+@@ -218,11 +218,25 @@ ReuseSocketPool::ReturnConnectedStream(S
+ 
+ void
+ ReuseSocketPool::OnStreamEvent(StreamInterface* stream, int events, int err) {
+-  LOG_F(LS_VERBOSE) << "Connection closed with error: " << err;
+   ASSERT(stream == stream_);
+   ASSERT(!checked_out_);
+-  ASSERT(0 != (events & SE_CLOSE));
+-  // Socket has closed.  We'll reconnect it the next time it is used.
++
++  // If the stream was written to and then immediately returned to us then
++  // we may get a writable notification for it, which we should ignore.
++  if (events == SE_WRITE) {
++    LOG_F(LS_VERBOSE) << "Pooled Socket unexpectedly writable: ignoring";
++    return;
++  }
++
++  // If the peer sent data, we can't process it, so drop the connection.
++  // If the socket has closed, clean it up.
++  // In either case, we'll reconnect it the next time it is used.
++  ASSERT(0 != (events & (SE_READ|SE_CLOSE)));
++  if (0 != (events & SE_CLOSE)) {
++    LOG_F(LS_VERBOSE) << "Connection closed with error: " << err;
++  } else {
++    LOG_F(LS_VERBOSE) << "Pooled Socket unexpectedly readable: closing";
++  }
+   stream_->Close();
+ }
+ 
+diff -upN libjingle-0.5.2/talk/base/socketpool.h.chromium12 libjingle-0.5.2/talk/base/socketpool.h
+--- libjingle-0.5.2/talk/base/socketpool.h.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/socketpool.h	2011-03-30 21:51:32.699287001 -0400
+@@ -25,8 +25,8 @@
+  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+-#ifndef TALK_BASE_SOCKETPOOL_H__
+-#define TALK_BASE_SOCKETPOOL_H__
++#ifndef TALK_BASE_SOCKETPOOL_H_
++#define TALK_BASE_SOCKETPOOL_H_
+ 
+ #include <deque>
+ #include <list>
+@@ -155,6 +155,6 @@ private:
+ 
+ //////////////////////////////////////////////////////////////////////
+ 
+-} // namespace talk_base
++}  // namespace talk_base
+ 
+-#endif // TALK_BASE_SOCKETPOOL_H__
++#endif  // TALK_BASE_SOCKETPOOL_H_
+diff -upN libjingle-0.5.2/talk/base/stream.cc.chromium12 libjingle-0.5.2/talk/base/stream.cc
+--- libjingle-0.5.2/talk/base/stream.cc.chromium12	2011-03-30 21:51:32.664287001 -0400
++++ libjingle-0.5.2/talk/base/stream.cc	2011-03-30 21:51:32.699287001 -0400
+@@ -1,6 +1,6 @@
+ /*
+  * libjingle
+- * Copyright 2004--2010, Google Inc.
++ * Copyright 2011, Google Inc.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions are met:
+@@ -552,7 +552,8 @@ void POpenStream::DoClose() {
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+ MemoryStreamBase::MemoryStreamBase()
+-  : buffer_(NULL), buffer_length_(0), data_length_(0), seek_position_(0) {
++  : buffer_(NULL), buffer_length_(0), data_length_(0),
++    seek_position_(0) {
+ }
+ 
+ StreamState MemoryStreamBase::GetState() const {
+@@ -647,25 +648,29 @@ StreamResult MemoryStreamBase::DoReserve
+ 
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+-MemoryStream::MemoryStream() {
++MemoryStream::MemoryStream()
++  : buffer_alloc_(NULL) {
+ }
+ 
+-MemoryStream::MemoryStream(const char* data) {
++MemoryStream::MemoryStream(const char* data)
++  : buffer_alloc_(NULL) {
+   SetData(data, strlen(data));
+ }
+ 
+-MemoryStream::MemoryStream(const void* data, size_t length) {
++MemoryStream::MemoryStream(const void* data, size_t length)
++  : buffer_alloc_(NULL) {
+   SetData(data, length);
+ }
+ 
+ MemoryStream::~MemoryStream() {
+-  delete [] buffer_;
++  delete [] buffer_alloc_;
+ }
+ 
+ void MemoryStream::SetData(const void* data, size_t length) {
+   data_length_ = buffer_length_ = length;
+-  delete [] buffer_;
+-  buffer_ = new char[buffer_length_];
++  delete [] buffer_alloc_;
++  buffer_alloc_ = new char[buffer_length_ + kAlignment];
++  buffer_ = reinterpret_cast<char*>(ALIGNP(buffer_alloc_, kAlignment));
+   memcpy(buffer_, data, data_length_);
+   seek_position_ = 0;
+ }
+@@ -674,9 +679,12 @@ StreamResult MemoryStream::DoReserve(siz
+   if (buffer_length_ >= size)
+     return SR_SUCCESS;
+ 
+-  if (char* new_buffer = new char[size]) {
++  if (char* new_buffer_alloc = new char[size + kAlignment]) {
++    char* new_buffer = reinterpret_cast<char*>(
++        ALIGNP(new_buffer_alloc, kAlignment));
+     memcpy(new_buffer, buffer_, data_length_);
+-    delete [] buffer_;
++    delete [] buffer_alloc_;
++    buffer_alloc_ = new_buffer_alloc;
+     buffer_ = new_buffer;
+     buffer_length_ = size;
+     return SR_SUCCESS;
+diff -upN libjingle-0.5.2/talk/base/stream.h.chromium12 libjingle-0.5.2/talk/base/stream.h
+--- libjingle-0.5.2/talk/base/stream.h.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/stream.h	2011-03-30 21:51:32.700287001 -0400
+@@ -530,6 +530,9 @@ class MemoryStream : public MemoryStream
+ 
+  protected:
+   virtual StreamResult DoReserve(size_t size, int* error);
++  // Memory Streams are aligned for efficiency.
++  static const int kAlignment = 16;
++  char* buffer_alloc_;
+ };
+ 
+ // ExternalMemoryStream adapts an external memory buffer, so writes which would
+diff -upN libjingle-0.5.2/talk/base/stringencode.cc.chromium12 libjingle-0.5.2/talk/base/stringencode.cc
+--- libjingle-0.5.2/talk/base/stringencode.cc.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/stringencode.cc	2011-03-30 21:51:32.700287001 -0400
+@@ -1,27 +1,27 @@
+ /*
+  * libjingle
+- * Copyright 2004--2005, Google Inc.
++ * Copyright 2011, 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.
+  */
+ 
+@@ -168,7 +168,7 @@ const unsigned char HTML_UNSAFE = 0x2; /
+ 
+ //  ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 6 5 7 8 9 : ; < = > ?
+ //@ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _
+-//` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ 
++//` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
+ 
+ const unsigned char ASCII_CLASS[128] = {
+   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+@@ -251,7 +251,7 @@ size_t utf8_decode(const char* source, s
+     return 0;
+   }
+   value16 = (value16 << 6) | (s[2] & 0x3F);
+-  if ((s[0] & 0xF0) == 0xE0) {                    // Check s[0] == 1110xxxx 
++  if ((s[0] & 0xF0) == 0xE0) {                    // Check s[0] == 1110xxxx
+     *value = ((s[0] & 0x0F) << 12) | value16;
+     return 3;
+   }
+@@ -259,7 +259,7 @@ size_t utf8_decode(const char* source, s
+     return 0;
+   }
+   value16 = (value16 << 6) | (s[3] & 0x3F);
+-  if ((s[0] & 0xF8) == 0xF0) {                    // Check s[0] == 11110xxx 
++  if ((s[0] & 0xF8) == 0xF0) {                    // Check s[0] == 11110xxx
+     *value = ((s[0] & 0x07) << 18) | value16;
+     return 4;
+   }
+@@ -511,8 +511,8 @@ std::string s_transform(const std::strin
+   return result;
+ }
+ 
+-size_t split(const std::string& source, char delimiter,
+-             std::vector<std::string>* fields) {
++size_t tokenize(const std::string& source, char delimiter,
++                std::vector<std::string>* fields) {
+   ASSERT(NULL != fields);
+   fields->clear();
+   size_t last = 0;
+@@ -530,20 +530,19 @@ size_t split(const std::string& source, 
+   return fields->size();
+ }
+ 
+-std::string split_one(const std::string& source, char delimiter, int* index) {
+-  std::string substring;
+-  size_t start = source.find_first_not_of(delimiter, *index);
+-  size_t end = source.find_first_of(delimiter, start);
+-  if (start != std::string::npos) {
+-    if (end == std::string::npos) {
+-      substring = source.substr(start);
+-      *index = source.length();
+-    } else {
+-      substring = source.substr(start, end - start);
+-      *index = source.find_first_not_of(delimiter, end);
++size_t split(const std::string& source, char delimiter,
++             std::vector<std::string>* fields) {
++  ASSERT(NULL != fields);
++  fields->clear();
++  size_t last = 0;
++  for (size_t i = 0; i < source.length(); ++i) {
++    if (source[i] == delimiter) {
++      fields->push_back(source.substr(last, i - last));
++      last = i + 1;
+     }
+   }
+-  return substring;
++  fields->push_back(source.substr(last, source.length() - last));
++  return fields->size();
+ }
+ 
+ char make_char_safe_for_filename(char c) {
+diff -upN libjingle-0.5.2/talk/base/stringencode.h.chromium12 libjingle-0.5.2/talk/base/stringencode.h
+--- libjingle-0.5.2/talk/base/stringencode.h.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/stringencode.h	2011-03-30 21:51:32.700287001 -0400
+@@ -1,27 +1,27 @@
+ /*
+  * libjingle
+- * Copyright 2004--2005, Google Inc.
++ * Copyright 2011, 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.
+  */
+ 
+@@ -58,7 +58,7 @@ size_t escape(char * buffer, size_t bufl
+ // Note: in-place unescaping (buffer == source) is allowed.
+ size_t unescape(char * buffer, size_t buflen,
+                 const char * source, size_t srclen,
+-                char escape); 
++                char escape);
+ 
+ // Encoding replaces illegal characters with the escape character and 2 hex
+ // chars, so it's a little less compact than escape, but completely removes
+@@ -125,14 +125,15 @@ inline std::string s_url_decode(const st
+   return s_transform(source, url_decode);
+ }
+ 
+-// Splits the source string into multiple fields separated by delimiter.
++// Splits the source string into multiple fields separated by delimiter,
++// with duplicates of delimiter creating empty fields.
+ size_t split(const std::string& source, char delimiter,
+              std::vector<std::string>* fields);
+ 
+-// Returns the first part of a string separated by delimiter.
+-// Index indicates the location to start parsing in the string and
+-// is increased to the start of the next substring.
+-std::string split_one(const std::string& source, char delimiter, int* index);
++// Splits the source string into multiple fields separated by delimiter,
++// with duplicates of delimiter ignored.  Trailing delimiter ignored.
++size_t tokenize(const std::string& source, char delimiter,
++                std::vector<std::string>* fields);
+ 
+ // Safe sprintf to std::string
+ //void sprintf(std::string& value, size_t maxlen, const char * format, ...)
+diff -upN libjingle-0.5.2/talk/base/stringutils.cc.chromium12 libjingle-0.5.2/talk/base/stringutils.cc
+--- libjingle-0.5.2/talk/base/stringutils.cc.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/stringutils.cc	2011-03-30 21:51:32.701287001 -0400
+@@ -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.
+  */
+ 
+@@ -33,7 +33,7 @@ namespace talk_base {
+ bool memory_check(const void* memory, int c, size_t count) {
+   const char* char_memory = static_cast<const char*>(memory);
+   char char_c = static_cast<char>(c);
+-  for (size_t i=0; i<count; ++i) {
++  for (size_t i = 0; i < count; ++i) {
+     if (char_memory[i] != char_c) {
+       return false;
+     }
+@@ -88,7 +88,7 @@ size_t asccpyn(wchar_t* buffer, size_t b
+                const char* source, size_t srclen) {
+   if (buflen <= 0)
+     return 0;
+-  
++
+   if (srclen == SIZE_UNKNOWN) {
+     srclen = strlenn(source, buflen - 1);
+   } else if (srclen >= buflen) {
+@@ -129,4 +129,17 @@ bool starts_with(const char *s1, const c
+   return true;
+ }
+ 
++static const std::string kWhitespace(" \n\r\t");
++
++std::string string_trim(const std::string& s) {
++  std::string::size_type first = s.find_first_not_of(kWhitespace);
++  std::string::size_type last  = s.find_last_not_of(kWhitespace);
++
++  if (first == std::string::npos || last == std::string::npos) {
++    return std::string("");
++  }
++
++  return s.substr(first, last - first + 1);
++}
++
+ }  // namespace talk_base
+diff -upN libjingle-0.5.2/talk/base/stringutils.h.chromium12 libjingle-0.5.2/talk/base/stringutils.h
+--- libjingle-0.5.2/talk/base/stringutils.h.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/stringutils.h	2011-03-30 21:51:32.701287001 -0400
+@@ -332,6 +332,9 @@ void replace_substrs(const char *search,
+ // True iff s1 starts with s2.
+ bool starts_with(const char *s1, const char *s2);
+ 
++// Remove leading and trailing whitespaces.
++std::string string_trim(const std::string& s);
++
+ }  // namespace talk_base
+ 
+ #endif // TALK_BASE_STRINGUTILS_H__
+diff -upN libjingle-0.5.2/talk/examples/call/callclient.cc.chromium12 libjingle-0.5.2/talk/examples/call/callclient.cc
+--- libjingle-0.5.2/talk/examples/call/callclient.cc.chromium12	2011-01-11 19:25:51.000000000 -0500
++++ libjingle-0.5.2/talk/examples/call/callclient.cc	2011-03-30 21:51:32.701287001 -0400
+@@ -29,19 +29,14 @@
+ 
+ #include <string>
+ 
+-#include "talk/xmpp/constants.h"
++#include "talk/base/basicpacketsocketfactory.h"
+ #include "talk/base/helpers.h"
+-#include "talk/base/thread.h"
++#include "talk/base/logging.h"
+ #include "talk/base/network.h"
+ #include "talk/base/socketaddress.h"
+-#include "talk/base/stringutils.h"
+ #include "talk/base/stringencode.h"
+-#include "talk/p2p/base/sessionmanager.h"
+-#include "talk/p2p/client/basicportallocator.h"
+-#include "talk/p2p/client/sessionmanagertask.h"
+-#include "talk/session/phone/devicemanager.h"
+-#include "talk/session/phone/mediaengine.h"
+-#include "talk/session/phone/mediasessionclient.h"
++#include "talk/base/stringutils.h"
++#include "talk/base/thread.h"
+ #include "talk/examples/call/console.h"
+ #include "talk/examples/call/presencepushtask.h"
+ #include "talk/examples/call/presenceouttask.h"
+@@ -50,11 +45,14 @@
+ #include "talk/examples/call/friendinvitesendtask.h"
+ #include "talk/examples/call/muc.h"
+ #include "talk/examples/call/voicemailjidrequester.h"
+-#ifdef USE_TALK_SOUND
+-#include "talk/sound/platformsoundsystemfactory.h"
+-#endif
++#include "talk/p2p/base/sessionmanager.h"
++#include "talk/p2p/client/basicportallocator.h"
++#include "talk/p2p/client/sessionmanagertask.h"
++#include "talk/session/phone/devicemanager.h"
++#include "talk/session/phone/mediaengine.h"
++#include "talk/session/phone/mediasessionclient.h"
++#include "talk/xmpp/constants.h"
+ 
+-#include "talk/base/logging.h"
+ 
+ class NullRenderer : public cricket::VideoRenderer {
+  public:
+@@ -250,11 +248,7 @@ CallClient::CallClient(buzz::XmppClient*
+       portallocator_flags_(0),
+       allow_local_ips_(false),
+       initial_protocol_(cricket::PROTOCOL_HYBRID),
+-      secure_policy_(cricket::SEC_DISABLED)
+-#ifdef USE_TALK_SOUND
+-      , sound_system_factory_(NULL)
+-#endif
+-    {
++      secure_policy_(cricket::SEC_DISABLED) {
+   xmpp_client_->SignalStateChange.connect(this, &CallClient::OnStateChange);
+ }
+ 
+@@ -342,14 +336,19 @@ void CallClient::InitPhone() {
+   // dispatched by it.
+   worker_thread_->Start();
+ 
++  // TODO: It looks like we are leaking many
++  // objects. E.g. |network_manager_| and |socket_factory_| are never
++  // deleted.
++
+   network_manager_ = new talk_base::NetworkManager();
++  socket_factory_ = new talk_base::BasicPacketSocketFactory(worker_thread_);
+ 
+   // TODO: Decide if the relay address should be specified here.
+   talk_base::SocketAddress stun_addr("stun.l.google.com", 19302);
+-  port_allocator_ =
+-      new cricket::BasicPortAllocator(network_manager_, stun_addr,
+-          talk_base::SocketAddress(), talk_base::SocketAddress(),
+-          talk_base::SocketAddress());
++  port_allocator_ = new cricket::BasicPortAllocator(
++      network_manager_, socket_factory_, stun_addr,
++      talk_base::SocketAddress(), talk_base::SocketAddress(),
++      talk_base::SocketAddress());
+ 
+   if (portallocator_flags_ != 0) {
+     port_allocator_->set_flags(portallocator_flags_);
+@@ -367,29 +366,15 @@ void CallClient::InitPhone() {
+   session_manager_task_->EnableOutgoingMessages();
+   session_manager_task_->Start();
+ 
+-#ifdef USE_TALK_SOUND
+-  if (!sound_system_factory_) {
+-    sound_system_factory_ = new cricket::PlatformSoundSystemFactory();
+-  }
+-#endif
+-
+   if (!media_engine_) {
+-    media_engine_ = cricket::MediaEngine::Create(
+-#ifdef USE_TALK_SOUND
+-        sound_system_factory_
+-#endif
+-        );
++    media_engine_ = cricket::MediaEngine::Create();
+   }
+ 
+   media_client_ = new cricket::MediaSessionClient(
+       xmpp_client_->jid(),
+       session_manager_,
+       media_engine_,
+-      new cricket::DeviceManager(
+-#ifdef USE_TALK_SOUND
+-          sound_system_factory_
+-#endif
+-          ));
++      new cricket::DeviceManager());
+   media_client_->SignalCallCreate.connect(this, &CallClient::OnCallCreate);
+   media_client_->SignalDevicesChange.connect(this,
+                                              &CallClient::OnDevicesChange);
+diff -upN libjingle-0.5.2/talk/examples/call/callclient.h.chromium12 libjingle-0.5.2/talk/examples/call/callclient.h
+--- libjingle-0.5.2/talk/examples/call/callclient.h.chromium12	2011-01-11 19:25:51.000000000 -0500
++++ libjingle-0.5.2/talk/examples/call/callclient.h	2011-03-30 21:51:32.701287001 -0400
+@@ -38,9 +38,6 @@
+ #include "talk/xmpp/xmppclient.h"
+ #include "talk/examples/call/status.h"
+ #include "talk/examples/call/console.h"
+-#ifdef USE_TALK_SOUND
+-#include "talk/sound/soundsystemfactory.h"
+-#endif
+ 
+ namespace buzz {
+ class PresencePushTask;
+@@ -92,7 +89,7 @@ class CallClient: public sigslot::has_sl
+     auto_accept_ = auto_accept;
+   }
+   void SetPmucDomain(const std::string &pmuc_domain) {
+-      pmuc_domain_ = pmuc_domain;
++    pmuc_domain_ = pmuc_domain;
+   }
+   void SetConsole(Console *console) {
+     console_ = console;
+@@ -171,6 +168,7 @@ class CallClient: public sigslot::has_sl
+   buzz::XmppClient* xmpp_client_;
+   talk_base::Thread* worker_thread_;
+   talk_base::NetworkManager* network_manager_;
++  talk_base::PacketSocketFactory* socket_factory_;
+   cricket::PortAllocator* port_allocator_;
+   cricket::SessionManager* session_manager_;
+   cricket::SessionManagerTask* session_manager_task_;
+@@ -199,9 +197,6 @@ class CallClient: public sigslot::has_sl
+   cricket::SignalingProtocol initial_protocol_;
+   cricket::SecureMediaPolicy secure_policy_;
+   std::string last_sent_to_;
+-#ifdef USE_TALK_SOUND
+-  cricket::SoundSystemFactory* sound_system_factory_;
+-#endif
+ };
+ 
+ #endif  // TALK_EXAMPLES_CALL_CALLCLIENT_H_
+diff -upN libjingle-0.5.2/talk/libjingle.scons.chromium12 libjingle-0.5.2/talk/libjingle.scons
+--- libjingle-0.5.2/talk/libjingle.scons.chromium12	2011-01-11 19:25:51.000000000 -0500
++++ libjingle-0.5.2/talk/libjingle.scons	2011-03-30 21:51:32.702287001 -0400
+@@ -56,7 +56,9 @@ talk.Library(env, name = "libsrtp",
+ )
+ talk.Library(env, name = "libjingle",
+              lin_srcs = [
++               "base/latebindingsymboltable.cc",
+                "base/linux.cc",
++               "session/phone/libudevsymboltable.cc",
+                "session/phone/v4llookup.cc",
+              ],
+              mac_srcs = [
+@@ -80,12 +82,12 @@ talk.Library(env, name = "libjingle",
+              srcs = [
+                "base/asyncfile.cc",
+                "base/asynchttprequest.cc",
+-               "base/asyncpacketsocket.cc",
+                "base/asyncsocket.cc",
+                "base/asynctcpsocket.cc",
+                "base/asyncudpsocket.cc",
+                "base/autodetectproxy.cc",
+                "base/base64.cc",
++               "base/basicpacketsocketfactory.cc",
+                "base/bytebuffer.cc",
+                "base/checks.cc",
+                "base/common.cc",
+@@ -100,7 +102,6 @@ talk.Library(env, name = "libjingle",
+                "base/httpclient.cc",
+                "base/httpcommon.cc",
+                "base/httprequest.cc",
+-               "base/latebindingsymboltable.cc",
+                "base/logging.cc",
+                "base/md5c.c",
+                "base/messagehandler.cc",
+@@ -166,7 +167,6 @@ talk.Library(env, name = "libjingle",
+                "session/phone/channelmanager.cc",
+                "session/phone/codec.cc",
+                "session/phone/devicemanager.cc",
+-               "session/phone/libudevsymboltable.cc",
+                "session/phone/filemediaengine.cc",
+                "session/phone/mediaengine.cc",
+                "session/phone/mediamonitor.cc",
+diff -upN libjingle-0.5.2/talk/main.scons.chromium12 libjingle-0.5.2/talk/main.scons
+--- libjingle-0.5.2/talk/main.scons.chromium12	2011-01-11 19:25:51.000000000 -0500
++++ libjingle-0.5.2/talk/main.scons	2011-03-30 21:51:32.702287001 -0400
+@@ -188,7 +188,7 @@ win_dbg_env = win_env.Clone(
+ )
+ 
+ win_dbg_env.Prepend(
+-  CCFLAGS=[
++  CCFLAGS = [
+       '/ZI',     # enable debugging
+       '/Od',     # disable optimizations
+       '/MTd',    # link with LIBCMTD.LIB debug lib
+@@ -198,6 +198,21 @@ win_dbg_env.Prepend(
+ 
+ envs.append(win_dbg_env)
+ 
++win_coverage_env = win_dbg_env.Clone(
++  tools = ['code_coverage'],
++  BUILD_TYPE = 'coverage',
++  BUILD_TYPE_DESCRIPTION = 'Windows code coverage build',
++  BUILD_GROUPS = ['all'],
++)
++
++win_coverage_env.Append(
++  CPPDEFINES = [
++    'COVERAGE_ENABLED',
++  ],
++)
++
++envs.append(win_coverage_env)
++
+ win_opt_env = win_env.Clone(
+   BUILD_TYPE = 'opt',
+   BUILD_TYPE_DESCRIPTION = 'Windows opt build',
+@@ -285,6 +300,7 @@ mac_env.Append(
+     'SystemConfiguration',
+     'OpenGL',
+     'CoreAudio',
++    'Quartz',
+     'QuickTime',
+     'Cocoa',
+     'QTKit',
+@@ -334,9 +350,7 @@ linux_common_env.Append(
+   CPPDEFINES = [
+     'LINUX',
+     'HAVE_GLIB',
+-    # TODO() Enable once we figure out multiple defines with gips lib
+-    # Also consider other linux flags:  64bit, no-strict-aliasing, wrap, etc
+-    #'USE_TALK_SOUND',
++#   'HAVE_DBUS_GLIB',
+   ],
+   CCFLAGS = [
+     # TODO: Some or all of this may be desirable for Mac too.
+@@ -469,6 +483,7 @@ if win_env.Bit('vsproj'):
+ 
+   # Solution and target projects
+   s = vs_env.ComponentVSSolution(
++    # 'libjingle',  # Please uncomment this line if you build VS proj files.
+     ['all_libraries', 'all_programs', 'all_test_programs'],
+     projects = [p],
+   )
+diff -upN libjingle-0.5.2/talk/p2p/base/common.h.chromium12 libjingle-0.5.2/talk/p2p/base/common.h
+--- libjingle-0.5.2/talk/p2p/base/common.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/common.h	2011-03-30 21:51:32.702287001 -0400
+@@ -25,12 +25,13 @@
+  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+-#ifndef CRICKET_P2P_BASE_COMMON_H__
+-#define CRICKET_P2P_BASE_COMMON_H__
++#ifndef TALK_P2P_BASE_COMMON_H_
++#define TALK_P2P_BASE_COMMON_H_
+ 
+ #include "talk/base/logging.h"
+ 
+ // Common log description format for jingle messages
+-#define LOG_J(sev,obj) LOG(sev) << "Jingle:" << obj->ToString() << ": "
++#define LOG_J(sev, obj) LOG(sev) << "Jingle:" << obj->ToString() << ": "
++#define LOG_JV(sev, obj) LOG_V(sev) << "Jingle:" << obj->ToString() << ": "
+ 
+-#endif  // CRICKET_P2P_BASE_COMMON_H__
++#endif  // TALK_P2P_BASE_COMMON_H_
+diff -upN libjingle-0.5.2/talk/p2p/base/constants.cc.chromium12 libjingle-0.5.2/talk/p2p/base/constants.cc
+--- libjingle-0.5.2/talk/p2p/base/constants.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/constants.cc	2011-03-30 21:51:32.702287001 -0400
+@@ -65,6 +65,7 @@ const std::string GINGLE_ACTION_TERMINAT
+ const std::string GINGLE_ACTION_CANDIDATES("candidates");
+ const std::string GINGLE_ACTION_NOTIFY("notify");
+ const std::string GINGLE_ACTION_UPDATE("update");
++const std::string GINGLE_ACTION_VIEW("view");
+ 
+ const std::string LN_ERROR("error");
+ const buzz::QName QN_GINGLE_REDIRECT(true, NS_GINGLE, "redirect");
+@@ -75,6 +76,7 @@ const std::string STR_REDIRECT_PREFIX("x
+ const std::string LN_DESCRIPTION("description");
+ const std::string LN_PAYLOADTYPE("payload-type");
+ const buzz::QName QN_ID(true, NS_EMPTY, "id");
++const buzz::QName QN_SID(true, NS_EMPTY, "sid");
+ const buzz::QName QN_NAME(true, NS_EMPTY, "name");
+ const buzz::QName QN_CLOCKRATE(true, NS_EMPTY, "clockrate");
+ const buzz::QName QN_BITRATE(true, NS_EMPTY, "bitrate");
+@@ -190,6 +192,34 @@ const std::string STR_TERMINATE_PROTOCOL
+ const std::string STR_TERMINATE_INTERNAL_SERVER_ERROR("internal-server-error");
+ const std::string STR_TERMINATE_UNKNOWN_ERROR("unknown-error");
+ 
++// Session notify messages
++const buzz::QName QN_GINGLE_NOTIFY(true, NS_GINGLE, "notify");
++const buzz::QName QN_GINGLE_NOTIFY_NICK(true, cricket::NS_EMPTY, "nick");
++const buzz::QName QN_GINGLE_NOTIFY_SOURCE(true, NS_GINGLE, "source");
++const buzz::QName QN_GINGLE_NOTIFY_SOURCE_MTYPE(
++    true, cricket::NS_EMPTY, "mtype");
++const buzz::QName QN_GINGLE_NOTIFY_SOURCE_SSRC(true, cricket::NS_EMPTY, "ssrc");
++const std::string GINGLE_NOTIFY_SOURCE_MTYPE_AUDIO("audio");
++const std::string GINGLE_NOTIFY_SOURCE_MTYPE_VIDEO("video");
++
++// Session view messages
++const buzz::QName QN_GINGLE_VIEW(true, cricket::NS_EMPTY, "view");
++const buzz::QName QN_GINGLE_VIEW_TYPE(true, cricket::NS_EMPTY, "type");
++const buzz::QName QN_GINGLE_VIEW_NICK(true, cricket::NS_EMPTY, "nick");
++const buzz::QName QN_GINGLE_VIEW_MEDIA_TYPE(true, cricket::NS_EMPTY, "mtype");
++const buzz::QName QN_GINGLE_VIEW_SSRC(true, cricket::NS_EMPTY, "ssrc");
++const std::string GINGLE_VIEW_TYPE_STATIC("static");
++const std::string GINGLE_VIEW_TYPE_DYNAMIC("dynamic");
++const std::string GINGLE_VIEW_MEDIA_TYPE_AUDIO("audio");
++const std::string GINGLE_VIEW_MEDIA_TYPE_VIDEO("video");
++const buzz::QName QN_GINGLE_VIEW_PARAMS(true, cricket::NS_EMPTY, "params");
++const buzz::QName QN_GINGLE_VIEW_PARAMS_WIDTH(true, cricket::NS_EMPTY, "width");
++const buzz::QName QN_GINGLE_VIEW_PARAMS_HEIGHT(
++    true, cricket::NS_EMPTY, "height");
++const buzz::QName QN_GINGLE_VIEW_PARAMS_FRAMERATE(
++    true, cricket::NS_EMPTY, "framerate");
++
++
+ // old stuff
+ #ifdef FEATURE_ENABLE_VOICEMAIL
+ const std::string NS_VOICEMAIL("http://www.google.com/session/voicemail");
+diff -upN libjingle-0.5.2/talk/p2p/base/constants.h.chromium12 libjingle-0.5.2/talk/p2p/base/constants.h
+--- libjingle-0.5.2/talk/p2p/base/constants.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/constants.h	2011-03-30 21:51:32.703287001 -0400
+@@ -81,6 +81,7 @@ extern const std::string GINGLE_ACTION_T
+ extern const std::string GINGLE_ACTION_CANDIDATES;
+ extern const std::string GINGLE_ACTION_NOTIFY;
+ extern const std::string GINGLE_ACTION_UPDATE;
++extern const std::string GINGLE_ACTION_VIEW;
+ 
+ extern const std::string LN_ERROR;
+ extern const buzz::QName QN_GINGLE_REDIRECT;
+@@ -91,6 +92,7 @@ extern const std::string STR_REDIRECT_PR
+ extern const std::string LN_DESCRIPTION;
+ extern const std::string LN_PAYLOADTYPE;
+ extern const buzz::QName QN_ID;
++extern const buzz::QName QN_SID;
+ extern const buzz::QName QN_NAME;
+ extern const buzz::QName QN_CLOCKRATE;
+ extern const buzz::QName QN_BITRATE;
+@@ -205,6 +207,30 @@ extern const std::string STR_TERMINATE_P
+ extern const std::string STR_TERMINATE_INTERNAL_SERVER_ERROR;
+ extern const std::string STR_TERMINATE_UNKNOWN_ERROR;
+ 
++// Session notify messages
++extern const buzz::QName QN_GINGLE_NOTIFY;
++extern const buzz::QName QN_GINGLE_NOTIFY_NICK;
++extern const buzz::QName QN_GINGLE_NOTIFY_SOURCE;
++extern const buzz::QName QN_GINGLE_NOTIFY_SOURCE_MTYPE;
++extern const buzz::QName QN_GINGLE_NOTIFY_SOURCE_SSRC;
++extern const std::string GINGLE_NOTIFY_SOURCE_MTYPE_AUDIO;
++extern const std::string GINGLE_NOTIFY_SOURCE_MTYPE_VIDEO;
++
++// Session view messages
++extern const buzz::QName QN_GINGLE_VIEW;
++extern const buzz::QName QN_GINGLE_VIEW_TYPE;
++extern const buzz::QName QN_GINGLE_VIEW_NICK;
++extern const buzz::QName QN_GINGLE_VIEW_MEDIA_TYPE;
++extern const buzz::QName QN_GINGLE_VIEW_SSRC;
++extern const std::string GINGLE_VIEW_TYPE_STATIC;
++extern const std::string GINGLE_VIEW_TYPE_DYNAMIC;
++extern const std::string GINGLE_VIEW_MEDIA_TYPE_AUDIO;
++extern const std::string GINGLE_VIEW_MEDIA_TYPE_VIDEO;
++extern const buzz::QName QN_GINGLE_VIEW_PARAMS;
++extern const buzz::QName QN_GINGLE_VIEW_PARAMS_WIDTH;
++extern const buzz::QName QN_GINGLE_VIEW_PARAMS_HEIGHT;
++extern const buzz::QName QN_GINGLE_VIEW_PARAMS_FRAMERATE;
++
+ // old stuff
+ #ifdef FEATURE_ENABLE_VOICEMAIL
+ extern const std::string NS_VOICEMAIL;
+diff -upN libjingle-0.5.2/talk/p2p/base/p2ptransportchannel.cc.chromium12 libjingle-0.5.2/talk/p2p/base/p2ptransportchannel.cc
+--- libjingle-0.5.2/talk/p2p/base/p2ptransportchannel.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/p2ptransportchannel.cc	2011-03-30 21:51:32.703287001 -0400
+@@ -621,12 +621,21 @@ void P2PTransportChannel::SortConnection
+ 
+ // Track the best connection, and let listeners know
+ void P2PTransportChannel::SwitchBestConnectionTo(Connection* conn) {
+-  // Note: the previous best_connection_ may be destroyed by now, so don't
++  // Note: if conn is NULL, the previous best_connection_ has been destroyed,
++  // so don't use it.
+   // use it.
++  Connection* old_best_connection = best_connection_;
+   best_connection_ = conn;
+   if (best_connection_) {
+-    LOG_J(LS_INFO, this) << "New best connection: " << conn->ToString();
++    if (old_best_connection) {
++      LOG_J(LS_INFO, this) << "Previous best connection: "
++                           << old_best_connection->ToString();
++    }
++    LOG_J(LS_INFO, this) << "New best connection: "
++                         << best_connection_->ToString();
+     SignalRouteChange(this, best_connection_->remote_candidate().address());
++  } else {
++    LOG_J(LS_INFO, this) << "No best connection";
+   }
+ }
+ 
+diff -upN libjingle-0.5.2/talk/p2p/base/portallocator.h.chromium12 libjingle-0.5.2/talk/p2p/base/portallocator.h
+--- libjingle-0.5.2/talk/p2p/base/portallocator.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/portallocator.h	2011-03-30 21:51:32.703287001 -0400
+@@ -25,13 +25,14 @@
+  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+-#ifndef _PORTALLOCATOR_H_
+-#define _PORTALLOCATOR_H_
++#ifndef TALK_P2P_BASE_PORTALLOCATOR_H_
++#define TALK_P2P_BASE_PORTALLOCATOR_H_
++
++#include <string>
++#include <vector>
+ 
+ #include "talk/base/sigslot.h"
+ #include "talk/p2p/base/port.h"
+-#include <string>
+-#undef SetPort
+ 
+ namespace cricket {
+ 
+@@ -50,8 +51,8 @@ const uint32 PORTALLOCATOR_ENABLE_SHAKER
+ const uint32 kDefaultPortAllocatorFlags = 0;
+ 
+ class PortAllocatorSession : public sigslot::has_slots<> {
+-public:
+-  PortAllocatorSession(uint32 flags) : flags_(flags) {}
++ public:
++  explicit PortAllocatorSession(uint32 flags) : flags_(flags) {}
+ 
+   // Subclasses should clean up any ports created.
+   virtual ~PortAllocatorSession() {}
+@@ -68,22 +69,28 @@ public:
+   virtual bool IsGettingAllPorts() = 0;
+ 
+   sigslot::signal2<PortAllocatorSession*, Port*> SignalPortReady;
+-  sigslot::signal2<PortAllocatorSession*, const std::vector<Candidate>&> SignalCandidatesReady;
++  sigslot::signal2<PortAllocatorSession*,
++                   const std::vector<Candidate>&> SignalCandidatesReady;
+ 
+   uint32 generation() { return generation_; }
+   void set_generation(uint32 generation) { generation_ = generation; }
+ 
+-private:
++ private:
+   uint32 flags_;
+   uint32 generation_;
+ };
+ 
+ class PortAllocator {
+-public:
+-  PortAllocator() : flags_(kDefaultPortAllocatorFlags) {}
++ public:
++  PortAllocator() :
++      flags_(kDefaultPortAllocatorFlags),
++      min_port_(0),
++      max_port_(0) {
++  }
+   virtual ~PortAllocator() {}
+ 
+-    virtual PortAllocatorSession *CreateSession(const std::string &name, const std::string &session_type) = 0;
++  virtual PortAllocatorSession *CreateSession(const std::string &name,
++      const std::string &session_type) = 0;
+ 
+   uint32 flags() const { return flags_; }
+   void set_flags(uint32 flags) { flags_ = flags; }
+@@ -91,15 +98,31 @@ public:
+   const std::string& user_agent() const { return agent_; }
+   const talk_base::ProxyInfo& proxy() const { return proxy_; }
+   void set_proxy(const std::string& agent, const talk_base::ProxyInfo& proxy) {
+-    agent_ = agent; proxy_ = proxy;
++    agent_ = agent;
++    proxy_ = proxy;
++  }
++
++  // Gets/Sets the port range to use when choosing client ports.
++  int min_port() const { return min_port_; }
++  int max_port() const { return max_port_; }
++  bool SetPortRange(int min_port, int max_port) {
++    if (min_port > max_port) {
++      return false;
++    }
++
++    min_port_ = min_port;
++    max_port_ = max_port;
++    return true;
+   }
+ 
+-protected:
++ protected:
+   uint32 flags_;
+   std::string agent_;
+   talk_base::ProxyInfo proxy_;
++  int min_port_;
++  int max_port_;
+ };
+ 
+-} // namespace cricket
++}  // namespace cricket
+ 
+-#endif // _PORTALLOCATOR_H_
++#endif  // TALK_P2P_BASE_PORTALLOCATOR_H_
+diff -upN libjingle-0.5.2/talk/p2p/base/port.cc.chromium12 libjingle-0.5.2/talk/p2p/base/port.cc
+--- libjingle-0.5.2/talk/p2p/base/port.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/port.cc	2011-03-30 21:51:32.704287001 -0400
+@@ -30,12 +30,9 @@
+ #include <algorithm>
+ #include <vector>
+ 
+-#include "talk/base/asyncudpsocket.h"
+-#include "talk/base/asynctcpsocket.h"
+ #include "talk/base/helpers.h"
+ #include "talk/base/logging.h"
+ #include "talk/base/scoped_ptr.h"
+-#include "talk/base/socketadapters.h"
+ #include "talk/base/stringutils.h"
+ #include "talk/p2p/base/common.h"
+ 
+@@ -128,11 +125,19 @@ bool StringToProto(const char* value, Pr
+ }
+ 
+ Port::Port(talk_base::Thread* thread, const std::string& type,
+-           talk_base::SocketFactory* factory, talk_base::Network* network)
+-  : thread_(thread), factory_(factory), type_(type), network_(network),
+-    preference_(-1), lifetime_(LT_PRESTART), enable_port_packets_(false) {
+-  if (factory_ == NULL)
+-    factory_ = thread_->socketserver();
++           talk_base::PacketSocketFactory* factory, talk_base::Network* network,
++           uint32 ip, int min_port, int max_port)
++    : thread_(thread),
++      factory_(factory),
++      type_(type),
++      network_(network),
++      ip_(ip),
++      min_port_(min_port),
++      max_port_(max_port),
++      preference_(-1),
++      lifetime_(LT_PRESTART),
++      enable_port_packets_(false) {
++  ASSERT(factory_ != NULL);
+ 
+   set_username_fragment(talk_base::CreateRandomString(16));
+   set_password(talk_base::CreateRandomString(16));
+@@ -200,7 +205,7 @@ void Port::OnReadPacket(
+   // send back a proper binding response.
+   StunMessage* msg;
+   std::string remote_username;
+-  if (!GetStunMessage(data, size, addr, msg, remote_username)) {
++  if (!GetStunMessage(data, size, addr, &msg, &remote_username)) {
+     LOG_J(LS_ERROR, this) << "Received non-STUN packet from unknown address ("
+                           << addr.ToString() << ")";
+   } else if (!msg) {
+@@ -219,34 +224,16 @@ void Port::OnReadPacket(
+   }
+ }
+ 
+-void Port::SendBindingRequest(Connection* conn) {
+-  // Construct the request message.
+-  StunMessage request;
+-  request.SetType(STUN_BINDING_REQUEST);
+-  request.SetTransactionID(talk_base::CreateRandomString(16));
+-
+-  StunByteStringAttribute* username_attr =
+-      StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+-  std::string username = conn->remote_candidate().username();
+-  username.append(username_frag_);
+-  username_attr->CopyBytes(username.c_str(), username.size());
+-  request.AddAttribute(username_attr);
+-
+-  // Send the request message.
+-  // NOTE: If we wanted to, this is where we would add the HMAC.
+-  talk_base::ByteBuffer buf;
+-  request.Write(&buf);
+-  SendTo(buf.Data(), buf.Length(), conn->remote_candidate().address(), false);
+-}
+-
+ bool Port::GetStunMessage(const char* data, size_t size,
+                           const talk_base::SocketAddress& addr,
+-                          StunMessage *& msg, std::string& remote_username) {
++                          StunMessage** out_msg, std::string* out_username) {
+   // NOTE: This could clearly be optimized to avoid allocating any memory.
+   //       However, at the data rates we'll be looking at on the client side,
+   //       this probably isn't worth worrying about.
+-
+-  msg = 0;
++  ASSERT(out_msg != NULL);
++  ASSERT(out_username != NULL);
++  *out_msg = NULL;
++  out_username->clear();
+ 
+   // Parse the request message.  If the packet is not a complete and correct
+   // STUN message, then ignore it.
+@@ -268,68 +255,73 @@ bool Port::GetStunMessage(const char* da
+   if (stun_msg->type() == STUN_BINDING_REQUEST) {
+     if (remote_frag_len < 0) {
+       // Username not present or corrupted, don't reply.
+-      LOG_J(LS_ERROR, this) << "Received STUN request without username";
++      LOG_J(LS_ERROR, this) << "Received STUN request without username from "
++                            << addr.ToString();
+       return true;
+     } else if (std::memcmp(username_attr->bytes(), username_frag_.c_str(),
+                            username_frag_.size()) != 0) {
+-      LOG_J(LS_ERROR, this) << "Received STUN request with bad username";
++      LOG_J(LS_ERROR, this) << "Received STUN request with bad local username "
++                            << std::string(username_attr->bytes(),
++                                           username_attr->length()) << " from "
++                            << addr.ToString();
+       SendBindingErrorResponse(stun_msg.get(), addr, STUN_ERROR_BAD_REQUEST,
+                                STUN_ERROR_REASON_BAD_REQUEST);
+       return true;
+     }
+ 
+-    remote_username.assign(username_attr->bytes() + username_frag_.size(),
+-      username_attr->bytes() + username_attr->length());
++    out_username->assign(username_attr->bytes() + username_frag_.size(),
++                         username_attr->bytes() + username_attr->length());
+   } else if ((stun_msg->type() == STUN_BINDING_RESPONSE)
+       || (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE)) {
+     if (remote_frag_len < 0) {
+-      // NOTE(tschmelcher): This is benign. It occurs when the response to a
+-      // StunBindingRequest to the real STUN server (which involves no
+-      // usernames) took too long to reach us and so the base StunRequest
+-      // re-sent itself, resulting in us getting an extraneous second response
+-      // that gets forwarded on to this code and correctly discarded.
+-      LOG_J(LS_ERROR, this) << "Received STUN response without username";
++      LOG_J(LS_ERROR, this) << "Received STUN response without username from "
++                            << addr.ToString();
+       // Do not send error response to a response
+       return true;
+     } else if (std::memcmp(username_attr->bytes() + remote_frag_len,
+                            username_frag_.c_str(),
+                            username_frag_.size()) != 0) {
+-      LOG_J(LS_ERROR, this) << "Received STUN response with bad username";
++      LOG_J(LS_ERROR, this) << "Received STUN response with bad local username "
++                            << std::string(username_attr->bytes(),
++                                           username_attr->length()) << " from "
++                            << addr.ToString();
+       // Do not send error response to a response
+       return true;
+     }
+ 
+-    remote_username.assign(username_attr->bytes(),
+-      username_attr->bytes() + remote_frag_len);
++    out_username->assign(username_attr->bytes(),
++                         username_attr->bytes() + remote_frag_len);
+ 
+     if (stun_msg->type() == STUN_BINDING_ERROR_RESPONSE) {
+       if (const StunErrorCodeAttribute* error_code = stun_msg->GetErrorCode()) {
+         LOG_J(LS_ERROR, this) << "Received STUN binding error:"
+-                              << " class=" << error_code->error_class()
+-                              << " number=" << error_code->number()
+-                              << " reason='" << error_code->reason() << "'";
++                              << " class="
++                              << static_cast<int>(error_code->error_class())
++                              << " number="
++                              << static_cast<int>(error_code->number())
++                              << " reason='" << error_code->reason() << "'"
++                              << " from " << addr.ToString();
+         // Return message to allow error-specific processing
+       } else {
+-        LOG_J(LS_ERROR, this)
+-          << "Received STUN error response with no error code";
++        LOG_J(LS_ERROR, this) << "Received STUN binding error without a error "
++                              << "code from " << addr.ToString();
+         // Drop corrupt message
+         return true;
+       }
+     }
+   } else {
+     LOG_J(LS_ERROR, this) << "Received STUN packet with invalid type ("
+-                          << stun_msg->type() << ")";
++                          << stun_msg->type() << ") from " << addr.ToString();
+     return true;
+   }
+ 
+   // Return the STUN message found.
+-  msg = stun_msg.release();
++  *out_msg = stun_msg.release();
+   return true;
+ }
+ 
+-void Port::SendBindingResponse(
+-    StunMessage* request, const talk_base::SocketAddress& addr) {
+-
++void Port::SendBindingResponse(StunMessage* request,
++                               const talk_base::SocketAddress& addr) {
+   ASSERT(request->type() == STUN_BINDING_REQUEST);
+ 
+   // Retrieve the username from the request.
+@@ -362,7 +354,10 @@ void Port::SendBindingResponse(
+   // NOTE: If we wanted to, this is where we would add the HMAC.
+   talk_base::ByteBuffer buf;
+   response.Write(&buf);
+-  SendTo(buf.Data(), buf.Length(), addr, false);
++  if (SendTo(buf.Data(), buf.Length(), addr, false) < 0) {
++    LOG_J(LS_ERROR, this) << "Failed to send STUN ping response to "
++                          << addr.ToString();
++  }
+ 
+   // The fact that we received a successful request means that this connection
+   // (if one exists) should now be readable.
+@@ -372,13 +367,12 @@ void Port::SendBindingResponse(
+     conn->ReceivedPing();
+ }
+ 
+-void Port::SendBindingErrorResponse(
+-    StunMessage* request, const talk_base::SocketAddress& addr, int error_code,
+-    const std::string& reason) {
+-
++void Port::SendBindingErrorResponse(StunMessage* request,
++                                    const talk_base::SocketAddress& addr,
++                                    int error_code, const std::string& reason) {
+   ASSERT(request->type() == STUN_BINDING_REQUEST);
+ 
+-  // Retrieve the username from the request.  If it didn't have one, we
++  // Retrieve the username from the request. If it didn't have one, we
+   // shouldn't be responding at all.
+   const StunByteStringAttribute* username_attr =
+       request->GetByteString(STUN_ATTR_USERNAME);
+@@ -408,41 +402,8 @@ void Port::SendBindingErrorResponse(
+   talk_base::ByteBuffer buf;
+   response.Write(&buf);
+   SendTo(buf.Data(), buf.Length(), addr, false);
+-}
+-
+-talk_base::AsyncPacketSocket* Port::CreatePacketSocket(ProtocolType proto) {
+-  if (proto == PROTO_UDP) {
+-    // UDP sockets are simple.
+-    return talk_base::AsyncUDPSocket::Create(factory_);
+-  } else if (proto == PROTO_TCP || proto == PROTO_SSLTCP) {
+-    // Create the base TCP socket. Bail out if this fails.
+-    talk_base::AsyncSocket* socket = factory_->CreateAsyncSocket(SOCK_STREAM);
+-    if (!socket) {
+-      return NULL;
+-    }
+-
+-    // If using a proxy, wrap the socket in a proxy socket.
+-    if (proxy().type == talk_base::PROXY_SOCKS5) {
+-      socket = new talk_base::AsyncSocksProxySocket(
+-          socket, proxy().address, proxy().username, proxy().password);
+-    } else if (proxy().type == talk_base::PROXY_HTTPS) {
+-      socket = new talk_base::AsyncHttpsProxySocket(
+-          socket, user_agent(), proxy().address,
+-          proxy().username, proxy().password);
+-    }
+-
+-    // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket.
+-    if (proto == PROTO_SSLTCP) {
+-      socket = new talk_base::AsyncSSLSocket(socket);
+-    }
+-
+-    // Finally, wrap that socket in a TCP packet socket.
+-    // [Insert obligatory Taco Town reference here]
+-    return new talk_base::AsyncTCPSocket(socket);
+-  } else {
+-    LOG_J(LS_ERROR, this) << "Unknown protocol (" << proto << ")";
+-    return NULL;
+-  }
++  LOG_J(LS_INFO, this) << "Sending STUN binding error: reason=" << reason
++                       << " to " << addr.ToString();
+ }
+ 
+ void Port::OnMessage(talk_base::Message *pmsg) {
+@@ -519,15 +480,15 @@ class ConnectionRequest : public StunReq
+   }
+ 
+   virtual void OnResponse(StunMessage* response) {
+-    connection_->OnConnectionRequestResponse(response, Elapsed());
++    connection_->OnConnectionRequestResponse(this, response);
+   }
+ 
+   virtual void OnErrorResponse(StunMessage* response) {
+-    connection_->OnConnectionRequestErrorResponse(response, Elapsed());
++    connection_->OnConnectionRequestErrorResponse(this, response);
+   }
+ 
+   virtual void OnTimeout() {
+-    LOG_J(LS_VERBOSE, connection_) << "Timing-out STUN ping " << id();
++    connection_->OnConnectionRequestTimeout(this);
+   }
+ 
+   virtual int GetNextDelay() {
+@@ -551,7 +512,8 @@ Connection::Connection(Port* port, size_
+     remote_candidate_(remote_candidate), read_state_(STATE_READ_TIMEOUT),
+     write_state_(STATE_WRITE_CONNECT), connected_(true), pruned_(false),
+     requests_(port->thread()), rtt_(DEFAULT_RTT),
+-    last_ping_sent_(0), last_ping_received_(0), reported_(false) {
++    last_ping_sent_(0), last_ping_received_(0), last_data_received_(0),
++    reported_(false) {
+   // Wire up to send stun packets
+   requests_.SignalSendPacket.connect(this, &Connection::OnSendStunPacket);
+   LOG_J(LS_INFO, this) << "Connection created";
+@@ -596,16 +558,18 @@ void Connection::set_connected(bool valu
+   }
+ }
+ 
+-void Connection::OnSendStunPacket(
+-    const void* data, size_t size, StunRequest* req) {
+-  port_->SendTo(data, size, remote_candidate_.address(), false);
++void Connection::OnSendStunPacket(const void* data, size_t size,
++                                  StunRequest* req) {
++  if (port_->SendTo(data, size, remote_candidate_.address(), false) < 0) {
++    LOG_J(LS_WARNING, this) << "Failed to send STUN ping " << req->id();
++  }
+ }
+ 
+ void Connection::OnReadPacket(const char* data, size_t size) {
+   StunMessage* msg;
+   std::string remote_username;
+   const talk_base::SocketAddress& addr(remote_candidate_.address());
+-  if (!port_->GetStunMessage(data, size, addr, msg, remote_username)) {
++  if (!port_->GetStunMessage(data, size, addr, &msg, &remote_username)) {
+     // The packet did not parse as a valid STUN message
+ 
+     // If this connection is readable, then pass along the packet.
+@@ -613,6 +577,7 @@ void Connection::OnReadPacket(const char
+       // readable means data from this address is acceptable
+       // Send it on!
+ 
++      last_data_received_ = talk_base::Time();
+       recv_rate_tracker_.Update(size);
+       SignalReadPacket(this, data, size);
+ 
+@@ -620,24 +585,30 @@ void Connection::OnReadPacket(const char
+       if (!pruned_ && (write_state_ == STATE_WRITE_TIMEOUT))
+         set_write_state(STATE_WRITE_CONNECT);
+     } else {
+-      // Not readable means the remote address hasn't send a valid
++      // Not readable means the remote address hasn't sent a valid
+       // binding request yet.
+ 
+       LOG_J(LS_WARNING, this)
+         << "Received non-STUN packet from an unreadable connection.";
+     }
+   } else if (!msg) {
+-    // The packet was STUN, but was already handled
++    // The packet was STUN, but was already handled internally.
+   } else if (remote_username != remote_candidate_.username()) {
+-    // Not destined this connection
+-    LOG_J(LS_ERROR, this) << "Received STUN packet on wrong address.";
++    // The packet had the right local username, but the remote username was
++    // not the right one for the remote address.
+     if (msg->type() == STUN_BINDING_REQUEST) {
++      LOG_J(LS_ERROR, this) << "Received STUN request with bad remote username "
++                            << remote_username;
+       port_->SendBindingErrorResponse(msg, addr, STUN_ERROR_BAD_REQUEST,
+                                       STUN_ERROR_REASON_BAD_REQUEST);
++    } else if (msg->type() == STUN_BINDING_RESPONSE ||
++               msg->type() == STUN_BINDING_ERROR_RESPONSE) {
++      LOG_J(LS_ERROR, this) << "Received STUN response with bad remote username"
++                            " " << remote_username;
+     }
+     delete msg;
+   } else {
+-    // The packet is STUN, with the current username
++    // The packet is STUN, with the right username.
+     // If this is a STUN request, then update the readable bit and respond.
+     // If this is a STUN response, then update the writable bit.
+ 
+@@ -688,6 +659,18 @@ void Connection::Destroy() {
+ }
+ 
+ void Connection::UpdateState(uint32 now) {
++  uint32 rtt = ConservativeRTTEstimate(rtt_);
++
++  std::string pings;
++  for (size_t i = 0; i < pings_since_last_response_.size(); ++i) {
++    char buf[32];
++    talk_base::sprintfn(buf, sizeof(buf), "%u",
++        pings_since_last_response_[i]);
++    pings.append(buf).append(" ");
++  }
++  LOG_J(LS_VERBOSE, this) << "UpdateState(): pings_since_last_response_=" <<
++      pings << ", rtt=" << rtt << ", now=" << now;
++
+   // Check the readable state.
+   //
+   // Since we don't know how many pings the other side has attempted, the best
+@@ -695,6 +678,9 @@ void Connection::UpdateState(uint32 now)
+ 
+   if ((read_state_ == STATE_READABLE) &&
+       (last_ping_received_ + CONNECTION_READ_TIMEOUT <= now)) {
++    LOG_J(LS_INFO, this) << "Unreadable after "
++                         << now - last_ping_received_
++                         << " ms without a ping, rtt=" << rtt;
+     set_read_state(STATE_READ_TIMEOUT);
+   }
+ 
+@@ -707,18 +693,6 @@ void Connection::UpdateState(uint32 now)
+   // Before timing out writability, we give a fixed amount of time.  This is to
+   // allow for changes in network conditions.
+ 
+-  uint32 rtt = ConservativeRTTEstimate(rtt_);
+-
+-  std::string pings;
+-  for (size_t i = 0; i < pings_since_last_response_.size(); ++i) {
+-    char buf[32];
+-    talk_base::sprintfn(buf, sizeof(buf), "%u",
+-        pings_since_last_response_[i]);
+-    pings.append(buf).append(" ");
+-  }
+-  LOG_J(LS_VERBOSE, this) << "UpdateState(): pings_since_last_response_ = " <<
+-      pings << ", rtt = " << rtt << ", now = " << now;
+-
+   if ((write_state_ == STATE_WRITABLE) &&
+       TooManyFailures(pings_since_last_response_,
+                       CONNECTION_WRITE_CONNECT_FAILURES,
+@@ -727,6 +701,16 @@ void Connection::UpdateState(uint32 now)
+       TooLongWithoutResponse(pings_since_last_response_,
+                              CONNECTION_WRITE_CONNECT_TIMEOUT,
+                              now)) {
++    uint32 max_pings = CONNECTION_WRITE_CONNECT_FAILURES;
++    LOG_J(LS_INFO, this) << "Unwritable after " << max_pings
++                         << " ping failures and "
++                         << now - pings_since_last_response_[0]
++                         << " ms without a response,"
++                         << " ms since last received ping="
++                         << now - last_ping_received_
++                         << " ms since last received data="
++                         << now - last_data_received_
++                         << " rtt=" << rtt;
+     set_write_state(STATE_WRITE_CONNECT);
+   }
+ 
+@@ -734,6 +718,9 @@ void Connection::UpdateState(uint32 now)
+       TooLongWithoutResponse(pings_since_last_response_,
+                              CONNECTION_WRITE_TIMEOUT,
+                              now)) {
++    LOG_J(LS_INFO, this) << "Timed out after "
++                         << now - pings_since_last_response_[0]
++                         << " ms without a response, rtt=" << rtt;
+     set_write_state(STATE_WRITE_TIMEOUT);
+   }
+ }
+@@ -778,79 +765,46 @@ std::string Connection::ToString() const
+      << CONNECT_STATE_ABBREV[connected()]
+      << READ_STATE_ABBREV[read_state()]
+      << WRITE_STATE_ABBREV[write_state()]
+-     << "|" << rtt_ << "]";
++     << "|";
++  if (rtt_ < DEFAULT_RTT) {
++    ss << rtt_ << "]";
++  } else {
++    ss << "-]";
++  }
+   return ss.str();
+ }
+ 
+-void Connection::OnConnectionRequestResponse(StunMessage* response,
+-                                             uint32 rtt) {
+-  // We have a potentially valid reply from the remote address.
+-  // The packet must include a username that ends with our fragment,
+-  // since it is a response.
+-
+-  // Check exact message type
+-  bool valid = true;
+-  if (response->type() != STUN_BINDING_RESPONSE)
+-    valid = false;
+-
+-  // Must have username attribute
+-  const StunByteStringAttribute* username_attr =
+-      response->GetByteString(STUN_ATTR_USERNAME);
+-  if (valid) {
+-    if (!username_attr) {
+-      LOG_J(LS_ERROR, this) << "Received likely STUN packet with no username";
+-      valid = false;
+-    }
+-  }
+-
+-  // Length must be at least the size of our fragment (actually, should
+-  // be bigger since our fragment is at the end!)
+-  if (valid) {
+-    if (username_attr->length() <= port_->username_fragment().size()) {
+-      LOG_J(LS_ERROR, this) << "Received likely STUN packet with short username";
+-      valid = false;
+-    }
+-  }
++void Connection::OnConnectionRequestResponse(ConnectionRequest* request,
++                                             StunMessage* response) {
++  // We've already validated that this is a STUN binding response with
++  // the correct local and remote username for this connection.
++  // So if we're not already, become writable. We may be bringing a pruned
++  // connection back to life, but if we don't really want it, we can always
++  // prune it again.
++  uint32 rtt = request->Elapsed();
++  set_write_state(STATE_WRITABLE);
+ 
+-  // Compare our fragment with the end of the username - must be exact match
+-  if (valid) {
+-    std::string username_fragment = port_->username_fragment();
+-    int offset = (int)(username_attr->length() - username_fragment.size());
+-    if (std::memcmp(username_attr->bytes() + offset,
+-        username_fragment.c_str(), username_fragment.size()) != 0) {
+-      LOG_J(LS_ERROR, this) << "Received STUN response with bad username";
+-      valid = false;
+-    }
++  std::string pings;
++  for (size_t i = 0; i < pings_since_last_response_.size(); ++i) {
++    char buf[32];
++    talk_base::sprintfn(buf, sizeof(buf), "%u",
++        pings_since_last_response_[i]);
++    pings.append(buf).append(" ");
+   }
+ 
+-  if (valid) {
+-    // Valid response. If we're not already, become writable.  We may be
+-    // bringing a pruned connection back to life, but if we don't really want
+-    // it, we can always prune it again.
+-    set_write_state(STATE_WRITABLE);
+-
+-    std::string pings;
+-    for (size_t i = 0; i < pings_since_last_response_.size(); ++i) {
+-      char buf[32];
+-      talk_base::sprintfn(buf, sizeof(buf), "%u",
+-          pings_since_last_response_[i]);
+-      pings.append(buf).append(" ");
+-    }
+-    LOG_J(LS_VERBOSE, this) << "OnConnectionRequestResponse(): "
+-        "pings_since_last_response_ = " << pings << ", rtt = " << rtt;
+-
+-    pings_since_last_response_.clear();
+-    rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
++  LOG_J(LS_VERBOSE, this) << "Received STUN ping response " << request->id()
++                          << ", pings_since_last_response_=" << pings
++                          << ", rtt=" << rtt;
+ 
+-    LOG_J(LS_VERBOSE, this) << "Received STUN ping response " <<
+-        response->transaction_id() << " after rtt = " << rtt;
+-  }
++  pings_since_last_response_.clear();
++  rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
+ }
+ 
+-void Connection::OnConnectionRequestErrorResponse(StunMessage *response,
+-                                                  uint32 rtt) {
++void Connection::OnConnectionRequestErrorResponse(ConnectionRequest* request,
++                                                  StunMessage* response) {
+   const StunErrorCodeAttribute* error = response->GetErrorCode();
+-  uint32 error_code = error ? error->error_code() : STUN_ERROR_GLOBAL_FAILURE;
++  uint32 error_code = error ?
++      error->error_code() : static_cast<uint32>(STUN_ERROR_GLOBAL_FAILURE);
+ 
+   if ((error_code == STUN_ERROR_UNKNOWN_ATTRIBUTE)
+       || (error_code == STUN_ERROR_SERVER_ERROR)
+@@ -860,16 +814,33 @@ void Connection::OnConnectionRequestErro
+     // Race failure, retry
+   } else {
+     // This is not a valid connection.
+-    LOG_J(LS_ERROR, this) << "Received STUN error response; killing connection";
++    LOG_J(LS_ERROR, this) << "Received STUN error response, code="
++                          << error_code << "; killing connection";
+     set_write_state(STATE_WRITE_TIMEOUT);
+   }
+ }
+ 
++void Connection::OnConnectionRequestTimeout(ConnectionRequest* request) {
++  // Log at LS_INFO if we miss a ping on a writable connection.
++  talk_base::LoggingSeverity sev = (write_state_ == STATE_WRITABLE) ?
++      talk_base::LS_INFO : talk_base::LS_VERBOSE;
++  uint32 when = talk_base::Time() - request->Elapsed();
++  size_t failures;
++  for (failures = 0; failures < pings_since_last_response_.size(); ++failures) {
++    if (pings_since_last_response_[failures] > when) {
++      break;
++    }
++  }
++  LOG_JV(sev, this) << "Timing-out STUN ping " << request->id()
++                    << " after " << request->Elapsed()
++                    << " ms, failures=" << failures;
++}
++
+ void Connection::CheckTimeout() {
+   // If both read and write have timed out, then this connection can contribute
+   // no more to p2p socket unless at some later date readability were to come
+   // back.  However, we gave readability a long time to timeout, so at this
+-  // point, it seems fair to get rid of this connectoin.
++  // point, it seems fair to get rid of this connection.
+   if ((read_state_ == STATE_READ_TIMEOUT) &&
+       (write_state_ == STATE_WRITE_TIMEOUT)) {
+     port_->thread()->Post(this, MSG_DELETE);
+diff -upN libjingle-0.5.2/talk/p2p/base/port.h.chromium12 libjingle-0.5.2/talk/p2p/base/port.h
+--- libjingle-0.5.2/talk/p2p/base/port.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/port.h	2011-03-30 21:51:32.704287001 -0400
+@@ -33,10 +33,11 @@
+ #include <map>
+ 
+ #include "talk/base/network.h"
+-#include "talk/base/socketaddress.h"
++#include "talk/base/packetsocketfactory.h"
+ #include "talk/base/proxyinfo.h"
+ #include "talk/base/ratetracker.h"
+ #include "talk/base/sigslot.h"
++#include "talk/base/socketaddress.h"
+ #include "talk/base/thread.h"
+ #include "talk/p2p/base/candidate.h"
+ #include "talk/p2p/base/stun.h"
+@@ -49,6 +50,7 @@ class AsyncPacketSocket;
+ namespace cricket {
+ 
+ class Connection;
++class ConnectionRequest;
+ 
+ enum ProtocolType {
+   PROTO_UDP,
+@@ -73,17 +75,19 @@ struct ProtocolAddress {
+ // one add support for specific mechanisms like local UDP ports.
+ class Port : public talk_base::MessageHandler, public sigslot::has_slots<> {
+  public:
+-  Port(talk_base::Thread* thread, const std::string &type,
+-       talk_base::SocketFactory* factory, talk_base::Network* network);
++  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);
+   virtual ~Port();
+ 
+   // The thread on which this port performs its I/O.
+   talk_base::Thread* thread() { return thread_; }
+ 
+   // The factory used to create the sockets of this port.
+-  talk_base::SocketFactory* socket_factory() const { return factory_; }
+-  void set_socket_factory(talk_base::SocketFactory* factory)
+-    { factory_ = factory; }
++  talk_base::PacketSocketFactory* socket_factory() const { return factory_; }
++  void set_socket_factory(talk_base::PacketSocketFactory* factory) {
++    factory_ = factory;
++  }
+ 
+   // Each port is identified by a name (for debugging purposes).
+   const std::string& name() const { return name_; }
+@@ -110,7 +114,6 @@ class Port : public talk_base::MessageHa
+   void set_preference(float preference) { preference_ = preference; }
+ 
+   // Identifies the port type.
+-  //const std::string& protocol() const { return proto_; }
+   const std::string& type() const { return type_; }
+ 
+   // Identifies network that this port was allocated on.
+@@ -185,8 +188,6 @@ class Port : public talk_base::MessageHa
+   const std::string& user_agent() { return user_agent_; }
+   const talk_base::ProxyInfo& proxy() { return proxy_; }
+ 
+-  talk_base::AsyncPacketSocket * CreatePacketSocket(ProtocolType proto);
+-
+   // Normally, packets arrive through a connection (or they result signaling of
+   // unknown address).  Calling this method turns off delivery of packets
+   // through their respective connection and instead delivers every packet
+@@ -212,20 +213,6 @@ class Port : public talk_base::MessageHa
+   std::string ToString() const;
+ 
+  protected:
+-  talk_base::Thread* thread_;
+-  talk_base::SocketFactory* factory_;
+-  std::string type_;
+-  talk_base::Network* network_;
+-  uint32 generation_;
+-  std::string name_;
+-  std::string username_frag_;
+-  std::string password_;
+-  float preference_;
+-  std::vector<Candidate> candidates_;
+-  AddressMap connections_;
+-  enum Lifetime { LT_PRESTART, LT_PRETIMEOUT, LT_POSTTIMEOUT } lifetime_;
+-  bool enable_port_packets_;
+-
+   // Fills in the local address of the port.
+   void AddAddress(const talk_base::SocketAddress& address,
+                   const std::string& protocol, bool final);
+@@ -239,8 +226,6 @@ class Port : public talk_base::MessageHa
+   void OnReadPacket(const char* data, size_t size,
+                     const talk_base::SocketAddress& addr);
+ 
+-  // Constructs a STUN binding request for the given connection and sends it.
+-  void SendBindingRequest(Connection* conn);
+ 
+   // If the given data comprises a complete and correct STUN message then the
+   // return value is true, otherwise false. If the message username corresponds
+@@ -249,9 +234,25 @@ class Port : public talk_base::MessageHa
+   // remote_username contains the remote fragment of the STUN username.
+   bool GetStunMessage(const char* data, size_t size,
+                       const talk_base::SocketAddress& addr,
+-                      StunMessage *& msg, std::string& remote_username);
++                      StunMessage** out_msg, std::string* out_username);
+ 
+-  friend class Connection;
++  // TODO: make these members private
++  talk_base::Thread* thread_;
++  talk_base::PacketSocketFactory* factory_;
++  std::string type_;
++  talk_base::Network* network_;
++  uint32 ip_;
++  int min_port_;
++  int max_port_;
++  uint32 generation_;
++  std::string name_;
++  std::string username_frag_;
++  std::string password_;
++  float preference_;
++  std::vector<Candidate> candidates_;
++  AddressMap connections_;
++  enum Lifetime { LT_PRESTART, LT_PRETIMEOUT, LT_POSTTIMEOUT } lifetime_;
++  bool enable_port_packets_;
+ 
+  private:
+   // Called when one of our connections deletes itself.
+@@ -263,6 +264,8 @@ class Port : public talk_base::MessageHa
+   // Information to use when going through a proxy.
+   std::string user_agent_;
+   talk_base::ProxyInfo proxy_;
++
++  friend class Connection;
+ };
+ 
+ // Represents a communication link between a port on the local client and a
+@@ -331,7 +334,7 @@ class Connection : public talk_base::Mes
+   // still keep it around in case the other side wants to use it.  But we can
+   // safely stop pinging on it and we can allow it to time out if the other
+   // side stops using it as well.
+-  bool pruned() { return pruned_; }
++  bool pruned() const { return pruned_; }
+   void Prune();
+ 
+   // Makes the connection go away.
+@@ -342,7 +345,7 @@ class Connection : public talk_base::Mes
+   void UpdateState(uint32 now);
+ 
+   // Called when this connection should try checking writability again.
+-  uint32 last_ping_sent() { return last_ping_sent_; }
++  uint32 last_ping_sent() const { return last_ping_sent_; }
+   void Ping(uint32 now);
+ 
+   // Called whenever a valid ping is received on this connection.  This is
+@@ -352,10 +355,33 @@ class Connection : public talk_base::Mes
+   // Debugging description of this connection
+   std::string ToString() const;
+ 
+-  bool reported() { return reported_; }
++  bool reported() const { return reported_; }
+   void set_reported(bool reported) { reported_ = reported;}
+ 
+  protected:
++  // Constructs a new connection to the given remote port.
++  Connection(Port* port, size_t index, const Candidate& candidate);
++
++  // Called back when StunRequestManager has a stun packet to send
++  void OnSendStunPacket(const void* data, size_t size, StunRequest* req);
++
++  // Callbacks from ConnectionRequest
++  void OnConnectionRequestResponse(ConnectionRequest* req,
++                                   StunMessage* response);
++  void OnConnectionRequestErrorResponse(ConnectionRequest* req,
++                                        StunMessage* response);
++  void OnConnectionRequestTimeout(ConnectionRequest* req);
++
++  // Changes the state and signals if necessary.
++  void set_read_state(ReadState value);
++  void set_write_state(WriteState value);
++  void set_connected(bool value);
++
++  // Checks if this connection is useless, and hence, should be destroyed.
++  void CheckTimeout();
++
++  void OnMessage(talk_base::Message *pmsg);
++
+   Port* port_;
+   size_t local_candidate_index_;
+   Candidate remote_candidate_;
+@@ -368,36 +394,17 @@ class Connection : public talk_base::Mes
+   uint32 last_ping_sent_;      // last time we sent a ping to the other side
+   uint32 last_ping_received_;  // last time we received a ping from the other
+                                // side
++  uint32 last_data_received_;
+   std::vector<uint32> pings_since_last_response_;
+ 
+   talk_base::RateTracker recv_rate_tracker_;
+   talk_base::RateTracker send_rate_tracker_;
+ 
+-  // Callbacks from ConnectionRequest
+-  void OnConnectionRequestResponse(StunMessage *response, uint32 rtt);
+-  void OnConnectionRequestErrorResponse(StunMessage *response, uint32 rtt);
+-
+-  // Called back when StunRequestManager has a stun packet to send
+-  void OnSendStunPacket(const void* data, size_t size, StunRequest* req);
+-
+-  // Constructs a new connection to the given remote port.
+-  Connection(Port* port, size_t index, const Candidate& candidate);
+-
+-  // Changes the state and signals if necessary.
+-  void set_read_state(ReadState value);
+-  void set_write_state(WriteState value);
+-  void set_connected(bool value);
+-
+-  // Checks if this connection is useless, and hence, should be destroyed.
+-  void CheckTimeout();
+-
+-  void OnMessage(talk_base::Message *pmsg);
++ private:
++  bool reported_;
+ 
+   friend class Port;
+   friend class ConnectionRequest;
+-
+- private:
+-  bool reported_;
+ };
+ 
+ // ProxyConnection defers all the interesting work to the port
+diff -upN libjingle-0.5.2/talk/p2p/base/pseudotcp.cc.chromium12 libjingle-0.5.2/talk/p2p/base/pseudotcp.cc
+--- libjingle-0.5.2/talk/p2p/base/pseudotcp.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/pseudotcp.cc	2011-03-30 21:51:32.705287001 -0400
+@@ -118,7 +118,7 @@ const uint32 PACKET_OVERHEAD = HEADER_SI
+ const uint32 MIN_RTO   =   250; // 250 ms (RFC1122, Sec 4.2.3.1 "fractions of a second")
+ const uint32 DEF_RTO   =  3000; // 3 seconds (RFC1122, Sec 4.2.3.1)
+ const uint32 MAX_RTO   = 60000; // 60 seconds
+-const uint32 ACK_DELAY =   100; // 100 milliseconds
++const uint32 DEF_ACK_DELAY = 100; // 100 milliseconds
+ 
+ const uint8 FLAG_CTL = 0x02;
+ const uint8 FLAG_RST = 0x04;
+@@ -256,6 +256,9 @@ PseudoTcp::PseudoTcp(IPseudoTcpNotify* n
+ 
+   m_rx_rto = DEF_RTO;
+   m_rx_srtt = m_rx_rttvar = 0;
++
++  m_use_nagling = true;
++  m_ack_delay = DEF_ACK_DELAY;
+ }
+ 
+ PseudoTcp::~PseudoTcp() {
+@@ -337,7 +340,7 @@ void PseudoTcp::NotifyClock(uint32 now) 
+   }
+ 
+   // Check if it's time to send delayed acks
+-  if (m_t_ack && (talk_base::TimeDiff(m_t_ack + ACK_DELAY, now) <= 0)) {
++  if (m_t_ack && (talk_base::TimeDiff(m_t_ack + m_ack_delay, now) <= 0)) {
+     packet(m_snd_nxt, 0, 0, 0);
+   }
+ 
+@@ -367,6 +370,26 @@ bool PseudoTcp::GetNextClock(uint32 now,
+   return clock_check(now, timeout);
+ }
+ 
++void PseudoTcp::GetOption(Option opt, int* value) {
++  if (opt == OPT_NODELAY) {
++    *value = m_use_nagling ? 0 : 1;
++  } else if (opt == OPT_ACKDELAY) {
++    *value = m_ack_delay;
++  } else {
++    ASSERT(false);
++  }
++}
++
++void PseudoTcp::SetOption(Option opt, int value) {
++  if (opt == OPT_NODELAY) {
++    m_use_nagling = value == 0;
++  } else if (opt == OPT_ACKDELAY) {
++    m_ack_delay = value;
++  } else {
++    ASSERT(false);
++  }
++}
++
+ //
+ // IPStream Implementation
+ //
+@@ -554,7 +577,7 @@ bool PseudoTcp::clock_check(uint32 now, 
+ 
+   if (m_t_ack) {
+     nTimeout = talk_base::_min<int32>(nTimeout,
+-      talk_base::TimeDiff(m_t_ack + ACK_DELAY, now));
++      talk_base::TimeDiff(m_t_ack + m_ack_delay, now));
+   }
+   if (m_rto_base) {
+     nTimeout = talk_base::_min<int32>(nTimeout,
+@@ -774,7 +797,11 @@ bool PseudoTcp::process(Segment& seg) {
+   if (seg.seq != m_rcv_nxt) {
+     sflags = sfImmediateAck; // (Fast Recovery)
+   } else if (seg.len != 0) {
+-    sflags = sfDelayedAck;
++    if (m_ack_delay == 0) {
++      sflags = sfImmediateAck;
++    } else {
++      sflags = sfDelayedAck;
++    }
+   }
+ #if _DEBUGMSG >= _DBG_NORMAL
+   if (sflags == sfImmediateAck) {
+@@ -992,8 +1019,11 @@ void PseudoTcp::attemptSend(SendFlags sf
+       return;
+     }
+ 
+-    // Nagle algorithm
+-    if ((m_snd_nxt > m_snd_una) && (nAvailable < m_mss))  {
++    // Nagle's algorithm.
++    // If there is data already in-flight, and we haven't a full segment of
++    // data ready to send then hold off until we get more to send, or the
++    // in-flight data is acknowledged.
++    if (m_use_nagling && (m_snd_nxt > m_snd_una) && (nAvailable < m_mss))  {
+       return;
+     }
+ 
+diff -upN libjingle-0.5.2/talk/p2p/base/pseudotcp.h.chromium12 libjingle-0.5.2/talk/p2p/base/pseudotcp.h
+--- libjingle-0.5.2/talk/p2p/base/pseudotcp.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/pseudotcp.h	2011-03-30 21:51:32.705287001 -0400
+@@ -92,6 +92,18 @@ class PseudoTcp {
+   // Returns false if the socket is ready to be destroyed.
+   bool GetNextClock(uint32 now, long& timeout);
+ 
++  // Call these to get/set option values to tailor this PseudoTcp
++  // instance's behaviour for the kind of data it will carry.
++  // If an unrecognized option is set or got, an assertion will fire.
++  enum Option {
++    OPT_NODELAY,      // Whether to enable Nagle's algorithm (0 == off)
++    OPT_ACKDELAY,     // The Delayed ACK timeout (0 == off).
++    //kOptRcvBuf,     // Set the receive buffer size, in bytes.
++    //kOptSndBuf,     // Set the send buffer size, in bytes.
++  };
++  void GetOption(Option opt, int* value);
++  void SetOption(Option opt, int value);
++
+  protected:
+   enum SendFlags { sfNone, sfDelayedAck, sfImmediateAck };
+   enum {
+@@ -180,6 +192,10 @@ class PseudoTcp {
+   uint8 m_dup_acks;
+   uint32 m_recover;
+   uint32 m_t_ack;
++
++  // Configuration options
++  bool m_use_nagling;
++  uint32 m_ack_delay;
+ };
+ 
+ }  // namespace cricket
+diff -upN libjingle-0.5.2/talk/p2p/base/relayport.cc.chromium12 libjingle-0.5.2/talk/p2p/base/relayport.cc
+--- libjingle-0.5.2/talk/p2p/base/relayport.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/relayport.cc	2011-03-30 21:51:32.706287001 -0400
+@@ -25,11 +25,7 @@
+  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+-#if defined(_MSC_VER) && _MSC_VER < 1300
+-#pragma warning(disable:4786)
+-#endif
+-
+-#include "talk/base/asynctcpsocket.h"
++#include "talk/base/asyncpacketsocket.h"
+ #include "talk/base/helpers.h"
+ #include "talk/base/logging.h"
+ #include "talk/p2p/base/relayport.h"
+@@ -96,8 +92,7 @@ class RelayConnection : public sigslot::
+ class RelayEntry : public talk_base::MessageHandler,
+                    public sigslot::has_slots<> {
+  public:
+-  RelayEntry(RelayPort* port, const talk_base::SocketAddress& ext_addr,
+-             const talk_base::SocketAddress& local_addr);
++  RelayEntry(RelayPort* port, const talk_base::SocketAddress& ext_addr);
+   ~RelayEntry();
+ 
+   RelayPort* port() { return port_; }
+@@ -148,21 +143,20 @@ class RelayEntry : public talk_base::Mes
+ 
+  private:
+   RelayPort* port_;
+-  talk_base::SocketAddress ext_addr_, local_addr_;
++  talk_base::SocketAddress ext_addr_;
+   size_t server_index_;
+   bool connected_;
+   bool locked_;
+   RelayConnection* current_connection_;
+ 
+   // Called when a TCP connection is established or fails
+-  void OnSocketConnect(talk_base::AsyncTCPSocket* socket);
+-  void OnSocketClose(talk_base::AsyncTCPSocket* socket, int error);
++  void OnSocketConnect(talk_base::AsyncPacketSocket* socket);
++  void OnSocketClose(talk_base::AsyncPacketSocket* socket, int error);
+ 
+   // Called when a packet is received on this socket.
+-  void OnReadPacket(
+-      const char* data, size_t size,
+-      const talk_base::SocketAddress& remote_addr,
+-      talk_base::AsyncPacketSocket* socket);
++  void OnReadPacket(talk_base::AsyncPacketSocket* socket,
++                    const char* data, size_t size,
++                    const talk_base::SocketAddress& remote_addr);
+ 
+   // Sends the given data on the socket to the server with no wrapping.  This
+   // returns the number of bytes written or -1 if an error occurred.
+@@ -192,14 +186,16 @@ class AllocateRequest : public StunReque
+ const std::string RELAY_PORT_TYPE("relay");
+ 
+ RelayPort::RelayPort(
+-    talk_base::Thread* thread, talk_base::SocketFactory* factory,
+-    talk_base::Network* network, const talk_base::SocketAddress& local_addr,
++    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)
+-    : Port(thread, RELAY_PORT_TYPE, factory, network), local_addr_(local_addr),
+-      ready_(false), magic_cookie_(magic_cookie), error_(0) {
++    : Port(thread, RELAY_PORT_TYPE, factory, network, ip, min_port, max_port),
++      ready_(false),
++      magic_cookie_(magic_cookie),
++      error_(0) {
+   entries_.push_back(
+-      new RelayEntry(this, talk_base::SocketAddress(), local_addr_));
++      new RelayEntry(this, talk_base::SocketAddress()));
+ 
+   set_username_fragment(username);
+   set_password(password);
+@@ -316,7 +312,7 @@ int RelayPort::SendTo(const void* data, 
+   // If we did not find one, then we make a new one.  This will not be useable
+   // until it becomes connected, however.
+   if (!entry && payload) {
+-    entry = new RelayEntry(this, addr, local_addr_);
++    entry = new RelayEntry(this, addr);
+     if (!entries_.empty()) {
+       entry->SetServerIndex(entries_[0]->ServerIndex());
+     }
+@@ -345,7 +341,7 @@ int RelayPort::SendTo(const void* data, 
+   }
+   // The caller of the function is expecting the number of user data bytes,
+   // rather than the size of the packet.
+-  return (int)size;
++  return size;
+ }
+ 
+ int RelayPort::SetOption(talk_base::Socket::Option opt, int value) {
+@@ -420,9 +416,8 @@ void RelayConnection::SendAllocateReques
+ }
+ 
+ RelayEntry::RelayEntry(RelayPort* port,
+-                       const talk_base::SocketAddress& ext_addr,
+-                       const talk_base::SocketAddress& local_addr)
+-    : port_(port), ext_addr_(ext_addr), local_addr_(local_addr),
++                       const talk_base::SocketAddress& ext_addr)
++    : port_(port), ext_addr_(ext_addr),
+       server_index_(0), connected_(false), locked_(false),
+       current_connection_(NULL) {
+ }
+@@ -455,13 +450,23 @@ void RelayEntry::Connect() {
+   LOG(LS_INFO) << "Connecting to relay via " << ProtoToString(ra->proto) <<
+       " @ " << ra->address.ToString();
+ 
+-  talk_base::AsyncPacketSocket* socket = port_->CreatePacketSocket(ra->proto);
++  talk_base::AsyncPacketSocket* socket = NULL;
++
++  if (ra->proto == PROTO_UDP) {
++    // UDP sockets are simple.
++    socket = port_->socket_factory()->CreateUdpSocket(
++        talk_base::SocketAddress(port_->ip_, 0),
++        port_->min_port_, port_->max_port_);
++  } else if (ra->proto == PROTO_TCP || ra->proto == PROTO_SSLTCP) {
++    socket = port_->socket_factory()->CreateClientTcpSocket(
++        talk_base::SocketAddress(port_->ip_, 0), ra->address,
++        port_->proxy(), port_->user_agent(), ra->proto == PROTO_SSLTCP);
++  } else {
++    LOG(LS_WARNING) << "Unknown protocol (" << ra->proto << ")";
++  }
++
+   if (!socket) {
+     LOG(LS_WARNING) << "Socket creation failed";
+-  } else if (socket->Bind(local_addr_) < 0) {
+-    LOG(LS_WARNING) << "Socket bind failed with error " << socket->GetError();
+-    delete socket;
+-    socket = NULL;
+   }
+ 
+   // If we failed to get a socket, move on to the next protocol.
+@@ -479,13 +484,10 @@ void RelayEntry::Connect() {
+   }
+ 
+   // If we're trying UDP, start binding requests.
+-  // If we're trying TCP, initiate a connection with a fixed timeout.
++  // If we're trying TCP, wait for connection with a fixed timeout.
+   if ((ra->proto == PROTO_TCP) || (ra->proto == PROTO_SSLTCP)) {
+-    talk_base::AsyncTCPSocket* tcp =
+-        static_cast<talk_base::AsyncTCPSocket*>(socket);
+-    tcp->SignalClose.connect(this, &RelayEntry::OnSocketClose);
+-    tcp->SignalConnect.connect(this, &RelayEntry::OnSocketConnect);
+-    tcp->Connect(ra->address);
++    socket->SignalClose.connect(this, &RelayEntry::OnSocketClose);
++    socket->SignalConnect.connect(this, &RelayEntry::OnSocketConnect);
+     port()->thread()->PostDelayed(kSoftConnectTimeoutMs, this,
+                                   kMessageConnectTimeout);
+   } else {
+@@ -538,13 +540,13 @@ int RelayEntry::SendTo(const void* data,
+   StunByteStringAttribute* magic_cookie_attr =
+       StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
+   magic_cookie_attr->CopyBytes(port_->magic_cookie().c_str(),
+-                               (uint16)port_->magic_cookie().size());
++                               port_->magic_cookie().size());
+   request.AddAttribute(magic_cookie_attr);
+ 
+   StunByteStringAttribute* username_attr =
+       StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+   username_attr->CopyBytes(port_->username_fragment().c_str(),
+-                           (uint16)port_->username_fragment().size());
++                           port_->username_fragment().size());
+   request.AddAttribute(username_attr);
+ 
+   StunAddressAttribute* addr_attr =
+@@ -564,7 +566,7 @@ int RelayEntry::SendTo(const void* data,
+ 
+   StunByteStringAttribute* data_attr =
+       StunAttribute::CreateByteString(STUN_ATTR_DATA);
+-  data_attr->CopyBytes(data, (uint16)size);
++  data_attr->CopyBytes(data, size);
+   request.AddAttribute(data_attr);
+ 
+   // TODO: compute the HMAC.
+@@ -616,8 +618,8 @@ void RelayEntry::OnMessage(talk_base::Me
+     // the next address, otherwise give this connection more time and
+     // await the real timeout.
+     //
+-    // TODO: Connect to servers in pararel to speed up connect time
+-    // and to avoid giving up to early.
++    // TODO: Connect to servers in parallel to speed up connect time
++    // and to avoid giving up too early.
+     port_->SignalSoftTimeout(ra);
+     HandleConnectFailure(current_connection_->socket());
+   } else {
+@@ -625,7 +627,7 @@ void RelayEntry::OnMessage(talk_base::Me
+   }
+ }
+ 
+-void RelayEntry::OnSocketConnect(talk_base::AsyncTCPSocket* socket) {
++void RelayEntry::OnSocketConnect(talk_base::AsyncPacketSocket* socket) {
+   LOG(INFO) << "relay tcp connected to " <<
+       socket->GetRemoteAddress().ToString();
+   if (current_connection_ != NULL) {
+@@ -633,14 +635,15 @@ void RelayEntry::OnSocketConnect(talk_ba
+   }
+ }
+ 
+-void RelayEntry::OnSocketClose(talk_base::AsyncTCPSocket* socket, int error) {
++void RelayEntry::OnSocketClose(talk_base::AsyncPacketSocket* socket,
++                               int error) {
+   PLOG(LERROR, error) << "Relay connection failed: socket closed";
+   HandleConnectFailure(socket);
+ }
+ 
+-void RelayEntry::OnReadPacket(const char* data, size_t size,
+-                              const talk_base::SocketAddress& remote_addr,
+-                              talk_base::AsyncPacketSocket* socket) {
++void RelayEntry::OnReadPacket(talk_base::AsyncPacketSocket* socket,
++                              const char* data, size_t size,
++                              const talk_base::SocketAddress& remote_addr) {
+   // ASSERT(remote_addr == port_->server_addr());
+   // TODO: are we worried about this?
+ 
+@@ -732,14 +735,14 @@ void AllocateRequest::Prepare(StunMessag
+       StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
+   magic_cookie_attr->CopyBytes(
+       entry_->port()->magic_cookie().c_str(),
+-      (uint16)entry_->port()->magic_cookie().size());
++      entry_->port()->magic_cookie().size());
+   request->AddAttribute(magic_cookie_attr);
+ 
+   StunByteStringAttribute* username_attr =
+       StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
+   username_attr->CopyBytes(
+       entry_->port()->username_fragment().c_str(),
+-      (uint16)entry_->port()->username_fragment().size());
++      entry_->port()->username_fragment().size());
+   request->AddAttribute(username_attr);
+ }
+ 
+diff -upN libjingle-0.5.2/talk/p2p/base/relayport.h.chromium12 libjingle-0.5.2/talk/p2p/base/relayport.h
+--- libjingle-0.5.2/talk/p2p/base/relayport.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/relayport.h	2011-03-30 21:51:32.706287001 -0400
+@@ -28,8 +28,11 @@
+ #ifndef TALK_P2P_BASE_RELAYPORT_H_
+ #define TALK_P2P_BASE_RELAYPORT_H_
+ 
++#include <deque>
+ #include <string>
++#include <utility>
+ #include <vector>
++
+ #include "talk/p2p/base/port.h"
+ #include "talk/p2p/base/stunrequest.h"
+ 
+@@ -51,18 +54,13 @@ class RelayPort : public Port {
+ 
+   // RelayPort doesn't yet do anything fancy in the ctor.
+   static RelayPort* Create(
+-    talk_base::Thread* thread, talk_base::SocketFactory* factory,
+-    talk_base::Network* network, const talk_base::SocketAddress& local_addr,
+-    const std::string& username, const std::string& password,
+-    const std::string& magic_cookie) {
+-    return new RelayPort(thread, factory, network, local_addr,
++      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) {
++    return new RelayPort(thread, factory, network, ip, min_port, max_port,
+                          username, password, magic_cookie);
+   }
+-  RelayPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
+-            talk_base::Network*, const talk_base::SocketAddress& local_addr,
+-            const std::string& username, const std::string& password,
+-            const std::string& magic_cookie);
+-  bool Init();
+   virtual ~RelayPort();
+ 
+   void AddServerAddress(const ProtocolAddress& addr);
+@@ -86,6 +84,12 @@ class RelayPort : public Port {
+   sigslot::signal1<const ProtocolAddress*> SignalSoftTimeout;
+ 
+  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);
++  bool Init();
++
+   void SetReady();
+ 
+   virtual int SendTo(const void* data, size_t size,
+@@ -98,7 +102,6 @@ class RelayPort : public Port {
+  private:
+   friend class RelayEntry;
+ 
+-  talk_base::SocketAddress local_addr_;
+   std::deque<ProtocolAddress> server_addr_;
+   bool ready_;
+   std::vector<RelayEntry*> entries_;
+diff -upN libjingle-0.5.2/talk/p2p/base/relayserver.cc.chromium12 libjingle-0.5.2/talk/p2p/base/relayserver.cc
+--- libjingle-0.5.2/talk/p2p/base/relayserver.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/relayserver.cc	2011-03-30 21:51:32.706287001 -0400
+@@ -159,12 +159,24 @@ void RelayServer::RemoveInternalServerSo
+   socket->SignalReadEvent.disconnect(this);
+ }
+ 
+-int RelayServer::GetConnectionCount() {
++int RelayServer::GetConnectionCount() const {
+   return connections_.size();
+ }
+ 
+-bool RelayServer::HasConnection(const talk_base::SocketAddress& address) {
+-  for (ConnectionMap::iterator it = connections_.begin();
++talk_base::SocketAddressPair RelayServer::GetConnection(int connection) const {
++  int i = 0;
++  for (ConnectionMap::const_iterator it = connections_.begin();
++       it != connections_.end(); ++it) {
++    if (i == connection) {
++      return it->second->addr_pair();
++    }
++    ++i;
++  }
++  return talk_base::SocketAddressPair();
++}
++
++bool RelayServer::HasConnection(const talk_base::SocketAddress& address) const {
++  for (ConnectionMap::const_iterator it = connections_.begin();
+        it != connections_.end(); ++it) {
+     if (it->second->addr_pair().destination() == address) {
+       return true;
+@@ -180,11 +192,14 @@ void RelayServer::OnReadEvent(talk_base:
+ }
+ 
+ void RelayServer::OnInternalPacket(
+-    const char* bytes, size_t size, const talk_base::SocketAddress& remote_addr,
+-    talk_base::AsyncPacketSocket* socket) {
++    talk_base::AsyncPacketSocket* socket, const char* bytes, size_t size,
++    const talk_base::SocketAddress& remote_addr) {
+ 
+   // Get the address of the connection we just received on.
+-  talk_base::SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
++  bool allocated;
++  talk_base::SocketAddressPair ap(
++      remote_addr, socket->GetLocalAddress(&allocated));
++  ASSERT(allocated);
+   ASSERT(!ap.destination().IsAny());
+ 
+   // If this did not come from an existing connection, it should be a STUN
+@@ -224,11 +239,14 @@ void RelayServer::OnInternalPacket(
+ }
+ 
+ void RelayServer::OnExternalPacket(
+-    const char* bytes, size_t size, const talk_base::SocketAddress& remote_addr,
+-    talk_base::AsyncPacketSocket* socket) {
++    talk_base::AsyncPacketSocket* socket, const char* bytes, size_t size,
++    const talk_base::SocketAddress& remote_addr) {
+ 
+   // Get the address of the connection we just received on.
+-  talk_base::SocketAddressPair ap(remote_addr, socket->GetLocalAddress());
++  bool allocated;
++  talk_base::SocketAddressPair ap(
++      remote_addr, socket->GetLocalAddress(&allocated));
++  ASSERT(allocated);
+   ASSERT(!ap.destination().IsAny());
+ 
+   // If this connection already exists, then forward the traffic.
+@@ -425,8 +443,10 @@ void RelayServer::HandleStunAllocate(
+   response.AddAttribute(magic_cookie_attr);
+ 
+   size_t index = rand() % external_sockets_.size();
++  bool allocated;
+   talk_base::SocketAddress ext_addr =
+-      external_sockets_[index]->GetLocalAddress();
++      external_sockets_[index]->GetLocalAddress(&allocated);
++  ASSERT(allocated);
+ 
+   StunAddressAttribute* addr_attr =
+       StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
+@@ -472,7 +492,10 @@ void RelayServer::HandleStunSend(
+     // Create a new connection to establish the relationship with this binding.
+     ASSERT(external_sockets_.size() == 1);
+     talk_base::AsyncPacketSocket* socket = external_sockets_[0];
+-    talk_base::SocketAddressPair ap(ext_addr, socket->GetLocalAddress());
++    bool allocated;
++    talk_base::SocketAddressPair ap(
++        ext_addr, socket->GetLocalAddress(&allocated));
++    ASSERT(allocated);
+     ext_conn = new RelayServerConnection(int_conn->binding(), ap, socket);
+     ext_conn->binding()->AddExternalConnection(ext_conn);
+     AddConnection(ext_conn);
+@@ -559,7 +582,7 @@ void RelayServer::AcceptConnection(talk_
+       accepted_socket = new talk_base::AsyncSSLServerSocket(accepted_socket);
+     }
+     talk_base::AsyncTCPSocket* tcp_socket =
+-        new talk_base::AsyncTCPSocket(accepted_socket);
++        new talk_base::AsyncTCPSocket(accepted_socket, false);
+ 
+     // Finally add the socket so it can start communicating with the client.
+     AddInternalSocket(tcp_socket);
+diff -upN libjingle-0.5.2/talk/p2p/base/relayserver.h.chromium12 libjingle-0.5.2/talk/p2p/base/relayserver.h
+--- libjingle-0.5.2/talk/p2p/base/relayserver.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/relayserver.h	2011-03-30 21:51:32.707287001 -0400
+@@ -25,8 +25,12 @@
+  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+-#ifndef __RELAYSERVER_H__
+-#define __RELAYSERVER_H__
++#ifndef TALK_P2P_BASE_RELAYSERVER_H_
++#define TALK_P2P_BASE_RELAYSERVER_H_
++
++#include <string>
++#include <vector>
++#include <map>
+ 
+ #include "talk/base/asyncudpsocket.h"
+ #include "talk/base/socketaddresspair.h"
+@@ -35,10 +39,6 @@
+ #include "talk/p2p/base/port.h"
+ #include "talk/p2p/base/stun.h"
+ 
+-#include <string>
+-#include <vector>
+-#include <map>
+-
+ namespace cricket {
+ 
+ class RelayServerBinding;
+@@ -48,9 +48,9 @@ class RelayServerConnection;
+ // All connections created with the same username/password are bound together.
+ class RelayServer : public talk_base::MessageHandler,
+                     public sigslot::has_slots<> {
+-public:
++ public:
+   // Creates a server, which will use this thread to post messages to itself.
+-  RelayServer(talk_base::Thread* thread);
++  explicit RelayServer(talk_base::Thread* thread);
+   ~RelayServer();
+ 
+   talk_base::Thread* thread() { return thread_; }
+@@ -79,16 +79,18 @@ public:
+   // Removes this server socket from the list.
+   void RemoveInternalServerSocket(talk_base::AsyncSocket* socket);
+ 
+-  int GetConnectionCount();
++  // Methods for testing and debuging.
++  int GetConnectionCount() const;
++  talk_base::SocketAddressPair GetConnection(int connection) const;
++  bool HasConnection(const talk_base::SocketAddress& address) const;
+ 
+-  bool HasConnection(const talk_base::SocketAddress& address);
+-
+-private:
++ private:
+   typedef std::vector<talk_base::AsyncPacketSocket*> SocketList;
+   typedef std::map<talk_base::AsyncSocket*,
+                    cricket::ProtocolType> ServerSocketMap;
+-  typedef std::map<std::string,RelayServerBinding*> BindingMap;
+-  typedef std::map<talk_base::SocketAddressPair,RelayServerConnection*> ConnectionMap;
++  typedef std::map<std::string, RelayServerBinding*> BindingMap;
++  typedef std::map<talk_base::SocketAddressPair,
++                   RelayServerConnection*> ConnectionMap;
+ 
+   talk_base::Thread* thread_;
+   bool log_bindings_;
+@@ -99,18 +101,19 @@ private:
+   ConnectionMap connections_;
+ 
+   // Called when a packet is received by the server on one of its sockets.
+-  void OnInternalPacket(
+-      const char* bytes, size_t size, const talk_base::SocketAddress& remote_addr,
+-      talk_base::AsyncPacketSocket* socket);
+-  void OnExternalPacket(
+-      const char* bytes, size_t size, const talk_base::SocketAddress& remote_addr,
+-      talk_base::AsyncPacketSocket* socket);
++  void OnInternalPacket(talk_base::AsyncPacketSocket* socket,
++                        const char* bytes, size_t size,
++                        const talk_base::SocketAddress& remote_addr);
++  void OnExternalPacket(talk_base::AsyncPacketSocket* socket,
++                        const char* bytes, size_t size,
++                        const talk_base::SocketAddress& remote_addr);
+ 
+   void OnReadEvent(talk_base::AsyncSocket* socket);
+ 
+   // Processes the relevant STUN request types from the client.
+   bool HandleStun(const char* bytes, size_t size,
+-                  const talk_base::SocketAddress& remote_addr, talk_base::AsyncPacketSocket* socket,
++                  const talk_base::SocketAddress& remote_addr,
++                  talk_base::AsyncPacketSocket* socket,
+                   std::string* username, StunMessage* msg);
+   void HandleStunAllocate(const char* bytes, size_t size,
+                           const talk_base::SocketAddressPair& ap,
+@@ -142,7 +145,7 @@ private:
+ // Maintains information about a connection to the server.  Each connection is
+ // part of one and only one binding.
+ class RelayServerConnection {
+-public:
++ public:
+   RelayServerConnection(RelayServerBinding* binding,
+                         const talk_base::SocketAddressPair& addrs,
+                         talk_base::AsyncPacketSocket* socket);
+@@ -158,7 +161,8 @@ public:
+   // Sends a packet to the connected client.  If an address is provided, then
+   // we make sure the internal client receives it, wrapping if necessary.
+   void Send(const char* data, size_t size);
+-  void Send(const char* data, size_t size, const talk_base::SocketAddress& ext_addr);
++  void Send(const char* data, size_t size,
++            const talk_base::SocketAddress& ext_addr);
+ 
+   // Sends a STUN message to the connected client with no wrapping.
+   void SendStun(const StunMessage& msg);
+@@ -172,12 +176,14 @@ public:
+ 
+   // Records the address that raw packets should be forwarded to (for internal
+   // packets only; for external, we already know where they go).
+-  const talk_base::SocketAddress& default_destination() const { return default_dest_; }
++  const talk_base::SocketAddress& default_destination() const {
++    return default_dest_;
++  }
+   void set_default_destination(const talk_base::SocketAddress& addr) {
+     default_dest_ = addr;
+   }
+ 
+-private:
++ private:
+   RelayServerBinding* binding_;
+   talk_base::SocketAddressPair addr_pair_;
+   talk_base::AsyncPacketSocket* socket_;
+@@ -188,7 +194,7 @@ private:
+ // Records a set of internal and external connections that we relay between,
+ // or in other words, that are "bound" together.
+ class RelayServerBinding : public talk_base::MessageHandler {
+-public:
++ public:
+   RelayServerBinding(
+       RelayServer* server, const std::string& username,
+       const std::string& password, uint32 lifetime);
+@@ -215,13 +221,15 @@ public:
+ 
+   // Determines the connection to use to send packets to or from the given
+   // external address.
+-  RelayServerConnection* GetInternalConnection(const talk_base::SocketAddress& ext_addr);
+-  RelayServerConnection* GetExternalConnection(const talk_base::SocketAddress& ext_addr);
++  RelayServerConnection* GetInternalConnection(
++      const talk_base::SocketAddress& ext_addr);
++  RelayServerConnection* GetExternalConnection(
++      const talk_base::SocketAddress& ext_addr);
+ 
+   // MessageHandler:
+   void OnMessage(talk_base::Message *pmsg);
+ 
+-private:
++ private:
+   RelayServer* server_;
+ 
+   std::string username_;
+@@ -236,6 +244,6 @@ private:
+   // TODO: bandwidth
+ };
+ 
+-} // namespace cricket
++}  // namespace cricket
+ 
+-#endif // __RELAYSERVER_H__
++#endif  // TALK_P2P_BASE_RELAYSERVER_H_
+diff -upN libjingle-0.5.2/talk/p2p/base/relayserver_main.cc.chromium12 libjingle-0.5.2/talk/p2p/base/relayserver_main.cc
+--- libjingle-0.5.2/talk/p2p/base/relayserver_main.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/relayserver_main.cc	2011-03-30 21:51:32.707287001 -0400
+@@ -53,18 +53,18 @@ int main(int argc, char **argv) {
+   talk_base::Thread *pthMain = talk_base::Thread::Current();
+ 
+   talk_base::scoped_ptr<talk_base::AsyncUDPSocket> int_socket(
+-      talk_base::CreateAsyncUDPSocket(pthMain->socketserver()));
+-  if (int_socket->Bind(int_addr) < 0) {
+-    std::cerr << "Internal socket bind(" << int_addr.ToString() << "): "
+-              << std::strerror(int_socket->GetError()) << std::endl;
++      talk_base::AsyncUDPSocket::Create(pthMain->socketserver(), int_addr));
++  if (!int_socket.get()) {
++    std::cerr << "Failed to create a UDP socket bound at"
++              << int_addr.ToString() << std::endl;
+     return 1;
+   }
+ 
+   talk_base::scoped_ptr<talk_base::AsyncUDPSocket> ext_socket(
+-      talk_base::CreateAsyncUDPSocket(pthMain->socketserver()));
+-  if (ext_socket->Bind(ext_addr) < 0) {
+-    std::cerr << "External socket bind(" << ext_addr.ToString() << "): "
+-              << std::strerror(ext_socket->GetError()) << std::endl;
++      talk_base::AsyncUDPSocket::Create(pthMain->socketserver(), ext_addr));
++  if (ext_socket.get()) {
++    std::cerr << "Failed to create a UDP socket bound at"
++              << ext_addr.ToString() << std::endl;
+     return 1;
+   }
+ 
+diff -upN libjingle-0.5.2/talk/p2p/base/session.cc.chromium12 libjingle-0.5.2/talk/p2p/base/session.cc
+--- libjingle-0.5.2/talk/p2p/base/session.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/session.cc	2011-03-30 21:51:32.707287001 -0400
+@@ -180,8 +180,6 @@ void BaseSession::SetError(Error error) 
+   if (error != error_) {
+     error_ = error;
+     SignalError(this, error);
+-    if (error_ != ERROR_NONE)
+-      signaling_thread_->Post(this, MSG_ERROR);
+   }
+ }
+ 
+@@ -647,12 +645,10 @@ void Session::OnIncomingMessage(const Se
+       valid = OnTransportAcceptMessage(msg, &error);
+       break;
+     case ACTION_NOTIFY:
++      valid = OnNotifyMessage(msg, &error);
++      break;
+     case ACTION_UPDATE:
+-      // TODO: Process these non-standard messages, but
+-      // only once we figure out how in a jingle-specific way (or
+-      // remove the need altogether).  For now, just don't send an
+-      // error back, because it disrupts call establishment.
+-      valid = true;
++      valid = OnUpdateMessage(msg, &error);
+       break;
+     default:
+       valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST,
+@@ -697,13 +693,16 @@ void Session::OnFailedSend(const buzz::X
+   std::string error_type = "cancel";
+ 
+   const buzz::XmlElement* error = error_stanza->FirstNamed(buzz::QN_ERROR);
+-  ASSERT(error != NULL);
+   if (error) {
+     ASSERT(error->HasAttr(buzz::QN_TYPE));
+     error_type = error->Attr(buzz::QN_TYPE);
+ 
+     LOG(LS_ERROR) << "Session error:\n" << error->Str() << "\n"
+                   << "in response to:\n" << orig_stanza->Str();
++  } else {
++    // don't crash if <error> is missing
++    LOG(LS_ERROR) << "Session error without <error/> element, ignoring";
++    return;
+   }
+ 
+   if (msg.type == ACTION_TRANSPORT_INFO) {
+@@ -832,6 +831,30 @@ bool Session::OnTransportAcceptMessage(c
+   return true;
+ }
+ 
++bool Session::OnNotifyMessage(const SessionMessage& msg,
++                              MessageError* error) {
++  SessionNotify notify;
++  if (!ParseSessionNotify(msg.action_elem, &notify, error)) {
++    return false;
++  }
++
++  SignalMediaSources(notify.nickname_to_sources);
++
++  return true;
++}
++
++bool Session::OnUpdateMessage(const SessionMessage& msg,
++                              MessageError* error) {
++  SessionUpdate update;
++  if (!ParseSessionUpdate(msg.action_elem, &update, error)) {
++    return false;
++  }
++
++  // TODO: Process this message appropriately.
++
++  return true;
++}
++
+ bool BareJidsEqual(const std::string& name1,
+                    const std::string& name2) {
+   buzz::Jid jid1(name1);
+@@ -868,6 +891,12 @@ bool Session::CheckState(State state, Me
+   return true;
+ }
+ 
++void Session::SetError(Error error) {
++  BaseSession::SetError(error);
++  if (error_ != ERROR_NONE)
++    signaling_thread_->Post(this, MSG_ERROR);
++}
++
+ void Session::OnMessage(talk_base::Message *pmsg) {
+   // preserve this because BaseSession::OnMessage may modify it
+   BaseSession::State orig_state = state_;
+@@ -909,6 +938,16 @@ bool Session::WriteSessionAction(
+                               elems, error);
+ }
+ 
++bool Session::SetVideoView(
++    const std::vector<VideoViewRequest>& view_requests) {
++  SessionView view;
++  SessionError error;
++
++  view.view_requests = view_requests;
++
++  return !SendViewMessage(view, &error);
++}
++
+ bool Session::SendAcceptMessage(const SessionDescription* sdesc,
+                                 SessionError* error) {
+   XmlElements elems;
+@@ -958,6 +997,12 @@ bool Session::WriteSessionAction(Signali
+                              elems, error);
+ }
+ 
++bool Session::SendViewMessage(const SessionView& view, SessionError* error) {
++  XmlElements elems;
++  WriteSessionView(view, &elems);
++  return SendMessage(ACTION_VIEW, elems, error);
++}
++
+ bool Session::ResendAllTransportInfoMessages(SessionError* error) {
+   for (TransportMap::iterator iter = transports_.begin();
+        iter != transports_.end(); ++iter) {
+diff -upN libjingle-0.5.2/talk/p2p/base/session.h.chromium12 libjingle-0.5.2/talk/p2p/base/session.h
+--- libjingle-0.5.2/talk/p2p/base/session.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/session.h	2011-03-30 21:51:32.708287001 -0400
+@@ -42,8 +42,6 @@
+ #include "talk/xmllite/xmlelement.h"
+ #include "talk/xmpp/constants.h"
+ 
+-class JingleMessageHandler;
+-
+ namespace cricket {
+ 
+ class P2PTransportChannel;
+@@ -163,6 +161,7 @@ class BaseSession : public sigslot::has_
+     ERROR_TIME = 1,      // no response to signaling
+     ERROR_RESPONSE = 2,  // error during signaling
+     ERROR_NETWORK = 3,   // network error, could not allocate network resources
++    ERROR_CONTENT = 4,   // channel errors in SetLocalContent/SetRemoteContent
+   };
+ 
+   explicit BaseSession(talk_base::Thread *signaling_thread);
+@@ -172,7 +171,7 @@ class BaseSession : public sigslot::has_
+   void SetState(State state);
+ 
+   // Updates the error state, signaling if necessary.
+-  void SetError(Error error);
++  virtual void SetError(Error error);
+ 
+   // Handles messages posted to us.
+   virtual void OnMessage(talk_base::Message *pmsg);
+@@ -364,9 +363,20 @@ class Session : public BaseSession {
+   virtual void DestroyChannel(const std::string& content_name,
+                               const std::string& channel_name);
+ 
++  // Updates the error state, signaling if necessary.
++  virtual void SetError(Error error);
++
+   // Handles messages posted to us.
+   virtual void OnMessage(talk_base::Message *pmsg);
+ 
++  // Fired when notification of media sources is received from the server.
++  // Passes a map whose keys are strings containing nick names for users
++  // in the session and whose values contain the SSRCs for each user.
++  sigslot::signal1<const StringToMediaSourcesMap&> SignalMediaSources;
++
++  // Sets the video streams to receive from the server.
++  bool SetVideoView(const VideoViewRequestVector& view_requests);
++
+  private:
+   // Creates or destroys a session.  (These are called only SessionManager.)
+   Session(SessionManager *session_manager,
+@@ -439,6 +449,7 @@ class Session : public BaseSession {
+   bool SendTerminateMessage(const std::string& reason, SessionError* error);
+   bool SendTransportInfoMessage(const TransportInfo& tinfo,
+                                 SessionError* error);
++  bool SendViewMessage(const SessionView& view, SessionError* error);
+   bool ResendAllTransportInfoMessages(SessionError* error);
+ 
+   // Both versions of SendMessage send a message of the given type to
+@@ -510,6 +521,8 @@ class Session : public BaseSession {
+   bool OnTerminateMessage(const SessionMessage& msg, MessageError* error);
+   bool OnTransportInfoMessage(const SessionMessage& msg, MessageError* error);
+   bool OnTransportAcceptMessage(const SessionMessage& msg, MessageError* error);
++  bool OnNotifyMessage(const SessionMessage& msg, MessageError* error);
++  bool OnUpdateMessage(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 -upN libjingle-0.5.2/talk/p2p/base/sessionmessages.cc.chromium12 libjingle-0.5.2/talk/p2p/base/sessionmessages.cc
+--- libjingle-0.5.2/talk/p2p/base/sessionmessages.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/sessionmessages.cc	2011-03-30 21:51:32.708287001 -0400
+@@ -25,11 +25,13 @@
+  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
++#include <stdio.h>
+ #include <string>
+ #include "talk/p2p/base/sessionmessages.h"
+ 
+ #include "talk/base/logging.h"
+ #include "talk/base/scoped_ptr.h"
++#include "talk/base/stringutils.h"
+ #include "talk/xmllite/xmlconstants.h"
+ #include "talk/xmpp/constants.h"
+ #include "talk/p2p/base/constants.h"
+@@ -38,6 +40,7 @@
+ #include "talk/p2p/base/sessionclient.h"
+ #include "talk/p2p/base/sessiondescription.h"
+ #include "talk/p2p/base/transport.h"
++#include "talk/xmllite/xmlconstants.h"
+ 
+ namespace cricket {
+ 
+@@ -112,6 +115,8 @@ std::string ToGingleString(ActionType ty
+       return GINGLE_ACTION_REJECT;
+     case ACTION_SESSION_TERMINATE:
+       return GINGLE_ACTION_TERMINATE;
++    case ACTION_VIEW:
++      return GINGLE_ACTION_VIEW;
+     case ACTION_TRANSPORT_INFO:
+       return GINGLE_ACTION_CANDIDATES;
+     default:
+@@ -126,7 +131,12 @@ bool IsJingleMessage(const buzz::XmlElem
+     return false;
+ 
+   return (jingle->HasAttr(buzz::QN_ACTION) &&
+-          jingle->HasAttr(buzz::QN_ID));
++          (jingle->HasAttr(QN_SID)
++           // TODO: This works around a bug in old jingle
++           // clients that set QN_ID instead of QN_SID.  Once we know
++           // there are no clients which have this bug, we can remove
++           // this code.
++           || jingle->HasAttr(QN_ID)));
+ }
+ 
+ bool IsGingleMessage(const buzz::XmlElement* stanza) {
+@@ -168,7 +178,13 @@ bool ParseJingleSessionMessage(const buz
+   msg->protocol = PROTOCOL_JINGLE;
+   std::string type_string = jingle->Attr(buzz::QN_ACTION);
+   msg->type = ToActionType(type_string);
+-  msg->sid = jingle->Attr(buzz::QN_ID);
++  msg->sid = jingle->Attr(QN_SID);
++  // TODO: This works around a bug in old jingle clients
++  // that set QN_ID instead of QN_SID.  Once we know there are no
++  // clients which have this bug, we can remove this code.
++  if (msg->sid.empty()) {
++    msg->sid = jingle->Attr(buzz::QN_ID);
++  }
+   msg->initiator = GetXmlAttr(jingle, QN_INITIATOR, buzz::STR_EMPTY);
+   msg->action_elem = jingle;
+ 
+@@ -221,7 +237,11 @@ buzz::XmlElement* WriteJingleAction(cons
+                                     const XmlElements& action_elems) {
+   buzz::XmlElement* jingle = new buzz::XmlElement(QN_JINGLE, true);
+   jingle->AddAttr(buzz::QN_ACTION, ToJingleString(msg.type));
+-  jingle->AddAttr(buzz::QN_ID, msg.sid);
++  jingle->AddAttr(QN_SID, msg.sid);
++  // TODO: This works around a bug in old jingle clinets
++  // that expected QN_ID instead of QN_SID.  Once we know there are no
++  // clients which have this bug, we can remove this code.
++  jingle->AddAttr(QN_ID, msg.sid);
+   // TODO: Right now, the XMPP server rejects a jingle-only
+   // (non hybrid) message with "feature-not-implemented" if there is
+   // no initiator.  Fix the server, and then only set the initiator on
+@@ -824,6 +844,40 @@ bool WriteTransportInfos(SignalingProtoc
+   }
+ }
+ 
++bool ParseSessionNotify(const buzz::XmlElement* action_elem,
++                        SessionNotify* notify, ParseError* error) {
++  const buzz::XmlElement* notify_elem;
++  for (notify_elem = action_elem->FirstNamed(QN_GINGLE_NOTIFY);
++      notify_elem != NULL;
++      notify_elem = notify_elem->NextNamed(QN_GINGLE_NOTIFY)) {
++    // Note that a subsequent notify element for the same user will override a
++    // previous.  We don't merge them.
++    std::string nick(notify_elem->Attr(QN_GINGLE_NOTIFY_NICK));
++    if (nick != buzz::STR_EMPTY) {
++      MediaSources sources;
++      const buzz::XmlElement* source_elem;
++      for (source_elem = notify_elem->FirstNamed(QN_GINGLE_NOTIFY_SOURCE);
++          source_elem != NULL;
++          source_elem = source_elem->NextNamed(QN_GINGLE_NOTIFY_SOURCE)) {
++        std::string ssrc = source_elem->Attr(QN_GINGLE_NOTIFY_SOURCE_SSRC);
++        if (ssrc != buzz::STR_EMPTY) {
++          std::string mtype = source_elem->Attr(QN_GINGLE_NOTIFY_SOURCE_MTYPE);
++          if (mtype == GINGLE_NOTIFY_SOURCE_MTYPE_AUDIO) {
++            sources.audio_ssrc = strtoul(ssrc.c_str(), NULL, 10);
++          } else if (mtype == GINGLE_NOTIFY_SOURCE_MTYPE_VIDEO) {
++            sources.video_ssrc = strtoul(ssrc.c_str(), NULL, 10);
++          }
++        }
++      }
++
++      notify->nickname_to_sources.insert(
++          std::pair<std::string, MediaSources>(nick, sources));
++    }
++  }
++
++  return true;
++}
++
+ bool GetUriTarget(const std::string& prefix, const std::string& str,
+                   std::string* after) {
+   size_t pos = str.find(prefix);
+@@ -834,6 +888,65 @@ bool GetUriTarget(const std::string& pre
+   return true;
+ }
+ 
++bool ParseSessionUpdate(const buzz::XmlElement* action_elem,
++                        SessionUpdate* update, ParseError* error) {
++  // TODO: Parse the update message.
++  return true;
++}
++
++void WriteSessionView(const SessionView& view, XmlElements* elems) {
++  std::vector<VideoViewRequest>::const_iterator it;
++  for (it = view.view_requests.begin(); it != view.view_requests.end(); it++) {
++    talk_base::scoped_ptr<buzz::XmlElement> view_elem(
++        new buzz::XmlElement(QN_GINGLE_VIEW));
++    if (view_elem.get() == NULL) {
++      return;
++    }
++
++    view_elem->SetAttr(QN_GINGLE_VIEW_TYPE, GINGLE_VIEW_TYPE_STATIC);
++    view_elem->SetAttr(QN_GINGLE_VIEW_NICK, it->nick_name);
++    view_elem->SetAttr(QN_GINGLE_VIEW_MEDIA_TYPE,
++        GINGLE_VIEW_MEDIA_TYPE_VIDEO);
++
++    // A 32-bit uint, expressed as decimal, has a max of 10 digits, plus one
++    // for the null.
++    char str[11];
++    int result = talk_base::sprintfn(str, ARRAY_SIZE(str), "%u", it->ssrc);
++    if (result < 0 || result >= ARRAY_SIZE(str)) {
++      continue;
++    }
++    view_elem->SetAttr(QN_GINGLE_VIEW_SSRC, str);
++
++    // Include video-specific parameters in a child <params> element.
++    talk_base::scoped_ptr<buzz::XmlElement> params_elem(
++        new buzz::XmlElement(QN_GINGLE_VIEW_PARAMS));
++    if (params_elem.get() == NULL) {
++      return;
++    }
++
++    result = talk_base::sprintfn(str, ARRAY_SIZE(str), "%u", it->width);
++    if (result < 0 || result >= ARRAY_SIZE(str)) {
++      continue;
++    }
++    params_elem->SetAttr(QN_GINGLE_VIEW_PARAMS_WIDTH, str);
++
++    result = talk_base::sprintfn(str, ARRAY_SIZE(str), "%u", it->height);
++    if (result < 0 || result >= ARRAY_SIZE(str)) {
++      continue;
++    }
++    params_elem->SetAttr(QN_GINGLE_VIEW_PARAMS_HEIGHT, str);
++
++    result = talk_base::sprintfn(str, ARRAY_SIZE(str), "%u", it->framerate);
++    if (result < 0 || result >= ARRAY_SIZE(str)) {
++      continue;
++    }
++    params_elem->SetAttr(QN_GINGLE_VIEW_PARAMS_FRAMERATE, str);
++
++    view_elem->AddElement(params_elem.release());
++    elems->push_back(view_elem.release());
++  }
++}
++
+ bool FindSessionRedirect(const buzz::XmlElement* stanza,
+                          SessionRedirect* redirect) {
+   const buzz::XmlElement* error_elem = GetXmlChild(stanza, LN_ERROR);
+diff -upN libjingle-0.5.2/talk/p2p/base/sessionmessages.h.chromium12 libjingle-0.5.2/talk/p2p/base/sessionmessages.h
+--- libjingle-0.5.2/talk/p2p/base/sessionmessages.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/sessionmessages.h	2011-03-30 21:51:32.709287001 -0400
+@@ -35,6 +35,7 @@
+ #include "talk/xmllite/xmlelement.h"
+ #include "talk/p2p/base/constants.h"
+ #include "talk/p2p/base/sessiondescription.h"  // Needed to delete contents.
++#include "talk/base/basictypes.h"
+ 
+ namespace cricket {
+ 
+@@ -66,6 +67,7 @@ enum ActionType {
+   // being needed at all.
+   ACTION_NOTIFY,
+   ACTION_UPDATE,
++  ACTION_VIEW,
+ };
+ 
+ // Abstraction of a <jingle> element within an <iq> stanza, per XMPP
+@@ -159,6 +161,45 @@ struct SessionRedirect {
+   std::string target;
+ };
+ 
++// Holds the ssrcs for a user's media streams.
++struct MediaSources {
++  uint32 audio_ssrc;
++  uint32 video_ssrc;
++  MediaSources() : audio_ssrc(0), video_ssrc(0) {}
++};
++
++typedef std::map<std::string, MediaSources> StringToMediaSourcesMap;
++
++struct SessionNotify {
++  // A mapping of room users (identified by their nicknames) to their ssrcs.
++  StringToMediaSourcesMap nickname_to_sources;
++};
++
++// TODO: Populate the update message.
++struct SessionUpdate {
++};
++
++// Represents an individual <view> element in the <session type="view">
++// message.
++struct VideoViewRequest {
++  std::string nick_name;
++  uint32 ssrc;
++  uint32 width;
++  uint32 height;
++  uint32 framerate;
++
++  VideoViewRequest(const std::string& nick_name, uint32 ssrc, uint32 width,
++            uint32 height, uint32 framerate) :
++      nick_name(nick_name), ssrc(ssrc), width(width), height(height),
++      framerate(framerate) {}
++};
++
++typedef std::vector<VideoViewRequest> VideoViewRequestVector;
++
++struct SessionView {
++  VideoViewRequestVector view_requests;
++};
++
+ bool IsSessionMessage(const buzz::XmlElement* stanza);
+ bool ParseSessionMessage(const buzz::XmlElement* stanza,
+                          SessionMessage* msg,
+@@ -218,6 +259,11 @@ bool WriteTransportInfos(SignalingProtoc
+                          const TransportParserMap& trans_parsers,
+                          XmlElements* elems,
+                          WriteError* error);
++bool ParseSessionNotify(const buzz::XmlElement* action_elem,
++                        SessionNotify* notify, ParseError* error);
++bool ParseSessionUpdate(const buzz::XmlElement* action_elem,
++                        SessionUpdate* update, ParseError* error);
++void WriteSessionView(const SessionView& view, XmlElements* elems);
+ // Handles both Gingle and Jingle syntax.
+ bool FindSessionRedirect(const buzz::XmlElement* stanza,
+                          SessionRedirect* redirect);
+diff -upN libjingle-0.5.2/talk/p2p/base/stunport.cc.chromium12 libjingle-0.5.2/talk/p2p/base/stunport.cc
+--- libjingle-0.5.2/talk/p2p/base/stunport.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/stunport.cc	2011-03-30 21:51:32.709287001 -0400
+@@ -102,8 +102,8 @@ class StunPortBindingRequest : public St
+ 
+   virtual void OnTimeout() {
+     LOG(LS_ERROR) << "Binding request timed out from "
+-      << port_->GetLocalAddress().ToString()
+-      << " (" << port_->network()->name() << ")";
++                  << port_->socket_->GetLocalAddress(NULL).ToString()
++                  << " (" << port_->network()->name() << ")";
+ 
+     port_->SignalAddressError(port_);
+ 
+@@ -124,26 +124,27 @@ class StunPortBindingRequest : public St
+ 
+ const std::string STUN_PORT_TYPE("stun");
+ 
+-StunPort::StunPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
++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::SocketAddress& server_addr)
+-    : Port(thread, STUN_PORT_TYPE, factory, network),
+-      server_addr_(server_addr), requests_(thread), socket_(NULL), error_(0),
++    : Port(thread, STUN_PORT_TYPE, factory, network, ip, min_port, max_port),
++      server_addr_(server_addr),
++      requests_(thread),
++      socket_(NULL),
++      error_(0),
+       resolver_(NULL) {
+   requests_.SignalSendPacket.connect(this, &StunPort::OnSendPacket);
+ }
+ 
+-bool StunPort::Init(const talk_base::SocketAddress& local_addr) {
+-  socket_ = CreatePacketSocket(PROTO_UDP);
++bool StunPort::Init() {
++  socket_ = factory_->CreateUdpSocket(
++      talk_base::SocketAddress(ip_, 0), min_port_, max_port_);
+   if (!socket_) {
+     LOG_J(LS_WARNING, this) << "UDP socket creation failed";
+     return false;
+   }
+-  if (socket_->Bind(local_addr) < 0) {
+-    LOG_J(LS_WARNING, this) << "UDP bind failed with error "
+-                            << socket_->GetError();
+-    return false;
+-  }
+   socket_->SignalReadPacket.connect(this, &StunPort::OnReadPacket);
+   return true;
+ }
+@@ -200,14 +201,20 @@ int StunPort::GetError() {
+   return error_;
+ }
+ 
+-void StunPort::OnReadPacket(
+-    const char* data, size_t size, const talk_base::SocketAddress& remote_addr,
+-    talk_base::AsyncPacketSocket* socket) {
++void StunPort::OnReadPacket(talk_base::AsyncPacketSocket* socket,
++                            const char* data, size_t size,
++                            const talk_base::SocketAddress& remote_addr) {
+   ASSERT(socket == socket_);
+ 
+-  // Look for a response to a binding request.
+-  if (requests_.CheckResponse(data, size))
++  // Look for a response from the STUN server.
++  // Even if the response doesn't match one of our outstanding requests, we
++  // will eat it because it might be a response to a retransmitted packet, and
++  // we already cleared the request when we got the first response.
++  ASSERT(!server_addr_.IsUnresolved());
++  if (remote_addr == server_addr_ || remote_addr == server_addr2_) {
++    requests_.CheckResponse(data, size);
+     return;
++  }
+ 
+   if (Connection* conn = GetConnection(remote_addr)) {
+     conn->OnReadPacket(data, size);
+diff -upN libjingle-0.5.2/talk/p2p/base/stunport.h.chromium12 libjingle-0.5.2/talk/p2p/base/stunport.h
+--- libjingle-0.5.2/talk/p2p/base/stunport.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/stunport.h	2011-03-30 21:51:32.709287001 -0400
+@@ -29,7 +29,8 @@
+ #define TALK_P2P_BASE_STUNPORT_H_
+ 
+ #include <string>
+-#include "talk/base/asyncudpsocket.h"
++
++#include "talk/base/asyncpacketsocket.h"
+ #include "talk/p2p/base/udpport.h"
+ #include "talk/p2p/base/stunrequest.h"
+ 
+@@ -46,27 +47,20 @@ extern const std::string STUN_PORT_TYPE;
+ class StunPort : public Port {
+  public:
+   static StunPort* Create(talk_base::Thread* thread,
+-                          talk_base::SocketFactory* factory,
++                          talk_base::PacketSocketFactory* factory,
+                           talk_base::Network* network,
+-                          const talk_base::SocketAddress& local_addr,
++                          uint32 ip, int min_port, int max_port,
+                           const talk_base::SocketAddress& server_addr) {
+-    StunPort* port = new StunPort(thread, factory, network, server_addr);
+-    if (!port->Init(local_addr)) {
++    StunPort* port = new StunPort(thread, factory, network,
++                                  ip, min_port, max_port, server_addr);
++    if (!port->Init()) {
+       delete port;
+       port = NULL;
+     }
+     return port;
+   }
+-  StunPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
+-           talk_base::Network* network,
+-           const talk_base::SocketAddress& server_addr);
+-  bool Init(const talk_base::SocketAddress& local_addr);
+   virtual ~StunPort();
+ 
+-  talk_base::SocketAddress GetLocalAddress() const {
+-    return socket_->GetLocalAddress();
+-  }
+-
+   const talk_base::SocketAddress& server_addr() const { return server_addr_; }
+   void set_server_addr(const talk_base::SocketAddress& addr) {
+     server_addr_ = addr;
+@@ -89,13 +83,17 @@ class StunPort : public Port {
+   virtual int GetError();
+ 
+  protected:
++  StunPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
++           talk_base::Network* network, uint32 ip, int min_port, int max_port,
++           const talk_base::SocketAddress& server_addr);
++  bool Init();
++
+   virtual int SendTo(const void* data, size_t size,
+                      const talk_base::SocketAddress& addr, bool payload);
+ 
+-  void OnReadPacket(
+-      const char* data, size_t size,
+-      const talk_base::SocketAddress& remote_addr,
+-      talk_base::AsyncPacketSocket* socket);
++  void OnReadPacket(talk_base::AsyncPacketSocket* socket,
++                    const char* data, size_t size,
++                    const talk_base::SocketAddress& remote_addr);
+ 
+  private:
+   // DNS resolution of the STUN server.
+diff -upN libjingle-0.5.2/talk/p2p/base/stunserver.cc.chromium12 libjingle-0.5.2/talk/p2p/base/stunserver.cc
+--- libjingle-0.5.2/talk/p2p/base/stunserver.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/stunserver.cc	2011-03-30 21:51:32.709287001 -0400
+@@ -44,8 +44,8 @@ StunServer::~StunServer() {
+ }
+ 
+ void StunServer::OnPacket(
+-    const char* buf, size_t size, const talk_base::SocketAddress& remote_addr,
+-    talk_base::AsyncPacketSocket* socket) {
++    talk_base::AsyncPacketSocket* socket, const char* buf, size_t size,
++    const talk_base::SocketAddress& remote_addr) {
+ 
+   // TODO: If appropriate, look for the magic cookie before parsing.
+ 
+@@ -97,7 +97,12 @@ void StunServer::OnBindingRequest(
+   response.AddAttribute(mapped_addr);
+ 
+   // Tell the user the address that we are sending the response from.
+-  talk_base::SocketAddress local_addr = socket_->GetLocalAddress();
++  // This method should not be called if socket address is not
++  // allocated yet.
++  bool allocated;
++  talk_base::SocketAddress local_addr = socket_->GetLocalAddress(&allocated);
++  ASSERT(allocated);
++
+   StunAddressAttribute* source_addr =
+       StunAttribute::CreateAddress(STUN_ATTR_SOURCE_ADDRESS);
+   source_addr->SetFamily(1);
+diff -upN libjingle-0.5.2/talk/p2p/base/stunserver.h.chromium12 libjingle-0.5.2/talk/p2p/base/stunserver.h
+--- libjingle-0.5.2/talk/p2p/base/stunserver.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/stunserver.h	2011-03-30 21:51:32.710287001 -0400
+@@ -46,8 +46,8 @@ class StunServer : public sigslot::has_s
+  protected:
+   // Slot for AsyncSocket.PacketRead:
+   void OnPacket(
+-      const char* buf, size_t size, const talk_base::SocketAddress& remote_addr,
+-      talk_base::AsyncPacketSocket* socket);
++      talk_base::AsyncPacketSocket* socket, const char* buf, size_t size,
++      const talk_base::SocketAddress& remote_addr);
+ 
+   // Handlers for the different types of STUN/TURN requests:
+   void OnBindingRequest(StunMessage* msg,
+diff -upN libjingle-0.5.2/talk/p2p/base/stunserver_main.cc.chromium12 libjingle-0.5.2/talk/p2p/base/stunserver_main.cc
+--- libjingle-0.5.2/talk/p2p/base/stunserver_main.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/stunserver_main.cc	2011-03-30 21:51:32.710287001 -0400
+@@ -52,9 +52,9 @@ int main(int argc, char* argv[]) {
+   talk_base::Thread *pthMain = talk_base::Thread::Current();
+ 
+   talk_base::AsyncUDPSocket* server_socket =
+-      talk_base::CreateAsyncUDPSocket(pthMain->socketserver());
+-  if (server_socket->Bind(server_addr) < 0) {
+-    std::cerr << "bind: " << std::strerror(errno) << std::endl;
++      talk_base::AsyncUDPSocket::Create(pthMain->socketserver(), server_addr);
++  if (!server_socket) {
++    std::cerr << "Failed to create a UDP socket" << std::endl;
+     return 1;
+   }
+ 
+diff -upN libjingle-0.5.2/talk/p2p/base/tcpport.cc.chromium12 libjingle-0.5.2/talk/p2p/base/tcpport.cc
+--- libjingle-0.5.2/talk/p2p/base/tcpport.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/tcpport.cc	2011-03-30 21:51:32.710287001 -0400
+@@ -25,10 +25,6 @@
+  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+-#if defined(_MSC_VER) && _MSC_VER < 1300
+-#pragma warning(disable:4786)
+-#endif
+-
+ #include "talk/p2p/base/tcpport.h"
+ 
+ #include "talk/base/common.h"
+@@ -37,30 +33,28 @@
+ 
+ namespace cricket {
+ 
+-TCPPort::TCPPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
+-                 talk_base::Network* network,
+-                 const talk_base::SocketAddress& address,
+-                 bool allow_listen)
+-    : Port(thread, LOCAL_PORT_TYPE, factory, network), address_(address),
+-      incoming_only_(address_.port() != 0), allow_listen_(allow_listen),
+-      socket_(NULL), error_(0) {
++TCPPort::TCPPort(talk_base::Thread* thread,
++                 talk_base::PacketSocketFactory* factory,
++                 talk_base::Network* network, uint32 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),
++      allow_listen_(allow_listen),
++      socket_(NULL),
++      error_(0) {
+ }
+ 
+ bool TCPPort::Init() {
+-  // We don't use CreatePacketSocket here since we're creating a listen socket.
+-  // However we will treat failure to create or bind a TCP socket as fatal.
+-  // This should never happen.
+-  socket_ = factory_->CreateAsyncSocket(SOCK_STREAM);
++  // Treat failure to create or bind a TCP socket as fatal.  This
++  // should never happen.
++  socket_ = factory_->CreateServerTcpSocket(
++      talk_base::SocketAddress(ip_, 0), min_port_, max_port_, allow_listen_,
++      false /* ssl */);
+   if (!socket_) {
+     LOG_J(LS_ERROR, this) << "TCP socket creation failed.";
+     return false;
+   }
+-  if (socket_->Bind(address_) < 0) {
+-    LOG_J(LS_ERROR, this) << "TCP bind failed with error "
+-                          << socket_->GetError();
+-    return false;
+-  }
+-  socket_->SignalReadEvent.connect(this, &TCPPort::OnAcceptEvent);
++  socket_->SignalNewConnection.connect(this, &TCPPort::OnNewConnection);
+   return true;
+ }
+ 
+@@ -87,8 +81,8 @@ Connection* TCPPort::CreateConnection(co
+     return NULL;
+ 
+   TCPConnection* conn = NULL;
+-  if (talk_base::AsyncTCPSocket * socket
+-        = GetIncoming(address.address(), true)) {
++  if (talk_base::AsyncPacketSocket* socket =
++      GetIncoming(address.address(), true)) {
+     socket->SignalReadPacket.disconnect(this);
+     conn = new TCPConnection(this, address, socket);
+   } else {
+@@ -101,18 +95,21 @@ Connection* TCPPort::CreateConnection(co
+ void TCPPort::PrepareAddress() {
+   if (!allow_listen_) {
+     LOG_J(LS_INFO, this) << "Not listening due to firewall restrictions.";
+-  } else if (socket_->Listen(5) < 0) {
+-    LOG_J(LS_WARNING, this) << "TCP listen failed with error "
+-                            << socket_->GetError();
+   }
+   // Note: We still add the address, since otherwise the remote side won't
+   // recognize our incoming TCP connections.
+-  AddAddress(socket_->GetLocalAddress(), "tcp", true);
++  bool allocated;
++  talk_base::SocketAddress address = socket_->GetLocalAddress(&allocated);
++  if (allocated) {
++    AddAddress(address, "tcp", true);
++  } else {
++    socket_->SignalAddressReady.connect(this, &TCPPort::OnAddresReady);
++  }
+ }
+ 
+ int TCPPort::SendTo(const void* data, size_t size,
+                     const talk_base::SocketAddress& addr, bool payload) {
+-  talk_base::AsyncTCPSocket * socket = NULL;
++  talk_base::AsyncPacketSocket * socket = NULL;
+   if (TCPConnection * conn = static_cast<TCPConnection*>(GetConnection(addr))) {
+     socket = conn->socket();
+   } else {
+@@ -141,31 +138,23 @@ int TCPPort::GetError() {
+   return error_;
+ }
+ 
+-void TCPPort::OnAcceptEvent(talk_base::AsyncSocket* socket) {
++void TCPPort::OnNewConnection(talk_base::AsyncPacketSocket* socket,
++                              talk_base::AsyncPacketSocket* new_socket) {
+   ASSERT(socket == socket_);
+ 
+   Incoming incoming;
+-  talk_base::AsyncSocket* newsocket = socket->Accept(&incoming.addr);
+-  if (!newsocket) {
+-    // TODO: Do something better like forwarding the error to the user.
+-    LOG_J(LS_ERROR, this) << "TCP accept failed with error "
+-                          << socket_->GetError();
+-    return;
+-  }
+-  incoming.socket = new talk_base::AsyncTCPSocket(newsocket);
++  incoming.addr = new_socket->GetRemoteAddress();
++  incoming.socket = new_socket;
+   incoming.socket->SignalReadPacket.connect(this, &TCPPort::OnReadPacket);
+ 
+   LOG_J(LS_VERBOSE, this) << "Accepted connection from "
+                           << incoming.addr.ToString();
+   incoming_.push_back(incoming);
+-
+-  // Prime a read event in case data is waiting
+-  newsocket->SignalReadEvent(newsocket);
+ }
+ 
+-talk_base::AsyncTCPSocket* TCPPort::GetIncoming(
++talk_base::AsyncPacketSocket* TCPPort::GetIncoming(
+     const talk_base::SocketAddress& addr, bool remove) {
+-  talk_base::AsyncTCPSocket* socket = NULL;
++  talk_base::AsyncPacketSocket* socket = NULL;
+   for (std::list<Incoming>::iterator it = incoming_.begin();
+        it != incoming_.end(); ++it) {
+     if (it->addr == addr) {
+@@ -178,34 +167,46 @@ talk_base::AsyncTCPSocket* TCPPort::GetI
+   return socket;
+ }
+ 
+-void TCPPort::OnReadPacket(const char* data, size_t size,
+-                           const talk_base::SocketAddress& remote_addr,
+-                            talk_base::AsyncPacketSocket* socket) {
++void TCPPort::OnReadPacket(talk_base::AsyncPacketSocket* socket,
++                           const char* data, size_t size,
++                           const talk_base::SocketAddress& remote_addr) {
+   Port::OnReadPacket(data, size, remote_addr);
+ }
+ 
++void TCPPort::OnAddresReady(talk_base::AsyncPacketSocket* socket,
++                            const talk_base::SocketAddress& address) {
++  AddAddress(address, "tcp", true);
++}
++
+ TCPConnection::TCPConnection(TCPPort* port, const Candidate& candidate,
+-                             talk_base::AsyncTCPSocket* socket)
++                             talk_base::AsyncPacketSocket* socket)
+     : Connection(port, 0, candidate), socket_(socket), error_(0) {
+   bool outgoing = (socket_ == NULL);
+   if (outgoing) {
+-    // TODO: Handle failures here (unlikely since TCP)
+-    socket_ = static_cast<talk_base::AsyncTCPSocket*>(port->CreatePacketSocket(
+-        (candidate.protocol() == "ssltcp") ? PROTO_SSLTCP : PROTO_TCP));
++    // TODO: Handle failures here (unlikely since TCP).
++
++    socket_ = port->socket_factory()->CreateClientTcpSocket(
++        talk_base::SocketAddress(port_->network()->ip(), 0),
++        candidate.address(), port->proxy(), port->user_agent(),
++        candidate.protocol() == "ssltcp");
++    if (socket_) {
++      LOG_J(LS_VERBOSE, this) << "Connecting from "
++                              << socket_->GetLocalAddress(NULL).ToString()
++                              << " to " << candidate.address().ToString();
++      set_connected(false);
++      socket_->SignalConnect.connect(this, &TCPConnection::OnConnect);
++    } else {
++      LOG_J(LS_WARNING, this) << "Failed to create connection to "
++                              << candidate.address().ToString();
++    }
+   } else {
+-    // Incoming connections should match the network address
+-    ASSERT(socket_->GetLocalAddress().EqualIPs(port->address_));
++    // Incoming connections should match the network address.
++    ASSERT(socket_->GetLocalAddress(NULL).ip() == port->ip_);
+   }
+-  socket_->SignalReadPacket.connect(this, &TCPConnection::OnReadPacket);
+-  socket_->SignalClose.connect(this, &TCPConnection::OnClose);
+-  if (outgoing) {
+-    set_connected(false);
+-    talk_base::SocketAddress local_address(port->address_.ip(), 0);
+-    socket_->SignalConnect.connect(this, &TCPConnection::OnConnect);
+-    socket_->Bind(local_address);
+-    socket_->Connect(candidate.address());
+-    LOG_J(LS_VERBOSE, this) << "Connecting from " << local_address.ToString()
+-                            << " to " << candidate.address().ToString();
++
++  if (socket_) {
++    socket_->SignalReadPacket.connect(this, &TCPConnection::OnReadPacket);
++    socket_->SignalClose.connect(this, &TCPConnection::OnClose);
+   }
+ }
+ 
+@@ -214,6 +215,11 @@ TCPConnection::~TCPConnection() {
+ }
+ 
+ int TCPConnection::Send(const void* data, size_t size) {
++  if (!socket_) {
++    error_ = ENOTCONN;
++    return SOCKET_ERROR;
++  }
++
+   if (write_state() != STATE_WRITABLE) {
+     // TODO: Should STATE_WRITE_TIMEOUT return a non-blocking error?
+     error_ = EWOULDBLOCK;
+@@ -232,23 +238,23 @@ int TCPConnection::GetError() {
+   return error_;
+ }
+ 
+-void TCPConnection::OnConnect(talk_base::AsyncTCPSocket* socket) {
++void TCPConnection::OnConnect(talk_base::AsyncPacketSocket* socket) {
+   ASSERT(socket == socket_);
+   LOG_J(LS_VERBOSE, this) << "Connection established to "
+                           << socket->GetRemoteAddress().ToString();
+   set_connected(true);
+ }
+ 
+-void TCPConnection::OnClose(talk_base::AsyncTCPSocket* socket, int error) {
++void TCPConnection::OnClose(talk_base::AsyncPacketSocket* socket, int error) {
+   ASSERT(socket == socket_);
+   LOG_J(LS_VERBOSE, this) << "Connection closed with error " << error;
+   set_connected(false);
+   set_write_state(STATE_WRITE_TIMEOUT);
+ }
+ 
+-void TCPConnection::OnReadPacket(const char* data, size_t size,
+-                                 const talk_base::SocketAddress& remote_addr,
+-                                 talk_base::AsyncPacketSocket* socket) {
++void TCPConnection::OnReadPacket(talk_base::AsyncPacketSocket* socket,
++                                 const char* data, size_t size,
++                                 const talk_base::SocketAddress& remote_addr) {
+   ASSERT(socket == socket_);
+   Connection::OnReadPacket(data, size);
+ }
+diff -upN libjingle-0.5.2/talk/p2p/base/tcpport.h.chromium12 libjingle-0.5.2/talk/p2p/base/tcpport.h
+--- libjingle-0.5.2/talk/p2p/base/tcpport.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/tcpport.h	2011-03-30 21:51:32.710287001 -0400
+@@ -30,7 +30,7 @@
+ 
+ #include <string>
+ #include <list>
+-#include "talk/base/asynctcpsocket.h"
++#include "talk/base/asyncpacketsocket.h"
+ #include "talk/p2p/base/port.h"
+ 
+ namespace cricket {
+@@ -48,19 +48,18 @@ extern const std::string LOCAL_PORT_TYPE
+ class TCPPort : public Port {
+  public:
+   static TCPPort* Create(talk_base::Thread* thread,
+-                         talk_base::SocketFactory* factory,
++                         talk_base::PacketSocketFactory* factory,
+                          talk_base::Network* network,
+-                         const talk_base::SocketAddress& local_addr,
++                         uint32 ip, int min_port, int max_port,
+                          bool allow_listen) {
+-    TCPPort* port = new TCPPort(thread, factory, network, local_addr,
+-                                allow_listen);
++    TCPPort* port = new TCPPort(thread, factory, network,
++                                ip, min_port, max_port, allow_listen);
+     if (!port->Init()) {
+       delete port;
+       port = NULL;
+     }
+     return port;
+   }
+-  bool Init();
+   virtual ~TCPPort();
+ 
+   virtual Connection* CreateConnection(const Candidate& address,
+@@ -72,36 +71,40 @@ class TCPPort : public Port {
+   virtual int GetError();
+ 
+  protected:
+-  TCPPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
+-          talk_base::Network* network, const talk_base::SocketAddress& address,
++  TCPPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
++          talk_base::Network* network, uint32 ip, int min_port, int max_port,
+           bool allow_listen);
++  bool Init();
+ 
+   // Handles sending using the local TCP socket.
+   virtual int SendTo(const void* data, size_t size,
+                      const talk_base::SocketAddress& addr, bool payload);
+ 
+-  // Creates TCPConnection for incoming sockets
+-  void OnAcceptEvent(talk_base::AsyncSocket* socket);
++  // Accepts incoming TCP connection.
++  void OnNewConnection(talk_base::AsyncPacketSocket* socket,
++                       talk_base::AsyncPacketSocket* new_socket);
+ 
+  private:
+   struct Incoming {
+     talk_base::SocketAddress addr;
+-    talk_base::AsyncTCPSocket * socket;
++    talk_base::AsyncPacketSocket* socket;
+   };
+ 
+-  talk_base::AsyncTCPSocket* GetIncoming(const talk_base::SocketAddress& addr,
+-                                         bool remove = false);
++  talk_base::AsyncPacketSocket* GetIncoming(
++      const talk_base::SocketAddress& addr, bool remove = false);
+ 
+   // Receives packet signal from the local TCP Socket.
+-  void OnReadPacket(const char* data, size_t size,
+-                    const talk_base::SocketAddress& remote_addr,
+-                    talk_base::AsyncPacketSocket* socket);
++  void OnReadPacket(talk_base::AsyncPacketSocket* socket,
++                    const char* data, size_t size,
++                    const talk_base::SocketAddress& remote_addr);
++
++  void OnAddresReady(talk_base::AsyncPacketSocket* socket,
++                     const talk_base::SocketAddress& address);
+ 
+-  // Note: use this until Network ips are stable, then use network->ip
+-  talk_base::SocketAddress address_;
++  // TODO: Is this still needed?
+   bool incoming_only_;
+   bool allow_listen_;
+-  talk_base::AsyncSocket* socket_;
++  talk_base::AsyncPacketSocket* socket_;
+   int error_;
+   std::list<Incoming> incoming_;
+ 
+@@ -112,22 +115,22 @@ class TCPConnection : public Connection 
+  public:
+   // Connection is outgoing unless socket is specified
+   TCPConnection(TCPPort* port, const Candidate& candidate,
+-    talk_base::AsyncTCPSocket* socket = 0);
++                talk_base::AsyncPacketSocket* socket = 0);
+   virtual ~TCPConnection();
+ 
+   virtual int Send(const void* data, size_t size);
+   virtual int GetError();
+ 
+-  talk_base::AsyncTCPSocket * socket() { return socket_; }
++  talk_base::AsyncPacketSocket* socket() { return socket_; }
+ 
+  private:
+-  void OnConnect(talk_base::AsyncTCPSocket* socket);
+-  void OnClose(talk_base::AsyncTCPSocket* socket, int error);
+-  void OnReadPacket(const char* data, size_t size,
+-                    const talk_base::SocketAddress& remote_addr,
+-                    talk_base::AsyncPacketSocket* socket);
++  void OnConnect(talk_base::AsyncPacketSocket* socket);
++  void OnClose(talk_base::AsyncPacketSocket* socket, int error);
++  void OnReadPacket(talk_base::AsyncPacketSocket* socket,
++                    const char* data, size_t size,
++                    const talk_base::SocketAddress& remote_addr);
+ 
+-  talk_base::AsyncTCPSocket* socket_;
++  talk_base::AsyncPacketSocket* socket_;
+   int error_;
+ 
+   friend class TCPPort;
+diff -upN libjingle-0.5.2/talk/p2p/base/transport.cc.chromium12 libjingle-0.5.2/talk/p2p/base/transport.cc
+--- libjingle-0.5.2/talk/p2p/base/transport.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/transport.cc	2011-03-30 21:51:32.711287001 -0400
+@@ -28,6 +28,7 @@
+ #include "talk/p2p/base/transport.h"
+ 
+ #include "talk/base/common.h"
++#include "talk/base/logging.h"
+ #include "talk/p2p/base/candidate.h"
+ #include "talk/p2p/base/constants.h"
+ #include "talk/p2p/base/sessionmanager.h"
+@@ -145,11 +146,13 @@ void Transport::DestroyChannel(const std
+ 
+ void Transport::DestroyChannel_w(const std::string& name) {
+   ASSERT(worker_thread()->IsCurrent());
++
+   TransportChannelImpl* impl = NULL;
+   {
+     talk_base::CritScope cs(&crit_);
+     ChannelMap::iterator iter = channels_.find(name);
+-    ASSERT(iter != channels_.end());
++    if (iter == channels_.end())
++      return;
+     impl = iter->second;
+     channels_.erase(iter);
+   }
+@@ -173,7 +176,7 @@ void Transport::ConnectChannels() {
+ 
+ void Transport::ConnectChannels_w() {
+   ASSERT(worker_thread()->IsCurrent());
+-  if (connect_requested_)
++  if (connect_requested_ || channels_.empty())
+     return;
+   connect_requested_ = true;
+   signaling_thread()->Post(
+@@ -192,6 +195,8 @@ void Transport::OnConnecting_s() {
+ void Transport::DestroyAllChannels() {
+   ASSERT(signaling_thread()->IsCurrent());
+   worker_thread()->Send(this, MSG_DESTROYALLCHANNELS, NULL);
++  worker_thread()->Clear(this);
++  signaling_thread()->Clear(this);
+   destroyed_ = true;
+ }
+ 
+@@ -233,6 +238,8 @@ void Transport::ResetChannels_w() {
+ 
+ void Transport::OnSignalingReady() {
+   ASSERT(signaling_thread()->IsCurrent());
++  if (destroyed_) return;
++
+   worker_thread()->Post(this, MSG_ONSIGNALINGREADY, NULL);
+ 
+   // Notify the subclass.
+@@ -283,7 +290,13 @@ void Transport::OnRemoteCandidates(const
+ 
+ void Transport::OnRemoteCandidate(const Candidate& candidate) {
+   ASSERT(signaling_thread()->IsCurrent());
+-  ASSERT(HasChannel(candidate.name()));
++  if (destroyed_) return;
++  if (!HasChannel(candidate.name())) {
++    LOG(LS_WARNING) << "Ignoring candidate for unknown channel "
++                    << candidate.name();
++    return;
++  }
++
+   // new candidate deleted when params is deleted
+   ChannelParams* params = new ChannelParams(new Candidate(candidate));
+   ChannelMessage* msg = new ChannelMessage(params);
+@@ -445,7 +458,7 @@ bool TransportParser::ParseAddress(const
+ 
+   address->SetIP(elem->Attr(address_name));
+   std::istringstream ist(elem->Attr(port_name));
+-  int port;
++  int port = 0;
+   ist >> port;
+   address->SetPort(port);
+ 
+diff -upN libjingle-0.5.2/talk/p2p/base/udpport.cc.chromium12 libjingle-0.5.2/talk/p2p/base/udpport.cc
+--- libjingle-0.5.2/talk/p2p/base/udpport.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/udpport.cc	2011-03-30 21:51:32.711287001 -0400
+@@ -27,6 +27,7 @@
+ 
+ #include "talk/p2p/base/udpport.h"
+ 
++#include "talk/base/asyncpacketsocket.h"
+ #include "talk/base/logging.h"
+ #include "talk/p2p/base/common.h"
+ 
+@@ -34,23 +35,22 @@ namespace cricket {
+ 
+ const std::string LOCAL_PORT_TYPE("local");
+ 
+-UDPPort::UDPPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
+-                 talk_base::Network* network)
+-    : Port(thread, LOCAL_PORT_TYPE, factory, network),
+-      socket_(NULL), error_(0) {
++UDPPort::UDPPort(talk_base::Thread* thread,
++                 talk_base::PacketSocketFactory* factory,
++                 talk_base::Network* network,
++                 uint32 ip, int min_port, int max_port)
++    : Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port),
++      socket_(NULL),
++      error_(0) {
+ }
+ 
+-bool UDPPort::Init(const talk_base::SocketAddress& local_addr) {
+-  socket_ = CreatePacketSocket(PROTO_UDP);
++bool UDPPort::Init() {
++  socket_ =  factory_->CreateUdpSocket(
++      talk_base::SocketAddress(ip_, 0), min_port_, max_port_);
+   if (!socket_) {
+     LOG_J(LS_WARNING, this) << "UDP socket creation failed";
+     return false;
+   }
+-  if (socket_->Bind(local_addr) < 0) {
+-    LOG_J(LS_WARNING, this) << "UDP bind failed with error "
+-                            << socket_->GetError();
+-    return false;
+-  }
+   socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacket);
+   return true;
+ }
+@@ -60,7 +60,13 @@ UDPPort::~UDPPort() {
+ }
+ 
+ void UDPPort::PrepareAddress() {
+-  AddAddress(socket_->GetLocalAddress(), "udp", true);
++  bool allocated;
++  talk_base::SocketAddress address = socket_->GetLocalAddress(&allocated);
++  if (allocated) {
++    AddAddress(address, "udp", true);
++  } else {
++    socket_->SignalAddressReady.connect(this, &UDPPort::OnAddresReady);
++  }
+ }
+ 
+ Connection* UDPPort::CreateConnection(const Candidate& address,
+@@ -80,7 +86,7 @@ int UDPPort::SendTo(const void* data, si
+     error_ = socket_->GetError();
+     LOG_J(LS_ERROR, this) << "UDP send of " << size
+                           << " bytes failed with error " << error_;
+-  }  
++  }
+   return sent;
+ }
+ 
+@@ -92,9 +98,14 @@ int UDPPort::GetError() {
+   return error_;
+ }
+ 
++void UDPPort::OnAddresReady(talk_base::AsyncPacketSocket* socket,
++                            const talk_base::SocketAddress& address) {
++  AddAddress(address, "udp", true);
++}
++
+ void UDPPort::OnReadPacket(
+-    const char* data, size_t size, const talk_base::SocketAddress& remote_addr,
+-    talk_base::AsyncPacketSocket* socket) {
++    talk_base::AsyncPacketSocket* socket, const char* data, size_t size,
++    const talk_base::SocketAddress& remote_addr) {
+   ASSERT(socket == socket_);
+   if (Connection* conn = GetConnection(remote_addr)) {
+     conn->OnReadPacket(data, size);
+diff -upN libjingle-0.5.2/talk/p2p/base/udpport.h.chromium12 libjingle-0.5.2/talk/p2p/base/udpport.h
+--- libjingle-0.5.2/talk/p2p/base/udpport.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/base/udpport.h	2011-03-30 21:51:32.711287001 -0400
+@@ -30,7 +30,6 @@
+ 
+ #include <string>
+ 
+-#include "talk/base/asyncudpsocket.h"
+ #include "talk/p2p/base/port.h"
+ 
+ namespace talk_base {
+@@ -47,19 +46,17 @@ extern const std::string LOCAL_PORT_TYPE
+ class UDPPort : public Port {
+  public:
+   static UDPPort* Create(talk_base::Thread* thread,
+-                         talk_base::SocketFactory* factory,
++                         talk_base::PacketSocketFactory* factory,
+                          talk_base::Network* network,
+-                         const talk_base::SocketAddress& local_addr) {
+-    UDPPort* port = new UDPPort(thread, factory, network);
+-    if (!port->Init(local_addr)) {
++                         uint32 ip, int min_port, int max_port) {
++    UDPPort* port = new UDPPort(thread, factory, network,
++                                ip, min_port, max_port);
++    if (!port->Init()) {
+       delete port;
+       port = NULL;
+     }
+     return port;
+   }
+-  UDPPort(talk_base::Thread* thread, talk_base::SocketFactory* factory,
+-          talk_base::Network* network);
+-  bool Init(const talk_base::SocketAddress& local_addr);
+   virtual ~UDPPort();
+ 
+   virtual void PrepareAddress();
+@@ -70,14 +67,21 @@ class UDPPort : public Port {
+   virtual int GetError();
+ 
+  protected:
++  UDPPort(talk_base::Thread* thread, talk_base::PacketSocketFactory* factory,
++          talk_base::Network* network, uint32 ip, int min_port, int max_port);
++  bool Init();
++
+   // Handles sending using the local UDP socket.
+   virtual int SendTo(const void* data, size_t size,
+                      const talk_base::SocketAddress& remote_addr, bool payload);
+ 
++  void OnAddresReady(talk_base::AsyncPacketSocket* socket,
++                     const talk_base::SocketAddress& address);
++
+   // Dispatches the given packet to the port or connection as appropriate.
+-  void OnReadPacket(const char* data, size_t size,
+-                    const talk_base::SocketAddress& remote_addr,
+-                    talk_base::AsyncPacketSocket* socket);
++  void OnReadPacket(talk_base::AsyncPacketSocket* socket,
++                    const char* data, size_t size,
++                    const talk_base::SocketAddress& remote_addr);
+ 
+  private:
+   talk_base::AsyncPacketSocket* socket_;
+diff -upN libjingle-0.5.2/talk/p2p/client/basicportallocator.cc.chromium12 libjingle-0.5.2/talk/p2p/client/basicportallocator.cc
+--- libjingle-0.5.2/talk/p2p/client/basicportallocator.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/client/basicportallocator.cc	2011-03-30 21:51:32.712287001 -0400
+@@ -166,17 +166,24 @@ class AllocationSequence : public talk_b
+ // BasicPortAllocator
+ 
+ BasicPortAllocator::BasicPortAllocator(
+-    talk_base::NetworkManager* network_manager)
+-    : network_manager_(network_manager), best_writable_phase_(-1) {
++    talk_base::NetworkManager* network_manager,
++    talk_base::PacketSocketFactory* socket_factory)
++    : network_manager_(network_manager),
++      socket_factory_(socket_factory),
++      best_writable_phase_(-1),
++      allow_tcp_listen_(true) {
++  ASSERT(socket_factory_ != NULL);
+ }
+ 
+ BasicPortAllocator::BasicPortAllocator(
+     talk_base::NetworkManager* network_manager,
++    talk_base::PacketSocketFactory* socket_factory,
+     const talk_base::SocketAddress& stun_address,
+     const talk_base::SocketAddress& relay_address_udp,
+     const talk_base::SocketAddress& relay_address_tcp,
+     const talk_base::SocketAddress& relay_address_ssl)
+     : network_manager_(network_manager),
++      socket_factory_(socket_factory),
+       stun_address_(stun_address),
+       relay_address_udp_(relay_address_udp),
+       relay_address_tcp_(relay_address_tcp),
+@@ -656,8 +663,11 @@ void AllocationSequence::CreateUDPPorts(
+     return;
+   }
+ 
+-  Port* port = UDPPort::Create(session_->network_thread(), NULL, network_,
+-                               talk_base::SocketAddress(ip_, 0));
++  Port* port = UDPPort::Create(session_->network_thread(),
++                               session_->allocator()->socket_factory(),
++                               network_, ip_,
++                               session_->allocator()->min_port(),
++                               session_->allocator()->max_port());
+   if (port)
+     session_->AddAllocatedPort(port, this, PREF_LOCAL_UDP);
+ }
+@@ -668,8 +678,11 @@ void AllocationSequence::CreateTCPPorts(
+     return;
+   }
+ 
+-  Port* port = TCPPort::Create(session_->network_thread(), NULL, network_,
+-                               talk_base::SocketAddress(ip_, 0),
++  Port* port = TCPPort::Create(session_->network_thread(),
++                               session_->allocator()->socket_factory(),
++                               network_, ip_,
++                               session_->allocator()->min_port(),
++                               session_->allocator()->max_port(),
+                                session_->allocator()->allow_tcp_listen());
+   if (port)
+     session_->AddAllocatedPort(port, this, PREF_LOCAL_TCP);
+@@ -690,8 +703,11 @@ void AllocationSequence::CreateStunPorts
+     return;
+   }
+ 
+-  Port* port = StunPort::Create(session_->network_thread(), NULL, network_,
+-                                talk_base::SocketAddress(ip_, 0),
++  Port* port = StunPort::Create(session_->network_thread(),
++                                session_->allocator()->socket_factory(),
++                                network_, ip_,
++                                session_->allocator()->min_port(),
++                                session_->allocator()->max_port(),
+                                 config_->stun_address);
+   if (port)
+     session_->AddAllocatedPort(port, this, PREF_LOCAL_STUN);
+@@ -715,9 +731,11 @@ void AllocationSequence::CreateRelayPort
+   PortConfiguration::RelayList::const_iterator relay;
+   for (relay = config_->relays.begin();
+        relay != config_->relays.end(); ++relay) {
+-    RelayPort* port = RelayPort::Create(session_->network_thread(), NULL,
+-                                        network_,
+-                                        talk_base::SocketAddress(ip_, 0),
++    RelayPort* port = RelayPort::Create(session_->network_thread(),
++                                        session_->allocator()->socket_factory(),
++                                        network_, ip_,
++                                        session_->allocator()->min_port(),
++                                        session_->allocator()->max_port(),
+                                         config_->username, config_->password,
+                                         config_->magic_cookie);
+     if (port) {
+diff -upN libjingle-0.5.2/talk/p2p/client/basicportallocator.h.chromium12 libjingle-0.5.2/talk/p2p/client/basicportallocator.h
+--- libjingle-0.5.2/talk/p2p/client/basicportallocator.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/client/basicportallocator.h	2011-03-30 21:51:32.712287001 -0400
+@@ -40,8 +40,10 @@ namespace cricket {
+ 
+ class BasicPortAllocator : public PortAllocator {
+  public:
+-  explicit BasicPortAllocator(talk_base::NetworkManager* network_manager);
+   BasicPortAllocator(talk_base::NetworkManager* network_manager,
++                     talk_base::PacketSocketFactory* socket_factory);
++  BasicPortAllocator(talk_base::NetworkManager* network_manager,
++                     talk_base::PacketSocketFactory* socket_factory,
+                      const talk_base::SocketAddress& stun_server,
+                      const talk_base::SocketAddress& relay_server_udp,
+                      const talk_base::SocketAddress& relay_server_tcp,
+@@ -50,6 +52,8 @@ class BasicPortAllocator : public PortAl
+ 
+   talk_base::NetworkManager* network_manager() { return network_manager_; }
+ 
++  talk_base::PacketSocketFactory* socket_factory() { return socket_factory_; }
++
+   const talk_base::SocketAddress& stun_address() const {
+     return stun_address_;
+   }
+@@ -84,6 +88,7 @@ class BasicPortAllocator : public PortAl
+ 
+  private:
+   talk_base::NetworkManager* network_manager_;
++  talk_base::PacketSocketFactory* socket_factory_;
+   const talk_base::SocketAddress stun_address_;
+   const talk_base::SocketAddress relay_address_udp_;
+   const talk_base::SocketAddress relay_address_tcp_;
+diff -upN libjingle-0.5.2/talk/p2p/client/httpportallocator.cc.chromium12 libjingle-0.5.2/talk/p2p/client/httpportallocator.cc
+--- libjingle-0.5.2/talk/p2p/client/httpportallocator.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/client/httpportallocator.cc	2011-03-30 21:51:32.712287001 -0400
+@@ -96,9 +96,11 @@ const int HttpPortAllocator::kNumRetries
+ 
+ const std::string HttpPortAllocator::kCreateSessionURL = "/create_session";
+ 
+-HttpPortAllocator::HttpPortAllocator(talk_base::NetworkManager* network_manager,
+-                                     const std::string &user_agent)
+-    : BasicPortAllocator(network_manager), agent_(user_agent) {
++HttpPortAllocator::HttpPortAllocator(
++    talk_base::NetworkManager* network_manager,
++    talk_base::PacketSocketFactory* socket_factory,
++    const std::string &user_agent)
++    : BasicPortAllocator(network_manager, socket_factory), agent_(user_agent) {
+   relay_hosts_.push_back("relay.google.com");
+   stun_hosts_.push_back(
+       talk_base::SocketAddress("stun.l.google.com", 19302));
+diff -upN libjingle-0.5.2/talk/p2p/client/httpportallocator.h.chromium12 libjingle-0.5.2/talk/p2p/client/httpportallocator.h
+--- libjingle-0.5.2/talk/p2p/client/httpportallocator.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/p2p/client/httpportallocator.h	2011-03-30 21:51:32.712287001 -0400
+@@ -50,6 +50,7 @@ class HttpPortAllocator : public BasicPo
+   static const std::string kCreateSessionURL;
+ 
+   HttpPortAllocator(talk_base::NetworkManager* network_manager,
++                    talk_base::PacketSocketFactory* socket_factory,
+                     const std::string& user_agent);
+   virtual ~HttpPortAllocator();
+ 
+diff -upN libjingle-0.5.2/talk/session/phone/channel.cc.chromium12 libjingle-0.5.2/talk/session/phone/channel.cc
+--- libjingle-0.5.2/talk/session/phone/channel.cc.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/channel.cc	2011-03-30 21:51:32.713287001 -0400
+@@ -43,6 +43,24 @@ struct PacketMessageData : public talk_b
+   talk_base::Buffer packet;
+ };
+ 
++struct VoiceChannelErrorMessageData : public talk_base::MessageData {
++  VoiceChannelErrorMessageData(uint32 in_ssrc,
++                               VoiceMediaChannel::Error in_error)
++      : ssrc(in_ssrc),
++        error(in_error) {}
++  uint32 ssrc;
++  VoiceMediaChannel::Error error;
++};
++
++struct VideoChannelErrorMessageData : public talk_base::MessageData {
++  VideoChannelErrorMessageData(uint32 in_ssrc,
++                               VideoMediaChannel::Error in_error)
++      : ssrc(in_ssrc),
++        error(in_error) {}
++  uint32 ssrc;
++  VideoMediaChannel::Error error;
++};
++
+ static const char* PacketType(bool rtcp) {
+   return (!rtcp) ? "RTP" : "RTCP";
+ }
+@@ -101,6 +119,7 @@ BaseChannel::BaseChannel(talk_base::Thre
+ BaseChannel::~BaseChannel() {
+   ASSERT(worker_thread_ == talk_base::Thread::Current());
+   StopConnectionMonitor();
++  FlushRtcpMessages();  // Send any outstanding RTCP packets.
+   Clear();  // eats any outstanding messages or packets
+   // We must destroy the media channel before the transport channel, otherwise
+   // the media channel may try to send on the dead transport channel. NULLing
+@@ -365,32 +384,34 @@ void BaseChannel::HandlePacket(bool rtcp
+ 
+ void BaseChannel::OnSessionState(BaseSession* session,
+                                  BaseSession::State state) {
+-  // TODO: tear down the call via session->SetError() if the
+-  // SetXXXXDescription calls fail.
+   const MediaContentDescription* content = NULL;
+   switch (state) {
+     case Session::STATE_SENTINITIATE:
+       content = GetFirstContent(session->local_description());
+-      if (content) {
+-        SetLocalContent(content, CA_OFFER);
++      if (content && !SetLocalContent(content, CA_OFFER)) {
++        LOG(LS_ERROR) << "Failure in SetLocalContent with CA_OFFER";
++        session->SetError(BaseSession::ERROR_CONTENT);
+       }
+       break;
+     case Session::STATE_SENTACCEPT:
+       content = GetFirstContent(session->local_description());
+-      if (content) {
+-        SetLocalContent(content, CA_ANSWER);
++      if (content && !SetLocalContent(content, CA_ANSWER)) {
++        LOG(LS_ERROR) << "Failure in SetLocalContent with CA_ANSWER";
++        session->SetError(BaseSession::ERROR_CONTENT);
+       }
+       break;
+     case Session::STATE_RECEIVEDINITIATE:
+       content = GetFirstContent(session->remote_description());
+-      if (content) {
+-        SetRemoteContent(content, CA_OFFER);
++      if (content && !SetRemoteContent(content, CA_OFFER)) {
++        LOG(LS_ERROR) << "Failure in SetRemoteContent with CA_OFFER";
++        session->SetError(BaseSession::ERROR_CONTENT);
+       }
+       break;
+     case Session::STATE_RECEIVEDACCEPT:
+       content = GetFirstContent(session->remote_description());
+-      if (content) {
+-        SetRemoteContent(content, CA_ANSWER);
++      if (content && !SetRemoteContent(content, CA_ANSWER)) {
++        LOG(LS_ERROR) << "Failure in SetRemoteContent with CA_ANSWER";
++        session->SetError(BaseSession::ERROR_CONTENT);
+       }
+       break;
+     default:
+@@ -578,6 +599,18 @@ void BaseChannel::Clear(uint32 id, talk_
+   worker_thread_->Clear(this, id, removed);
+ }
+ 
++void BaseChannel::FlushRtcpMessages() {
++  // Flush all remaining RTCP messages. This should only be called in
++  // destructor.
++  ASSERT(talk_base::Thread::Current() == worker_thread_);
++  talk_base::MessageList rtcp_messages;
++  Clear(MSG_RTCPPACKET, &rtcp_messages);
++  for (talk_base::MessageList::iterator it = rtcp_messages.begin();
++       it != rtcp_messages.end(); ++it) {
++    Send(MSG_RTCPPACKET, it->pdata);
++  }
++}
++
+ VoiceChannel::VoiceChannel(talk_base::Thread* thread,
+                            MediaEngine* media_engine,
+                            VoiceMediaChannel* media_channel,
+@@ -593,6 +626,9 @@ VoiceChannel::VoiceChannel(talk_base::Th
+   // Can't go in BaseChannel because certain session states will
+   // trigger pure virtual functions, such as GetFirstContent().
+   OnSessionState(session, session->state());
++
++  media_channel->SignalMediaError.connect(
++      this, &VoiceChannel::OnVoiceChannelError);
+ }
+ 
+ VoiceChannel::~VoiceChannel() {
+@@ -692,8 +728,10 @@ void VoiceChannel::OnChannelRead(Transpo
+   // If we were playing out our local ringback, make sure it is stopped to
+   // prevent it from interfering with the incoming media.
+   if (!received_media_) {
+-    received_media_ = false;
+-    PlayRingbackTone_w(false, false);
++    if (!PlayRingbackTone_w(false, false)) {
++      LOG(LS_ERROR) << "Failed to stop ringback tone.";
++      SendLastMediaError();
++    }
+   }
+ }
+ 
+@@ -701,13 +739,19 @@ void VoiceChannel::ChangeState() {
+   // render incoming data if we are the active call
+   // we receive data on the default channel and multiplexed streams
+   bool recv = enabled();
+-  media_channel()->SetPlayout(recv);
++  if (!media_channel()->SetPlayout(recv)) {
++    SendLastMediaError();
++  }
+ 
+   // send outgoing data if we are the active call, have the
+   // remote party's codec, and have a writable transport
+   // we only send data on the default channel
+   bool send = enabled() && has_codec() && writable();
+-  media_channel()->SetSend(send ? SEND_MICROPHONE : SEND_NOTHING);
++  SendFlags send_flag = send ? SEND_MICROPHONE : SEND_NOTHING;
++  if (!media_channel()->SetSend(send_flag)) {
++    LOG(LS_ERROR) << "Failed to SetSend " << send_flag << " on voice channel";
++    SendLastMediaError();
++  }
+ 
+   LOG(LS_INFO) << "Changing voice state, recv=" << recv << " send=" << send;
+ }
+@@ -769,7 +813,10 @@ bool VoiceChannel::SetRemoteContent_w(co
+     ret = media_channel()->SetSendCodecs(audio->codecs());
+   }
+ 
+-  int audio_options = audio->conference_mode() ? OPT_CONFERENCE : 0;
++  int audio_options = 0;
++  if (audio->conference_mode()) {
++    audio_options |= OPT_CONFERENCE;
++  }
+   if (!media_channel()->SetOptions(audio_options)) {
+     // Log an error on failure, but don't abort the call.
+     LOG(LS_ERROR) << "Failed to set voice channel options";
+@@ -850,6 +897,13 @@ void VoiceChannel::OnMessage(talk_base::
+       data->result = PressDTMF_w(data->digit, data->playout);
+       break;
+     }
++    case MSG_CHANNEL_ERROR: {
++      VoiceChannelErrorMessageData* data =
++          static_cast<VoiceChannelErrorMessageData*>(pmsg->pdata);
++      SignalMediaError(this, data->ssrc, data->error);
++      delete data;
++      break;
++    }
+ 
+     default:
+       BaseChannel::OnMessage(pmsg);
+@@ -873,6 +927,13 @@ void VoiceChannel::OnAudioMonitorUpdate(
+   SignalAudioMonitor(this, info);
+ }
+ 
++void VoiceChannel::OnVoiceChannelError(
++    uint32 ssrc, VoiceMediaChannel::Error error) {
++  VoiceChannelErrorMessageData *data = new VoiceChannelErrorMessageData(
++      ssrc, error);
++  signaling_thread()->Post(this, MSG_CHANNEL_ERROR, data);
++}
++
+ VideoChannel::VideoChannel(talk_base::Thread* thread,
+                            MediaEngine* media_engine,
+                            VideoMediaChannel* media_channel,
+@@ -891,6 +952,15 @@ VideoChannel::VideoChannel(talk_base::Th
+   // trigger pure virtual functions, such as GetFirstContent()
+   OnSessionState(session, session->state());
+ 
++  media_channel->SignalMediaError.connect(
++      this, &VideoChannel::OnVideoChannelError);
++}
++
++void VoiceChannel::SendLastMediaError() {
++  uint32 ssrc;
++  VoiceMediaChannel::Error error;
++  media_channel()->GetLastMediaError(&ssrc, &error);
++  SignalMediaError(this, ssrc, error);
+ }
+ 
+ VideoChannel::~VideoChannel() {
+@@ -926,13 +996,19 @@ void VideoChannel::ChangeState() {
+   // render incoming data if we are the active call
+   // we receive data on the default channel and multiplexed streams
+   bool recv = enabled();
+-  media_channel()->SetRender(recv);
++  if (!media_channel()->SetRender(recv)) {
++    LOG(LS_ERROR) << "Failed to SetRender on video channel";
++    // TODO: Report error back to server.
++  }
+ 
+   // send outgoing data if we are the active call, have the
+   // remote party's codec, and have a writable transport
+   // we only send data on the default channel
+   bool send = enabled() && has_codec() && writable();
+-  media_channel()->SetSend(send);
++  if (!media_channel()->SetSend(send)) {
++    LOG(LS_ERROR) << "Failed to SetSend on video channel";
++    // TODO: Report error back to server.
++  }
+ 
+   LOG(LS_INFO) << "Changing video state, recv=" << recv << " send=" << send;
+ }
+@@ -1053,10 +1129,16 @@ void VideoChannel::OnMessage(talk_base::
+     case MSG_REQUESTINTRAFRAME:
+       RequestIntraFrame_w();
+       break;
+-
+-  default:
+-    BaseChannel::OnMessage(pmsg);
+-    break;
++    case MSG_CHANNEL_ERROR: {
++      const VideoChannelErrorMessageData* data =
++          static_cast<VideoChannelErrorMessageData*>(pmsg->pdata);
++      SignalMediaError(this, data->ssrc, data->error);
++      delete data;
++      break;
++    }
++    default:
++      BaseChannel::OnMessage(pmsg);
++      break;
+   }
+ }
+ 
+@@ -1072,4 +1154,11 @@ void VideoChannel::OnMediaMonitorUpdate(
+ }
+ 
+ 
++void VideoChannel::OnVideoChannelError(uint32 ssrc,
++                                       VideoMediaChannel::Error error) {
++  VideoChannelErrorMessageData* data = new VideoChannelErrorMessageData(
++      ssrc, error);
++  signaling_thread()->Post(this, MSG_CHANNEL_ERROR, data);
++}
++
+ }  // namespace cricket
+diff -upN libjingle-0.5.2/talk/session/phone/channel.h.chromium12 libjingle-0.5.2/talk/session/phone/channel.h
+--- libjingle-0.5.2/talk/session/phone/channel.h.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/channel.h	2011-03-30 21:51:32.713287001 -0400
+@@ -69,7 +69,8 @@ enum {
+   MSG_SENDINTRAFRAME = 19,
+   MSG_REQUESTINTRAFRAME = 20,
+   MSG_RTPPACKET = 22,
+-  MSG_RTCPPACKET = 23
++  MSG_RTCPPACKET = 23,
++  MSG_CHANNEL_ERROR = 24
+ };
+ 
+ // BaseChannel contains logic common to voice and video, including
+@@ -83,7 +84,7 @@ class BaseChannel
+               MediaChannel* channel, BaseSession* session,
+               const std::string& content_name,
+               TransportChannel* transport_channel);
+-  ~BaseChannel();
++  virtual ~BaseChannel();
+ 
+   talk_base::Thread* worker_thread() const { return worker_thread_; }
+   BaseSession* session() const { return session_; }
+@@ -94,6 +95,7 @@ class BaseChannel
+   TransportChannel* rtcp_transport_channel() const {
+     return rtcp_transport_channel_;
+   }
++  bool enabled() const { return enabled_; }
+   bool secure() const { return srtp_filter_.IsActive(); }
+ 
+   // Channel control
+@@ -136,7 +138,6 @@ class BaseChannel
+   MediaEngine* media_engine() const { return media_engine_; }
+   virtual MediaChannel* media_channel() const { return media_channel_; }
+   void set_rtcp_transport_channel(TransportChannel* transport);
+-  bool enabled() const { return enabled_; }
+   bool writable() const { return writable_; }
+   bool has_codec() const { return has_codec_; }
+   void set_has_codec(bool has_codec) { has_codec_ = has_codec; }
+@@ -149,6 +150,7 @@ class BaseChannel
+                    talk_base::MessageData *pdata = NULL);
+   void Clear(uint32 id = talk_base::MQID_ANY,
+              talk_base::MessageList* removed = NULL);
++  void FlushRtcpMessages();
+ 
+   // NetworkInterface implementation, called by MediaEngine
+   virtual bool SendPacket(talk_base::Buffer* packet);
+@@ -290,6 +292,11 @@ class VoiceChannel : public BaseChannel 
+   int GetOutputLevel_w();
+   void GetActiveStreams_w(AudioInfo::StreamList* actives);
+ 
++  // Signal errors from VoiceMediaChannel.  Arguments are:
++  //     ssrc(uint32), and error(VoiceMediaChannel::Error).
++  sigslot::signal3<VoiceChannel*, uint32, VoiceMediaChannel::Error>
++      SignalMediaError;
++
+  private:
+   struct SetRingbackToneMessageData : public talk_base::MessageData {
+     SetRingbackToneMessageData(const void* b, int l)
+@@ -345,6 +352,8 @@ class VoiceChannel : public BaseChannel 
+   virtual void OnMediaMonitorUpdate(
+       VoiceMediaChannel *media_channel, const VoiceMediaInfo& info);
+   void OnAudioMonitorUpdate(AudioMonitor *monitor, const AudioInfo& info);
++  void OnVoiceChannelError(uint32 ssrc, VoiceMediaChannel::Error error);
++  void SendLastMediaError();
+ 
+   static const int kEarlyMediaTimeout = 1000;
+   bool received_media_;
+@@ -382,6 +391,9 @@ class VideoChannel : public BaseChannel 
+   bool SendIntraFrame();
+   bool RequestIntraFrame();
+ 
++  sigslot::signal3<VideoChannel*, uint32, VideoMediaChannel::Error>
++      SignalMediaError;
++
+  private:
+   // overrides from BaseChannel
+   virtual void ChangeState();
+@@ -417,6 +429,8 @@ class VideoChannel : public BaseChannel 
+       SocketMonitor *monitor, const std::vector<ConnectionInfo> &infos);
+   virtual void OnMediaMonitorUpdate(
+       VideoMediaChannel *media_channel, const VideoMediaInfo& info);
++  void OnVideoChannelError(uint32 ssrc, VideoMediaChannel::Error error);
++
+   VoiceChannel *voice_channel_;
+   VideoRenderer *renderer_;
+   talk_base::scoped_ptr<VideoMediaMonitor> media_monitor_;
+diff -upN libjingle-0.5.2/talk/session/phone/channelmanager.cc.chromium12 libjingle-0.5.2/talk/session/phone/channelmanager.cc
+--- libjingle-0.5.2/talk/session/phone/channelmanager.cc.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/channelmanager.cc	2011-03-30 21:51:32.714287001 -0400
+@@ -39,10 +39,6 @@
+ #include "talk/base/stringencode.h"
+ #include "talk/session/phone/mediaengine.h"
+ #include "talk/session/phone/soundclip.h"
+-#ifdef USE_TALK_SOUND
+-#include "talk/sound/platformsoundsystemfactory.h"
+-#include "talk/sound/soundsysteminterface.h"
+-#endif
+ 
+ namespace cricket {
+ 
+@@ -134,23 +130,13 @@ struct CaptureParams : public talk_base:
+ };
+ 
+ ChannelManager::ChannelManager(talk_base::Thread* worker_thread)
+-    :
+-#ifdef USE_TALK_SOUND
+-      sound_system_factory_(new PlatformSoundSystemFactory()),
+-#endif
+-      media_engine_(MediaEngine::Create(
+-#ifdef USE_TALK_SOUND
+-          sound_system_factory_.get()
+-#endif
+-          )),
+-      device_manager_(new DeviceManager(
+-#ifdef USE_TALK_SOUND
+-          sound_system_factory_.get()
+-#endif
+-          )),
++    : media_engine_(MediaEngine::Create()),
++      device_manager_(new DeviceManager()),
+       initialized_(false),
+       main_thread_(talk_base::Thread::Current()),
+       worker_thread_(worker_thread),
++      audio_in_device_(DeviceManager::kDefaultDeviceName),
++      audio_out_device_(DeviceManager::kDefaultDeviceName),
+       audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
+       local_renderer_(NULL),
+       capturing_(false),
+@@ -160,15 +146,13 @@ ChannelManager::ChannelManager(talk_base
+ 
+ ChannelManager::ChannelManager(MediaEngine* me, DeviceManager* dm,
+                                talk_base::Thread* worker_thread)
+-    :
+-#ifdef USE_TALK_SOUND
+-      sound_system_factory_(NULL),
+-#endif
+-      media_engine_(me),
++    : media_engine_(me),
+       device_manager_(dm),
+       initialized_(false),
+       main_thread_(talk_base::Thread::Current()),
+       worker_thread_(worker_thread),
++      audio_in_device_(DeviceManager::kDefaultDeviceName),
++      audio_out_device_(DeviceManager::kDefaultDeviceName),
+       audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
+       local_renderer_(NULL),
+       capturing_(false),
+@@ -180,7 +164,8 @@ void ChannelManager::Construct() {
+   // Init the device manager immediately, and set up our default video device.
+   SignalDevicesChange.repeat(device_manager_->SignalDevicesChange);
+   device_manager_->Init();
+-  SetVideoOptions("");
++  // Set camera_device_ to the name of the default video capturer.
++  SetVideoOptions(DeviceManager::kDefaultDeviceName);
+ 
+   // Camera is started asynchronously, request callbacks when startup
+   // completes to be able to forward them to the rendering manager.
+@@ -230,18 +215,47 @@ bool ChannelManager::Init() {
+     if (media_engine_->Init()) {
+       initialized_ = true;
+ 
+-      // Now that we're initialized, apply any stored preferences.
++      // Now that we're initialized, apply any stored preferences. A preferred
++      // device might have been unplugged. In this case, we fallback to the
++      // default device but keep the user preferences. The preferences are
++      // changed only when the Javascript FE changes them.
++      const std::string preferred_audio_in_device = audio_in_device_;
++      const std::string preferred_audio_out_device = audio_out_device_;
++      const std::string preferred_camera_device = camera_device_;
++      Device device;
++      if (!device_manager_->GetAudioInputDevice(audio_in_device_, &device)) {
++        LOG(LS_WARNING) << "The preferred microphone '" << audio_in_device_
++                        << "' is unavailable. Fall back to the default.";
++        audio_in_device_ = DeviceManager::kDefaultDeviceName;
++      }
++      if (!device_manager_->GetAudioOutputDevice(audio_out_device_, &device)) {
++        LOG(LS_WARNING) << "The preferred speaker '" << audio_out_device_
++                        << "' is unavailable. Fall back to the default.";
++        audio_out_device_ = DeviceManager::kDefaultDeviceName;
++      }
++      if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
++        LOG(LS_WARNING) << "The preferred camera '" << camera_device_
++                        << "' is unavailable. Fall back to the default.";
++        camera_device_ = DeviceManager::kDefaultDeviceName;
++      }
++
+       if (!SetAudioOptions(audio_in_device_, audio_out_device_,
+                            audio_options_)) {
+-        audio_in_device_.clear();
+-        audio_out_device_.clear();
++        LOG(LS_WARNING) << "Failed to SetAudioOptions with"
++                        << " microphone: " << audio_in_device_
++                        << " speaker: " << audio_out_device_
++                        << " options: " << audio_options_;
+       }
+       if (!SetVideoOptions(camera_device_)) {
+-        // Perhaps it's been unplugged, fall back to default device
+-        if (!SetVideoOptions("")) {
+-          camera_device_.clear();
+-        }
++        LOG(LS_WARNING) << "Failed to SetVideoOptions with camera: "
++                        << camera_device_;
+       }
++
++      // Restore the user preferences.
++      audio_in_device_ = preferred_audio_in_device;
++      audio_out_device_ = preferred_audio_out_device;
++      camera_device_ = preferred_camera_device;
++
+       // Now apply the default video codec that has been set earlier.
+       if (default_video_encoder_config_.max_codec.id != 0) {
+         SetDefaultVideoEncoderConfig(default_video_encoder_config_);
+@@ -480,29 +494,15 @@ bool ChannelManager::GetVideoOptions(std
+ }
+ 
+ bool ChannelManager::SetVideoOptions(const std::string& cam_name) {
+-  bool ret;
+   Device device;
+-
+-  if (cam_name.empty()) {
+-    // If we're passed the default device name, get the default device.
+-    ret = device_manager_->GetDefaultVideoCaptureDevice(&device);
+-  } else {
+-    // Convert the camera name to a device, fail if it can't be found.
+-    std::vector<Device> devices;
+-    ret = device_manager_->GetVideoCaptureDevices(&devices);
+-    if (ret) {
+-      for (size_t i = 0; i < devices.size(); ++i) {
+-        if (devices[i].name == cam_name) {
+-          device = devices[i];
+-          break;
+-        }
+-      }
+-      ret = !device.name.empty();
+-    }
++  if (!device_manager_->GetVideoCaptureDevice(cam_name, &device)) {
++    LOG(LS_WARNING) << "Device manager can't find camera: " << cam_name;
++    return false;
+   }
+ 
+   // If we're running, tell the media engine about it.
+-  if (ret && initialized_) {
++  bool ret = true;
++  if (initialized_) {
+     VideoOptions options(&device);
+     ret = (Send(MSG_SETVIDEOOPTIONS, &options) && options.result);
+   }
+@@ -628,10 +628,10 @@ bool ChannelManager::Send(uint32 id, tal
+   return true;
+ }
+ 
+-void ChannelManager::OnVideoCaptureResult(bool result) {
+-  capturing_ = result;
++void ChannelManager::OnVideoCaptureResult(CaptureResult result) {
++  capturing_ = result == CR_SUCCESS;
+   main_thread_->Post(this, MSG_CAMERASTARTED,
+-                     new talk_base::TypedMessageData<bool>(result));
++                     new talk_base::TypedMessageData<CaptureResult>(result));
+ }
+ 
+ void ChannelManager::OnMessage(talk_base::Message* message) {
+@@ -718,8 +718,9 @@ void ChannelManager::OnMessage(talk_base
+       break;
+     }
+     case MSG_CAMERASTARTED: {
+-      talk_base::TypedMessageData<bool> *data =
+-          static_cast<talk_base::TypedMessageData<bool>*>(message->pdata);
++      talk_base::TypedMessageData<CaptureResult>* data =
++          static_cast<talk_base::TypedMessageData<CaptureResult>*>(
++              message->pdata);
+       SignalVideoCaptureResult(data->data());
+       delete data;
+       break;
+diff -upN libjingle-0.5.2/talk/session/phone/channelmanager.h.chromium12 libjingle-0.5.2/talk/session/phone/channelmanager.h
+--- libjingle-0.5.2/talk/session/phone/channelmanager.h.chromium12	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/channelmanager.h	2011-03-30 21:51:32.714287001 -0400
+@@ -38,9 +38,6 @@
+ #include "talk/session/phone/voicechannel.h"
+ #include "talk/session/phone/mediaengine.h"
+ #include "talk/session/phone/devicemanager.h"
+-#ifdef USE_TALK_SOUND
+-#include "talk/sound/soundsystemfactory.h"
+-#endif
+ 
+ namespace cricket {
+ 
+@@ -157,7 +154,7 @@ class ChannelManager : public talk_base:
+   bool GetAudioOutputDevices(std::vector<std::string>* names);
+   bool GetVideoCaptureDevices(std::vector<std::string>* names);
+   sigslot::repeater0<> SignalDevicesChange;
+-  sigslot::signal1<bool> SignalVideoCaptureResult;
++  sigslot::signal1<CaptureResult> SignalVideoCaptureResult;
+ 
+  private:
+   typedef std::vector<VoiceChannel*> VoiceChannels;
+@@ -185,13 +182,10 @@ class ChannelManager : public talk_base:
+   CaptureResult SetVideoCapture_w(bool capture);
+   void SetMediaLogging(bool video, int level, const char* filter);
+   void SetMediaLogging_w(bool video, int level, const char* filter);
+-  void OnVideoCaptureResult(bool result);
++  void OnVideoCaptureResult(CaptureResult result);
+   void OnMessage(talk_base::Message *message);
+ 
+   talk_base::CriticalSection crit_;
+-#ifdef USE_TALK_SOUND
+-  talk_base::scoped_ptr<SoundSystemFactory> sound_system_factory_;
+-#endif
+   talk_base::scoped_ptr<MediaEngine> media_engine_;
+   talk_base::scoped_ptr<DeviceManager> device_manager_;
+   bool initialized_;
+diff -upN libjingle-0.5.2/talk/session/phone/cryptoparams.h.chromium12 libjingle-0.5.2/talk/session/phone/cryptoparams.h
+--- libjingle-0.5.2/talk/session/phone/cryptoparams.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/cryptoparams.h	2011-03-30 21:51:32.714287001 -0400
+@@ -32,7 +32,7 @@
+ 
+ namespace cricket {
+ 
+-// Parameters for SRTP negotiation, as described in RFC 4586.
++// Parameters for SRTP negotiation, as described in RFC 4568.
+ struct CryptoParams {
+   CryptoParams() : tag(0) {}
+   CryptoParams(int t, const std::string& cs,
+diff -upN libjingle-0.5.2/talk/session/phone/Makefile.am.chromium12 libjingle-0.5.2/talk/session/phone/Makefile.am
+--- libjingle-0.5.2/talk/session/phone/Makefile.am.chromium12	2011-03-30 21:51:32.658287001 -0400
++++ libjingle-0.5.2/talk/session/phone/Makefile.am	2011-03-30 21:51:32.715287001 -0400
+@@ -7,9 +7,11 @@
+                                     codec.cc \
+                                     devicemanager.cc \
+                                     filemediaengine.cc \
++                                    libudevsymboltable.cc \
+                                     mediaengine.cc \
+                                     mediamonitor.cc \
+                                     mediasessionclient.cc \
++                                    rtcpmuxfilter.cc \
+                                     rtpdump.cc \
+                                     soundclip.cc \
+                                     srtpfilter.cc \
+@@ -26,8 +28,10 @@
+                                     channel.h \
+                                     filemediaengine.h \
+                                     mediasessionclient.h \
++                                    rtcpmuxfilter.h \
+                                     rtpdump.h \
+                                     srtpfilter.h \
++                                    libudevsymboltable.h \
+                                     videocommon.h
+ 
+ libjinglesessionphone_la_LDFLAGS = -version-info $(LIBJINGLE_LIBRARY_VERSION)
+diff -upN libjingle-0.5.2/talk/session/phone/mediachannel.h.chromium12 libjingle-0.5.2/talk/session/phone/mediachannel.h
+--- libjingle-0.5.2/talk/session/phone/mediachannel.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/mediachannel.h	2011-03-30 21:51:32.715287001 -0400
+@@ -187,6 +187,24 @@ struct VideoMediaInfo {
+ 
+ class VoiceMediaChannel : public MediaChannel {
+  public:
++  enum Error {
++    ERROR_NONE = 0,                       // No error.
++    ERROR_OTHER,                          // Other errors.
++    ERROR_REC_DEVICE_OPEN_FAILED = 100,   // Could not open mic.
++    ERROR_REC_DEVICE_MUTED,               // Mic was muted by OS.
++    ERROR_REC_DEVICE_SILENT,              // No background noise picked up.
++    ERROR_REC_DEVICE_SATURATION,          // Mic input is clipping.
++    ERROR_REC_DEVICE_REMOVED,             // Mic was removed while active.
++    ERROR_REC_RUNTIME_ERROR,              // Processing is encountering errors.
++    ERROR_REC_SRTP_ERROR,                 // Generic SRTP failure.
++    ERROR_PLAY_DEVICE_OPEN_FAILED = 200,  // Could not open playout.
++    ERROR_PLAY_DEVICE_MUTED,              // Playout muted by OS.
++    ERROR_PLAY_DEVICE_REMOVED,            // Playout removed while active.
++    ERROR_PLAY_RUNTIME_ERROR,             // Errors in voice processing.
++    ERROR_PLAY_SRTP_ERROR,                // Generic SRTP failure.
++    ERROR_PLAY_SRTP_AUTH_FAILED,          // Failed to authenticate packets.
++  };
++
+   VoiceMediaChannel() {}
+   virtual ~VoiceMediaChannel() {}
+   // Sets the codecs/payload types to be used for incoming media.
+@@ -213,6 +231,16 @@ class VoiceMediaChannel : public MediaCh
+   virtual bool PressDTMF(int event, bool playout) = 0;
+   // Gets quality stats for the channel.
+   virtual bool GetStats(VoiceMediaInfo* info) = 0;
++  // Gets last reported error for this media channel.
++  virtual void GetLastMediaError(uint32* ssrc,
++                                 VoiceMediaChannel::Error* error) {
++    ASSERT(error != NULL);
++    *error = ERROR_NONE;
++  }
++
++  // Signal errors from MediaChannel.  Arguments are:
++  //     ssrc(uint32), and error(VoiceMediaChannel::Error).
++  sigslot::signal2<uint32, VoiceMediaChannel::Error> SignalMediaError;
+ };
+ 
+ // Represents a YUV420 (a.k.a. I420) video frame.
+@@ -390,6 +418,18 @@ class NullVideoRenderer : public VideoRe
+ 
+ class VideoMediaChannel : public MediaChannel {
+  public:
++  enum Error {
++    ERROR_NONE = 0,                       // No error.
++    ERROR_OTHER,                          // Other errors.
++    ERROR_REC_DEVICE_OPEN_FAILED = 100,   // Could not open camera.
++    ERROR_REC_DEVICE_NO_DEVICE,           // No camera.
++    ERROR_REC_DEVICE_IN_USE,              // Device is in already use.
++    ERROR_REC_DEVICE_REMOVED,             // Device is removed.
++    ERROR_REC_SRTP_ERROR,                 // Generic sender SRTP failure.
++    ERROR_PLAY_SRTP_ERROR = 200,          // Generic receiver SRTP failure.
++    ERROR_PLAY_SRTP_AUTH_FAILED,          // Failed to authenticate packets.
++  };
++
+   VideoMediaChannel() { renderer_ = NULL; }
+   virtual ~VideoMediaChannel() {}
+   // Sets the codecs/payload types to be used for incoming media.
+@@ -415,6 +455,7 @@ class VideoMediaChannel : public MediaCh
+   // Reuqest each of the remote senders to send an intra frame.
+   virtual bool RequestIntraFrame() = 0;
+ 
++  sigslot::signal2<uint32, Error> SignalMediaError;
+ 
+  protected:
+   VideoRenderer *renderer_;
+diff -upN libjingle-0.5.2/talk/session/phone/mediaengine.cc.chromium12 libjingle-0.5.2/talk/session/phone/mediaengine.cc
+--- libjingle-0.5.2/talk/session/phone/mediaengine.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/mediaengine.cc	2011-03-30 21:51:32.716287001 -0400
+@@ -33,11 +33,7 @@ namespace cricket {
+ // TODO: according to thaloun, HAVE_GIPSVIDEO will always
+ // be false, so we can get rid of it.
+ 
+-MediaEngine* MediaEngine::Create(
+-#ifdef USE_TALK_SOUND
+-    SoundSystemFactory *factory
+-#endif
+-    ) {
++MediaEngine* MediaEngine::Create() {
+   return new NullMediaEngine();
+ }
+ 
+diff -upN libjingle-0.5.2/talk/session/phone/mediaengine.h.chromium12 libjingle-0.5.2/talk/session/phone/mediaengine.h
+--- libjingle-0.5.2/talk/session/phone/mediaengine.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/mediaengine.h	2011-03-30 21:51:32.716287001 -0400
+@@ -39,9 +39,6 @@
+ #include "talk/session/phone/codec.h"
+ #include "talk/session/phone/devicemanager.h"
+ #include "talk/session/phone/mediachannel.h"
+-#ifdef USE_TALK_SOUND
+-#include "talk/sound/soundsystemfactory.h"
+-#endif
+ #include "talk/session/phone/videocommon.h"
+ 
+ namespace cricket {
+@@ -88,11 +85,7 @@ class MediaEngine {
+   };
+ 
+   virtual ~MediaEngine() {}
+-  static MediaEngine* Create(
+-#ifdef USE_TALK_SOUND
+-      SoundSystemFactory *factory
+-#endif
+-      );
++  static MediaEngine* Create();
+ 
+   // Initialization
+   // Starts the engine.
+@@ -154,7 +147,7 @@ class MediaEngine {
+   virtual void SetVoiceLogging(int min_sev, const char* filter) = 0;
+   virtual void SetVideoLogging(int min_sev, const char* filter) = 0;
+ 
+-  sigslot::repeater1<bool> SignalVideoCaptureResult;
++  sigslot::repeater1<CaptureResult> SignalVideoCaptureResult;
+ };
+ 
+ // CompositeMediaEngine constructs a MediaEngine from separate
+@@ -162,11 +155,6 @@ class MediaEngine {
+ template<class VOICE, class VIDEO>
+ class CompositeMediaEngine : public MediaEngine {
+  public:
+-#ifdef USE_TALK_SOUND
+-  explicit CompositeMediaEngine(SoundSystemFactory *factory)
+-      : voice_(factory) {
+-  }
+-#endif
+   CompositeMediaEngine() {}
+   virtual bool Init() {
+     if (!voice_.Init())
+@@ -257,6 +245,37 @@ class CompositeMediaEngine : public Medi
+   VIDEO video_;
+ };
+ 
++class NullVoiceMediaChannel : public VoiceMediaChannel {
++ public:
++  explicit NullVoiceMediaChannel() {}
++  ~NullVoiceMediaChannel() {}
++  // MediaChannel implementations
++  virtual void OnPacketReceived(talk_base::Buffer* packet) {}
++  virtual void OnRtcpReceived(talk_base::Buffer* packet) {}
++  virtual void SetSendSsrc(uint32 id) {}
++  virtual bool SetRtcpCName(const std::string& cname) { return true; }
++  virtual bool Mute(bool on) { return true; }
++  virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
++  virtual bool SetOptions(int options) { return true; }
++  // VoiceMediaChannel implementations
++  virtual bool SetRecvCodecs(const std::vector<AudioCodec> &codecs) {
++    return true;
++  }
++  virtual bool SetSendCodecs(const std::vector<AudioCodec> &codecs) {
++    return true;
++  }
++  virtual bool SetPlayout(bool playout) { return true; }
++  virtual bool SetSend(SendFlags flag) { return true; }
++  virtual bool AddStream(uint32 ssrc) { return true; }
++  virtual bool RemoveStream(uint32 ssrc) { return true; }
++  virtual bool GetActiveStreams(AudioInfo::StreamList* streams) { return true; }
++  virtual int GetOutputLevel() { return 0; }
++  virtual void SetRingbackTone(const char *buf, int len) {}
++  virtual bool PlayRingbackTone(bool play, bool loop) { return true; }
++  virtual bool PressDTMF(int event, bool playout) { return true; }
++  virtual bool GetStats(VoiceMediaInfo* info) { return false; }
++};
++
+ // NullVoiceEngine can be used with CompositeMediaEngine in the case where only
+ // a video engine is desired.
+ class NullVoiceEngine {
+@@ -265,7 +284,9 @@ class NullVoiceEngine {
+   void Terminate() {}
+   int GetCapabilities() { return 0; }
+   VoiceMediaChannel* CreateChannel() {
+-    return NULL;
++    // TODO: See if we can make things work without requiring
++    // allocation of a channel.
++    return new NullVoiceMediaChannel();
+   }
+   SoundclipMedia* CreateSoundclip() {
+     return NULL;
+@@ -304,7 +325,7 @@ class NullVideoEngine {
+   const std::vector<VideoCodec>& codecs() { return codecs_; }
+   bool FindCodec(const VideoCodec&) { return false; }
+   void SetLogging(int min_sev, const char* filter) {}
+-  sigslot::signal1<bool> SignalCaptureResult;
++  sigslot::signal1<CaptureResult> SignalCaptureResult;
+  private:
+   std::vector<VideoCodec> codecs_;
+ };
+diff -upN libjingle-0.5.2/talk/session/phone/rtpdump.cc.chromium12 libjingle-0.5.2/talk/session/phone/rtpdump.cc
+--- libjingle-0.5.2/talk/session/phone/rtpdump.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/rtpdump.cc	2011-03-30 21:51:32.716287001 -0400
+@@ -262,9 +262,9 @@ void RtpDumpLoopReader::UpdateDumpPacket
+ 
+   if (packet->IsValidRtpPacket()) {
+     // Get the old RTP sequence number and timestamp.
+-    uint16 sequence;
++    uint16 sequence = 0;
+     packet->GetRtpSeqNum(&sequence);
+-    uint32 timestamp;
++    uint32 timestamp = 0;
+     packet->GetRtpTimestamp(&timestamp);
+     // Increase the RTP sequence number and timestamp.
+     sequence += loop_count_ * rtp_seq_num_increase_;
+diff -upN libjingle-0.5.2/talk/session/phone/videocommon.h.chromium12 libjingle-0.5.2/talk/session/phone/videocommon.h
+--- libjingle-0.5.2/talk/session/phone/videocommon.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/videocommon.h	2011-03-30 21:51:32.716287001 -0400
+@@ -1,5 +1,5 @@
+ // libjingle
+-// Copyright 2004--2005, Google Inc.
++// Copyright 2011, Google Inc.
+ //
+ // Redistribution and use in source and binary forms, with or without
+ // modification, are permitted provided that the following conditions are met:
+@@ -59,34 +59,35 @@ inline std::string GetFourccName(uint32 
+ //   http://developer.apple.com/quicktime/icefloe/dispatch020.html
+ //   http://www.fourcc.org/yuv.php
+ enum FourCC {
+-  // Canonical fourccs used in our code.
++  // Canonical fourcc codes used in our code.
+   FOURCC_I420 = FOURCC('I', '4', '2', '0'),
+   FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'),
+   FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'),
++  FOURCC_M420 = FOURCC('M', '4', '2', '0'),
+   FOURCC_24BG = FOURCC('2', '4', 'B', 'G'),
+-  FOURCC_RGBA = FOURCC('R', 'G', 'B', 'A'),
++  FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'),
+   FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'),
+   FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B'),
+   FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'),
+-  FOURCC_JPEG = FOURCC('J', 'P', 'E', 'G'),
+   FOURCC_RAW  = FOURCC('r', 'a', 'w', ' '),
+-  // Next five are Bayer RGB formats. The four characters define the order of
++  FOURCC_NV21 = FOURCC('N', 'V', '2', '1'),
++  FOURCC_NV12 = FOURCC('N', 'V', '1', '2'),
++  // Next four are Bayer RGB formats. The four characters define the order of
+   // the colours in each 2x2 pixel grid, going left-to-right and top-to-bottom.
+   FOURCC_RGGB = FOURCC('R', 'G', 'G', 'B'),
+   FOURCC_BGGR = FOURCC('B', 'G', 'G', 'R'),
+   FOURCC_GRBG = FOURCC('G', 'R', 'B', 'G'),
+   FOURCC_GBRG = FOURCC('G', 'B', 'R', 'G'),
+ 
+-  // Aliases for canonical fourccs, replaced with their canonical equivalents by
+-  // CanonicalFourCC().
++  // Aliases for canonical fourcc codes, replaced with their canonical
++  // equivalents by CanonicalFourCC().
+   FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'),  // Alias for I420
+   FOURCC_YU12 = FOURCC('Y', 'U', '1', '2'),  // Alias for I420
+   FOURCC_YUYV = FOURCC('Y', 'U', 'Y', 'V'),  // Alias for YUY2
+-  FOURCC_YUVS = FOURCC('y', 'u', 'v', 's'),  // Alias for YUY2
++  FOURCC_YUVS = FOURCC('y', 'u', 'v', 's'),  // Alias for YUY2 on Mac
+   FOURCC_HDYC = FOURCC('H', 'D', 'Y', 'C'),  // Alias for UYVY
+   FOURCC_2VUY = FOURCC('2', 'v', 'u', 'y'),  // Alias for UYVY
+-  FOURCC_RGB1 = FOURCC('R', 'G', 'B', '1'),  // Alias for ABGR
+-  FOURCC_RGB2 = FOURCC('R', 'G', 'B', '2'),  // Alias for BGRA
++  FOURCC_JPEG = FOURCC('J', 'P', 'E', 'G'),  // Alias for MJPG
+   FOURCC_BA81 = FOURCC('B', 'A', '8', '1'),  // Alias for BGGR
+ 
+   // Match any fourcc.
+diff -upN libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.cc.chromium12 libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.cc
+--- libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.cc.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.cc	2011-03-30 21:51:32.717287001 -0400
+@@ -198,6 +198,26 @@ void PseudoTcpChannel::OnSessionTerminat
+     if (stream_ != NULL)
+       stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_CLOSE, -1));
+   }
++
++  // Even though session_ is being destroyed, we mustn't clear the pointer,
++  // since we'll need it to tear down channel_.
++  //
++  // TODO(wez): Is it always the case that if channel_ != NULL then we'll get
++  // a channel-destroyed notification?
++}
++
++void PseudoTcpChannel::GetOption(PseudoTcp::Option opt, int* value) {
++  ASSERT(signal_thread_->IsCurrent());
++  CritScope lock(&cs_);
++  ASSERT(tcp_ != NULL);
++  tcp_->GetOption(opt, value);
++}
++
++void PseudoTcpChannel::SetOption(PseudoTcp::Option opt, int value) {
++  ASSERT(signal_thread_->IsCurrent());
++  CritScope lock(&cs_);
++  ASSERT(tcp_ != NULL);
++  tcp_->SetOption(opt, value);
+ }
+ 
+ //
+diff -upN libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.h.chromium12 libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.h
+--- libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/tunnel/pseudotcpchannel.h	2011-03-30 21:51:32.717287001 -0400
+@@ -43,18 +43,22 @@ namespace cricket {
+ class TransportChannel;
+ 
+ ///////////////////////////////////////////////////////////////////////////////
+-// ChannelStream
+-// Note: The lifetime of TunnelSession is complicated.  It needs to survive
+-// until the following three conditions are true:
+-// 1) TunnelStream has called Close (tracked via non-null stream_)
+-// 2) PseudoTcp has completed (tracked via non-null tcp_)
+-// 3) Session has been destroyed (tracked via non-null session_)
+-// This is accomplished by calling CheckDestroy after these indicators change.
++// PseudoTcpChannel
++// Note: The PseudoTcpChannel must persist until both of:
++// 1) The StreamInterface provided via GetStream has been closed.
++//    This is tracked via non-null stream_.
++// 2) The PseudoTcp session has completed.
++//    This is tracked via non-null worker_thread_.  When PseudoTcp is done,
++//    the TransportChannel is signalled to tear-down.  Once the channel is
++//    torn down, the worker thread is purged.
++// These indicators are checked by CheckDestroy, invoked whenever one of them
++// changes.
+ ///////////////////////////////////////////////////////////////////////////////
+-// TunnelStream
+-// Note: Because TunnelStream provides a stream interface, it's lifetime is
+-// controlled by the owner of the stream pointer.  As a result, we must support
+-// both the TunnelSession disappearing before TunnelStream, and vice versa.
++// PseudoTcpChannel::GetStream
++// Note: The stream pointer returned by GetStream is owned by the caller.
++// They can close & immediately delete the stream while PseudoTcpChannel still
++// has cleanup work to do.  They can also close the stream but not delete it
++// until long after PseudoTcpChannel has finished.  We must cope with both.
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+ class PseudoTcpChannel
+@@ -72,8 +76,14 @@ public:
+ 
+   sigslot::signal1<PseudoTcpChannel*> SignalChannelClosed;
+ 
++  // Call this when the Session used to create this channel is being torn
++  // down, to ensure that things get cleaned up properly.
+   void OnSessionTerminate(Session* session);
+ 
++  // See the PseudoTcp class for available options.
++  void GetOption(PseudoTcp::Option opt, int* value);
++  void SetOption(PseudoTcp::Option opt, int value);
++
+ private:
+   class InternalStream;
+   friend class InternalStream;
+diff -upN libjingle-0.5.2/talk/site_scons/talk.py.chromium12 libjingle-0.5.2/talk/site_scons/talk.py
+--- libjingle-0.5.2/talk/site_scons/talk.py.chromium12	2011-01-11 19:25:51.000000000 -0500
++++ libjingle-0.5.2/talk/site_scons/talk.py	2011-03-30 21:51:32.717287001 -0400
+@@ -211,7 +211,7 @@ def AddMediaLibs(env, **kwargs):
+   elif env.Bit('mac'):
+     gips_lib = 'VoiceEngine_mac_universal_gcc'
+   elif env.Bit('linux'):
+-      gips_lib = 'VoiceEngine_Linux_external_gcc'
++      gips_lib = 'VoiceEngine_Linux_gcc'
+ 
+ 
+   AddToDict(kwargs, 'libs', [
+--- libjingle-0.5.2/talk/session/phone/devicemanager.h.chromium12	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/devicemanager.h	2011-03-30 23:57:46.524287064 -0400
+@@ -59,11 +59,7 @@
+ // Methods are virtual to allow for easy stubbing/mocking in tests.
+ class DeviceManager {
+  public:
+-  DeviceManager(
+-#ifdef USE_TALK_SOUND
+-      SoundSystemFactory *factory
+-#endif
+-      );
++  DeviceManager();
+   virtual ~DeviceManager();
+ 
+   // Initialization
+@@ -82,7 +78,7 @@
+   bool GetAudioOutputDevice(const std::string& name, Device* out);
+ 
+   virtual bool GetVideoCaptureDevices(std::vector<Device>* devs);
+-  virtual bool GetDefaultVideoCaptureDevice(Device* device);
++  bool GetVideoCaptureDevice(const std::string& name, Device* out);
+ 
+   sigslot::signal0<> SignalDevicesChange;
+ 
+@@ -93,10 +89,15 @@
+  protected:
+   virtual bool GetAudioDevice(bool is_input, const std::string& name,
+                               Device* out);
++  virtual bool GetDefaultVideoCaptureDevice(Device* device);
++
+  private:
+   bool GetAudioDevicesByPlatform(bool input, std::vector<Device>* devs);
+ 
+   bool initialized_;
++#ifdef WIN32
++  bool need_couninitialize_;
++#endif
+   DeviceWatcher* watcher_;
+ #ifdef USE_TALK_SOUND
+   SoundSystemHandle sound_system_;
+--- libjingle-0.5.2/talk/session/phone/devicemanager.cc.chromium12	2011-03-30 23:58:32.819287002 -0400
++++ libjingle-0.5.2/talk/session/phone/devicemanager.cc	2011-03-31 00:03:00.810286990 -0400
+@@ -53,17 +53,18 @@
+ #include "talk/base/stream.h"
+ #include "talk/session/phone/libudevsymboltable.h"
+ #include "talk/session/phone/v4llookup.h"
++#if USE_TALK_SOUND
++#include "talk/sound/platformsoundsystem.h"
++#include "talk/sound/platformsoundsystemfactory.h"
++#include "talk/sound/sounddevicelocator.h"
++#include "talk/sound/soundsysteminterface.h"
++#endif
+ #endif
+ 
+ #include "talk/session/phone/devicemanager.h"
+ #include "talk/base/logging.h"
+ #include "talk/base/stringutils.h"
+ #include "talk/session/phone/mediaengine.h"
+-#if USE_TALK_SOUND
+-#include "talk/sound/platformsoundsystem.h"
+-#include "talk/sound/sounddevicelocator.h"
+-#include "talk/sound/soundsysteminterface.h"
+-#endif
+ 
+ namespace cricket {
+ // Initialize to empty string.
+@@ -116,9 +117,17 @@
+   DeviceManager* manager_;
+   void* impl_;
+ };
++#elif defined(IOS) || defined(ANDROID)
++// We don't use DeviceWatcher on iOS or Android, so just stub out a noop class.
++class DeviceWatcher {
++ public:
++  explicit DeviceWatcher(DeviceManager* dm) {}
++  bool Start() { return true; }
++  void Stop() {}
++};
+ #endif
+ 
+-#ifndef LINUX
++#if !defined(LINUX) && !defined(IOS)
+ static bool ShouldDeviceBeIgnored(const std::string& device_name);
+ #endif
+ #ifndef OSX
+@@ -142,15 +151,14 @@
+ static bool GetAudioDeviceName(AudioDeviceID id, bool input, std::string* out);
+ #endif
+ 
+-DeviceManager::DeviceManager(
+-#ifdef USE_TALK_SOUND
+-    SoundSystemFactory *factory
+-#endif
+-    )
++DeviceManager::DeviceManager()
+     : initialized_(false),
++#if defined(WIN32)
++      need_couninitialize_(false),
++#endif
+       watcher_(new DeviceWatcher(this))
+ #ifdef USE_TALK_SOUND
+-      , sound_system_(factory)
++      , sound_system_(new PlatformSoundSystemFactory())
+ #endif
+     {
+ }
+@@ -164,6 +172,16 @@
+ 
+ bool DeviceManager::Init() {
+   if (!initialized_) {
++#if defined(WIN32)
++    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
++    need_couninitialize_ = SUCCEEDED(hr);
++    if (FAILED(hr)) {
++      LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr;
++      if (hr != RPC_E_CHANGED_MODE) {
++        return false;
++      }
++    }
++#endif
+     if (!watcher_->Start()) {
+       return false;
+     }
+@@ -175,6 +193,12 @@
+ void DeviceManager::Terminate() {
+   if (initialized_) {
+     watcher_->Stop();
++#if defined(WIN32)
++    if (need_couninitialize_) {
++      CoUninitialize();
++      need_couninitialize_ = false;
++    }
++#endif
+     initialized_ = false;
+   }
+ }
+@@ -259,6 +283,28 @@
+   return ret;
+ }
+ 
++bool DeviceManager::GetVideoCaptureDevice(const std::string& name,
++                                          Device* out) {
++  // If the name is empty, return the default device.
++  if (name.empty() || name == kDefaultDeviceName) {
++    return GetDefaultVideoCaptureDevice(out);
++  }
++
++  std::vector<Device> devices;
++  if (!GetVideoCaptureDevices(&devices)) {
++    return false;
++  }
++
++  for (std::vector<Device>::const_iterator it = devices.begin();
++      it != devices.end(); ++it) {
++    if (name == it->name) {
++      *out = *it;
++      return true;
++    }
++  }
++
++  return false;
++}
+ 
+ bool DeviceManager::GetAudioDevice(bool is_input, const std::string& name,
+                                    Device* out) {
+@@ -287,6 +333,7 @@
+ bool DeviceManager::GetAudioDevicesByPlatform(bool input,
+                                               std::vector<Device>* devs) {
+   devs->clear();
++
+ #if defined(USE_TALK_SOUND)
+   if (!sound_system_.get()) {
+     return false;
+@@ -332,7 +379,6 @@
+     }
+   }
+   return ret;
+-
+ #elif defined(LINUX)
+   int card = -1, dev = -1;
+   snd_ctl_t *handle = NULL;
+@@ -385,20 +431,7 @@
+ 
+ #if defined(WIN32)
+ bool GetVideoDevices(std::vector<Device>* devices) {
+-  // TODO: Move the CoInit stuff to Initialize/Terminate.
+-  HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+-  if (FAILED(hr)) {
+-    LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr;
+-    if (hr != RPC_E_CHANGED_MODE) {
+-      return false;
+-    }
+-  }
+-
+-  bool ret = GetDevices(CLSID_VideoInputDeviceCategory, devices);
+-  if (SUCCEEDED(hr)) {
+-    CoUninitialize();
+-  }
+-  return ret;
++  return GetDevices(CLSID_VideoInputDeviceCategory, devices);
+ }
+ 
+ bool GetDevices(const CLSID& catid, std::vector<Device>* devices) {
+@@ -977,7 +1010,7 @@
+ 
+ // TODO: Try to get hold of a copy of Final Cut to understand why we
+ //               crash while scanning their components on OS X.
+-#ifndef LINUX
++#if !defined(LINUX) && !defined(IOS)
+ static bool ShouldDeviceBeIgnored(const std::string& device_name) {
+   static const char* const kFilteredDevices[] =  {
+       "Google Camera Adapter",   // Our own magiccams
diff --git a/libjingle-0.5.2-compilefix.patch b/libjingle-0.5.2-compilefix.patch
new file mode 100644
index 0000000..2e17641
--- /dev/null
+++ b/libjingle-0.5.2-compilefix.patch
@@ -0,0 +1,13 @@
+diff -upN libjingle-0.5.2/talk/base/ratetracker.cc.compilefix libjingle-0.5.2/talk/base/ratetracker.cc
+--- libjingle-0.5.2/talk/base/ratetracker.cc.compilefix	2011-01-11 19:25:49.000000000 -0500
++++ libjingle-0.5.2/talk/base/ratetracker.cc	2011-03-30 23:53:08.288286757 -0400
+@@ -25,8 +25,8 @@
+  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+-#include "talk/base/ratetracker.h"
+ #include "talk/base/time.h"
++#include "talk/base/ratetracker.h"
+ 
+ namespace talk_base {
+ 
diff --git a/libjingle-0.5.2-devicemanager-alsafix.patch b/libjingle-0.5.2-devicemanager-alsafix.patch
new file mode 100644
index 0000000..a7f271b
--- /dev/null
+++ b/libjingle-0.5.2-devicemanager-alsafix.patch
@@ -0,0 +1,30 @@
+diff -up libjingle-0.5.2/talk/session/phone/devicemanager.cc.alsa libjingle-0.5.2/talk/session/phone/devicemanager.cc
+--- libjingle-0.5.2/talk/session/phone/devicemanager.cc.alsa	2011-01-11 19:25:50.000000000 -0500
++++ libjingle-0.5.2/talk/session/phone/devicemanager.cc	2011-03-30 19:49:54.989287610 -0400
+@@ -25,7 +25,7 @@
+  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+-#include "talk/session/phone/devicemanager.h"
++#include "config.h"
+ 
+ #if WIN32
+ #include <atlbase.h>
+@@ -45,9 +45,7 @@
+ #elif LINUX
+ #include <libudev.h>
+ #include <unistd.h>
+-#ifndef USE_TALK_SOUND
+ #include <alsa/asoundlib.h>
+-#endif
+ #include "talk/base/linux.h"
+ #include "talk/base/fileutils.h"
+ #include "talk/base/pathutils.h"
+@@ -57,6 +55,7 @@
+ #include "talk/session/phone/v4llookup.h"
+ #endif
+ 
++#include "talk/session/phone/devicemanager.h"
+ #include "talk/base/logging.h"
+ #include "talk/base/stringutils.h"
+ #include "talk/session/phone/mediaengine.h"
diff --git a/libjingle.spec b/libjingle.spec
index 3d4ee5d..643d716 100644
--- a/libjingle.spec
+++ b/libjingle.spec
@@ -1,6 +1,6 @@
 Name:           libjingle
-Version:        0.5.1
-Release:        5%{?dist}
+Version:        0.5.2
+Release:        1%{?dist}
 Summary:        GoogleTalk implementation of Jingle
 Group:          System Environment/Libraries
 License:        BSD
@@ -34,7 +34,7 @@ Patch6:		libjingle-0.5.1-unixfilesystemfix.patch
 Patch7:		libjingle-0.5.1-system-expat.patch
 Patch8:		libjingle-0.5.1-system-srtp.patch
 # Fix devicemanager.cc to compile, alsa as linux default
-Patch9:		libjingle-0.5.1-devicemanager-alsafix.patch
+Patch9:		libjingle-0.5.2-devicemanager-alsafix.patch
 # Fix v4llookup.cc to compile
 Patch10:	libjingle-0.5.1-v4llookup-fix.patch
 # Fix type and definition conflicts with Chromium
@@ -45,6 +45,10 @@ Patch12:        libjingle-0.5.1-64bittypes.patch
 Patch13:	libjingle-0.5.1-qname-threadsafe.patch
 # Make sure linux.h/linux.cc pulls in config.h for LINUX define
 Patch14:	libjingle-0.5.1-config-linux.patch
+# Chromium 12 forks libjingle. Again. :P
+Patch15:	libjingle-0.5.2-chromium12-changes.patch
+# Fix 0.5.2 compilation
+Patch16:	libjingle-0.5.2-compilefix.patch
 
 BuildRequires:	libtool, autoconf, automake
 BuildRequires:	openssl-devel
@@ -94,6 +98,8 @@ developing applications that use %{name}.
 %patch12 -p1 -b .64bit
 %patch13 -p1 -b .threadsafe
 %patch14 -p1 -b .config
+%patch15 -p1 -b .chromium12
+%patch16 -p1 -b .compilefix
 
 touch NEWS ChangeLog
 autoreconf -i
@@ -138,6 +144,10 @@ rm -rf $RPM_BUILD_ROOT
 
 
 %changelog
+* Wed Mar 30 2011 Tom Callaway <spot at fedoraproject.org> - 0.5.2-1
+- update to 0.5.2
+- merge Google's unpublished Chromium 12 changes
+
 * Tue Feb 08 2011 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 0.5.1-5
 - Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
 
diff --git a/sources b/sources
index e3e55b0..d908674 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-a59bac5b6111afc79efd3d1e821c13d8  libjingle-0.5.1.zip
+b5b7e91adb38aa2d79920ad27cec7759  libjingle-0.5.2.zip


More information about the scm-commits mailing list