Bug 1208417 - Part 3 - Leverage socket-based session transport to establish presentation connection, r=schien, r=smaug
authorKuoE0 <kuoe0.tw@gmail.com>
Thu, 28 Apr 2016 15:05:53 +0800
changeset 357328 c2da65057928abc7fb07c061c0581b743a7baec1
parent 357327 4f95de9b438f19200f3399814348ea6dda563bc1
child 357329 e3245a8dfacdefc22a21261c32e5129afc725dfb
push id16755
push useryura.zenevich@gmail.com
push dateThu, 28 Apr 2016 15:12:20 +0000
reviewersschien, smaug
bugs1208417
milestone49.0a1
Bug 1208417 - Part 3 - Leverage socket-based session transport to establish presentation connection, r=schien, r=smaug
dom/presentation/provider/DisplayDeviceProvider.cpp
dom/presentation/provider/DisplayDeviceProvider.h
dom/presentation/provider/MulticastDNSDeviceProvider.cpp
dom/presentation/provider/nsTCPDeviceInfo.h
--- 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__ */
+