int32_t WebrtcGmpVideoDecoder::InitDecode(const webrtc::VideoCodec* aCodecSettings, int32_t aNumberOfCores) { if (!mMPS) { mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1"); } MOZ_ASSERT(mMPS); if (!mGMPThread) { if (NS_WARN_IF(NS_FAILED(mMPS->GetThread(getter_AddRefs(mGMPThread))))) { return WEBRTC_VIDEO_CODEC_ERROR; } } RefPtr<GmpInitDoneRunnable> initDone(new GmpInitDoneRunnable(mPCHandle)); mGMPThread->Dispatch(WrapRunnableNM(&WebrtcGmpVideoDecoder::InitDecode_g, RefPtr<WebrtcGmpVideoDecoder>(this), aCodecSettings, aNumberOfCores, initDone), NS_DISPATCH_NORMAL); return WEBRTC_VIDEO_CODEC_OK; }
void GMPParent::ActorDestroy(ActorDestroyReason aWhy) { LOGD(("%s::%s: %p (%d)", __CLASS__, __FUNCTION__, this, (int) aWhy)); #ifdef MOZ_CRASHREPORTER if (AbnormalShutdown == aWhy) { nsString dumpID; GetCrashID(dumpID); nsString id; // use the parent address to identify it // We could use any unique-to-the-parent value id.AppendInt(reinterpret_cast<uint64_t>(this)); id.Append(NS_LITERAL_STRING(" ")); AppendUTF8toUTF16(mDisplayName, id); id.Append(NS_LITERAL_STRING(" ")); id.Append(dumpID); // NotifyObservers is mainthread-only NS_DispatchToMainThread(WrapRunnableNM(&GMPNotifyObservers, id), NS_DISPATCH_NORMAL); } #endif // warn us off trying to close again mState = GMPStateClosing; mAbnormalShutdownInProgress = true; CloseActive(false); // Normal Shutdown() will delete the process on unwind. if (AbnormalShutdown == aWhy) { mState = GMPStateClosing; nsRefPtr<GMPParent> self(this); // Note: final destruction will be Dispatched to ourself mService->ReAddOnGMPThread(self); } }
void GMPParent::ActorDestroy(ActorDestroyReason aWhy) { #ifdef MOZ_CRASHREPORTER if (AbnormalShutdown == aWhy) { nsString dumpID; GetCrashID(dumpID); nsString id; // use the parent address to identify it // We could use any unique-to-the-parent value id.AppendInt(reinterpret_cast<uint64_t>(this)); id.Append(NS_LITERAL_STRING(" ")); AppendUTF8toUTF16(mDisplayName, id); id.Append(NS_LITERAL_STRING(" ")); id.Append(dumpID); // NotifyObservers is mainthread-only NS_DispatchToMainThread(WrapRunnableNM(&GMPNotifyObservers, id), NS_DISPATCH_NORMAL); } #endif // warn us off trying to close again mState = GMPStateClosing; CloseActive(); // Normal Shutdown() will delete the process on unwind. if (AbnormalShutdown == aWhy) { NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, &GMPParent::DeleteProcess)); } }
void WebrtcGlobalInformation::GetAllStats( const GlobalObject& aGlobal, WebrtcGlobalStatisticsCallback& aStatsCallback, const Optional<nsAString>& pcIdFilter, ErrorResult& aRv) { if (!NS_IsMainThread()) { aRv.Throw(NS_ERROR_NOT_SAME_THREAD); return; } nsresult rv; nsCOMPtr<nsIEventTarget> stsThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); if (NS_FAILED(rv)) { aRv.Throw(rv); return; } if (!stsThread) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } nsAutoPtr<RTCStatsQueries> queries(new RTCStatsQueries); // If there is no PeerConnectionCtx, go through the same motions, since // the API consumer doesn't care why there are no PeerConnectionImpl. PeerConnectionCtx *ctx = GetPeerConnectionCtx(); if (ctx) { for (auto p = ctx->mPeerConnections.begin(); p != ctx->mPeerConnections.end(); ++p) { MOZ_ASSERT(p->second); if (!pcIdFilter.WasPassed() || pcIdFilter.Value().EqualsASCII(p->second->GetIdAsAscii().c_str())) { if (p->second->HasMedia()) { queries->append(nsAutoPtr<RTCStatsQuery>(new RTCStatsQuery(true))); p->second->BuildStatsQuery_m(nullptr, // all tracks queries->back()); } } } } // CallbackObject does not support threadsafe refcounting, and must be // destroyed on main. nsMainThreadPtrHandle<WebrtcGlobalStatisticsCallback> callbackHandle( new nsMainThreadPtrHolder<WebrtcGlobalStatisticsCallback>(&aStatsCallback)); rv = RUN_ON_THREAD(stsThread, WrapRunnableNM(&GetAllStats_s, callbackHandle, queries), NS_DISPATCH_NORMAL); aRv = rv; }
static void thread_ended_dispatcher(thread_ended_funct func, thread_monitor_id_t id) { nsresult rv = PeerConnectionCtx::gMainThread->Dispatch(WrapRunnableNM(func, id), NS_DISPATCH_NORMAL); if (NS_FAILED(rv)) { CSFLogError( logTag, "%s(): Could not dispatch to main thread", __FUNCTION__); } }
int32_t WebrtcGmpVideoEncoder::InitEncode(const webrtc::VideoCodec* aCodecSettings, int32_t aNumberOfCores, uint32_t aMaxPayloadSize) { if (!mMPS) { mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1"); } MOZ_ASSERT(mMPS); if (!mGMPThread) { if (NS_WARN_IF(NS_FAILED(mMPS->GetThread(getter_AddRefs(mGMPThread))))) { return WEBRTC_VIDEO_CODEC_ERROR; } } // Bug XXXXXX: transfer settings from codecSettings to codec. GMPVideoCodec codecParams; memset(&codecParams, 0, sizeof(codecParams)); codecParams.mGMPApiVersion = 33; codecParams.mStartBitrate = aCodecSettings->startBitrate; codecParams.mMinBitrate = aCodecSettings->minBitrate; codecParams.mMaxBitrate = aCodecSettings->maxBitrate; codecParams.mMaxFramerate = aCodecSettings->maxFramerate; mMaxPayloadSize = aMaxPayloadSize; memset(&mCodecSpecificInfo, 0, sizeof(webrtc::CodecSpecificInfo)); mCodecSpecificInfo.codecType = webrtc::kVideoCodecH264; mCodecSpecificInfo.codecSpecific.H264.packetizationMode = aCodecSettings->codecSpecific.H264.packetizationMode; if (mCodecSpecificInfo.codecSpecific.H264.packetizationMode == 1) { mMaxPayloadSize = 0; // No limit. } if (aCodecSettings->mode == webrtc::kScreensharing) { codecParams.mMode = kGMPScreensharing; } else { codecParams.mMode = kGMPRealtimeVideo; } codecParams.mWidth = aCodecSettings->width; codecParams.mHeight = aCodecSettings->height; RefPtr<GmpInitDoneRunnable> initDone(new GmpInitDoneRunnable(mPCHandle)); mGMPThread->Dispatch(WrapRunnableNM(WebrtcGmpVideoEncoder::InitEncode_g, RefPtr<WebrtcGmpVideoEncoder>(this), codecParams, aNumberOfCores, aMaxPayloadSize, initDone), NS_DISPATCH_NORMAL); // Since init of the GMP encoder is a multi-step async dispatch (including // dispatches to main), and since this function is invoked on main, there's // no safe way to block until this init is done. If an error occurs, we'll // handle it later. return WEBRTC_VIDEO_CODEC_OK; }
static void PipelineDetachTransport_s(RefPtr<MediaPipeline> pipeline, nsCOMPtr<nsIThread> mainThread) { pipeline->DetachTransport_s(); mainThread->Dispatch( // Make sure we let go of our reference before dispatching // If the dispatch fails, well, we're hosed anyway. WrapRunnableNM(PipelineReleaseRef_m, pipeline.forget()), NS_DISPATCH_NORMAL); }
int32_t WebrtcGmpVideoDecoder::ReleaseGmp() { LOGD(("GMP Released:")); if (mGMPThread) { mGMPThread->Dispatch( WrapRunnableNM(&WebrtcGmpVideoDecoder::ReleaseGmp_g, RefPtr<WebrtcGmpVideoDecoder>(this)), NS_DISPATCH_NORMAL); } return WEBRTC_VIDEO_CODEC_OK; }
void PeerConnectionMedia::DtlsConnected_s(TransportLayer *layer, TransportLayer::State state) { MOZ_ASSERT(layer->id() == "dtls"); TransportLayerDtls* dtlsLayer = static_cast<TransportLayerDtls*>(layer); dtlsLayer->SignalStateChange.disconnect(this); bool privacyRequested = (dtlsLayer->GetNegotiatedAlpn() == "c-webrtc"); GetMainThread()->Dispatch( WrapRunnableNM(&PeerConnectionMedia::DtlsConnected_m, mParentHandle, privacyRequested), NS_DISPATCH_NORMAL); }
void PeerConnectionMedia::DtlsConnected_s(TransportLayer *dtlsLayer, TransportLayer::State state) { dtlsLayer->SignalStateChange.disconnect(this); bool privacyRequested = false; // TODO (Bug 952678) set privacy mode, ask the DTLS layer about that // This has to be a dispatch to a static method, we could be going away GetMainThread()->Dispatch( WrapRunnableNM(&PeerConnectionMedia::DtlsConnected_m, mParentHandle, privacyRequested), NS_DISPATCH_NORMAL); }
void SourceStreamInfo::RemoveTrack(const std::string& trackId) { mTracks.erase(trackId); RefPtr<MediaPipeline> pipeline = GetPipelineByTrackId_m(trackId); if (pipeline) { mPipelines.erase(trackId); pipeline->ShutdownMedia_m(); mParent->GetSTSThread()->Dispatch( WrapRunnableNM(PipelineDetachTransport_s, pipeline.forget(), mParent->GetMainThread()), NS_DISPATCH_NORMAL); } }
int32_t WebrtcGmpVideoEncoder::SetRates(uint32_t aNewBitRate, uint32_t aFrameRate) { MOZ_ASSERT(mGMPThread); if (aFrameRate == 0) { aFrameRate = 30; // Assume 30fps if we don't know the rate } mGMPThread->Dispatch(WrapRunnableNM(&WebrtcGmpVideoEncoder::SetRates_g, RefPtr<WebrtcGmpVideoEncoder>(this), aNewBitRate, aFrameRate), NS_DISPATCH_NORMAL); return WEBRTC_VIDEO_CODEC_OK; }
static void GetAllStats_s( nsMainThreadPtrHandle<WebrtcGlobalStatisticsCallback> aStatsCallback, nsAutoPtr<RTCStatsQueries> aQueryList) { MOZ_ASSERT(aQueryList); for (auto q = aQueryList->begin(); q != aQueryList->end(); ++q) { MOZ_ASSERT(*q); PeerConnectionImpl::ExecuteStatsQuery_s(*q); } NS_DispatchToMainThread(WrapRunnableNM(&OnStatsReport_m, aStatsCallback, aQueryList), NS_DISPATCH_NORMAL); }
static void GetLogging_s( nsMainThreadPtrHandle<WebrtcGlobalLoggingCallback> aLoggingCallback, const std::string& aPattern) { RLogRingBuffer* logs = RLogRingBuffer::GetInstance(); nsAutoPtr<std::deque<std::string>> result(new std::deque<std::string>); // Might not exist yet. if (logs) { logs->Filter(aPattern, 0, result); } NS_DispatchToMainThread(WrapRunnableNM(&OnGetLogging_m, aLoggingCallback, aPattern, result), NS_DISPATCH_NORMAL); }
void WebrtcGlobalInformation::GetLogging( const GlobalObject& aGlobal, const nsAString& aPattern, WebrtcGlobalLoggingCallback& aLoggingCallback, ErrorResult& aRv) { if (!NS_IsMainThread()) { aRv.Throw(NS_ERROR_NOT_SAME_THREAD); return; } nsresult rv; nsCOMPtr<nsIEventTarget> stsThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); if (NS_FAILED(rv)) { aRv.Throw(rv); return; } if (!stsThread) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } std::string pattern(NS_ConvertUTF16toUTF8(aPattern).get()); // CallbackObject does not support threadsafe refcounting, and must be // destroyed on main. nsMainThreadPtrHandle<WebrtcGlobalLoggingCallback> callbackHandle( new nsMainThreadPtrHolder<WebrtcGlobalLoggingCallback>(&aLoggingCallback)); rv = RUN_ON_THREAD(stsThread, WrapRunnableNM(&GetLogging_s, callbackHandle, pattern), NS_DISPATCH_NORMAL); if (NS_FAILED(rv)) { aLoggingCallback.Release(); } aRv = rv; }
bool GMPVideoEncoderParent::RecvEncoded(const GMPVideoEncodedFrameData& aEncodedFrame, InfallibleTArray<uint8_t>&& aCodecSpecificInfo) { if (!mCallback) { return false; } auto f = new GMPVideoEncodedFrameImpl(aEncodedFrame, &mVideoHost); nsTArray<uint8_t> *codecSpecificInfo = new nsTArray<uint8_t>; codecSpecificInfo->AppendElements((uint8_t*)aCodecSpecificInfo.Elements(), aCodecSpecificInfo.Length()); nsCOMPtr<nsIThread> thread = NS_GetCurrentThread(); mEncodedThread->Dispatch(WrapRunnableNM(&EncodedCallback, mCallback, f, codecSpecificInfo, thread), NS_DISPATCH_NORMAL); return true; }
void PeerConnectionCtx::onCallEvent(ccapi_call_event_e aCallEvent, CSF::CC_CallPtr aCall, CSF::CC_CallInfoPtr aInfo) { // This is called on a SIPCC thread. // // We cannot use SyncRunnable to main thread, as that would deadlock on // shutdown. Instead, we dispatch asynchronously. We copy getPeerConnection(), // a "weak ref" to the PC, which is safe in shutdown, and CC_CallInfoPtr (an // nsRefPtr) is thread-safe and keeps aInfo alive. nsAutoPtr<std::string> pcDuped(new std::string(aCall->getPeerConnection())); // DISPATCH_NORMAL with duped string nsresult rv = gMainThread->Dispatch(WrapRunnableNM(&onCallEvent_m, pcDuped, aCallEvent, aInfo), NS_DISPATCH_NORMAL); if (NS_FAILED(rv)) { CSFLogError( logTag, "%s(): Could not dispatch to main thread", __FUNCTION__); } }
void GeckoMediaPluginServiceParent::ReAddOnGMPThread(const nsRefPtr<GMPParent>& aOld) { MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread); LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, (void*) aOld)); nsRefPtr<GMPParent> gmp; if (!mShuttingDownOnGMPThread) { // Don't re-add plugin if we're shutting down. Let the old plugin die. gmp = ClonePlugin(aOld); } // Note: both are now in the list // Until we give up the GMPThread, we're safe even if we unlock temporarily // since off-main-thread users just test for existance; they don't modify the list. MutexAutoLock lock(mMutex); mPlugins.RemoveElement(aOld); // Schedule aOld to be destroyed. We can't destroy it from here since we // may be inside ActorDestroyed() for it. NS_DispatchToCurrentThread(WrapRunnableNM(&Dummy, aOld)); }
void WebrtcGlobalInformation::StoreLongTermICEStatistics( sipcc::PeerConnectionImpl& aPc) { Telemetry::Accumulate(Telemetry::WEBRTC_ICE_FINAL_CONNECTION_STATE, static_cast<uint32_t>(aPc.IceConnectionState())); if (aPc.IceConnectionState() == PCImplIceConnectionState::New) { // ICE has not started; we won't have any remote candidates, so recording // statistics on gathered candidates is pointless. return; } nsAutoPtr<RTCStatsQuery> query(new RTCStatsQuery(true)); nsresult rv = aPc.BuildStatsQuery_m(nullptr, query.get()); NS_ENSURE_SUCCESS_VOID(rv); RUN_ON_THREAD(aPc.GetSTSThread(), WrapRunnableNM(&GetStatsForLongTermStorage_s, query), NS_DISPATCH_NORMAL); }
static void GetStatsForLongTermStorage_s( nsAutoPtr<RTCStatsQuery> query) { MOZ_ASSERT(query); nsresult rv = PeerConnectionImpl::ExecuteStatsQuery_s(query.get()); // Check whether packets were dropped due to rate limiting during // this call. (These calls must be made on STS) unsigned char rate_limit_bit_pattern = 0; if (!mozilla::nr_socket_short_term_violation_time().IsNull() && mozilla::nr_socket_short_term_violation_time() >= query->iceStartTime) { rate_limit_bit_pattern |= 1; } if (!mozilla::nr_socket_long_term_violation_time().IsNull() && mozilla::nr_socket_long_term_violation_time() >= query->iceStartTime) { rate_limit_bit_pattern |= 2; } if (query->failed) { Telemetry::Accumulate( Telemetry::WEBRTC_STUN_RATE_LIMIT_EXCEEDED_BY_TYPE_GIVEN_FAILURE, rate_limit_bit_pattern); } else { Telemetry::Accumulate( Telemetry::WEBRTC_STUN_RATE_LIMIT_EXCEEDED_BY_TYPE_GIVEN_SUCCESS, rate_limit_bit_pattern); } // Even if Telemetry::Accumulate is threadsafe, we still need to send the // query back to main, since that is where it must be destroyed. NS_DispatchToMainThread( WrapRunnableNM( &StoreLongTermICEStatisticsImpl_m, rv, query), NS_DISPATCH_NORMAL); }
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; }
nsresult MediaPipelineFactory::CreateOrGetTransportFlow( size_t aLevel, bool aIsRtcp, const JsepTransport& aTransport, RefPtr<TransportFlow>* aFlowOutparam) { nsresult rv; RefPtr<TransportFlow> flow; flow = mPCMedia->GetTransportFlow(aLevel, aIsRtcp); if (flow) { *aFlowOutparam = flow; return NS_OK; } std::ostringstream osId; osId << mPC->GetHandle() << ":" << 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>(mPC->GetHandle()); auto dtls = MakeUnique<TransportLayerDtls>(); dtls->SetRole(aTransport.mDtls->GetRole() == JsepDtlsTransport::kJsepDtlsClient ? TransportLayerDtls::CLIENT : TransportLayerDtls::SERVER); RefPtr<DtlsIdentity> pcid = mPC->Identity(); if (!pcid) { MOZ_MTLOG(ML_ERROR, "Failed to get DTLS identity."); return NS_ERROR_FAILURE; } dtls->SetIdentity(pcid); const SdpFingerprintAttributeList& fingerprints = aTransport.mDtls->GetFingerprints(); for (auto fp = fingerprints.mFingerprints.begin(); fp != fingerprints.mFingerprints.end(); ++fp) { std::ostringstream ss; ss << fp->hashFunc; rv = dtls->SetVerificationDigest(ss.str(), &fp->fingerprint[0], fp->fingerprint.size()); if (NS_FAILED(rv)) { MOZ_MTLOG(ML_ERROR, "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)) { MOZ_MTLOG(ML_ERROR, "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 (!mPC->PrivacyRequested()) { alpnDefault = "webrtc"; alpn.insert(alpnDefault); } rv = dtls->SetAlpn(alpn, alpnDefault); if (NS_FAILED(rv)) { MOZ_MTLOG(ML_ERROR, "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()); rv = mPCMedia->GetSTSThread()->Dispatch( WrapRunnableNM(FinalizeTransportFlow_s, mPCMedia, flow, aLevel, aIsRtcp, layers), NS_DISPATCH_NORMAL); if (NS_FAILED(rv)) { MOZ_MTLOG(ML_ERROR, "Failed to dispatch FinalizeTransportFlow_s"); return rv; } mPCMedia->AddTransportFlow(aLevel, aIsRtcp, flow); *aFlowOutparam = flow; return NS_OK; }
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; }