diff options
Diffstat (limited to 'dom/presentation/PresentationService.cpp')
-rw-r--r-- | dom/presentation/PresentationService.cpp | 1188 |
1 files changed, 0 insertions, 1188 deletions
diff --git a/dom/presentation/PresentationService.cpp b/dom/presentation/PresentationService.cpp deleted file mode 100644 index bc525cdb8..000000000 --- a/dom/presentation/PresentationService.cpp +++ /dev/null @@ -1,1188 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=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/. */ - -#include "PresentationService.h" - -#include "ipc/PresentationIPCService.h" -#include "mozilla/Services.h" -#include "nsGlobalWindow.h" -#include "nsIMutableArray.h" -#include "nsIObserverService.h" -#include "nsIPresentationControlChannel.h" -#include "nsIPresentationDeviceManager.h" -#include "nsIPresentationDevicePrompt.h" -#include "nsIPresentationListener.h" -#include "nsIPresentationRequestUIGlue.h" -#include "nsIPresentationSessionRequest.h" -#include "nsIPresentationTerminateRequest.h" -#include "nsISupportsPrimitives.h" -#include "nsNetUtil.h" -#include "nsServiceManagerUtils.h" -#include "nsThreadUtils.h" -#include "nsXPCOMCID.h" -#include "nsXULAppAPI.h" -#include "PresentationLog.h" - -namespace mozilla { -namespace dom { - -static bool -IsSameDevice(nsIPresentationDevice* aDevice, nsIPresentationDevice* aDeviceAnother) { - if (!aDevice || !aDeviceAnother) { - return false; - } - - nsAutoCString deviceId; - aDevice->GetId(deviceId); - nsAutoCString anotherId; - aDeviceAnother->GetId(anotherId); - if (!deviceId.Equals(anotherId)) { - return false; - } - - nsAutoCString deviceType; - aDevice->GetType(deviceType); - nsAutoCString anotherType; - aDeviceAnother->GetType(anotherType); - if (!deviceType.Equals(anotherType)) { - return false; - } - - return true; -} - -static nsresult -ConvertURLArrayHelper(const nsTArray<nsString>& aUrls, nsIArray** aResult) -{ - if (!aResult) { - return NS_ERROR_INVALID_POINTER; - } - - *aResult = nullptr; - - nsresult rv; - nsCOMPtr<nsIMutableArray> urls = - do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - for (const auto& url : aUrls) { - nsCOMPtr<nsISupportsString> isupportsString = - do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = isupportsString->SetData(url); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = urls->AppendElement(isupportsString, false); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - } - - urls.forget(aResult); - return NS_OK; -} - -/* - * Implementation of PresentationDeviceRequest - */ - -class PresentationDeviceRequest final : public nsIPresentationDeviceRequest -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIPRESENTATIONDEVICEREQUEST - - PresentationDeviceRequest( - const nsTArray<nsString>& aUrls, - const nsAString& aId, - const nsAString& aOrigin, - uint64_t aWindowId, - nsIDOMEventTarget* aEventTarget, - nsIPrincipal* aPrincipal, - nsIPresentationServiceCallback* aCallback, - nsIPresentationTransportBuilderConstructor* aBuilderConstructor); - -private: - virtual ~PresentationDeviceRequest() = default; - nsresult CreateSessionInfo(nsIPresentationDevice* aDevice, - const nsAString& aSelectedRequestUrl); - - nsTArray<nsString> mRequestUrls; - nsString mId; - nsString mOrigin; - uint64_t mWindowId; - nsWeakPtr mChromeEventHandler; - nsCOMPtr<nsIPrincipal> mPrincipal; - nsCOMPtr<nsIPresentationServiceCallback> mCallback; - nsCOMPtr<nsIPresentationTransportBuilderConstructor> mBuilderConstructor; -}; - -LazyLogModule gPresentationLog("Presentation"); - -NS_IMPL_ISUPPORTS(PresentationDeviceRequest, nsIPresentationDeviceRequest) - -PresentationDeviceRequest::PresentationDeviceRequest( - const nsTArray<nsString>& aUrls, - const nsAString& aId, - const nsAString& aOrigin, - uint64_t aWindowId, - nsIDOMEventTarget* aEventTarget, - nsIPrincipal* aPrincipal, - nsIPresentationServiceCallback* aCallback, - nsIPresentationTransportBuilderConstructor* aBuilderConstructor) - : mRequestUrls(aUrls) - , mId(aId) - , mOrigin(aOrigin) - , mWindowId(aWindowId) - , mChromeEventHandler(do_GetWeakReference(aEventTarget)) - , mPrincipal(aPrincipal) - , mCallback(aCallback) - , mBuilderConstructor(aBuilderConstructor) -{ - MOZ_ASSERT(!mRequestUrls.IsEmpty()); - MOZ_ASSERT(!mId.IsEmpty()); - MOZ_ASSERT(!mOrigin.IsEmpty()); - MOZ_ASSERT(mCallback); - MOZ_ASSERT(mBuilderConstructor); -} - -NS_IMETHODIMP -PresentationDeviceRequest::GetOrigin(nsAString& aOrigin) -{ - aOrigin = mOrigin; - return NS_OK; -} - -NS_IMETHODIMP -PresentationDeviceRequest::GetRequestURLs(nsIArray** aUrls) -{ - return ConvertURLArrayHelper(mRequestUrls, aUrls); -} - -NS_IMETHODIMP -PresentationDeviceRequest::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler) -{ - nsCOMPtr<nsIDOMEventTarget> handler(do_QueryReferent(mChromeEventHandler)); - handler.forget(aChromeEventHandler); - return NS_OK; -} - -NS_IMETHODIMP -PresentationDeviceRequest::GetPrincipal(nsIPrincipal** aPrincipal) -{ - nsCOMPtr<nsIPrincipal> principal(mPrincipal); - principal.forget(aPrincipal); - return NS_OK; -} - -NS_IMETHODIMP -PresentationDeviceRequest::Select(nsIPresentationDevice* aDevice) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (NS_WARN_IF(!aDevice)) { - MOZ_ASSERT(false, "|aDevice| should noe be null."); - mCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR); - return NS_ERROR_INVALID_ARG; - } - - // Select the most suitable URL for starting the presentation. - nsAutoString selectedRequestUrl; - for (const auto& url : mRequestUrls) { - bool isSupported; - if (NS_SUCCEEDED(aDevice->IsRequestedUrlSupported(url, &isSupported)) && - isSupported) { - selectedRequestUrl.Assign(url); - break; - } - } - - if (selectedRequestUrl.IsEmpty()) { - return mCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR); - } - - if (NS_WARN_IF(NS_FAILED(CreateSessionInfo(aDevice, selectedRequestUrl)))) { - return mCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR); - } - - return mCallback->NotifySuccess(selectedRequestUrl); -} - -nsresult -PresentationDeviceRequest::CreateSessionInfo( - nsIPresentationDevice* aDevice, - const nsAString& aSelectedRequestUrl) -{ - nsCOMPtr<nsIPresentationService> service = - do_GetService(PRESENTATION_SERVICE_CONTRACTID); - if (NS_WARN_IF(!service)) { - return NS_ERROR_NOT_AVAILABLE; - } - - // Create the controlling session info - RefPtr<PresentationSessionInfo> info = - static_cast<PresentationService*>(service.get())-> - CreateControllingSessionInfo(aSelectedRequestUrl, mId, mWindowId); - if (NS_WARN_IF(!info)) { - return NS_ERROR_NOT_AVAILABLE; - } - info->SetDevice(aDevice); - - // Establish a control channel. If we failed to do so, the callback is called - // with an error message. - nsCOMPtr<nsIPresentationControlChannel> ctrlChannel; - nsresult rv = aDevice->EstablishControlChannel(getter_AddRefs(ctrlChannel)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR); - } - - // Initialize the session info with the control channel. - rv = info->Init(ctrlChannel); - if (NS_WARN_IF(NS_FAILED(rv))) { - return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR); - } - - info->SetTransportBuilderConstructor(mBuilderConstructor); - return NS_OK; -} - -NS_IMETHODIMP -PresentationDeviceRequest::Cancel(nsresult aReason) -{ - return mCallback->NotifyError(aReason); -} - -/* - * Implementation of PresentationService - */ - -NS_IMPL_ISUPPORTS(PresentationService, - nsIPresentationService, - nsIObserver) - -PresentationService::PresentationService() -{ -} - -PresentationService::~PresentationService() -{ - HandleShutdown(); -} - -bool -PresentationService::Init() -{ - MOZ_ASSERT(NS_IsMainThread()); - - nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); - if (NS_WARN_IF(!obs)) { - return false; - } - - nsresult rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } - rv = obs->AddObserver(this, PRESENTATION_DEVICE_CHANGE_TOPIC, false); - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } - rv = obs->AddObserver(this, PRESENTATION_SESSION_REQUEST_TOPIC, false); - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } - rv = obs->AddObserver(this, PRESENTATION_TERMINATE_REQUEST_TOPIC, false); - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } - rv = obs->AddObserver(this, PRESENTATION_RECONNECT_REQUEST_TOPIC, false); - if (NS_WARN_IF(NS_FAILED(rv))) { - return false; - } - - return !NS_WARN_IF(NS_FAILED(rv)); -} - -NS_IMETHODIMP -PresentationService::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { - HandleShutdown(); - return NS_OK; - } else if (!strcmp(aTopic, PRESENTATION_DEVICE_CHANGE_TOPIC)) { - // Ignore the "update" case here, since we only care about the arrival and - // removal of the device. - if (!NS_strcmp(aData, u"add")) { - nsCOMPtr<nsIPresentationDevice> device = do_QueryInterface(aSubject); - if (NS_WARN_IF(!device)) { - return NS_ERROR_FAILURE; - } - - return HandleDeviceAdded(device); - } else if(!NS_strcmp(aData, u"remove")) { - return HandleDeviceRemoved(); - } - - return NS_OK; - } else if (!strcmp(aTopic, PRESENTATION_SESSION_REQUEST_TOPIC)) { - nsCOMPtr<nsIPresentationSessionRequest> request(do_QueryInterface(aSubject)); - if (NS_WARN_IF(!request)) { - return NS_ERROR_FAILURE; - } - - return HandleSessionRequest(request); - } else if (!strcmp(aTopic, PRESENTATION_TERMINATE_REQUEST_TOPIC)) { - nsCOMPtr<nsIPresentationTerminateRequest> request(do_QueryInterface(aSubject)); - if (NS_WARN_IF(!request)) { - return NS_ERROR_FAILURE; - } - - return HandleTerminateRequest(request); - } else if (!strcmp(aTopic, PRESENTATION_RECONNECT_REQUEST_TOPIC)) { - nsCOMPtr<nsIPresentationSessionRequest> request(do_QueryInterface(aSubject)); - if (NS_WARN_IF(!request)) { - return NS_ERROR_FAILURE; - } - - return HandleReconnectRequest(request); - } else if (!strcmp(aTopic, "profile-after-change")) { - // It's expected since we add and entry to |kLayoutCategories| in - // |nsLayoutModule.cpp| to launch this service earlier. - return NS_OK; - } - - MOZ_ASSERT(false, "Unexpected topic for PresentationService"); - return NS_ERROR_UNEXPECTED; -} - -void -PresentationService::HandleShutdown() -{ - MOZ_ASSERT(NS_IsMainThread()); - - Shutdown(); - - mAvailabilityManager.Clear(); - mSessionInfoAtController.Clear(); - mSessionInfoAtReceiver.Clear(); - - nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); - if (obs) { - obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); - obs->RemoveObserver(this, PRESENTATION_DEVICE_CHANGE_TOPIC); - obs->RemoveObserver(this, PRESENTATION_SESSION_REQUEST_TOPIC); - obs->RemoveObserver(this, PRESENTATION_TERMINATE_REQUEST_TOPIC); - obs->RemoveObserver(this, PRESENTATION_RECONNECT_REQUEST_TOPIC); - } -} - -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; -} - -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); -} - -nsresult -PresentationService::UpdateAvailabilityUrlChange( - const nsTArray<nsString>& aAvailabilityUrls) -{ - nsCOMPtr<nsIPresentationDeviceManager> deviceManager = - do_GetService(PRESENTATION_DEVICE_MANAGER_CONTRACTID); - if (NS_WARN_IF(!deviceManager)) { - return NS_ERROR_NOT_AVAILABLE; - } - - nsCOMPtr<nsIArray> devices; - nsresult rv = deviceManager->GetAvailableDevices(nullptr, - getter_AddRefs(devices)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - uint32_t numOfDevices; - devices->GetLength(&numOfDevices); - - nsTArray<nsString> supportedAvailabilityUrl; - for (const auto& url : aAvailabilityUrls) { - for (uint32_t i = 0; i < numOfDevices; ++i) { - nsCOMPtr<nsIPresentationDevice> device = do_QueryElementAt(devices, i); - if (device) { - bool isSupported; - if (NS_SUCCEEDED(device->IsRequestedUrlSupported(url, &isSupported)) && - isSupported) { - supportedAvailabilityUrl.AppendElement(url); - break; - } - } - } - } - - if (supportedAvailabilityUrl.IsEmpty()) { - return mAvailabilityManager.DoNotifyAvailableChange(aAvailabilityUrls, - false); - } - - return mAvailabilityManager.DoNotifyAvailableChange(supportedAvailabilityUrl, - true); -} - -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; -} - -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); -} - -nsresult -PresentationService::HandleReconnectRequest(nsIPresentationSessionRequest* 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; - } - - uint64_t windowId; - rv = GetWindowIdBySessionIdInternal(sessionId, - nsIPresentationService::ROLE_RECEIVER, - &windowId); - if (NS_WARN_IF(NS_FAILED(rv))) { - ctrlChannel->Disconnect(rv); - return rv; - } - - RefPtr<PresentationSessionInfo> info = - GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER); - if (NS_WARN_IF(!info)) { - // Cannot reconnect non-existed session - ctrlChannel->Disconnect(NS_ERROR_DOM_OPERATION_ERR); - return NS_ERROR_DOM_ABORT_ERR; - } - - nsAutoString url; - rv = aRequest->GetUrl(url); - if (NS_WARN_IF(NS_FAILED(rv))) { - ctrlChannel->Disconnect(rv); - return rv; - } - - // Make sure the url is the same as the previous one. - if (NS_WARN_IF(!info->GetUrl().Equals(url))) { - ctrlChannel->Disconnect(rv); - return rv; - } - - return HandleSessionRequest(aRequest); -} - -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); -} - -already_AddRefed<PresentationSessionInfo> -PresentationService::CreateControllingSessionInfo(const nsAString& aUrl, - const nsAString& aSessionId, - uint64_t aWindowId) -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (aSessionId.IsEmpty()) { - return nullptr; - } - - RefPtr<PresentationSessionInfo> info = - new PresentationControllingInfo(aUrl, aSessionId); - - mSessionInfoAtController.Put(aSessionId, info); - AddRespondingSessionId(aWindowId, - aSessionId, - nsIPresentationService::ROLE_CONTROLLER); - return info.forget(); -} - -NS_IMETHODIMP -PresentationService::SendSessionMessage(const nsAString& aSessionId, - uint8_t aRole, - const nsAString& aData) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!aData.IsEmpty()); - 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->Send(aData); -} - -NS_IMETHODIMP -PresentationService::SendSessionBinaryMsg(const nsAString& aSessionId, - uint8_t aRole, - const nsACString &aData) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!aData.IsEmpty()); - 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->SendBinaryMsg(aData); -} - -NS_IMETHODIMP -PresentationService::SendSessionBlob(const nsAString& aSessionId, - uint8_t aRole, - nsIDOMBlob* aBlob) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!aSessionId.IsEmpty()); - MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER || - aRole == nsIPresentationService::ROLE_RECEIVER); - MOZ_ASSERT(aBlob); - - RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole); - if (NS_WARN_IF(!info)) { - return NS_ERROR_NOT_AVAILABLE; - } - - return info->SendBlob(aBlob); -} - -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); -} - -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); -} - -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::BuildTransport(const nsAString& aSessionId, - uint8_t aRole) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!aSessionId.IsEmpty()); - - if (aRole != nsIPresentationService::ROLE_CONTROLLER) { - MOZ_ASSERT(false, "Only controller can call BuildTransport."); - return NS_ERROR_INVALID_ARG; - } - - RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole); - if (NS_WARN_IF(!info)) { - return NS_ERROR_NOT_AVAILABLE; - } - - return static_cast<PresentationControllingInfo*>(info.get())->BuildTransport(); -} - -NS_IMETHODIMP -PresentationService::RegisterAvailabilityListener( - const nsTArray<nsString>& aAvailabilityUrls, - nsIPresentationAvailabilityListener* aListener) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!aAvailabilityUrls.IsEmpty()); - MOZ_ASSERT(aListener); - - mAvailabilityManager.AddAvailabilityListener(aAvailabilityUrls, aListener); - return UpdateAvailabilityUrlChange(aAvailabilityUrls); -} - -NS_IMETHODIMP -PresentationService::UnregisterAvailabilityListener( - const nsTArray<nsString>& aAvailabilityUrls, - nsIPresentationAvailabilityListener* aListener) -{ - MOZ_ASSERT(NS_IsMainThread()); - - mAvailabilityManager.RemoveAvailabilityListener(aAvailabilityUrls, aListener); - 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::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; -} - -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::UnregisterRespondingListener(uint64_t aWindowId) -{ - PRES_DEBUG("%s:windowId[%lld]\n", __func__, aWindowId); - - MOZ_ASSERT(NS_IsMainThread()); - - mRespondingListeners.Remove(aWindowId); - return NS_OK; -} - -NS_IMETHODIMP -PresentationService::NotifyReceiverReady( - const nsAString& aSessionId, - uint64_t aWindowId, - bool aIsLoading, - nsIPresentationTransportBuilderConstructor* aBuilderConstructor) -{ - PRES_DEBUG("%s:id[%s], windowId[%lld], 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(); -} - -nsresult -PresentationService::NotifyTransportClosed(const nsAString& aSessionId, - uint8_t aRole, - nsresult aReason) -{ - PRES_DEBUG("%s:id[%s], reason[%x], role[%d]\n", __func__, - NS_ConvertUTF16toUTF8(aSessionId).get(), 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); -} - -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 -PresentationService::GetWindowIdBySessionId(const nsAString& aSessionId, - uint8_t aRole, - uint64_t* aWindowId) -{ - return GetWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId); -} - -NS_IMETHODIMP -PresentationService::UpdateWindowIdBySessionId(const nsAString& aSessionId, - uint8_t aRole, - const uint64_t aWindowId) -{ - return UpdateWindowIdBySessionIdInternal(aSessionId, aRole, aWindowId); -} - -bool -PresentationService::IsSessionAccessible(const nsAString& aSessionId, - const uint8_t aRole, - base::ProcessId aProcessId) -{ - MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER || - aRole == nsIPresentationService::ROLE_RECEIVER); - RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole); - if (NS_WARN_IF(!info)) { - return false; - } - return info->IsAccessible(aProcessId); -} - -} // namespace dom -} // namespace mozilla - -already_AddRefed<nsIPresentationService> -NS_CreatePresentationService() -{ - MOZ_ASSERT(NS_IsMainThread()); - - nsCOMPtr<nsIPresentationService> service; - if (XRE_GetProcessType() == GeckoProcessType_Content) { - service = new mozilla::dom::PresentationIPCService(); - } else { - service = new PresentationService(); - if (NS_WARN_IF(!static_cast<PresentationService*>(service.get())->Init())) { - return nullptr; - } - } - - return service.forget(); -} |