Move talk/media to webrtc/media

I removed the 'libjingle' target in talk/libjingle.gyp and replaced
all users of it with base/base.gyp:rtc_base. It seems the jsoncpp
and expat dependencies were not used by it's previous references.

The files in talk/media/testdata were uploaded to Google Storage and
added .sha1 files in resources/media instead of simply moving them.

The previously disabled warnings that were inherited from
talk/build/common.gypi are now replaced by target-specific disabling
of only the failing warnings. Additional disabling was needed since the stricter
compilation warnings that applies to code in webrtc/.

License headers will be updated in a follow-up CL in order to not
break Git history.

Other modifications:
* Updated the header guards.
* Sorted the includes using chromium/src/tools/sort-headers.py
  except for these files:
  talk/app/webrtc/peerconnectionendtoend_unittest.cc
  talk/app/webrtc/java/jni/androidmediadecoder_jni.cc
  talk/app/webrtc/java/jni/androidmediaencoder_jni.cc
  webrtc/media/devices/win32devicemanager.cc.
* Unused GYP reference to libjingle_tests_additional_deps was removed.
* Removed duplicated GYP entries of
  webrtc/base/testutils.cc
  webrtc/base/testutils.h

The HAVE_WEBRTC_VIDEO and HAVE_WEBRTC_VOICE defines were used by only talk/media,
so they were moved to the media.gyp.

I also checked that none of
EXPAT_RELATIVE_PATH,
FEATURE_ENABLE_VOICEMAIL,
GTEST_RELATIVE_PATH,
JSONCPP_RELATIVE_PATH,
LOGGING=1,
SRTP_RELATIVE_PATH,
FEATURE_ENABLE_SSL,
FEATURE_ENABLE_VOICEMAIL,
FEATURE_ENABLE_PSTN,
HAVE_SCTP,
HAVE_SRTP,
are used by the talk/media code.

For Chromium, the following changes will need to be applied to the roll CL that updates the
DEPS for WebRTC and libjingle: https://codereview.chromium.org/1604303002/

BUG=webrtc:5420
NOPRESUBMIT=True
TBR=tommi@webrtc.org

Review URL: https://codereview.webrtc.org/1587193006

