rename from media/webrtc/signaling/src/mediapipeline/SrtpFlow.cpp
rename to media/mtransport/SrtpFlow.cpp
--- a/media/webrtc/signaling/src/mediapipeline/SrtpFlow.cpp
+++ b/media/mtransport/SrtpFlow.cpp
@@ -8,26 +8,21 @@
#include "SrtpFlow.h"
#include "srtp.h"
#include "ssl.h"
#include "sslproto.h"
#include "mozilla/RefPtr.h"
-static const char* sfLogTag = "SrtpFlow";
-#ifdef LOGTAG
-#undef LOGTAG
-#endif
-#define LOGTAG sfLogTag
-
using namespace mozilla;
namespace mozilla {
+MOZ_MTLOG_MODULE("mtransport")
bool SrtpFlow::initialized; // Static
SrtpFlow::~SrtpFlow() {
if (session_) {
srtp_dealloc(session_);
}
}
@@ -37,97 +32,97 @@ RefPtr<SrtpFlow> SrtpFlow::Create(int ci
size_t key_len) {
nsresult res = Init();
if (!NS_SUCCEEDED(res))
return nullptr;
RefPtr<SrtpFlow> flow = new SrtpFlow();
if (!key) {
- CSFLogError(LOGTAG, "Null SRTP key specified");
+ MOZ_MTLOG(ML_ERROR, "Null SRTP key specified");
return nullptr;
}
if (key_len != SRTP_TOTAL_KEY_LENGTH) {
- CSFLogError(LOGTAG, "Invalid SRTP key length");
+ MOZ_MTLOG(ML_ERROR, "Invalid SRTP key length");
return nullptr;
}
srtp_policy_t policy;
memset(&policy, 0, sizeof(srtp_policy_t));
// Note that we set the same cipher suite for RTP and RTCP
// since any flow can only have one cipher suite with DTLS-SRTP
switch (cipher_suite) {
case SRTP_AES128_CM_HMAC_SHA1_80:
- CSFLogDebug(LOGTAG,
+ MOZ_MTLOG(ML_DEBUG,
"Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_80");
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
break;
case SRTP_AES128_CM_HMAC_SHA1_32:
- CSFLogDebug(LOGTAG,
+ MOZ_MTLOG(ML_DEBUG,
"Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_32");
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); // 80-bit per RFC 5764
break; // S 4.1.2.
default:
- CSFLogError(LOGTAG, "Request to set unknown SRTP cipher suite");
+ MOZ_MTLOG(ML_ERROR, "Request to set unknown SRTP cipher suite");
return nullptr;
}
// This key is copied into the srtp_t object, so we don't
// need to keep it.
policy.key = const_cast<unsigned char *>(
static_cast<const unsigned char *>(key));
policy.ssrc.type = inbound ? ssrc_any_inbound : ssrc_any_outbound;
policy.ssrc.value = 0;
policy.ekt = nullptr;
policy.window_size = 1024; // Use the Chrome value. Needs to be revisited. Default is 128
policy.allow_repeat_tx = 1; // Use Chrome value; needed for NACK mode to work
policy.next = nullptr;
// Now make the session
srtp_err_status_t r = srtp_create(&flow->session_, &policy);
if (r != srtp_err_status_ok) {
- CSFLogError(LOGTAG, "Error creating srtp session");
+ MOZ_MTLOG(ML_ERROR, "Error creating srtp session");
return nullptr;
}
return flow;
}
nsresult SrtpFlow::CheckInputs(bool protect, void *in, int in_len,
int max_len, int *out_len) {
MOZ_ASSERT(in);
if (!in) {
- CSFLogError(LOGTAG, "NULL input value");
+ MOZ_MTLOG(ML_ERROR, "NULL input value");
return NS_ERROR_NULL_POINTER;
}
if (in_len < 0) {
- CSFLogError(LOGTAG, "Input length is negative");
+ MOZ_MTLOG(ML_ERROR, "Input length is negative");
return NS_ERROR_ILLEGAL_VALUE;
}
if (max_len < 0) {
- CSFLogError(LOGTAG, "Max output length is negative");
+ MOZ_MTLOG(ML_ERROR, "Max output length is negative");
return NS_ERROR_ILLEGAL_VALUE;
}
if (protect) {
if ((max_len < SRTP_MAX_EXPANSION) ||
((max_len - SRTP_MAX_EXPANSION) < in_len)) {
- CSFLogError(LOGTAG, "Output too short");
+ MOZ_MTLOG(ML_ERROR, "Output too short");
return NS_ERROR_ILLEGAL_VALUE;
}
}
else {
if (in_len > max_len) {
- CSFLogError(LOGTAG, "Output too short");
+ MOZ_MTLOG(ML_ERROR, "Output too short");
return NS_ERROR_ILLEGAL_VALUE;
}
}
return NS_OK;
}
nsresult SrtpFlow::ProtectRtp(void *in, int in_len,
@@ -135,117 +130,117 @@ nsresult SrtpFlow::ProtectRtp(void *in,
nsresult res = CheckInputs(true, in, in_len, max_len, out_len);
if (NS_FAILED(res))
return res;
int len = in_len;
srtp_err_status_t r = srtp_protect(session_, in, &len);
if (r != srtp_err_status_ok) {
- CSFLogError(LOGTAG, "Error protecting SRTP packet");
+ MOZ_MTLOG(ML_ERROR, "Error protecting SRTP packet");
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(len <= max_len);
*out_len = len;
- CSFLogDebug(LOGTAG, "Successfully protected an SRTP packet of len %d",
- *out_len);
+ MOZ_MTLOG(ML_DEBUG, "Successfully protected an SRTP packet of len "
+ << *out_len);
return NS_OK;
}
nsresult SrtpFlow::UnprotectRtp(void *in, int in_len,
int max_len, int *out_len) {
nsresult res = CheckInputs(false, in, in_len, max_len, out_len);
if (NS_FAILED(res))
return res;
int len = in_len;
srtp_err_status_t r = srtp_unprotect(session_, in, &len);
if (r != srtp_err_status_ok) {
- CSFLogError(LOGTAG, "Error unprotecting SRTP packet error=%d", (int)r);
+ MOZ_MTLOG(ML_ERROR, "Error unprotecting SRTP packet error=" << (int)r);
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(len <= max_len);
*out_len = len;
- CSFLogDebug(LOGTAG, "Successfully unprotected an SRTP packet of len %d",
- *out_len);
+ MOZ_MTLOG(ML_DEBUG, "Successfully unprotected an SRTP packet of len "
+ << *out_len);
return NS_OK;
}
nsresult SrtpFlow::ProtectRtcp(void *in, int in_len,
int max_len, int *out_len) {
nsresult res = CheckInputs(true, in, in_len, max_len, out_len);
if (NS_FAILED(res))
return res;
int len = in_len;
srtp_err_status_t r = srtp_protect_rtcp(session_, in, &len);
if (r != srtp_err_status_ok) {
- CSFLogError(LOGTAG, "Error protecting SRTCP packet");
+ MOZ_MTLOG(ML_ERROR, "Error protecting SRTCP packet");
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(len <= max_len);
*out_len = len;
- CSFLogDebug(LOGTAG, "Successfully protected an SRTCP packet of len %d",
- *out_len);
+ MOZ_MTLOG(ML_DEBUG, "Successfully protected an SRTCP packet of len "
+ << *out_len);
return NS_OK;
}
nsresult SrtpFlow::UnprotectRtcp(void *in, int in_len,
int max_len, int *out_len) {
nsresult res = CheckInputs(false, in, in_len, max_len, out_len);
if (NS_FAILED(res))
return res;
int len = in_len;
srtp_err_status_t r = srtp_unprotect_rtcp(session_, in, &len);
if (r != srtp_err_status_ok) {
- CSFLogError(LOGTAG, "Error unprotecting SRTCP packet error=%d", (int)r);
+ MOZ_MTLOG(ML_ERROR, "Error unprotecting SRTCP packet error=" << (int)r);
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(len <= max_len);
*out_len = len;
- CSFLogDebug(LOGTAG, "Successfully unprotected an SRTCP packet of len %d",
- *out_len);
+ MOZ_MTLOG(ML_DEBUG, "Successfully unprotected an SRTCP packet of len "
+ << *out_len);
return NS_OK;
}
// Statics
void SrtpFlow::srtp_event_handler(srtp_event_data_t *data) {
// TODO(ekr@rtfm.com): Implement this
MOZ_CRASH();
}
nsresult SrtpFlow::Init() {
if (!initialized) {
srtp_err_status_t r = srtp_init();
if (r != srtp_err_status_ok) {
- CSFLogError(LOGTAG, "Could not initialize SRTP");
+ MOZ_MTLOG(ML_ERROR, "Could not initialize SRTP");
MOZ_ASSERT(PR_FALSE);
return NS_ERROR_FAILURE;
}
r = srtp_install_event_handler(&SrtpFlow::srtp_event_handler);
if (r != srtp_err_status_ok) {
- CSFLogError(LOGTAG, "Could not install SRTP event handler");
+ MOZ_MTLOG(ML_ERROR, "Could not install SRTP event handler");
MOZ_ASSERT(PR_FALSE);
return NS_ERROR_FAILURE;
}
initialized = true;
}
return NS_OK;
rename from media/webrtc/signaling/src/mediapipeline/SrtpFlow.h
rename to media/mtransport/SrtpFlow.h
--- a/media/mtransport/build/moz.build
+++ b/media/mtransport/build/moz.build
@@ -12,23 +12,25 @@ EXPORTS.mtransport += [
'../nricectx.h',
'../nricemediastream.h',
'../nriceresolverfake.h',
'../nricestunaddr.h',
'../rlogconnector.h',
'../runnable_utils.h',
'../sigslot.h',
'../simpletokenbucket.h',
+ '../SrtpFlow.h',
'../stun_socket_filter.h',
'../transportflow.h',
'../transportlayer.h',
'../transportlayerdtls.h',
'../transportlayerice.h',
'../transportlayerlog.h',
'../transportlayerloopback.h',
+ '../transportlayersrtp.h',
]
include('../common.build')
# Add libFuzzer configuration directives
include('/tools/fuzzing/libfuzzer-config.mozbuild')
# These files cannot be built in unified mode because of the redefinition of
--- a/media/mtransport/common.build
+++ b/media/mtransport/common.build
@@ -12,24 +12,26 @@ mtransport_lcppsrcs = [
'nricectxhandler.cpp',
'nricemediastream.cpp',
'nriceresolver.cpp',
'nriceresolverfake.cpp',
'nricestunaddr.cpp',
'nrinterfaceprioritizer.cpp',
'rlogconnector.cpp',
'simpletokenbucket.cpp',
+ 'SrtpFlow.cpp',
'stun_socket_filter.cpp',
'test_nr_socket.cpp',
'transportflow.cpp',
'transportlayer.cpp',
'transportlayerdtls.cpp',
'transportlayerice.cpp',
'transportlayerlog.cpp',
'transportlayerloopback.cpp',
+ 'transportlayersrtp.cpp',
]
mtransport_cppsrcs = [
'/media/mtransport/%s' % s for s in sorted(mtransport_lcppsrcs)
]
LOCAL_INCLUDES += [
'/media/mtransport/',
@@ -42,16 +44,18 @@ LOCAL_INCLUDES += [
'/media/mtransport/third_party/nrappkit/src/event',
'/media/mtransport/third_party/nrappkit/src/log',
'/media/mtransport/third_party/nrappkit/src/plugin',
'/media/mtransport/third_party/nrappkit/src/port/generic/include',
'/media/mtransport/third_party/nrappkit/src/registry',
'/media/mtransport/third_party/nrappkit/src/share',
'/media/mtransport/third_party/nrappkit/src/stats',
'/media/mtransport/third_party/nrappkit/src/util/libekr',
+ '/netwerk/srtp/src/crypto/include',
+ '/netwerk/srtp/src/include',
]
if CONFIG['OS_TARGET'] in ['Darwin', 'DragonFly', 'FreeBSD', 'NetBSD', 'OpenBSD']:
if CONFIG['OS_TARGET'] == 'Darwin':
DEFINES['DARWIN'] = True
else:
DEFINES['BSD'] = True
LOCAL_INCLUDES += [
--- a/media/mtransport/test/sctp_unittest.cpp
+++ b/media/mtransport/test/sctp_unittest.cpp
@@ -153,16 +153,17 @@ class TransportTestPeer : public sigslot
std::cerr << "Calling usrsctp_connect()" << std::endl;
r = usrsctp_connect(sctp_, reinterpret_cast<struct sockaddr *>(
&remote_addr_), sizeof(remote_addr_));
ASSERT_GE(0, r);
}
void Disconnect_s() {
+ disconnect_all();
if (flow_) {
flow_ = nullptr;
}
}
void Disconnect() {
loopback_->Disconnect();
}
new file mode 100644
--- /dev/null
+++ b/media/mtransport/transportlayersrtp.cpp
@@ -0,0 +1,267 @@
+/* -*- 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 "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());
+}
+
+void
+TransportLayerSrtp::WasInserted()
+{
+ // Connect to the lower layers
+ if (!Setup()) {
+ TL_SET_STATE(TS_ERROR);
+ }
+}
+
+bool
+TransportLayerSrtp::Setup()
+{
+ CheckThread();
+ if (!downward_) {
+ MOZ_MTLOG(ML_ERROR, "SRTP layer with nothing below. This is useless");
+ return false;
+ }
+
+ // 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;
+}
+
+TransportResult
+TransportLayerSrtp::SendPacket(const unsigned char* data, size_t len)
+{
+ 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 (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;
+ }
+
+ // 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;
+}
+
+void
+TransportLayerSrtp::StateChange(TransportLayer* layer, State state)
+{
+ 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);
+}
+
+void
+TransportLayerSrtp::PacketReceived(TransportLayer* layer,
+ const unsigned char *data,
+ size_t len)
+{
+ 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]
+ << "]");
+ }
+}
+
+} // namespace mozilla
+
+
new file mode 100644
--- /dev/null
+++ b/media/mtransport/transportlayersrtp.h
@@ -0,0 +1,45 @@
+/* -*- 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>
+
+#include "transportlayer.h"
+#include "mozilla/RefPtr.h"
+#include "SrtpFlow.h"
+
+namespace mozilla {
+
+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;
+
+ // Signals
+ void StateChange(TransportLayer *layer, State state);
+ void PacketReceived(TransportLayer* layer, const unsigned char *data,
+ size_t len);
+
+ TRANSPORT_LAYER_ID("srtp")
+
+ private:
+ bool Setup();
+ DISALLOW_COPY_ASSIGN(TransportLayerSrtp);
+ RefPtr<SrtpFlow> mSendSrtp;
+ RefPtr<SrtpFlow> mRecvSrtp;
+};
+
+
+} // close namespace
+#endif
--- a/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp
+++ b/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp
@@ -19,16 +19,17 @@
#include "MediaPipeline.h"
#include "MediaPipelineFilter.h"
#include "MediaStreamGraph.h"
#include "MediaStreamListener.h"
#include "MediaStreamTrack.h"
#include "transportflow.h"
#include "transportlayerloopback.h"
#include "transportlayerdtls.h"
+#include "transportlayersrtp.h"
#include "mozilla/SyncRunnable.h"
#include "mtransport_test_utils.h"
#include "SharedBuffer.h"
#define GTEST_HAS_RTTI 0
#include "gtest/gtest.h"
using namespace mozilla;
@@ -164,97 +165,69 @@ public:
}
}
};
class TransportInfo {
public:
TransportInfo() :
flow_(nullptr),
- loopback_(nullptr),
- dtls_(nullptr) {}
+ loopback_(nullptr) {}
static void InitAndConnect(TransportInfo &client, TransportInfo &server) {
client.Init(true);
server.Init(false);
- client.PushLayers();
- server.PushLayers();
client.Connect(&server);
server.Connect(&client);
}
void Init(bool client) {
- nsresult res;
-
- flow_ = new TransportFlow();
- loopback_ = new TransportLayerLoopback();
- dtls_ = new TransportLayerDtls();
-
- res = loopback_->Init();
- if (res != NS_OK) {
- FreeLayers();
- }
- ASSERT_EQ((nsresult)NS_OK, res);
+ UniquePtr<TransportLayerLoopback> loopback(new TransportLayerLoopback);
+ UniquePtr<TransportLayerDtls> dtls(new TransportLayerDtls);
+ UniquePtr<TransportLayerSrtp> srtp(new TransportLayerSrtp(*dtls));
std::vector<uint16_t> ciphers;
ciphers.push_back(SRTP_AES128_CM_HMAC_SHA1_80);
- dtls_->SetSrtpCiphers(ciphers);
- dtls_->SetIdentity(DtlsIdentity::Generate());
- dtls_->SetRole(client ? TransportLayerDtls::CLIENT :
+ dtls->SetSrtpCiphers(ciphers);
+ dtls->SetIdentity(DtlsIdentity::Generate());
+ dtls->SetRole(client ? TransportLayerDtls::CLIENT :
TransportLayerDtls::SERVER);
- dtls_->SetVerificationAllowAll();
- }
+ dtls->SetVerificationAllowAll();
- void PushLayers() {
- if (NS_FAILED(loopback_->Init())) {
- delete loopback_;
- loopback_ = nullptr;
- }
+ ASSERT_EQ(NS_OK, loopback->Init());
+ ASSERT_EQ(NS_OK, dtls->Init());
+ ASSERT_EQ(NS_OK, srtp->Init());
- if (NS_FAILED(dtls_->Init())) {
- delete dtls_;
- dtls_ = nullptr;
- }
+ dtls->Chain(loopback.get());
+ srtp->Chain(loopback.get());
- ASSERT_TRUE(loopback_);
- ASSERT_TRUE(dtls_);
-
- dtls_->Chain(loopback_);
+ flow_ = new TransportFlow();
+ loopback_ = loopback.release();
flow_->PushLayer(loopback_);
- flow_->PushLayer(dtls_);
+ flow_->PushLayer(dtls.release());
+ flow_->PushLayer(srtp.release());
}
void Connect(TransportInfo* peer) {
MOZ_ASSERT(loopback_);
MOZ_ASSERT(peer->loopback_);
loopback_->Connect(peer->loopback_);
}
- // Free the memory allocated at the beginning of Init
- // if failure occurs before layers setup.
- void FreeLayers() {
- delete loopback_;
- loopback_ = nullptr;
- delete dtls_;
- dtls_ = nullptr;
- }
-
void Shutdown() {
if (loopback_) {
loopback_->Disconnect();
}
loopback_ = nullptr;
- dtls_ = nullptr;
flow_ = nullptr;
}
RefPtr<TransportFlow> flow_;
TransportLayerLoopback *loopback_;
- TransportLayerDtls *dtls_;
};
class TestAgent {
public:
TestAgent() :
audio_config_(109, "opus", 48000, 960, 2, 64000, false),
audio_conduit_(mozilla::AudioSessionConduit::Create()),
audio_pipeline_(),
@@ -369,19 +342,19 @@ class TestAgentSend : public TestAgent {
}
RefPtr<MediaPipelineTransmit> audio_pipeline =
new mozilla::MediaPipelineTransmit(
test_pc,
nullptr,
test_utils->sts_target(),
false,
- audio_stream_track_.get(),
audio_conduit_);
+ audio_pipeline->SetTrack(audio_stream_track_.get());
audio_pipeline->Start();
audio_pipeline_ = audio_pipeline;
RefPtr<TransportFlow> rtp(audio_rtp_transport_.flow_);
RefPtr<TransportFlow> rtcp(audio_rtcp_transport_.flow_);
if (use_bundle_) {
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -670,33 +670,29 @@ protected:
UniquePtr<AudioPacketizer<int16_t, int16_t>> mPacketizer;
// A buffer to hold a single packet of audio.
UniquePtr<int16_t[]> mPacket;
nsTArray<int16_t> mInterleavedAudio;
AlignedShortBuffer mOutputAudio;
UniquePtr<AudioConverter> mAudioConverter;
};
-static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
-
MediaPipeline::MediaPipeline(const std::string& aPc,
DirectionType aDirection,
nsCOMPtr<nsIEventTarget> aMainThread,
nsCOMPtr<nsIEventTarget> aStsThread,
RefPtr<MediaSessionConduit> aConduit)
: mDirection(aDirection)
, mLevel(0)
, mConduit(aConduit)
, mRtp(nullptr, RTP)
, mRtcp(nullptr, RTCP)
, mMainThread(aMainThread)
, mStsThread(aStsThread)
- , mTransport(new PipelineTransport(this)) // PipelineTransport() will access
- // this->mStsThread; moved here
- // for safety
+ , mTransport(new PipelineTransport(aStsThread))
, mRtpPacketsSent(0)
, mRtcpPacketsSent(0)
, mRtpPacketsReceived(0)
, mRtcpPacketsReceived(0)
, mRtpBytesSent(0)
, mRtpBytesReceived(0)
, mPc(aPc)
, mRtpParser(webrtc::RtpHeaderParser::Create())
@@ -916,106 +912,33 @@ MediaPipeline::TransportReady_s(Transpor
}
CSFLogInfo(LOGTAG,
"Transport ready for pipeline %p flow %s: %s",
this,
mDescription.c_str(),
ToString(aInfo.mType));
- // TODO(bcampen@mozilla.com): Should we disconnect from the flow on failure?
- nsresult res;
-
- // Now instantiate the SRTP objects
- TransportLayerDtls* dtls = static_cast<TransportLayerDtls*>(
- aInfo.mTransport->GetLayer(TransportLayerDtls::ID()));
- MOZ_ASSERT(dtls); // DTLS is mandatory
-
- uint16_t cipher_suite;
- res = dtls->GetSrtpCipher(&cipher_suite);
- if (NS_FAILED(res)) {
- CSFLogError(LOGTAG, "Failed to negotiate DTLS-SRTP. This is an error");
- aInfo.mState = StateType::MP_CLOSED;
- UpdateRtcpMuxState(aInfo);
- return res;
- }
-
- // 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)) {
- CSFLogError(LOGTAG, "Failed to compute DTLS-SRTP keys. This is an error");
- aInfo.mState = StateType::MP_CLOSED;
- UpdateRtcpMuxState(aInfo);
- MOZ_CRASH(); // TODO: Remove once we have enough field experience to
- // know it doesn't happen. bug 798797. Note that the
- // code after this never executes.
- return res;
- }
-
- // 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(!aInfo.mSendSrtp && !aInfo.mRecvSrtp);
- aInfo.mSendSrtp =
- SrtpFlow::Create(cipher_suite, false, write_key, SRTP_TOTAL_KEY_LENGTH);
- aInfo.mRecvSrtp =
- SrtpFlow::Create(cipher_suite, true, read_key, SRTP_TOTAL_KEY_LENGTH);
- if (!aInfo.mSendSrtp || !aInfo.mRecvSrtp) {
- CSFLogError(
- LOGTAG, "Couldn't create SRTP flow for %s", ToString(aInfo.mType));
- aInfo.mState = StateType::MP_CLOSED;
- UpdateRtcpMuxState(aInfo);
- return NS_ERROR_FAILURE;
- }
-
if (mDirection == DirectionType::RECEIVE) {
CSFLogInfo(LOGTAG,
"Listening for %s packets received on %p",
ToString(aInfo.mType),
- dtls->downward());
+ aInfo.mSrtp);
switch (aInfo.mType) {
case RTP:
- dtls->downward()->SignalPacketReceived.connect(
+ aInfo.mSrtp->SignalPacketReceived.connect(
this, &MediaPipeline::RtpPacketReceived);
break;
case RTCP:
- dtls->downward()->SignalPacketReceived.connect(
+ aInfo.mSrtp->SignalPacketReceived.connect(
this, &MediaPipeline::RtcpPacketReceived);
break;
case MUX:
- dtls->downward()->SignalPacketReceived.connect(
+ aInfo.mSrtp->SignalPacketReceived.connect(
this, &MediaPipeline::PacketReceived);
break;
default:
MOZ_CRASH();
}
}
aInfo.mState = StateType::MP_OPEN;
@@ -1045,20 +968,16 @@ MediaPipeline::TransportFailed_s(Transpo
}
void
MediaPipeline::UpdateRtcpMuxState(TransportInfo& aInfo)
{
if (aInfo.mType == MUX) {
if (aInfo.mTransport == mRtcp.mTransport) {
mRtcp.mState = aInfo.mState;
- if (!mRtcp.mSendSrtp) {
- mRtcp.mSendSrtp = aInfo.mSendSrtp;
- mRtcp.mRecvSrtp = aInfo.mRecvSrtp;
- }
}
}
}
nsresult
MediaPipeline::SendPacket(TransportLayer* aLayer, const void* aData, int aLen)
{
ASSERT_ON_THREAD(mStsThread);
@@ -1161,24 +1080,21 @@ MediaPipeline::RtpPacketReceived(Transpo
return;
}
if (mRtp.mState != StateType::MP_OPEN) {
CSFLogError(LOGTAG, "Discarding incoming packet; pipeline not open");
return;
}
- if (mRtp.mDtls->state() != TransportLayer::TS_OPEN) {
+ if (mRtp.mSrtp->state() != TransportLayer::TS_OPEN) {
CSFLogError(LOGTAG, "Discarding incoming packet; transport not open");
return;
}
- // This should never happen.
- MOZ_ASSERT(mRtp.mRecvSrtp);
-
if (!aLen) {
return;
}
// Filter out everything but RTP/RTCP
if (aData[0] < 128 || aData[0] > 191) {
return;
}
@@ -1227,51 +1143,28 @@ MediaPipeline::RtpPacketReceived(Transpo
} else {
csrcInfo->second.SetTimestamp(now);
}
}
}
mPacketDumper->Dump(mLevel, dom::mozPacketDumpType::Srtp, false, aData, aLen);
- // Make a copy rather than cast away constness
- auto innerData = MakeUnique<unsigned char[]>(aLen);
- memcpy(innerData.get(), aData, aLen);
- int outLen = 0;
- nsresult res =
- mRtp.mRecvSrtp->UnprotectRtp(innerData.get(), aLen, aLen, &outLen);
- if (!NS_SUCCEEDED(res)) {
- char tmp[16];
-
- SprintfLiteral(tmp,
- "%.2x %.2x %.2x %.2x",
- innerData[0],
- innerData[1],
- innerData[2],
- innerData[3]);
-
- CSFLogError(LOGTAG,
- "Error unprotecting RTP in %s len= %zu [%s]",
- mDescription.c_str(),
- aLen,
- tmp);
- return;
- }
CSFLogDebug(LOGTAG, "%s received RTP packet.", mDescription.c_str());
- IncrementRtpPacketsReceived(outLen);
+ IncrementRtpPacketsReceived(aLen);
OnRtpPacketReceived();
RtpLogger::LogPacket(
- innerData.get(), outLen, true, true, header.headerLength, mDescription);
+ aData, aLen, true, true, header.headerLength, mDescription);
mPacketDumper->Dump(
- mLevel, dom::mozPacketDumpType::Rtp, false, innerData.get(), outLen);
+ mLevel, dom::mozPacketDumpType::Rtp, false, aData, aLen);
(void)mConduit->ReceivedRTPPacket(
- innerData.get(), outLen, header.ssrc); // Ignore error codes
+ aData, aLen, header.ssrc); // Ignore error codes
}
void
MediaPipeline::RtcpPacketReceived(TransportLayer* aLayer,
const unsigned char* aData,
size_t aLen)
{
if (!mTransport->Pipeline()) {
@@ -1284,17 +1177,17 @@ MediaPipeline::RtcpPacketReceived(Transp
return;
}
if (mRtcp.mState != StateType::MP_OPEN) {
CSFLogDebug(LOGTAG, "Discarding incoming packet; pipeline not open");
return;
}
- if (mRtcp.mDtls->state() != TransportLayer::TS_OPEN) {
+ if (mRtcp.mSrtp->state() != TransportLayer::TS_OPEN) {
CSFLogError(LOGTAG, "Discarding incoming packet; transport not open");
return;
}
if (!aLen) {
return;
}
@@ -1308,38 +1201,24 @@ MediaPipeline::RtcpPacketReceived(Transp
// TODO bug 1279153: remove SR check for reduced size RTCP
if (mFilter && !mFilter->FilterSenderReport(aData, aLen)) {
CSFLogWarn(LOGTAG, "Dropping incoming RTCP packet; filtered out");
return;
}
mPacketDumper->Dump(mLevel, dom::mozPacketDumpType::Srtcp, false, aData, aLen);
- // Make a copy rather than cast away constness
- auto innerData = MakeUnique<unsigned char[]>(aLen);
- memcpy(innerData.get(), aData, aLen);
- int outLen;
-
- nsresult res =
- mRtcp.mRecvSrtp->UnprotectRtcp(innerData.get(), aLen, aLen, &outLen);
-
- if (!NS_SUCCEEDED(res))
- return;
-
CSFLogDebug(LOGTAG, "%s received RTCP packet.", mDescription.c_str());
IncrementRtcpPacketsReceived();
- RtpLogger::LogPacket(innerData.get(), outLen, true, false, 0, mDescription);
+ RtpLogger::LogPacket(aData, aLen, true, false, 0, mDescription);
mPacketDumper->Dump(mLevel, dom::mozPacketDumpType::Rtcp, false, aData, aLen);
- MOZ_ASSERT(mRtcp.mRecvSrtp); // This should never happen
-
- (void)mConduit->ReceivedRTCPPacket(innerData.get(),
- outLen); // Ignore error codes
+ (void)mConduit->ReceivedRTCPPacket(aData, aLen); // Ignore error codes
}
bool
MediaPipeline::IsRtp(const unsigned char* aData, size_t aLen) const
{
if (aLen < 2)
return false;
@@ -1509,35 +1388,32 @@ protected:
RefPtr<PipelineListener> mListener;
};
MediaPipelineTransmit::MediaPipelineTransmit(
const std::string& aPc,
nsCOMPtr<nsIEventTarget> aMainThread,
nsCOMPtr<nsIEventTarget> aStsThread,
bool aIsVideo,
- dom::MediaStreamTrack* aDomTrack,
RefPtr<MediaSessionConduit> aConduit)
: MediaPipeline(aPc,
DirectionType::TRANSMIT,
aMainThread,
aStsThread,
aConduit)
, mIsVideo(aIsVideo)
, mListener(new PipelineListener(aConduit))
, mFeeder(aIsVideo ? MakeAndAddRef<VideoFrameFeeder>(mListener)
: nullptr) // For video we send frames to an
// async VideoFrameConverter that
// calls back to a VideoFrameFeeder
// that feeds I420 frames to
// VideoConduit.
- , mDomTrack(aDomTrack)
, mTransmitting(false)
{
- SetDescription();
if (!IsVideo()) {
mAudioProcessing = MakeAndAddRef<AudioProxyThread>(
static_cast<AudioSessionConduit*>(aConduit.get()));
mListener->SetAudioProxy(mAudioProcessing);
} else { // Video
mConverter = MakeAndAddRef<VideoFrameConverter>();
mConverter->AddListener(mFeeder);
mListener->SetVideoFrameConverter(mConverter);
@@ -1709,17 +1585,17 @@ MediaPipelineTransmit::TransportReady_s(
if (&aInfo == &mRtp) {
mListener->SetActive(true);
}
return NS_OK;
}
nsresult
-MediaPipelineTransmit::ReplaceTrack(RefPtr<MediaStreamTrack>& aDomTrack)
+MediaPipelineTransmit::SetTrack(MediaStreamTrack* aDomTrack)
{
// MainThread, checked in calls we make
if (aDomTrack) {
nsString nsTrackId;
aDomTrack->GetId(nsTrackId);
std::string track_id(NS_ConvertUTF16toUTF8(nsTrackId).get());
CSFLogDebug(
LOGTAG,
@@ -1740,62 +1616,61 @@ MediaPipelineTransmit::ReplaceTrack(RefP
}
return NS_OK;
}
nsresult
MediaPipeline::ConnectTransport_s(TransportInfo& aInfo)
{
MOZ_ASSERT(aInfo.mTransport);
- MOZ_ASSERT(aInfo.mDtls);
+ MOZ_ASSERT(aInfo.mSrtp);
ASSERT_ON_THREAD(mStsThread);
// Look to see if the transport is ready
- if (aInfo.mDtls->state() == TransportLayer::TS_OPEN) {
+ if (aInfo.mSrtp->state() == TransportLayer::TS_OPEN) {
nsresult res = TransportReady_s(aInfo);
if (NS_FAILED(res)) {
CSFLogError(LOGTAG,
"Error calling TransportReady(); res=%u in %s",
static_cast<uint32_t>(res),
__FUNCTION__);
return res;
}
- } else if (aInfo.mDtls->state() == TransportLayer::TS_ERROR) {
+ } else if (aInfo.mSrtp->state() == TransportLayer::TS_ERROR) {
CSFLogError(
LOGTAG, "%s transport is already in error state", ToString(aInfo.mType));
TransportFailed_s(aInfo);
return NS_ERROR_FAILURE;
}
- aInfo.mDtls->SignalStateChange.connect(this, &MediaPipeline::StateChange);
+ aInfo.mSrtp->SignalStateChange.connect(this, &MediaPipeline::StateChange);
return NS_OK;
}
MediaPipeline::TransportInfo*
MediaPipeline::GetTransportInfo_s(TransportLayer* aLayer)
{
ASSERT_ON_THREAD(mStsThread);
- if (aLayer == mRtp.mDtls) {
+ if (aLayer == mRtp.mSrtp) {
return &mRtp;
}
- if (aLayer == mRtcp.mDtls) {
+ if (aLayer == mRtcp.mSrtp) {
return &mRtcp;
}
return nullptr;
}
nsresult
MediaPipeline::PipelineTransport::SendRtpPacket(const uint8_t* aData, size_t aLen)
{
-
- nsAutoPtr<DataBuffer> buf(
- new DataBuffer(aData, aLen, aLen + SRTP_MAX_EXPANSION));
+ // Might be nice to avoid this copy.
+ nsAutoPtr<DataBuffer> buf(new DataBuffer(aData, aLen));
RUN_ON_THREAD(
mStsThread,
WrapRunnable(RefPtr<MediaPipeline::PipelineTransport>(this),
&MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
buf,
true),
NS_DISPATCH_NORMAL);
@@ -1803,108 +1678,75 @@ MediaPipeline::PipelineTransport::SendRt
return NS_OK;
}
nsresult
MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s(
nsAutoPtr<DataBuffer> aData,
bool aIsRtp)
{
-
ASSERT_ON_THREAD(mStsThread);
if (!mPipeline) {
return NS_OK; // Detached
}
TransportInfo& transport = aIsRtp ? mPipeline->mRtp : mPipeline->mRtcp;
- if (!transport.mSendSrtp) {
- CSFLogDebug(LOGTAG, "Couldn't write RTP/RTCP packet; SRTP not set up yet");
+ 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);
- // libsrtp enciphers in place, so we need a big enough buffer.
- MOZ_ASSERT(aData->capacity() >= aData->len() + SRTP_MAX_EXPANSION);
-
if (RtpLogger::IsPacketLoggingOn()) {
int headerLen = 12;
webrtc::RTPHeader header;
if (mPipeline->mRtpParser &&
mPipeline->mRtpParser->Parse(aData->data(), aData->len(), &header)) {
headerLen = header.headerLength;
}
RtpLogger::LogPacket(aData->data(),
aData->len(),
false,
aIsRtp,
headerLen,
mPipeline->mDescription);
}
- int out_len;
- nsresult res;
if (aIsRtp) {
mPipeline->mPacketDumper->Dump(mPipeline->Level(),
dom::mozPacketDumpType::Rtp,
true,
aData->data(),
aData->len());
-
- res = transport.mSendSrtp->ProtectRtp(
- aData->data(), aData->len(), aData->capacity(), &out_len);
+ mPipeline->IncrementRtpPacketsSent(aData->len());
} else {
mPipeline->mPacketDumper->Dump(mPipeline->Level(),
dom::mozPacketDumpType::Rtcp,
true,
aData->data(),
aData->len());
-
- res = transport.mSendSrtp->ProtectRtcp(
- aData->data(), aData->len(), aData->capacity(), &out_len);
+ mPipeline->IncrementRtcpPacketsSent();
}
- if (!NS_SUCCEEDED(res)) {
- return res;
- }
-
- // paranoia; don't have uninitialized bytes included in data->len()
- aData->SetLength(out_len);
CSFLogDebug(LOGTAG,
"%s sending %s packet",
mPipeline->mDescription.c_str(),
(aIsRtp ? "RTP" : "RTCP"));
- if (aIsRtp) {
- mPipeline->mPacketDumper->Dump(mPipeline->Level(),
- dom::mozPacketDumpType::Srtp,
- true,
- aData->data(),
- out_len);
- mPipeline->IncrementRtpPacketsSent(out_len);
- } else {
- mPipeline->mPacketDumper->Dump(mPipeline->Level(),
- dom::mozPacketDumpType::Srtcp,
- true,
- aData->data(),
- out_len);
-
- mPipeline->IncrementRtcpPacketsSent();
- }
- return mPipeline->SendPacket(transport.mDtls->downward(), aData->data(), out_len);
+ return mPipeline->SendPacket(transport.mSrtp, aData->data(), aData->len());
}
nsresult
MediaPipeline::PipelineTransport::SendRtcpPacket(const uint8_t* aData,
size_t aLen)
{
-
- nsAutoPtr<DataBuffer> buf(
- new DataBuffer(aData, aLen, aLen + SRTP_MAX_EXPANSION));
+ // Might be nice to avoid this copy.
+ nsAutoPtr<DataBuffer> buf(new DataBuffer(aData, aLen));
RUN_ON_THREAD(
mStsThread,
WrapRunnable(RefPtr<MediaPipeline::PipelineTransport>(this),
&MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
buf,
false),
NS_DISPATCH_NORMAL);
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
@@ -180,19 +180,19 @@ public:
typedef enum { RTP, RTCP, MUX, MAX_RTP_TYPE } RtpType;
// Separate class to allow ref counting
class PipelineTransport : public TransportInterface
{
public:
// Implement the TransportInterface functions
- explicit PipelineTransport(MediaPipeline* aPipeline)
- : mPipeline(aPipeline)
- , mStsThread(aPipeline->mStsThread)
+ explicit PipelineTransport(nsIEventTarget* aStsThread)
+ : mPipeline(nullptr)
+ , mStsThread(aStsThread)
{
}
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;
@@ -210,35 +210,31 @@ protected:
virtual ~MediaPipeline();
nsresult AttachTransport_s();
friend class PipelineTransport;
struct TransportInfo
{
TransportInfo(RefPtr<TransportFlow> aFlow, RtpType aType)
: mTransport(aFlow)
- , mDtls(mTransport ? mTransport->GetLayer("dtls") : nullptr)
+ , mSrtp(mTransport ? mTransport->GetLayer("srtp") : nullptr)
, mState(StateType::MP_CONNECTING)
, mType(aType)
{
}
void Detach()
{
mTransport = nullptr;
- mDtls = nullptr;
- mSendSrtp = nullptr;
- mRecvSrtp = nullptr;
+ mSrtp = nullptr;
}
RefPtr<TransportFlow> mTransport;
- TransportLayer* mDtls;
+ TransportLayer* mSrtp;
StateType mState;
- RefPtr<SrtpFlow> mSendSrtp;
- RefPtr<SrtpFlow> mRecvSrtp;
RtpType mType;
};
// The transport is down
virtual nsresult TransportFailed_s(TransportInfo& aInfo);
// The transport is ready
virtual nsresult TransportReady_s(TransportInfo& aInfo);
void UpdateRtcpMuxState(TransportInfo& aInfo);
@@ -324,17 +320,16 @@ private:
class MediaPipelineTransmit : public MediaPipeline
{
public:
// Set aRtcpTransport to nullptr to use rtcp-mux
MediaPipelineTransmit(const std::string& aPc,
nsCOMPtr<nsIEventTarget> aMainThread,
nsCOMPtr<nsIEventTarget> aStsThread,
bool aIsVideo,
- dom::MediaStreamTrack* aDomTrack,
RefPtr<MediaSessionConduit> aConduit);
void Start() override;
void Stop() override;
// written and used from MainThread
bool IsVideo() const override;
@@ -350,17 +345,17 @@ public:
// Override MediaPipeline::TransportReady.
nsresult TransportReady_s(TransportInfo& aInfo) override;
// Replace a track with a different one
// In non-compliance with the likely final spec, allow the new
// track to be part of a different stream (since we don't support
// multiple tracks of a type in a stream yet). bug 1056650
- virtual nsresult ReplaceTrack(RefPtr<dom::MediaStreamTrack>& aDomTrack);
+ virtual nsresult SetTrack(dom::MediaStreamTrack* aDomTrack);
// Separate classes to allow ref counting
class PipelineListener;
class VideoFrameFeeder;
protected:
~MediaPipelineTransmit();
--- a/media/webrtc/signaling/src/mediapipeline/moz.build
+++ b/media/webrtc/signaling/src/mediapipeline/moz.build
@@ -18,12 +18,11 @@ LOCAL_INCLUDES += [
'/netwerk/srtp/src/crypto/include',
'/netwerk/srtp/src/include',
]
UNIFIED_SOURCES += [
'MediaPipeline.cpp',
'MediaPipelineFilter.cpp',
'RtpLogger.cpp',
- 'SrtpFlow.cpp',
]
FINAL_LIBRARY = 'xul'
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -14,16 +14,17 @@
#include "nricemediastream.h"
#include "MediaPipelineFilter.h"
#include "MediaPipeline.h"
#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 "nsContentUtils.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsIURI.h"
#include "nsIScriptSecurityManager.h"
@@ -525,26 +526,30 @@ PeerConnectionMedia::UpdateTransportFlow
// 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,
RefPtr<TransportFlow> aFlow, size_t aLevel,
bool aIsRtcp,
TransportLayerIce* aIceLayer,
- TransportLayerDtls* aDtlsLayer)
+ TransportLayerDtls* aDtlsLayer,
+ TransportLayerSrtp* aSrtpLayer)
{
aIceLayer->SetParameters(aPCMedia->ice_media_stream(aLevel),
aIsRtcp ? 2 : 1);
// TODO(bug 854518): Process errors.
(void)aIceLayer->Init();
(void)aDtlsLayer->Init();
+ (void)aSrtpLayer->Init();
aDtlsLayer->Chain(aIceLayer);
+ aSrtpLayer->Chain(aIceLayer);
aFlow->PushLayer(aIceLayer);
aFlow->PushLayer(aDtlsLayer);
+ aFlow->PushLayer(aSrtpLayer);
}
static void
AddNewIceStreamForRestart_s(RefPtr<PeerConnectionMedia> aPCMedia,
RefPtr<TransportFlow> aFlow,
size_t aLevel,
bool aIsRtcp)
{
@@ -594,16 +599,17 @@ PeerConnectionMedia::UpdateTransportFlow
std::ostringstream osId;
osId << mParentHandle << ":" << aLevel << "," << (aIsRtcp ? "rtcp" : "rtp");
flow = new TransportFlow(osId.str());
// The media streams are made on STS so we need to defer setup.
auto ice = MakeUnique<TransportLayerIce>();
auto dtls = MakeUnique<TransportLayerDtls>();
+ auto srtp = MakeUnique<TransportLayerSrtp>(*dtls);
dtls->SetRole(aTransport.mDtls->GetRole() ==
JsepDtlsTransport::kJsepDtlsClient
? TransportLayerDtls::CLIENT
: TransportLayerDtls::SERVER);
RefPtr<DtlsIdentity> pcid = mParent->Identity();
if (!pcid) {
CSFLogError(LOGTAG, "Failed to get DTLS identity.");
@@ -648,17 +654,17 @@ PeerConnectionMedia::UpdateTransportFlow
if (NS_FAILED(rv)) {
CSFLogError(LOGTAG, "Couldn't set ALPN");
return rv;
}
RefPtr<PeerConnectionMedia> pcMedia(this);
rv = GetSTSThread()->Dispatch(
WrapRunnableNM(FinalizeTransportFlow_s, pcMedia, flow, aLevel, aIsRtcp,
- ice.release(), dtls.release()),
+ 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/media/webrtc/signaling/src/peerconnection/TransceiverImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/TransceiverImpl.cpp
@@ -64,18 +64,19 @@ TransceiverImpl::TransceiverImpl(
mConduit->SetPCHandle(mPCHandle);
mTransmitPipeline = new MediaPipelineTransmit(
mPCHandle,
mMainThread.get(),
mStsThread.get(),
IsVideo(),
- mSendTrack,
mConduit);
+
+ mTransmitPipeline->SetTrack(mSendTrack);
}
TransceiverImpl::~TransceiverImpl() = default;
NS_IMPL_ISUPPORTS0(TransceiverImpl)
void
TransceiverImpl::InitAudio()
@@ -153,17 +154,17 @@ TransceiverImpl::UpdateSendTrack(dom::Me
{
if (mJsepTransceiver->IsStopped()) {
return NS_ERROR_UNEXPECTED;
}
MOZ_MTLOG(ML_DEBUG, mPCHandle << "[" << mMid << "]: " << __FUNCTION__ <<
"(" << aSendTrack << ")");
mSendTrack = aSendTrack;
- return mTransmitPipeline->ReplaceTrack(mSendTrack);
+ return mTransmitPipeline->SetTrack(mSendTrack);
}
nsresult
TransceiverImpl::UpdateTransport(PeerConnectionMedia& aTransportManager)
{
if (!mJsepTransceiver->HasLevel()) {
return NS_OK;
}