Bug 1208417 - Part 3 - Leverage socket-based session transport to establish presentation connection, r=schien, r=smaug
--- a/dom/presentation/provider/DisplayDeviceProvider.cpp
+++ b/dom/presentation/provider/DisplayDeviceProvider.cpp
@@ -6,34 +6,63 @@
#include "DisplayDeviceProvider.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/unused.h"
#include "nsIObserverService.h"
#include "nsIServiceManager.h"
+#include "nsITCPPresentationServer.h"
#include "nsIWindowWatcher.h"
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
#include "nsSimpleURI.h"
+#include "nsTCPDeviceInfo.h"
#include "nsThreadUtils.h"
static mozilla::LazyLogModule gDisplayDeviceProviderLog("DisplayDeviceProvider");
#define LOG(format) MOZ_LOG(gDisplayDeviceProviderLog, mozilla::LogLevel::Debug, format)
#define DISPLAY_CHANGED_NOTIFICATION "display-changed"
#define DEFAULT_CHROME_FEATURES_PREF "toolkit.defaultChromeFeatures"
#define CHROME_REMOTE_URL_PREF "b2g.multiscreen.chrome_remote_url"
namespace mozilla {
namespace dom {
namespace presentation {
+/**
+ * This wrapper is used to break circular-reference problem.
+ */
+class DisplayDeviceProviderWrappedListener final
+ : public nsITCPPresentationServerListener
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_FORWARD_SAFE_NSITCPPRESENTATIONSERVERLISTENER(mListener)
+
+ explicit DisplayDeviceProviderWrappedListener() = default;
+
+ nsresult SetListener(DisplayDeviceProvider* aListener)
+ {
+ mListener = aListener;
+ return NS_OK;
+ }
+
+private:
+ virtual ~DisplayDeviceProviderWrappedListener() = default;
+
+ DisplayDeviceProvider* mListener = nullptr;
+};
+
+NS_IMPL_ISUPPORTS(DisplayDeviceProviderWrappedListener,
+ nsITCPPresentationServerListener)
+
NS_IMPL_ISUPPORTS(DisplayDeviceProvider::HDMIDisplayDevice,
nsIPresentationDevice,
nsIPresentationLocalDevice)
// nsIPresentationDevice
NS_IMETHODIMP
DisplayDeviceProvider::HDMIDisplayDevice::GetId(nsACString& aId)
{
@@ -146,38 +175,58 @@ DisplayDeviceProvider::HDMIDisplayDevice
return rv;
}
return NS_OK;
}
NS_IMPL_ISUPPORTS(DisplayDeviceProvider,
nsIObserver,
- nsIPresentationDeviceProvider)
+ nsIPresentationDeviceProvider,
+ nsITCPPresentationServerListener)
DisplayDeviceProvider::~DisplayDeviceProvider()
{
Uninit();
}
nsresult
DisplayDeviceProvider::Init()
{
// Provider must be initialized only once.
if (mInitialized) {
return NS_OK;
}
+ nsresult rv;
+
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
MOZ_ASSERT(obs);
obs->AddObserver(this, DISPLAY_CHANGED_NOTIFICATION, false);
mDevice = new HDMIDisplayDevice(this);
+ mWrappedListener = new DisplayDeviceProviderWrappedListener();
+ rv = mWrappedListener->SetListener(this);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ mPresentationServer = do_CreateInstance(TCP_PRESENTATION_SERVER_CONTACT_ID,
+ &rv);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ rv = StartTCPService();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
mInitialized = true;
return NS_OK;
}
nsresult
DisplayDeviceProvider::Uninit()
{
// Provider must be deleted only once.
@@ -189,16 +238,60 @@ DisplayDeviceProvider::Uninit()
if (obs) {
obs->RemoveObserver(this, DISPLAY_CHANGED_NOTIFICATION);
}
// Remove device from device manager when the provider is uninit
RemoveExternalScreen();
mInitialized = false;
+ mWrappedListener->SetListener(nullptr);
+ return NS_OK;
+}
+
+nsresult
+DisplayDeviceProvider::StartTCPService()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsresult rv;
+ rv = mPresentationServer->SetId(NS_LITERAL_CSTRING("DisplayDeviceProvider"));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ uint16_t servicePort;
+ rv = mPresentationServer->GetPort(&servicePort);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ /*
+ * If |servicePort| is non-zero, it means PresentationServer is running.
+ * Otherwise, we should make it start serving.
+ */
+ if (!servicePort) {
+ rv = mPresentationServer->SetListener(mWrappedListener);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ rv = mPresentationServer->StartService(0);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ rv = mPresentationServer->GetPort(&servicePort);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ }
+
+ mPort = servicePort;
+
return NS_OK;
}
nsresult
DisplayDeviceProvider::AddExternalScreen()
{
MOZ_ASSERT(mDeviceListener);
@@ -270,16 +363,56 @@ DisplayDeviceProvider::SetListener(nsIPr
}
NS_IMETHODIMP
DisplayDeviceProvider::ForceDiscovery()
{
return NS_OK;
}
+// nsITCPPresentationServerListener
+NS_IMETHODIMP
+DisplayDeviceProvider::OnPortChange(uint16_t aPort)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ mPort = aPort;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+DisplayDeviceProvider::OnSessionRequest(nsITCPDeviceInfo* aDeviceInfo,
+ const nsAString& aUrl,
+ const nsAString& aPresentationId,
+ nsIPresentationControlChannel* aControlChannel)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(aDeviceInfo);
+ MOZ_ASSERT(aControlChannel);
+
+ nsresult rv;
+
+ nsCOMPtr<nsIPresentationDeviceListener> listener;
+ rv = GetListener(getter_AddRefs(listener));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ MOZ_ASSERT(!listener);
+
+ rv = listener->OnSessionRequest(mDevice,
+ aUrl,
+ aPresentationId,
+ aControlChannel);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ return NS_OK;
+}
+
// nsIObserver
NS_IMETHODIMP
DisplayDeviceProvider::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
if (!strcmp(aTopic, DISPLAY_CHANGED_NOTIFICATION)) {
nsCOMPtr<nsIDisplayInfo> displayInfo = do_QueryInterface(aSubject);
@@ -300,19 +433,30 @@ DisplayDeviceProvider::Observe(nsISuppor
}
}
return NS_OK;
}
nsresult
DisplayDeviceProvider::RequestSession(HDMIDisplayDevice* aDevice,
- const nsAString& aUrl,
- const nsAString& aPresentationId,
- nsIPresentationControlChannel** aControlChannel)
+ const nsAString& aUrl,
+ const nsAString& aPresentationId,
+ nsIPresentationControlChannel** aControlChannel)
{
- // Implement in part 3
- return NS_OK;
+ MOZ_ASSERT(aDevice);
+ MOZ_ASSERT(mPresentationServer);
+ NS_ENSURE_ARG_POINTER(aControlChannel);
+ *aControlChannel = nullptr;
+
+ nsCOMPtr<nsITCPDeviceInfo> deviceInfo = new TCPDeviceInfo(aDevice->Id(),
+ aDevice->Address(),
+ mPort);
+
+ return mPresentationServer->RequestSession(deviceInfo,
+ aUrl,
+ aPresentationId,
+ aControlChannel);
}
} // namespace presentation
} // namespace dom
} // namespace mozilla
--- a/dom/presentation/provider/DisplayDeviceProvider.h
+++ b/dom/presentation/provider/DisplayDeviceProvider.h
@@ -10,16 +10,17 @@
#include "mozilla/RefPtr.h"
#include "mozilla/WeakPtr.h"
#include "nsCOMPtr.h"
#include "nsIDOMWindow.h"
#include "nsIDisplayInfo.h"
#include "nsIObserver.h"
#include "nsIPresentationDeviceProvider.h"
#include "nsIPresentationLocalDevice.h"
+#include "nsITCPPresentationServer.h"
#include "nsIWindowWatcher.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsWeakReference.h"
namespace mozilla {
namespace dom {
namespace presentation {
@@ -28,88 +29,103 @@ namespace presentation {
// widget/gonk/libdisplay/GonkDisplay.h.
enum DisplayType {
DISPLAY_PRIMARY,
DISPLAY_EXTERNAL,
DISPLAY_VIRTUAL,
NUM_DISPLAY_TYPES
};
+class DisplayDeviceProviderWrappedListener;
+
class DisplayDeviceProvider final : public nsIObserver
, public nsIPresentationDeviceProvider
+ , public nsITCPPresentationServerListener
, public SupportsWeakPtr<DisplayDeviceProvider>
{
private:
class HDMIDisplayDevice final : public nsIPresentationLocalDevice
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPRESENTATIONDEVICE
NS_DECL_NSIPRESENTATIONLOCALDEVICE
// mScreenId is as same as the definition of display type.
explicit HDMIDisplayDevice(DisplayDeviceProvider* aProvider)
: mScreenId(DisplayType::DISPLAY_EXTERNAL)
, mName("HDMI")
, mType("external")
, mWindowId("hdmi")
+ , mAddress("127.0.0.1")
, mProvider(aProvider)
{}
nsresult OpenTopLevelWindow();
nsresult CloseTopLevelWindow();
const nsCString& Id() const { return mWindowId; }
+ const nsCString& Address() const { return mAddress; }
private:
virtual ~HDMIDisplayDevice() = default;
// Due to the limitation of nsWinodw, mScreenId must be an integer.
// And mScreenId is also align to the display type defined in
// widget/gonk/libdisplay/GonkDisplay.h.
// HDMI display is DisplayType::DISPLAY_EXTERNAL.
uint32_t mScreenId;
nsCString mName;
nsCString mType;
nsCString mWindowId;
+ nsCString mAddress;
nsCOMPtr<mozIDOMWindowProxy> mWindow;
// weak pointer
// Provider hold a strong pointer to the device. Use weak pointer to prevent
// the reference cycle.
WeakPtr<DisplayDeviceProvider> mProvider;
};
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIPRESENTATIONDEVICEPROVIDER
+ NS_DECL_NSITCPPRESENTATIONSERVERLISTENER
// For using WeakPtr when MOZ_REFCOUNTED_LEAK_CHECKING defined
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(DisplayDeviceProvider)
nsresult RequestSession(HDMIDisplayDevice* aDevice,
const nsAString& aUrl,
const nsAString& aPresentationId,
nsIPresentationControlChannel** aControlChannel);
private:
virtual ~DisplayDeviceProvider();
nsresult Init();
nsresult Uninit();
nsresult AddExternalScreen();
nsresult RemoveExternalScreen();
+ nsresult StartTCPService();
+
// Now support HDMI display only and there should be only one HDMI display.
nsCOMPtr<nsIPresentationLocalDevice> mDevice = nullptr;
// weak pointer
// PresentationDeviceManager (mDeviceListener) hold strong pointer to
// DisplayDeviceProvider. Use nsWeakPtr to avoid reference cycle.
nsWeakPtr mDeviceListener = nullptr;
+ nsCOMPtr<nsITCPPresentationServer> mPresentationServer;
+ // Used to prevent reference cycle between DisplayDeviceProvider and
+ // TCPPresentationServer.
+ RefPtr<DisplayDeviceProviderWrappedListener> mWrappedListener;
+
bool mInitialized = false;
+ uint16_t mPort;
};
} // mozilla
} // dom
} // presentation
#endif // mozilla_dom_presentation_provider_DisplayDeviceProvider_h
--- a/dom/presentation/provider/MulticastDNSDeviceProvider.cpp
+++ b/dom/presentation/provider/MulticastDNSDeviceProvider.cpp
@@ -8,16 +8,17 @@
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/unused.h"
#include "nsAutoPtr.h"
#include "nsComponentManagerUtils.h"
#include "nsIObserverService.h"
#include "nsServiceManagerUtils.h"
+#include "nsTCPDeviceInfo.h"
#include "nsThreadUtils.h"
#ifdef MOZ_WIDGET_ANDROID
#include "nsIPropertyBag2.h"
#endif // MOZ_WIDGET_ANDROID
#define PREF_PRESENTATION_DISCOVERY "dom.presentation.discovery.enabled"
#define PREF_PRESENTATION_DISCOVERY_TIMEOUT_MS "dom.presentation.discovery.timeout_ms"
@@ -54,64 +55,16 @@ GetAndroidDeviceName(nsACString& aRetVal
nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
MOZ_ASSERT(infoService, "Could not find a system info service");
Unused << NS_WARN_IF(NS_FAILED(infoService->GetPropertyAsACString(
NS_LITERAL_STRING("device"), aRetVal)));
}
#endif // MOZ_WIDGET_ANDROID
-class TCPDeviceInfo final : public nsITCPDeviceInfo
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSITCPDEVICEINFO
-
- explicit TCPDeviceInfo(const nsACString& aId,
- const nsACString& aAddress,
- const uint16_t aPort)
- : mId(aId)
- , mAddress(aAddress)
- , mPort(aPort)
- {
- }
-
-private:
- virtual ~TCPDeviceInfo() {}
-
- nsCString mId;
- nsCString mAddress;
- uint16_t mPort;
-};
-
-NS_IMPL_ISUPPORTS(TCPDeviceInfo,
- nsITCPDeviceInfo)
-
-// nsITCPDeviceInfo
-NS_IMETHODIMP
-TCPDeviceInfo::GetId(nsACString& aId)
-{
- aId = mId;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-TCPDeviceInfo::GetAddress(nsACString& aAddress)
-{
- aAddress = mAddress;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-TCPDeviceInfo::GetPort(uint16_t* aPort)
-{
- *aPort = mPort;
- return NS_OK;
-}
-
} //anonymous namespace
/**
* This wrapper is used to break circular-reference problem.
*/
class DNSServiceWrappedListener final
: public nsIDNSServiceDiscoveryListener
, public nsIDNSRegistrationListener
new file mode 100644
--- /dev/null
+++ b/dom/presentation/provider/nsTCPDeviceInfo.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 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/. */
+
+#ifndef __TCPDeviceInfo_h__
+#define __TCPDeviceInfo_h__
+
+namespace mozilla {
+namespace dom {
+namespace presentation {
+
+class TCPDeviceInfo final : public nsITCPDeviceInfo
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSITCPDEVICEINFO
+
+ explicit TCPDeviceInfo(const nsACString& aId,
+ const nsACString& aAddress,
+ const uint16_t aPort)
+ : mId(aId)
+ , mAddress(aAddress)
+ , mPort(aPort)
+ {
+ }
+
+private:
+ virtual ~TCPDeviceInfo() {}
+
+ nsCString mId;
+ nsCString mAddress;
+ uint16_t mPort;
+};
+
+NS_IMPL_ISUPPORTS(TCPDeviceInfo,
+ nsITCPDeviceInfo)
+
+// nsITCPDeviceInfo
+NS_IMETHODIMP
+TCPDeviceInfo::GetId(nsACString& aId)
+{
+ aId = mId;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TCPDeviceInfo::GetAddress(nsACString& aAddress)
+{
+ aAddress = mAddress;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TCPDeviceInfo::GetPort(uint16_t* aPort)
+{
+ *aPort = mPort;
+ return NS_OK;
+}
+
+}
+}
+}
+
+#endif /* !__TCPDeviceInfo_h__ */
+