зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1455647 - Part 3: Move SRTP into a TransportLayer. r=drno
MozReview-Commit-ID: LWZFPVDYZKb --HG-- rename : media/webrtc/signaling/src/mediapipeline/SrtpFlow.cpp => media/mtransport/SrtpFlow.cpp rename : media/webrtc/signaling/src/mediapipeline/SrtpFlow.h => media/mtransport/SrtpFlow.h extra : rebase_source : 16e1e38c0c6f9153375735b7cb93a8286364df5f
This commit is contained in:
Родитель
ab2913f71d
Коммит
148a322296
|
@ -13,16 +13,11 @@
|
|||
|
||||
#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() {
|
||||
|
@ -42,12 +37,12 @@ RefPtr<SrtpFlow> SrtpFlow::Create(int cipher_suite,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -58,19 +53,19 @@ RefPtr<SrtpFlow> SrtpFlow::Create(int cipher_suite,
|
|||
// 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
|
||||
|
@ -87,7 +82,7 @@ RefPtr<SrtpFlow> SrtpFlow::Create(int cipher_suite,
|
|||
// 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;
|
||||
}
|
||||
|
||||
|
@ -99,30 +94,30 @@ 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;
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +135,7 @@ nsresult SrtpFlow::ProtectRtp(void *in, int 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;
|
||||
}
|
||||
|
||||
|
@ -148,8 +143,8 @@ nsresult SrtpFlow::ProtectRtp(void *in, int in_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;
|
||||
}
|
||||
|
@ -164,15 +159,15 @@ nsresult SrtpFlow::UnprotectRtp(void *in, int 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;
|
||||
}
|
||||
|
@ -187,15 +182,15 @@ nsresult SrtpFlow::ProtectRtcp(void *in, int 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;
|
||||
}
|
||||
|
@ -210,15 +205,15 @@ nsresult SrtpFlow::UnprotectRtcp(void *in, int 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;
|
||||
}
|
||||
|
@ -233,14 +228,14 @@ 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;
|
||||
}
|
|
@ -17,6 +17,7 @@ EXPORTS.mtransport += [
|
|||
'../runnable_utils.h',
|
||||
'../sigslot.h',
|
||||
'../simpletokenbucket.h',
|
||||
'../SrtpFlow.h',
|
||||
'../stun_socket_filter.h',
|
||||
'../transportflow.h',
|
||||
'../transportlayer.h',
|
||||
|
@ -24,6 +25,7 @@ EXPORTS.mtransport += [
|
|||
'../transportlayerice.h',
|
||||
'../transportlayerlog.h',
|
||||
'../transportlayerloopback.h',
|
||||
'../transportlayersrtp.h',
|
||||
]
|
||||
|
||||
include('../common.build')
|
||||
|
|
|
@ -17,6 +17,7 @@ mtransport_lcppsrcs = [
|
|||
'nrinterfaceprioritizer.cpp',
|
||||
'rlogconnector.cpp',
|
||||
'simpletokenbucket.cpp',
|
||||
'SrtpFlow.cpp',
|
||||
'stun_socket_filter.cpp',
|
||||
'test_nr_socket.cpp',
|
||||
'transportflow.cpp',
|
||||
|
@ -25,6 +26,7 @@ mtransport_lcppsrcs = [
|
|||
'transportlayerice.cpp',
|
||||
'transportlayerlog.cpp',
|
||||
'transportlayerloopback.cpp',
|
||||
'transportlayersrtp.cpp',
|
||||
]
|
||||
|
||||
mtransport_cppsrcs = [
|
||||
|
@ -47,6 +49,8 @@ LOCAL_INCLUDES += [
|
|||
'/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']:
|
||||
|
|
|
@ -158,6 +158,7 @@ class TransportTestPeer : public sigslot::has_slots<> {
|
|||
}
|
||||
|
||||
void Disconnect_s() {
|
||||
disconnect_all();
|
||||
if (flow_) {
|
||||
flow_ = nullptr;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
|
@ -24,6 +24,7 @@
|
|||
#include "transportflow.h"
|
||||
#include "transportlayerloopback.h"
|
||||
#include "transportlayerdtls.h"
|
||||
#include "transportlayersrtp.h"
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
#include "mtransport_test_utils.h"
|
||||
#include "SharedBuffer.h"
|
||||
|
@ -169,57 +170,40 @@ 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) {
|
||||
|
@ -229,27 +213,16 @@ class TransportInfo {
|
|||
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 {
|
||||
|
@ -374,9 +347,9 @@ class TestAgentSend : public TestAgent {
|
|||
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;
|
||||
|
|
|
@ -675,8 +675,6 @@ protected:
|
|||
UniquePtr<AudioConverter> mAudioConverter;
|
||||
};
|
||||
|
||||
static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
|
||||
|
||||
MediaPipeline::MediaPipeline(const std::string& aPc,
|
||||
DirectionType aDirection,
|
||||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
|
@ -689,9 +687,7 @@ MediaPipeline::MediaPipeline(const std::string& aPc,
|
|||
, 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)
|
||||
|
@ -921,96 +917,23 @@ MediaPipeline::TransportReady_s(TransportInfo& aInfo)
|
|||
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:
|
||||
|
@ -1050,10 +973,6 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1166,14 +1085,11 @@ MediaPipeline::RtpPacketReceived(TransportLayer* aLayer,
|
|||
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;
|
||||
}
|
||||
|
@ -1232,41 +1148,18 @@ MediaPipeline::RtpPacketReceived(TransportLayer* aLayer,
|
|||
|
||||
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
|
||||
|
@ -1289,7 +1182,7 @@ MediaPipeline::RtcpPacketReceived(TransportLayer* aLayer,
|
|||
return;
|
||||
}
|
||||
|
||||
if (mRtcp.mDtls->state() != TransportLayer::TS_OPEN) {
|
||||
if (mRtcp.mSrtp->state() != TransportLayer::TS_OPEN) {
|
||||
CSFLogError(LOGTAG, "Discarding incoming packet; transport not open");
|
||||
return;
|
||||
}
|
||||
|
@ -1313,28 +1206,14 @@ MediaPipeline::RtcpPacketReceived(TransportLayer* aLayer,
|
|||
|
||||
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
|
||||
|
@ -1514,7 +1393,6 @@ MediaPipelineTransmit::MediaPipelineTransmit(
|
|||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
nsCOMPtr<nsIEventTarget> aStsThread,
|
||||
bool aIsVideo,
|
||||
dom::MediaStreamTrack* aDomTrack,
|
||||
RefPtr<MediaSessionConduit> aConduit)
|
||||
: MediaPipeline(aPc,
|
||||
DirectionType::TRANSMIT,
|
||||
|
@ -1529,10 +1407,8 @@ MediaPipelineTransmit::MediaPipelineTransmit(
|
|||
// 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()));
|
||||
|
@ -1714,7 +1590,7 @@ MediaPipelineTransmit::TransportReady_s(TransportInfo& aInfo)
|
|||
}
|
||||
|
||||
nsresult
|
||||
MediaPipelineTransmit::ReplaceTrack(RefPtr<MediaStreamTrack>& aDomTrack)
|
||||
MediaPipelineTransmit::SetTrack(MediaStreamTrack* aDomTrack)
|
||||
{
|
||||
// MainThread, checked in calls we make
|
||||
if (aDomTrack) {
|
||||
|
@ -1745,11 +1621,11 @@ 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,
|
||||
|
@ -1758,14 +1634,14 @@ MediaPipeline::ConnectTransport_s(TransportInfo& aInfo)
|
|||
__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;
|
||||
}
|
||||
|
@ -1774,11 +1650,11 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -1788,9 +1664,8 @@ MediaPipeline::GetTransportInfo_s(TransportLayer* aLayer)
|
|||
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,
|
||||
|
@ -1808,24 +1683,20 @@ 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;
|
||||
|
@ -1841,65 +1712,36 @@ MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s(
|
|||
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,
|
||||
|
|
|
@ -185,9 +185,9 @@ public:
|
|||
{
|
||||
public:
|
||||
// Implement the TransportInterface functions
|
||||
explicit PipelineTransport(MediaPipeline* aPipeline)
|
||||
: mPipeline(aPipeline)
|
||||
, mStsThread(aPipeline->mStsThread)
|
||||
explicit PipelineTransport(nsIEventTarget* aStsThread)
|
||||
: mPipeline(nullptr)
|
||||
, mStsThread(aStsThread)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,7 @@ protected:
|
|||
{
|
||||
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)
|
||||
{
|
||||
|
@ -224,16 +224,12 @@ protected:
|
|||
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;
|
||||
};
|
||||
|
||||
|
@ -329,7 +325,6 @@ public:
|
|||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
nsCOMPtr<nsIEventTarget> aStsThread,
|
||||
bool aIsVideo,
|
||||
dom::MediaStreamTrack* aDomTrack,
|
||||
RefPtr<MediaSessionConduit> aConduit);
|
||||
|
||||
void Start() override;
|
||||
|
@ -355,7 +350,7 @@ public:
|
|||
// 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;
|
||||
|
|
|
@ -23,7 +23,6 @@ UNIFIED_SOURCES += [
|
|||
'MediaPipeline.cpp',
|
||||
'MediaPipelineFilter.cpp',
|
||||
'RtpLogger.cpp',
|
||||
'SrtpFlow.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#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"
|
||||
|
||||
|
@ -530,16 +531,20 @@ 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
|
||||
|
@ -599,6 +604,7 @@ PeerConnectionMedia::UpdateTransportFlow(
|
|||
// 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
|
||||
|
@ -653,7 +659,7 @@ PeerConnectionMedia::UpdateTransportFlow(
|
|||
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");
|
||||
|
|
|
@ -69,8 +69,9 @@ TransceiverImpl::TransceiverImpl(
|
|||
mMainThread.get(),
|
||||
mStsThread.get(),
|
||||
IsVideo(),
|
||||
mSendTrack,
|
||||
mConduit);
|
||||
|
||||
mTransmitPipeline->SetTrack(mSendTrack);
|
||||
}
|
||||
|
||||
TransceiverImpl::~TransceiverImpl() = default;
|
||||
|
@ -158,7 +159,7 @@ TransceiverImpl::UpdateSendTrack(dom::MediaStreamTrack* aSendTrack)
|
|||
MOZ_MTLOG(ML_DEBUG, mPCHandle << "[" << mMid << "]: " << __FUNCTION__ <<
|
||||
"(" << aSendTrack << ")");
|
||||
mSendTrack = aSendTrack;
|
||||
return mTransmitPipeline->ReplaceTrack(mSendTrack);
|
||||
return mTransmitPipeline->SetTrack(mSendTrack);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
Загрузка…
Ссылка в новой задаче