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);
}
Example #5
0
// 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;
}
Example #16
0
static void CheckSTSThread()
{
  DebugOnly<nsCOMPtr<nsIEventTarget>> sts_thread = GetSTSThread();

  ASSERT_ON_THREAD(sts_thread.value);
}