NS_IMETHODIMP
PresentationService::UntrackSessionInfo(const nsAString& aSessionId,
                                        uint8_t aRole)
{
  PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
             NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);

  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
             aRole == nsIPresentationService::ROLE_RECEIVER);
  // Remove the session info.
  if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
    mSessionInfoAtController.Remove(aSessionId);
  } else {
    // Terminate receiver page.
    uint64_t windowId;
    nsresult rv = GetWindowIdBySessionIdInternal(aSessionId, aRole, &windowId);
    if (NS_SUCCEEDED(rv)) {
      NS_DispatchToMainThread(NS_NewRunnableFunction([windowId]() -> void {
        PRES_DEBUG("Attempt to close window[%d]\n", windowId);

        if (auto* window = nsGlobalWindow::GetInnerWindowWithId(windowId)) {
          window->Close();
        }
      }));
    }

    mSessionInfoAtReceiver.Remove(aSessionId);
  }

  // Remove the in-process responding info if there's still any.
  RemoveRespondingSessionId(aSessionId, aRole);

  return NS_OK;
}
NS_IMETHODIMP
PresentationReceiver::NotifySessionConnect(uint64_t aWindowId,
                                           const nsAString& aSessionId)
{
  PRES_DEBUG("receiver session connect:id[%s], windowId[%x]\n",
             NS_ConvertUTF16toUTF8(aSessionId).get(), aWindowId);

  if (NS_WARN_IF(!mOwner)) {
    return NS_ERROR_FAILURE;
  }

  if (NS_WARN_IF(aWindowId != mWindowId)) {
    return NS_ERROR_INVALID_ARG;
  }

  if (NS_WARN_IF(!mConnectionList)) {
    return NS_ERROR_FAILURE;
  }

  RefPtr<PresentationConnection> connection =
    PresentationConnection::Create(mOwner, aSessionId, mUrl,
                                   nsIPresentationService::ROLE_RECEIVER,
                                   mConnectionList);
  if (NS_WARN_IF(!connection)) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  return NS_OK;
}
NS_IMETHODIMP
PresentationService::RegisterSessionListener(const nsAString& aSessionId,
                                             uint8_t aRole,
                                             nsIPresentationSessionListener* aListener)
{
  PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
             NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);

  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aListener);
  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
             aRole == nsIPresentationService::ROLE_RECEIVER);

  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
  if (NS_WARN_IF(!info)) {
    // Notify the listener of TERMINATED since no correspondent session info is
    // available possibly due to establishment failure. This would be useful at
    // the receiver side, since a presentation session is created at beginning
    // and here is the place to realize the underlying establishment fails.
    nsresult rv = aListener->NotifyStateChange(aSessionId,
                                               nsIPresentationSessionListener::STATE_TERMINATED,
                                               NS_ERROR_NOT_AVAILABLE);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }
    return NS_ERROR_NOT_AVAILABLE;
  }

  return info->SetListener(aListener);
}
NS_IMETHODIMP
PresentationService::ReconnectSession(const nsTArray<nsString>& aUrls,
                                      const nsAString& aSessionId,
                                      uint8_t aRole,
                                      nsIPresentationServiceCallback* aCallback)
{
  PRES_DEBUG("%s:id[%s]\n", __func__, NS_ConvertUTF16toUTF8(aSessionId).get());

  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(!aSessionId.IsEmpty());
  MOZ_ASSERT(aCallback);
  MOZ_ASSERT(!aUrls.IsEmpty());

  if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
    MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
    return NS_ERROR_INVALID_ARG;
  }

  if (NS_WARN_IF(!aCallback)) {
    return NS_ERROR_INVALID_ARG;
  }

  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
  if (NS_WARN_IF(!info)) {
    return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
  }

  if (NS_WARN_IF(!aUrls.Contains(info->GetUrl()))) {
    return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
  }

  return static_cast<PresentationControllingInfo*>(info.get())->Reconnect(aCallback);
}
NS_IMETHODIMP
PresentationService::CloseSession(const nsAString& aSessionId,
                                  uint8_t aRole,
                                  uint8_t aClosedReason)
{
  PRES_DEBUG("%s:id[%s], reason[%x], role[%d]\n", __func__,
             NS_ConvertUTF16toUTF8(aSessionId).get(), aClosedReason, aRole);

  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(!aSessionId.IsEmpty());
  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
             aRole == nsIPresentationService::ROLE_RECEIVER);

  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
  if (NS_WARN_IF(!info)) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  if (aClosedReason == nsIPresentationService::CLOSED_REASON_WENTAWAY) {
    // Remove nsIPresentationSessionListener since we don't want to dispatch
    // PresentationConnectionCloseEvent if the page is went away.
    info->SetListener(nullptr);
  }

  return info->Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED);
}
nsresult
PresentationService::HandleDeviceAdded(nsIPresentationDevice* aDevice)
{
  PRES_DEBUG("%s\n", __func__);
  if (!aDevice) {
    MOZ_ASSERT(false, "aDevice shoud no be null.");
    return NS_ERROR_INVALID_ARG;
  }

  // Query for only unavailable URLs while device added.
  nsTArray<nsString> unavailableUrls;
  mAvailabilityManager.GetAvailbilityUrlByAvailability(unavailableUrls, false);

  nsTArray<nsString> supportedAvailabilityUrl;
  for (const auto& url : unavailableUrls) {
     bool isSupported;
    if (NS_SUCCEEDED(aDevice->IsRequestedUrlSupported(url, &isSupported)) &&
        isSupported) {
      supportedAvailabilityUrl.AppendElement(url);
    }
  }

  if (!supportedAvailabilityUrl.IsEmpty()) {
    return mAvailabilityManager.DoNotifyAvailableChange(supportedAvailabilityUrl,
                                                        true);
  }

  return NS_OK;
}
NS_IMETHODIMP
PresentationService::RegisterRespondingListener(
  uint64_t aWindowId,
  nsIPresentationRespondingListener* aListener)
{
  PRES_DEBUG("%s:windowId[%lld]\n", __func__, aWindowId);

  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aListener);

  nsCOMPtr<nsIPresentationRespondingListener> listener;
  if (mRespondingListeners.Get(aWindowId, getter_AddRefs(listener))) {
    return (listener == aListener) ? NS_OK : NS_ERROR_DOM_INVALID_STATE_ERR;
  }

  nsTArray<nsString> sessionIdArray;
  nsresult rv = mReceiverSessionIdManager.GetSessionIds(aWindowId,
                                                        sessionIdArray);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  for (const auto& id : sessionIdArray) {
    aListener->NotifySessionConnect(aWindowId, id);
  }

  mRespondingListeners.Put(aWindowId, aListener);
  return NS_OK;
}
NS_IMETHODIMP
PresentationService::NotifyReceiverReady(
    const nsAString& aSessionId, uint64_t aWindowId, bool aIsLoading,
    nsIPresentationTransportBuilderConstructor* aBuilderConstructor) {
  PRES_DEBUG("%s:id[%s], windowId[%" PRIu64 "], loading[%d]\n", __func__,
             NS_ConvertUTF16toUTF8(aSessionId).get(), aWindowId, aIsLoading);

  RefPtr<PresentationSessionInfo> info =
      GetSessionInfo(aSessionId, nsIPresentationService::ROLE_RECEIVER);
  if (NS_WARN_IF(!info)) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  AddRespondingSessionId(aWindowId, aSessionId,
                         nsIPresentationService::ROLE_RECEIVER);

  if (!aIsLoading) {
    return static_cast<PresentationPresentingInfo*>(info.get())
        ->NotifyResponderFailure();
  }

  nsCOMPtr<nsIPresentationRespondingListener> listener;
  if (mRespondingListeners.Get(aWindowId, getter_AddRefs(listener))) {
    nsresult rv = listener->NotifySessionConnect(aWindowId, aSessionId);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }
  }

  info->SetTransportBuilderConstructor(aBuilderConstructor);
  return static_cast<PresentationPresentingInfo*>(info.get())
      ->NotifyResponderReady();
}
NS_IMETHODIMP
PresentationService::UnregisterRespondingListener(uint64_t aWindowId) {
  PRES_DEBUG("%s:windowId[%" PRIu64 "]\n", __func__, aWindowId);

  MOZ_ASSERT(NS_IsMainThread());

  mRespondingListeners.Remove(aWindowId);
  return NS_OK;
}
nsresult PresentationService::HandleDeviceRemoved() {
  PRES_DEBUG("%s\n", __func__);

  // Query for only available URLs while device removed.
  nsTArray<nsString> availabilityUrls;
  mAvailabilityManager.GetAvailbilityUrlByAvailability(availabilityUrls, true);

  return UpdateAvailabilityUrlChange(availabilityUrls);
}
示例#11
0
nsresult
PresentationService::HandleTerminateRequest(nsIPresentationTerminateRequest* aRequest)
{
  nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
  nsresult rv = aRequest->GetControlChannel(getter_AddRefs(ctrlChannel));
  if (NS_WARN_IF(NS_FAILED(rv) || !ctrlChannel)) {
    return rv;
  }

  nsAutoString sessionId;
  rv = aRequest->GetPresentationId(sessionId);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    ctrlChannel->Disconnect(rv);
    return rv;
  }

  nsCOMPtr<nsIPresentationDevice> device;
  rv = aRequest->GetDevice(getter_AddRefs(device));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    ctrlChannel->Disconnect(rv);
    return rv;
  }

  bool isFromReceiver;
  rv = aRequest->GetIsFromReceiver(&isFromReceiver);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    ctrlChannel->Disconnect(rv);
    return rv;
  }

  RefPtr<PresentationSessionInfo> info;
  if (!isFromReceiver) {
    info = GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER);
  } else {
    info = GetSessionInfo(sessionId, nsIPresentationService::ROLE_CONTROLLER);
  }
  if (NS_WARN_IF(!info)) {
    // Cannot terminate non-existed session.
    ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
    return NS_ERROR_DOM_ABORT_ERR;
  }

  // Check if terminate request comes from known device.
  RefPtr<nsIPresentationDevice> knownDevice = info->GetDevice();
  if (NS_WARN_IF(!IsSameDevice(device, knownDevice))) {
    ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
    return NS_ERROR_DOM_ABORT_ERR;
  }

  PRES_DEBUG("handle termination:id[%s], receiver[%d]\n", __func__,
             sessionId.get(), isFromReceiver);

  return info->OnTerminate(ctrlChannel);
}
NS_IMETHODIMP
PresentationService::TerminateSession(const nsAString& aSessionId,
                                      uint8_t aRole) {
  PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
             NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);

  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(!aSessionId.IsEmpty());
  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
             aRole == nsIPresentationService::ROLE_RECEIVER);

  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
  if (NS_WARN_IF(!info)) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  return info->Close(NS_OK, nsIPresentationSessionListener::STATE_TERMINATED);
}
nsresult PresentationService::NotifyTransportClosed(const nsAString& aSessionId,
                                                    uint8_t aRole,
                                                    nsresult aReason) {
  PRES_DEBUG("%s:id[%s], reason[%" PRIx32 "], role[%d]\n", __func__,
             NS_ConvertUTF16toUTF8(aSessionId).get(),
             static_cast<uint32_t>(aReason), aRole);

  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(!aSessionId.IsEmpty());
  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
             aRole == nsIPresentationService::ROLE_RECEIVER);

  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
  if (NS_WARN_IF(!info)) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  return info->NotifyTransportClosed(aReason);
}
示例#14
0
NS_IMETHODIMP
PresentationService::UnregisterSessionListener(const nsAString& aSessionId,
                                               uint8_t aRole)
{
  PRES_DEBUG("%s:id[%s], role[%d]\n", __func__,
             NS_ConvertUTF16toUTF8(aSessionId).get(), aRole);

  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
             aRole == nsIPresentationService::ROLE_RECEIVER);

  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
  if (info) {
    // When content side decide not handling this session anymore, simply
    // close the connection. Session info is kept for reconnection.
    Unused << NS_WARN_IF(NS_FAILED(info->Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED)));
    return info->SetListener(nullptr);
  }
  return NS_OK;
}
示例#15
0
NS_IMETHODIMP
PresentationService::StartSession(
               const nsTArray<nsString>& aUrls,
               const nsAString& aSessionId,
               const nsAString& aOrigin,
               const nsAString& aDeviceId,
               uint64_t aWindowId,
               nsIDOMEventTarget* aEventTarget,
               nsIPrincipal* aPrincipal,
               nsIPresentationServiceCallback* aCallback,
               nsIPresentationTransportBuilderConstructor* aBuilderConstructor)
{
  PRES_DEBUG("%s:id[%s]\n", __func__, NS_ConvertUTF16toUTF8(aSessionId).get());

  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aCallback);
  MOZ_ASSERT(!aSessionId.IsEmpty());
  MOZ_ASSERT(!aUrls.IsEmpty());

  nsCOMPtr<nsIPresentationDeviceRequest> request =
    new PresentationDeviceRequest(aUrls,
                                  aSessionId,
                                  aOrigin,
                                  aWindowId,
                                  aEventTarget,
                                  aPrincipal,
                                  aCallback,
                                  aBuilderConstructor);

  if (aDeviceId.IsVoid()) {
    // Pop up a prompt and ask user to select a device.
    nsCOMPtr<nsIPresentationDevicePrompt> prompt =
      do_GetService(PRESENTATION_DEVICE_PROMPT_CONTRACTID);
    if (NS_WARN_IF(!prompt)) {
      return aCallback->NotifyError(NS_ERROR_DOM_INVALID_ACCESS_ERR);
    }

    nsresult rv = prompt->PromptDeviceSelection(request);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
    }

    return NS_OK;
  }

  // Find the designated device from available device list.
  nsCOMPtr<nsIPresentationDeviceManager> deviceManager =
    do_GetService(PRESENTATION_DEVICE_MANAGER_CONTRACTID);
  if (NS_WARN_IF(!deviceManager)) {
    return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
  }

  nsCOMPtr<nsIArray> presentationUrls;
  if (NS_WARN_IF(NS_FAILED(
    ConvertURLArrayHelper(aUrls, getter_AddRefs(presentationUrls))))) {
    return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
  }

  nsCOMPtr<nsIArray> devices;
  nsresult rv = deviceManager->GetAvailableDevices(presentationUrls, getter_AddRefs(devices));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
  }

  nsCOMPtr<nsISimpleEnumerator> enumerator;
  rv = devices->Enumerate(getter_AddRefs(enumerator));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
  }

  NS_ConvertUTF16toUTF8 utf8DeviceId(aDeviceId);
  bool hasMore;
  while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
    nsCOMPtr<nsISupports> isupports;
    rv = enumerator->GetNext(getter_AddRefs(isupports));

    nsCOMPtr<nsIPresentationDevice> device(do_QueryInterface(isupports));
    MOZ_ASSERT(device);

    nsAutoCString id;
    if (NS_SUCCEEDED(device->GetId(id)) && id.Equals(utf8DeviceId)) {
      request->Select(device);
      return NS_OK;
    }
  }

  // Reject if designated device is not available.
  return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
}
示例#16
0
nsresult
PresentationService::HandleSessionRequest(nsIPresentationSessionRequest* aRequest)
{
  nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
  nsresult rv = aRequest->GetControlChannel(getter_AddRefs(ctrlChannel));
  if (NS_WARN_IF(NS_FAILED(rv) || !ctrlChannel)) {
    return rv;
  }

  nsAutoString url;
  rv = aRequest->GetUrl(url);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    ctrlChannel->Disconnect(rv);
    return rv;
  }

  nsAutoString sessionId;
  rv = aRequest->GetPresentationId(sessionId);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    ctrlChannel->Disconnect(rv);
    return rv;
  }

  nsCOMPtr<nsIPresentationDevice> device;
  rv = aRequest->GetDevice(getter_AddRefs(device));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    ctrlChannel->Disconnect(rv);
    return rv;
  }

  // Create or reuse session info.
  RefPtr<PresentationSessionInfo> info =
    GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER);

  // This is the case for reconnecting a session.
  // Update the control channel and device of the session info.
  // Call |NotifyResponderReady| to indicate the receiver page is already there.
  if (info) {
    PRES_DEBUG("handle reconnection:id[%s]\n",
               NS_ConvertUTF16toUTF8(sessionId).get());

    info->SetControlChannel(ctrlChannel);
    info->SetDevice(device);
    return static_cast<PresentationPresentingInfo*>(
      info.get())->DoReconnect();
  }

  // This is the case for a new session.
  PRES_DEBUG("handle new session:url[%d], id[%s]\n",
             NS_ConvertUTF16toUTF8(url).get(),
             NS_ConvertUTF16toUTF8(sessionId).get());

  info = new PresentationPresentingInfo(url, sessionId, device);
  rv = info->Init(ctrlChannel);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    ctrlChannel->Disconnect(rv);
    return rv;
  }

  mSessionInfoAtReceiver.Put(sessionId, info);

  // Notify the receiver to launch.
  nsCOMPtr<nsIPresentationRequestUIGlue> glue =
    do_CreateInstance(PRESENTATION_REQUEST_UI_GLUE_CONTRACTID);
  if (NS_WARN_IF(!glue)) {
    ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR);
    return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
  }
  nsCOMPtr<nsISupports> promise;
  rv = glue->SendRequest(url, sessionId, device, getter_AddRefs(promise));
  if (NS_WARN_IF(NS_FAILED(rv))) {
    ctrlChannel->Disconnect(rv);
    return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
  }
  nsCOMPtr<Promise> realPromise = do_QueryInterface(promise);
  static_cast<PresentationPresentingInfo*>(info.get())->SetPromise(realPromise);

  return NS_OK;
}