Cr-Commit-Position: refs/heads/master@{#11495}
diff --git a/webrtc/media/sctp/sctpdataengine.cc b/webrtc/media/sctp/sctpdataengine.cc
new file mode 100644
index 0000000..4cd39e9
--- /dev/null
+++ b/webrtc/media/sctp/sctpdataengine.cc
@@ -0,0 +1,1053 @@
+/*
+ * libjingle
+ * Copyright 2012 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "webrtc/media/sctp/sctpdataengine.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <sstream>
+#include <vector>
+
+#include "usrsctplib/usrsctp.h"
+#include "webrtc/base/arraysize.h"
+#include "webrtc/base/buffer.h"
+#include "webrtc/base/helpers.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/safe_conversions.h"
+#include "webrtc/media/base/codec.h"
+#include "webrtc/media/base/constants.h"
+#include "webrtc/media/base/streamparams.h"
+
+namespace {
+typedef cricket::SctpDataMediaChannel::StreamSet StreamSet;
+// Returns a comma-separated, human-readable list of the stream IDs in 's'
+std::string ListStreams(const StreamSet& s) {
+  std::stringstream result;
+  bool first = true;
+  for (StreamSet::const_iterator it = s.begin(); it != s.end(); ++it) {
+    if (!first) {
+      result << ", " << *it;
+    } else {
+      result << *it;
+      first = false;
+    }
+  }
+  return result.str();
+}
+
+// Returns a pipe-separated, human-readable list of the SCTP_STREAM_RESET
+// flags in 'flags'
+std::string ListFlags(int flags) {
+  std::stringstream result;
+  bool first = true;
+  // Skip past the first 12 chars (strlen("SCTP_STREAM_"))
+#define MAKEFLAG(X) { X, #X + 12}
+  struct flaginfo_t {
+    int value;
+    const char* name;
+  } flaginfo[] = {
+    MAKEFLAG(SCTP_STREAM_RESET_INCOMING_SSN),
+    MAKEFLAG(SCTP_STREAM_RESET_OUTGOING_SSN),
+    MAKEFLAG(SCTP_STREAM_RESET_DENIED),
+    MAKEFLAG(SCTP_STREAM_RESET_FAILED),
+    MAKEFLAG(SCTP_STREAM_CHANGE_DENIED)
+  };
+#undef MAKEFLAG
+  for (uint32_t i = 0; i < arraysize(flaginfo); ++i) {
+    if (flags & flaginfo[i].value) {
+      if (!first) result << " | ";
+      result << flaginfo[i].name;
+      first = false;
+    }
+  }
+  return result.str();
+}
+
+// Returns a comma-separated, human-readable list of the integers in 'array'.
+// All 'num_elems' of them.
+std::string ListArray(const uint16_t* array, int num_elems) {
+  std::stringstream result;
+  for (int i = 0; i < num_elems; ++i) {
+    if (i) {
+      result << ", " << array[i];
+    } else {
+      result << array[i];
+    }
+  }
+  return result.str();
+}
+}  // namespace
+
+namespace cricket {
+typedef rtc::ScopedMessageData<SctpInboundPacket> InboundPacketMessage;
+typedef rtc::ScopedMessageData<rtc::Buffer> OutboundPacketMessage;
+
+// The biggest SCTP packet.  Starting from a 'safe' wire MTU value of 1280,
+// take off 80 bytes for DTLS/TURN/TCP/IP overhead.
+static const size_t kSctpMtu = 1200;
+
+// The size of the SCTP association send buffer.  256kB, the usrsctp default.
+static const int kSendBufferSize = 262144;
+enum {
+  MSG_SCTPINBOUNDPACKET = 1,   // MessageData is SctpInboundPacket
+  MSG_SCTPOUTBOUNDPACKET = 2,  // MessageData is rtc:Buffer
+};
+
+struct SctpInboundPacket {
+  rtc::Buffer buffer;
+  ReceiveDataParams params;
+  // The |flags| parameter is used by SCTP to distinguish notification packets
+  // from other types of packets.
+  int flags;
+};
+
+// Helper for logging SCTP messages.
+static void debug_sctp_printf(const char *format, ...) {
+  char s[255];
+  va_list ap;
+  va_start(ap, format);
+  vsnprintf(s, sizeof(s), format, ap);
+  LOG(LS_INFO) << "SCTP: " << s;
+  va_end(ap);
+}
+
+// Get the PPID to use for the terminating fragment of this type.
+static SctpDataMediaChannel::PayloadProtocolIdentifier GetPpid(
+    cricket::DataMessageType type) {
+  switch (type) {
+  default:
+  case cricket::DMT_NONE:
+    return SctpDataMediaChannel::PPID_NONE;
+  case cricket::DMT_CONTROL:
+    return SctpDataMediaChannel::PPID_CONTROL;
+  case cricket::DMT_BINARY:
+    return SctpDataMediaChannel::PPID_BINARY_LAST;
+  case cricket::DMT_TEXT:
+    return SctpDataMediaChannel::PPID_TEXT_LAST;
+  };
+}
+
+static bool GetDataMediaType(
+    SctpDataMediaChannel::PayloadProtocolIdentifier ppid,
+    cricket::DataMessageType *dest) {
+  ASSERT(dest != NULL);
+  switch (ppid) {
+    case SctpDataMediaChannel::PPID_BINARY_PARTIAL:
+    case SctpDataMediaChannel::PPID_BINARY_LAST:
+      *dest = cricket::DMT_BINARY;
+      return true;
+
+    case SctpDataMediaChannel::PPID_TEXT_PARTIAL:
+    case SctpDataMediaChannel::PPID_TEXT_LAST:
+      *dest = cricket::DMT_TEXT;
+      return true;
+
+    case SctpDataMediaChannel::PPID_CONTROL:
+      *dest = cricket::DMT_CONTROL;
+      return true;
+
+    case SctpDataMediaChannel::PPID_NONE:
+      *dest = cricket::DMT_NONE;
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+// Log the packet in text2pcap format, if log level is at LS_VERBOSE.
+static void VerboseLogPacket(void *data, size_t length, int direction) {
+  if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) {
+    char *dump_buf;
+    if ((dump_buf = usrsctp_dumppacket(
+             data, length, direction)) != NULL) {
+      LOG(LS_VERBOSE) << dump_buf;
+      usrsctp_freedumpbuffer(dump_buf);
+    }
+  }
+}
+
+// This is the callback usrsctp uses when there's data to send on the network
+// that has been wrapped appropriatly for the SCTP protocol.
+static int OnSctpOutboundPacket(void* addr, void* data, size_t length,
+                                uint8_t tos, uint8_t set_df) {
+  SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(addr);
+  LOG(LS_VERBOSE) << "global OnSctpOutboundPacket():"
+                  << "addr: " << addr << "; length: " << length
+                  << "; tos: " << std::hex << static_cast<int>(tos)
+                  << "; set_df: " << std::hex << static_cast<int>(set_df);
+
+  VerboseLogPacket(addr, length, SCTP_DUMP_OUTBOUND);
+  // Note: We have to copy the data; the caller will delete it.
+  auto* msg = new OutboundPacketMessage(
+      new rtc::Buffer(reinterpret_cast<uint8_t*>(data), length));
+  channel->worker_thread()->Post(channel, MSG_SCTPOUTBOUNDPACKET, msg);
+  return 0;
+}
+
+// This is the callback called from usrsctp when data has been received, after
+// a packet has been interpreted and parsed by usrsctp and found to contain
+// payload data. It is called by a usrsctp thread. It is assumed this function
+// will free the memory used by 'data'.
+static int OnSctpInboundPacket(struct socket* sock, union sctp_sockstore addr,
+                               void* data, size_t length,
+                               struct sctp_rcvinfo rcv, int flags,
+                               void* ulp_info) {
+  SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(ulp_info);
+  // Post data to the channel's receiver thread (copying it).
+  // TODO(ldixon): Unclear if copy is needed as this method is responsible for
+  // memory cleanup. But this does simplify code.
+  const SctpDataMediaChannel::PayloadProtocolIdentifier ppid =
+      static_cast<SctpDataMediaChannel::PayloadProtocolIdentifier>(
+          rtc::HostToNetwork32(rcv.rcv_ppid));
+  cricket::DataMessageType type = cricket::DMT_NONE;
+  if (!GetDataMediaType(ppid, &type) && !(flags & MSG_NOTIFICATION)) {
+    // It's neither a notification nor a recognized data packet.  Drop it.
+    LOG(LS_ERROR) << "Received an unknown PPID " << ppid
+                  << " on an SCTP packet.  Dropping.";
+  } else {
+    SctpInboundPacket* packet = new SctpInboundPacket;
+    packet->buffer.SetData(reinterpret_cast<uint8_t*>(data), length);
+    packet->params.ssrc = rcv.rcv_sid;
+    packet->params.seq_num = rcv.rcv_ssn;
+    packet->params.timestamp = rcv.rcv_tsn;
+    packet->params.type = type;
+    packet->flags = flags;
+    // The ownership of |packet| transfers to |msg|.
+    InboundPacketMessage* msg = new InboundPacketMessage(packet);
+    channel->worker_thread()->Post(channel, MSG_SCTPINBOUNDPACKET, msg);
+  }
+  free(data);
+  return 1;
+}
+
+// Set the initial value of the static SCTP Data Engines reference count.
+int SctpDataEngine::usrsctp_engines_count = 0;
+
+SctpDataEngine::SctpDataEngine() {
+  if (usrsctp_engines_count == 0) {
+    // First argument is udp_encapsulation_port, which is not releveant for our
+    // AF_CONN use of sctp.
+    usrsctp_init(0, cricket::OnSctpOutboundPacket, debug_sctp_printf);
+
+    // To turn on/off detailed SCTP debugging. You will also need to have the
+    // SCTP_DEBUG cpp defines flag.
+    // usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
+
+    // TODO(ldixon): Consider turning this on/off.
+    usrsctp_sysctl_set_sctp_ecn_enable(0);
+
+    // This is harmless, but we should find out when the library default
+    // changes.
+    int send_size = usrsctp_sysctl_get_sctp_sendspace();
+    if (send_size != kSendBufferSize) {
+      LOG(LS_ERROR) << "Got different send size than expected: " << send_size;
+    }
+
+    // TODO(ldixon): Consider turning this on/off.
+    // This is not needed right now (we don't do dynamic address changes):
+    // If SCTP Auto-ASCONF is enabled, the peer is informed automatically
+    // when a new address is added or removed. This feature is enabled by
+    // default.
+    // usrsctp_sysctl_set_sctp_auto_asconf(0);
+
+    // TODO(ldixon): Consider turning this on/off.
+    // Add a blackhole sysctl. Setting it to 1 results in no ABORTs
+    // being sent in response to INITs, setting it to 2 results
+    // in no ABORTs being sent for received OOTB packets.
+    // This is similar to the TCP sysctl.
+    //
+    // See: http://lakerest.net/pipermail/sctp-coders/2012-January/009438.html
+    // See: http://svnweb.freebsd.org/base?view=revision&revision=229805
+    // usrsctp_sysctl_set_sctp_blackhole(2);
+
+    // Set the number of default outgoing streams.  This is the number we'll
+    // send in the SCTP INIT message.  The 'appropriate default' in the
+    // second paragraph of
+    // http://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-05#section-6.2
+    // is cricket::kMaxSctpSid.
+    usrsctp_sysctl_set_sctp_nr_outgoing_streams_default(
+        cricket::kMaxSctpSid);
+  }
+  usrsctp_engines_count++;
+
+  cricket::DataCodec codec(kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, 0);
+  codec.SetParam(kCodecParamPort, kSctpDefaultPort);
+  codecs_.push_back(codec);
+}
+
+SctpDataEngine::~SctpDataEngine() {
+  usrsctp_engines_count--;
+  LOG(LS_VERBOSE) << "usrsctp_engines_count:" << usrsctp_engines_count;
+
+  if (usrsctp_engines_count == 0) {
+    // usrsctp_finish() may fail if it's called too soon after the channels are
+    // closed. Wait and try again until it succeeds for up to 3 seconds.
+    for (size_t i = 0; i < 300; ++i) {
+      if (usrsctp_finish() == 0)
+        return;
+
+      rtc::Thread::SleepMs(10);
+    }
+    LOG(LS_ERROR) << "Failed to shutdown usrsctp.";
+  }
+}
+
+DataMediaChannel* SctpDataEngine::CreateChannel(
+    DataChannelType data_channel_type) {
+  if (data_channel_type != DCT_SCTP) {
+    return NULL;
+  }
+  return new SctpDataMediaChannel(rtc::Thread::Current());
+}
+
+// static
+SctpDataMediaChannel* SctpDataEngine::GetChannelFromSocket(
+    struct socket* sock) {
+  struct sockaddr* addrs = nullptr;
+  int naddrs = usrsctp_getladdrs(sock, 0, &addrs);
+  if (naddrs <= 0 || addrs[0].sa_family != AF_CONN) {
+    return nullptr;
+  }
+  // usrsctp_getladdrs() returns the addresses bound to this socket, which
+  // contains the SctpDataMediaChannel* as sconn_addr.  Read the pointer,
+  // then free the list of addresses once we have the pointer.  We only open
+  // AF_CONN sockets, and they should all have the sconn_addr set to the
+  // pointer that created them, so [0] is as good as any other.
+  struct sockaddr_conn* sconn =
+      reinterpret_cast<struct sockaddr_conn*>(&addrs[0]);
+  SctpDataMediaChannel* channel =
+      reinterpret_cast<SctpDataMediaChannel*>(sconn->sconn_addr);
+  usrsctp_freeladdrs(addrs);
+
+  return channel;
+}
+
+// static
+int SctpDataEngine::SendThresholdCallback(struct socket* sock,
+                                          uint32_t sb_free) {
+  // Fired on our I/O thread.  SctpDataMediaChannel::OnPacketReceived() gets
+  // a packet containing acknowledgments, which goes into usrsctp_conninput,
+  // and then back here.
+  SctpDataMediaChannel* channel = GetChannelFromSocket(sock);
+  if (!channel) {
+    LOG(LS_ERROR) << "SendThresholdCallback: Failed to get channel for socket "
+                  << sock;
+    return 0;
+  }
+  channel->OnSendThresholdCallback();
+  return 0;
+}
+
+SctpDataMediaChannel::SctpDataMediaChannel(rtc::Thread* thread)
+    : worker_thread_(thread),
+      local_port_(kSctpDefaultPort),
+      remote_port_(kSctpDefaultPort),
+      sock_(NULL),
+      sending_(false),
+      receiving_(false),
+      debug_name_("SctpDataMediaChannel") {
+}
+
+SctpDataMediaChannel::~SctpDataMediaChannel() {
+  CloseSctpSocket();
+}
+
+void SctpDataMediaChannel::OnSendThresholdCallback() {
+  RTC_DCHECK(rtc::Thread::Current() == worker_thread_);
+  SignalReadyToSend(true);
+}
+
+sockaddr_conn SctpDataMediaChannel::GetSctpSockAddr(int port) {
+  sockaddr_conn sconn = {0};
+  sconn.sconn_family = AF_CONN;
+#ifdef HAVE_SCONN_LEN
+  sconn.sconn_len = sizeof(sockaddr_conn);
+#endif
+  // Note: conversion from int to uint16_t happens here.
+  sconn.sconn_port = rtc::HostToNetwork16(port);
+  sconn.sconn_addr = this;
+  return sconn;
+}
+
+bool SctpDataMediaChannel::OpenSctpSocket() {
+  if (sock_) {
+    LOG(LS_VERBOSE) << debug_name_
+                    << "->Ignoring attempt to re-create existing socket.";
+    return false;
+  }
+
+  // If kSendBufferSize isn't reflective of reality, we log an error, but we
+  // still have to do something reasonable here.  Look up what the buffer's
+  // real size is and set our threshold to something reasonable.
+  const static int kSendThreshold = usrsctp_sysctl_get_sctp_sendspace() / 2;
+
+  sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP,
+                         cricket::OnSctpInboundPacket,
+                         &SctpDataEngine::SendThresholdCallback,
+                         kSendThreshold, this);
+  if (!sock_) {
+    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket.";
+    return false;
+  }
+
+  // Make the socket non-blocking. Connect, close, shutdown etc will not block
+  // the thread waiting for the socket operation to complete.
+  if (usrsctp_set_non_blocking(sock_, 1) < 0) {
+    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking.";
+    return false;
+  }
+
+  // This ensures that the usrsctp close call deletes the association. This
+  // prevents usrsctp from calling OnSctpOutboundPacket with references to
+  // this class as the address.
+  linger linger_opt;
+  linger_opt.l_onoff = 1;
+  linger_opt.l_linger = 0;
+  if (usrsctp_setsockopt(sock_, SOL_SOCKET, SO_LINGER, &linger_opt,
+                         sizeof(linger_opt))) {
+    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SO_LINGER.";
+    return false;
+  }
+
+  // Enable stream ID resets.
+  struct sctp_assoc_value stream_rst;
+  stream_rst.assoc_id = SCTP_ALL_ASSOC;
+  stream_rst.assoc_value = 1;
+  if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET,
+                         &stream_rst, sizeof(stream_rst))) {
+    LOG_ERRNO(LS_ERROR) << debug_name_
+                        << "Failed to set SCTP_ENABLE_STREAM_RESET.";
+    return false;
+  }
+
+  // Nagle.
+  uint32_t nodelay = 1;
+  if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay,
+                         sizeof(nodelay))) {
+    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_NODELAY.";
+    return false;
+  }
+
+  // Disable MTU discovery
+  sctp_paddrparams params = {{0}};
+  params.spp_assoc_id = 0;
+  params.spp_flags = SPP_PMTUD_DISABLE;
+  params.spp_pathmtu = kSctpMtu;
+  if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &params,
+      sizeof(params))) {
+    LOG_ERRNO(LS_ERROR) << debug_name_
+                        << "Failed to set SCTP_PEER_ADDR_PARAMS.";
+    return false;
+  }
+
+  // Subscribe to SCTP event notifications.
+  int event_types[] = {SCTP_ASSOC_CHANGE,
+                       SCTP_PEER_ADDR_CHANGE,
+                       SCTP_SEND_FAILED_EVENT,
+                       SCTP_SENDER_DRY_EVENT,
+                       SCTP_STREAM_RESET_EVENT};
+  struct sctp_event event = {0};
+  event.se_assoc_id = SCTP_ALL_ASSOC;
+  event.se_on = 1;
+  for (size_t i = 0; i < arraysize(event_types); i++) {
+    event.se_type = event_types[i];
+    if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_EVENT, &event,
+                           sizeof(event)) < 0) {
+      LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_EVENT type: "
+                          << event.se_type;
+      return false;
+    }
+  }
+
+  // Register this class as an address for usrsctp. This is used by SCTP to
+  // direct the packets received (by the created socket) to this class.
+  usrsctp_register_address(this);
+  sending_ = true;
+  return true;
+}
+
+void SctpDataMediaChannel::CloseSctpSocket() {
+  sending_ = false;
+  if (sock_) {
+    // We assume that SO_LINGER option is set to close the association when
+    // close is called. This means that any pending packets in usrsctp will be
+    // discarded instead of being sent.
+    usrsctp_close(sock_);
+    sock_ = NULL;
+    usrsctp_deregister_address(this);
+  }
+}
+
+bool SctpDataMediaChannel::Connect() {
+  LOG(LS_VERBOSE) << debug_name_ << "->Connect().";
+
+  // If we already have a socket connection, just return.
+  if (sock_) {
+    LOG(LS_WARNING) << debug_name_ << "->Connect(): Ignored as socket "
+                                      "is already established.";
+    return true;
+  }
+
+  // If no socket (it was closed) try to start it again. This can happen when
+  // the socket we are connecting to closes, does an sctp shutdown handshake,
+  // or behaves unexpectedly causing us to perform a CloseSctpSocket.
+  if (!sock_ && !OpenSctpSocket()) {
+    return false;
+  }
+
+  // Note: conversion from int to uint16_t happens on assignment.
+  sockaddr_conn local_sconn = GetSctpSockAddr(local_port_);
+  if (usrsctp_bind(sock_, reinterpret_cast<sockaddr *>(&local_sconn),
+                   sizeof(local_sconn)) < 0) {
+    LOG_ERRNO(LS_ERROR) << debug_name_ << "->Connect(): "
+                        << ("Failed usrsctp_bind");
+    CloseSctpSocket();
+    return false;
+  }
+
+  // Note: conversion from int to uint16_t happens on assignment.
+  sockaddr_conn remote_sconn = GetSctpSockAddr(remote_port_);
+  int connect_result = usrsctp_connect(
+      sock_, reinterpret_cast<sockaddr *>(&remote_sconn), sizeof(remote_sconn));
+  if (connect_result < 0 && errno != SCTP_EINPROGRESS) {
+    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed usrsctp_connect. got errno="
+                        << errno << ", but wanted " << SCTP_EINPROGRESS;
+    CloseSctpSocket();
+    return false;
+  }
+  return true;
+}
+
+void SctpDataMediaChannel::Disconnect() {
+  // TODO(ldixon): Consider calling |usrsctp_shutdown(sock_, ...)| to do a
+  // shutdown handshake and remove the association.
+  CloseSctpSocket();
+}
+
+bool SctpDataMediaChannel::SetSend(bool send) {
+  if (!sending_ && send) {
+    return Connect();
+  }
+  if (sending_ && !send) {
+    Disconnect();
+  }
+  return true;
+}
+
+bool SctpDataMediaChannel::SetReceive(bool receive) {
+  receiving_ = receive;
+  return true;
+}
+
+bool SctpDataMediaChannel::SetSendParameters(const DataSendParameters& params) {
+  return SetSendCodecs(params.codecs);
+}
+
+bool SctpDataMediaChannel::SetRecvParameters(const DataRecvParameters& params) {
+  return SetRecvCodecs(params.codecs);
+}
+
+bool SctpDataMediaChannel::AddSendStream(const StreamParams& stream) {
+  return AddStream(stream);
+}
+
+bool SctpDataMediaChannel::RemoveSendStream(uint32_t ssrc) {
+  return ResetStream(ssrc);
+}
+
+bool SctpDataMediaChannel::AddRecvStream(const StreamParams& stream) {
+  // SCTP DataChannels are always bi-directional and calling AddSendStream will
+  // enable both sending and receiving on the stream. So AddRecvStream is a
+  // no-op.
+  return true;
+}
+
+bool SctpDataMediaChannel::RemoveRecvStream(uint32_t ssrc) {
+  // SCTP DataChannels are always bi-directional and calling RemoveSendStream
+  // will disable both sending and receiving on the stream. So RemoveRecvStream
+  // is a no-op.
+  return true;
+}
+
+bool SctpDataMediaChannel::SendData(
+    const SendDataParams& params,
+    const rtc::Buffer& payload,
+    SendDataResult* result) {
+  if (result) {
+    // Preset |result| to assume an error.  If SendData succeeds, we'll
+    // overwrite |*result| once more at the end.
+    *result = SDR_ERROR;
+  }
+
+  if (!sending_) {
+    LOG(LS_WARNING) << debug_name_ << "->SendData(...): "
+                    << "Not sending packet with ssrc=" << params.ssrc
+                    << " len=" << payload.size() << " before SetSend(true).";
+    return false;
+  }
+
+  if (params.type != cricket::DMT_CONTROL &&
+      open_streams_.find(params.ssrc) == open_streams_.end()) {
+    LOG(LS_WARNING) << debug_name_ << "->SendData(...): "
+                    << "Not sending data because ssrc is unknown: "
+                    << params.ssrc;
+    return false;
+  }
+
+  //
+  // Send data using SCTP.
+  ssize_t send_res = 0;  // result from usrsctp_sendv.
+  struct sctp_sendv_spa spa = {0};
+  spa.sendv_flags |= SCTP_SEND_SNDINFO_VALID;
+  spa.sendv_sndinfo.snd_sid = params.ssrc;
+  spa.sendv_sndinfo.snd_ppid = rtc::HostToNetwork32(
+      GetPpid(params.type));
+
+  // Ordered implies reliable.
+  if (!params.ordered) {
+    spa.sendv_sndinfo.snd_flags |= SCTP_UNORDERED;
+    if (params.max_rtx_count >= 0 || params.max_rtx_ms == 0) {
+      spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
+      spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
+      spa.sendv_prinfo.pr_value = params.max_rtx_count;
+    } else {
+      spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
+      spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL;
+      spa.sendv_prinfo.pr_value = params.max_rtx_ms;
+    }
+  }
+
+  // We don't fragment.
+  send_res = usrsctp_sendv(
+      sock_, payload.data(), static_cast<size_t>(payload.size()), NULL, 0, &spa,
+      rtc::checked_cast<socklen_t>(sizeof(spa)), SCTP_SENDV_SPA, 0);
+  if (send_res < 0) {
+    if (errno == SCTP_EWOULDBLOCK) {
+      *result = SDR_BLOCK;
+      LOG(LS_INFO) << debug_name_ << "->SendData(...): EWOULDBLOCK returned";
+    } else {
+      LOG_ERRNO(LS_ERROR) << "ERROR:" << debug_name_
+                          << "->SendData(...): "
+                          << " usrsctp_sendv: ";
+    }
+    return false;
+  }
+  if (result) {
+    // Only way out now is success.
+    *result = SDR_SUCCESS;
+  }
+  return true;
+}
+
+// Called by network interface when a packet has been received.
+void SctpDataMediaChannel::OnPacketReceived(
+    rtc::Buffer* packet, const rtc::PacketTime& packet_time) {
+  RTC_DCHECK(rtc::Thread::Current() == worker_thread_);
+  LOG(LS_VERBOSE) << debug_name_ << "->OnPacketReceived(...): "
+                  << " length=" << packet->size() << ", sending: " << sending_;
+  // Only give receiving packets to usrsctp after if connected. This enables two
+  // peers to each make a connect call, but for them not to receive an INIT
+  // packet before they have called connect; least the last receiver of the INIT
+  // packet will have called connect, and a connection will be established.
+  if (sending_) {
+    // Pass received packet to SCTP stack. Once processed by usrsctp, the data
+    // will be will be given to the global OnSctpInboundData, and then,
+    // marshalled by a Post and handled with OnMessage.
+    VerboseLogPacket(packet->data(), packet->size(), SCTP_DUMP_INBOUND);
+    usrsctp_conninput(this, packet->data(), packet->size(), 0);
+  } else {
+    // TODO(ldixon): Consider caching the packet for very slightly better
+    // reliability.
+  }
+}
+
+void SctpDataMediaChannel::OnInboundPacketFromSctpToChannel(
+    SctpInboundPacket* packet) {
+  LOG(LS_VERBOSE) << debug_name_ << "->OnInboundPacketFromSctpToChannel(...): "
+                  << "Received SCTP data:"
+                  << " ssrc=" << packet->params.ssrc
+                  << " notification: " << (packet->flags & MSG_NOTIFICATION)
+                  << " length=" << packet->buffer.size();
+  // Sending a packet with data == NULL (no data) is SCTPs "close the
+  // connection" message. This sets sock_ = NULL;
+  if (!packet->buffer.size() || !packet->buffer.data()) {
+    LOG(LS_INFO) << debug_name_ << "->OnInboundPacketFromSctpToChannel(...): "
+                                   "No data, closing.";
+    return;
+  }
+  if (packet->flags & MSG_NOTIFICATION) {
+    OnNotificationFromSctp(&packet->buffer);
+  } else {
+    OnDataFromSctpToChannel(packet->params, &packet->buffer);
+  }
+}
+
+void SctpDataMediaChannel::OnDataFromSctpToChannel(
+    const ReceiveDataParams& params, rtc::Buffer* buffer) {
+  if (receiving_) {
+    LOG(LS_VERBOSE) << debug_name_ << "->OnDataFromSctpToChannel(...): "
+                    << "Posting with length: " << buffer->size()
+                    << " on stream " << params.ssrc;
+    // Reports all received messages to upper layers, no matter whether the sid
+    // is known.
+    SignalDataReceived(params, buffer->data<char>(), buffer->size());
+  } else {
+    LOG(LS_WARNING) << debug_name_ << "->OnDataFromSctpToChannel(...): "
+                    << "Not receiving packet with sid=" << params.ssrc
+                    << " len=" << buffer->size() << " before SetReceive(true).";
+  }
+}
+
+bool SctpDataMediaChannel::AddStream(const StreamParams& stream) {
+  if (!stream.has_ssrcs()) {
+    return false;
+  }
+
+  const uint32_t ssrc = stream.first_ssrc();
+  if (ssrc >= cricket::kMaxSctpSid) {
+    LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
+                    << "Not adding data stream '" << stream.id
+                    << "' with ssrc=" << ssrc
+                    << " because stream ssrc is too high.";
+    return false;
+  } else if (open_streams_.find(ssrc) != open_streams_.end()) {
+    LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
+                    << "Not adding data stream '" << stream.id
+                    << "' with ssrc=" << ssrc
+                    << " because stream is already open.";
+    return false;
+  } else if (queued_reset_streams_.find(ssrc) != queued_reset_streams_.end()
+             || sent_reset_streams_.find(ssrc) != sent_reset_streams_.end()) {
+    LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): "
+                    << "Not adding data stream '" << stream.id
+                    << "' with ssrc=" << ssrc
+                    << " because stream is still closing.";
+    return false;
+  }
+
+  open_streams_.insert(ssrc);
+  return true;
+}
+
+bool SctpDataMediaChannel::ResetStream(uint32_t ssrc) {
+  // We typically get this called twice for the same stream, once each for
+  // Send and Recv.
+  StreamSet::iterator found = open_streams_.find(ssrc);
+
+  if (found == open_streams_.end()) {
+    LOG(LS_VERBOSE) << debug_name_ << "->ResetStream(" << ssrc << "): "
+                    << "stream not found.";
+    return false;
+  } else {
+    LOG(LS_VERBOSE) << debug_name_ << "->ResetStream(" << ssrc << "): "
+                    << "Removing and queuing RE-CONFIG chunk.";
+    open_streams_.erase(found);
+  }
+
+  // SCTP won't let you have more than one stream reset pending at a time, but
+  // you can close multiple streams in a single reset.  So, we keep an internal
+  // queue of streams-to-reset, and send them as one reset message in
+  // SendQueuedStreamResets().
+  queued_reset_streams_.insert(ssrc);
+
+  // Signal our stream-reset logic that it should try to send now, if it can.
+  SendQueuedStreamResets();
+
+  // The stream will actually get removed when we get the acknowledgment.
+  return true;
+}
+
+void SctpDataMediaChannel::OnNotificationFromSctp(rtc::Buffer* buffer) {
+  const sctp_notification& notification =
+      reinterpret_cast<const sctp_notification&>(*buffer->data());
+  ASSERT(notification.sn_header.sn_length == buffer->size());
+
+  // TODO(ldixon): handle notifications appropriately.
+  switch (notification.sn_header.sn_type) {
+    case SCTP_ASSOC_CHANGE:
+      LOG(LS_VERBOSE) << "SCTP_ASSOC_CHANGE";
+      OnNotificationAssocChange(notification.sn_assoc_change);
+      break;
+    case SCTP_REMOTE_ERROR:
+      LOG(LS_INFO) << "SCTP_REMOTE_ERROR";
+      break;
+    case SCTP_SHUTDOWN_EVENT:
+      LOG(LS_INFO) << "SCTP_SHUTDOWN_EVENT";
+      break;
+    case SCTP_ADAPTATION_INDICATION:
+      LOG(LS_INFO) << "SCTP_ADAPTATION_INDICATION";
+      break;
+    case SCTP_PARTIAL_DELIVERY_EVENT:
+      LOG(LS_INFO) << "SCTP_PARTIAL_DELIVERY_EVENT";
+      break;
+    case SCTP_AUTHENTICATION_EVENT:
+      LOG(LS_INFO) << "SCTP_AUTHENTICATION_EVENT";
+      break;
+    case SCTP_SENDER_DRY_EVENT:
+      LOG(LS_VERBOSE) << "SCTP_SENDER_DRY_EVENT";
+      SignalReadyToSend(true);
+      break;
+    // TODO(ldixon): Unblock after congestion.
+    case SCTP_NOTIFICATIONS_STOPPED_EVENT:
+      LOG(LS_INFO) << "SCTP_NOTIFICATIONS_STOPPED_EVENT";
+      break;
+    case SCTP_SEND_FAILED_EVENT:
+      LOG(LS_INFO) << "SCTP_SEND_FAILED_EVENT";
+      break;
+    case SCTP_STREAM_RESET_EVENT:
+      OnStreamResetEvent(&notification.sn_strreset_event);
+      break;
+    case SCTP_ASSOC_RESET_EVENT:
+      LOG(LS_INFO) << "SCTP_ASSOC_RESET_EVENT";
+      break;
+    case SCTP_STREAM_CHANGE_EVENT:
+      LOG(LS_INFO) << "SCTP_STREAM_CHANGE_EVENT";
+      // An acknowledgment we get after our stream resets have gone through,
+      // if they've failed.  We log the message, but don't react -- we don't
+      // keep around the last-transmitted set of SSIDs we wanted to close for
+      // error recovery.  It doesn't seem likely to occur, and if so, likely
+      // harmless within the lifetime of a single SCTP association.
+      break;
+    default:
+      LOG(LS_WARNING) << "Unknown SCTP event: "
+                      << notification.sn_header.sn_type;
+      break;
+  }
+}
+
+void SctpDataMediaChannel::OnNotificationAssocChange(
+    const sctp_assoc_change& change) {
+  switch (change.sac_state) {
+    case SCTP_COMM_UP:
+      LOG(LS_VERBOSE) << "Association change SCTP_COMM_UP";
+      break;
+    case SCTP_COMM_LOST:
+      LOG(LS_INFO) << "Association change SCTP_COMM_LOST";
+      break;
+    case SCTP_RESTART:
+      LOG(LS_INFO) << "Association change SCTP_RESTART";
+      break;
+    case SCTP_SHUTDOWN_COMP:
+      LOG(LS_INFO) << "Association change SCTP_SHUTDOWN_COMP";
+      break;
+    case SCTP_CANT_STR_ASSOC:
+      LOG(LS_INFO) << "Association change SCTP_CANT_STR_ASSOC";
+      break;
+    default:
+      LOG(LS_INFO) << "Association change UNKNOWN";
+      break;
+  }
+}
+
+void SctpDataMediaChannel::OnStreamResetEvent(
+    const struct sctp_stream_reset_event* evt) {
+  // A stream reset always involves two RE-CONFIG chunks for us -- we always
+  // simultaneously reset a sid's sequence number in both directions.  The
+  // requesting side transmits a RE-CONFIG chunk and waits for the peer to send
+  // one back.  Both sides get this SCTP_STREAM_RESET_EVENT when they receive
+  // RE-CONFIGs.
+  const int num_ssrcs = (evt->strreset_length - sizeof(*evt)) /
+      sizeof(evt->strreset_stream_list[0]);
+  LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
+                  << "): Flags = 0x"
+                  << std::hex << evt->strreset_flags << " ("
+                  << ListFlags(evt->strreset_flags) << ")";
+  LOG(LS_VERBOSE) << "Assoc = " << evt->strreset_assoc_id << ", Streams = ["
+                  << ListArray(evt->strreset_stream_list, num_ssrcs)
+                  << "], Open: ["
+                  << ListStreams(open_streams_) << "], Q'd: ["
+                  << ListStreams(queued_reset_streams_) << "], Sent: ["
+                  << ListStreams(sent_reset_streams_) << "]";
+
+  // If both sides try to reset some streams at the same time (even if they're
+  // disjoint sets), we can get reset failures.
+  if (evt->strreset_flags & SCTP_STREAM_RESET_FAILED) {
+    // OK, just try again.  The stream IDs sent over when the RESET_FAILED flag
+    // is set seem to be garbage values.  Ignore them.
+    queued_reset_streams_.insert(
+        sent_reset_streams_.begin(),
+        sent_reset_streams_.end());
+    sent_reset_streams_.clear();
+
+  } else if (evt->strreset_flags & SCTP_STREAM_RESET_INCOMING_SSN) {
+    // Each side gets an event for each direction of a stream.  That is,
+    // closing sid k will make each side receive INCOMING and OUTGOING reset
+    // events for k.  As per RFC6525, Section 5, paragraph 2, each side will
+    // get an INCOMING event first.
+    for (int i = 0; i < num_ssrcs; i++) {
+      const int stream_id = evt->strreset_stream_list[i];
+
+      // See if this stream ID was closed by our peer or ourselves.
+      StreamSet::iterator it = sent_reset_streams_.find(stream_id);
+
+      // The reset was requested locally.
+      if (it != sent_reset_streams_.end()) {
+        LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
+                        << "): local sid " << stream_id << " acknowledged.";
+        sent_reset_streams_.erase(it);
+
+      } else if ((it = open_streams_.find(stream_id))
+                 != open_streams_.end()) {
+        // The peer requested the reset.
+        LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
+                        << "): closing sid " << stream_id;
+        open_streams_.erase(it);
+        SignalStreamClosedRemotely(stream_id);
+
+      } else if ((it = queued_reset_streams_.find(stream_id))
+                 != queued_reset_streams_.end()) {
+        // The peer requested the reset, but there was a local reset
+        // queued.
+        LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
+                        << "): double-sided close for sid " << stream_id;
+        // Both sides want the stream closed, and the peer got to send the
+        // RE-CONFIG first.  Treat it like the local Remove(Send|Recv)Stream
+        // finished quickly.
+        queued_reset_streams_.erase(it);
+
+      } else {
+        // This stream is unknown.  Sometimes this can be from an
+        // RESET_FAILED-related retransmit.
+        LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
+                        << "): Unknown sid " << stream_id;
+      }
+    }
+  }
+
+  // Always try to send the queued RESET because this call indicates that the
+  // last local RESET or remote RESET has made some progress.
+  SendQueuedStreamResets();
+}
+
+// Puts the specified |param| from the codec identified by |id| into |dest|
+// and returns true.  Or returns false if it wasn't there, leaving |dest|
+// untouched.
+static bool GetCodecIntParameter(const std::vector<DataCodec>& codecs,
+                                 int id, const std::string& name,
+                                 const std::string& param, int* dest) {
+  std::string value;
+  Codec match_pattern;
+  match_pattern.id = id;
+  match_pattern.name = name;
+  for (size_t i = 0; i < codecs.size(); ++i) {
+    if (codecs[i].Matches(match_pattern)) {
+      if (codecs[i].GetParam(param, &value)) {
+        *dest = rtc::FromString<int>(value);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool SctpDataMediaChannel::SetSendCodecs(const std::vector<DataCodec>& codecs) {
+  return GetCodecIntParameter(
+      codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort,
+      &remote_port_);
+}
+
+bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) {
+  return GetCodecIntParameter(
+      codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort,
+      &local_port_);
+}
+
+void SctpDataMediaChannel::OnPacketFromSctpToNetwork(
+    rtc::Buffer* buffer) {
+  // usrsctp seems to interpret the MTU we give it strangely -- it seems to
+  // give us back packets bigger than that MTU, if only by a fixed amount.
+  // This is that amount that we've observed.
+  const int kSctpOverhead = 76;
+  if (buffer->size() > (kSctpOverhead + kSctpMtu)) {
+    LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): "
+                  << "SCTP seems to have made a packet that is bigger "
+                  << "than its official MTU: " << buffer->size()
+                  << " vs max of " << kSctpMtu
+                  << " even after adding " << kSctpOverhead
+                  << " extra SCTP overhead";
+  }
+  MediaChannel::SendPacket(buffer, rtc::PacketOptions());
+}
+
+bool SctpDataMediaChannel::SendQueuedStreamResets() {
+  if (!sent_reset_streams_.empty() || queued_reset_streams_.empty())
+    return true;
+
+  LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending ["
+                  << ListStreams(queued_reset_streams_) << "], Open: ["
+                  << ListStreams(open_streams_) << "], Sent: ["
+                  << ListStreams(sent_reset_streams_) << "]";
+
+  const size_t num_streams = queued_reset_streams_.size();
+  const size_t num_bytes =
+      sizeof(struct sctp_reset_streams) + (num_streams * sizeof(uint16_t));
+
+  std::vector<uint8_t> reset_stream_buf(num_bytes, 0);
+  struct sctp_reset_streams* resetp = reinterpret_cast<sctp_reset_streams*>(
+      &reset_stream_buf[0]);
+  resetp->srs_assoc_id = SCTP_ALL_ASSOC;
+  resetp->srs_flags = SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_OUTGOING;
+  resetp->srs_number_streams = rtc::checked_cast<uint16_t>(num_streams);
+  int result_idx = 0;
+  for (StreamSet::iterator it = queued_reset_streams_.begin();
+       it != queued_reset_streams_.end(); ++it) {
+    resetp->srs_stream_list[result_idx++] = *it;
+  }
+
+  int ret = usrsctp_setsockopt(
+      sock_, IPPROTO_SCTP, SCTP_RESET_STREAMS, resetp,
+      rtc::checked_cast<socklen_t>(reset_stream_buf.size()));
+  if (ret < 0) {
+    LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to send a stream reset for "
+                        << num_streams << " streams";
+    return false;
+  }
+
+  // sent_reset_streams_ is empty, and all the queued_reset_streams_ go into
+  // it now.
+  queued_reset_streams_.swap(sent_reset_streams_);
+  return true;
+}
+
+void SctpDataMediaChannel::OnMessage(rtc::Message* msg) {
+  switch (msg->message_id) {
+    case MSG_SCTPINBOUNDPACKET: {
+      rtc::scoped_ptr<InboundPacketMessage> pdata(
+          static_cast<InboundPacketMessage*>(msg->pdata));
+      OnInboundPacketFromSctpToChannel(pdata->data().get());
+      break;
+    }
+    case MSG_SCTPOUTBOUNDPACKET: {
+      rtc::scoped_ptr<OutboundPacketMessage> pdata(
+          static_cast<OutboundPacketMessage*>(msg->pdata));
+      OnPacketFromSctpToNetwork(pdata->data().get());
+      break;
+    }
+  }
+}
+}  // namespace cricket