Bug 1455647 - Part 4: Make a place to live for context about media packets, to fix packet dump hooks. r+drno r=drno
authorByron Campen [:bwc] <docfaraday@gmail.com>
Wed, 09 May 2018 17:13:35 -0500
changeset 422117 8ab6afabc78cd909ff90ba74c1eab098985f83ef
parent 422116 cbac90b0c34d8362ea4542ae5795a4e48f71aee4
child 422118 2091c74ecd29d90d96e4302ae0467eb3bed7973c
child 422288 95e129c56b0fa43caf9ee4c507f3d6dda6ab99e4
push id34120
push usernerli@mozilla.com
push dateSun, 10 Jun 2018 21:36:56 +0000
treeherdermozilla-central@8ab6afabc78c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdrno
bugs1455647
milestone62.0a1
first release with
nightly linux32
8ab6afabc78c / 62.0a1 / 20180610220159 / files
nightly linux64
8ab6afabc78c / 62.0a1 / 20180610220159 / files
nightly mac
8ab6afabc78c / 62.0a1 / 20180610220159 / files
nightly win32
8ab6afabc78c / 62.0a1 / 20180610220159 / files
nightly win64
8ab6afabc78c / 62.0a1 / 20180610220159 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1455647 - Part 4: Make a place to live for context about media packets, to fix packet dump hooks. r+drno r=drno MozReview-Commit-ID: 1HMF93mLa7r
media/mtransport/build/moz.build
media/mtransport/common.build
media/mtransport/databuffer.h
media/mtransport/mediapacket.cpp
media/mtransport/mediapacket.h
media/mtransport/nr_socket_prsock.cpp
media/mtransport/nr_socket_prsock.h
media/mtransport/test/buffered_stun_socket_unittest.cpp
media/mtransport/test/dummysocket.h
media/mtransport/test/proxy_tunnel_socket_unittest.cpp
media/mtransport/test/sctp_unittest.cpp
media/mtransport/test/stunserver.cpp
media/mtransport/test/transport_unittests.cpp
media/mtransport/test_nr_socket.h
media/mtransport/transportlayer.h
media/mtransport/transportlayerdtls.cpp
media/mtransport/transportlayerdtls.h
media/mtransport/transportlayerice.cpp
media/mtransport/transportlayerice.h
media/mtransport/transportlayerlog.cpp
media/mtransport/transportlayerlog.h
media/mtransport/transportlayerloopback.cpp
media/mtransport/transportlayerloopback.h
media/mtransport/transportlayersrtp.cpp
media/mtransport/transportlayersrtp.h
media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
media/webrtc/signaling/src/mediapipeline/RtpLogger.cpp
media/webrtc/signaling/src/mediapipeline/RtpLogger.h
media/webrtc/signaling/src/mediapipeline/TransportLayerPacketDumper.cpp
media/webrtc/signaling/src/mediapipeline/TransportLayerPacketDumper.h
media/webrtc/signaling/src/mediapipeline/moz.build
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
netwerk/sctp/datachannel/DataChannel.cpp
netwerk/sctp/datachannel/DataChannel.h
--- a/media/mtransport/build/moz.build
+++ b/media/mtransport/build/moz.build
@@ -4,16 +4,17 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 include("/ipc/chromium/chromium-config.mozbuild")
 
 EXPORTS.mtransport += [
     '../dtlsidentity.h',
     '../m_cpp_utils.h',
+    '../mediapacket.h',
     '../nricectx.h',
     '../nricemediastream.h',
     '../nriceresolverfake.h',
     '../nricestunaddr.h',
     '../rlogconnector.h',
     '../runnable_utils.h',
     '../sigslot.h',
     '../simpletokenbucket.h',
--- a/media/mtransport/common.build
+++ b/media/mtransport/common.build
@@ -1,16 +1,17 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 mtransport_lcppsrcs = [
     'dtlsidentity.cpp',
+    'mediapacket.cpp',
     'nr_socket_prsock.cpp',
     'nr_timer.cpp',
     'nricectx.cpp',
     'nricectxhandler.cpp',
     'nricemediastream.cpp',
     'nriceresolver.cpp',
     'nriceresolverfake.cpp',
     'nricestunaddr.cpp',
deleted file mode 100644
--- a/media/mtransport/databuffer.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// Original author: ekr@rtfm.com
-
-#ifndef databuffer_h__
-#define databuffer_h__
-#include <algorithm>
-#include <mozilla/UniquePtr.h>
-#include <m_cpp_utils.h>
-#include <nsISupportsImpl.h>
-
-namespace mozilla {
-
-class DataBuffer {
- public:
-  DataBuffer() : data_(nullptr), len_(0), capacity_(0) {}
-  DataBuffer(const uint8_t *data, size_t len) {
-    Assign(data, len, len);
-  }
-  DataBuffer(const uint8_t *data, size_t len, size_t capacity) {
-    Assign(data, len, capacity);
-  }
-
-  // to ensure extra space for expansion
-  void Assign(const uint8_t *data, size_t len, size_t capacity) {
-    MOZ_RELEASE_ASSERT(len <= capacity);
-    Allocate(capacity); // sets len_ = capacity
-    memcpy(static_cast<void *>(data_.get()),
-           static_cast<const void *>(data), len);
-    len_ = len;
-  }
-
-  void Allocate(size_t capacity) {
-    data_.reset(new uint8_t[capacity ? capacity : 1]);  // Don't depend on new [0].
-    len_ = capacity_ = capacity;
-  }
-
-  void EnsureCapacity(size_t capacity) {
-    if (capacity_ < capacity) {
-      uint8_t *new_data = new uint8_t[ capacity ? capacity : 1];
-      memcpy(static_cast<void *>(new_data),
-             static_cast<const void *>(data_.get()), len_);
-      data_.reset(new_data); // after copying!  Deletes old data
-      capacity_ = capacity;
-    }
-  }
-
-  // used when something writes to the buffer (having checked
-  // capacity() or used EnsureCapacity()) and increased the length.
-  void SetLength(size_t len) {
-    MOZ_RELEASE_ASSERT(len <= capacity_);
-    len_ = len;
-  }
-
-  const uint8_t *data() const { return data_.get(); }
-  uint8_t *data() { return data_.get(); }
-  size_t len() const { return len_; }
-  size_t capacity() const { return capacity_; }
-
-private:
-  UniquePtr<uint8_t[]> data_;
-  size_t len_;
-  size_t capacity_;
-
-  DISALLOW_COPY_ASSIGN(DataBuffer);
-};
-
-}
-
-#endif
new file mode 100644
--- /dev/null
+++ b/media/mtransport/mediapacket.cpp
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mediapacket.h"
+
+#include <cstring>
+
+namespace mozilla {
+
+void
+MediaPacket::Copy(const uint8_t* data, size_t len, size_t capacity)
+{
+  if (capacity < len) {
+    capacity = len;
+  }
+  data_.reset(new uint8_t[capacity]);
+  len_ = len;
+  capacity_ = capacity;
+  memcpy(data_.get(), data, len);
+}
+
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/mediapacket.h
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mediapacket_h__
+#define mediapacket_h__
+
+#include <cstddef>
+#include <cstdint>
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Maybe.h"
+
+namespace mozilla {
+
+// TODO: It might be worthwhile to teach this class how to "borrow" a buffer.
+// That would make it easier to misuse, however, so maybe not worth it.
+class MediaPacket {
+  public:
+    MediaPacket() = default;
+    MediaPacket(MediaPacket&& orig) = default;
+
+    // Takes ownership of the passed-in data
+    void Take(UniquePtr<uint8_t[]>&& data, size_t len, size_t capacity=0)
+    {
+      data_ = std::move(data);
+      len_ = len;
+      if (capacity < len) {
+        capacity = len;
+      }
+      capacity_ = capacity;
+    }
+
+    void Reset()
+    {
+      data_.reset();
+      len_ = 0;
+      capacity_ = 0;
+    }
+
+    // Copies the passed-in data
+    void Copy(const uint8_t* data, size_t len, size_t capacity=0);
+
+    uint8_t* data() const
+    {
+      return data_.get();
+    }
+
+    size_t len() const
+    {
+      return len_;
+    }
+
+    void SetLength(size_t length)
+    {
+      len_ = length;
+    }
+
+    size_t capacity() const
+    {
+      return capacity_;
+    }
+
+    Maybe<size_t>& sdp_level()
+    {
+      return sdp_level_;
+    }
+
+    void CopyDataToEncrypted()
+    {
+      encrypted_data_ = std::move(data_);
+      encrypted_len_ = len_;
+      Copy(encrypted_data_.get(), len_);
+    }
+
+    const uint8_t* encrypted_data() const
+    {
+      return encrypted_data_.get();
+    }
+
+    size_t encrypted_len() const
+    {
+      return encrypted_len_;
+    }
+
+    enum Type {
+      UNCLASSIFIED,
+      RTP,
+      RTCP,
+      SCTP
+    };
+
+    void SetType(Type type)
+    {
+      type_ = type;
+    }
+
+    Type type() const
+    {
+      return type_;
+    }
+
+  private:
+    UniquePtr<uint8_t[]> data_;
+    size_t len_ = 0;
+    size_t capacity_ = 0;
+    // Encrypted form of the data, if there is one.
+    UniquePtr<uint8_t[]> encrypted_data_;
+    size_t encrypted_len_ = 0;
+    // SDP level that this packet belongs to, if known.
+    Maybe<size_t> sdp_level_;
+    Type type_ = UNCLASSIFIED;
+};
+}
+#endif // mediapacket_h__
+
--- a/media/mtransport/nr_socket_prsock.cpp
+++ b/media/mtransport/nr_socket_prsock.cpp
@@ -1180,17 +1180,18 @@ NS_IMETHODIMP NrUdpSocketIpc::CallListen
     // Use PR_IpAddrNull to avoid address being reset to 0.
     if (PR_SUCCESS != PR_SetNetAddr(PR_IpAddrNull, addr.raw.family, port, &addr)) {
       err_ = true;
       MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
       return NS_OK;
     }
   }
 
-  nsAutoPtr<DataBuffer> buf(new DataBuffer(data, data_length));
+  nsAutoPtr<MediaPacket> buf(new MediaPacket);
+  buf->Copy(data, data_length);
   RefPtr<nr_udp_message> msg(new nr_udp_message(addr, buf));
 
   RUN_ON_THREAD(sts_thread_,
                 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
                                       &NrUdpSocketIpc::recv_callback_s,
                                       msg),
                 NS_DISPATCH_NORMAL);
   return NS_OK;
@@ -1371,17 +1372,18 @@ int NrUdpSocketIpc::sendto(const void *m
   if ((r=nr_transport_addr_to_netaddr(to, &addr))) {
     return r;
   }
 
   if (nr_is_stun_request_message((UCHAR*)msg, len) && ShouldDrop(len)) {
     return R_WOULDBLOCK;
   }
 
-  nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t*>(msg), len));
+  nsAutoPtr<MediaPacket> buf(new MediaPacket);
+  buf->Copy(static_cast<const uint8_t*>(msg), len);
 
   RUN_ON_THREAD(io_thread_,
                 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this),
                                       &NrUdpSocketIpc::sendto_i,
                                       addr, buf),
                 NS_DISPATCH_NORMAL);
   return 0;
 }
@@ -1589,17 +1591,17 @@ void NrUdpSocketIpc::connect_i(const nsA
     err_ = true;
     MOZ_ASSERT(false, "Failed to connect UDP socket");
     mon.NotifyAll();
     return;
   }
 }
 
 
