mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Bug 1494301: Single API for mtransport. r=mjf
Differential Revision: https://phabricator.services.mozilla.com/D7212 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
6f57bf69b4
commit
41541e64f6
@ -22,5 +22,60 @@ MediaPacket::Copy(const uint8_t* data, size_t len, size_t capacity)
|
||||
memcpy(data_.get(), data, len);
|
||||
}
|
||||
|
||||
static bool IsRtp(const uint8_t* data, size_t len)
|
||||
{
|
||||
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 ((data[1] < 192) || (data[1] > 207))
|
||||
return true;
|
||||
|
||||
if (data[1] == 192) // FIR
|
||||
return false;
|
||||
|
||||
if (data[1] == 193) // NACK, but could also be RTP. This makes us sad
|
||||
return true; // but it's how webrtc.org behaves.
|
||||
|
||||
if (data[1] == 194)
|
||||
return true;
|
||||
|
||||
if (data[1] == 195) // IJ.
|
||||
return false;
|
||||
|
||||
if ((data[1] > 195) && (data[1] < 200)) // the > 195 is redundant
|
||||
return true;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
MediaPacket::Categorize()
|
||||
{
|
||||
SetType(MediaPacket::UNCLASSIFIED);
|
||||
|
||||
if (!data_ || len_ < 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data_[0] >= 20 && data_[0] <= 63) {
|
||||
// DTLS per RFC 7983
|
||||
SetType(MediaPacket::DTLS);
|
||||
} else if (data_[0] > 127 && data_[0] < 192) {
|
||||
// RTP/RTCP per RFC 7983
|
||||
if (IsRtp(data_.get(), len_)) {
|
||||
SetType(MediaPacket::SRTP);
|
||||
} else {
|
||||
SetType(MediaPacket::SRTCP);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -86,11 +86,16 @@ class MediaPacket {
|
||||
|
||||
enum Type {
|
||||
UNCLASSIFIED,
|
||||
SRTP,
|
||||
SRTCP,
|
||||
DTLS,
|
||||
RTP,
|
||||
RTCP,
|
||||
SCTP
|
||||
};
|
||||
|
||||
void Categorize();
|
||||
|
||||
void SetType(Type type)
|
||||
{
|
||||
type_ = type;
|
||||
|
@ -786,7 +786,6 @@ NrIceStats NrIceCtx::Destroy() {
|
||||
}
|
||||
|
||||
NrIceCtx::~NrIceCtx() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void NrIceCtx::destroy_peer_ctx() {
|
||||
|
@ -477,6 +477,10 @@ nsresult NrIceMediaStream::GetDefaultCandidate(
|
||||
int component,
|
||||
NrIceCandidate* candidate) const {
|
||||
|
||||
if (!stream_) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nr_ice_candidate *cand;
|
||||
|
||||
int r = nr_ice_media_stream_get_default_candidate(stream_, component, &cand);
|
||||
|
@ -979,6 +979,7 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
}
|
||||
}
|
||||
|
||||
ice_ctx_->Destroy();
|
||||
ice_ctx_ = nullptr;
|
||||
|
||||
if (remote_) {
|
||||
|
@ -482,6 +482,7 @@ class TransportTestPeer : public sigslot::has_slots<> {
|
||||
loopback_->Disconnect();
|
||||
flow_ = nullptr;
|
||||
}
|
||||
ice_ctx_->Destroy();
|
||||
ice_ctx_ = nullptr;
|
||||
streams_.clear();
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "transportflow.h"
|
||||
#include "transportlayer.h"
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
NS_IMPL_ISUPPORTS0(TransportFlow)
|
||||
@ -26,12 +28,12 @@ TransportFlow::~TransportFlow() {
|
||||
// destroy it simultaneously. The conversion to an nsAutoPtr
|
||||
// ensures automatic destruction of the queue at exit of
|
||||
// DestroyFinal.
|
||||
if (target_) {
|
||||
nsAutoPtr<std::deque<TransportLayer*>> layers_tmp(layers_.release());
|
||||
RUN_ON_THREAD(target_,
|
||||
WrapRunnableNM(&TransportFlow::DestroyFinal, layers_tmp),
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
MOZ_RELEASE_ASSERT(target_);
|
||||
nsAutoPtr<std::deque<TransportLayer*>> layers_tmp(layers_.release());
|
||||
DebugOnly<nsresult> rv = target_->Dispatch(
|
||||
WrapRunnableNM(&TransportFlow::DestroyFinal, layers_tmp),
|
||||
NS_DISPATCH_NORMAL);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
void TransportFlow::DestroyFinal(nsAutoPtr<std::deque<TransportLayer *> > layers) {
|
||||
|
@ -100,6 +100,7 @@ int32_t TransportLayerNSPRAdapter::Write(const void *buf, int32_t length) {
|
||||
MediaPacket packet;
|
||||
// Copies. Oh well.
|
||||
packet.Copy(static_cast<const uint8_t*>(buf), static_cast<size_t>(length));
|
||||
packet.SetType(MediaPacket::DTLS);
|
||||
|
||||
TransportResult r = output_->SendPacket(packet);
|
||||
if (r >= 0) {
|
||||
@ -1017,8 +1018,7 @@ void TransportLayerDtls::PacketReceived(TransportLayer* layer,
|
||||
return;
|
||||
}
|
||||
|
||||
// not DTLS per RFC 7983
|
||||
if (packet.data()[0] < 20 || packet.data()[0] > 63) {
|
||||
if (packet.type() != MediaPacket::DTLS) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1048,6 +1048,7 @@ TransportLayerDtls::GetDecryptedPackets()
|
||||
// We have data
|
||||
MOZ_MTLOG(ML_DEBUG, LAYER_INFO << "Read " << rv << " bytes from NSS");
|
||||
MediaPacket packet;
|
||||
packet.SetType(MediaPacket::SCTP);
|
||||
packet.Take(std::move(buffer), static_cast<size_t>(rv));
|
||||
SignalPacketReceived(this, packet);
|
||||
} else if (rv == 0) {
|
||||
|
@ -125,6 +125,7 @@ void TransportLayerIce::PostSetup() {
|
||||
|
||||
TransportResult TransportLayerIce::SendPacket(MediaPacket& packet) {
|
||||
CheckThread();
|
||||
SignalPacketSending(this, packet);
|
||||
nsresult res = stream_->SendPacket(component_,
|
||||
packet.data(),
|
||||
packet.len());
|
||||
@ -182,6 +183,8 @@ void TransportLayerIce::IcePacketReceived(NrIceMediaStream *stream, int componen
|
||||
// footgun though with MediaPackets that end up on the heap.
|
||||
MediaPacket packet;
|
||||
packet.Copy(data, len);
|
||||
packet.Categorize();
|
||||
|
||||
SignalPacketReceived(this, packet);
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,9 @@ class TransportLayerIce : public TransportLayer {
|
||||
void IcePacketReceived(NrIceMediaStream *stream, int component,
|
||||
const unsigned char *data, int len);
|
||||
|
||||
// Useful for capturing encrypted packets
|
||||
sigslot::signal2<TransportLayer*, MediaPacket&> SignalPacketSending;
|
||||
|
||||
TRANSPORT_LAYER_ID("ice")
|
||||
|
||||
private:
|
||||
|
@ -56,40 +56,6 @@ TransportLayerSrtp::Setup()
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsRtp(const unsigned char* data, size_t len)
|
||||
{
|
||||
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 ((data[1] < 192) || (data[1] > 207))
|
||||
return true;
|
||||
|
||||
if (data[1] == 192) // FIR
|
||||
return false;
|
||||
|
||||
if (data[1] == 193) // NACK, but could also be RTP. This makes us sad
|
||||
return true; // but it's how webrtc.org behaves.
|
||||
|
||||
if (data[1] == 194)
|
||||
return true;
|
||||
|
||||
if (data[1] == 195) // IJ.
|
||||
return false;
|
||||
|
||||
if ((data[1] > 195) && (data[1] < 200)) // the > 195 is redundant
|
||||
return true;
|
||||
|
||||
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(MediaPacket& packet)
|
||||
{
|
||||
@ -105,9 +71,11 @@ TransportLayerSrtp::SendPacket(MediaPacket& packet)
|
||||
switch (packet.type()) {
|
||||
case MediaPacket::RTP:
|
||||
res = mSendSrtp->ProtectRtp(packet.data(), packet.len(), packet.capacity(), &out_len);
|
||||
packet.SetType(MediaPacket::SRTP);
|
||||
break;
|
||||
case MediaPacket::RTCP:
|
||||
res = mSendSrtp->ProtectRtcp(packet.data(), packet.len(), packet.capacity(), &out_len);
|
||||
packet.SetType(MediaPacket::SRTCP);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("SRTP layer asked to send packet that is neither RTP or RTCP");
|
||||
@ -227,12 +195,8 @@ TransportLayerSrtp::PacketReceived(TransportLayer* layer, MediaPacket& packet)
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.len() < 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
// not RTP/RTCP per RFC 7983
|
||||
if (packet.data()[0] <= 127 || packet.data()[0] >= 192) {
|
||||
if (packet.type() != MediaPacket::SRTP &&
|
||||
packet.type() != MediaPacket::SRTCP) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -241,7 +205,7 @@ TransportLayerSrtp::PacketReceived(TransportLayer* layer, MediaPacket& packet)
|
||||
int outLen;
|
||||
nsresult res;
|
||||
|
||||
if (IsRtp(packet.data(), packet.len())) {
|
||||
if (packet.type() == MediaPacket::SRTP) {
|
||||
packet.SetType(MediaPacket::RTP);
|
||||
res = mRecvSrtp->UnprotectRtp(packet.data(), packet.len(), packet.len(), &outLen);
|
||||
} else {
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
#include "mtransport_test_utils.h"
|
||||
#include "SharedBuffer.h"
|
||||
#include "MediaTransportHandler.h"
|
||||
|
||||
#define GTEST_HAS_RTTI 0
|
||||
#include "gtest/gtest.h"
|
||||
@ -164,63 +165,71 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class TransportInfo {
|
||||
class LoopbackTransport : public MediaTransportBase {
|
||||
public:
|
||||
TransportInfo() :
|
||||
flow_(nullptr),
|
||||
loopback_(nullptr) {}
|
||||
LoopbackTransport()
|
||||
{
|
||||
SetState("mux", TransportLayer::TS_INIT, false);
|
||||
SetState("mux", TransportLayer::TS_INIT, true);
|
||||
SetState("non-mux", TransportLayer::TS_INIT, false);
|
||||
SetState("non-mux", TransportLayer::TS_INIT, true);
|
||||
}
|
||||
|
||||
static void InitAndConnect(TransportInfo &client, TransportInfo &server) {
|
||||
client.Init(true);
|
||||
server.Init(false);
|
||||
static void InitAndConnect(LoopbackTransport &client, LoopbackTransport &server) {
|
||||
client.Connect(&server);
|
||||
server.Connect(&client);
|
||||
}
|
||||
|
||||
void Init(bool client) {
|
||||
UniquePtr<TransportLayerLoopback> loopback(new TransportLayerLoopback);
|
||||
UniquePtr<TransportLayerDtls> dtls(new TransportLayerDtls);
|
||||
UniquePtr<TransportLayerSrtp> srtp(new TransportLayerSrtp(*dtls));
|
||||
|
||||
std::vector<uint16_t> ciphers;
|
||||
ciphers.push_back(kDtlsSrtpAeadAes256Gcm);
|
||||
dtls->SetSrtpCiphers(ciphers);
|
||||
dtls->SetIdentity(DtlsIdentity::Generate());
|
||||
dtls->SetRole(client ? TransportLayerDtls::CLIENT :
|
||||
TransportLayerDtls::SERVER);
|
||||
dtls->SetVerificationAllowAll();
|
||||
|
||||
ASSERT_EQ(NS_OK, loopback->Init());
|
||||
ASSERT_EQ(NS_OK, dtls->Init());
|
||||
ASSERT_EQ(NS_OK, srtp->Init());
|
||||
|
||||
dtls->Chain(loopback.get());
|
||||
srtp->Chain(loopback.get());
|
||||
|
||||
flow_ = new TransportFlow();
|
||||
loopback_ = loopback.release();
|
||||
flow_->PushLayer(loopback_);
|
||||
flow_->PushLayer(dtls.release());
|
||||
flow_->PushLayer(srtp.release());
|
||||
}
|
||||
|
||||
void Connect(TransportInfo* peer) {
|
||||
MOZ_ASSERT(loopback_);
|
||||
MOZ_ASSERT(peer->loopback_);
|
||||
|
||||
loopback_->Connect(peer->loopback_);
|
||||
void Connect(LoopbackTransport* peer) {
|
||||
peer_ = peer;
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
if (loopback_) {
|
||||
loopback_->Disconnect();
|
||||
}
|
||||
loopback_ = nullptr;
|
||||
flow_ = nullptr;
|
||||
peer_ = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<TransportFlow> flow_;
|
||||
TransportLayerLoopback *loopback_;
|
||||
nsresult SendPacket(const std::string& aTransportId,
|
||||
MediaPacket& aPacket) override
|
||||
{
|
||||
peer_->SignalPacketReceived(aTransportId, aPacket);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
TransportLayer::State GetState(const std::string& aTransportId,
|
||||
bool aRtcp) const override
|
||||
{
|
||||
if (aRtcp) {
|
||||
auto it = mRtcpStates.find(aTransportId);
|
||||
if (it != mRtcpStates.end()) {
|
||||
return it->second;
|
||||
}
|
||||
} else {
|
||||
auto it = mRtpStates.find(aTransportId);
|
||||
if (it != mRtpStates.end()) {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
return TransportLayer::TS_NONE;
|
||||
}
|
||||
|
||||
void SetState(const std::string& aTransportId,
|
||||
TransportLayer::State aState,
|
||||
bool aRtcp)
|
||||
{
|
||||
if (aRtcp) {
|
||||
mRtcpStates[aTransportId] = aState;
|
||||
SignalRtcpStateChange(aTransportId, aState);
|
||||
} else {
|
||||
mRtpStates[aTransportId] = aState;
|
||||
SignalStateChange(aTransportId, aState);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<MediaTransportBase> peer_;
|
||||
std::map<std::string, TransportLayer::State> mRtpStates;
|
||||
std::map<std::string, TransportLayer::State> mRtcpStates;
|
||||
};
|
||||
|
||||
class TestAgent {
|
||||
@ -229,26 +238,35 @@ class TestAgent {
|
||||
audio_config_(109, "opus", 48000, 960, 2, 64000, false),
|
||||
audio_conduit_(mozilla::AudioSessionConduit::Create()),
|
||||
audio_pipeline_(),
|
||||
use_bundle_(false) {
|
||||
transport_(new LoopbackTransport) {
|
||||
}
|
||||
|
||||
static void ConnectRtp(TestAgent *client, TestAgent *server) {
|
||||
TransportInfo::InitAndConnect(client->audio_rtp_transport_,
|
||||
server->audio_rtp_transport_);
|
||||
static void Connect(TestAgent *client, TestAgent *server) {
|
||||
LoopbackTransport::InitAndConnect(*client->transport_,
|
||||
*server->transport_);
|
||||
}
|
||||
|
||||
static void ConnectRtcp(TestAgent *client, TestAgent *server) {
|
||||
TransportInfo::InitAndConnect(client->audio_rtcp_transport_,
|
||||
server->audio_rtcp_transport_);
|
||||
virtual void CreatePipeline(const std::string& aTransportId) = 0;
|
||||
|
||||
void SetState(const std::string& aTransportId,
|
||||
TransportLayer::State aState,
|
||||
bool aRtcp)
|
||||
{
|
||||
mozilla::SyncRunnable::DispatchToThread(
|
||||
test_utils->sts_target(),
|
||||
WrapRunnable(transport_,
|
||||
&LoopbackTransport::SetState, aTransportId, aState, aRtcp));
|
||||
}
|
||||
|
||||
static void ConnectBundle(TestAgent *client, TestAgent *server) {
|
||||
TransportInfo::InitAndConnect(client->bundle_transport_,
|
||||
server->bundle_transport_);
|
||||
void UpdateTransport(const std::string& aTransportId,
|
||||
nsAutoPtr<MediaPipelineFilter> aFilter)
|
||||
{
|
||||
mozilla::SyncRunnable::DispatchToThread(
|
||||
test_utils->sts_target(),
|
||||
WrapRunnable(audio_pipeline_,
|
||||
&MediaPipeline::UpdateTransport_s, aTransportId, aFilter));
|
||||
}
|
||||
|
||||
virtual void CreatePipeline(bool aIsRtcpMux) = 0;
|
||||
|
||||
void Stop() {
|
||||
MOZ_MTLOG(ML_DEBUG, "Stopping");
|
||||
|
||||
@ -257,9 +275,7 @@ class TestAgent {
|
||||
}
|
||||
|
||||
void Shutdown_s() {
|
||||
audio_rtp_transport_.Shutdown();
|
||||
audio_rtcp_transport_.Shutdown();
|
||||
bundle_transport_.Shutdown();
|
||||
transport_->Shutdown();
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
@ -301,11 +317,6 @@ class TestAgent {
|
||||
return audio_pipeline_->RtcpPacketsReceived();
|
||||
}
|
||||
|
||||
|
||||
void SetUsingBundle(bool use_bundle) {
|
||||
use_bundle_ = use_bundle;
|
||||
}
|
||||
|
||||
protected:
|
||||
mozilla::AudioCodecConfig audio_config_;
|
||||
RefPtr<mozilla::MediaSessionConduit> audio_conduit_;
|
||||
@ -314,10 +325,7 @@ class TestAgent {
|
||||
// both directions; only the sender's RTCP is sent, but the receiver should
|
||||
// be sending it too.
|
||||
RefPtr<mozilla::MediaPipeline> audio_pipeline_;
|
||||
TransportInfo audio_rtp_transport_;
|
||||
TransportInfo audio_rtcp_transport_;
|
||||
TransportInfo bundle_transport_;
|
||||
bool use_bundle_;
|
||||
RefPtr<LoopbackTransport> transport_;
|
||||
};
|
||||
|
||||
class TestAgentSend : public TestAgent {
|
||||
@ -331,17 +339,14 @@ class TestAgentSend : public TestAgent {
|
||||
audio_stream_track_ = new FakeAudioStreamTrack();
|
||||
}
|
||||
|
||||
virtual void CreatePipeline(bool aIsRtcpMux) {
|
||||
virtual void CreatePipeline(const std::string& aTransportId) {
|
||||
|
||||
std::string test_pc;
|
||||
|
||||
if (aIsRtcpMux) {
|
||||
ASSERT_FALSE(audio_rtcp_transport_.flow_);
|
||||
}
|
||||
|
||||
RefPtr<MediaPipelineTransmit> audio_pipeline =
|
||||
new mozilla::MediaPipelineTransmit(
|
||||
test_pc,
|
||||
transport_,
|
||||
nullptr,
|
||||
test_utils->sts_target(),
|
||||
false,
|
||||
@ -352,16 +357,8 @@ class TestAgentSend : public TestAgent {
|
||||
|
||||
audio_pipeline_ = audio_pipeline;
|
||||
|
||||
RefPtr<TransportFlow> rtp(audio_rtp_transport_.flow_);
|
||||
RefPtr<TransportFlow> rtcp(audio_rtcp_transport_.flow_);
|
||||
|
||||
if (use_bundle_) {
|
||||
rtp = bundle_transport_.flow_;
|
||||
rtcp = nullptr;
|
||||
}
|
||||
|
||||
audio_pipeline_->UpdateTransport_m(
|
||||
rtp, rtcp, nsAutoPtr<MediaPipelineFilter>(nullptr));
|
||||
audio_pipeline_->UpdateTransport_m(aTransportId,
|
||||
nsAutoPtr<MediaPipelineFilter>(nullptr));
|
||||
}
|
||||
};
|
||||
|
||||
@ -379,15 +376,12 @@ class TestAgentReceive : public TestAgent {
|
||||
EXPECT_EQ(mozilla::kMediaConduitNoError, err);
|
||||
}
|
||||
|
||||
virtual void CreatePipeline(bool aIsRtcpMux) {
|
||||
virtual void CreatePipeline(const std::string& aTransportId) {
|
||||
std::string test_pc;
|
||||
|
||||
if (aIsRtcpMux) {
|
||||
ASSERT_FALSE(audio_rtcp_transport_.flow_);
|
||||
}
|
||||
|
||||
audio_pipeline_ = new mozilla::MediaPipelineReceiveAudio(
|
||||
test_pc,
|
||||
transport_,
|
||||
nullptr,
|
||||
test_utils->sts_target(),
|
||||
static_cast<mozilla::AudioSessionConduit *>(audio_conduit_.get()),
|
||||
@ -395,26 +389,16 @@ class TestAgentReceive : public TestAgent {
|
||||
|
||||
audio_pipeline_->Start();
|
||||
|
||||
RefPtr<TransportFlow> rtp(audio_rtp_transport_.flow_);
|
||||
RefPtr<TransportFlow> rtcp(audio_rtcp_transport_.flow_);
|
||||
|
||||
if (use_bundle_) {
|
||||
rtp = bundle_transport_.flow_;
|
||||
rtcp = nullptr;
|
||||
}
|
||||
|
||||
audio_pipeline_->UpdateTransport_m(rtp, rtcp, bundle_filter_);
|
||||
audio_pipeline_->UpdateTransport_m(aTransportId, bundle_filter_);
|
||||
}
|
||||
|
||||
void SetBundleFilter(nsAutoPtr<MediaPipelineFilter> filter) {
|
||||
bundle_filter_ = filter;
|
||||
}
|
||||
|
||||
void UpdateFilter_s(
|
||||
void UpdateTransport_s(const std::string& aTransportId,
|
||||
nsAutoPtr<MediaPipelineFilter> filter) {
|
||||
audio_pipeline_->UpdateTransport_s(audio_rtp_transport_.flow_,
|
||||
audio_rtcp_transport_.flow_,
|
||||
filter);
|
||||
audio_pipeline_->UpdateTransport_s(aTransportId, filter);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -436,24 +420,10 @@ class MediaPipelineTest : public ::testing::Test {
|
||||
}
|
||||
|
||||
// Setup transport.
|
||||
void InitTransports(bool aIsRtcpMux) {
|
||||
// RTP, p1_ is server, p2_ is client
|
||||
void InitTransports() {
|
||||
mozilla::SyncRunnable::DispatchToThread(
|
||||
test_utils->sts_target(),
|
||||
WrapRunnableNM(&TestAgent::ConnectRtp, &p2_, &p1_));
|
||||
|
||||
// Create RTCP flows separately if we are not muxing them.
|
||||
if(!aIsRtcpMux) {
|
||||
// RTCP, p1_ is server, p2_ is client
|
||||
mozilla::SyncRunnable::DispatchToThread(
|
||||
test_utils->sts_target(),
|
||||
WrapRunnableNM(&TestAgent::ConnectRtcp, &p2_, &p1_));
|
||||
}
|
||||
|
||||
// BUNDLE, p1_ is server, p2_ is client
|
||||
mozilla::SyncRunnable::DispatchToThread(
|
||||
test_utils->sts_target(),
|
||||
WrapRunnableNM(&TestAgent::ConnectBundle, &p2_, &p1_));
|
||||
WrapRunnableNM(&TestAgent::Connect, &p2_, &p1_));
|
||||
}
|
||||
|
||||
// Verify RTP and RTCP
|
||||
@ -473,10 +443,28 @@ class MediaPipelineTest : public ::testing::Test {
|
||||
p2_.SetBundleFilter(initialFilter);
|
||||
|
||||
// Setup transport flows
|
||||
InitTransports(aIsRtcpMux);
|
||||
InitTransports();
|
||||
|
||||
p1_.CreatePipeline(aIsRtcpMux);
|
||||
p2_.CreatePipeline(aIsRtcpMux);
|
||||
std::string transportId = aIsRtcpMux ? "mux" : "non-mux";
|
||||
p1_.CreatePipeline(transportId);
|
||||
p2_.CreatePipeline(transportId);
|
||||
|
||||
// Set state of transports to CONNECTING. MediaPipeline doesn't really care
|
||||
// about this transition, but we're trying to simluate what happens in a
|
||||
// real case.
|
||||
p1_.SetState(transportId, TransportLayer::TS_CONNECTING, false);
|
||||
p1_.SetState(transportId, TransportLayer::TS_CONNECTING, true);
|
||||
p2_.SetState(transportId, TransportLayer::TS_CONNECTING, false);
|
||||
p2_.SetState(transportId, TransportLayer::TS_CONNECTING, true);
|
||||
|
||||
PR_Sleep(10);
|
||||
|
||||
// Set state of transports to OPEN (ie; connected). This should result in
|
||||
// media flowing.
|
||||
p1_.SetState(transportId, TransportLayer::TS_OPEN, false);
|
||||
p1_.SetState(transportId, TransportLayer::TS_OPEN, true);
|
||||
p2_.SetState(transportId, TransportLayer::TS_OPEN, false);
|
||||
p2_.SetState(transportId, TransportLayer::TS_OPEN, true);
|
||||
|
||||
if (bundle) {
|
||||
PR_Sleep(ms_until_filter_update);
|
||||
@ -489,11 +477,7 @@ class MediaPipelineTest : public ::testing::Test {
|
||||
refinedFilter->AddRemoteSSRC(p1_.GetLocalSSRC());
|
||||
}
|
||||
|
||||
mozilla::SyncRunnable::DispatchToThread(
|
||||
test_utils->sts_target(),
|
||||
WrapRunnable(&p2_,
|
||||
&TestAgentReceive::UpdateFilter_s,
|
||||
refinedFilter));
|
||||
p2_.UpdateTransport(transportId, refinedFilter);
|
||||
}
|
||||
|
||||
// wait for some RTP/RTCP tx and rx to happen
|
||||
|
@ -44,13 +44,8 @@
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "nsError.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nspr.h"
|
||||
#include "runnable_utils.h"
|
||||
#include "srtp.h"
|
||||
#include "transportflow.h"
|
||||
#include "transportlayer.h"
|
||||
#include "transportlayerdtls.h"
|
||||
#include "transportlayerice.h"
|
||||
#include "signaling/src/peerconnection/MediaTransportHandler.h"
|
||||
#include "Tracing.h"
|
||||
|
||||
#include "webrtc/base/bind.h"
|
||||
@ -602,15 +597,15 @@ protected:
|
||||
};
|
||||
|
||||
MediaPipeline::MediaPipeline(const std::string& aPc,
|
||||
MediaTransportBase* aTransportHandler,
|
||||
DirectionType aDirection,
|
||||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
nsCOMPtr<nsIEventTarget> aStsThread,
|
||||
RefPtr<MediaSessionConduit> aConduit)
|
||||
: mDirection(aDirection)
|
||||
, mLevel(0)
|
||||
, mTransportHandler(aTransportHandler)
|
||||
, mConduit(aConduit)
|
||||
, mRtp(nullptr, RTP)
|
||||
, mRtcp(nullptr, RTCP)
|
||||
, mMainThread(aMainThread)
|
||||
, mStsThread(aStsThread)
|
||||
, mTransport(new PipelineTransport(aStsThread))
|
||||
@ -660,74 +655,49 @@ MediaPipeline::DetachTransport_s()
|
||||
("%s in %s", mDescription.c_str(), __FUNCTION__));
|
||||
|
||||
disconnect_all();
|
||||
mRtpState = TransportLayer::TS_NONE;
|
||||
mRtcpState = TransportLayer::TS_NONE;
|
||||
mTransportId.clear();
|
||||
mTransport->Detach();
|
||||
mRtp.Detach();
|
||||
mRtcp.Detach();
|
||||
|
||||
// Make sure any cycles are broken
|
||||
mPacketDumper = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaPipeline::AttachTransport_s()
|
||||
{
|
||||
ASSERT_ON_THREAD(mStsThread);
|
||||
nsresult res;
|
||||
MOZ_ASSERT(mRtp.mTransport);
|
||||
MOZ_ASSERT(mRtcp.mTransport);
|
||||
res = ConnectTransport_s(mRtp);
|
||||
if (NS_FAILED(res)) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (mRtcp.mTransport != mRtp.mTransport) {
|
||||
res = ConnectTransport_s(mRtcp);
|
||||
if (NS_FAILED(res)) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
mTransport->Attach(this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaPipeline::UpdateTransport_m(RefPtr<TransportFlow> aRtpTransport,
|
||||
RefPtr<TransportFlow> aRtcpTransport,
|
||||
MediaPipeline::UpdateTransport_m(const std::string& aTransportId,
|
||||
nsAutoPtr<MediaPipelineFilter> aFilter)
|
||||
{
|
||||
RUN_ON_THREAD(mStsThread,
|
||||
WrapRunnable(RefPtr<MediaPipeline>(this),
|
||||
&MediaPipeline::UpdateTransport_s,
|
||||
aRtpTransport,
|
||||
aRtcpTransport,
|
||||
aTransportId,
|
||||
aFilter),
|
||||
NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
MediaPipeline::UpdateTransport_s(RefPtr<TransportFlow> aRtpTransport,
|
||||
RefPtr<TransportFlow> aRtcpTransport,
|
||||
MediaPipeline::UpdateTransport_s(const std::string& aTransportId,
|
||||
nsAutoPtr<MediaPipelineFilter> aFilter)
|
||||
{
|
||||
bool rtcp_mux = false;
|
||||
if (!aRtcpTransport) {
|
||||
aRtcpTransport = aRtpTransport;
|
||||
rtcp_mux = true;
|
||||
ASSERT_ON_THREAD(mStsThread);
|
||||
if (!mSignalsConnected) {
|
||||
mTransportHandler->SignalStateChange.connect(
|
||||
this, &MediaPipeline::RtpStateChange);
|
||||
mTransportHandler->SignalRtcpStateChange.connect(
|
||||
this, &MediaPipeline::RtcpStateChange);
|
||||
mTransportHandler->SignalEncryptedSending.connect(
|
||||
this, &MediaPipeline::EncryptedPacketSending);
|
||||
mTransportHandler->SignalPacketReceived.connect(
|
||||
this, &MediaPipeline::PacketReceived);
|
||||
mSignalsConnected = true;
|
||||
}
|
||||
|
||||
if ((aRtpTransport != mRtp.mTransport) ||
|
||||
(aRtcpTransport != mRtcp.mTransport)) {
|
||||
disconnect_all();
|
||||
mTransport->Detach();
|
||||
mRtp.Detach();
|
||||
mRtcp.Detach();
|
||||
if (aRtpTransport && aRtcpTransport) {
|
||||
mRtp = TransportInfo(aRtpTransport, rtcp_mux ? MUX : RTP);
|
||||
mRtcp = TransportInfo(aRtcpTransport, rtcp_mux ? MUX : RTCP);
|
||||
AttachTransport_s();
|
||||
}
|
||||
if (aTransportId != mTransportId) {
|
||||
mTransportId = aTransportId;
|
||||
mRtpState = mTransportHandler->GetState(mTransportId, false);
|
||||
mRtcpState = mTransportHandler->GetState(mTransportId, true);
|
||||
CheckTransportStates();
|
||||
}
|
||||
|
||||
if (mFilter && aFilter) {
|
||||
@ -790,121 +760,80 @@ MediaPipeline::GetContributingSourceStats(
|
||||
}
|
||||
|
||||
void
|
||||
MediaPipeline::StateChange(TransportLayer* aLayer, TransportLayer::State aState)
|
||||
MediaPipeline::RtpStateChange(const std::string& aTransportId,
|
||||
TransportLayer::State aState)
|
||||
{
|
||||
TransportInfo* info = GetTransportInfo_s(aLayer);
|
||||
MOZ_ASSERT(info);
|
||||
|
||||
if (aState == TransportLayer::TS_OPEN) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Info, ("Flow is ready"));
|
||||
TransportReady_s(*info);
|
||||
} else if (aState == TransportLayer::TS_CLOSED ||
|
||||
aState == TransportLayer::TS_ERROR) {
|
||||
TransportFailed_s(*info);
|
||||
if (mTransportId != aTransportId) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
MakeRtpTypeToStringArray(const char** aArray)
|
||||
{
|
||||
static const char* RTP_str = "RTP";
|
||||
static const char* RTCP_str = "RTCP";
|
||||
static const char* MUX_str = "RTP/RTCP mux";
|
||||
aArray[MediaPipeline::RTP] = RTP_str;
|
||||
aArray[MediaPipeline::RTCP] = RTCP_str;
|
||||
aArray[MediaPipeline::MUX] = MUX_str;
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char*
|
||||
ToString(MediaPipeline::RtpType type)
|
||||
{
|
||||
static const char* array[(int)MediaPipeline::MAX_RTP_TYPE] = { nullptr };
|
||||
// Dummy variable to cause init to happen only on first call
|
||||
static bool dummy = MakeRtpTypeToStringArray(array);
|
||||
(void)dummy;
|
||||
return array[type];
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaPipeline::TransportReady_s(TransportInfo& aInfo)
|
||||
{
|
||||
// TODO(ekr@rtfm.com): implement some kind of notification on
|
||||
// failure. bug 852665.
|
||||
if (aInfo.mState != StateType::MP_CONNECTING) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Error,
|
||||
("Transport ready for flow in wrong state:%s :%s",
|
||||
mDescription.c_str(),
|
||||
ToString(aInfo.mType)));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Info,
|
||||
("Transport ready for pipeline %p flow %s: %s",
|
||||
this,
|
||||
mDescription.c_str(),
|
||||
ToString(aInfo.mType)));
|
||||
|
||||
if (mDirection == DirectionType::RECEIVE) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Info,
|
||||
("Listening for %s packets received on %p",
|
||||
ToString(aInfo.mType),
|
||||
aInfo.mSrtp));
|
||||
|
||||
aInfo.mSrtp->SignalPacketReceived.connect(
|
||||
this, &MediaPipeline::PacketReceived);
|
||||
}
|
||||
|
||||
aInfo.mState = StateType::MP_OPEN;
|
||||
UpdateRtcpMuxState(aInfo);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaPipeline::TransportFailed_s(TransportInfo& aInfo)
|
||||
{
|
||||
ASSERT_ON_THREAD(mStsThread);
|
||||
|
||||
aInfo.mState = StateType::MP_CLOSED;
|
||||
UpdateRtcpMuxState(aInfo);
|
||||
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Info,
|
||||
("Transport closed for flow %s", ToString(aInfo.mType)));
|
||||
|
||||
NS_WARNING(
|
||||
"MediaPipeline Transport failed. This is not properly cleaned up yet");
|
||||
|
||||
// TODO(ekr@rtfm.com): SECURITY: Figure out how to clean up if the
|
||||
// connection was good and now it is bad.
|
||||
// TODO(ekr@rtfm.com): Report up so that the PC knows we
|
||||
// have experienced an error.
|
||||
|
||||
return NS_OK;
|
||||
mRtpState = aState;
|
||||
CheckTransportStates();
|
||||
}
|
||||
|
||||
void
|
||||
MediaPipeline::UpdateRtcpMuxState(TransportInfo& aInfo)
|
||||
MediaPipeline::RtcpStateChange(const std::string& aTransportId,
|
||||
TransportLayer::State aState)
|
||||
{
|
||||
if (aInfo.mType == MUX) {
|
||||
if (aInfo.mTransport == mRtcp.mTransport) {
|
||||
mRtcp.mState = aInfo.mState;
|
||||
}
|
||||
if (mTransportId != aTransportId) {
|
||||
return;
|
||||
}
|
||||
mRtcpState = aState;
|
||||
CheckTransportStates();
|
||||
}
|
||||
|
||||
void
|
||||
MediaPipeline::CheckTransportStates()
|
||||
{
|
||||
ASSERT_ON_THREAD(mStsThread);
|
||||
|
||||
if (mRtpState == TransportLayer::TS_CLOSED ||
|
||||
mRtpState == TransportLayer::TS_ERROR ||
|
||||
mRtcpState == TransportLayer::TS_CLOSED ||
|
||||
mRtcpState == TransportLayer::TS_ERROR) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Warning,
|
||||
("RTP Transport failed for pipeline %p flow %s",
|
||||
this,
|
||||
mDescription.c_str()));
|
||||
|
||||
NS_WARNING(
|
||||
"MediaPipeline Transport failed. This is not properly cleaned up yet");
|
||||
// TODO(ekr@rtfm.com): SECURITY: Figure out how to clean up if the
|
||||
// connection was good and now it is bad.
|
||||
// TODO(ekr@rtfm.com): Report up so that the PC knows we
|
||||
// have experienced an error.
|
||||
mTransport->Detach();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRtpState == TransportLayer::TS_OPEN) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Info,
|
||||
("RTP Transport ready for pipeline %p flow %s",
|
||||
this,
|
||||
mDescription.c_str()));
|
||||
}
|
||||
|
||||
if (mRtcpState == TransportLayer::TS_OPEN) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Info,
|
||||
("RTCP Transport ready for pipeline %p flow %s",
|
||||
this,
|
||||
mDescription.c_str()));
|
||||
}
|
||||
|
||||
if (mRtpState == TransportLayer::TS_OPEN && mRtcpState == mRtpState) {
|
||||
mTransport->Attach(this);
|
||||
TransportReady_s();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaPipeline::SendPacket(TransportLayer* aLayer, MediaPacket& packet)
|
||||
MediaPipeline::SendPacket(MediaPacket& packet)
|
||||
{
|
||||
ASSERT_ON_THREAD(mStsThread);
|
||||
MOZ_ASSERT(mRtpState == TransportLayer::TS_OPEN);
|
||||
MOZ_ASSERT(!mTransportId.empty());
|
||||
nsresult rv = mTransportHandler->SendPacket(mTransportId, packet);
|
||||
|
||||
int len = packet.len();
|
||||
TransportResult res = aLayer->SendPacket(packet);
|
||||
|
||||
if (res != len) {
|
||||
// Ignore blocking indications
|
||||
if (res == TE_WOULDBLOCK)
|
||||
return NS_OK;
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Error,
|
||||
("Failed write on stream %s", mDescription.c_str()));
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
@ -921,11 +850,10 @@ MediaPipeline::IncrementRtpPacketsSent(int32_t aBytes)
|
||||
|
||||
if (!(mRtpPacketsSent % 100)) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Info,
|
||||
("RTP sent packet count for %s Pipeline %p Flow: %p: %u (%" PRId64
|
||||
("RTP sent packet count for %s Pipeline %p: %u (%" PRId64
|
||||
" bytes)",
|
||||
mDescription.c_str(),
|
||||
this,
|
||||
static_cast<void*>(mRtp.mTransport),
|
||||
mRtpPacketsSent,
|
||||
mRtpBytesSent));
|
||||
}
|
||||
@ -937,10 +865,9 @@ MediaPipeline::IncrementRtcpPacketsSent()
|
||||
++mRtcpPacketsSent;
|
||||
if (!(mRtcpPacketsSent % 100)) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Info,
|
||||
("RTCP sent packet count for %s Pipeline %p Flow: %p: %u",
|
||||
("RTCP sent packet count for %s Pipeline %p: %u",
|
||||
mDescription.c_str(),
|
||||
this,
|
||||
static_cast<void*>(mRtp.mTransport),
|
||||
mRtcpPacketsSent));
|
||||
}
|
||||
}
|
||||
@ -952,11 +879,10 @@ MediaPipeline::IncrementRtpPacketsReceived(int32_t aBytes)
|
||||
mRtpBytesReceived += aBytes;
|
||||
if (!(mRtpPacketsReceived % 100)) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Info,
|
||||
("RTP received packet count for %s Pipeline %p Flow: %p: %u (%"
|
||||
("RTP received packet count for %s Pipeline %p: %u (%"
|
||||
PRId64 " bytes)",
|
||||
mDescription.c_str(),
|
||||
this,
|
||||
static_cast<void*>(mRtp.mTransport),
|
||||
mRtpPacketsReceived,
|
||||
mRtpBytesReceived));
|
||||
}
|
||||
@ -968,16 +894,15 @@ MediaPipeline::IncrementRtcpPacketsReceived()
|
||||
++mRtcpPacketsReceived;
|
||||
if (!(mRtcpPacketsReceived % 100)) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Info,
|
||||
("RTCP received packet count for %s Pipeline %p Flow: %p: %u",
|
||||
("RTCP received packet count for %s Pipeline %p: %u",
|
||||
mDescription.c_str(),
|
||||
this,
|
||||
static_cast<void*>(mRtp.mTransport),
|
||||
mRtcpPacketsReceived));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaPipeline::RtpPacketReceived(TransportLayer* aLayer, MediaPacket& packet)
|
||||
MediaPipeline::RtpPacketReceived(MediaPacket& packet)
|
||||
{
|
||||
if (mDirection == DirectionType::TRANSMIT) {
|
||||
return;
|
||||
@ -995,18 +920,6 @@ MediaPipeline::RtpPacketReceived(TransportLayer* aLayer, MediaPacket& packet)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRtp.mState != StateType::MP_OPEN) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Error,
|
||||
("Discarding incoming packet; pipeline not open"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRtp.mSrtp->state() != TransportLayer::TS_OPEN) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Error,
|
||||
("Discarding incoming packet; transport not open"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!packet.len()) {
|
||||
return;
|
||||
}
|
||||
@ -1078,7 +991,7 @@ MediaPipeline::RtpPacketReceived(TransportLayer* aLayer, MediaPacket& packet)
|
||||
}
|
||||
|
||||
void
|
||||
MediaPipeline::RtcpPacketReceived(TransportLayer* aLayer, MediaPacket& packet)
|
||||
MediaPipeline::RtcpPacketReceived(MediaPacket& packet)
|
||||
{
|
||||
if (!mTransport->Pipeline()) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Debug,
|
||||
@ -1092,18 +1005,6 @@ MediaPipeline::RtcpPacketReceived(TransportLayer* aLayer, MediaPacket& packet)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRtcp.mState != StateType::MP_OPEN) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Debug,
|
||||
("Discarding incoming packet; pipeline not open"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRtcp.mSrtp->state() != TransportLayer::TS_OPEN) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Error,
|
||||
("Discarding incoming packet; transport not open"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!packet.len()) {
|
||||
return;
|
||||
}
|
||||
@ -1131,8 +1032,13 @@ MediaPipeline::RtcpPacketReceived(TransportLayer* aLayer, MediaPacket& packet)
|
||||
}
|
||||
|
||||
void
|
||||
MediaPipeline::PacketReceived(TransportLayer* aLayer, MediaPacket& packet)
|
||||
MediaPipeline::PacketReceived(const std::string& aTransportId,
|
||||
MediaPacket& packet)
|
||||
{
|
||||
if (mTransportId != aTransportId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mTransport->Pipeline()) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Debug,
|
||||
("Discarding incoming packet; transport disconnected"));
|
||||
@ -1141,13 +1047,34 @@ MediaPipeline::PacketReceived(TransportLayer* aLayer, MediaPacket& packet)
|
||||
|
||||
switch (packet.type()) {
|
||||
case MediaPacket::RTP:
|
||||
RtpPacketReceived(aLayer, packet);
|
||||
RtpPacketReceived(packet);
|
||||
break;
|
||||
case MediaPacket::RTCP:
|
||||
RtcpPacketReceived(aLayer, packet);
|
||||
RtcpPacketReceived(packet);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("TransportLayerSrtp let something other than RTP/RTCP through");
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaPipeline::EncryptedPacketSending(const std::string& aTransportId,
|
||||
MediaPacket& aPacket)
|
||||
{
|
||||
if (mTransportId == aTransportId) {
|
||||
dom::mozPacketDumpType type;
|
||||
if (aPacket.type() == MediaPacket::SRTP) {
|
||||
type = dom::mozPacketDumpType::Srtp;
|
||||
} else if (aPacket.type() == MediaPacket::SRTCP) {
|
||||
type = dom::mozPacketDumpType::Srtcp;
|
||||
} else if (aPacket.type() == MediaPacket::DTLS) {
|
||||
// TODO(bug 1497936): Implement packet dump for DTLS
|
||||
return;
|
||||
} else {
|
||||
MOZ_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
mPacketDumper->Dump(Level(), type, true, aPacket.data(), aPacket.len());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1273,11 +1200,13 @@ protected:
|
||||
|
||||
MediaPipelineTransmit::MediaPipelineTransmit(
|
||||
const std::string& aPc,
|
||||
MediaTransportBase* aTransportHandler,
|
||||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
nsCOMPtr<nsIEventTarget> aStsThread,
|
||||
bool aIsVideo,
|
||||
RefPtr<MediaSessionConduit> aConduit)
|
||||
: MediaPipeline(aPc,
|
||||
aTransportHandler,
|
||||
DirectionType::TRANSMIT,
|
||||
aMainThread,
|
||||
aStsThread,
|
||||
@ -1468,19 +1397,13 @@ MediaPipelineTransmit::DetachMedia()
|
||||
// Let the listener be destroyed with the pipeline (or later).
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaPipelineTransmit::TransportReady_s(TransportInfo& aInfo)
|
||||
void
|
||||
MediaPipelineTransmit::TransportReady_s()
|
||||
{
|
||||
ASSERT_ON_THREAD(mStsThread);
|
||||
// Call base ready function.
|
||||
MediaPipeline::TransportReady_s(aInfo);
|
||||
|
||||
// Should not be set for a transmitter
|
||||
if (&aInfo == &mRtp) {
|
||||
mListener->SetActive(true);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
MediaPipeline::TransportReady_s();
|
||||
mListener->SetActive(true);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -1510,51 +1433,6 @@ MediaPipelineTransmit::SetTrack(MediaStreamTrack* aDomTrack)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaPipeline::ConnectTransport_s(TransportInfo& aInfo)
|
||||
{
|
||||
MOZ_ASSERT(aInfo.mTransport);
|
||||
MOZ_ASSERT(aInfo.mSrtp);
|
||||
ASSERT_ON_THREAD(mStsThread);
|
||||
|
||||
// Look to see if the transport is ready
|
||||
if (aInfo.mSrtp->state() == TransportLayer::TS_OPEN) {
|
||||
nsresult res = TransportReady_s(aInfo);
|
||||
if (NS_FAILED(res)) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Error,
|
||||
("Error calling TransportReady(); res=%u in %s",
|
||||
static_cast<uint32_t>(res),
|
||||
__FUNCTION__));
|
||||
return res;
|
||||
}
|
||||
} else if (aInfo.mSrtp->state() == TransportLayer::TS_ERROR) {
|
||||
MOZ_LOG(gMediaPipelineLog, LogLevel::Error,
|
||||
("%s transport is already in error state",
|
||||
ToString(aInfo.mType)));
|
||||
TransportFailed_s(aInfo);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aInfo.mSrtp->SignalStateChange.connect(this, &MediaPipeline::StateChange);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MediaPipeline::TransportInfo*
|
||||
MediaPipeline::GetTransportInfo_s(TransportLayer* aLayer)
|
||||
{
|
||||
ASSERT_ON_THREAD(mStsThread);
|
||||
if (aLayer == mRtp.mSrtp) {
|
||||
return &mRtp;
|
||||
}
|
||||
|
||||
if (aLayer == mRtcp.mSrtp) {
|
||||
return &mRtcp;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaPipeline::PipelineTransport::SendRtpPacket(const uint8_t* aData, size_t aLen)
|
||||
{
|
||||
@ -1583,15 +1461,13 @@ MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s(
|
||||
return NS_OK; // Detached
|
||||
}
|
||||
|
||||
TransportInfo& transport = isRtp ? mPipeline->mRtp : mPipeline->mRtcp;
|
||||
|
||||
if (transport.mSrtp->state() != TransportLayer::TS_OPEN) {
|
||||
// SRTP not ready yet.
|
||||
if (isRtp && mPipeline->mRtpState != TransportLayer::TS_OPEN) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(transport.mTransport);
|
||||
NS_ENSURE_TRUE(transport.mTransport, NS_ERROR_NULL_POINTER);
|
||||
if (!isRtp && mPipeline->mRtcpState != TransportLayer::TS_OPEN) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MediaPacket packet(std::move(*aPacket));
|
||||
packet.sdp_level() = Some(mPipeline->Level());
|
||||
@ -1621,7 +1497,7 @@ MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s(
|
||||
mPipeline->mDescription.c_str(),
|
||||
(isRtp ? "RTP" : "RTCP")));
|
||||
|
||||
return mPipeline->SendPacket(transport.mSrtp, packet);
|
||||
return mPipeline->SendPacket(packet);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -1898,11 +1774,14 @@ protected:
|
||||
Atomic<bool> mMaybeTrackNeedsUnmute;
|
||||
};
|
||||
|
||||
MediaPipelineReceive::MediaPipelineReceive(const std::string& aPc,
|
||||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
nsCOMPtr<nsIEventTarget> aStsThread,
|
||||
RefPtr<MediaSessionConduit> aConduit)
|
||||
MediaPipelineReceive::MediaPipelineReceive(
|
||||
const std::string& aPc,
|
||||
MediaTransportBase* aTransportHandler,
|
||||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
nsCOMPtr<nsIEventTarget> aStsThread,
|
||||
RefPtr<MediaSessionConduit> aConduit)
|
||||
: MediaPipeline(aPc,
|
||||
aTransportHandler,
|
||||
DirectionType::RECEIVE,
|
||||
aMainThread,
|
||||
aStsThread,
|
||||
@ -2048,11 +1927,16 @@ private:
|
||||
|
||||
MediaPipelineReceiveAudio::MediaPipelineReceiveAudio(
|
||||
const std::string& aPc,
|
||||
MediaTransportBase* aTransportHandler,
|
||||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
nsCOMPtr<nsIEventTarget> aStsThread,
|
||||
RefPtr<AudioSessionConduit> aConduit,
|
||||
dom::MediaStreamTrack* aTrack)
|
||||
: MediaPipelineReceive(aPc, aMainThread, aStsThread, aConduit)
|
||||
: MediaPipelineReceive(aPc,
|
||||
aTransportHandler,
|
||||
aMainThread,
|
||||
aStsThread,
|
||||
aConduit)
|
||||
, mListener(aTrack ? new PipelineListener(aTrack, mConduit) : nullptr)
|
||||
{
|
||||
mDescription = mPc + "| Receive audio";
|
||||
@ -2236,11 +2120,16 @@ private:
|
||||
|
||||
MediaPipelineReceiveVideo::MediaPipelineReceiveVideo(
|
||||
const std::string& aPc,
|
||||
MediaTransportBase* aTransportHandler,
|
||||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
nsCOMPtr<nsIEventTarget> aStsThread,
|
||||
RefPtr<VideoSessionConduit> aConduit,
|
||||
dom::MediaStreamTrack* aTrack)
|
||||
: MediaPipelineReceive(aPc, aMainThread, aStsThread, aConduit)
|
||||
: MediaPipelineReceive(aPc,
|
||||
aTransportHandler,
|
||||
aMainThread,
|
||||
aStsThread,
|
||||
aConduit)
|
||||
, mRenderer(new PipelineRenderer(this))
|
||||
, mListener(aTrack ? new PipelineListener(aTrack) : nullptr)
|
||||
{
|
||||
|
@ -11,14 +11,14 @@
|
||||
#include <map>
|
||||
|
||||
#include "sigslot.h"
|
||||
#include "transportlayer.h" // For TransportLayer::State
|
||||
|
||||
#include "signaling/src/media-conduit/MediaConduitInterface.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "SrtpFlow.h"
|
||||
#include "SrtpFlow.h" // For SRTP_MAX_EXPANSION
|
||||
#include "mediapacket.h"
|
||||
#include "mtransport/runnable_utils.h"
|
||||
#include "mtransport/transportflow.h"
|
||||
#include "AudioPacketizer.h"
|
||||
#include "StreamTracks.h"
|
||||
#include "signaling/src/peerconnection/PacketDumper.h"
|
||||
@ -33,6 +33,7 @@ class nsIPrincipal;
|
||||
|
||||
namespace mozilla {
|
||||
class MediaPipelineFilter;
|
||||
class MediaTransportBase;
|
||||
class PeerIdentity;
|
||||
class AudioProxyThread;
|
||||
class VideoFrameConverter;
|
||||
@ -83,13 +84,8 @@ public:
|
||||
TRANSMIT,
|
||||
RECEIVE
|
||||
};
|
||||
enum class StateType
|
||||
{
|
||||
MP_CONNECTING,
|
||||
MP_OPEN,
|
||||
MP_CLOSED
|
||||
};
|
||||
MediaPipeline(const std::string& aPc,
|
||||
MediaTransportBase* aTransportHandler,
|
||||
DirectionType aDirection,
|
||||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
nsCOMPtr<nsIEventTarget> aStsThread,
|
||||
@ -104,12 +100,10 @@ public:
|
||||
// Must be called on the main thread.
|
||||
void Shutdown_m();
|
||||
|
||||
void UpdateTransport_m(RefPtr<TransportFlow> aRtpTransport,
|
||||
RefPtr<TransportFlow> aRtcpTransport,
|
||||
void UpdateTransport_m(const std::string& aTransportId,
|
||||
nsAutoPtr<MediaPipelineFilter> aFilter);
|
||||
|
||||
void UpdateTransport_s(RefPtr<TransportFlow> aRtpTransport,
|
||||
RefPtr<TransportFlow> aRtcpTransport,
|
||||
void UpdateTransport_s(const std::string& aTransportId,
|
||||
nsAutoPtr<MediaPipelineFilter> aFilter);
|
||||
|
||||
// Used only for testing; adds RTP header extension for RTP Stream Id with
|
||||
@ -125,8 +119,6 @@ public:
|
||||
int Level() const { return mLevel; }
|
||||
virtual bool IsVideo() const = 0;
|
||||
|
||||
bool IsDoingRtcpMux() const { return mRtp.mType == MUX; }
|
||||
|
||||
class RtpCSRCStats
|
||||
{
|
||||
public:
|
||||
@ -178,8 +170,6 @@ public:
|
||||
// Thread counting
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaPipeline)
|
||||
|
||||
typedef enum { RTP, RTCP, MUX, MAX_RTP_TYPE } RtpType;
|
||||
|
||||
// Separate class to allow ref counting
|
||||
class PipelineTransport : public TransportInterface
|
||||
{
|
||||
@ -208,40 +198,10 @@ public:
|
||||
|
||||
protected:
|
||||
virtual ~MediaPipeline();
|
||||
nsresult AttachTransport_s();
|
||||
friend class PipelineTransport;
|
||||
|
||||
struct TransportInfo
|
||||
{
|
||||
TransportInfo(RefPtr<TransportFlow> aFlow, RtpType aType)
|
||||
: mTransport(aFlow)
|
||||
, mSrtp(mTransport ? mTransport->GetLayer("srtp") : nullptr)
|
||||
, mState(StateType::MP_CONNECTING)
|
||||
, mType(aType)
|
||||
{
|
||||
}
|
||||
|
||||
void Detach()
|
||||
{
|
||||
mTransport = nullptr;
|
||||
mSrtp = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<TransportFlow> mTransport;
|
||||
TransportLayer* mSrtp;
|
||||
StateType mState;
|
||||
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);
|
||||
|
||||
nsresult ConnectTransport_s(TransportInfo& aInfo);
|
||||
|
||||
TransportInfo* GetTransportInfo_s(TransportLayer* aLayer);
|
||||
virtual void TransportReady_s() {}
|
||||
|
||||
void IncrementRtpPacketsSent(int aBytes);
|
||||
void IncrementRtcpPacketsSent();
|
||||
@ -249,25 +209,32 @@ protected:
|
||||
virtual void OnRtpPacketReceived() {};
|
||||
void IncrementRtcpPacketsReceived();
|
||||
|
||||
virtual nsresult SendPacket(TransportLayer* aLayer,
|
||||
MediaPacket& packet);
|
||||
virtual nsresult SendPacket(MediaPacket& packet);
|
||||
|
||||
// Process slots on transports
|
||||
void StateChange(TransportLayer* aLayer, TransportLayer::State);
|
||||
void RtpPacketReceived(TransportLayer* aLayer, MediaPacket& packet);
|
||||
void RtcpPacketReceived(TransportLayer* aLayer, MediaPacket& packet);
|
||||
void PacketReceived(TransportLayer* aLayer, MediaPacket& packet);
|
||||
void RtpStateChange(const std::string& aTransportId, TransportLayer::State);
|
||||
void RtcpStateChange(const std::string& aTransportId, TransportLayer::State);
|
||||
virtual void CheckTransportStates();
|
||||
void PacketReceived(const std::string& aTransportId, MediaPacket& packet);
|
||||
|
||||
void RtpPacketReceived(MediaPacket& packet);
|
||||
void RtcpPacketReceived(MediaPacket& packet);
|
||||
|
||||
void EncryptedPacketSending(const std::string& aTransportId,
|
||||
MediaPacket& aPacket);
|
||||
|
||||
void SetDescription_s(const std::string& description);
|
||||
|
||||
const DirectionType mDirection;
|
||||
size_t mLevel;
|
||||
std::string mTransportId;
|
||||
RefPtr<MediaTransportBase> mTransportHandler;
|
||||
RefPtr<MediaSessionConduit> mConduit; // Our conduit. Written on the main
|
||||
// thread. Read on STS thread.
|
||||
|
||||
// The transport objects. Read/written on STS thread.
|
||||
TransportInfo mRtp;
|
||||
TransportInfo mRtcp;
|
||||
TransportLayer::State mRtpState = TransportLayer::TS_NONE;
|
||||
TransportLayer::State mRtcpState = TransportLayer::TS_NONE;
|
||||
bool mSignalsConnected = false;
|
||||
|
||||
// Pointers to the threads we need. Initialized at creation
|
||||
// and used all over the place.
|
||||
@ -278,7 +245,6 @@ protected:
|
||||
RefPtr<PipelineTransport> mTransport;
|
||||
|
||||
// Only safe to access from STS thread.
|
||||
// Build into TransportInfo?
|
||||
int32_t mRtpPacketsSent;
|
||||
int32_t mRtcpPacketsSent;
|
||||
int32_t mRtpPacketsReceived;
|
||||
@ -315,6 +281,7 @@ class MediaPipelineTransmit : public MediaPipeline
|
||||
public:
|
||||
// Set aRtcpTransport to nullptr to use rtcp-mux
|
||||
MediaPipelineTransmit(const std::string& aPc,
|
||||
MediaTransportBase* aTransportHandler,
|
||||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
nsCOMPtr<nsIEventTarget> aStsThread,
|
||||
bool aIsVideo,
|
||||
@ -338,8 +305,8 @@ public:
|
||||
// Called on the main thread.
|
||||
void DetachMedia() override;
|
||||
|
||||
// Override MediaPipeline::TransportReady.
|
||||
nsresult TransportReady_s(TransportInfo& aInfo) override;
|
||||
// Override MediaPipeline::TransportReady_s.
|
||||
void TransportReady_s() override;
|
||||
|
||||
// Replace a track with a different one
|
||||
// In non-compliance with the likely final spec, allow the new
|
||||
@ -373,6 +340,7 @@ class MediaPipelineReceive : public MediaPipeline
|
||||
public:
|
||||
// Set aRtcpTransport to nullptr to use rtcp-mux
|
||||
MediaPipelineReceive(const std::string& aPc,
|
||||
MediaTransportBase* aTransportHandler,
|
||||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
nsCOMPtr<nsIEventTarget> aStsThread,
|
||||
RefPtr<MediaSessionConduit> aConduit);
|
||||
@ -392,6 +360,7 @@ class MediaPipelineReceiveAudio : public MediaPipelineReceive
|
||||
{
|
||||
public:
|
||||
MediaPipelineReceiveAudio(const std::string& aPc,
|
||||
MediaTransportBase* aTransportHandler,
|
||||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
nsCOMPtr<nsIEventTarget> aStsThread,
|
||||
RefPtr<AudioSessionConduit> aConduit,
|
||||
@ -421,6 +390,7 @@ class MediaPipelineReceiveVideo : public MediaPipelineReceive
|
||||
{
|
||||
public:
|
||||
MediaPipelineReceiveVideo(const std::string& aPc,
|
||||
MediaTransportBase* aTransportHandler,
|
||||
nsCOMPtr<nsIEventTarget> aMainThread,
|
||||
nsCOMPtr<nsIEventTarget> aStsThread,
|
||||
RefPtr<VideoSessionConduit> aConduit,
|
||||
|
@ -1,77 +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
|
||||
|
||||
#include "TransportLayerPacketDumper.h"
|
||||
|
||||
#include "logging.h"
|
||||
#include "nsError.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MOZ_MTLOG_MODULE("mtransport")
|
||||
|
||||
TransportLayerPacketDumper::TransportLayerPacketDumper(
|
||||
nsAutoPtr<PacketDumper>&& aPacketDumper, dom::mozPacketDumpType aType) :
|
||||
mPacketDumper(std::move(aPacketDumper)),
|
||||
mType(aType)
|
||||
{}
|
||||
|
||||
void
|
||||
TransportLayerPacketDumper::WasInserted()
|
||||
{
|
||||
CheckThread();
|
||||
if (!downward_) {
|
||||
MOZ_MTLOG(ML_ERROR, "Packet dumper with nothing below. This is useless");
|
||||
TL_SET_STATE(TS_ERROR);
|
||||
}
|
||||
|
||||
downward_->SignalStateChange.connect(this,
|
||||
&TransportLayerPacketDumper::StateChange);
|
||||
downward_->SignalPacketReceived.connect(this,
|
||||
&TransportLayerPacketDumper::PacketReceived);
|
||||
}
|
||||
|
||||
TransportResult
|
||||
TransportLayerPacketDumper::SendPacket(MediaPacket& packet)
|
||||
{
|
||||
if (packet.sdp_level().isSome()) {
|
||||
dom::mozPacketDumpType dumpType = mType;
|
||||
if (mType == dom::mozPacketDumpType::Srtp &&
|
||||
packet.type() == MediaPacket::RTCP) {
|
||||
dumpType = dom::mozPacketDumpType::Srtcp;
|
||||
}
|
||||
|
||||
mPacketDumper->Dump(*packet.sdp_level(),
|
||||
dumpType,
|
||||
true,
|
||||
packet.data(),
|
||||
packet.len());
|
||||
}
|
||||
return downward_->SendPacket(packet);
|
||||
}
|
||||
|
||||
void
|
||||
TransportLayerPacketDumper::StateChange(TransportLayer* aLayer, State aState)
|
||||
{
|
||||
TL_SET_STATE(aState);
|
||||
}
|
||||
|
||||
void
|
||||
TransportLayerPacketDumper::PacketReceived(TransportLayer* aLayer,
|
||||
MediaPacket& packet)
|
||||
{
|
||||
// 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
|
||||
|
||||
|
@ -1,40 +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/. */
|
||||
|
||||
#ifndef transportlayerpacketdumper_h__
|
||||
#define transportlayerpacketdumper_h__
|
||||
|
||||
#include "transportlayer.h"
|
||||
#include "signaling/src/peerconnection/PacketDumper.h"
|
||||
#include "mozilla/dom/RTCPeerConnectionBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class TransportLayerPacketDumper final : public TransportLayer {
|
||||
public:
|
||||
explicit TransportLayerPacketDumper(nsAutoPtr<PacketDumper>&& aPacketDumper,
|
||||
dom::mozPacketDumpType aType);
|
||||
virtual ~TransportLayerPacketDumper() {};
|
||||
|
||||
// Transport layer overrides.
|
||||
void WasInserted() override;
|
||||
TransportResult SendPacket(MediaPacket& packet) override;
|
||||
|
||||
// Signals
|
||||
void StateChange(TransportLayer *aLayer, State state);
|
||||
void PacketReceived(TransportLayer* aLayer, MediaPacket& packet);
|
||||
|
||||
TRANSPORT_LAYER_ID("packet-dumper")
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_ASSIGN(TransportLayerPacketDumper);
|
||||
nsAutoPtr<PacketDumper> mPacketDumper;
|
||||
dom::mozPacketDumpType mType;
|
||||
};
|
||||
|
||||
|
||||
} // close namespace
|
||||
#endif
|
@ -22,7 +22,6 @@ UNIFIED_SOURCES += [
|
||||
'MediaPipeline.cpp',
|
||||
'MediaPipelineFilter.cpp',
|
||||
'RtpLogger.cpp',
|
||||
'TransportLayerPacketDumper.cpp',
|
||||
]
|
||||
|
||||
DEFINES['TRACING'] = True
|
||||
|
@ -0,0 +1,906 @@
|
||||
/* 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 "MediaTransportHandler.h"
|
||||
#include "nricemediastream.h"
|
||||
#include "nriceresolver.h"
|
||||
#include "transportflow.h"
|
||||
#include "transportlayerice.h"
|
||||
#include "transportlayerdtls.h"
|
||||
#include "transportlayersrtp.h"
|
||||
|
||||
// Config stuff
|
||||
#include "nsIPrefService.h"
|
||||
#include "mozilla/dom/RTCConfigurationBinding.h"
|
||||
|
||||
// Parsing STUN/TURN URIs
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsURLHelper.h"
|
||||
#include "nsIURLParser.h"
|
||||
|
||||
// Logging stuff
|
||||
#include "CSFLog.h"
|
||||
|
||||
// DTLS
|
||||
#include "signaling/src/sdp/SdpAttribute.h"
|
||||
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#include "mozilla/dom/RTCStatsReportBinding.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static const char* mthLogTag = "MediaTransportHandler";
|
||||
#ifdef LOGTAG
|
||||
#undef LOGTAG
|
||||
#endif
|
||||
#define LOGTAG mthLogTag
|
||||
|
||||
MediaTransportHandler::MediaTransportHandler()
|
||||
{}
|
||||
|
||||
MediaTransportHandler::~MediaTransportHandler()
|
||||
{}
|
||||
|
||||
static NrIceCtx::Policy toNrIcePolicy(dom::RTCIceTransportPolicy aPolicy)
|
||||
{
|
||||
switch (aPolicy) {
|
||||
case dom::RTCIceTransportPolicy::Relay:
|
||||
return NrIceCtx::ICE_POLICY_RELAY;
|
||||
case dom::RTCIceTransportPolicy::All:
|
||||
if (Preferences::GetBool("media.peerconnection.ice.no_host", false)) {
|
||||
return NrIceCtx::ICE_POLICY_NO_HOST;
|
||||
} else {
|
||||
return NrIceCtx::ICE_POLICY_ALL;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
return NrIceCtx::ICE_POLICY_ALL;
|
||||
}
|
||||
|
||||
static nsresult addNrIceServer(const nsString& aIceUrl,
|
||||
const dom::RTCIceServer& aIceServer,
|
||||
std::vector<NrIceStunServer>* aStunServersOut,
|
||||
std::vector<NrIceTurnServer>* aTurnServersOut)
|
||||
{
|
||||
// Without STUN/TURN handlers, NS_NewURI returns nsSimpleURI rather than
|
||||
// nsStandardURL. To parse STUN/TURN URI's to spec
|
||||
// http://tools.ietf.org/html/draft-nandakumar-rtcweb-stun-uri-02#section-3
|
||||
// http://tools.ietf.org/html/draft-petithuguenin-behave-turn-uri-03#section-3
|
||||
// we parse out the query-string, and use ParseAuthority() on the rest
|
||||
RefPtr<nsIURI> url;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(url), aIceUrl);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
bool isStun = false, isStuns = false, isTurn = false, isTurns = false;
|
||||
url->SchemeIs("stun", &isStun);
|
||||
url->SchemeIs("stuns", &isStuns);
|
||||
url->SchemeIs("turn", &isTurn);
|
||||
url->SchemeIs("turns", &isTurns);
|
||||
if (!(isStun || isStuns || isTurn || isTurns)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (isStuns) {
|
||||
return NS_OK; // TODO: Support STUNS (Bug 1056934)
|
||||
}
|
||||
|
||||
nsAutoCString spec;
|
||||
rv = url->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// TODO(jib@mozilla.com): Revisit once nsURI supports STUN/TURN (Bug 833509)
|
||||
int32_t port;
|
||||
nsAutoCString host;
|
||||
nsAutoCString transport;
|
||||
{
|
||||
uint32_t hostPos;
|
||||
int32_t hostLen;
|
||||
nsAutoCString path;
|
||||
rv = url->GetPathQueryRef(path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Tolerate query-string + parse 'transport=[udp|tcp]' by hand.
|
||||
int32_t questionmark = path.FindChar('?');
|
||||
if (questionmark >= 0) {
|
||||
const nsCString match = NS_LITERAL_CSTRING("transport=");
|
||||
|
||||
for (int32_t i = questionmark, endPos; i >= 0; i = endPos) {
|
||||
endPos = path.FindCharInSet("&", i + 1);
|
||||
const nsDependentCSubstring fieldvaluepair = Substring(path, i + 1,
|
||||
endPos);
|
||||
if (StringBeginsWith(fieldvaluepair, match)) {
|
||||
transport = Substring(fieldvaluepair, match.Length());
|
||||
ToLowerCase(transport);
|
||||
}
|
||||
}
|
||||
path.SetLength(questionmark);
|
||||
}
|
||||
|
||||
rv = net_GetAuthURLParser()->ParseAuthority(path.get(), path.Length(),
|
||||
nullptr, nullptr,
|
||||
nullptr, nullptr,
|
||||
&hostPos, &hostLen, &port);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!hostLen) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (hostPos > 1) /* The username was removed */
|
||||
return NS_ERROR_FAILURE;
|
||||
path.Mid(host, hostPos, hostLen);
|
||||
}
|
||||
if (port == -1)
|
||||
port = (isStuns || isTurns)? 5349 : 3478;
|
||||
|
||||
if (isStuns || isTurns) {
|
||||
// Should we barf if transport is set to udp or something?
|
||||
transport = kNrIceTransportTls;
|
||||
}
|
||||
|
||||
if (transport.IsEmpty()) {
|
||||
transport = kNrIceTransportUdp;
|
||||
}
|
||||
|
||||
if (isTurn || isTurns) {
|
||||
std::string pwd(NS_ConvertUTF16toUTF8(aIceServer.mCredential.Value()).get());
|
||||
std::string username(NS_ConvertUTF16toUTF8(aIceServer.mUsername.Value()).get());
|
||||
|
||||
std::vector<unsigned char> password(pwd.begin(), pwd.end());
|
||||
|
||||
UniquePtr<NrIceTurnServer> server(NrIceTurnServer::Create(host.get(), port, username, password, transport.get()));
|
||||
if (!server) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aTurnServersOut->emplace_back(std::move(*server));
|
||||
} else {
|
||||
UniquePtr<NrIceStunServer> server(NrIceStunServer::Create(host.get(), port, transport.get()));
|
||||
if (!server) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aStunServersOut->emplace_back(std::move(*server));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaTransportHandler::Init(const std::string& aName,
|
||||
const dom::RTCConfiguration& aConfiguration)
|
||||
{
|
||||
bool allowIceLoopback = Preferences::GetBool(
|
||||
"media.peerconnection.ice.loopback", false);
|
||||
bool iceTcp = Preferences::GetBool("media.peerconnection.ice.tcp", false);
|
||||
bool allowIceLinkLocal = Preferences::GetBool(
|
||||
"media.peerconnection.ice.link_local", false);
|
||||
|
||||
NrIceCtx::InitializeGlobals(allowIceLoopback, iceTcp, allowIceLinkLocal);
|
||||
|
||||
bool allowLoopback = Preferences::GetBool(
|
||||
"media.peerconnection.ice.loopback", false);
|
||||
bool tcpEnabled = Preferences::GetBool(
|
||||
"media.peerconnection.ice.tcp", false);
|
||||
bool allowLinkLocal = Preferences::GetBool(
|
||||
"media.peerconnection.ice.link_local", false);
|
||||
|
||||
mIceCtx = NrIceCtx::Create(aName, allowLoopback, tcpEnabled, allowLinkLocal,
|
||||
toNrIcePolicy(aConfiguration.mIceTransportPolicy));
|
||||
if (!mIceCtx) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mProxyOnly = Preferences::GetBool(
|
||||
"media.peerconnection.ice.proxy_only", false);
|
||||
|
||||
mIceCtx->SignalGatheringStateChange.connect(
|
||||
this, &MediaTransportHandler::OnGatheringStateChange);
|
||||
mIceCtx->SignalConnectionStateChange.connect(
|
||||
this, &MediaTransportHandler::OnConnectionStateChange);
|
||||
|
||||
std::vector<NrIceStunServer> stunServers;
|
||||
std::vector<NrIceTurnServer> turnServers;
|
||||
|
||||
nsresult rv;
|
||||
if (aConfiguration.mIceServers.WasPassed()) {
|
||||
for (const auto& iceServer : aConfiguration.mIceServers.Value()) {
|
||||
NS_ENSURE_STATE(iceServer.mUrls.WasPassed());
|
||||
NS_ENSURE_STATE(iceServer.mUrls.Value().IsStringSequence());
|
||||
for (const auto& iceUrl : iceServer.mUrls.Value().GetAsStringSequence()) {
|
||||
rv = addNrIceServer(iceUrl, iceServer, &stunServers, &turnServers);
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(LOGTAG, "%s: invalid STUN/TURN server: %s",
|
||||
__FUNCTION__, NS_ConvertUTF16toUTF8(iceUrl).get());
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv = mIceCtx->SetStunServers(stunServers))) {
|
||||
CSFLogError(LOGTAG, "%s: Failed to set stun servers", __FUNCTION__);
|
||||
return rv;
|
||||
}
|
||||
// Give us a way to globally turn off TURN support
|
||||
bool disabled = Preferences::GetBool("media.peerconnection.turn.disable", false);
|
||||
if (!disabled) {
|
||||
if (NS_FAILED(rv = mIceCtx->SetTurnServers(turnServers))) {
|
||||
CSFLogError(LOGTAG, "%s: Failed to set turn servers", __FUNCTION__);
|
||||
return rv;
|
||||
}
|
||||
} else if (!turnServers.empty()) {
|
||||
CSFLogError(LOGTAG, "%s: Setting turn servers disabled", __FUNCTION__);
|
||||
}
|
||||
|
||||
mDNSResolver = new NrIceResolver;
|
||||
if (NS_FAILED(rv = mDNSResolver->Init())) {
|
||||
CSFLogError(LOGTAG, "%s: Failed to initialize dns resolver", __FUNCTION__);
|
||||
return rv;
|
||||
}
|
||||
if (NS_FAILED(rv = mIceCtx->SetResolver(mDNSResolver->AllocateResolver()))) {
|
||||
CSFLogError(LOGTAG, "%s: Failed to get dns resolver", __FUNCTION__);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::Destroy()
|
||||
{
|
||||
disconnect_all();
|
||||
NrIceStats stats = mIceCtx->Destroy();
|
||||
CSFLogDebug(LOGTAG, "Ice Telemetry: stun (retransmits: %d)"
|
||||
" turn (401s: %d 403s: %d 438s: %d)",
|
||||
stats.stun_retransmits, stats.turn_401s, stats.turn_403s,
|
||||
stats.turn_438s);
|
||||
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::WEBRTC_NICER_STUN_RETRANSMITS,
|
||||
stats.stun_retransmits);
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::WEBRTC_NICER_TURN_401S,
|
||||
stats.turn_401s);
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::WEBRTC_NICER_TURN_403S,
|
||||
stats.turn_403s);
|
||||
Telemetry::ScalarAdd(Telemetry::ScalarID::WEBRTC_NICER_TURN_438S,
|
||||
stats.turn_438s);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaTransportHandler::SetProxyServer(const std::string& aProxyHost,
|
||||
uint16_t aProxyPort,
|
||||
const std::string& aAlpnProtocols)
|
||||
{
|
||||
NrIceProxyServer proxyServer(aProxyHost, aProxyPort, aAlpnProtocols);
|
||||
return mIceCtx->SetProxyServer(proxyServer);
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::EnsureProvisionalTransport(
|
||||
const std::string& aTransportId,
|
||||
const std::string& aUfrag,
|
||||
const std::string& aPwd,
|
||||
size_t aComponentCount)
|
||||
{
|
||||
RefPtr<NrIceMediaStream> stream(mIceCtx->GetStream(aTransportId));
|
||||
if (!stream) {
|
||||
CSFLogDebug(LOGTAG, "%s: Creating ICE media stream=%s components=%u",
|
||||
mIceCtx->name().c_str(),
|
||||
aTransportId.c_str(),
|
||||
static_cast<unsigned>(aComponentCount));
|
||||
|
||||
std::ostringstream os;
|
||||
os << mIceCtx->name() << " transport-id=" << aTransportId;
|
||||
stream = mIceCtx->CreateStream(aTransportId,
|
||||
os.str(),
|
||||
aComponentCount);
|
||||
|
||||
if (!stream) {
|
||||
CSFLogError(LOGTAG, "Failed to create ICE stream.");
|
||||
return;
|
||||
}
|
||||
|
||||
stream->SignalCandidate.connect(this,
|
||||
&MediaTransportHandler::OnCandidateFound);
|
||||
}
|
||||
|
||||
// Begins an ICE restart if this stream has a different ufrag/pwd
|
||||
stream->SetIceCredentials(aUfrag, aPwd);
|
||||
|
||||
// Make sure there's an entry in mTransports
|
||||
mTransports[aTransportId];
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaTransportHandler::ActivateTransport(
|
||||
const std::string& aTransportId,
|
||||
const std::string& aLocalUfrag,
|
||||
const std::string& aLocalPwd,
|
||||
size_t aComponentCount,
|
||||
const std::string& aUfrag,
|
||||
const std::string& aPassword,
|
||||
const std::vector<std::string>& aCandidateList,
|
||||
RefPtr<DtlsIdentity> aDtlsIdentity,
|
||||
bool aDtlsClient,
|
||||
const SdpFingerprintAttributeList& aFingerprints,
|
||||
bool aPrivacyRequested)
|
||||
{
|
||||
MOZ_ASSERT(aComponentCount);
|
||||
MOZ_ASSERT(aDtlsIdentity);
|
||||
|
||||
RefPtr<NrIceMediaStream> stream(mIceCtx->GetStream(aTransportId));
|
||||
if (!stream) {
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
CSFLogDebug(LOGTAG, "%s: Activating ICE media stream=%s components=%u",
|
||||
mIceCtx->name().c_str(),
|
||||
aTransportId.c_str(),
|
||||
static_cast<unsigned>(aComponentCount));
|
||||
|
||||
std::vector<std::string> attrs;
|
||||
attrs.reserve(aCandidateList.size() + 2 /* ufrag + pwd */);
|
||||
for (const auto& candidate : aCandidateList) {
|
||||
attrs.push_back("candidate:" + candidate);
|
||||
}
|
||||
attrs.push_back("ice-ufrag:" + aUfrag);
|
||||
attrs.push_back("ice-pwd:" + aPassword);
|
||||
|
||||
// If we started an ICE restart in EnsureProvisionalTransport, this is where
|
||||
// we decide whether to commit or rollback.
|
||||
nsresult rv = stream->ConnectToPeer(aLocalUfrag, aLocalPwd, attrs);
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(LOGTAG, "Couldn't parse ICE attributes, rv=%u",
|
||||
static_cast<unsigned>(rv));
|
||||
MOZ_ASSERT(false);
|
||||
return rv;
|
||||
}
|
||||
|
||||
Transport transport = mTransports[aTransportId];
|
||||
if (!transport.mFlow) {
|
||||
transport.mFlow = CreateTransportFlow(aTransportId, false, aDtlsIdentity,
|
||||
aDtlsClient, aFingerprints, aPrivacyRequested);
|
||||
if (!transport.mFlow) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
TransportLayer* dtls = transport.mFlow->GetLayer(TransportLayerDtls::ID());
|
||||
dtls->SignalStateChange.connect(
|
||||
this, &MediaTransportHandler::OnStateChange);
|
||||
if (aComponentCount < 2) {
|
||||
dtls->SignalStateChange.connect(
|
||||
this, &MediaTransportHandler::OnRtcpStateChange);
|
||||
}
|
||||
}
|
||||
|
||||
if (aComponentCount == 2) {
|
||||
if (!transport.mRtcpFlow) {
|
||||
transport.mRtcpFlow = CreateTransportFlow(aTransportId, true,
|
||||
aDtlsIdentity, aDtlsClient, aFingerprints, aPrivacyRequested);
|
||||
if (!transport.mRtcpFlow) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
TransportLayer* dtls = transport.mRtcpFlow->GetLayer(
|
||||
TransportLayerDtls::ID());
|
||||
dtls->SignalStateChange.connect(
|
||||
this, &MediaTransportHandler::OnRtcpStateChange);
|
||||
}
|
||||
} else {
|
||||
transport.mRtcpFlow = nullptr;
|
||||
// components are 1-indexed
|
||||
stream->DisableComponent(2);
|
||||
}
|
||||
|
||||
mTransports[aTransportId] = transport;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::StartIceGathering(
|
||||
bool aDefaultRouteOnly,
|
||||
const nsTArray<NrIceStunAddr>& aStunAddrs)
|
||||
{
|
||||
// Belt and suspenders - in e10s mode, the call below to SetStunAddrs
|
||||
// needs to have the proper flags set on ice ctx. For non-e10s,
|
||||
// setting those flags happens in StartGathering. We could probably
|
||||
// just set them here, and only do it here.
|
||||
mIceCtx->SetCtxFlags(aDefaultRouteOnly, mProxyOnly);
|
||||
|
||||
if (aStunAddrs.Length()) {
|
||||
mIceCtx->SetStunAddrs(aStunAddrs);
|
||||
}
|
||||
|
||||
// Start gathering, but only if there are streams
|
||||
if (!mIceCtx->GetStreams().empty()) {
|
||||
mIceCtx->StartGathering(aDefaultRouteOnly, mProxyOnly);
|
||||
return;
|
||||
}
|
||||
|
||||
CSFLogWarn(LOGTAG,
|
||||
"%s: No streams to start gathering on. Can happen with rollback",
|
||||
__FUNCTION__);
|
||||
|
||||
// If there are no streams, we're probably in a situation where we've rolled
|
||||
// back while still waiting for our proxy configuration to come back. Make
|
||||
// sure content knows that the rollback has stuck wrt gathering.
|
||||
SignalGatheringStateChange(dom::PCImplIceGatheringState::Complete);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaTransportHandler::StartIceChecks(
|
||||
bool aIsControlling,
|
||||
bool aIsOfferer,
|
||||
const std::vector<std::string>& aIceOptions)
|
||||
{
|
||||
nsresult rv = mIceCtx->ParseGlobalAttributes(aIceOptions);
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(LOGTAG, "%s: couldn't parse global parameters", __FUNCTION__ );
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mIceCtx->SetControlling(aIsControlling ? NrIceCtx::ICE_CONTROLLING :
|
||||
NrIceCtx::ICE_CONTROLLED);
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(LOGTAG, "%s: couldn't set controlling to %d",
|
||||
__FUNCTION__, aIsControlling);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mIceCtx->StartChecks(aIsOfferer);
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(LOGTAG, "%s: couldn't start checks", __FUNCTION__);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaTransportHandler::AddIceCandidate(const std::string& aTransportId,
|
||||
const std::string& aCandidate)
|
||||
{
|
||||
RefPtr<NrIceMediaStream> stream(mIceCtx->GetStream(aTransportId));
|
||||
if (!stream) {
|
||||
CSFLogError(LOGTAG, "No ICE stream for candidate with transport id %s: %s",
|
||||
aTransportId.c_str(), aCandidate.c_str());
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsresult rv = stream->ParseTrickleCandidate(aCandidate);
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(LOGTAG, "Couldn't process ICE candidate with transport id %s: "
|
||||
"%s",
|
||||
aTransportId.c_str(), aCandidate.c_str());
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::UpdateNetworkState(bool aOnline)
|
||||
{
|
||||
mIceCtx->UpdateNetworkState(aOnline);
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::RemoveTransportsExcept(
|
||||
const std::set<std::string>& aTransportIds)
|
||||
{
|
||||
for (auto it = mTransports.begin(); it != mTransports.end();) {
|
||||
if (!aTransportIds.count(it->first)) {
|
||||
if (it->second.mFlow) {
|
||||
SignalStateChange(it->first, TransportLayer::TS_NONE);
|
||||
SignalRtcpStateChange(it->first, TransportLayer::TS_NONE);
|
||||
}
|
||||
mIceCtx->DestroyStream(it->first);
|
||||
it = mTransports.erase(it);
|
||||
} else {
|
||||
MOZ_ASSERT(it->second.mFlow);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaTransportHandler::SendPacket(const std::string& aTransportId,
|
||||
MediaPacket& aPacket)
|
||||
{
|
||||
MOZ_ASSERT(aPacket.type() != MediaPacket::UNCLASSIFIED);
|
||||
RefPtr<TransportFlow> flow = GetTransportFlow(
|
||||
aTransportId, aPacket.type() == MediaPacket::RTCP);
|
||||
|
||||
if (!flow) {
|
||||
CSFLogError(LOGTAG, "%s: No such transport flow (%s) for outgoing packet",
|
||||
mIceCtx->name().c_str(), aTransportId.c_str());
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
TransportLayer* layer = nullptr;
|
||||
switch (aPacket.type()) {
|
||||
case MediaPacket::SCTP:
|
||||
layer = flow->GetLayer(TransportLayerDtls::ID());
|
||||
break;
|
||||
case MediaPacket::RTP:
|
||||
case MediaPacket::RTCP:
|
||||
layer = flow->GetLayer(TransportLayerSrtp::ID());
|
||||
break;
|
||||
default:
|
||||
// Maybe it would be useful to allow the injection of other packet types
|
||||
// for testing?
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(layer);
|
||||
|
||||
if (layer->SendPacket(aPacket) < 0) {
|
||||
CSFLogError(LOGTAG, "%s: Transport flow (%s) failed to send packet",
|
||||
mIceCtx->name().c_str(), aTransportId.c_str());
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
TransportLayer::State
|
||||
MediaTransportHandler::GetState(const std::string& aTransportId,
|
||||
bool aRtcp) const
|
||||
{
|
||||
RefPtr<TransportFlow> flow = GetTransportFlow(aTransportId, aRtcp);
|
||||
if (flow) {
|
||||
return flow->GetLayer(TransportLayerDtls::ID())->state();
|
||||
}
|
||||
return TransportLayer::TS_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::GetAllIceStats(bool aInternalStats,
|
||||
DOMHighResTimeStamp aNow,
|
||||
dom::RTCStatsReportInternal* aReport)
|
||||
{
|
||||
for (const auto& stream : mIceCtx->GetStreams()) {
|
||||
GetIceStats(*stream, aInternalStats, aNow, aReport);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::GetIceStats(const std::string& aTransportId,
|
||||
bool aInternalStats,
|
||||
DOMHighResTimeStamp aNow,
|
||||
dom::RTCStatsReportInternal* aReport)
|
||||
{
|
||||
auto stream = mIceCtx->GetStream(aTransportId);
|
||||
if (stream) {
|
||||
GetIceStats(*stream, aInternalStats, aNow, aReport);
|
||||
}
|
||||
}
|
||||
|
||||
static void ToRTCIceCandidateStats(
|
||||
const std::vector<NrIceCandidate>& candidates,
|
||||
dom::RTCStatsType candidateType,
|
||||
const nsString& componentId,
|
||||
DOMHighResTimeStamp now,
|
||||
dom::RTCStatsReportInternal* report) {
|
||||
|
||||
MOZ_ASSERT(report);
|
||||
for (const auto& candidate : candidates) {
|
||||
dom::RTCIceCandidateStats cand;
|
||||
cand.mType.Construct(candidateType);
|
||||
NS_ConvertASCIItoUTF16 codeword(candidate.codeword.c_str());
|
||||
cand.mComponentId.Construct(componentId);
|
||||
cand.mId.Construct(codeword);
|
||||
cand.mTimestamp.Construct(now);
|
||||
cand.mCandidateType.Construct(
|
||||
dom::RTCStatsIceCandidateType(candidate.type));
|
||||
cand.mIpAddress.Construct(
|
||||
NS_ConvertASCIItoUTF16(candidate.cand_addr.host.c_str()));
|
||||
cand.mPortNumber.Construct(candidate.cand_addr.port);
|
||||
cand.mTransport.Construct(
|
||||
NS_ConvertASCIItoUTF16(candidate.cand_addr.transport.c_str()));
|
||||
if (candidateType == dom::RTCStatsType::Local_candidate) {
|
||||
cand.mMozLocalTransport.Construct(
|
||||
NS_ConvertASCIItoUTF16(candidate.local_addr.transport.c_str()));
|
||||
if (dom::RTCStatsIceCandidateType(candidate.type) ==
|
||||
dom::RTCStatsIceCandidateType::Relayed) {
|
||||
cand.mRelayProtocol.Construct(
|
||||
NS_ConvertASCIItoUTF16(candidate.local_addr.transport.c_str()));
|
||||
}
|
||||
}
|
||||
report->mIceCandidateStats.Value().AppendElement(cand, fallible);
|
||||
if (candidate.trickled) {
|
||||
report->mTrickledIceCandidateStats.Value().AppendElement(cand, fallible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::GetIceStats(
|
||||
const NrIceMediaStream& aStream,
|
||||
bool aInternalStats,
|
||||
DOMHighResTimeStamp aNow,
|
||||
dom::RTCStatsReportInternal* aReport) const
|
||||
{
|
||||
NS_ConvertASCIItoUTF16 transportId(aStream.GetId().c_str());
|
||||
|
||||
std::vector<NrIceCandidatePair> candPairs;
|
||||
nsresult res = aStream.GetCandidatePairs(&candPairs);
|
||||
if (NS_FAILED(res)) {
|
||||
CSFLogError(LOGTAG,
|
||||
"%s: Error getting candidate pairs for transport id \"%s\"",
|
||||
__FUNCTION__, aStream.GetId().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& candPair : candPairs) {
|
||||
NS_ConvertASCIItoUTF16 codeword(candPair.codeword.c_str());
|
||||
NS_ConvertASCIItoUTF16 localCodeword(candPair.local.codeword.c_str());
|
||||
NS_ConvertASCIItoUTF16 remoteCodeword(candPair.remote.codeword.c_str());
|
||||
// Only expose candidate-pair statistics to chrome, until we've thought
|
||||
// through the implications of exposing it to content.
|
||||
|
||||
dom::RTCIceCandidatePairStats s;
|
||||
s.mId.Construct(codeword);
|
||||
s.mTransportId.Construct(transportId);
|
||||
s.mTimestamp.Construct(aNow);
|
||||
s.mType.Construct(dom::RTCStatsType::Candidate_pair);
|
||||
s.mLocalCandidateId.Construct(localCodeword);
|
||||
s.mRemoteCandidateId.Construct(remoteCodeword);
|
||||
s.mNominated.Construct(candPair.nominated);
|
||||
s.mWritable.Construct(candPair.writable);
|
||||
s.mReadable.Construct(candPair.readable);
|
||||
s.mPriority.Construct(candPair.priority);
|
||||
s.mSelected.Construct(candPair.selected);
|
||||
s.mBytesSent.Construct(candPair.bytes_sent);
|
||||
s.mBytesReceived.Construct(candPair.bytes_recvd);
|
||||
s.mLastPacketSentTimestamp.Construct(candPair.ms_since_last_send);
|
||||
s.mLastPacketReceivedTimestamp.Construct(candPair.ms_since_last_recv);
|
||||
s.mState.Construct(dom::RTCStatsIceCandidatePairState(candPair.state));
|
||||
s.mComponentId.Construct(candPair.component_id);
|
||||
aReport->mIceCandidatePairStats.Value().AppendElement(s, fallible);
|
||||
}
|
||||
|
||||
std::vector<NrIceCandidate> candidates;
|
||||
if (NS_SUCCEEDED(aStream.GetLocalCandidates(&candidates))) {
|
||||
ToRTCIceCandidateStats(candidates,
|
||||
dom::RTCStatsType::Local_candidate,
|
||||
transportId,
|
||||
aNow,
|
||||
aReport);
|
||||
// add the local candidates unparsed string to a sequence
|
||||
for (const auto& candidate : candidates) {
|
||||
aReport->mRawLocalCandidates.Value().AppendElement(
|
||||
NS_ConvertASCIItoUTF16(candidate.label.c_str()), fallible);
|
||||
}
|
||||
}
|
||||
candidates.clear();
|
||||
|
||||
if (NS_SUCCEEDED(aStream.GetRemoteCandidates(&candidates))) {
|
||||
ToRTCIceCandidateStats(candidates,
|
||||
dom::RTCStatsType::Remote_candidate,
|
||||
transportId,
|
||||
aNow,
|
||||
aReport);
|
||||
// add the remote candidates unparsed string to a sequence
|
||||
for (const auto& candidate : candidates) {
|
||||
aReport->mRawRemoteCandidates.Value().AppendElement(
|
||||
NS_ConvertASCIItoUTF16(candidate.label.c_str()), fallible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<TransportFlow>
|
||||
MediaTransportHandler::GetTransportFlow(const std::string& aTransportId,
|
||||
bool aIsRtcp) const
|
||||
{
|
||||
auto it = mTransports.find(aTransportId);
|
||||
if (it == mTransports.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aIsRtcp) {
|
||||
return it->second.mRtcpFlow ? it->second.mRtcpFlow : it->second.mFlow;;
|
||||
}
|
||||
|
||||
return it->second.mFlow;
|
||||
}
|
||||
|
||||
RefPtr<TransportFlow>
|
||||
MediaTransportHandler::CreateTransportFlow(
|
||||
const std::string& aTransportId,
|
||||
bool aIsRtcp,
|
||||
RefPtr<DtlsIdentity> aDtlsIdentity,
|
||||
bool aDtlsClient,
|
||||
const SdpFingerprintAttributeList& aFingerprints,
|
||||
bool aPrivacyRequested)
|
||||
{
|
||||
nsresult rv;
|
||||
RefPtr<TransportFlow> flow = new TransportFlow(aTransportId);
|
||||
|
||||
// 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(aDtlsClient
|
||||
? TransportLayerDtls::CLIENT
|
||||
: TransportLayerDtls::SERVER);
|
||||
|
||||
dtls->SetIdentity(aDtlsIdentity);
|
||||
|
||||
for (const auto& fingerprint : aFingerprints.mFingerprints) {
|
||||
std::ostringstream ss;
|
||||
ss << fingerprint.hashFunc;
|
||||
rv = dtls->SetVerificationDigest(ss.str(), &fingerprint.fingerprint[0],
|
||||
fingerprint.fingerprint.size());
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(LOGTAG, "Could not set fingerprint");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint16_t> srtpCiphers = TransportLayerDtls::GetDefaultSrtpCiphers();
|
||||
|
||||
rv = dtls->SetSrtpCiphers(srtpCiphers);
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(LOGTAG, "Couldn't set SRTP ciphers");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Always permits negotiation of the confidential mode.
|
||||
// Only allow non-confidential (which is an allowed default),
|
||||
// if we aren't confidential.
|
||||
std::set<std::string> alpn;
|
||||
std::string alpnDefault = "";
|
||||
alpn.insert("c-webrtc");
|
||||
if (!aPrivacyRequested) {
|
||||
alpnDefault = "webrtc";
|
||||
alpn.insert(alpnDefault);
|
||||
}
|
||||
rv = dtls->SetAlpn(alpn, alpnDefault);
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(LOGTAG, "Couldn't set ALPN");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ice->SetParameters(mIceCtx->GetStream(aTransportId), aIsRtcp ? 2 : 1);
|
||||
NS_ENSURE_SUCCESS(ice->Init(), nullptr);
|
||||
NS_ENSURE_SUCCESS(dtls->Init(), nullptr);
|
||||
NS_ENSURE_SUCCESS(srtp->Init(), nullptr);
|
||||
dtls->Chain(ice.get());
|
||||
srtp->Chain(ice.get());
|
||||
|
||||
dtls->SignalPacketReceived.connect(
|
||||
this, &MediaTransportHandler::PacketReceived);
|
||||
srtp->SignalPacketReceived.connect(
|
||||
this, &MediaTransportHandler::PacketReceived);
|
||||
ice->SignalPacketSending.connect(
|
||||
this, &MediaTransportHandler::EncryptedPacketSending);
|
||||
flow->PushLayer(ice.release());
|
||||
flow->PushLayer(dtls.release());
|
||||
flow->PushLayer(srtp.release());
|
||||
return flow;
|
||||
}
|
||||
|
||||
static mozilla::dom::PCImplIceGatheringState
|
||||
toDomIceGatheringState(NrIceCtx::GatheringState aState)
|
||||
{
|
||||
switch (aState) {
|
||||
case NrIceCtx::ICE_CTX_GATHER_INIT:
|
||||
return dom::PCImplIceGatheringState::New;
|
||||
case NrIceCtx::ICE_CTX_GATHER_STARTED:
|
||||
return dom::PCImplIceGatheringState::Gathering;
|
||||
case NrIceCtx::ICE_CTX_GATHER_COMPLETE:
|
||||
return dom::PCImplIceGatheringState::Complete;
|
||||
}
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::OnGatheringStateChange(NrIceCtx* aIceCtx,
|
||||
NrIceCtx::GatheringState aState)
|
||||
{
|
||||
if (aState == NrIceCtx::ICE_CTX_GATHER_COMPLETE) {
|
||||
for (const auto& stream : mIceCtx->GetStreams()) {
|
||||
OnCandidateFound(stream, "");
|
||||
}
|
||||
}
|
||||
SignalGatheringStateChange(toDomIceGatheringState(aState));
|
||||
}
|
||||
|
||||
static mozilla::dom::PCImplIceConnectionState
|
||||
toDomIceConnectionState(NrIceCtx::ConnectionState aState)
|
||||
{
|
||||
switch (aState) {
|
||||
case NrIceCtx::ICE_CTX_INIT:
|
||||
return dom::PCImplIceConnectionState::New;
|
||||
case NrIceCtx::ICE_CTX_CHECKING:
|
||||
return dom::PCImplIceConnectionState::Checking;
|
||||
case NrIceCtx::ICE_CTX_CONNECTED:
|
||||
return dom::PCImplIceConnectionState::Connected;
|
||||
case NrIceCtx::ICE_CTX_COMPLETED:
|
||||
return dom::PCImplIceConnectionState::Completed;
|
||||
case NrIceCtx::ICE_CTX_FAILED:
|
||||
return dom::PCImplIceConnectionState::Failed;
|
||||
case NrIceCtx::ICE_CTX_DISCONNECTED:
|
||||
return dom::PCImplIceConnectionState::Disconnected;
|
||||
case NrIceCtx::ICE_CTX_CLOSED:
|
||||
return dom::PCImplIceConnectionState::Closed;
|
||||
}
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::OnConnectionStateChange(NrIceCtx* aIceCtx,
|
||||
NrIceCtx::ConnectionState aState)
|
||||
{
|
||||
SignalConnectionStateChange(toDomIceConnectionState(aState));
|
||||
}
|
||||
|
||||
// The stuff below here will eventually go into the MediaTransportChild class
|
||||
void
|
||||
MediaTransportHandler::OnCandidateFound(NrIceMediaStream* aStream,
|
||||
const std::string& aCandidate)
|
||||
{
|
||||
CandidateInfo info;
|
||||
info.mCandidate = aCandidate;
|
||||
NrIceCandidate defaultRtpCandidate;
|
||||
NrIceCandidate defaultRtcpCandidate;
|
||||
nsresult rv = aStream->GetDefaultCandidate(1, &defaultRtpCandidate);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
info.mDefaultHostRtp = defaultRtpCandidate.cand_addr.host;
|
||||
info.mDefaultPortRtp = defaultRtpCandidate.cand_addr.port;
|
||||
} else {
|
||||
CSFLogError(LOGTAG, "%s: GetDefaultCandidates failed for transport id %s, "
|
||||
"res=%u",
|
||||
__FUNCTION__,
|
||||
aStream->GetId().c_str(),
|
||||
static_cast<unsigned>(rv));
|
||||
}
|
||||
|
||||
// Optional; component won't exist if doing rtcp-mux
|
||||
if (NS_SUCCEEDED(aStream->GetDefaultCandidate(2, &defaultRtcpCandidate))) {
|
||||
info.mDefaultHostRtcp = defaultRtcpCandidate.cand_addr.host;
|
||||
info.mDefaultPortRtcp = defaultRtcpCandidate.cand_addr.port;
|
||||
}
|
||||
|
||||
SignalCandidate(aStream->GetId(), info);
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::OnStateChange(TransportLayer* aLayer,
|
||||
TransportLayer::State aState)
|
||||
{
|
||||
if (aState == TransportLayer::TS_OPEN) {
|
||||
MOZ_ASSERT(aLayer->id() == TransportLayerDtls::ID());
|
||||
TransportLayerDtls* dtlsLayer = static_cast<TransportLayerDtls*>(aLayer);
|
||||
SignalAlpnNegotiated(dtlsLayer->GetNegotiatedAlpn());
|
||||
}
|
||||
|
||||
// DTLS state indicates the readiness of the transport as a whole, because
|
||||
// SRTP uses the keys from the DTLS handshake.
|
||||
SignalStateChange(aLayer->flow_id(), aState);
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::OnRtcpStateChange(TransportLayer* aLayer,
|
||||
TransportLayer::State aState)
|
||||
{
|
||||
SignalRtcpStateChange(aLayer->flow_id(), aState);
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::PacketReceived(TransportLayer* aLayer,
|
||||
MediaPacket& aPacket)
|
||||
{
|
||||
SignalPacketReceived(aLayer->flow_id(), aPacket);
|
||||
}
|
||||
|
||||
void
|
||||
MediaTransportHandler::EncryptedPacketSending(TransportLayer* aLayer,
|
||||
MediaPacket& aPacket)
|
||||
{
|
||||
SignalEncryptedSending(aLayer->flow_id(), aPacket);
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
@ -0,0 +1,183 @@
|
||||
/* 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 _MTRANSPORTHANDLER_H__
|
||||
#define _MTRANSPORTHANDLER_H__
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "sigslot.h"
|
||||
#include "transportlayer.h" // Need the State enum
|
||||
#include "mozilla/dom/PeerConnectionImplEnumsBinding.h"
|
||||
#include "nricectx.h" // Need some enums
|
||||
#include "nsDOMNavigationTiming.h" // DOMHighResTimeStamp
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace mozilla {
|
||||
class DtlsIdentity; // TODO(bug 1494311) Use IPC type
|
||||
class NrIceCtx;
|
||||
class NrIceMediaStream;
|
||||
class NrIceResolver;
|
||||
class SdpFingerprintAttributeList; // TODO(bug 1494311) Use IPC type
|
||||
class TransportFlow;
|
||||
|
||||
namespace dom {
|
||||
struct RTCConfiguration;
|
||||
struct RTCStatsReportInternal;
|
||||
}
|
||||
|
||||
// Base-class, makes some testing easier
|
||||
class MediaTransportBase {
|
||||
public:
|
||||
virtual nsresult SendPacket(const std::string& aTransportId,
|
||||
MediaPacket& aPacket) = 0;
|
||||
|
||||
virtual TransportLayer::State GetState(const std::string& aTransportId,
|
||||
bool aRtcp) const = 0;
|
||||
sigslot::signal2<const std::string&, MediaPacket&> SignalPacketReceived;
|
||||
sigslot::signal2<const std::string&, MediaPacket&> SignalEncryptedSending;
|
||||
sigslot::signal2<const std::string&, TransportLayer::State>
|
||||
SignalStateChange;
|
||||
sigslot::signal2<const std::string&, TransportLayer::State>
|
||||
SignalRtcpStateChange;
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaTransportBase)
|
||||
|
||||
protected:
|
||||
virtual ~MediaTransportBase() {}
|
||||
};
|
||||
|
||||
class MediaTransportHandler : public MediaTransportBase,
|
||||
public sigslot::has_slots<> {
|
||||
public:
|
||||
MediaTransportHandler();
|
||||
nsresult Init(const std::string& aName,
|
||||
const dom::RTCConfiguration& aConfiguration);
|
||||
void Destroy();
|
||||
|
||||
// We will probably be able to move the proxy lookup stuff into
|
||||
// this class once we move mtransport to its own process.
|
||||
nsresult SetProxyServer(const std::string& aProxyHost,
|
||||
uint16_t aProxyPort,
|
||||
const std::string& aAlpnProtocols);
|
||||
|
||||
void EnsureProvisionalTransport(const std::string& aTransportId,
|
||||
const std::string& aLocalUfrag,
|
||||
const std::string& aLocalPwd,
|
||||
size_t aComponentCount);
|
||||
|
||||
// We set default-route-only as late as possible because it depends on what
|
||||
// capture permissions have been granted on the window, which could easily
|
||||
// change between Init (ie; when the PC is created) and StartIceGathering
|
||||
// (ie; when we set the local description).
|
||||
void StartIceGathering(bool aDefaultRouteOnly,
|
||||
// This will go away once mtransport moves to its
|
||||
// own process, because we won't need to get this
|
||||
// via IPC anymore
|
||||
const nsTArray<NrIceStunAddr>& aStunAddrs);
|
||||
|
||||
|
||||
nsresult ActivateTransport(const std::string& aTransportId,
|
||||
const std::string& aLocalUfrag,
|
||||
const std::string& aLocalPwd,
|
||||
size_t aComponentCount,
|
||||
const std::string& aUfrag,
|
||||
const std::string& aPassword,
|
||||
const std::vector<std::string>& aCandidateList,
|
||||
// TODO(bug 1494311): Use an IPC type.
|
||||
RefPtr<DtlsIdentity> aDtlsIdentity,
|
||||
bool aDtlsClient,
|
||||
// TODO(bug 1494311): Use IPC type
|
||||
const SdpFingerprintAttributeList& aFingerprints,
|
||||
bool aPrivacyRequested);
|
||||
|
||||
void RemoveTransportsExcept(const std::set<std::string>& aTransportIds);
|
||||
|
||||
nsresult StartIceChecks(bool aIsControlling,
|
||||
bool aIsOfferer,
|
||||
const std::vector<std::string>& aIceOptions);
|
||||
|
||||
nsresult AddIceCandidate(const std::string& aTransportId,
|
||||
const std::string& aCandidate);
|
||||
|
||||
void UpdateNetworkState(bool aOnline);
|
||||
|
||||
nsresult SendPacket(const std::string& aTransportId,
|
||||
MediaPacket& aPacket) override;
|
||||
|
||||
// TODO(bug 1494312): Figure out how this fits with an async API. Maybe we
|
||||
// cache on the content process.
|
||||
TransportLayer::State GetState(const std::string& aTransportId,
|
||||
bool aRtcp) const override;
|
||||
|
||||
// TODO(bug 1494312): Stats stuff needs to be async.
|
||||
void GetAllIceStats(bool internalStats,
|
||||
DOMHighResTimeStamp now,
|
||||
dom::RTCStatsReportInternal* report);
|
||||
|
||||
// TODO(bug 1494312): Stats stuff needs to be async.
|
||||
void GetIceStats(const std::string& aTransportId,
|
||||
bool internalStats,
|
||||
DOMHighResTimeStamp now,
|
||||
dom::RTCStatsReportInternal* report);
|
||||
|
||||
// TODO(bug 1494311) Use IPC type
|
||||
struct CandidateInfo {
|
||||
std::string mCandidate;
|
||||
std::string mDefaultHostRtp;
|
||||
uint16_t mDefaultPortRtp = 0;
|
||||
std::string mDefaultHostRtcp;
|
||||
uint16_t mDefaultPortRtcp = 0;
|
||||
};
|
||||
|
||||
sigslot::signal2<const std::string&, const CandidateInfo&> SignalCandidate;
|
||||
sigslot::signal1<const std::string&> SignalAlpnNegotiated;
|
||||
sigslot::signal1<dom::PCImplIceGatheringState> SignalGatheringStateChange;
|
||||
sigslot::signal1<dom::PCImplIceConnectionState> SignalConnectionStateChange;
|
||||
|
||||
private:
|
||||
RefPtr<TransportFlow> CreateTransportFlow(
|
||||
const std::string& aTransportId,
|
||||
bool aIsRtcp,
|
||||
RefPtr<DtlsIdentity> aDtlsIdentity,
|
||||
bool aDtlsClient,
|
||||
// TODO(bug 1494312) Use IPC type
|
||||
const SdpFingerprintAttributeList& aFingerprints,
|
||||
bool aPrivacyRequested);
|
||||
|
||||
struct Transport {
|
||||
RefPtr<TransportFlow> mFlow;
|
||||
RefPtr<TransportFlow> mRtcpFlow;
|
||||
};
|
||||
|
||||
void OnGatheringStateChange(NrIceCtx* aIceCtx,
|
||||
NrIceCtx::GatheringState aState);
|
||||
void OnConnectionStateChange(NrIceCtx* aIceCtx,
|
||||
NrIceCtx::ConnectionState aState);
|
||||
void OnCandidateFound(NrIceMediaStream* aStream,
|
||||
const std::string& aCandidate);
|
||||
void OnStateChange(TransportLayer* aLayer, TransportLayer::State);
|
||||
void OnRtcpStateChange(TransportLayer* aLayer, TransportLayer::State);
|
||||
void PacketReceived(TransportLayer* aLayer, MediaPacket& aPacket);
|
||||
void EncryptedPacketSending(TransportLayer* aLayer, MediaPacket& aPacket);
|
||||
RefPtr<TransportFlow> GetTransportFlow(const std::string& aId,
|
||||
bool aIsRtcp) const;
|
||||
void GetIceStats(const NrIceMediaStream& aStream,
|
||||
bool aInternalStats,
|
||||
DOMHighResTimeStamp aNow,
|
||||
dom::RTCStatsReportInternal* aReport) const;
|
||||
|
||||
|
||||
~MediaTransportHandler() override;
|
||||
RefPtr<NrIceCtx> mIceCtx;
|
||||
RefPtr<NrIceResolver> mDNSResolver;
|
||||
std::map<std::string, Transport> mTransports;
|
||||
bool mProxyOnly = false;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //_MTRANSPORTHANDLER_H__
|
@ -319,13 +319,9 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
|
||||
, mSignalingState(PCImplSignalingState::SignalingStable)
|
||||
, mIceConnectionState(PCImplIceConnectionState::New)
|
||||
, mIceGatheringState(PCImplIceGatheringState::New)
|
||||
, mDtlsConnected(false)
|
||||
, mWindow(nullptr)
|
||||
, mCertificate(nullptr)
|
||||
, mPrivacyRequested(false)
|
||||
, mSTSThread(nullptr)
|
||||
, mAllowIceLoopback(false)
|
||||
, mAllowIceLinkLocal(false)
|
||||
, mForceIceTcp(false)
|
||||
, mMedia(nullptr)
|
||||
, mUuidGen(MakeUnique<PCUuidGenerator>())
|
||||
@ -356,10 +352,6 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
|
||||
CSFLogInfo(LOGTAG, "%s: PeerConnectionImpl constructor for %s",
|
||||
__FUNCTION__, mHandle.c_str());
|
||||
STAMP_TIMECARD(mTimeCard, "Constructor Completed");
|
||||
mAllowIceLoopback = Preferences::GetBool(
|
||||
"media.peerconnection.ice.loopback", false);
|
||||
mAllowIceLinkLocal = Preferences::GetBool(
|
||||
"media.peerconnection.ice.link_local", false);
|
||||
mForceIceTcp = Preferences::GetBool(
|
||||
"media.peerconnection.ice.force_ice_tcp", false);
|
||||
memset(mMaxReceiving, 0, sizeof(mMaxReceiving));
|
||||
@ -507,9 +499,6 @@ PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
|
||||
mMedia->SignalUpdateDefaultCandidate.connect(
|
||||
this,
|
||||
&PeerConnectionImpl::UpdateDefaultCandidate);
|
||||
mMedia->SignalEndOfLocalCandidates.connect(
|
||||
this,
|
||||
&PeerConnectionImpl::EndOfLocalCandidates);
|
||||
mMedia->SignalIceConnectionStateChange.connect(
|
||||
this,
|
||||
&PeerConnectionImpl::IceConnectionStateChange);
|
||||
@ -582,7 +571,7 @@ PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
|
||||
|
||||
if (!aConfiguration.mPeerIdentity.IsEmpty()) {
|
||||
mPeerIdentity = new PeerIdentity(aConfiguration.mPeerIdentity);
|
||||
mPrivacyRequested = true;
|
||||
mPrivacyRequested = Some(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -922,7 +911,8 @@ PeerConnectionImpl::EnsureDataConnection(uint16_t aLocalPort,
|
||||
nsCOMPtr<nsIEventTarget> target = mWindow
|
||||
? mWindow->EventTargetFor(TaskCategory::Other)
|
||||
: nullptr;
|
||||
mDataConnection = new DataChannelConnection(this, target);
|
||||
mDataConnection = new DataChannelConnection(
|
||||
this, target, mMedia->mTransportHandler);
|
||||
if (!mDataConnection->Init(aLocalPort, aNumstreams, aMMSSet, aMaxMessageSize)) {
|
||||
CSFLogError(LOGTAG,"%s DataConnection Init Failed",__FUNCTION__);
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -939,7 +929,8 @@ PeerConnectionImpl::GetDatachannelParameters(
|
||||
uint16_t* remoteport,
|
||||
uint32_t* remotemaxmessagesize,
|
||||
bool* mmsset,
|
||||
std::string* transportId) const {
|
||||
std::string* transportId,
|
||||
bool* client) const {
|
||||
|
||||
for (const auto& transceiver : mJsepSession->GetTransceivers()) {
|
||||
bool dataChannel =
|
||||
@ -990,6 +981,9 @@ PeerConnectionImpl::GetDatachannelParameters(
|
||||
(codec)->mRemoteMMSSet;
|
||||
MOZ_ASSERT(!transceiver->mTransport.mTransportId.empty());
|
||||
*transportId = transceiver->mTransport.mTransportId;
|
||||
*client =
|
||||
transceiver->mTransport.mDtls->GetRole() ==
|
||||
JsepDtlsTransport::kJsepDtlsClient;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
@ -1115,8 +1109,9 @@ PeerConnectionImpl::InitializeDataChannel()
|
||||
uint32_t remotemaxmessagesize = 0;
|
||||
bool mmsset = false;
|
||||
std::string transportId;
|
||||
bool client = false;
|
||||
nsresult rv = GetDatachannelParameters(&channels, &localport, &remoteport,
|
||||
&remotemaxmessagesize, &mmsset, &transportId);
|
||||
&remotemaxmessagesize, &mmsset, &transportId, &client);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogDebug(LOGTAG, "%s: We did not negotiate datachannel", __FUNCTION__);
|
||||
@ -1129,16 +1124,9 @@ PeerConnectionImpl::InitializeDataChannel()
|
||||
|
||||
rv = EnsureDataConnection(localport, channels, remotemaxmessagesize, mmsset);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// use the specified TransportFlow
|
||||
RefPtr<TransportFlow> flow = mMedia->GetTransportFlow(transportId, false).get();
|
||||
CSFLogDebug(LOGTAG, "Transportflow[%s] = %p",
|
||||
transportId.c_str(), flow.get());
|
||||
if (flow) {
|
||||
if (mDataConnection->ConnectViaTransportFlow(flow,
|
||||
localport,
|
||||
remoteport)) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (mDataConnection->ConnectToTransport(
|
||||
transportId, client, localport, remoteport)) {
|
||||
return NS_OK;
|
||||
}
|
||||
// If we inited the DataConnection, call Destroy() before releasing it
|
||||
mDataConnection->Destroy();
|
||||
@ -1443,8 +1431,9 @@ PeerConnectionImpl::SetLocalDescription(int32_t aAction, const char* aSDP)
|
||||
|
||||
STAMP_TIMECARD(mTimeCard, "Set Local Description");
|
||||
|
||||
bool isolated = mMedia->AnyLocalTrackHasPeerIdentity();
|
||||
mPrivacyRequested = mPrivacyRequested || isolated;
|
||||
if (mMedia->AnyLocalTrackHasPeerIdentity()) {
|
||||
mPrivacyRequested = Some(true);
|
||||
}
|
||||
|
||||
mLocalRequestedSDP = aSDP;
|
||||
|
||||
@ -1820,16 +1809,21 @@ PeerConnectionImpl::SetPeerIdentity(const nsAString& aPeerIdentity)
|
||||
}
|
||||
|
||||
nsresult
|
||||
PeerConnectionImpl::SetDtlsConnected(bool aPrivacyRequested)
|
||||
PeerConnectionImpl::OnAlpnNegotiated(const std::string& aAlpn)
|
||||
{
|
||||
PC_AUTO_ENTER_API_CALL(false);
|
||||
if (mPrivacyRequested.isSome()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mPrivacyRequested = Some(aAlpn == "c-webrtc");
|
||||
|
||||
// For this, as with mPrivacyRequested, once we've connected to a peer, we
|
||||
// fixate on that peer. Dealing with multiple peers or connections is more
|
||||
// than this run-down wreck of an object can handle.
|
||||
// Besides, this is only used to say if we have been connected ever.
|
||||
if (!mPrivacyRequested && !aPrivacyRequested && !mDtlsConnected) {
|
||||
// now we know that privacy isn't needed for sure
|
||||
if (!*mPrivacyRequested) {
|
||||
// Neither side wants privacy
|
||||
nsIDocument* doc = GetWindow()->GetExtantDoc();
|
||||
if (!doc) {
|
||||
CSFLogInfo(LOGTAG, "Can't update principal on streams; document gone");
|
||||
@ -1837,8 +1831,7 @@ PeerConnectionImpl::SetDtlsConnected(bool aPrivacyRequested)
|
||||
}
|
||||
mMedia->UpdateRemoteStreamPrincipals_m(doc->NodePrincipal());
|
||||
}
|
||||
mDtlsConnected = true;
|
||||
mPrivacyRequested = mPrivacyRequested || aPrivacyRequested;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2069,7 +2062,7 @@ PeerConnectionImpl::CreateReceiveTrack(SdpMediaSection::MediaType type)
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsIDocument* doc = GetWindow()->GetExtantDoc();
|
||||
MOZ_ASSERT(doc);
|
||||
if (mDtlsConnected && !PrivacyRequested()) {
|
||||
if (mPrivacyRequested.isSome() && !*mPrivacyRequested) {
|
||||
principal = doc->NodePrincipal();
|
||||
} else {
|
||||
// we're either certain that we need isolation for the streams, OR
|
||||
@ -2669,6 +2662,11 @@ PeerConnectionImpl::CandidateReady(const std::string& candidate,
|
||||
const std::string& transportId) {
|
||||
PC_AUTO_ENTER_API_CALL_VOID_RETURN(false);
|
||||
|
||||
if (candidate.empty()) {
|
||||
mJsepSession->EndOfLocalCandidates(transportId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mForceIceTcp && std::string::npos != candidate.find(" UDP ")) {
|
||||
CSFLogWarn(LOGTAG, "Blocking local UDP candidate: %s", candidate.c_str());
|
||||
return;
|
||||
@ -2886,12 +2884,6 @@ PeerConnectionImpl::UpdateDefaultCandidate(const std::string& defaultAddr,
|
||||
transportId);
|
||||
}
|
||||
|
||||
void
|
||||
PeerConnectionImpl::EndOfLocalCandidates(const std::string& transportId) {
|
||||
CSFLogDebug(LOGTAG, "%s", __FUNCTION__);
|
||||
mJsepSession->EndOfLocalCandidates(transportId);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PeerConnectionImpl::BuildStatsQuery_m(
|
||||
mozilla::dom::MediaStreamTrack *aSelector,
|
||||
@ -2912,10 +2904,6 @@ PeerConnectionImpl::BuildStatsQuery_m(
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Note: mMedia->ice_ctx() is deleted on STS thread; so make sure we grab and hold
|
||||
// a ref instead of making multiple calls. NrIceCtx uses threadsafe refcounting.
|
||||
// NOTE: Do this after all other failure tests, to ensure we don't
|
||||
// accidentally release the Ctx on Mainthread.
|
||||
query->media = mMedia;
|
||||
if (!query->media) {
|
||||
CSFLogError(LOGTAG, "Could not build stats query, no ice_ctx");
|
||||
@ -3199,15 +3187,17 @@ PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
|
||||
}
|
||||
}
|
||||
|
||||
if (query->grabAllLevels) {
|
||||
query->media->GetAllIceStats_s(query->internalStats,
|
||||
query->now,
|
||||
query->report);
|
||||
} else {
|
||||
query->media->GetIceStats_s(query->transportId,
|
||||
query->internalStats,
|
||||
query->now,
|
||||
query->report);
|
||||
if (query->media->mTransportHandler) {
|
||||
if (query->grabAllLevels) {
|
||||
query->media->mTransportHandler->GetAllIceStats(query->internalStats,
|
||||
query->now,
|
||||
query->report);
|
||||
} else {
|
||||
query->media->mTransportHandler->GetIceStats(query->transportId,
|
||||
query->internalStats,
|
||||
query->now,
|
||||
query->report);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -211,14 +211,6 @@ public:
|
||||
return mMedia;
|
||||
}
|
||||
|
||||
// Configure the ability to use localhost.
|
||||
void SetAllowIceLoopback(bool val) { mAllowIceLoopback = val; }
|
||||
bool GetAllowIceLoopback() const { return mAllowIceLoopback; }
|
||||
|
||||
// Configure the ability to use IPV6 link-local addresses.
|
||||
void SetAllowIceLinkLocal(bool val) { mAllowIceLinkLocal = val; }
|
||||
bool GetAllowIceLinkLocal() const { return mAllowIceLinkLocal; }
|
||||
|
||||
// Handle system to allow weak references to be passed through C code
|
||||
virtual const std::string& GetHandle();
|
||||
|
||||
@ -233,7 +225,6 @@ public:
|
||||
const std::string& defaultRtcpAddr,
|
||||
uint16_t defaultRtcpPort,
|
||||
const std::string& transportId);
|
||||
void EndOfLocalCandidates(const std::string& transportId);
|
||||
|
||||
static void ListenThread(void *aData);
|
||||
static void ConnectThread(void *aData);
|
||||
@ -447,7 +438,10 @@ public:
|
||||
}
|
||||
|
||||
// this method checks to see if we've made a promise to protect media.
|
||||
bool PrivacyRequested() const { return mPrivacyRequested; }
|
||||
bool PrivacyRequested() const
|
||||
{
|
||||
return mPrivacyRequested.isSome() && *mPrivacyRequested;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP GetFingerprint(char** fingerprint);
|
||||
void GetFingerprint(nsAString& fingerprint)
|
||||
@ -541,7 +535,7 @@ public:
|
||||
|
||||
bool IsClosed() const;
|
||||
// called when DTLS connects; we only need this once
|
||||
nsresult SetDtlsConnected(bool aPrivacyRequested);
|
||||
nsresult OnAlpnNegotiated(const std::string& aAlpn);
|
||||
|
||||
bool HasMedia() const;
|
||||
|
||||
@ -611,7 +605,8 @@ private:
|
||||
uint16_t* remoteport,
|
||||
uint32_t* maxmessagesize,
|
||||
bool* mmsset,
|
||||
std::string* transportId) const;
|
||||
std::string* transportId,
|
||||
bool* client) const;
|
||||
|
||||
nsresult AddRtpTransceiverToJsepSession(RefPtr<JsepTransceiver>& transceiver);
|
||||
already_AddRefed<TransceiverImpl> CreateTransceiverImpl(
|
||||
@ -649,10 +644,6 @@ private:
|
||||
mozilla::dom::PCImplIceConnectionState mIceConnectionState;
|
||||
mozilla::dom::PCImplIceGatheringState mIceGatheringState;
|
||||
|
||||
// DTLS
|
||||
// this is true if we have been connected ever, see SetDtlsConnected
|
||||
bool mDtlsConnected;
|
||||
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
// TODO: Remove if we ever properly wire PeerConnection for cycle-collection.
|
||||
nsWeakPtr mPCObserver;
|
||||
@ -679,7 +670,7 @@ private:
|
||||
//
|
||||
// This can be false if mPeerIdentity is set, in the case where identity is
|
||||
// provided, but the media is not protected from the app on either side
|
||||
bool mPrivacyRequested;
|
||||
Maybe<bool> mPrivacyRequested;
|
||||
|
||||
// A handle to refer to this PC with
|
||||
std::string mHandle;
|
||||
@ -693,8 +684,6 @@ private:
|
||||
// DataConnection that's used to get all the DataChannels
|
||||
RefPtr<mozilla::DataChannelConnection> mDataConnection;
|
||||
|
||||
bool mAllowIceLoopback;
|
||||
bool mAllowIceLinkLocal;
|
||||
bool mForceIceTcp;
|
||||
RefPtr<PeerConnectionMedia> mMedia;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,7 @@
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/net/StunAddrsRequestChild.h"
|
||||
#include "nsIProtocolProxyCallback.h"
|
||||
#include "MediaTransportHandler.h"
|
||||
|
||||
#include "TransceiverImpl.h"
|
||||
|
||||
@ -22,8 +23,6 @@ namespace mozilla {
|
||||
class DataChannel;
|
||||
class PeerIdentity;
|
||||
namespace dom {
|
||||
struct RTCInboundRTPStreamStats;
|
||||
struct RTCOutboundRTPStreamStats;
|
||||
class MediaStreamTrack;
|
||||
}
|
||||
}
|
||||
@ -49,19 +48,10 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
|
||||
public:
|
||||
explicit PeerConnectionMedia(PeerConnectionImpl *parent);
|
||||
|
||||
PeerConnectionImpl* GetPC() { return mParent; }
|
||||
nsresult Init(const dom::RTCConfiguration& aConfiguration);
|
||||
// WARNING: This destroys the object!
|
||||
void SelfDestruct();
|
||||
|
||||
void GetIceStats_s(const std::string& aTransportId,
|
||||
bool internalStats,
|
||||
DOMHighResTimeStamp now,
|
||||
RTCStatsReportInternal* report) const;
|
||||
void GetAllIceStats_s(bool internalStats,
|
||||
DOMHighResTimeStamp now,
|
||||
RTCStatsReportInternal* report) const;
|
||||
|
||||
// Ensure ICE transports exist that we might need when offer/answer concludes
|
||||
void EnsureTransports(const JsepSession& aSession);
|
||||
|
||||
@ -129,19 +119,6 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
|
||||
const nsCOMPtr<nsIThread>& GetMainThread() const { return mMainThread; }
|
||||
const nsCOMPtr<nsIEventTarget>& GetSTSThread() const { return mSTSThread; }
|
||||
|
||||
// Get a transport flow either RTP/RTCP for a particular stream
|
||||
// A stream can be of audio/video/datachannel/budled(?) types
|
||||
RefPtr<TransportFlow> GetTransportFlow(const std::string& aId,
|
||||
bool aIsRtcp) {
|
||||
auto& flows = aIsRtcp ? mRtcpTransportFlows : mTransportFlows;
|
||||
auto it = flows.find(aId);
|
||||
if (it == flows.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Used by PCImpl in a couple of places. Might be good to move that code in
|
||||
// here.
|
||||
std::vector<RefPtr<TransceiverImpl>>& GetTransceivers()
|
||||
@ -149,15 +126,9 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
|
||||
return mTransceivers;
|
||||
}
|
||||
|
||||
// Add a transport flow
|
||||
void AddTransportFlow(const std::string& aId, bool aRtcp,
|
||||
const RefPtr<TransportFlow> &aFlow);
|
||||
void RemoveTransportFlow(const std::string& aId, bool aRtcp);
|
||||
void ConnectDtlsListener_s(const RefPtr<TransportFlow>& aFlow);
|
||||
void DtlsConnected_s(TransportLayer* aFlow,
|
||||
TransportLayer::State state);
|
||||
static void DtlsConnected_m(const std::string& aParentHandle,
|
||||
bool aPrivacyRequested);
|
||||
void AlpnNegotiated_s(const std::string& aAlpn);
|
||||
static void AlpnNegotiated_m(const std::string& aParentHandle,
|
||||
const std::string& aAlpn);
|
||||
|
||||
// ICE state signals
|
||||
sigslot::signal1<mozilla::dom::PCImplIceGatheringState>
|
||||
@ -165,17 +136,19 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
|
||||
sigslot::signal1<mozilla::dom::PCImplIceConnectionState>
|
||||
SignalIceConnectionStateChange;
|
||||
// This passes a candidate:... attribute and transport id
|
||||
// end-of-candidates is signaled with the empty string
|
||||
sigslot::signal2<const std::string&, const std::string&> SignalCandidate;
|
||||
// This passes address, port, transport id of the default candidate.
|
||||
sigslot::signal5<const std::string&, uint16_t,
|
||||
const std::string&, uint16_t, const std::string&>
|
||||
SignalUpdateDefaultCandidate;
|
||||
sigslot::signal1<const std::string&>
|
||||
SignalEndOfLocalCandidates;
|
||||
|
||||
// TODO: Move to PeerConnectionImpl
|
||||
RefPtr<WebRtcCallWrapper> mCall;
|
||||
|
||||
// mtransport objects
|
||||
RefPtr<MediaTransportHandler> mTransportHandler;
|
||||
|
||||
private:
|
||||
void InitLocalAddrs(); // for stun local address IPC request
|
||||
nsresult InitProxy();
|
||||
@ -215,86 +188,39 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
|
||||
void SelfDestruct_m();
|
||||
|
||||
// Manage ICE transports.
|
||||
nsresult UpdateTransport(const JsepTransceiver& aTransceiver,
|
||||
bool aForceIceTcp);
|
||||
|
||||
void EnsureTransport_s(const std::string& aTransportId,
|
||||
const std::string& aUfrag,
|
||||
const std::string& aPwd,
|
||||
size_t aComponentCount);
|
||||
void ActivateTransport_s(const std::string& aTransportId,
|
||||
const std::string& aLocalUfrag,
|
||||
const std::string& aLocalPwd,
|
||||
size_t aComponentCount,
|
||||
const std::string& aUfrag,
|
||||
const std::string& aPassword,
|
||||
const std::vector<std::string>& aCandidateList);
|
||||
void RemoveTransportsExcept_s(const std::set<std::string>& aTransportIds);
|
||||
nsresult UpdateTransportFlows(const JsepTransceiver& transceiver);
|
||||
nsresult UpdateTransportFlow(bool aIsRtcp,
|
||||
const JsepTransport& aTransport);
|
||||
void UpdateTransport(const JsepTransceiver& aTransceiver,
|
||||
bool aForceIceTcp);
|
||||
|
||||
void GatherIfReady();
|
||||
void FlushIceCtxOperationQueueIfReady();
|
||||
void PerformOrEnqueueIceCtxOperation(nsIRunnable* runnable);
|
||||
void EnsureIceGathering_s(bool aDefaultRouteOnly, bool aProxyOnly);
|
||||
void EnsureIceGathering_s(bool aDefaultRouteOnly);
|
||||
void StartIceChecks_s(bool aIsControlling,
|
||||
bool aIsOfferer,
|
||||
bool aIsIceLite,
|
||||
const std::vector<std::string>& aIceOptionsList);
|
||||
|
||||
bool GetPrefDefaultAddressOnly() const;
|
||||
bool GetPrefProxyOnly() const;
|
||||
|
||||
void ConnectSignals(NrIceCtx *aCtx, NrIceCtx *aOldCtx=nullptr);
|
||||
|
||||
// Process a trickle ICE candidate.
|
||||
void AddIceCandidate_s(const std::string& aCandidate,
|
||||
const std::string& aTransportId);
|
||||
|
||||
void UpdateNetworkState_s(bool online);
|
||||
void ConnectSignals();
|
||||
|
||||
// ICE events
|
||||
void IceGatheringStateChange_s(NrIceCtx* ctx,
|
||||
NrIceCtx::GatheringState state);
|
||||
void IceConnectionStateChange_s(NrIceCtx* ctx,
|
||||
NrIceCtx::ConnectionState state);
|
||||
void IceStreamReady_s(NrIceMediaStream *aStream);
|
||||
void OnCandidateFound_s(NrIceMediaStream *aStream,
|
||||
const std::string& aCandidate);
|
||||
void EndOfLocalCandidates(const std::string& aDefaultAddr,
|
||||
uint16_t aDefaultPort,
|
||||
const std::string& aDefaultRtcpAddr,
|
||||
uint16_t aDefaultRtcpPort,
|
||||
const std::string& aTransportId);
|
||||
void GetDefaultCandidates(const NrIceMediaStream& aStream,
|
||||
NrIceCandidate* aCandidate,
|
||||
NrIceCandidate* aRtcpCandidate);
|
||||
void IceGatheringStateChange_s(dom::PCImplIceGatheringState aState);
|
||||
void IceConnectionStateChange_s(dom::PCImplIceConnectionState aState);
|
||||
void OnCandidateFound_s(
|
||||
const std::string& aTransportId,
|
||||
const MediaTransportHandler::CandidateInfo& aCandidateInfo);
|
||||
|
||||
void IceGatheringStateChange_m(dom::PCImplIceGatheringState aState);
|
||||
void IceConnectionStateChange_m(dom::PCImplIceConnectionState aState);
|
||||
void OnCandidateFound_m(
|
||||
const std::string& aTransportId,
|
||||
const MediaTransportHandler::CandidateInfo& aCandidateInfo);
|
||||
|
||||
void IceGatheringStateChange_m(NrIceCtx* ctx,
|
||||
NrIceCtx::GatheringState state);
|
||||
void IceConnectionStateChange_m(NrIceCtx* ctx,
|
||||
NrIceCtx::ConnectionState state);
|
||||
void OnCandidateFound_m(const std::string& aCandidateLine,
|
||||
const std::string& aDefaultAddr,
|
||||
uint16_t aDefaultPort,
|
||||
const std::string& aDefaultRtcpAddr,
|
||||
uint16_t aDefaultRtcpPort,
|
||||
const std::string& aTransportId);
|
||||
void EndOfLocalCandidates_m(const std::string& aDefaultAddr,
|
||||
uint16_t aDefaultPort,
|
||||
const std::string& aDefaultRtcpAddr,
|
||||
uint16_t aDefaultRtcpPort,
|
||||
const std::string& aTransportId);
|
||||
bool IsIceCtxReady() const {
|
||||
return mProxyResolveCompleted && mLocalAddrsCompleted;
|
||||
}
|
||||
|
||||
void GetIceStats_s(const NrIceMediaStream& aStream,
|
||||
bool internalStats,
|
||||
DOMHighResTimeStamp now,
|
||||
RTCStatsReportInternal* report) const;
|
||||
|
||||
// The parent PC
|
||||
PeerConnectionImpl *mParent;
|
||||
// and a loose handle on it for event driven stuff
|
||||
@ -303,21 +229,6 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
|
||||
|
||||
std::vector<RefPtr<TransceiverImpl>> mTransceivers;
|
||||
|
||||
// ICE objects
|
||||
RefPtr<NrIceCtx> mIceCtx;
|
||||
|
||||
// DNS
|
||||
RefPtr<NrIceResolver> mDNSResolver;
|
||||
|
||||
// Transport flows for RTP and RTP/RTCP mux
|
||||
std::map<std::string, RefPtr<TransportFlow> > mTransportFlows;
|
||||
|
||||
// Transport flows for standalone RTCP (rarely used)
|
||||
std::map<std::string, RefPtr<TransportFlow> > mRtcpTransportFlows;
|
||||
|
||||
// UUID Generator
|
||||
UniquePtr<PCUuidGenerator> mUuidGen;
|
||||
|
||||
// The main thread.
|
||||
nsCOMPtr<nsIThread> mMainThread;
|
||||
|
||||
@ -337,7 +248,8 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
|
||||
bool mProxyResolveCompleted;
|
||||
|
||||
// Used to store the result of the request.
|
||||
UniquePtr<NrIceProxyServer> mProxyServer;
|
||||
std::string mProxyHost;
|
||||
uint16_t mProxyPort;
|
||||
|
||||
// Used to cancel incoming stun addrs response
|
||||
RefPtr<net::StunAddrsRequestChild> mStunAddrsRequest;
|
||||
|
@ -3,12 +3,9 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "TransceiverImpl.h"
|
||||
#include "mtransport/runnable_utils.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include "AudioConduit.h"
|
||||
#include "VideoConduit.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
@ -22,7 +19,7 @@
|
||||
#include "MediaSegment.h"
|
||||
#include "RemoteTrackSource.h"
|
||||
#include "MediaConduitInterface.h"
|
||||
#include "PeerConnectionMedia.h"
|
||||
#include "MediaTransportHandler.h"
|
||||
#include "mozilla/dom/RTCRtpReceiverBinding.h"
|
||||
#include "mozilla/dom/RTCRtpSenderBinding.h"
|
||||
#include "mozilla/dom/RTCRtpTransceiverBinding.h"
|
||||
@ -36,6 +33,7 @@ using LocalDirection = MediaSessionConduitLocalDirection;
|
||||
|
||||
TransceiverImpl::TransceiverImpl(
|
||||
const std::string& aPCHandle,
|
||||
MediaTransportHandler* aTransportHandler,
|
||||
JsepTransceiver* aJsepTransceiver,
|
||||
nsIEventTarget* aMainThread,
|
||||
nsIEventTarget* aStsThread,
|
||||
@ -43,6 +41,7 @@ TransceiverImpl::TransceiverImpl(
|
||||
dom::MediaStreamTrack* aSendTrack,
|
||||
WebRtcCallWrapper* aCallWrapper) :
|
||||
mPCHandle(aPCHandle),
|
||||
mTransportHandler(aTransportHandler),
|
||||
mJsepTransceiver(aJsepTransceiver),
|
||||
mHaveStartedReceiving(false),
|
||||
mHaveSetupTransport(false),
|
||||
@ -66,6 +65,7 @@ TransceiverImpl::TransceiverImpl(
|
||||
|
||||
mTransmitPipeline = new MediaPipelineTransmit(
|
||||
mPCHandle,
|
||||
mTransportHandler,
|
||||
mMainThread.get(),
|
||||
mStsThread.get(),
|
||||
IsVideo(),
|
||||
@ -93,6 +93,7 @@ TransceiverImpl::InitAudio()
|
||||
|
||||
mReceivePipeline = new MediaPipelineReceiveAudio(
|
||||
mPCHandle,
|
||||
mTransportHandler,
|
||||
mMainThread.get(),
|
||||
mStsThread.get(),
|
||||
static_cast<AudioSessionConduit*>(mConduit.get()),
|
||||
@ -114,6 +115,7 @@ TransceiverImpl::InitVideo()
|
||||
|
||||
mReceivePipeline = new MediaPipelineReceiveVideo(
|
||||
mPCHandle,
|
||||
mTransportHandler,
|
||||
mMainThread.get(),
|
||||
mStsThread.get(),
|
||||
static_cast<VideoSessionConduit*>(mConduit.get()),
|
||||
@ -140,13 +142,12 @@ TransceiverImpl::Shutdown_m()
|
||||
mTransmitPipeline->Shutdown_m();
|
||||
mReceivePipeline = nullptr;
|
||||
mTransmitPipeline = nullptr;
|
||||
mTransportHandler = nullptr;
|
||||
mSendTrack = nullptr;
|
||||
if (mConduit) {
|
||||
mConduit->DeleteStreams();
|
||||
}
|
||||
mConduit = nullptr;
|
||||
RUN_ON_THREAD(mStsThread, WrapRelease(mRtpFlow.forget()), NS_DISPATCH_NORMAL);
|
||||
RUN_ON_THREAD(mStsThread, WrapRelease(mRtcpFlow.forget()), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -163,7 +164,7 @@ TransceiverImpl::UpdateSendTrack(dom::MediaStreamTrack* aSendTrack)
|
||||
}
|
||||
|
||||
nsresult
|
||||
TransceiverImpl::UpdateTransport(PeerConnectionMedia& aTransportManager)
|
||||
TransceiverImpl::UpdateTransport()
|
||||
{
|
||||
if (!mJsepTransceiver->HasLevel()) {
|
||||
return NS_OK;
|
||||
@ -178,9 +179,6 @@ TransceiverImpl::UpdateTransport(PeerConnectionMedia& aTransportManager)
|
||||
ASSERT_ON_THREAD(mMainThread);
|
||||
nsAutoPtr<MediaPipelineFilter> filter;
|
||||
|
||||
mRtpFlow = aTransportManager.GetTransportFlow(GetTransportId(), false);
|
||||
mRtcpFlow = aTransportManager.GetTransportFlow(GetTransportId(), true);
|
||||
|
||||
if (mJsepTransceiver->HasBundleLevel() &&
|
||||
mJsepTransceiver->mRecvTrack.GetNegotiatedDetails()) {
|
||||
filter = new MediaPipelineFilter;
|
||||
@ -201,8 +199,10 @@ TransceiverImpl::UpdateTransport(PeerConnectionMedia& aTransportManager)
|
||||
}
|
||||
}
|
||||
|
||||
mReceivePipeline->UpdateTransport_m(mRtpFlow, mRtcpFlow, filter);
|
||||
mTransmitPipeline->UpdateTransport_m(mRtpFlow, mRtcpFlow, nsAutoPtr<MediaPipelineFilter>());
|
||||
mReceivePipeline->UpdateTransport_m(
|
||||
mJsepTransceiver->mTransport.mTransportId, filter);
|
||||
mTransmitPipeline->UpdateTransport_m(
|
||||
mJsepTransceiver->mTransport.mTransportId, filter);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -9,17 +9,14 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
#include "mozilla/dom/MediaStreamTrack.h"
|
||||
#include "ErrorList.h"
|
||||
#include "mtransport/transportflow.h"
|
||||
#include "signaling/src/jsep/JsepTransceiver.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
|
||||
namespace mozilla {
|
||||
class PeerIdentity;
|
||||
class PeerConnectionMedia;
|
||||
class JsepTransceiver;
|
||||
enum class MediaSessionConduitLocalDirection : int;
|
||||
class MediaSessionConduit;
|
||||
@ -29,6 +26,7 @@ class MediaPipelineReceive;
|
||||
class MediaPipelineTransmit;
|
||||
class MediaPipeline;
|
||||
class MediaPipelineFilter;
|
||||
class MediaTransportHandler;
|
||||
class WebRtcCallWrapper;
|
||||
class JsepTrackNegotiatedDetails;
|
||||
|
||||
@ -41,7 +39,7 @@ struct RTCRtpSourceEntry;
|
||||
* This is what ties all the various pieces that make up a transceiver
|
||||
* together. This includes:
|
||||
* MediaStreamTrack for rendering and capture
|
||||
* TransportFlow for RTP transmission/reception
|
||||
* MediaTransportHandler for RTP transmission/reception
|
||||
* Audio/VideoConduit for feeding RTP/RTCP into webrtc.org for decoding, and
|
||||
* feeding audio/video frames into webrtc.org for encoding into RTP/RTCP.
|
||||
*/
|
||||
@ -53,6 +51,7 @@ public:
|
||||
* set.
|
||||
*/
|
||||
TransceiverImpl(const std::string& aPCHandle,
|
||||
MediaTransportHandler* aTransportHandler,
|
||||
JsepTransceiver* aJsepTransceiver,
|
||||
nsIEventTarget* aMainThread,
|
||||
nsIEventTarget* aStsThread,
|
||||
@ -71,7 +70,7 @@ public:
|
||||
nsIPrincipal* aPrincipal,
|
||||
const PeerIdentity* aSinkIdentity);
|
||||
|
||||
nsresult UpdateTransport(PeerConnectionMedia& aTransportManager);
|
||||
nsresult UpdateTransport();
|
||||
|
||||
nsresult UpdateConduit();
|
||||
|
||||
@ -144,6 +143,7 @@ private:
|
||||
void Stop();
|
||||
|
||||
const std::string mPCHandle;
|
||||
RefPtr<MediaTransportHandler> mTransportHandler;
|
||||
RefPtr<JsepTransceiver> mJsepTransceiver;
|
||||
std::string mMid;
|
||||
bool mHaveStartedReceiving;
|
||||
@ -154,8 +154,6 @@ private:
|
||||
RefPtr<dom::MediaStreamTrack> mSendTrack;
|
||||
// state for webrtc.org that is shared between all transceivers
|
||||
RefPtr<WebRtcCallWrapper> mCallWrapper;
|
||||
RefPtr<TransportFlow> mRtpFlow;
|
||||
RefPtr<TransportFlow> mRtcpFlow;
|
||||
RefPtr<MediaSessionConduit> mConduit;
|
||||
RefPtr<MediaPipelineReceive> mReceivePipeline;
|
||||
RefPtr<MediaPipelineTransmit> mTransmitPipeline;
|
||||
|
@ -22,6 +22,7 @@ LOCAL_INCLUDES += [
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'MediaTransportHandler.cpp',
|
||||
'PacketDumper.cpp',
|
||||
'PeerConnectionCtx.cpp',
|
||||
'PeerConnectionImpl.cpp',
|
||||
|
@ -50,6 +50,8 @@
|
||||
#include "mozilla/Unused.h"
|
||||
#ifdef MOZ_PEERCONNECTION
|
||||
#include "mtransport/runnable_utils.h"
|
||||
#include "signaling/src/peerconnection/MediaTransportHandler.h"
|
||||
#include "mediapacket.h"
|
||||
#endif
|
||||
|
||||
#define DATACHANNEL_LOG(args) LOG(args)
|
||||
@ -304,7 +306,8 @@ debug_printf(const char *format, ...)
|
||||
}
|
||||
|
||||
DataChannelConnection::DataChannelConnection(DataConnectionListener *listener,
|
||||
nsIEventTarget *aTarget)
|
||||
nsIEventTarget *aTarget,
|
||||
MediaTransportHandler* aHandler)
|
||||
: NeckoTargetHolder(aTarget)
|
||||
, mLock("netwerk::sctp::DataChannelConnection")
|
||||
, mSendInterleaved(false)
|
||||
@ -312,13 +315,13 @@ DataChannelConnection::DataChannelConnection(DataConnectionListener *listener,
|
||||
, mMaxMessageSizeSet(false)
|
||||
, mMaxMessageSize(0)
|
||||
, mAllocateEven(false)
|
||||
, mTransportHandler(aHandler)
|
||||
{
|
||||
mCurrentStream = 0;
|
||||
mState = CLOSED;
|
||||
mSocket = nullptr;
|
||||
mMasterSocket = nullptr;
|
||||
mListener = listener;
|
||||
mDtls = nullptr;
|
||||
mLocalPort = 0;
|
||||
mRemotePort = 0;
|
||||
mPendingType = PENDING_NONE;
|
||||
@ -336,10 +339,7 @@ DataChannelConnection::~DataChannelConnection()
|
||||
ASSERT_WEBRTC(mState == CLOSED);
|
||||
MOZ_ASSERT(!mMasterSocket);
|
||||
MOZ_ASSERT(mPending.GetSize() == 0);
|
||||
MOZ_ASSERT(!mDtls);
|
||||
|
||||
// Already disconnected from sigslot/mTransportFlow
|
||||
// TransportFlows must be released from the STS thread
|
||||
if (!IsSTSThread()) {
|
||||
ASSERT_WEBRTC(NS_IsMainThread());
|
||||
|
||||
@ -421,8 +421,7 @@ void DataChannelConnection::DestroyOnSTS(struct socket *aMasterSocket,
|
||||
|
||||
void DataChannelConnection::DestroyOnSTSFinal()
|
||||
{
|
||||
mTransportFlow = nullptr;
|
||||
mDtls = nullptr;
|
||||
mTransportHandler = nullptr;
|
||||
sDataChannelShutdown->CreateConnectionShutdown(this);
|
||||
}
|
||||
|
||||
@ -686,60 +685,71 @@ DataChannelConnection::GetMaxMessageSize()
|
||||
}
|
||||
|
||||
#ifdef MOZ_PEERCONNECTION
|
||||
void
|
||||
DataChannelConnection::SetEvenOdd()
|
||||
{
|
||||
ASSERT_WEBRTC(IsSTSThread());
|
||||
|
||||
MOZ_ASSERT(mDtls); // DTLS is mandatory
|
||||
mAllocateEven = (mDtls->role() == TransportLayerDtls::CLIENT);
|
||||
}
|
||||
|
||||
bool
|
||||
DataChannelConnection::ConnectViaTransportFlow(TransportFlow *aFlow, uint16_t localport, uint16_t remoteport)
|
||||
DataChannelConnection::ConnectToTransport(
|
||||
const std::string& aTransportId,
|
||||
bool aClient,
|
||||
uint16_t localport, uint16_t remoteport)
|
||||
{
|
||||
LOG(("Connect DTLS local %u, remote %u", localport, remoteport));
|
||||
|
||||
MOZ_ASSERT(mMasterSocket, "SCTP wasn't initialized before ConnectViaTransportFlow!");
|
||||
if (NS_WARN_IF(!aFlow)) {
|
||||
MOZ_ASSERT(mMasterSocket, "SCTP wasn't initialized before ConnectToTransport!");
|
||||
if (NS_WARN_IF(aTransportId.empty())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mTransportFlow = aFlow;
|
||||
mLocalPort = localport;
|
||||
mRemotePort = remoteport;
|
||||
mState = CONNECTING;
|
||||
|
||||
RUN_ON_THREAD(mSTS, WrapRunnable(RefPtr<DataChannelConnection>(this),
|
||||
&DataChannelConnection::SetSignals),
|
||||
&DataChannelConnection::SetSignals,
|
||||
aTransportId,
|
||||
aClient),
|
||||
NS_DISPATCH_NORMAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DataChannelConnection::SetSignals()
|
||||
DataChannelConnection::SetSignals(const std::string& aTransportId,
|
||||
bool aClient)
|
||||
{
|
||||
ASSERT_WEBRTC(IsSTSThread());
|
||||
mDtls = static_cast<TransportLayerDtls*>(mTransportFlow->GetLayer("dtls"));
|
||||
ASSERT_WEBRTC(mDtls);
|
||||
LOG(("Setting transport signals, state: %d", mDtls->state()));
|
||||
mDtls->SignalPacketReceived.connect(this, &DataChannelConnection::SctpDtlsInput);
|
||||
mTransportId = aTransportId;
|
||||
mAllocateEven = aClient;
|
||||
mTransportHandler->SignalPacketReceived.connect(
|
||||
this, &DataChannelConnection::SctpDtlsInput);
|
||||
// SignalStateChange() doesn't call you with the initial state
|
||||
mDtls->SignalStateChange.connect(this, &DataChannelConnection::CompleteConnect);
|
||||
CompleteConnect(mDtls, mDtls->state());
|
||||
if (mTransportHandler->GetState(mTransportId, false)
|
||||
== TransportLayer::TS_OPEN) {
|
||||
LOG(("Setting transport signals, dtls already open"));
|
||||
CompleteConnect();
|
||||
} else {
|
||||
LOG(("Setting transport signals, dtls not open yet"));
|
||||
mTransportHandler->SignalStateChange.connect(
|
||||
this, &DataChannelConnection::TransportStateChange);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DataChannelConnection::CompleteConnect(TransportLayer *layer, TransportLayer::State state)
|
||||
DataChannelConnection::TransportStateChange(const std::string& aTransportId,
|
||||
TransportLayer::State aState)
|
||||
{
|
||||
LOG(("Data transport state: %d", state));
|
||||
if (aState == TransportLayer::TS_OPEN) {
|
||||
CompleteConnect();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DataChannelConnection::CompleteConnect()
|
||||
{
|
||||
LOG(("dtls open"));
|
||||
MutexAutoLock lock(mLock);
|
||||
ASSERT_WEBRTC(IsSTSThread());
|
||||
// We should abort connection on TS_ERROR.
|
||||
// Note however that the association will also fail (perhaps with a delay) and
|
||||
// notify us in that way
|
||||
if (state != TransportLayer::TS_OPEN || !mMasterSocket)
|
||||
if (!mMasterSocket) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_conn addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
@ -795,8 +805,7 @@ DataChannelConnection::CompleteConnect(TransportLayer *layer, TransportLayer::St
|
||||
LOG(("usrsctp_connect failed: %d", errno));
|
||||
mState = CLOSED;
|
||||
} else {
|
||||
// We set Even/Odd and fire ON_CONNECTION via SCTP_COMM_UP when we get that
|
||||
// This also avoids issues with calling TransportFlow stuff on Mainthread
|
||||
// We fire ON_CONNECTION via SCTP_COMM_UP when we get that
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -838,8 +847,13 @@ DataChannelConnection::ProcessQueuedOpens()
|
||||
}
|
||||
|
||||
void
|
||||
DataChannelConnection::SctpDtlsInput(TransportLayer *layer, MediaPacket& packet)
|
||||
DataChannelConnection::SctpDtlsInput(const std::string& aTransportId,
|
||||
MediaPacket& packet)
|
||||
{
|
||||
if ((packet.type() != MediaPacket::SCTP) || (mTransportId != aTransportId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (MOZ_LOG_TEST(gSCTPLog, LogLevel::Debug)) {
|
||||
char *buf;
|
||||
|
||||
@ -859,8 +873,9 @@ int
|
||||
DataChannelConnection::SendPacket(nsAutoPtr<MediaPacket> packet)
|
||||
{
|
||||
//LOG(("%p: SCTP/DTLS sent %ld bytes", this, len));
|
||||
if (mDtls) {
|
||||
return mDtls->SendPacket(*packet) < 0 ? 1 : 0;
|
||||
if (!mTransportId.empty()) {
|
||||
nsresult rv = mTransportHandler->SendPacket(mTransportId, *packet);
|
||||
return NS_FAILED(rv) ? 1 : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -888,6 +903,7 @@ DataChannelConnection::SctpDtlsOutput(void *addr, void *buffer, size_t length,
|
||||
// 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.
|
||||
nsAutoPtr<MediaPacket> packet(new MediaPacket);
|
||||
packet->SetType(MediaPacket::SCTP);
|
||||
packet->Copy(static_cast<const uint8_t*>(buffer), length);
|
||||
|
||||
// XXX It might be worthwhile to add an assertion against the thread
|
||||
@ -906,8 +922,6 @@ DataChannelConnection::SctpDtlsOutput(void *addr, void *buffer, size_t length,
|
||||
// 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
|
||||
|
||||
bool
|
||||
DataChannelConnection::Listen(unsigned short port)
|
||||
{
|
||||
@ -952,8 +966,6 @@ DataChannelConnection::Listen(unsigned short port)
|
||||
LOG(("Couldn't set SO_LINGER on SCTP socket"));
|
||||
}
|
||||
|
||||
SetEvenOdd();
|
||||
|
||||
// Notify Connection open
|
||||
// XXX We need to make sure connection sticks around until the message is delivered
|
||||
LOG(("%s: sending ON_CONNECTION for %p", __FUNCTION__, this));
|
||||
@ -1031,8 +1043,6 @@ DataChannelConnection::Connect(const char *addr, unsigned short port)
|
||||
LOG(("connect() succeeded! Entering connected mode"));
|
||||
mState = OPEN;
|
||||
|
||||
SetEvenOdd();
|
||||
|
||||
// Notify Connection open
|
||||
// XXX We need to make sure connection sticks around until the message is delivered
|
||||
LOG(("%s: sending ON_CONNECTION for %p", __FUNCTION__, this));
|
||||
@ -1810,8 +1820,6 @@ DataChannelConnection::HandleAssociationChangeEvent(const struct sctp_assoc_chan
|
||||
mPpidFragmentation = true;
|
||||
}
|
||||
|
||||
SetEvenOdd();
|
||||
|
||||
Dispatch(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CONNECTION,
|
||||
this)));
|
||||
|
@ -27,9 +27,7 @@
|
||||
#include "mozilla/net/NeckoTargetHolder.h"
|
||||
#ifdef SCTP_DTLS_SUPPORTED
|
||||
#include "mtransport/sigslot.h"
|
||||
#include "mtransport/transportflow.h"
|
||||
#include "mtransport/transportlayer.h"
|
||||
#include "mtransport/transportlayerdtls.h"
|
||||
#include "mtransport/transportlayer.h" // For TransportLayer::State
|
||||
#endif
|
||||
|
||||
#ifndef DATACHANNEL_LOG
|
||||
@ -50,6 +48,8 @@ namespace mozilla {
|
||||
class DataChannelConnection;
|
||||
class DataChannel;
|
||||
class DataChannelOnMessageAvailable;
|
||||
class MediaPacket;
|
||||
class MediaTransportHandler;
|
||||
|
||||
// For sending outgoing messages.
|
||||
// This class only holds a reference to the data and the info structure but does
|
||||
@ -145,7 +145,8 @@ public:
|
||||
};
|
||||
|
||||
DataChannelConnection(DataConnectionListener *listener,
|
||||
nsIEventTarget *aTarget);
|
||||
nsIEventTarget *aTarget,
|
||||
MediaTransportHandler* aTransportHandler);
|
||||
|
||||
bool Init(unsigned short aPort, uint16_t aNumStreams, bool aMaxMessageSizeSet,
|
||||
uint64_t aMaxMessageSize);
|
||||
@ -168,11 +169,11 @@ public:
|
||||
#endif
|
||||
|
||||
#ifdef SCTP_DTLS_SUPPORTED
|
||||
// Connect using a TransportFlow (DTLS) channel
|
||||
void SetEvenOdd();
|
||||
bool ConnectViaTransportFlow(TransportFlow *aFlow, uint16_t localport, uint16_t remoteport);
|
||||
void CompleteConnect(TransportLayer *layer, TransportLayer::State state);
|
||||
void SetSignals();
|
||||
bool ConnectToTransport(const std::string& aTransportId, bool aClient, uint16_t localport, uint16_t remoteport);
|
||||
void TransportStateChange(const std::string& aTransportId,
|
||||
TransportLayer::State aState);
|
||||
void CompleteConnect();
|
||||
void SetSignals(const std::string& aTransportId, bool aClient);
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
@ -247,7 +248,7 @@ private:
|
||||
#ifdef SCTP_DTLS_SUPPORTED
|
||||
static void DTLSConnectThread(void *data);
|
||||
int SendPacket(nsAutoPtr<MediaPacket> packet);
|
||||
void SctpDtlsInput(TransportLayer *layer, MediaPacket& packet);
|
||||
void SctpDtlsInput(const std::string& aTransportId, 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);
|
||||
@ -310,9 +311,6 @@ private:
|
||||
}
|
||||
#endif
|
||||
|
||||
// Exists solely for proxying release of the TransportFlow to the STS thread
|
||||
static void ReleaseTransportFlow(const RefPtr<TransportFlow>& aFlow) {}
|
||||
|
||||
bool mSendInterleaved;
|
||||
bool mPpidFragmentation;
|
||||
bool mMaxMessageSizeSet;
|
||||
@ -338,8 +336,8 @@ private:
|
||||
uint16_t mState; // Protected with mLock
|
||||
|
||||
#ifdef SCTP_DTLS_SUPPORTED
|
||||
RefPtr<TransportFlow> mTransportFlow;
|
||||
TransportLayerDtls* mDtls;
|
||||
std::string mTransportId;
|
||||
RefPtr<MediaTransportHandler> mTransportHandler;
|
||||
nsCOMPtr<nsIEventTarget> mSTS;
|
||||
#endif
|
||||
uint16_t mLocalPort; // Accessed from connect thread
|
||||
|
@ -20,6 +20,7 @@ FINAL_LIBRARY = 'xul'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/media/mtransport',
|
||||
'/media/webrtc',
|
||||
'/netwerk/sctp/src',
|
||||
]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user