void PeerConnectionMedia::PerformOrEnqueueIceCtxOperation(nsIRunnable* runnable) { ASSERT_ON_THREAD(mMainThread); if (IsIceCtxReady()) { GetSTSThread()->Dispatch(runnable, NS_DISPATCH_NORMAL); } else { mQueuedIceCtxOperations.push_back(runnable); } }
void PeerConnectionMedia::FlushIceCtxOperationQueueIfReady() { ASSERT_ON_THREAD(mMainThread); if (IsIceCtxReady()) { for (auto& mQueuedIceCtxOperation : mQueuedIceCtxOperations) { GetSTSThread()->Dispatch(mQueuedIceCtxOperation, NS_DISPATCH_NORMAL); } mQueuedIceCtxOperations.clear(); } }
void PeerConnectionMedia::AddIceCandidate(const std::string& candidate, const std::string& mid, uint32_t aMLine) { RUN_ON_THREAD(GetSTSThread(), WrapRunnable( RefPtr<PeerConnectionMedia>(this), &PeerConnectionMedia::AddIceCandidate_s, std::string(candidate), // Make copies. std::string(mid), aMLine), NS_DISPATCH_NORMAL); }
void PeerConnectionMedia::AddTransportFlow(int aIndex, bool aRtcp, const RefPtr<TransportFlow> &aFlow) { int index_inner = GetTransportFlowIndex(aIndex, aRtcp); MOZ_ASSERT(!mTransportFlows[index_inner]); mTransportFlows[index_inner] = aFlow; GetSTSThread()->Dispatch( WrapRunnable(this, &PeerConnectionMedia::ConnectDtlsListener_s, aFlow), NS_DISPATCH_NORMAL); }
// Proxy the Connect() request to the STS thread, since it may block and // should be done there. bool UDPSocketParent::RecvConnect(const UDPAddressInfo& aAddressInfo) { nsCOMPtr<nsIEventTarget> thread(NS_GetCurrentThread()); NS_WARN_IF(NS_FAILED(GetSTSThread()->Dispatch(WrapRunnable( this, &UDPSocketParent::DoConnect, mSocket, thread, aAddressInfo), NS_DISPATCH_NORMAL))); return true; }
// Proxy the Connect() request to the STS thread, since it may block and // should be done there. mozilla::ipc::IPCResult UDPSocketParent::RecvConnect(const UDPAddressInfo& aAddressInfo) { nsCOMPtr<nsIEventTarget> thread(NS_GetCurrentThread()); Unused << NS_WARN_IF(NS_FAILED(GetSTSThread()->Dispatch(WrapRunnable( RefPtr<UDPSocketParent>(this), &UDPSocketParent::DoConnect, mSocket, thread, aAddressInfo), NS_DISPATCH_NORMAL))); return IPC_OK(); }
void PeerConnectionMedia::RollbackIceRestart() { ASSERT_ON_THREAD(mMainThread); if (mIceRestartState != ICE_RESTART_PROVISIONAL) { return; } RUN_ON_THREAD(GetSTSThread(), WrapRunnable( RefPtr<PeerConnectionMedia>(this), &PeerConnectionMedia::RollbackIceRestart_s), NS_DISPATCH_NORMAL); mIceRestartState = ICE_RESTART_NONE; }
void PeerConnectionMedia::FinalizeIceRestart() { ASSERT_ON_THREAD(mMainThread); if (!IsIceRestarting()) { return; } RUN_ON_THREAD(GetSTSThread(), WrapRunnable( RefPtr<PeerConnectionMedia>(this), &PeerConnectionMedia::FinalizeIceRestart_s), NS_DISPATCH_NORMAL); mIceRestartState = ICE_RESTART_NONE; }
void PeerConnectionMedia::EnsureTransports(const JsepSession& aSession) { auto transports = aSession.GetTransports(); for (size_t i = 0; i < transports.size(); ++i) { RefPtr<JsepTransport> transport = transports[i]; RUN_ON_THREAD( GetSTSThread(), WrapRunnable(RefPtr<PeerConnectionMedia>(this), &PeerConnectionMedia::EnsureTransport_s, i, transport->mComponents), NS_DISPATCH_NORMAL); } GatherIfReady(); }
void PeerConnectionMedia::BeginIceRestart(const std::string& ufrag, const std::string& pwd) { ASSERT_ON_THREAD(mMainThread); if (IsIceRestarting()) { return; } RefPtr<NrIceCtx> new_ctx = mIceCtxHdlr->CreateCtx(ufrag, pwd); RUN_ON_THREAD(GetSTSThread(), WrapRunnable( RefPtr<PeerConnectionMedia>(this), &PeerConnectionMedia::BeginIceRestart_s, new_ctx), NS_DISPATCH_NORMAL); mIceRestartState = ICE_RESTART_PROVISIONAL; }
void PeerConnectionMedia::EnsureTransports(const JsepSession& aSession) { for (const auto& transceiver : aSession.GetTransceivers()) { if (!transceiver->HasLevel()) { continue; } RefPtr<JsepTransport> transport = transceiver->mTransport; RUN_ON_THREAD( GetSTSThread(), WrapRunnable(RefPtr<PeerConnectionMedia>(this), &PeerConnectionMedia::EnsureTransport_s, transceiver->GetLevel(), transport->mComponents), NS_DISPATCH_NORMAL); } GatherIfReady(); }
void PeerConnectionMedia::UpdateTransports(const JsepSession& session, bool restartGathering) { auto transports = session.GetTransports(); for (size_t i = 0; i < transports.size(); ++i) { RefPtr<JsepTransport> transport = transports[i]; std::string ufrag; std::string pwd; std::vector<std::string> candidates; bool hasAttrs = false; if (transport->mIce) { CSFLogDebug(logTag, "Transport %u is active", static_cast<unsigned>(i)); hasAttrs = true; ufrag = transport->mIce->GetUfrag(); pwd = transport->mIce->GetPassword(); candidates = transport->mIce->GetCandidates(); } // Update the transport. RUN_ON_THREAD(GetSTSThread(), WrapRunnable(RefPtr<PeerConnectionMedia>(this), &PeerConnectionMedia::UpdateIceMediaStream_s, i, transport->mComponents, hasAttrs, ufrag, pwd, candidates), NS_DISPATCH_NORMAL); } if (restartGathering) { GatherIfReady(); } }
bool PeerConnectionMedia::UpdateFilterFromRemoteDescription_m( int level, nsAutoPtr<mozilla::MediaPipelineFilter> filter) { ASSERT_ON_THREAD(mMainThread); RefPtr<mozilla::MediaPipeline> receive; for (size_t i = 0; !receive && i < mRemoteSourceStreams.Length(); ++i) { receive = mRemoteSourceStreams[i]->GetPipelineByLevel_m(level); } RefPtr<mozilla::MediaPipeline> transmit; for (size_t i = 0; !transmit && i < mLocalSourceStreams.Length(); ++i) { transmit = mLocalSourceStreams[i]->GetPipelineByLevel_m(level); } if (receive && transmit) { // GetPipelineByLevel_m will return nullptr if shutdown is in progress; // since shutdown is initiated in main, and involves a dispatch to STS // before the pipelines are released, our dispatch to STS will complete // before any release can happen due to a shutdown that hasn't started yet. RUN_ON_THREAD(GetSTSThread(), WrapRunnableNM( &UpdateFilterFromRemoteDescription_s, receive, transmit, filter ), NS_DISPATCH_NORMAL); return true; } else { CSFLogWarn(logTag, "Could not locate level %d to update filter", static_cast<int>(level)); } return false; }
void PeerConnectionMedia::RemoveTransportFlow(int aIndex, bool aRtcp) { int index_inner = GetTransportFlowIndex(aIndex, aRtcp); NS_ProxyRelease(GetSTSThread(), mTransportFlows[index_inner].forget()); }
nsresult PeerConnectionMedia::UpdateTransportFlow( size_t aLevel, bool aIsRtcp, const JsepTransport& aTransport) { if (aIsRtcp && aTransport.mComponents < 2) { RemoveTransportFlow(aLevel, aIsRtcp); return NS_OK; } if (!aIsRtcp && !aTransport.mComponents) { RemoveTransportFlow(aLevel, aIsRtcp); return NS_OK; } nsresult rv; RefPtr<TransportFlow> flow = GetTransportFlow(aLevel, aIsRtcp); if (flow) { if (IsIceRestarting()) { CSFLogInfo(LOGTAG, "Flow[%s]: detected ICE restart - level: %u rtcp: %d", flow->id().c_str(), (unsigned)aLevel, aIsRtcp); RefPtr<PeerConnectionMedia> pcMedia(this); rv = GetSTSThread()->Dispatch( WrapRunnableNM(AddNewIceStreamForRestart_s, pcMedia, flow, aLevel, aIsRtcp), NS_DISPATCH_NORMAL); if (NS_FAILED(rv)) { CSFLogError(LOGTAG, "Failed to dispatch AddNewIceStreamForRestart_s"); return rv; } } return NS_OK; } std::ostringstream osId; osId << mParentHandle << ":" << aLevel << "," << (aIsRtcp ? "rtcp" : "rtp"); flow = new TransportFlow(osId.str()); // The media streams are made on STS so we need to defer setup. auto ice = MakeUnique<TransportLayerIce>(); auto dtls = MakeUnique<TransportLayerDtls>(); dtls->SetRole(aTransport.mDtls->GetRole() == JsepDtlsTransport::kJsepDtlsClient ? TransportLayerDtls::CLIENT : TransportLayerDtls::SERVER); RefPtr<DtlsIdentity> pcid = mParent->Identity(); if (!pcid) { CSFLogError(LOGTAG, "Failed to get DTLS identity."); return NS_ERROR_FAILURE; } dtls->SetIdentity(pcid); const SdpFingerprintAttributeList& fingerprints = aTransport.mDtls->GetFingerprints(); for (const auto& fingerprint : fingerprints.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 rv; } } std::vector<uint16_t> srtpCiphers; srtpCiphers.push_back(SRTP_AES128_CM_HMAC_SHA1_80); srtpCiphers.push_back(SRTP_AES128_CM_HMAC_SHA1_32); rv = dtls->SetSrtpCiphers(srtpCiphers); if (NS_FAILED(rv)) { CSFLogError(LOGTAG, "Couldn't set SRTP ciphers"); return rv; } // 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 (!mParent->PrivacyRequested()) { alpnDefault = "webrtc"; alpn.insert(alpnDefault); } rv = dtls->SetAlpn(alpn, alpnDefault); if (NS_FAILED(rv)) { CSFLogError(LOGTAG, "Couldn't set ALPN"); return rv; } nsAutoPtr<PtrVector<TransportLayer> > layers(new PtrVector<TransportLayer>); layers->values.push_back(ice.release()); layers->values.push_back(dtls.release()); RefPtr<PeerConnectionMedia> pcMedia(this); rv = GetSTSThread()->Dispatch( WrapRunnableNM(FinalizeTransportFlow_s, pcMedia, flow, aLevel, aIsRtcp, layers), NS_DISPATCH_NORMAL); if (NS_FAILED(rv)) { CSFLogError(LOGTAG, "Failed to dispatch FinalizeTransportFlow_s"); return rv; } AddTransportFlow(aLevel, aIsRtcp, flow); return NS_OK; }
static void CheckSTSThread() { DebugOnly<nsCOMPtr<nsIEventTarget>> sts_thread = GetSTSThread(); ASSERT_ON_THREAD(sts_thread.value); }