-void NrUdpSocketIpc::sendto_i(const net::NetAddr &addr, nsAutoPtr<DataBuffer> buf) {
+void NrUdpSocketIpc::sendto_i(const net::NetAddr &addr, nsAutoPtr<MediaPacket> buf) {
   ASSERT_ON_THREAD(io_thread_);
 
   ReentrantMonitorAutoEnter mon(monitor_);
 
   if (!socket_child_) {
     MOZ_ASSERT(false);
     err_ = true;
     return;
@@ -1746,17 +1748,18 @@ NS_IMETHODIMP NrTcpSocketIpc::UpdateBuff
   return NS_OK;
 }
 
 NS_IMETHODIMP NrTcpSocketIpc::FireDataArrayEvent(const nsAString& aType,
                                                  const InfallibleTArray<uint8_t>& buffer) {
   // Called when we received data.
   uint8_t *buf = const_cast<uint8_t*>(buffer.Elements());
 
-  nsAutoPtr<DataBuffer> data_buf(new DataBuffer(buf, buffer.Length()));
+  nsAutoPtr<MediaPacket> data_buf(new MediaPacket);
+  data_buf->Copy(buf, buffer.Length());
   RefPtr<nr_tcp_message> msg = new nr_tcp_message(data_buf);
 
   RUN_ON_THREAD(sts_thread_,
                 mozilla::WrapRunnable(RefPtr<NrTcpSocketIpc>(this),
                                       &NrTcpSocketIpc::recv_message_s,
                                       msg),
                 NS_DISPATCH_NORMAL);
   return NS_OK;
--- a/media/mtransport/nr_socket_prsock.h
+++ b/media/mtransport/nr_socket_prsock.h
@@ -57,17 +57,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 #include "nsISocketTransportService.h"
 #include "nsXPCOM.h"
 #include "nsIEventTarget.h"
 #include "nsIUDPSocketChild.h"
 #include "nsProxyRelease.h"
 #include "nsThreadUtils.h"
 
 #include "nsITCPSocketCallback.h"
-#include "databuffer.h"
+#include "mediapacket.h"
 #include "m_cpp_utils.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/ClearOnShutdown.h"
 
 // Stub declaration for nICEr type
 typedef struct nr_socket_vtbl_ nr_socket_vtbl;
@@ -192,24 +192,24 @@ protected:
 
   DISALLOW_COPY_ASSIGN(NrSocket);
 
   PRFileDesc *fd_;
   nsCOMPtr<nsIEventTarget> ststhread_;
 };
 
 struct nr_udp_message {
-  nr_udp_message(const PRNetAddr &from, nsAutoPtr<DataBuffer> &data)
+  nr_udp_message(const PRNetAddr &from, nsAutoPtr<MediaPacket> &data)
       : from(from), data(data) {
   }
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nr_udp_message);
 
   PRNetAddr from;
-  nsAutoPtr<DataBuffer> data;
+  nsAutoPtr<MediaPacket> data;
 
 private:
   ~nr_udp_message() {}
   DISALLOW_COPY_ASSIGN(nr_udp_message);
 };
 
 class NrSocketIpc : public NrSocketBase {
 public:
@@ -272,17 +272,17 @@ private:
 
   DISALLOW_COPY_ASSIGN(NrUdpSocketIpc);
 
   nsresult SetAddress();  // Set the local address from parent info.
 
   // Main or private thread executors of the NrSocketBase APIs
   void create_i(const nsACString &host, const uint16_t port);
   void connect_i(const nsACString &host, const uint16_t port);
-  void sendto_i(const net::NetAddr &addr, nsAutoPtr<DataBuffer> buf);
+  void sendto_i(const net::NetAddr &addr, nsAutoPtr<MediaPacket> buf);
   void close_i();
 #if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API)
   static void destroy_i(nsIUDPSocketChild* aChild,
                         nsCOMPtr<nsIEventTarget>& aStsThread);
 #endif
   // STS thread executor
   void recv_callback_s(RefPtr<nr_udp_message> msg);
 
@@ -307,17 +307,17 @@ public:
 private:
   virtual ~NrUdpSocketIpcProxy();
 
   RefPtr<NrUdpSocketIpc> socket_;
   nsCOMPtr<nsIEventTarget> sts_thread_;
 };
 
 struct nr_tcp_message {
-  explicit nr_tcp_message(nsAutoPtr<DataBuffer> &data)
+  explicit nr_tcp_message(nsAutoPtr<MediaPacket> &data)
     : read_bytes(0)
     , data(data) {
   }
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nr_tcp_message);
 
   const uint8_t *reading_pointer() const {
     return data->data() + read_bytes;
@@ -328,17 +328,17 @@ struct nr_tcp_message {
   }
 
   size_t read_bytes;
 
 private:
   ~nr_tcp_message() {}
   DISALLOW_COPY_ASSIGN(nr_tcp_message);
 
-  nsAutoPtr<DataBuffer> data;
+  nsAutoPtr<MediaPacket> data;
 };
 
 #if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API)
 class NrTcpSocketIpc : public NrSocketIpc,
                        public nsITCPSocketCallback {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSITCPSOCKETCALLBACK
--- a/media/mtransport/test/buffered_stun_socket_unittest.cpp
+++ b/media/mtransport/test/buffered_stun_socket_unittest.cpp
@@ -15,17 +15,16 @@
 extern "C" {
 #include "nr_api.h"
 #include "nr_socket.h"
 #include "nr_socket_buffered_stun.h"
 #include "transport_addr.h"
 #include "stun.h"
 }
 
-#include "databuffer.h"
 #include "dummysocket.h"
 
 #include "nr_socket_prsock.h"
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 #include "gtest_utils.h"
 
--- a/media/mtransport/test/dummysocket.h
+++ b/media/mtransport/test/dummysocket.h
@@ -10,33 +10,33 @@
 #define MTRANSPORT_DUMMY_SOCKET_H_
 
 #include "nr_socket_prsock.h"
 
 extern "C" {
 #include "transport_addr.h"
 }
 
-#include "databuffer.h"
+#include "mediapacket.h"
 #include "mozilla/UniquePtr.h"
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 #include "gtest_utils.h"
 
 namespace mozilla {
 
-static UniquePtr<DataBuffer> merge(UniquePtr<DataBuffer> a, UniquePtr<DataBuffer> b) {
+static UniquePtr<MediaPacket> merge(UniquePtr<MediaPacket> a, UniquePtr<MediaPacket> b) {
   if (a && a->len() && b && b->len()) {
-    UniquePtr<DataBuffer> merged(new DataBuffer());
-    merged->Allocate(a->len() + b->len());
+    UniquePtr<uint8_t[]> data(new uint8_t[a->len() + b->len()]);
+    memcpy(data.get(), a->data(), a->len());
+    memcpy(data.get() + a->len(), b->data(), b->len());
 
-    memcpy(merged->data(), a->data(), a->len());
-    memcpy(merged->data() + a->len(), b->data(), b->len());
-
+    UniquePtr<MediaPacket> merged(new MediaPacket);
+    merged->Take(std::move(data), a->len() + b->len());
     return merged;
   }
 
   if (a && a->len()) {
     return a;
   }
 
   if (b && b->len()) {
@@ -95,17 +95,18 @@ class DummySocket : public NrSocketBase 
   virtual int accept(nr_transport_addr *addrp, nr_socket **sockp) override {
     return 0;
   }
 
   virtual int write(const void *msg, size_t len, size_t *written) override {
     size_t to_write = std::min(len, writable_);
 
     if (to_write) {
-      UniquePtr<DataBuffer> msgbuf(new DataBuffer(static_cast<const uint8_t *>(msg), to_write));
+      UniquePtr<MediaPacket> msgbuf(new MediaPacket);
+      msgbuf->Copy(static_cast<const uint8_t *>(msg), to_write);
       write_buffer_ = merge(std::move(write_buffer_), std::move(msgbuf));
     }
 
     *written = to_write;
 
     return 0;
   }
 
@@ -116,18 +117,20 @@ class DummySocket : public NrSocketBase 
 
     size_t to_read = std::min(read_buffer_->len(),
                               std::min(maxlen, readable_));
 
     memcpy(buf, read_buffer_->data(), to_read);
     *len = to_read;
 
     if (to_read < read_buffer_->len()) {
-      read_buffer_.reset(new DataBuffer(read_buffer_->data() + to_read,
-                                    read_buffer_->len() - to_read));
+      MediaPacket* newPacket = new MediaPacket;
+      newPacket->Copy(read_buffer_->data() + to_read,
+                      read_buffer_->len() - to_read);
+      read_buffer_.reset(newPacket);
     } else {
       read_buffer_.reset();
     }
 
     return 0;
   }
 
   // Implementations of the async_event APIs.
@@ -175,17 +178,18 @@ class DummySocket : public NrSocketBase 
     cb_ = nullptr;
     cb_arg_ = nullptr;
 
     cb(this, NR_ASYNC_WAIT_WRITE, cb_arg);
   }
 
   void SetReadBuffer(const uint8_t *data, size_t len) {
     EXPECT_EQ(nullptr, write_buffer_.get());
-    read_buffer_.reset(new DataBuffer(data, len));
+    read_buffer_.reset(new MediaPacket);
+    read_buffer_->Copy(data, len);
   }
 
   void ClearReadBuffer() {
     read_buffer_.reset();
   }
 
   void SetReadable(size_t val) {
     readable_ = val;
@@ -209,19 +213,19 @@ class DummySocket : public NrSocketBase 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DummySocket, override);
 
  private:
   ~DummySocket() {}
 
   DISALLOW_COPY_ASSIGN(DummySocket);
 
   size_t writable_;  // Amount we allow someone to write.
-  UniquePtr<DataBuffer> write_buffer_;
+  UniquePtr<MediaPacket> write_buffer_;
   size_t readable_;   // Amount we allow someone to read.
-  UniquePtr<DataBuffer> read_buffer_;
+  UniquePtr<MediaPacket> read_buffer_;
 
   NR_async_cb cb_;
   void *cb_arg_;
   nr_socket *self_;
 
   nr_transport_addr connect_addr_;
 };
 
--- a/media/mtransport/test/proxy_tunnel_socket_unittest.cpp
+++ b/media/mtransport/test/proxy_tunnel_socket_unittest.cpp
@@ -15,17 +15,16 @@
 extern "C" {
 #include "nr_api.h"
 #include "nr_socket.h"
 #include "nr_proxy_tunnel.h"
 #include "transport_addr.h"
 #include "stun.h"
 }
 
-#include "databuffer.h"
 #include "dummysocket.h"
 
 #include "nr_socket_prsock.h"
 #include "nriceresolverfake.h"
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 #include "gtest_utils.h"
--- a/media/mtransport/test/sctp_unittest.cpp
+++ b/media/mtransport/test/sctp_unittest.cpp
@@ -194,48 +194,45 @@ class TransportTestPeer : public sigslot
 
     ++sent_;
   }
 
   int sent() const { return sent_; }
   int received() const { return received_; }
   bool connected() const { return connected_; }
 
-  static TransportResult SendPacket_s(const unsigned char* data, size_t len,
+  static TransportResult SendPacket_s(nsAutoPtr<MediaPacket> packet,
                                       const RefPtr<TransportFlow>& flow,
                                       TransportLayer* layer) {
-    TransportResult res = layer->SendPacket(data, len);
-    delete data; // we always allocate
-    return res;
+    return layer->SendPacket(*packet);
   }
 
   TransportResult SendPacket(const unsigned char* data, size_t len) {
-    unsigned char *buffer = new unsigned char[len];
-    memcpy(buffer, data, len);
+    nsAutoPtr<MediaPacket> packet(new MediaPacket);
+    packet->Copy(data, len);
 
     // Uses DISPATCH_NORMAL to avoid possible deadlocks when we're called
     // from MainThread especially during shutdown (same as DataChannels).
     // RUN_ON_THREAD short-circuits if already on the STS thread, which is
     // normal for most transfers outside of connect() and close().  Passes
     // a refptr to flow_ to avoid any async deletion issues (since we can't
     // make 'this' into a refptr as it isn't refcounted)
     RUN_ON_THREAD(test_utils_->sts_target(), WrapRunnableNM(
-        &TransportTestPeer::SendPacket_s, buffer, len, flow_, loopback_),
+        &TransportTestPeer::SendPacket_s, packet, flow_, loopback_),
                   NS_DISPATCH_NORMAL);
 
     return 0;
   }
 
-  void PacketReceived(TransportLayer * layer, const unsigned char* data,
-                      size_t len) {
-    std::cerr << "Received " << len << " bytes" << std::endl;
+  void PacketReceived(TransportLayer * layer, MediaPacket& packet) {
+    std::cerr << "Received " << packet.len() << " bytes" << std::endl;
 
     // Pass the data to SCTP
 
-    usrsctp_conninput(static_cast<void *>(this), data, len, 0);
+    usrsctp_conninput(static_cast<void *>(this), packet.data(), packet.len(), 0);
   }
 
   // Process SCTP notification
   void Notification(union sctp_notification *msg, size_t len) {
     ASSERT_EQ(msg->sn_header.sn_length, len);
 
     if (msg->sn_header.sn_type == SCTP_ASSOC_CHANGE) {
       struct sctp_assoc_change *change = &msg->sn_assoc_change;
--- a/media/mtransport/test/stunserver.cpp
+++ b/media/mtransport/test/stunserver.cpp
@@ -75,17 +75,17 @@ nrappkit copyright:
    POSSIBILITY OF SUCH DAMAGE.
 
 
    ekr@rtfm.com  Thu Dec 20 20:14:49 2001
 */
 #include "logging.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
-#include "databuffer.h"
+#include "mediapacket.h"
 
 // mozilla/utils.h defines this as well
 #ifdef UNIMPLEMENTED
 #undef UNIMPLEMENTED
 #endif
 
 extern "C" {
 #include "nr_api.h"
@@ -387,23 +387,24 @@ void TestStunServer::ShutdownInstance() 
 
 
 struct DeferredStunOperation {
   DeferredStunOperation(TestStunServer *server,
                         const char *data, size_t len,
                         nr_transport_addr *addr,
                         nr_socket *sock) :
       server_(server),
-      buffer_(reinterpret_cast<const uint8_t *>(data), len),
+      buffer_(),
       sock_(sock) {
+    buffer_.Copy(reinterpret_cast<const uint8_t *>(data), len);
     nr_transport_addr_copy(&addr_, addr);
   }
 
   TestStunServer *server_;
-  DataBuffer buffer_;
+  MediaPacket buffer_;
   nr_transport_addr addr_;
   nr_socket *sock_;
 };
 
 void TestStunServer::Process(const uint8_t *msg, size_t len, nr_transport_addr *addr, nr_socket *sock) {
 
   if (!sock) {
     sock = send_sock_;
--- a/media/mtransport/test/transport_unittests.cpp
+++ b/media/mtransport/test/transport_unittests.cpp
@@ -19,17 +19,17 @@
 #include "nspr.h"
 #include "nss.h"
 #include "ssl.h"
 #include "sslproto.h"
 
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 
-#include "databuffer.h"
+#include "mediapacket.h"
 #include "dtlsidentity.h"
 #include "nricectxhandler.h"
 #include "nricemediastream.h"
 #include "transportflow.h"
 #include "transportlayer.h"
 #include "transportlayerdtls.h"
 #include "transportlayerice.h"
 #include "transportlayerlog.h"
@@ -71,17 +71,17 @@ class TransportLayerDummy : public Trans
   virtual ~TransportLayerDummy() {
     *destroyed_ = true;
   }
 
   nsresult InitInternal() override {
     return allow_init_ ? NS_OK : NS_ERROR_FAILURE;
   }
 
-  TransportResult SendPacket(const unsigned char *data, size_t len) override {
+  TransportResult SendPacket(MediaPacket& packet) override {
     MOZ_CRASH();  // Should never be called.
     return 0;
   }
 
   TRANSPORT_LAYER_ID("lossy")
 
  private:
   bool allow_init_;
@@ -97,48 +97,47 @@ class Inspector {
 };
 
 // Class to simulate various kinds of network lossage
 class TransportLayerLossy : public TransportLayer {
  public:
   TransportLayerLossy() : loss_mask_(0), packet_(0), inspector_(nullptr) {}
   ~TransportLayerLossy () {}
 
-  TransportResult SendPacket(const unsigned char *data, size_t len) override {
-    MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "SendPacket(" << len << ")");
+  TransportResult SendPacket(MediaPacket& packet) override {
+    MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "SendPacket(" << packet.len() << ")");
 
     if (loss_mask_ & (1 << (packet_ % 32))) {
       MOZ_MTLOG(ML_NOTICE, "Dropping packet");
       ++packet_;
-      return len;
+      return packet.len();
     }
     if (inspector_) {
-      inspector_->Inspect(this, data, len);
+      inspector_->Inspect(this, packet.data(), packet.len());
     }
 
     ++packet_;
 
-    return downward_->SendPacket(data, len);
+    return downward_->SendPacket(packet);
   }
 
   void SetLoss(uint32_t packet) {
     loss_mask_ |= (1 << (packet & 32));
   }
 
   void SetInspector(UniquePtr<Inspector> inspector) {
     inspector_ = std::move(inspector);
   }
 
   void StateChange(TransportLayer *layer, State state) {
     TL_SET_STATE(state);
   }
 
-  void PacketReceived(TransportLayer *layer, const unsigned char *data,
-                      size_t len) {
-    SignalPacketReceived(this, data, len);
+  void PacketReceived(TransportLayer *layer, MediaPacket& packet) {
+    SignalPacketReceived(this, packet);
   }
 
   TRANSPORT_LAYER_ID("lossy")
 
  protected:
   void WasInserted() override {
     downward_->SignalPacketReceived.
         connect(this,
@@ -161,17 +160,19 @@ class TransportLayerLossy : public Trans
   do { \
     EXPECT_GE(remaining(), expected); \
     if (remaining() < expected) return false; \
   } while(0)
 
 class TlsParser {
  public:
   TlsParser(const unsigned char *data, size_t len)
-      : buffer_(data, len), offset_(0) {}
+      : buffer_(), offset_(0) {
+    buffer_.Copy(data, len);
+  }
 
   bool Read(unsigned char* val) {
     if (remaining() < 1) {
       return false;
     }
     *val = *ptr();
     consume(1);
     return true;
@@ -209,97 +210,97 @@ class TlsParser {
     return true;
   }
 
  private:
   size_t remaining() const { return buffer_.len() - offset_; }
   const uint8_t *ptr() const { return buffer_.data() + offset_; }
   void consume(size_t len) { offset_ += len; }
 
-  DataBuffer buffer_;
+  MediaPacket buffer_;
   size_t offset_;
 };
 
 class DtlsRecordParser {
  public:
   DtlsRecordParser(const unsigned char *data, size_t len)
-      : buffer_(data, len), offset_(0) {}
+      : buffer_(), offset_(0) {
+    buffer_.Copy(data, len);
+  }
 
-  bool NextRecord(uint8_t* ct, nsAutoPtr<DataBuffer>* buffer) {
+  bool NextRecord(uint8_t* ct, nsAutoPtr<MediaPacket>* buffer) {
     if (!remaining())
       return false;
 
     CHECK_LENGTH(13U);
     const uint8_t *ctp = reinterpret_cast<const uint8_t *>(ptr());
     consume(11); // ct + version + length
 
     const uint16_t *tmp = reinterpret_cast<const uint16_t*>(ptr());
     size_t length = ntohs(*tmp);
     consume(2);
 
     CHECK_LENGTH(length);
-    DataBuffer* db = new DataBuffer(ptr(), length);
+    MediaPacket* db = new MediaPacket;
+    db->Copy(ptr(), length);
     consume(length);
 
     *ct = *ctp;
     *buffer = db;
 
     return true;
   }
 
  private:
   size_t remaining() const { return buffer_.len() - offset_; }
   const uint8_t *ptr() const { return buffer_.data() + offset_; }
   void consume(size_t len) { offset_ += len; }
 
-  DataBuffer buffer_;
+  MediaPacket buffer_;
   size_t offset_;
 };
 
 
 // Inspector that parses out DTLS records and passes
 // them on.
 class DtlsRecordInspector : public Inspector {
  public:
   virtual void Inspect(TransportLayer* layer,
                        const unsigned char *data, size_t len) {
     DtlsRecordParser parser(data, len);
 
     uint8_t ct;
-    nsAutoPtr<DataBuffer> buf;
+    nsAutoPtr<MediaPacket> buf;
     while(parser.NextRecord(&ct, &buf)) {
       OnRecord(layer, ct, buf->data(), buf->len());
     }
   }
 
   virtual void OnRecord(TransportLayer* layer,
                         uint8_t content_type,
                         const unsigned char *record,
                         size_t len) = 0;
 };
 
 // Inspector that injects arbitrary packets based on
 // DTLS records of various types.
 class DtlsInspectorInjector : public DtlsRecordInspector {
  public:
   DtlsInspectorInjector(uint8_t packet_type, uint8_t handshake_type,
-                    const unsigned char *data, size_t len) :
+                        const unsigned char *data, size_t len) :
       packet_type_(packet_type),
-      handshake_type_(handshake_type),
-      injected_(false) {
-    data_.reset(new unsigned char[len]);
-    memcpy(data_.get(), data, len);
-    len_ = len;
+      handshake_type_(handshake_type) {
+    packet_.Copy(data, len);
   }
 
   virtual void OnRecord(TransportLayer* layer,
                         uint8_t content_type,
                         const unsigned char *data, size_t len) {
     // Only inject once.
-    if (injected_) {
+    if (!packet_.data()) {
       return;
     }
 
     // Check that the first byte is as requested.
     if (content_type != packet_type_) {
       return;
     }
 
@@ -310,25 +311,24 @@ class DtlsInspectorInjector : public Dtl
       }
 
       // Check that the handshake type is as requested.
       if (data[0] != handshake_type_) {
         return;
       }
     }
 
-    layer->SendPacket(data_.get(), len_);
+    layer->SendPacket(packet_);
+    packet_.Reset();
   }
 
  private:
   uint8_t packet_type_;
   uint8_t handshake_type_;
-  bool injected_;
-  UniquePtr<unsigned char[]> data_;
-  size_t len_;
+  MediaPacket packet_;
 };
 
 // Make a copy of the first instance of a message.
 class DtlsInspectorRecordHandshakeMessage : public DtlsRecordInspector {
  public:
   explicit DtlsInspectorRecordHandshakeMessage(uint8_t handshake_type)
       : handshake_type_(handshake_type),
         buffer_() {}
@@ -377,27 +377,28 @@ class DtlsInspectorRecordHandshakeMessag
     }
 
     if ((fragment_offset != 0) || (fragment_length != length)) {
       // This shouldn't happen because all current tests where we
       // are using this code don't fragment.
       return;
     }
 
-    buffer_.Allocate(length);
-    if (!parser.Read(buffer_.data(), length)) {
+    UniquePtr<uint8_t[]> buffer(new uint8_t[length]);
+    if (!parser.Read(buffer.get(), length)) {
       return;
     }
+    buffer_.Take(std::move(buffer), length);
   }
 
-  const DataBuffer& buffer() { return buffer_; }
+  const MediaPacket& buffer() { return buffer_; }
 
  private:
   uint8_t handshake_type_;
-  DataBuffer buffer_;
+  MediaPacket buffer_;
 };
 
 class TlsServerKeyExchangeECDHE {
  public:
   bool Parse(const unsigned char* data, size_t len) {
     TlsParser parser(data, len);
 
     uint8_t curve_type;
@@ -414,25 +415,26 @@ class TlsServerKeyExchangeECDHE {
       return false;
     }
 
     uint32_t point_length;
     if (!parser.Read(&point_length, 1)) {
       return false;
     }
 
-    public_key_.Allocate(point_length);
-    if (!parser.Read(public_key_.data(), point_length)) {
+    UniquePtr<uint8_t[]> key(new uint8_t[point_length]);
+    if (!parser.Read(key.get(), point_length)) {
       return false;
     }
+    public_key_.Take(std::move(key), point_length);
 
     return true;
   }
 
-  DataBuffer public_key_;
+  MediaPacket public_key_;
 };
 
 namespace {
 class TransportTestPeer : public sigslot::has_slots<> {
  public:
   TransportTestPeer(nsCOMPtr<nsIEventTarget> target, std::string name, MtransportTestUtils* utils)
       : name_(name), offerer_(name == "P1"), target_(target),
         received_packets_(0),received_bytes_(0),flow_(new TransportFlow(name)),
@@ -710,37 +712,47 @@ class TransportTestPeer : public sigslot
     // Start checks on the other peer.
     test_utils_->sts_target()->Dispatch(
       WrapRunnableRet(&res, peer_->ice_ctx_->ctx(), &NrIceCtx::StartChecks,
                       offerer_),
       NS_DISPATCH_SYNC);
     ASSERT_TRUE(NS_SUCCEEDED(res));
   }
 
-  TransportResult SendPacket(const unsigned char* data, size_t len) {
+  // WrapRunnable/lambda and move semantics (MediaPacket is not copyable) don't
+  // get along yet, so we need a wrapper. Gross.
+  static TransportResult SendPacketWrapper(TransportLayer* layer,
+                                           MediaPacket* packet) {
+    return layer->SendPacket(*packet);
+  }
+
+  TransportResult SendPacket(MediaPacket& packet) {
     TransportResult ret;
+
     test_utils_->sts_target()->Dispatch(
-      WrapRunnableRet(&ret, dtls_, &TransportLayer::SendPacket, data, len),
+      WrapRunnableNMRet(&ret,
+                        &TransportTestPeer::SendPacketWrapper,
+                        dtls_,
+                        &packet),
       NS_DISPATCH_SYNC);
 
     return ret;
   }
 
 
   void StateChanged(TransportLayer *layer, TransportLayer::State state) {
     if (state == TransportLayer::TS_OPEN) {
       std::cerr << "Now connected" << std::endl;
     }
   }
 
-  void PacketReceived(TransportLayer* layer, const unsigned char* data,
-                      size_t len) {
-    std::cerr << "Received " << len << " bytes" << std::endl;
+  void PacketReceived(TransportLayer* layer, MediaPacket& packet) {
+    std::cerr << "Received " << packet.len() << " bytes" << std::endl;
     ++received_packets_;
-    received_bytes_ += len;
+    received_bytes_ += packet.len();
   }
 
   void SetLoss(uint32_t loss) {
     lossy_->SetLoss(loss);
   }
 
   void SetCombinePackets(bool combine) {
     loopback_->CombinePackets(combine);
@@ -945,17 +957,19 @@ class TransportTest : public MtransportT
     ASSERT_TRUE_WAIT(p2_->connected(), 10000);
   }
 
   void TransferTest(size_t count, size_t bytes = 1024) {
     unsigned char buf[bytes];
 
     for (size_t i= 0; i<count; ++i) {
       memset(buf, count & 0xff, sizeof(buf));
-      TransportResult rv = p1_->SendPacket(buf, sizeof(buf));
+      MediaPacket packet;
+      packet.Copy(buf, sizeof(buf));
+      TransportResult rv = p1_->SendPacket(packet);
       ASSERT_TRUE(rv > 0);
     }
 
     std::cerr << "Received == " << p2_->receivedPackets() << " packets" << std::endl;
     ASSERT_TRUE_WAIT(count == p2_->receivedPackets(), 10000);
     ASSERT_TRUE((count * sizeof(buf)) == p2_->receivedBytes());
   }
 
--- a/media/mtransport/test_nr_socket.h
+++ b/media/mtransport/test_nr_socket.h
@@ -96,16 +96,17 @@ extern "C" {
 #include <set>
 #include <vector>
 #include <map>
 #include <list>
 #include <string>
 
 #include "mozilla/UniquePtr.h"
 #include "prinrval.h"
+#include "mediapacket.h"
 
 namespace mozilla {
 
 class TestNrSocket;
 
 /**
  * A group of TestNrSockets that behave as if they were behind the same NAT.
  * @note We deliberately avoid addref/release of TestNrSocket here to avoid
@@ -236,24 +237,25 @@ class TestNrSocket : public NrSocketBase
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestNrSocket, override)
 
   private:
     virtual ~TestNrSocket();
 
     class UdpPacket {
       public:
         UdpPacket(const void *msg, size_t len, const nr_transport_addr &addr) :
-          buffer_(new DataBuffer(static_cast<const uint8_t*>(msg), len)) {
+          buffer_(new MediaPacket) {
+          buffer_->Copy(static_cast<const uint8_t*>(msg), len);
           // TODO(bug 1170299): Remove const_cast when no longer necessary
           nr_transport_addr_copy(&remote_address_,
                                  const_cast<nr_transport_addr*>(&addr));
         }
 
         nr_transport_addr remote_address_;
-        UniquePtr<DataBuffer> buffer_;
+        UniquePtr<MediaPacket> buffer_;
 
         NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UdpPacket);
       private:
         ~UdpPacket(){}
     };
 
     class PortMapping {
       public:
@@ -285,24 +287,25 @@ class TestNrSocket : public NrSocketBase
 
     struct DeferredPacket {
       DeferredPacket(TestNrSocket *sock,
                      const void *data, size_t len,
                      int flags,
                      nr_transport_addr *addr,
                      RefPtr<NrSocketBase> internal_socket) :
           socket_(sock),
-          buffer_(reinterpret_cast<const uint8_t *>(data), len),
+          buffer_(),
           flags_(flags),
           internal_socket_(internal_socket) {
+        buffer_.Copy(reinterpret_cast<const uint8_t *>(data), len);
         nr_transport_addr_copy(&to_, addr);
       }
 
       TestNrSocket *socket_;
-      DataBuffer buffer_;
+      MediaPacket buffer_;
       int flags_;
       nr_transport_addr to_;
       RefPtr<NrSocketBase> internal_socket_;
     };
 
     bool is_port_mapping_stale(const PortMapping &port_mapping) const;
     bool allow_ingress(const nr_transport_addr &from,
                        PortMapping **port_mapping_used) const;
--- a/media/mtransport/transportlayer.h
+++ b/media/mtransport/transportlayer.h
@@ -12,16 +12,17 @@
 #include "sigslot.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIEventTarget.h"
 
 #include "m_cpp_utils.h"
+#include "mediapacket.h"
 
 namespace mozilla {
 
 class TransportFlow;
 
 typedef int TransportResult;
 
 enum {
@@ -56,29 +57,28 @@ class TransportLayer : public sigslot::h
   virtual void Chain(TransportLayer *downward);
 
   // Downward interface
   TransportLayer *downward() { return downward_; }
 
   // Get the state
   State state() const { return state_; }
   // Must be implemented by derived classes
-  virtual TransportResult SendPacket(const unsigned char *data, size_t len) = 0;
+  virtual TransportResult SendPacket(MediaPacket& packet) = 0;
 
   // Get the thread.
   const nsCOMPtr<nsIEventTarget> GetThread() const {
     return target_;
   }
 
   // Event definitions that one can register for
   // State has changed
   sigslot::signal2<TransportLayer*, State> SignalStateChange;
   // Data received on the flow
-  sigslot::signal3<TransportLayer*, const unsigned char *, size_t>
-                         SignalPacketReceived;
+  sigslot::signal2<TransportLayer*, MediaPacket&> SignalPacketReceived;
 
   // Return the layer id for this layer
   virtual const std::string id() const = 0;
 
   // The id of the flow
   const std::string& flow_id() const {
     return flow_id_;
   }
--- a/media/mtransport/transportlayerdtls.cpp
+++ b/media/mtransport/transportlayerdtls.cpp
@@ -10,17 +10,16 @@
 
 #include <algorithm>
 #include <queue>
 #include <sstream>
 
 #include "dtlsidentity.h"
 #include "keyhi.h"
 #include "logging.h"
-#include "mozilla/Move.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "nsCOMPtr.h"
 #include "nsComponentManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIEventTarget.h"
 #include "nsNetCID.h"
@@ -58,66 +57,57 @@ static PRDescIdentity transport_layer_id
 // - The TransportLayerNSPRAdapter is a PRFileDesc containing a
 //   FIFO.
 // - When TransportLayerDtls.PacketReceived() is called, we insert
 //   the packets in the FIFO and then do a PR_Recv() on the NSS
 //   PRFileDesc, which eventually reads off the FIFO.
 //
 // All of this stuff is assumed to happen solely in a single thread
 // (generally the SocketTransportService thread)
-struct Packet {
-  Packet() : data_(nullptr), len_(0) {}
 
-  void Assign(const void *data, int32_t len) {
-    data_.reset(new uint8_t[len]);
-    memcpy(data_.get(), data, len);
-    len_ = len;
-  }
-
-  UniquePtr<uint8_t[]> data_;
-  int32_t len_;
-};
-
-void TransportLayerNSPRAdapter::PacketReceived(const void *data, int32_t len) {
+void TransportLayerNSPRAdapter::PacketReceived(MediaPacket& packet) {
   if (enabled_) {
-    input_.push(new Packet());
-    input_.back()->Assign(data, len);
+    input_.push(new MediaPacket(std::move(packet)));
   }
 }
 
 int32_t TransportLayerNSPRAdapter::Recv(void *buf, int32_t buflen) {
   if (input_.empty()) {
     PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
     return -1;
   }
 
-  Packet* front = input_.front();
-  if (buflen < front->len_) {
+  MediaPacket* front = input_.front();
+  int32_t count = static_cast<int32_t>(front->len());
+
+  if (buflen < count) {
     MOZ_ASSERT(false, "Not enough buffer space to receive into");
     PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
     return -1;
   }
 
-  int32_t count = front->len_;
-  memcpy(buf, front->data_.get(), count);
+  memcpy(buf, front->data(), count);
 
   input_.pop();
   delete front;
 
   return count;
 }
 
 int32_t TransportLayerNSPRAdapter::Write(const void *buf, int32_t length) {
   if (!enabled_) {
     MOZ_MTLOG(ML_WARNING, "Writing to disabled transport layer");
     return -1;
   }
 
-  TransportResult r = output_->SendPacket(
-      static_cast<const unsigned char *>(buf), length);
+  MediaPacket packet;
+  // Copies. Oh well.
+  packet.Copy(static_cast<const uint8_t*>(buf), static_cast<size_t>(length));
+
+  TransportResult r = output_->SendPacket(packet);
   if (r >= 0) {
     return r;
   }
 
   if (r == TE_WOULDBLOCK) {
     PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
   } else {
     PR_SetError(PR_IO_ERROR, 0);
@@ -984,51 +974,64 @@ bool TransportLayerDtls::CheckAlpn() {
     return false;
   }
   alpn_ = chosen;
   return true;
 }
 
 
 void TransportLayerDtls::PacketReceived(TransportLayer* layer,
-                                        const unsigned char *data,
-                                        size_t len) {
+                                        MediaPacket& packet) {
   CheckThread();
-  MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "PacketReceived(" << len << ")");
+  MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "PacketReceived(" << packet.len() << ")");
 
   if (state_ != TS_CONNECTING && state_ != TS_OPEN) {
     MOZ_MTLOG(ML_DEBUG,
               LAYER_INFO << "Discarding packet in inappropriate state");
     return;
   }
 
-  // not DTLS per RFC 7983
-  if (data[0] < 20 || data[0] > 63) {
+  if (!packet.data()) {
+    // Something ate this, probably the SRTP layer
     return;
   }
 
-  nspr_io_adapter_->PacketReceived(data, len);
+  // not DTLS per RFC 7983
+  if (packet.data()[0] < 20 || packet.data()[0] > 63) {
+    return;
+  }
 
+  nspr_io_adapter_->PacketReceived(packet);
+  GetDecryptedPackets();
+}
+
+void
+TransportLayerDtls::GetDecryptedPackets()
+{
   // If we're still connecting, try to handshake
   if (state_ == TS_CONNECTING) {
     Handshake();
   }
 
   // Now try a recv if we're open, since there might be data left
   if (state_ == TS_OPEN) {
-    // nICEr uses a 9216 bytes buffer to allow support for jumbo frames
-    unsigned char buf[9216];
     int32_t rv;
     // One packet might contain several DTLS packets
     do {
-      rv = PR_Recv(ssl_fd_.get(), buf, sizeof(buf), 0, PR_INTERVAL_NO_WAIT);
+      // nICEr uses a 9216 bytes buffer to allow support for jumbo frames
+      // Can we peek to get a better idea of the actual size?
+      static const size_t kBufferSize = 9216;
+      auto buffer = MakeUnique<uint8_t[]>(kBufferSize);
+      rv = PR_Recv(ssl_fd_.get(), buffer.get(), kBufferSize, 0, PR_INTERVAL_NO_WAIT);
       if (rv > 0) {
         // We have data
         MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Read " << rv << " bytes from NSS");
-        SignalPacketReceived(this, buf, rv);
+        MediaPacket packet;
+        packet.Take(std::move(buffer), static_cast<size_t>(rv));
+        SignalPacketReceived(this, packet);
       } else if (rv == 0) {
         TL_SET_STATE(TS_CLOSED);
       } else {
         int32_t err = PR_GetError();
 
         if (err == PR_WOULD_BLOCK_ERROR) {
           // This gets ignored
           MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Receive would have blocked");
@@ -1064,26 +1067,26 @@ void TransportLayerDtls::SetState(State 
     }
   } else {
     MOZ_ASSERT(false, "Invalid state transition");
   }
 
   TransportLayer::SetState(state, file, line);
 }
 
-TransportResult TransportLayerDtls::SendPacket(const unsigned char *data,
-                                               size_t len) {
+TransportResult TransportLayerDtls::SendPacket(MediaPacket& packet) {
   CheckThread();
   if (state_ != TS_OPEN) {
     MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Can't call SendPacket() in state "
               << state_);
     return TE_ERROR;
   }
 
-  int32_t rv = PR_Send(ssl_fd_.get(), data, len, 0, PR_INTERVAL_NO_WAIT);
+  int32_t rv = PR_Send(ssl_fd_.get(), packet.data(), packet.len(), 0,
+      PR_INTERVAL_NO_WAIT);
 
   if (rv > 0) {
     // We have data
     MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Wrote " << rv << " bytes to SSL Layer");
     return rv;
   }
 
   if (rv == 0) {
--- a/media/mtransport/transportlayerdtls.h
+++ b/media/mtransport/transportlayerdtls.h
@@ -31,26 +31,26 @@ struct Packet;
 
 class TransportLayerNSPRAdapter {
  public:
   explicit TransportLayerNSPRAdapter(TransportLayer *output) :
   output_(output),
   input_(),
   enabled_(true) {}
 
-  void PacketReceived(const void *data, int32_t len);
+  void PacketReceived(MediaPacket& packet);
   int32_t Recv(void *buf, int32_t buflen);
   int32_t Write(const void *buf, int32_t length);
   void SetEnabled(bool enabled) { enabled_ = enabled; }
 
  private:
   DISALLOW_COPY_ASSIGN(TransportLayerNSPRAdapter);
 
   TransportLayer *output_;
-  std::queue<Packet *> input_;
+  std::queue<MediaPacket *> input_;
   bool enabled_;
 };
 
 class TransportLayerDtls final : public TransportLayer {
  public:
   TransportLayerDtls() :
       role_(CLIENT),
       verification_mode_(VERIFY_UNSET),
@@ -89,22 +89,21 @@ class TransportLayerDtls final : public 
                                 bool use_context,
                                 const std::string& context,
                                 unsigned char *out,
                                 unsigned int outlen);
 
   // Transport layer overrides.
   nsresult InitInternal() override;
   void WasInserted() override;
-  TransportResult SendPacket(const unsigned char *data, size_t len) override;
+  TransportResult SendPacket(MediaPacket& packet) override;
 
   // Signals
   void StateChange(TransportLayer *layer, State state);
-  void PacketReceived(TransportLayer* layer, const unsigned char *data,
-                      size_t len);
+  void PacketReceived(TransportLayer* layer, MediaPacket& packet);
 
   // For testing use only.  Returns the fd.
   PRFileDesc* internal_fd() { CheckThread(); return ssl_fd_.get(); }
 
   TRANSPORT_LAYER_ID("dtls")
 
   protected:
   void SetState(State state, const char *file, unsigned line) override;
@@ -134,16 +133,17 @@ class TransportLayerDtls final : public 
     ~VerificationDigest() {}
     DISALLOW_COPY_ASSIGN(VerificationDigest);
   };
 
 
   bool Setup();
   bool SetupCipherSuites(UniquePRFileDesc& ssl_fd) const;
   bool SetupAlpn(UniquePRFileDesc& ssl_fd) const;
+  void GetDecryptedPackets();
   void Handshake();
 
   bool CheckAlpn();
 
   static SECStatus GetClientAuthDataHook(void *arg, PRFileDesc *fd,
                                          CERTDistNames *caNames,
                                          CERTCertificate **pRetCert,
                                          SECKEYPrivateKey **pRetKey);
--- a/media/mtransport/transportlayerice.cpp
+++ b/media/mtransport/transportlayerice.cpp
@@ -166,32 +166,31 @@ void TransportLayerIce::RestoreOldStream
   } else if (stream_->state() == NrIceMediaStream::ICE_CLOSED) {
     IceFailed(stream_);
   }
   // No events are fired when the stream is ICE_CONNECTING.  If the
   // restored stream is ICE_CONNECTING, IceReady/IceFailed will fire
   // later.
 }
 
-TransportResult TransportLayerIce::SendPacket(const unsigned char *data,
-                                              size_t len) {
+TransportResult TransportLayerIce::SendPacket(MediaPacket& packet) {
   CheckThread();
   // use old_stream_ until stream_ is ready
   nsresult res = (old_stream_?old_stream_:stream_)->SendPacket(component_,
-                                                               data,
-                                                               len);
+                                                               packet.data(),
+                                                               packet.len());
 
   if (!NS_SUCCEEDED(res)) {
     return (res == NS_BASE_STREAM_WOULD_BLOCK) ?
         TE_WOULDBLOCK : TE_ERROR;
   }
 
-  MOZ_MTLOG(ML_DEBUG, LAYER_INFO << " SendPacket(" << len << ") succeeded");
+  MOZ_MTLOG(ML_DEBUG, LAYER_INFO << " SendPacket(" << packet.len() << ") succeeded");
 
-  return len;
+  return packet.len();
 }
 
 
 void TransportLayerIce::IceCandidate(NrIceMediaStream *stream,
                                      const std::string&) {
   // NO-OP for now
 }
 
@@ -222,12 +221,17 @@ void TransportLayerIce::IcePacketReceive
   CheckThread();
   // We get packets for both components, so ignore the ones that aren't
   // for us.
   if (component_ != component)
     return;
 
   MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "PacketReceived(" << stream->name() << ","
     << component << "," << len << ")");
-  SignalPacketReceived(this, data, len);
+  // Might be useful to allow MediaPacket to borrow a buffer (ie; not take
+  // ownership, but copy it if the MediaPacket is moved). This could be a
+  // footgun though with MediaPackets that end up on the heap.
+  MediaPacket packet;
+  packet.Copy(data, len);
+  SignalPacketReceived(this, packet);
 }
 
 }  // close namespace
--- a/media/mtransport/transportlayerice.h
+++ b/media/mtransport/transportlayerice.h
@@ -36,17 +36,17 @@ class TransportLayerIce : public Transpo
 
   void SetParameters(RefPtr<NrIceMediaStream> stream,
                      int component);
 
   void ResetOldStream(); // called after successful ice restart
   void RestoreOldStream(); // called after unsuccessful ice restart
 
   // Transport layer overrides.
-  TransportResult SendPacket(const unsigned char *data, size_t len) override;
+  TransportResult SendPacket(MediaPacket& packet) override;
 
   // Slots for ICE
   void IceCandidate(NrIceMediaStream *stream, const std::string&);
   void IceReady(NrIceMediaStream *stream);
   void IceFailed(NrIceMediaStream *stream);
   void IcePacketReceived(NrIceMediaStream *stream, int component,
                          const unsigned char *data, int len);
 
--- a/media/mtransport/transportlayerlog.cpp
+++ b/media/mtransport/transportlayerlog.cpp
@@ -20,34 +20,31 @@ void TransportLayerLogging::WasInserted(
         this, &TransportLayerLogging::StateChange);
     downward_->SignalPacketReceived.connect(
         this, &TransportLayerLogging::PacketReceived);
     TL_SET_STATE(downward_->state());
   }
 }
 
 TransportResult
-TransportLayerLogging::SendPacket(const unsigned char *data, size_t len) {
-  MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "SendPacket(" << len << ")");
+TransportLayerLogging::SendPacket(MediaPacket& packet) {
+  MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "SendPacket(" << packet.len() << ")");
 
   if (downward_) {
-    return downward_->SendPacket(data, len);
+    return downward_->SendPacket(packet);
   }
-  return static_cast<TransportResult>(len);
+  return static_cast<TransportResult>(packet.len());
 }
 
 void TransportLayerLogging::StateChange(TransportLayer *layer, State state) {
   MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Received StateChange to " << state);
 
   TL_SET_STATE(state);
 }
 
 void TransportLayerLogging::PacketReceived(TransportLayer* layer,
-                                           const unsigned char *data,
-                                           size_t len) {
-  MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "PacketReceived(" << len << ")");
+                                           MediaPacket& packet) {
+  MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "PacketReceived(" << packet.len() << ")");
 
-  SignalPacketReceived(this, data, len);
+  SignalPacketReceived(this, packet);
 }
 
-
-
 }  // close namespace
--- a/media/mtransport/transportlayerlog.h
+++ b/media/mtransport/transportlayerlog.h
@@ -15,22 +15,21 @@
 
 namespace mozilla {
 
 class TransportLayerLogging : public TransportLayer {
 public:
   TransportLayerLogging() {}
 
   // Overrides for TransportLayer
-  TransportResult SendPacket(const unsigned char *data, size_t len) override;
+  TransportResult SendPacket(MediaPacket& packet) override;
 
   // Signals (forwarded to upper layer)
   void StateChange(TransportLayer *layer, State state);
-  void PacketReceived(TransportLayer* layer, const unsigned char *data,
-                      size_t len);
+  void PacketReceived(TransportLayer* layer, MediaPacket& packet);
 
   TRANSPORT_LAYER_ID("log")
 
 protected:
   void WasInserted() override;
 
 private:
   DISALLOW_COPY_ASSIGN(TransportLayerLogging);
--- a/media/mtransport/transportlayerloopback.cpp
+++ b/media/mtransport/transportlayerloopback.cpp
@@ -55,70 +55,67 @@ nsresult TransportLayerLoopback::Init() 
 // Connect to the other side
 void TransportLayerLoopback::Connect(TransportLayerLoopback* peer) {
   peer_ = peer;
 
   TL_SET_STATE(TS_OPEN);
 }
 
 TransportResult
-TransportLayerLoopback::SendPacket(const unsigned char *data, size_t len) {
-  MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "SendPacket(" << len << ")");
+TransportLayerLoopback::SendPacket(MediaPacket& packet) {
+  MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "SendPacket(" << packet.len() << ")");
 
   if (!peer_) {
     MOZ_MTLOG(ML_ERROR, "Discarding packet because peer not attached");
     return TE_ERROR;
   }
 
-  nsresult res = peer_->QueuePacket(data, len);
+  size_t len = packet.len();
+  nsresult res = peer_->QueuePacket(packet);
   if (!NS_SUCCEEDED(res))
     return TE_ERROR;
 
   return static_cast<TransportResult>(len);
 }
 
-nsresult TransportLayerLoopback::QueuePacket(const unsigned char *data,
-                                         size_t len) {
+nsresult TransportLayerLoopback::QueuePacket(MediaPacket& packet) {
   MOZ_ASSERT(packets_lock_);
 
   PR_Lock(packets_lock_);
 
   if (combinePackets_ && !packets_.empty()) {
-    QueuedPacket *packet = packets_.front();
-    packets_.pop();
+    MediaPacket *prevPacket = packets_.front();
 
-    MOZ_MTLOG(ML_DEBUG, LAYER_INFO << " Enqueuing combined packets of length " << packet->len() << " and " << len);
-    packets_.push(new QueuedPacket());
-    packets_.back()->Assign(packet->data(), packet->len(),
-                            data, len);
+    MOZ_MTLOG(ML_DEBUG, LAYER_INFO << " Enqueuing combined packets of length " << prevPacket->len() << " and " << packet.len());
+    auto combined = MakeUnique<uint8_t[]>(prevPacket->len() + packet.len());
+    memcpy(combined.get(), prevPacket->data(), prevPacket->len());
+    memcpy(combined.get() + prevPacket->len(), packet.data(), packet.len());
+    prevPacket->Take(std::move(combined), prevPacket->len() + packet.len());
   } else {
-    MOZ_MTLOG(ML_DEBUG, LAYER_INFO << " Enqueuing packet of length " << len);
-    packets_.push(new QueuedPacket());
-    packets_.back()->Assign(data, len);
+    MOZ_MTLOG(ML_DEBUG, LAYER_INFO << " Enqueuing packet of length " << packet.len());
+    packets_.push(new MediaPacket(std::move(packet)));
   }
 
   PRStatus r = PR_Unlock(packets_lock_);
   MOZ_ASSERT(r == PR_SUCCESS);
   if (r != PR_SUCCESS)
     return NS_ERROR_FAILURE;
 
   return NS_OK;
 }
 
 
 void TransportLayerLoopback::DeliverPackets() {
   while (!packets_.empty()) {
-    QueuedPacket *packet = packets_.front();
+    UniquePtr<MediaPacket> packet(packets_.front());
     packets_.pop();
 
     MOZ_MTLOG(ML_DEBUG, LAYER_INFO << " Delivering packet of length " <<
          packet->len());
-    SignalPacketReceived(this, packet->data(), packet->len());
-
-    delete packet;
+    SignalPacketReceived(this, *packet);
   }
 }
 
 NS_IMPL_ISUPPORTS(TransportLayerLoopback::Deliverer, nsITimerCallback, nsINamed)
 
 NS_IMETHODIMP TransportLayerLoopback::Deliverer::Notify(nsITimer *timer) {
   if (!layer_)
     return NS_OK;
--- a/media/mtransport/transportlayerloopback.h
+++ b/media/mtransport/transportlayerloopback.h
@@ -37,17 +37,17 @@ class TransportLayerLoopback : public Tr
       timer_(nullptr),
       packets_(),
       packets_lock_(nullptr),
       deliverer_(nullptr),
       combinePackets_(false) {}
 
   ~TransportLayerLoopback() {
     while (!packets_.empty()) {
-      QueuedPacket *packet = packets_.front();
+      MediaPacket *packet = packets_.front();
       packets_.pop();
       delete packet;
     }
     if (packets_lock_) {
       PR_DestroyLock(packets_lock_);
     }
     timer_->Cancel();
     deliverer_->Detach();
@@ -67,61 +67,26 @@ class TransportLayerLoopback : public Tr
     if (peer) {
       peer->Disconnect();
     }
   }
 
   void CombinePackets(bool combine) { combinePackets_ = combine; }
 
   // Overrides for TransportLayer
-  TransportResult SendPacket(const unsigned char *data, size_t len) override;
+  TransportResult SendPacket(MediaPacket& packet) override;
 
   // Deliver queued packets
   void DeliverPackets();
 
   TRANSPORT_LAYER_ID("loopback")
 
  private:
   DISALLOW_COPY_ASSIGN(TransportLayerLoopback);
 
-  // A queued packet
-  class QueuedPacket {
-   public:
-    QueuedPacket() : data_(nullptr), len_(0) {}
-    ~QueuedPacket() {
-      delete [] data_;
-    }
-
-    void Assign(const unsigned char *data, size_t len) {
-      data_ = new unsigned char[len];
-      memcpy(static_cast<void *>(data_),
-             static_cast<const void *>(data), len);
-      len_ = len;
-    }
-
-    void Assign(const unsigned char *data1, size_t len1,
-                const unsigned char *data2, size_t len2) {
-      data_ = new unsigned char[len1 + len2];
-      memcpy(static_cast<void *>(data_),
-             static_cast<const void *>(data1), len1);
-      memcpy(static_cast<void *>(data_ + len1),
-             static_cast<const void *>(data2), len2);
-      len_ = len1 + len2;
-    }
-
-    const unsigned char *data() const { return data_; }
-    size_t len() const { return len_; }
-
-   private:
-    DISALLOW_COPY_ASSIGN(QueuedPacket);
-
-    unsigned char *data_;
-    size_t len_;
-  };
-
   // A timer to deliver packets if some are available
   // Fires every 100 ms
   class Deliverer : public nsITimerCallback
                   , public nsINamed {
    public:
     explicit Deliverer(TransportLayerLoopback *layer) :
         layer_(layer) {}
     void Detach() {
@@ -137,20 +102,20 @@ class TransportLayerLoopback : public Tr
     }
 
     DISALLOW_COPY_ASSIGN(Deliverer);
 
     TransportLayerLoopback *layer_;
   };
 
   // Queue a packet for delivery
-  nsresult QueuePacket(const unsigned char *data, size_t len);
+  nsresult QueuePacket(MediaPacket& packet);
 
   TransportLayerLoopback* peer_;
   nsCOMPtr<nsITimer> timer_;
-  std::queue<QueuedPacket *> packets_;
+  std::queue<MediaPacket *> packets_;
   PRLock *packets_lock_;
   RefPtr<Deliverer> deliverer_;
   bool combinePackets_;
 };
 
 }  // close namespace
 #endif
--- a/media/mtransport/transportlayersrtp.cpp
+++ b/media/mtransport/transportlayersrtp.cpp
@@ -9,17 +9,16 @@
 #include "transportlayersrtp.h"
 #include "transportlayerdtls.h"
 
 #include "logging.h"
 #include "nsError.h"
 #include "mozilla/Assertions.h"
 #include "transportlayerdtls.h"
 #include "srtp.h"
-#include "databuffer.h"
 #include "nsAutoPtr.h"
 
 namespace mozilla {
 
 MOZ_MTLOG_MODULE("mtransport")
 
 static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
 
@@ -52,95 +51,95 @@ TransportLayerSrtp::Setup()
   }
 
   // downward_ is the TransportLayerIce
   downward_->SignalPacketReceived.connect(this, &TransportLayerSrtp::PacketReceived);
 
   return true;
 }
 
-static bool
-IsRtp(const unsigned char* aData, size_t aLen)
+static bool IsRtp(const unsigned char* data, size_t len)
 {
-  if (aLen < 2)
+  if (len < 2)
     return false;
 
   // Check if this is a RTCP packet. Logic based on the types listed in
   // media/webrtc/trunk/src/modules/rtp_rtcp/source/rtp_utility.cc
 
   // Anything outside this range is RTP.
-  if ((aData[1] < 192) || (aData[1] > 207))
+  if ((data[1] < 192) || (data[1] > 207))
     return true;
 
-  if (aData[1] == 192) // FIR
+  if (data[1] == 192) // FIR
     return false;
 
-  if (aData[1] == 193) // NACK, but could also be RTP. This makes us sad
+  if (data[1] == 193) // NACK, but could also be RTP. This makes us sad
     return true;      // but it's how webrtc.org behaves.
 
-  if (aData[1] == 194)
+  if (data[1] == 194)
     return true;
 
-  if (aData[1] == 195) // IJ.
+  if (data[1] == 195) // IJ.
     return false;
 
-  if ((aData[1] > 195) && (aData[1] < 200)) // the > 195 is redundant
+  if ((data[1] > 195) && (data[1] < 200)) // the > 195 is redundant
     return true;
 
-  if ((aData[1] >= 200) && (aData[1] <= 207)) // SR, RR, SDES, BYE,
+  if ((data[1] >= 200) && (data[1] <= 207)) // SR, RR, SDES, BYE,
     return false;                           // APP, RTPFB, PSFB, XR
 
   MOZ_ASSERT(false); // Not reached, belt and suspenders.
   return true;
 }
 
 TransportResult
-TransportLayerSrtp::SendPacket(const unsigned char* data, size_t len)
+TransportLayerSrtp::SendPacket(MediaPacket& packet)
 {
-  if (len < 4) {
+  if (packet.len() < 4) {
     MOZ_ASSERT(false);
     return TE_ERROR;
   }
 
-  // Make copy and add some room to expand.
-  nsAutoPtr<DataBuffer> buf(
-    new DataBuffer(data, len, len + SRTP_MAX_EXPANSION));
+  MOZ_ASSERT(packet.capacity() - packet.len() >= SRTP_MAX_EXPANSION);
 
   int out_len;
   nsresult res;
-  if (IsRtp(data, len)) {
-    MOZ_MTLOG(ML_INFO, "Attempting to protect RTP...");
-    res = mSendSrtp->ProtectRtp(
-      buf->data(), buf->len(), buf->capacity(), &out_len);
-  } else {
-    MOZ_MTLOG(ML_INFO, "Attempting to protect RTCP...");
-    res = mSendSrtp->ProtectRtcp(
-      buf->data(), buf->len(), buf->capacity(), &out_len);
+  switch (packet.type()) {
+    case MediaPacket::RTP:
+      MOZ_MTLOG(ML_INFO, "Attempting to protect RTP...");
+      res = mSendSrtp->ProtectRtp(packet.data(), packet.len(), packet.capacity(), &out_len);
+      break;
+    case MediaPacket::RTCP:
+      MOZ_MTLOG(ML_INFO, "Attempting to protect RTCP...");
+      res = mSendSrtp->ProtectRtcp(packet.data(), packet.len(), packet.capacity(), &out_len);
+      break;
+    default:
+      MOZ_CRASH("SRTP layer asked to send packet that is neither RTP or RTCP");
   }
 
   if (NS_FAILED(res)) {
     MOZ_MTLOG(ML_ERROR,
-                "Error protecting RTP/RTCP len=" << len
+                "Error protecting RTP/RTCP len=" << packet.len()
                 << "[" << std::hex
-                << buf->data()[0] << " "
-                << buf->data()[1] << " "
-                << buf->data()[2] << " "
-                << buf->data()[3]
+                << packet.data()[0] << " "
+                << packet.data()[1] << " "
+                << packet.data()[2] << " "
+                << packet.data()[3]
                 << "]");
     return TE_ERROR;
   }
 
-  // paranoia; don't have uninitialized bytes included in data->len()
-  buf->SetLength(out_len);
+  size_t unencrypted_len = packet.len();
+  packet.SetLength(out_len);
 
-  TransportResult bytes = downward_->SendPacket(buf->data(), buf->len());
-  if (bytes == static_cast<int>(buf->len())) {
+  TransportResult bytes = downward_->SendPacket(packet);
+  if (bytes == out_len) {
     // Whole packet was written, but the encrypted length might be different.
     // Don't confuse the caller.
-    return len;
+    return unencrypted_len;
   }
 
   if (bytes == TE_WOULDBLOCK) {
     return TE_WOULDBLOCK;
   }
 
   return TE_ERROR;
 }
@@ -212,56 +211,63 @@ TransportLayerSrtp::StateChange(Transpor
 
     MOZ_MTLOG(ML_INFO, "Created SRTP flow!");
   }
 
   TL_SET_STATE(state);
 }
 
 void
-TransportLayerSrtp::PacketReceived(TransportLayer* layer,
-                                   const unsigned char *data,
-                                   size_t len)
+TransportLayerSrtp::PacketReceived(TransportLayer* layer, MediaPacket& packet)
 {
   if (state() != TS_OPEN) {
     return;
   }
 
-  if (len < 4) {
+  if (!packet.data()) {
+    // Something ate this, probably the DTLS layer
+    return;
+  }
+
+  if (packet.len() < 4) {
     return;
   }
 
   // not RTP/RTCP per RFC 7983
-  if (data[0] <= 127 || data[0] >= 192) {
+  if (packet.data()[0] <= 127 || packet.data()[0] >= 192) {
     return;
   }
 
-  // Make a copy rather than cast away constness
-  auto innerData = MakeUnique<unsigned char[]>(len);
-  memcpy(innerData.get(), data, len);
+  // We want to keep the encrypted packet around for packet dumping
+  packet.CopyDataToEncrypted();
   int outLen;
   nsresult res;
 
-  if (IsRtp(innerData.get(), len)) {
+  if (IsRtp(packet.data(), packet.len())) {
+    packet.SetType(MediaPacket::RTP);
     MOZ_MTLOG(ML_INFO, "Attempting to unprotect RTP...");
-    res = mRecvSrtp->UnprotectRtp(innerData.get(), len, len, &outLen);
+    res = mRecvSrtp->UnprotectRtp(packet.data(), packet.len(), packet.len(), &outLen);
   } else {
+    packet.SetType(MediaPacket::RTCP);
     MOZ_MTLOG(ML_INFO, "Attempting to unprotect RTCP...");
-    res = mRecvSrtp->UnprotectRtcp(innerData.get(), len, len, &outLen);
+    res = mRecvSrtp->UnprotectRtcp(packet.data(), packet.len(), packet.len(), &outLen);
   }
 
   if (NS_SUCCEEDED(res)) {
-    SignalPacketReceived(this, innerData.get(), outLen);
+    packet.SetLength(outLen);
+    SignalPacketReceived(this, packet);
   } else {
+    // TODO: What do we do wrt packet dumping here? Maybe signal an empty
+    // packet? Signal the still-encrypted packet?
     MOZ_MTLOG(ML_ERROR,
-                "Error unprotecting RTP/RTCP len=" << len
+                "Error unprotecting RTP/RTCP len=" << packet.len()
                 << "[" << std::hex
-                << innerData[0] << " "
-                << innerData[1] << " "
-                << innerData[2] << " "
-                << innerData[3]
+                << packet.data()[0] << " "
+                << packet.data()[1] << " "
+                << packet.data()[2] << " "
+                << packet.data()[3]
                 << "]");
   }
 }
 
 } // namespace mozilla
 
 
--- a/media/mtransport/transportlayersrtp.h
+++ b/media/mtransport/transportlayersrtp.h
@@ -19,22 +19,21 @@ class TransportLayerDtls;
 
 class TransportLayerSrtp final : public TransportLayer {
   public:
     explicit TransportLayerSrtp(TransportLayerDtls& dtls);
     virtual ~TransportLayerSrtp() {};
 
     // Transport layer overrides.
     void WasInserted() override;
-    TransportResult SendPacket(const unsigned char *data, size_t len) override;
+    TransportResult SendPacket(MediaPacket& packet) override;
 
     // Signals
     void StateChange(TransportLayer *layer, State state);
-    void PacketReceived(TransportLayer* layer, const unsigned char *data,
-                        size_t len);
+    void PacketReceived(TransportLayer* layer, MediaPacket& packet);
 
     TRANSPORT_LAYER_ID("srtp")
 
   private:
     bool Setup();
     DISALLOW_COPY_ASSIGN(TransportLayerSrtp);
     RefPtr<SrtpFlow> mSendSrtp;
     RefPtr<SrtpFlow> mRecvSrtp;
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -25,17 +25,16 @@
 #include "MediaStreamGraphImpl.h"
 #include "MediaStreamListener.h"
 #include "MediaStreamTrack.h"
 #include "MediaStreamVideoSink.h"
 #include "RtpLogger.h"
 #include "VideoSegment.h"
 #include "VideoStreamTrack.h"
 #include "VideoUtils.h"
-#include "databuffer.h"
 #include "libyuv/convert.h"
 #include "mozilla/PeerIdentity.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/SharedThreadPool.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/UniquePtrExtensions.h"
 #include "mozilla/dom/RTCStatsReportBinding.h"
@@ -918,32 +917,18 @@ MediaPipeline::TransportReady_s(Transpor
              ToString(aInfo.mType));
 
   if (mDirection == DirectionType::RECEIVE) {
     CSFLogInfo(LOGTAG,
                "Listening for %s packets received on %p",
                ToString(aInfo.mType),
                aInfo.mSrtp);
 
-    switch (aInfo.mType) {
-      case RTP:
-        aInfo.mSrtp->SignalPacketReceived.connect(
-          this, &MediaPipeline::RtpPacketReceived);
-        break;
-      case RTCP:
-        aInfo.mSrtp->SignalPacketReceived.connect(
-          this, &MediaPipeline::RtcpPacketReceived);
-        break;
-      case MUX:
-        aInfo.mSrtp->SignalPacketReceived.connect(
-          this, &MediaPipeline::PacketReceived);
-        break;
-      default:
-        MOZ_CRASH();
-    }
+    aInfo.mSrtp->SignalPacketReceived.connect(
+        this, &MediaPipeline::PacketReceived);
   }
 
   aInfo.mState = StateType::MP_OPEN;
   UpdateRtcpMuxState(aInfo);
   return NS_OK;
 }
 
 nsresult
@@ -973,24 +958,24 @@ MediaPipeline::UpdateRtcpMuxState(Transp
   if (aInfo.mType == MUX) {
     if (aInfo.mTransport == mRtcp.mTransport) {
       mRtcp.mState = aInfo.mState;
     }
   }
 }
 
 nsresult
-MediaPipeline::SendPacket(TransportLayer* aLayer, const void* aData, int aLen)
+MediaPipeline::SendPacket(TransportLayer* aLayer, MediaPacket& packet)
 {
   ASSERT_ON_THREAD(mStsThread);
 
-  TransportResult res =
-    aLayer->SendPacket(static_cast<const unsigned char*>(aData), aLen);
+  int len = packet.len();
+  TransportResult res = aLayer->SendPacket(packet);
 
-  if (res != aLen) {
+  if (res != len) {
     // Ignore blocking indications
     if (res == TE_WOULDBLOCK)
       return NS_OK;
 
     CSFLogError(LOGTAG, "Failed write on stream %s", mDescription.c_str());
     return NS_BASE_STREAM_CLOSED;
   }
 
@@ -1057,19 +1042,17 @@ MediaPipeline::IncrementRtcpPacketsRecei
                mDescription.c_str(),
                this,
                static_cast<void*>(mRtp.mTransport),
                mRtcpPacketsReceived);
   }
 }
 
 void
-MediaPipeline::RtpPacketReceived(TransportLayer* aLayer,
-                                 const unsigned char* aData,
-                                 size_t aLen)
+MediaPipeline::RtpPacketReceived(TransportLayer* aLayer, MediaPacket& packet)
 {
   if (mDirection == DirectionType::TRANSMIT) {
     return;
   }
 
   if (!mTransport->Pipeline()) {
     CSFLogError(LOGTAG, "Discarding incoming packet; transport disconnected");
     return;
@@ -1085,27 +1068,22 @@ MediaPipeline::RtpPacketReceived(Transpo
     return;
   }
 
   if (mRtp.mSrtp->state() != TransportLayer::TS_OPEN) {
     CSFLogError(LOGTAG, "Discarding incoming packet; transport not open");
     return;
   }
 
-  if (!aLen) {
-    return;
-  }
-
-  // Filter out everything but RTP/RTCP
-  if (aData[0] < 128 || aData[0] > 191) {
+  if (!packet.len()) {
     return;
   }
 
   webrtc::RTPHeader header;
-  if (!mRtpParser->Parse(aData, aLen, &header, true)) {
+  if (!mRtpParser->Parse(packet.data(), packet.len(), &header, true)) {
     return;
   }
 
   if (mFilter && !mFilter->Filter(header)) {
     return;
   }
 
   // Make sure to only get the time once, and only if we need it by
@@ -1141,36 +1119,36 @@ MediaPipeline::RtpPacketReceived(Transpo
         mCsrcStats.insert(std::make_pair(
           header.arrOfCSRCs[i], RtpCSRCStats(header.arrOfCSRCs[i], now)));
       } else {
         csrcInfo->second.SetTimestamp(now);
       }
     }
   }
 
-  mPacketDumper->Dump(mLevel, dom::mozPacketDumpType::Srtp, false, aData, aLen);
-
   CSFLogDebug(LOGTAG, "%s received RTP packet.", mDescription.c_str());
-  IncrementRtpPacketsReceived(aLen);
+  IncrementRtpPacketsReceived(packet.len());
   OnRtpPacketReceived();
 
-  RtpLogger::LogPacket(
-    aData, aLen, true, true, header.headerLength, mDescription);
+  RtpLogger::LogPacket(packet, true, header.headerLength, mDescription);
+
+  // Might be nice to pass ownership of the buffer in this case, but it is a
+  // small optimization in a rare case.
+  mPacketDumper->Dump(
+    mLevel, dom::mozPacketDumpType::Srtp, false, packet.encrypted_data(), packet.encrypted_len());
 
   mPacketDumper->Dump(
-    mLevel, dom::mozPacketDumpType::Rtp, false, aData, aLen);
+    mLevel, dom::mozPacketDumpType::Rtp, false, packet.data(), packet.len());
 
   (void)mConduit->ReceivedRTPPacket(
-    aData, aLen, header.ssrc); // Ignore error codes
+    packet.data(), packet.len(), header.ssrc); // Ignore error codes
 }
 
 void
-MediaPipeline::RtcpPacketReceived(TransportLayer* aLayer,
-                                  const unsigned char* aData,
-                                  size_t aLen)
+MediaPipeline::RtcpPacketReceived(TransportLayer* aLayer, MediaPacket& packet)
 {
   if (!mTransport->Pipeline()) {
     CSFLogDebug(LOGTAG, "Discarding incoming packet; transport disconnected");
     return;
   }
 
   if (!mConduit) {
     CSFLogDebug(LOGTAG, "Discarding incoming packet; media disconnected");
@@ -1182,94 +1160,60 @@ MediaPipeline::RtcpPacketReceived(Transp
     return;
   }
 
   if (mRtcp.mSrtp->state() != TransportLayer::TS_OPEN) {
     CSFLogError(LOGTAG, "Discarding incoming packet; transport not open");
     return;
   }
 
-  if (!aLen) {
-    return;
-  }
-
-  // Filter out everything but RTP/RTCP
-  if (aData[0] < 128 || aData[0] > 191) {
+  if (!packet.len()) {
     return;
   }
 
   // We do not filter receiver reports, since the webrtc.org code for
   // senders already has logic to ignore RRs that do not apply.
   // TODO bug 1279153: remove SR check for reduced size RTCP
-  if (mFilter && !mFilter->FilterSenderReport(aData, aLen)) {
+  if (mFilter && !mFilter->FilterSenderReport(packet.data(), packet.len())) {
     CSFLogWarn(LOGTAG, "Dropping incoming RTCP packet; filtered out");
     return;
   }
 
-  mPacketDumper->Dump(mLevel, dom::mozPacketDumpType::Srtcp, false, aData, aLen);
-
   CSFLogDebug(LOGTAG, "%s received RTCP packet.", mDescription.c_str());
   IncrementRtcpPacketsReceived();
 
-  RtpLogger::LogPacket(aData, aLen, true, false, 0, mDescription);
-
-  mPacketDumper->Dump(mLevel, dom::mozPacketDumpType::Rtcp, false, aData, aLen);
-
-  (void)mConduit->ReceivedRTCPPacket(aData, aLen); // Ignore error codes
-}
-
-bool
-MediaPipeline::IsRtp(const unsigned char* aData, size_t aLen) const
-{
-  if (aLen < 2)
-    return false;
-
-  // Check if this is a RTCP packet. Logic based on the types listed in
-  // media/webrtc/trunk/src/modules/rtp_rtcp/source/rtp_utility.cc
-
-  // Anything outside this range is RTP.
-  if ((aData[1] < 192) || (aData[1] > 207))
-    return true;
+  RtpLogger::LogPacket(packet, true, 0, mDescription);
 
-  if (aData[1] == 192) // FIR
-    return false;
-
-  if (aData[1] == 193) // NACK, but could also be RTP. This makes us sad
-    return true;      // but it's how webrtc.org behaves.
-
-  if (aData[1] == 194)
-    return true;
+  // Might be nice to pass ownership of the buffer in this case, but it is a
+  // small optimization in a rare case.
+  mPacketDumper->Dump(
+    mLevel, dom::mozPacketDumpType::Srtcp, false, packet.encrypted_data(), packet.encrypted_len());
 
-  if (aData[1] == 195) // IJ.
-    return false;
-
-  if ((aData[1] > 195) && (aData[1] < 200)) // the > 195 is redundant
-    return true;
+  mPacketDumper->Dump(mLevel, dom::mozPacketDumpType::Rtcp, false, packet.data(), packet.len());
 
-  if ((aData[1] >= 200) && (aData[1] <= 207)) // SR, RR, SDES, BYE,
-    return false;                           // APP, RTPFB, PSFB, XR
-
-  MOZ_ASSERT(false); // Not reached, belt and suspenders.
-  return true;
+  (void)mConduit->ReceivedRTCPPacket(packet.data(), packet.len()); // Ignore error codes
 }
 
 void
-MediaPipeline::PacketReceived(TransportLayer* aLayer,
-                              const unsigned char* aData,
-                              size_t aLen)
+MediaPipeline::PacketReceived(TransportLayer* aLayer, MediaPacket& packet)
 {
   if (!mTransport->Pipeline()) {
     CSFLogDebug(LOGTAG, "Discarding incoming packet; transport disconnected");
     return;
   }
 
-  if (IsRtp(aData, aLen)) {
-    RtpPacketReceived(aLayer, aData, aLen);
-  } else {
-    RtcpPacketReceived(aLayer, aData, aLen);
+  switch (packet.type()) {
+    case MediaPacket::RTP:
+      RtpPacketReceived(aLayer, packet);
+      break;
+    case MediaPacket::RTCP:
+      RtcpPacketReceived(aLayer, packet);
+      break;
+    default:
+      MOZ_CRASH("TransportLayerSrtp let something other than RTP/RTCP through");
   }
 }
 
 class MediaPipelineTransmit::PipelineListener : public MediaStreamVideoSink
 {
   friend class MediaPipelineTransmit;
 
 public:
@@ -1659,101 +1603,101 @@ MediaPipeline::GetTransportInfo_s(Transp
   }
 
   return nullptr;
 }
 
 nsresult
 MediaPipeline::PipelineTransport::SendRtpPacket(const uint8_t* aData, size_t aLen)
 {
-  // Might be nice to avoid this copy.
-  nsAutoPtr<DataBuffer> buf(new DataBuffer(aData, aLen));
+  nsAutoPtr<MediaPacket> packet(new MediaPacket);
+  packet->Copy(aData, aLen, aLen + SRTP_MAX_EXPANSION);
+  packet->SetType(MediaPacket::RTP);
 
   RUN_ON_THREAD(
     mStsThread,
     WrapRunnable(RefPtr<MediaPipeline::PipelineTransport>(this),
                  &MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
-                 buf,
-                 true),
+                 packet),
     NS_DISPATCH_NORMAL);
 
   return NS_OK;
 }
 
 nsresult
 MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s(
-  nsAutoPtr<DataBuffer> aData,
-  bool aIsRtp)
+  nsAutoPtr<MediaPacket> aPacket)
 {
+  bool isRtp = aPacket->type() == MediaPacket::RTP;
+
   ASSERT_ON_THREAD(mStsThread);
   if (!mPipeline) {
     return NS_OK; // Detached
   }
-  TransportInfo& transport = aIsRtp ? mPipeline->mRtp : mPipeline->mRtcp;
+
+  TransportInfo& transport = isRtp ? mPipeline->mRtp : mPipeline->mRtcp;
 
   if (transport.mSrtp->state() != TransportLayer::TS_OPEN) {
     // SRTP not ready yet.
     return NS_OK;
   }
 
   MOZ_ASSERT(transport.mTransport);
   NS_ENSURE_TRUE(transport.mTransport, NS_ERROR_NULL_POINTER);
 
+  MediaPacket packet(std::move(*aPacket));
+  packet.sdp_level() = Some(mPipeline->Level());
+
   if (RtpLogger::IsPacketLoggingOn()) {
     int headerLen = 12;
     webrtc::RTPHeader header;
     if (mPipeline->mRtpParser &&
-        mPipeline->mRtpParser->Parse(aData->data(), aData->len(), &header)) {
+        mPipeline->mRtpParser->Parse(packet.data(), packet.len(), &header)) {
       headerLen = header.headerLength;
     }
-    RtpLogger::LogPacket(aData->data(),
-                         aData->len(),
-                         false,
-                         aIsRtp,
-                         headerLen,
-                         mPipeline->mDescription);
+    RtpLogger::LogPacket(packet, false, headerLen, mPipeline->mDescription);
   }
 
-  if (aIsRtp) {
+  if (isRtp) {
     mPipeline->mPacketDumper->Dump(mPipeline->Level(),
                                     dom::mozPacketDumpType::Rtp,
                                     true,
-                                    aData->data(),
-                                    aData->len());
-    mPipeline->IncrementRtpPacketsSent(aData->len());
+                                    packet.data(),
+                                    packet.len());
+    mPipeline->IncrementRtpPacketsSent(packet.len());
   } else {
     mPipeline->mPacketDumper->Dump(mPipeline->Level(),
                                     dom::mozPacketDumpType::Rtcp,
                                     true,
-                                    aData->data(),
-                                    aData->len());
+                                    packet.data(),
+                                    packet.len());
     mPipeline->IncrementRtcpPacketsSent();
   }
 
   CSFLogDebug(LOGTAG,
               "%s sending %s packet",
               mPipeline->mDescription.c_str(),
-              (aIsRtp ? "RTP" : "RTCP"));
+              (isRtp ? "RTP" : "RTCP"));
 
-  return mPipeline->SendPacket(transport.mSrtp, aData->data(), aData->len());
+  return mPipeline->SendPacket(transport.mSrtp, packet);
 }
 
 nsresult
 MediaPipeline::PipelineTransport::SendRtcpPacket(const uint8_t* aData,
                                                  size_t aLen)
 {
-  // Might be nice to avoid this copy.
-  nsAutoPtr<DataBuffer> buf(new DataBuffer(aData, aLen));
+  nsAutoPtr<MediaPacket> packet(new MediaPacket);
+  packet->Copy(aData, aLen, aLen + SRTP_MAX_EXPANSION);
+  packet->SetType(MediaPacket::RTCP);
 
   RUN_ON_THREAD(
     mStsThread,
     WrapRunnable(RefPtr<MediaPipeline::PipelineTransport>(this),
                  &MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
-                 buf,
-                 false),
+                 packet),
     NS_DISPATCH_NORMAL);
 
   return NS_OK;
 }
 
 // Called if we're attached with AddDirectListener()
 void
 MediaPipelineTransmit::PipelineListener::NotifyRealtimeTrackData(
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
@@ -11,17 +11,17 @@
 #include <map>
 
 #include "sigslot.h"
 
 #include "signaling/src/media-conduit/MediaConduitInterface.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/Atomics.h"
 #include "SrtpFlow.h"
-#include "databuffer.h"
+#include "mediapacket.h"
 #include "mtransport/runnable_utils.h"
 #include "mtransport/transportflow.h"
 #include "AudioPacketizer.h"
 #include "StreamTracks.h"
 #include "signaling/src/peerconnection/PacketDumper.h"
 
 #include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
 
@@ -194,17 +194,17 @@ public:
     void Attach(MediaPipeline* pipeline) { mPipeline = pipeline; }
     void Detach() { mPipeline = nullptr; }
     MediaPipeline* Pipeline() const { return mPipeline; }
 
     virtual nsresult SendRtpPacket(const uint8_t* aData, size_t aLen) override;
     virtual nsresult SendRtcpPacket(const uint8_t* aData, size_t aLen) override;
 
   private:
-    nsresult SendRtpRtcpPacket_s(nsAutoPtr<DataBuffer> aData, bool aIsRtp);
+    nsresult SendRtpRtcpPacket_s(nsAutoPtr<MediaPacket> aData);
 
     // Creates a cycle, which we break with Detach
     RefPtr<MediaPipeline> mPipeline;
     const nsCOMPtr<nsIEventTarget> mStsThread;
   };
 
 protected:
   virtual ~MediaPipeline();
@@ -245,30 +245,23 @@ protected:
 
   void IncrementRtpPacketsSent(int aBytes);
   void IncrementRtcpPacketsSent();
   void IncrementRtpPacketsReceived(int aBytes);
   virtual void OnRtpPacketReceived() {};
   void IncrementRtcpPacketsReceived();
 
   virtual nsresult SendPacket(TransportLayer* aLayer,
-                              const void* aData,
-                              int aLen);
+                              MediaPacket& packet);
 
   // Process slots on transports
   void StateChange(TransportLayer* aLayer, TransportLayer::State);
-  void RtpPacketReceived(TransportLayer* aLayer,
-                         const unsigned char* aData,
-                         size_t aLen);
-  void RtcpPacketReceived(TransportLayer* aLayer,
-                          const unsigned char* aData,
-                          size_t aLen);
-  void PacketReceived(TransportLayer* aLayer,
-                      const unsigned char* aData,
-                      size_t aLen);
+  void RtpPacketReceived(TransportLayer* aLayer, MediaPacket& packet);
+  void RtcpPacketReceived(TransportLayer* aLayer, MediaPacket& packet);
+  void PacketReceived(TransportLayer* aLayer, MediaPacket& packet);
 
   void SetDescription_s(const std::string& description);
 
   const DirectionType mDirection;
   size_t mLevel;
   RefPtr<MediaSessionConduit> mConduit; // Our conduit. Written on the main
                                         // thread. Read on STS thread.
 
--- a/media/webrtc/signaling/src/mediapipeline/RtpLogger.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/RtpLogger.cpp
@@ -28,18 +28,19 @@ static const char* rlLogTag = "RtpLogger
 #define LOGTAG rlLogTag
 
 namespace mozilla {
 
 bool RtpLogger::IsPacketLoggingOn() {
   return CSFLogTestLevel(CSF_LOG_DEBUG);
 }
 
-void RtpLogger::LogPacket(const unsigned char *data, int len, bool input,
-                          bool isRtp, int headerLength, std::string desc) {
+void RtpLogger::LogPacket(const MediaPacket& packet, bool input,
+                          size_t headerLength, std::string desc) {
+  bool isRtp = (packet.type() == MediaPacket::RTP);
   if (CSFLogTestLevel(CSF_LOG_DEBUG)) {
     std::stringstream ss;
     /* This creates text2pcap compatible format, e.g.:
      *   O 10:36:26.864934  000000 80 c8 00 06 6d ... RTCP_PACKET
      */
     ss << (input ? "I " : "O ");
     std::time_t t = std::time(nullptr);
     std::tm tm = *std::localtime(&t);
@@ -54,27 +55,27 @@ void RtpLogger::LogPacket(const unsigned
     ss << "." << (tb.millitm) << " ";
 #else
     struct timeval tv;
     gettimeofday(&tv, NULL);
     ss << "." << (tv.tv_usec) << " ";
 #endif
     ss << " 000000";
     ss << std::hex << std::setfill('0');
-    int offset_ = headerLength;
-    if (isRtp && (offset_ + 5 < len)) {
+    size_t offset_ = headerLength;
+    if (isRtp && (offset_ + 5 < packet.len())) {
       // Allow the first 5 bytes of the payload in clear
       offset_ += 5;
     }
-    for (int i=0; i < len; ++i) {
+    for (size_t i=0; i < packet.len(); ++i) {
       if (isRtp && i > offset_) {
         ss << " 00";
       }
       else {
-        ss << " " << std::setw(2) << (int)data[i];
+        ss << " " << std::setw(2) << (int)packet.data()[i];
       }
     }
     CSFLogDebug(LOGTAG, "%s%s%s", ss.str().c_str(),
                 (isRtp ? " RTP_PACKET " : " RTCP_PACKET "), desc.c_str());
   }
 }
 
 }  // end of namespace
--- a/media/webrtc/signaling/src/mediapipeline/RtpLogger.h
+++ b/media/webrtc/signaling/src/mediapipeline/RtpLogger.h
@@ -3,26 +3,27 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Original author: nohlmeier@mozilla.com
 
 #ifndef rtplogger_h__
 #define rtplogger_h__
 
 #include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
+#include "mtransport/mediapacket.h"
 
 namespace mozilla {
 
 /* This class logs RTP and RTCP packets in hex in a format compatible to
  * text2pcap.
  * Example to convert the MOZ log file into a PCAP file:
  *   egrep '(RTP_PACKET|RTCP_PACKET)' moz.log | text2pcap -D -n -l 1 -i 17 -u 1234,1235 -t '%H:%M:%S.' - rtp.pcap
  */
 class RtpLogger {
 public:
   static bool IsPacketLoggingOn();
-  static void LogPacket(const unsigned char *data, int len, bool input,
-                        bool isRtp, int headerLength, std::string desc);
+  static void LogPacket(const MediaPacket& packet, bool input,
+                        size_t headerLength, std::string desc);
 };
 
 }  // End of namespace
 #endif
 
copy from media/mtransport/transportlayersrtp.cpp
copy to media/webrtc/signaling/src/mediapipeline/TransportLayerPacketDumper.cpp
--- a/media/mtransport/transportlayersrtp.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/TransportLayerPacketDumper.cpp
@@ -1,267 +1,77 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Original author: ekr@rtfm.com
 
-#include "transportlayersrtp.h"
-#include "transportlayerdtls.h"
+#include "TransportLayerPacketDumper.h"
 
 #include "logging.h"
 #include "nsError.h"
 #include "mozilla/Assertions.h"
-#include "transportlayerdtls.h"
-#include "srtp.h"
-#include "databuffer.h"
-#include "nsAutoPtr.h"
 
 namespace mozilla {
 
 MOZ_MTLOG_MODULE("mtransport")
 
-static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
-
-TransportLayerSrtp::TransportLayerSrtp(TransportLayerDtls& dtls)
-{
-  // We need to connect to the dtls layer, not the ice layer, because even
-  // though the packets that DTLS decrypts don't flow through us, we do base our
-  // keying information on the keying information established by the DTLS layer.
-  dtls.SignalStateChange.connect(this, &TransportLayerSrtp::StateChange);
-
-  TL_SET_STATE(dtls.state());
-}
+TransportLayerPacketDumper::TransportLayerPacketDumper(
+    nsAutoPtr<PacketDumper>&& aPacketDumper, dom::mozPacketDumpType aType) :
+  mPacketDumper(std::move(aPacketDumper)),
+  mType(aType)
+{}
 
 void
-TransportLayerSrtp::WasInserted()
-{
-  // Connect to the lower layers
-  if (!Setup()) {
-    TL_SET_STATE(TS_ERROR);
-  }
-}
-
-bool
-TransportLayerSrtp::Setup()
+TransportLayerPacketDumper::WasInserted()
 {
   CheckThread();
   if (!downward_) {
-    MOZ_MTLOG(ML_ERROR, "SRTP layer with nothing below. This is useless");
-    return false;
+    MOZ_MTLOG(ML_ERROR, "Packet dumper with nothing below. This is useless");
+    TL_SET_STATE(TS_ERROR);
   }
 
-  // downward_ is the TransportLayerIce
-  downward_->SignalPacketReceived.connect(this, &TransportLayerSrtp::PacketReceived);
-
-  return true;
-}
-
-static bool
-IsRtp(const unsigned char* aData, size_t aLen)
-{
-  if (aLen < 2)
-    return false;
-
-  // Check if this is a RTCP packet. Logic based on the types listed in
-  // media/webrtc/trunk/src/modules/rtp_rtcp/source/rtp_utility.cc
-
-  // Anything outside this range is RTP.
-  if ((aData[1] < 192) || (aData[1] > 207))
-    return true;
-
-  if (aData[1] == 192) // FIR
-    return false;
-
-  if (aData[1] == 193) // NACK, but could also be RTP. This makes us sad
-    return true;      // but it's how webrtc.org behaves.
-
-  if (aData[1] == 194)
-    return true;
-
-  if (aData[1] == 195) // IJ.
-    return false;
-
-  if ((aData[1] > 195) && (aData[1] < 200)) // the > 195 is redundant
-    return true;
-
-  if ((aData[1] >= 200) && (aData[1] <= 207)) // SR, RR, SDES, BYE,
-    return false;                           // APP, RTPFB, PSFB, XR
-
-  MOZ_ASSERT(false); // Not reached, belt and suspenders.
-  return true;
+  downward_->SignalStateChange.connect(this,
+      &TransportLayerPacketDumper::StateChange);
+  downward_->SignalPacketReceived.connect(this,
+      &TransportLayerPacketDumper::PacketReceived);
 }
 
 TransportResult
-TransportLayerSrtp::SendPacket(const unsigned char* data, size_t len)
+TransportLayerPacketDumper::SendPacket(MediaPacket& packet)
 {
-  if (len < 4) {
-    MOZ_ASSERT(false);
-    return TE_ERROR;
-  }
-
-  // Make copy and add some room to expand.
-  nsAutoPtr<DataBuffer> buf(
-    new DataBuffer(data, len, len + SRTP_MAX_EXPANSION));
-
-  int out_len;
-  nsresult res;
-  if (IsRtp(data, len)) {
-    MOZ_MTLOG(ML_INFO, "Attempting to protect RTP...");
-    res = mSendSrtp->ProtectRtp(
-      buf->data(), buf->len(), buf->capacity(), &out_len);
-  } else {
-    MOZ_MTLOG(ML_INFO, "Attempting to protect RTCP...");
-    res = mSendSrtp->ProtectRtcp(
-      buf->data(), buf->len(), buf->capacity(), &out_len);
-  }
+  if (packet.sdp_level().isSome()) {
+    dom::mozPacketDumpType dumpType = mType;
+    if (mType == dom::mozPacketDumpType::Srtp &&
+        packet.type() == MediaPacket::RTCP) {
+      dumpType = dom::mozPacketDumpType::Srtcp;
+    }
 
-  if (NS_FAILED(res)) {
-    MOZ_MTLOG(ML_ERROR,
-                "Error protecting RTP/RTCP len=" << len
-                << "[" << std::hex
-                << buf->data()[0] << " "
-                << buf->data()[1] << " "
-                << buf->data()[2] << " "
-                << buf->data()[3]
-                << "]");
-    return TE_ERROR;
+    mPacketDumper->Dump(*packet.sdp_level(),
+                        dumpType,
+                        true,
+                        packet.data(),
+                        packet.len());
   }
-
-  // paranoia; don't have uninitialized bytes included in data->len()
-  buf->SetLength(out_len);
-
-  TransportResult bytes = downward_->SendPacket(buf->data(), buf->len());
-  if (bytes == static_cast<int>(buf->len())) {
-    // Whole packet was written, but the encrypted length might be different.
-    // Don't confuse the caller.
-    return len;
-  }
-
-  if (bytes == TE_WOULDBLOCK) {
-    return TE_WOULDBLOCK;
-  }
-
-  return TE_ERROR;
+  return downward_->SendPacket(packet);
 }
 
 void
-TransportLayerSrtp::StateChange(TransportLayer* layer, State state)
+TransportLayerPacketDumper::StateChange(TransportLayer* aLayer, State aState)
 {
-  if (state == TS_OPEN) {
-    TransportLayerDtls* dtls = static_cast<TransportLayerDtls*>(layer);
-    MOZ_ASSERT(dtls); // DTLS is mandatory
-
-    uint16_t cipher_suite;
-    nsresult res = dtls->GetSrtpCipher(&cipher_suite);
-    if (NS_FAILED(res)) {
-      MOZ_MTLOG(ML_ERROR, "Failed to negotiate DTLS-SRTP. This is an error");
-      TL_SET_STATE(TS_ERROR);
-      return;
-    }
-
-    // SRTP Key Exporter as per RFC 5764 S 4.2
-    unsigned char srtp_block[SRTP_TOTAL_KEY_LENGTH * 2];
-    res = dtls->ExportKeyingMaterial(
-      kDTLSExporterLabel, false, "", srtp_block, sizeof(srtp_block));
-    if (NS_FAILED(res)) {
-      MOZ_MTLOG(ML_ERROR, "Failed to compute DTLS-SRTP keys. This is an error");
-      TL_SET_STATE(TS_ERROR);
-      return;
-    }
-
-    // Slice and dice as per RFC 5764 S 4.2
-    unsigned char client_write_key[SRTP_TOTAL_KEY_LENGTH];
-    unsigned char server_write_key[SRTP_TOTAL_KEY_LENGTH];
-    int offset = 0;
-    memcpy(client_write_key, srtp_block + offset, SRTP_MASTER_KEY_LENGTH);
-    offset += SRTP_MASTER_KEY_LENGTH;
-    memcpy(server_write_key, srtp_block + offset, SRTP_MASTER_KEY_LENGTH);
-    offset += SRTP_MASTER_KEY_LENGTH;
-    memcpy(client_write_key + SRTP_MASTER_KEY_LENGTH,
-           srtp_block + offset,
-           SRTP_MASTER_SALT_LENGTH);
-    offset += SRTP_MASTER_SALT_LENGTH;
-    memcpy(server_write_key + SRTP_MASTER_KEY_LENGTH,
-           srtp_block + offset,
-           SRTP_MASTER_SALT_LENGTH);
-    offset += SRTP_MASTER_SALT_LENGTH;
-    MOZ_ASSERT(offset == sizeof(srtp_block));
-
-    unsigned char* write_key;
-    unsigned char* read_key;
-
-    if (dtls->role() == TransportLayerDtls::CLIENT) {
-      write_key = client_write_key;
-      read_key = server_write_key;
-    } else {
-      write_key = server_write_key;
-      read_key = client_write_key;
-    }
-
-    MOZ_ASSERT(!mSendSrtp && !mRecvSrtp);
-    mSendSrtp =
-      SrtpFlow::Create(cipher_suite, false, write_key, SRTP_TOTAL_KEY_LENGTH);
-    mRecvSrtp =
-      SrtpFlow::Create(cipher_suite, true, read_key, SRTP_TOTAL_KEY_LENGTH);
-    if (!mSendSrtp || !mRecvSrtp) {
-      MOZ_MTLOG(ML_ERROR, "Couldn't create SRTP flow.");
-      TL_SET_STATE(TS_ERROR);
-      return;
-    }
-
-    MOZ_MTLOG(ML_INFO, "Created SRTP flow!");
-  }
-
-  TL_SET_STATE(state);
+  TL_SET_STATE(aState);
 }
 
 void
-TransportLayerSrtp::PacketReceived(TransportLayer* layer,
-                                   const unsigned char *data,
-                                   size_t len)
+TransportLayerPacketDumper::PacketReceived(TransportLayer* aLayer,
+                                           MediaPacket& packet)
 {
-  if (state() != TS_OPEN) {
-    return;
-  }
-
-  if (len < 4) {
-    return;
-  }
-
-  // not RTP/RTCP per RFC 7983
-  if (data[0] <= 127 || data[0] >= 192) {
-    return;
-  }
-
-  // Make a copy rather than cast away constness
-  auto innerData = MakeUnique<unsigned char[]>(len);
-  memcpy(innerData.get(), data, len);
-  int outLen;
-  nsresult res;
-
-  if (IsRtp(innerData.get(), len)) {
-    MOZ_MTLOG(ML_INFO, "Attempting to unprotect RTP...");
-    res = mRecvSrtp->UnprotectRtp(innerData.get(), len, len, &outLen);
-  } else {
-    MOZ_MTLOG(ML_INFO, "Attempting to unprotect RTCP...");
-    res = mRecvSrtp->UnprotectRtcp(innerData.get(), len, len, &outLen);
-  }
-
-  if (NS_SUCCEEDED(res)) {
-    SignalPacketReceived(this, innerData.get(), outLen);
-  } else {
-    MOZ_MTLOG(ML_ERROR,
-                "Error unprotecting RTP/RTCP len=" << len
-                << "[" << std::hex
-                << innerData[0] << " "
-                << innerData[1] << " "
-                << innerData[2] << " "
-                << innerData[3]
-                << "]");
-  }
+  // There's no way to know the level yet, so we can't use the packet dumper
+  // yet. We rely on the SRTP layer saving the encrypted packet in
+  // MediaPacket::encrypted_, to allow MediaPipeline to dump it later.
+  SignalPacketReceived(this, packet);
 }
 
 } // namespace mozilla
 
 
copy from media/mtransport/transportlayersrtp.h
copy to media/webrtc/signaling/src/mediapipeline/TransportLayerPacketDumper.h
--- a/media/mtransport/transportlayersrtp.h
+++ b/media/webrtc/signaling/src/mediapipeline/TransportLayerPacketDumper.h
@@ -1,45 +1,40 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef transportlayersrtp_h__
-#define transportlayersrtp_h__
-
-#include <string>
+#ifndef transportlayerpacketdumper_h__
+#define transportlayerpacketdumper_h__
 
 #include "transportlayer.h"
-#include "mozilla/RefPtr.h"
-#include "SrtpFlow.h"
+#include "signaling/src/peerconnection/PacketDumper.h"
+#include "mozilla/dom/RTCPeerConnectionBinding.h"
 
 namespace mozilla {
 
-class TransportLayerDtls;
-
-class TransportLayerSrtp final : public TransportLayer {
+class TransportLayerPacketDumper final : public TransportLayer {
   public:
-    explicit TransportLayerSrtp(TransportLayerDtls& dtls);
-    virtual ~TransportLayerSrtp() {};
+    explicit TransportLayerPacketDumper(nsAutoPtr<PacketDumper>&& aPacketDumper,
+                                        dom::mozPacketDumpType aType);
+    virtual ~TransportLayerPacketDumper() {};
 
     // Transport layer overrides.
     void WasInserted() override;
-    TransportResult SendPacket(const unsigned char *data, size_t len) override;
+    TransportResult SendPacket(MediaPacket& packet) override;
 
     // Signals
-    void StateChange(TransportLayer *layer, State state);
-    void PacketReceived(TransportLayer* layer, const unsigned char *data,
-                        size_t len);
+    void StateChange(TransportLayer *aLayer, State state);
+    void PacketReceived(TransportLayer* aLayer, MediaPacket& packet);
 
-    TRANSPORT_LAYER_ID("srtp")
+    TRANSPORT_LAYER_ID("packet-dumper")
 
   private:
-    bool Setup();
-    DISALLOW_COPY_ASSIGN(TransportLayerSrtp);
-    RefPtr<SrtpFlow> mSendSrtp;
-    RefPtr<SrtpFlow> mRecvSrtp;
+    DISALLOW_COPY_ASSIGN(TransportLayerPacketDumper);
+    nsAutoPtr<PacketDumper> mPacketDumper;
+    dom::mozPacketDumpType mType;
 };
 
 
 }  // close namespace
 #endif
--- a/media/webrtc/signaling/src/mediapipeline/moz.build
+++ b/media/webrtc/signaling/src/mediapipeline/moz.build
@@ -18,11 +18,12 @@ LOCAL_INCLUDES += [
     '/netwerk/srtp/src/crypto/include',
     '/netwerk/srtp/src/include',
 ]
 
 UNIFIED_SOURCES += [
     'MediaPipeline.cpp',
     'MediaPipelineFilter.cpp',
     'RtpLogger.cpp',
+    'TransportLayerPacketDumper.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -17,16 +17,18 @@
 #include "PeerConnectionImpl.h"
 #include "PeerConnectionMedia.h"
 #include "runnable_utils.h"
 #include "transportlayerice.h"
 #include "transportlayerdtls.h"
 #include "transportlayersrtp.h"
 #include "signaling/src/jsep/JsepSession.h"
 #include "signaling/src/jsep/JsepTransport.h"
+#include "signaling/src/mediapipeline/TransportLayerPacketDumper.h"
+#include "signaling/src/peerconnection/PacketDumper.h"
 
 #include "nsContentUtils.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsIURI.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsICancelable.h"
 #include "nsILoadInfo.h"
@@ -523,32 +525,39 @@ PeerConnectionMedia::UpdateTransportFlow
   return UpdateTransportFlow(transportLevel, true, *aTransceiver.mTransport);
 }
 
 // Accessing the PCMedia should be safe here because we shouldn't
 // have enqueued this function unless it was still active and
 // the ICE data is destroyed on the STS.
 static void
 FinalizeTransportFlow_s(RefPtr<PeerConnectionMedia> aPCMedia,
+                        nsAutoPtr<PacketDumper> aPacketDumper,
                         RefPtr<TransportFlow> aFlow, size_t aLevel,
                         bool aIsRtcp,
                         TransportLayerIce* aIceLayer,
                         TransportLayerDtls* aDtlsLayer,
                         TransportLayerSrtp* aSrtpLayer)
 {
+  TransportLayerPacketDumper* srtpDumper(new TransportLayerPacketDumper(
+        std::move(aPacketDumper), dom::mozPacketDumpType::Srtp));
+
   aIceLayer->SetParameters(aPCMedia->ice_media_stream(aLevel),
                            aIsRtcp ? 2 : 1);
   // TODO(bug 854518): Process errors.
   (void)aIceLayer->Init();
   (void)aDtlsLayer->Init();
+  (void)srtpDumper->Init();
   (void)aSrtpLayer->Init();
   aDtlsLayer->Chain(aIceLayer);
-  aSrtpLayer->Chain(aIceLayer);
+  srtpDumper->Chain(aIceLayer);
+  aSrtpLayer->Chain(srtpDumper);
   aFlow->PushLayer(aIceLayer);
   aFlow->PushLayer(aDtlsLayer);
+  aFlow->PushLayer(srtpDumper);
   aFlow->PushLayer(aSrtpLayer);
 }
 
 static void
 AddNewIceStreamForRestart_s(RefPtr<PeerConnectionMedia> aPCMedia,
                             RefPtr<TransportFlow> aFlow,
                             size_t aLevel,
                             bool aIsRtcp)
@@ -651,19 +660,22 @@ PeerConnectionMedia::UpdateTransportFlow
     alpn.insert(alpnDefault);
   }
   rv = dtls->SetAlpn(alpn, alpnDefault);
   if (NS_FAILED(rv)) {
     CSFLogError(LOGTAG, "Couldn't set ALPN");
     return rv;
   }
 
+  nsAutoPtr<PacketDumper> packetDumper(new PacketDumper(mParent));
+
   RefPtr<PeerConnectionMedia> pcMedia(this);
   rv = GetSTSThread()->Dispatch(
-      WrapRunnableNM(FinalizeTransportFlow_s, pcMedia, flow, aLevel, aIsRtcp,
+      WrapRunnableNM(FinalizeTransportFlow_s, pcMedia, packetDumper, flow,
+                     aLevel, aIsRtcp,
                      ice.release(), dtls.release(), srtp.release()),
       NS_DISPATCH_NORMAL);
   if (NS_FAILED(rv)) {
     CSFLogError(LOGTAG, "Failed to dispatch FinalizeTransportFlow_s");
     return rv;
   }
 
   AddTransportFlow(aLevel, aIsRtcp, flow);
--- a/netwerk/sctp/datachannel/DataChannel.cpp
+++ b/netwerk/sctp/datachannel/DataChannel.cpp
@@ -812,87 +812,79 @@ DataChannelConnection::ProcessQueuedOpen
       // OpenFinish returns a reference itself, so we need to take it can Release it
       channel = OpenFinish(channel.forget()); // may reset the flag and re-push
     } else {
       NS_ASSERTION(false, "How did a DataChannel get queued without the FINISH_OPEN flag?");
     }
   }
 
 }
+
 void
-DataChannelConnection::SctpDtlsInput(TransportLayer *layer,
-                                     const unsigned char *data, size_t len)
+DataChannelConnection::SctpDtlsInput(TransportLayer *layer, MediaPacket& packet)
 {
   if (MOZ_LOG_TEST(gSCTPLog, LogLevel::Debug)) {
     char *buf;
 
-    if ((buf = usrsctp_dumppacket((void *)data, len, SCTP_DUMP_INBOUND)) != nullptr) {
+    if ((buf = usrsctp_dumppacket((void *)packet.data(),
+                                  packet.len(),
+                                  SCTP_DUMP_INBOUND)) != nullptr) {
       SCTP_LOG(("%s", buf));
       usrsctp_freedumpbuffer(buf);
     }
   }
   // Pass the data to SCTP
   MutexAutoLock lock(mLock);
-  usrsctp_conninput(static_cast<void *>(this), data, len, 0);
+  usrsctp_conninput(static_cast<void *>(this), packet.data(), packet.len(), 0);
 }
 
 int
-DataChannelConnection::SendPacket(unsigned char data[], size_t len, bool release)
+DataChannelConnection::SendPacket(nsAutoPtr<MediaPacket> packet)
 {
   //LOG(("%p: SCTP/DTLS sent %ld bytes", this, len));
-  int res = 0;
   if (mDtls) {
-    res = mDtls->SendPacket(data, len) < 0 ? 1 : 0;
+    return mDtls->SendPacket(*packet) < 0 ? 1 : 0;
   }
-  if (release)
-    delete [] data;
-  return res;
+  return 0;
 }
 
 /* static */
 int
 DataChannelConnection::SctpDtlsOutput(void *addr, void *buffer, size_t length,
                                       uint8_t tos, uint8_t set_df)
 {
   DataChannelConnection *peer = static_cast<DataChannelConnection *>(addr);
-  int res;
   MOZ_DIAGNOSTIC_ASSERT(!peer->mShutdown);
 
   if (MOZ_LOG_TEST(gSCTPLog, LogLevel::Debug)) {
     char *buf;
 
     if ((buf = usrsctp_dumppacket(buffer, length, SCTP_DUMP_OUTBOUND)) != nullptr) {
       SCTP_LOG(("%s", buf));
       usrsctp_freedumpbuffer(buf);
     }
   }
+
   // We're async proxying even if on the STSThread because this is called
   // with internal SCTP locks held in some cases (such as in usrsctp_connect()).
   // SCTP has an option for Apple, on IP connections only, to release at least
   // one of the locks before calling a packet output routine; with changes to
   // the underlying SCTP stack this might remove the need to use an async proxy.
-  if ((false /*peer->IsSTSThread()*/)) {
-    res = peer->SendPacket(static_cast<unsigned char *>(buffer), length, false);
-  } else {
-    auto *data = new unsigned char[length];
-    memcpy(data, buffer, length);
-    // Commented out since we have to Dispatch SendPacket to avoid deadlock"
-    // res = -1;
-
-    // XXX It might be worthwhile to add an assertion against the thread
-    // somehow getting into the DataChannel/SCTP code again, as
-    // DISPATCH_SYNC is not fully blocking.  This may be tricky, as it
-    // needs to be a per-thread check, not a global.
-    peer->mSTS->Dispatch(WrapRunnable(
-                           RefPtr<DataChannelConnection>(peer),
-                           &DataChannelConnection::SendPacket, data, length, true),
-                                   NS_DISPATCH_NORMAL);
-    res = 0; // cheat!  Packets can always be dropped later anyways
-  }
-  return res;
+  nsAutoPtr<MediaPacket> packet(new MediaPacket);
+  packet->Copy(static_cast<const uint8_t*>(buffer), length);
+
+  // XXX It might be worthwhile to add an assertion against the thread
+  // somehow getting into the DataChannel/SCTP code again, as
+  // DISPATCH_SYNC is not fully blocking.  This may be tricky, as it
+  // needs to be a per-thread check, not a global.
+  peer->mSTS->Dispatch(WrapRunnable(
+                         RefPtr<DataChannelConnection>(peer),
+                         &DataChannelConnection::SendPacket, packet),
+                                 NS_DISPATCH_NORMAL);
+  return 0; // cheat!  Packets can always be dropped later anyways
 }
 #endif
 
 #ifdef ALLOW_DIRECT_SCTP_LISTEN_CONNECT
 // listen for incoming associations
 // Blocks! - Don't call this from main thread!
 
 #error This code will not work as-is since SetEvenOdd() runs on Mainthread
--- a/netwerk/sctp/datachannel/DataChannel.h
+++ b/netwerk/sctp/datachannel/DataChannel.h
@@ -236,18 +236,18 @@ protected:
   // Use from main thread only as WeakPtr is not threadsafe
   WeakPtr<DataConnectionListener> mListener;
 
 private:
   friend class DataChannelConnectRunnable;
 
 #ifdef SCTP_DTLS_SUPPORTED
   static void DTLSConnectThread(void *data);
-  int SendPacket(unsigned char data[], size_t len, bool release);
-  void SctpDtlsInput(TransportLayer *layer, const unsigned char *data, size_t len);
+  int SendPacket(nsAutoPtr<MediaPacket> packet);
+  void SctpDtlsInput(TransportLayer *layer, MediaPacket& packet);
   static int SctpDtlsOutput(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df);
 #endif
   DataChannel* FindChannelByStream(uint16_t stream);
   uint16_t FindFreeStream();
   bool RequestMoreStreams(int32_t aNeeded = 16);
   uint32_t UpdateCurrentStreamIndex();
   uint32_t GetCurrentStreamIndex();
   int SendControlMessage(const uint8_t *data, uint32_t len, uint16_t stream);