Bug 1026350 - Part 1: Inputport API implementation. r=baku
authorJames Cheng <jacheng@mozilla.com>
Wed, 08 Apr 2015 03:07:00 -0400
changeset 238442 5508dd802e48de4139bf3f45df3d27f5bc1cfde2
parent 238441 3182e5961729cdae20b931d0232262e34bc29463
child 238443 ded8396fa202b22d8fcfc918861d3f179483ec11
push id58223
push userryanvm@gmail.com
push dateFri, 10 Apr 2015 03:00:59 +0000
treeherdermozilla-inbound@b2e2a9ff51e9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1026350
milestone40.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1026350 - Part 1: Inputport API implementation. r=baku
b2g/app/b2g.js
b2g/installer/package-manifest.in
dom/apps/PermissionsTable.jsm
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/base/nsGkAtomList.h
dom/inputport/AVInputPort.cpp
dom/inputport/AVInputPort.h
dom/inputport/DisplayPortInputPort.cpp
dom/inputport/DisplayPortInputPort.h
dom/inputport/FakeInputPortService.cpp
dom/inputport/FakeInputPortService.h
dom/inputport/HDMIInputPort.cpp
dom/inputport/HDMIInputPort.h
dom/inputport/InputPort.cpp
dom/inputport/InputPort.h
dom/inputport/InputPortData.cpp
dom/inputport/InputPortData.h
dom/inputport/InputPortListeners.cpp
dom/inputport/InputPortListeners.h
dom/inputport/InputPortManager.cpp
dom/inputport/InputPortManager.h
dom/inputport/InputPortServiceFactory.cpp
dom/inputport/InputPortServiceFactory.h
dom/inputport/moz.build
dom/inputport/nsIInputPortService.idl
dom/moz.build
dom/tests/mochitest/general/test_interfaces.html
dom/webidl/AVInputPort.webidl
dom/webidl/DisplayPortInputPort.webidl
dom/webidl/HDMIInputPort.webidl
dom/webidl/InputPort.webidl
dom/webidl/InputPortManager.webidl
dom/webidl/Navigator.webidl
dom/webidl/moz.build
layout/build/nsLayoutModule.cpp
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -1103,16 +1103,19 @@ pref("dom.mapped_arraybuffer.enabled", t
 pref("dom.broadcastChannel.enabled", true);
 
 // UDPSocket API
 pref("dom.udpsocket.enabled", true);
 
 // Enable TV Manager API
 pref("dom.tv.enabled", true);
 
+// Enable Inputport Manager API
+pref("dom.inputport.enabled", true);
+
 pref("dom.mozSettings.SettingsDB.debug.enabled", true);
 pref("dom.mozSettings.SettingsManager.debug.enabled", true);
 pref("dom.mozSettings.SettingsRequestManager.debug.enabled", true);
 pref("dom.mozSettings.SettingsService.debug.enabled", true);
 
 pref("dom.mozSettings.SettingsDB.verbose.enabled", false);
 pref("dom.mozSettings.SettingsManager.verbose.enabled", false);
 pref("dom.mozSettings.SettingsRequestManager.verbose.enabled", false);
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -219,16 +219,17 @@
 @RESPATH@/components/dom_icc.xpt
 @RESPATH@/components/dom_mobilemessage.xpt
 @RESPATH@/components/dom_storage.xpt
 @RESPATH@/components/dom_stylesheets.xpt
 @RESPATH@/components/dom_telephony.xpt
 @RESPATH@/components/dom_threads.xpt
 @RESPATH@/components/dom_traversal.xpt
 @RESPATH@/components/dom_tv.xpt
+@RESPATH@/components/dom_inputport.xpt
 @RESPATH@/components/dom_views.xpt
 @RESPATH@/components/dom_voicemail.xpt
 #ifdef MOZ_WEBSPEECH
 @RESPATH@/components/dom_webspeechrecognition.xpt
 #endif
 @RESPATH@/components/dom_xbl.xpt
 @RESPATH@/components/dom_xpath.xpt
 @RESPATH@/components/dom_xul.xpt
--- a/dom/apps/PermissionsTable.jsm
+++ b/dom/apps/PermissionsTable.jsm
@@ -531,16 +531,22 @@ this.PermissionsTable =  { geolocation: 
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
                            "secureelement-manage": {
                              app: DENY_ACTION,
                              trusted: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
+                           },
+                           "inputport": {
+                             app: DENY_ACTION,
+                             trusted: DENY_ACTION,
+                             privileged: DENY_ACTION,
+                             certified: ALLOW_ACTION
                            }
                          };
 
 /**
  * Append access modes to the permission name as suffixes.
  *   e.g. permission name 'contacts' with ['read', 'write'] =
  *   ['contacts-read', contacts-write']
  * @param string aPermName
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -32,16 +32,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "BatteryManager.h"
 #include "mozilla/dom/PowerManager.h"
 #include "mozilla/dom/WakeLock.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/CellBroadcast.h"
 #include "mozilla/dom/IccManager.h"
+#include "mozilla/dom/InputPortManager.h"
 #include "mozilla/dom/MobileMessageManager.h"
 #include "mozilla/dom/ServiceWorkerContainer.h"
 #include "mozilla/dom/Telephony.h"
 #include "mozilla/dom/Voicemail.h"
 #include "mozilla/dom/TVManager.h"
 #include "mozilla/dom/VRDevice.h"
 #include "mozilla/Hal.h"
 #include "nsISiteSpecificUserAgent.h"
@@ -178,16 +179,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTVManager)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputPortManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
 #ifdef MOZ_B2G_RIL
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
 #endif
 #ifdef MOZ_B2G_BT
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBluetooth)
 #endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
@@ -272,16 +274,20 @@ Navigator::Invalidate()
     mVoicemail->Shutdown();
     mVoicemail = nullptr;
   }
 
   if (mTVManager) {
     mTVManager = nullptr;
   }
 
+  if (mInputPortManager) {
+    mInputPortManager = nullptr;
+  }
+
   if (mConnection) {
     mConnection->Shutdown();
     mConnection = nullptr;
   }
 
 #ifdef MOZ_B2G_RIL
   if (mMobileConnections) {
     mMobileConnections = nullptr;
@@ -1630,16 +1636,33 @@ Navigator::GetTv()
       return nullptr;
     }
     mTVManager = TVManager::Create(mWindow);
   }
 
   return mTVManager;
 }
 
+InputPortManager*
+Navigator::GetInputPortManager(ErrorResult& aRv)
+{
+  if (!mInputPortManager) {
+    if (!mWindow) {
+      aRv.Throw(NS_ERROR_FAILURE);
+      return nullptr;
+    }
+    mInputPortManager = InputPortManager::Create(mWindow, aRv);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return nullptr;
+    }
+  }
+
+  return mInputPortManager;
+}
+
 #ifdef MOZ_B2G
 already_AddRefed<Promise>
 Navigator::GetMobileIdAssertion(const MobileIdOptions& aOptions,
                                 ErrorResult& aRv)
 {
   if (!mWindow || !mWindow->GetDocShell()) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -88,16 +88,17 @@ class MobileConnectionArray;
 #endif
 
 class PowerManager;
 class CellBroadcast;
 class IccManager;
 class Telephony;
 class Voicemail;
 class TVManager;
+class InputPortManager;
 
 namespace time {
 class TimeManager;
 } // namespace time
 
 namespace system {
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
 class AudioChannelManager;
@@ -220,16 +221,17 @@ public:
                          ErrorResult& aRv);
   DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv);
   CellBroadcast* GetMozCellBroadcast(ErrorResult& aRv);
   IccManager* GetMozIccManager(ErrorResult& aRv);
   MobileMessageManager* GetMozMobileMessage();
   Telephony* GetMozTelephony(ErrorResult& aRv);
   Voicemail* GetMozVoicemail(ErrorResult& aRv);
   TVManager* GetTv();
+  InputPortManager* GetInputPortManager(ErrorResult& aRv);
   network::Connection* GetConnection(ErrorResult& aRv);
   nsDOMCameraManager* GetMozCameras(ErrorResult& aRv);
   MediaDevices* GetMediaDevices(ErrorResult& aRv);
   void MozSetMessageHandler(const nsAString& aType,
                             systemMessageCallback* aCallback,
                             ErrorResult& aRv);
   bool MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv);
   void MozSetMessageHandlerPromise(Promise& aPromise, ErrorResult& aRv);
@@ -351,16 +353,17 @@ private:
 #endif
   nsRefPtr<PowerManager> mPowerManager;
   nsRefPtr<CellBroadcast> mCellBroadcast;
   nsRefPtr<IccManager> mIccManager;
   nsRefPtr<MobileMessageManager> mMobileMessageManager;
   nsRefPtr<Telephony> mTelephony;
   nsRefPtr<Voicemail> mVoicemail;
   nsRefPtr<TVManager> mTVManager;
+  nsRefPtr<InputPortManager> mInputPortManager;
   nsRefPtr<network::Connection> mConnection;
 #ifdef MOZ_B2G_RIL
   nsRefPtr<MobileConnectionArray> mMobileConnections;
 #endif
 #ifdef MOZ_B2G_BT
   nsRefPtr<bluetooth::BluetoothManager> mBluetooth;
 #endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -721,16 +721,17 @@ GK_ATOM(ondeleted, "ondeleted")
 GK_ATOM(ondeliverysuccess, "ondeliverysuccess")
 GK_ATOM(ondeliveryerror, "ondeliveryerror")
 GK_ATOM(ondevicefound, "ondevicefound")
 GK_ATOM(ondevicepaired, "ondevicepaired")
 GK_ATOM(ondeviceunpaired, "ondeviceunpaired")
 GK_ATOM(ondialing, "ondialing")
 GK_ATOM(ondisabled, "ondisabled")
 GK_ATOM(ondischargingtimechange, "ondischargingtimechange")
+GK_ATOM(ondisconnect, "ondisconnect")
 GK_ATOM(ondisconnected, "ondisconnected")
 GK_ATOM(ondisconnecting, "ondisconnecting")
 GK_ATOM(ondiscoverystatechanged, "ondiscoverystatechanged")
 GK_ATOM(ondisplaypasskeyreq, "ondisplaypasskeyreq")
 GK_ATOM(ondownloading, "ondownloading")
 GK_ATOM(onDOMActivate, "onDOMActivate")
 GK_ATOM(onDOMAttrModified, "onDOMAttrModified")
 GK_ATOM(onDOMCharacterDataModified, "onDOMCharacterDataModified")
new file mode 100644
--- /dev/null
+++ b/dom/inputport/AVInputPort.cpp
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 et tw=78: */
+/* 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 "mozilla/dom/AVInputPort.h"
+#include "mozilla/dom/AVInputPortBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+AVInputPort::AVInputPort(nsPIDOMWindow* aWindow)
+  : InputPort(aWindow)
+{
+}
+
+AVInputPort::~AVInputPort()
+{
+}
+
+/* static */ already_AddRefed<AVInputPort>
+AVInputPort::Create(nsPIDOMWindow* aWindow,
+                    nsIInputPortListener* aListener,
+                    nsIInputPortData* aData,
+                    ErrorResult& aRv)
+{
+  nsRefPtr<AVInputPort> inputport = new AVInputPort(aWindow);
+  inputport->Init(aData, aListener, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+  return inputport.forget();
+}
+
+JSObject*
+AVInputPort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return AVInputPortBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace dom
+} //namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/inputport/AVInputPort.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 et tw=78: */
+/* 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 mozilla_dom_AVInputPort_h
+#define mozilla_dom_AVInputPort_h
+
+#include "mozilla/dom/InputPort.h"
+
+namespace mozilla {
+namespace dom {
+
+class AVInputPort final : public InputPort
+{
+public:
+  static already_AddRefed<AVInputPort> Create(nsPIDOMWindow* aWindow,
+                                              nsIInputPortListener* aListener,
+                                              nsIInputPortData* aData,
+                                              ErrorResult& aRv);
+
+  virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+private:
+  explicit AVInputPort(nsPIDOMWindow* aWindow);
+
+  ~AVInputPort();
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_AVInputPort_h
new file mode 100644
--- /dev/null
+++ b/dom/inputport/DisplayPortInputPort.cpp
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 et tw=78: */
+/* 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 "mozilla/dom/DisplayPortInputPort.h"
+#include "mozilla/dom/DisplayPortInputPortBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+DisplayPortInputPort::DisplayPortInputPort(nsPIDOMWindow* aWindow)
+  : InputPort(aWindow)
+{
+}
+
+DisplayPortInputPort::~DisplayPortInputPort()
+{
+}
+
+/* static */ already_AddRefed<DisplayPortInputPort>
+DisplayPortInputPort::Create(nsPIDOMWindow* aWindow,
+                             nsIInputPortListener* aListener,
+                             nsIInputPortData* aData,
+                             ErrorResult& aRv)
+{
+  nsRefPtr<DisplayPortInputPort> inputport = new DisplayPortInputPort(aWindow);
+  inputport->Init(aData, aListener, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+  return inputport.forget();
+}
+
+JSObject*
+DisplayPortInputPort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return DisplayPortInputPortBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace dom
+} //namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/inputport/DisplayPortInputPort.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 et tw=78: */
+/* 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 mozilla_dom_DisplayPortInputPort_h
+#define mozilla_dom_DisplayPortInputPort_h
+
+#include "mozilla/dom/InputPort.h"
+
+namespace mozilla {
+namespace dom {
+
+class DisplayPortInputPort final : public InputPort
+{
+public:
+  static already_AddRefed<DisplayPortInputPort> Create(nsPIDOMWindow* aWindow,
+                                                       nsIInputPortListener* aListener,
+                                                       nsIInputPortData* aData,
+                                                       ErrorResult& aRv);
+
+  virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+private:
+  explicit DisplayPortInputPort(nsPIDOMWindow* aWindow);
+
+  ~DisplayPortInputPort();
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_DisplayPortInputPort_h
new file mode 100644
--- /dev/null
+++ b/dom/inputport/FakeInputPortService.cpp
@@ -0,0 +1,208 @@
+/* -*- 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/. */
+
+#include "FakeInputPortService.h"
+#include "InputPortData.h"
+#include "mozilla/dom/InputPort.h"
+#include "nsIMutableArray.h"
+#include "nsITimer.h"
+#include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+namespace {
+class InputPortServiceNotifyRunnable final : public nsRunnable
+{
+public:
+  InputPortServiceNotifyRunnable(
+      nsIInputPortServiceCallback* aCallback,
+      nsIArray* aDataList,
+      uint16_t aErrorCode = nsIInputPortServiceCallback::INPUTPORT_ERROR_OK)
+    : mCallback(aCallback)
+    , mDataList(aDataList)
+    , mErrorCode(aErrorCode)
+  {
+    MOZ_ASSERT(aCallback);
+    MOZ_ASSERT(aDataList);
+  }
+
+  NS_IMETHOD Run()
+  {
+    if (mErrorCode == nsIInputPortServiceCallback::INPUTPORT_ERROR_OK) {
+      return mCallback->NotifySuccess(mDataList);
+    } else {
+      return mCallback->NotifyError(mErrorCode);
+    }
+  }
+
+private:
+  nsCOMPtr<nsIInputPortServiceCallback> mCallback;
+  nsCOMPtr<nsIArray> mDataList;
+  uint16_t mErrorCode;
+};
+
+class PortConnectionChangedCallback final : public nsITimerCallback
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  PortConnectionChangedCallback(nsIInputPortData* aInputPortData,
+                                nsIInputPortListener* aInputPortListener,
+                                const bool aIsConnected)
+    : mInputPortData(aInputPortData)
+    , mInputPortListener(aInputPortListener)
+    , mIsConnected(aIsConnected)
+  {}
+
+  NS_IMETHODIMP
+  Notify(nsITimer* aTimer)
+  {
+    InputPortData* portData = static_cast<InputPortData*>(mInputPortData.get());
+    portData->SetConnected(mIsConnected);
+    nsresult rv = mInputPortListener->NotifyConnectionChanged(
+      portData->GetId(), mIsConnected);
+    return rv;
+  }
+
+private:
+  ~PortConnectionChangedCallback() {}
+
+  nsCOMPtr<nsIInputPortData> mInputPortData;
+  nsCOMPtr<nsIInputPortListener> mInputPortListener;
+  bool mIsConnected;
+};
+
+} // namespace anonymous
+
+NS_IMPL_ISUPPORTS(PortConnectionChangedCallback, nsITimerCallback)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(FakeInputPortService)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FakeInputPortService)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputPortListener)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPortConnectionChangedTimer)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPortDatas)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FakeInputPortService)
+  tmp->Shutdown();
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mInputPortListener)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPortConnectionChangedTimer)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPortDatas)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(FakeInputPortService)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(FakeInputPortService)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FakeInputPortService)
+  NS_INTERFACE_MAP_ENTRY(nsIInputPortService)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+FakeInputPortService::FakeInputPortService()
+{
+  Init();
+}
+
+FakeInputPortService::~FakeInputPortService()
+{
+  Shutdown();
+}
+
+void
+FakeInputPortService::Init()
+{
+  nsCOMPtr<nsIInputPortData> portData1 =
+      MockInputPort(NS_LITERAL_STRING("1"), NS_LITERAL_STRING("av"), true);
+  mPortDatas.AppendElement(portData1);
+
+  nsCOMPtr<nsIInputPortData> portData2 =
+      MockInputPort(NS_LITERAL_STRING("2"), NS_LITERAL_STRING("displayport"), false);
+  mPortDatas.AppendElement(portData2);
+
+  nsCOMPtr<nsIInputPortData> portData3 =
+      MockInputPort(NS_LITERAL_STRING("3"), NS_LITERAL_STRING("hdmi"), true);
+  mPortDatas.AppendElement(portData3);
+}
+
+void
+FakeInputPortService::Shutdown()
+{
+  if (mPortConnectionChangedTimer) {
+    mPortConnectionChangedTimer->Cancel();
+  }
+}
+
+/* virtual */ NS_IMETHODIMP
+FakeInputPortService::GetInputPortListener(nsIInputPortListener** aInputPortListener)
+{
+  if (!mInputPortListener) {
+    *aInputPortListener = nullptr;
+    return NS_OK;
+  }
+
+  *aInputPortListener = mInputPortListener;
+  NS_ADDREF(*aInputPortListener);
+  return NS_OK;
+}
+
+/* virtual */ NS_IMETHODIMP
+FakeInputPortService::SetInputPortListener(nsIInputPortListener* aInputPortListener)
+{
+  mInputPortListener = aInputPortListener;
+  return NS_OK;
+}
+
+/* virtual */ NS_IMETHODIMP
+FakeInputPortService::GetInputPorts(nsIInputPortServiceCallback* aCallback)
+{
+  if (!aCallback) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  nsCOMPtr<nsIMutableArray> portDataList = do_CreateInstance(NS_ARRAY_CONTRACTID);
+  if (!portDataList) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  for (uint32_t i = 0; i < mPortDatas.Length(); i++) {
+    portDataList->AppendElement(mPortDatas[i], false);
+  }
+
+  mPortConnectionChangedTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
+  NS_ENSURE_TRUE(mPortConnectionChangedTimer, NS_ERROR_OUT_OF_MEMORY);
+  bool isConnected = false;
+  mPortDatas[0]->GetConnected(&isConnected);
+  //simulate the connection change event.
+  nsRefPtr<PortConnectionChangedCallback> connectionChangedCb =
+    new PortConnectionChangedCallback(mPortDatas[0], mInputPortListener, !isConnected);
+  nsresult rv = mPortConnectionChangedTimer->InitWithCallback(
+    connectionChangedCb, 100, nsITimer::TYPE_ONE_SHOT);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIRunnable> runnable =
+    new InputPortServiceNotifyRunnable(aCallback, portDataList);
+  return NS_DispatchToCurrentThread(runnable);
+}
+
+already_AddRefed<nsIInputPortData>
+FakeInputPortService::MockInputPort(const nsAString& aId,
+                                    const nsAString& aType,
+                                    bool aIsConnected)
+{
+  nsCOMPtr<nsIInputPortData> portData = new InputPortData();
+  portData->SetId(aId);
+  portData->SetType(aType);
+  portData->SetConnected(aIsConnected);
+  return portData.forget();
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/inputport/FakeInputPortService.h
@@ -0,0 +1,55 @@
+/* -*- 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 mozilla_dom_FakeInputPortService_h
+#define mozilla_dom_FakeInputPortService_h
+
+#include "nsCOMPtr.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsIInputPortService.h"
+#include "nsTArray.h"
+
+#define FAKE_INPUTPORT_SERVICE_CONTRACTID \
+  "@mozilla.org/inputport/fakeinputportservice;1"
+#define FAKE_INPUTPORT_SERVICE_CID \
+  { 0xea6b01c5, 0xad04, 0x4f2a, \
+    { 0x8a, 0xbe, 0x64, 0xdb, 0xa2, 0x22, 0xe3, 0x3d } }
+
+class nsITimer;
+class nsIInputPortData;
+
+namespace mozilla {
+namespace dom {
+
+class FakeInputPortService final : public nsIInputPortService
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(FakeInputPortService)
+  NS_DECL_NSIINPUTPORTSERVICE
+
+  FakeInputPortService();
+
+private:
+  ~FakeInputPortService();
+
+  void Init();
+
+  void Shutdown();
+
+  already_AddRefed<nsIInputPortData> MockInputPort(const nsAString& aId,
+                                                   const nsAString& aType,
+                                                   bool aIsConnected);
+
+  nsCOMPtr<nsIInputPortListener> mInputPortListener;
+  nsCOMPtr<nsITimer> mPortConnectionChangedTimer;
+  nsTArray<nsCOMPtr<nsIInputPortData>> mPortDatas;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_FakeInputPortService_h
new file mode 100644
--- /dev/null
+++ b/dom/inputport/HDMIInputPort.cpp
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 et tw=78: */
+/* 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 "mozilla/dom/HDMIInputPort.h"
+#include "mozilla/dom/HDMIInputPortBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+HDMIInputPort::HDMIInputPort(nsPIDOMWindow* aWindow)
+  : InputPort(aWindow)
+{
+}
+
+HDMIInputPort::~HDMIInputPort()
+{
+}
+
+/* static */ already_AddRefed<HDMIInputPort>
+HDMIInputPort::Create(nsPIDOMWindow* aWindow,
+                      nsIInputPortListener* aListener,
+                      nsIInputPortData* aData,
+                      ErrorResult& aRv)
+{
+  nsRefPtr<HDMIInputPort> inputport = new HDMIInputPort(aWindow);
+  inputport->Init(aData, aListener, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+  return inputport.forget();
+}
+
+
+JSObject*
+HDMIInputPort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return HDMIInputPortBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace dom
+} //namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/inputport/HDMIInputPort.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 et tw=78: */
+/* 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 mozilla_dom_HDMIInputPort_h
+#define mozilla_dom_HDMIInputPort_h
+
+#include "mozilla/dom/InputPort.h"
+
+namespace mozilla {
+namespace dom {
+
+class HDMIInputPort final : public InputPort
+{
+public:
+  static already_AddRefed<HDMIInputPort> Create(nsPIDOMWindow* aWindow,
+                                                nsIInputPortListener* aListener,
+                                                nsIInputPortData* aData,
+                                                ErrorResult& aRv);
+
+  virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+private:
+  explicit HDMIInputPort(nsPIDOMWindow* aWindow);
+
+  ~HDMIInputPort();
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_HDMIInputPort_h
new file mode 100644
--- /dev/null
+++ b/dom/inputport/InputPort.cpp
@@ -0,0 +1,115 @@
+/* -*- 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/. */
+
+#include "DOMMediaStream.h"
+#include "InputPortData.h"
+#include "InputPortListeners.h"
+#include "mozilla/AsyncEventDispatcher.h"
+#include "mozilla/dom/InputPort.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(InputPort, DOMEventTargetHelper,
+                                   mStream,
+                                   mInputPortListener)
+
+NS_IMPL_ADDREF_INHERITED(InputPort, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(InputPort, DOMEventTargetHelper)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(InputPort)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+InputPort::InputPort(nsPIDOMWindow* aWindow)
+  : DOMEventTargetHelper(aWindow)
+  , mIsConnected(false)
+{
+}
+
+InputPort::~InputPort()
+{
+}
+
+void
+InputPort::Init(nsIInputPortData* aData, nsIInputPortListener* aListener, ErrorResult& aRv)
+{
+  MOZ_ASSERT(aData);
+  MOZ_ASSERT(aListener);
+
+  aRv = aData->GetId(mId);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
+  if (NS_WARN_IF(mId.IsEmpty())) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  InputPortType type = static_cast<InputPortData*>(aData)->GetType();
+  if (NS_WARN_IF(type == InputPortType::EndGuard_)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  aData->GetConnected(&mIsConnected);
+
+  mInputPortListener = static_cast<InputPortListener*>(aListener);
+  mInputPortListener->RegisterInputPort(this);
+
+  mStream = DOMMediaStream::CreateSourceStream(GetOwner());
+}
+
+void
+InputPort::Shutdown()
+{
+  MOZ_ASSERT(mInputPortListener);
+  if (mInputPortListener) {
+    mInputPortListener->UnregisterInputPort(this);
+    mInputPortListener = nullptr;
+  }
+}
+
+/* virtual */ JSObject*
+InputPort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return InputPortBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+InputPort::NotifyConnectionChanged(bool aIsConnected)
+{
+  MOZ_ASSERT(mIsConnected != aIsConnected);
+  mIsConnected = aIsConnected;
+
+  nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
+    new AsyncEventDispatcher(this,
+                             aIsConnected ? NS_LITERAL_STRING("connect") :
+                                            NS_LITERAL_STRING("disconnect"),
+                             false);
+  asyncDispatcher->PostDOMEvent();
+}
+
+void
+InputPort::GetId(nsAString& aId) const
+{
+  aId = mId;
+}
+
+DOMMediaStream*
+InputPort::Stream() const
+{
+  return mStream;
+}
+
+bool
+InputPort::Connected() const
+{
+  return mIsConnected;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/inputport/InputPort.h
@@ -0,0 +1,59 @@
+/* -*- 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 mozilla_dom_InputPort_h
+#define mozilla_dom_InputPort_h
+
+#include "InputPortListeners.h"
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/InputPortBinding.h"
+#include "nsIInputPortService.h"
+
+namespace mozilla {
+
+class DOMMediaStream;
+
+namespace dom {
+
+class InputPort : public DOMEventTargetHelper
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(InputPort, DOMEventTargetHelper)
+
+  // WebIDL (internal functions)
+  virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  void NotifyConnectionChanged(bool aIsConnected);
+
+  // WebIDL (public APIs)
+  void GetId(nsAString& aId) const;
+
+  DOMMediaStream* Stream() const;
+
+  bool Connected() const;
+
+  IMPL_EVENT_HANDLER(connect);
+  IMPL_EVENT_HANDLER(disconnect);
+
+protected:
+  explicit InputPort(nsPIDOMWindow* aWindow);
+
+  virtual ~InputPort();
+
+  void Init(nsIInputPortData* aData, nsIInputPortListener* aListener, ErrorResult& aRv);
+  void Shutdown();
+
+  nsString mId;
+  nsRefPtr<DOMMediaStream> mStream;
+  nsRefPtr<InputPortListener> mInputPortListener;
+  bool mIsConnected;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_InputPort_h
new file mode 100644
--- /dev/null
+++ b/dom/inputport/InputPortData.cpp
@@ -0,0 +1,113 @@
+/* -*- 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/. */
+
+#include "InputPortData.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace dom {
+
+namespace {
+
+InputPortType
+ToInputPortType(const nsAString& aStr)
+{
+  if (aStr.EqualsLiteral("av")) {
+    return InputPortType::Av;
+  }
+
+  if (aStr.EqualsLiteral("displayport")) {
+    return InputPortType::Displayport;
+  }
+
+  if (aStr.EqualsLiteral("hdmi")) {
+    return InputPortType::Hdmi;
+  }
+
+  return InputPortType::EndGuard_;
+}
+
+} // namespace anonymous
+
+NS_IMPL_ISUPPORTS(InputPortData, nsIInputPortData)
+
+InputPortData::InputPortData()
+  : mIsConnected(false)
+{
+}
+
+InputPortData::~InputPortData()
+{
+}
+
+/* virtual */ NS_IMETHODIMP
+InputPortData::GetId(nsAString& aId)
+{
+  aId = mId;
+  return NS_OK;
+}
+
+/* virtual */ NS_IMETHODIMP
+InputPortData::SetId(const nsAString& aId)
+{
+  if (aId.IsEmpty()) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  mId = aId;
+  return NS_OK;
+}
+
+/* virtual */ NS_IMETHODIMP
+InputPortData::GetType(nsAString& aType)
+{
+  aType = mType;
+  return NS_OK;
+}
+
+/* virtual */ NS_IMETHODIMP
+InputPortData::SetType(const nsAString& aType)
+{
+  if (aType.IsEmpty()) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  if (InputPortType::EndGuard_ == ToInputPortType(aType)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  mType = aType;
+  return NS_OK;
+}
+
+/* virtual */ NS_IMETHODIMP
+InputPortData::GetConnected(bool* aIsConnected)
+{
+  *aIsConnected = mIsConnected;
+  return NS_OK;
+}
+
+/* virtual */ NS_IMETHODIMP
+InputPortData::SetConnected(const bool aIsConnected)
+{
+  mIsConnected = aIsConnected;
+  return NS_OK;
+}
+
+const nsString&
+InputPortData::GetId() const
+{
+  return mId;
+}
+
+const InputPortType
+InputPortData::GetType() const
+{
+  return ToInputPortType(mType);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/inputport/InputPortData.h
@@ -0,0 +1,49 @@
+/* -*- 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 mozilla_dom_InputPortData_h
+#define mozilla_dom_InputPortData_h
+
+#include "mozilla/dom/InputPortBinding.h"
+#include "nsIInputPortService.h"
+
+class nsString;
+
+namespace mozilla {
+namespace dom {
+
+enum class InputPortType : uint32_t
+{
+  Av,
+  Displayport,
+  Hdmi,
+  EndGuard_
+};
+
+class InputPortData final : public nsIInputPortData
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIINPUTPORTDATA
+
+  InputPortData();
+
+  const nsString& GetId() const;
+
+  const InputPortType GetType() const;
+
+private:
+  ~InputPortData();
+
+  nsString mId;
+  nsString mType;
+  bool mIsConnected;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_InputPortData_h
new file mode 100644
--- /dev/null
+++ b/dom/inputport/InputPortListeners.cpp
@@ -0,0 +1,54 @@
+/* -*- 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/. */
+
+#include "InputPortListeners.h"
+#include "mozilla/dom/InputPort.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION(InputPortListener, mInputPorts)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(InputPortListener)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(InputPortListener)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InputPortListener)
+  NS_INTERFACE_MAP_ENTRY(nsIInputPortListener)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+void
+InputPortListener::RegisterInputPort(InputPort* aPort)
+{
+  MOZ_ASSERT(!mInputPorts.Contains(aPort));
+  mInputPorts.AppendElement(aPort);
+}
+
+void
+InputPortListener::UnregisterInputPort(InputPort* aPort)
+{
+  MOZ_ASSERT(mInputPorts.Contains(aPort));
+  mInputPorts.RemoveElement(aPort);
+}
+
+/* virtual */ NS_IMETHODIMP
+InputPortListener::NotifyConnectionChanged(const nsAString& aPortId,
+                                           bool aIsConnected)
+{
+  for (uint32_t i = 0; i < mInputPorts.Length(); ++i) {
+    nsString id;
+    mInputPorts[i]->GetId(id);
+    if (aPortId.Equals(id)) {
+      mInputPorts[i]->NotifyConnectionChanged(aIsConnected);
+      break;
+    }
+  }
+
+  return NS_OK;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/inputport/InputPortListeners.h
@@ -0,0 +1,39 @@
+/* -*- 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 mozilla_dom_InputPortListeners_h
+#define mozilla_dom_InputPortListeners_h
+
+#include "nsCycleCollectionParticipant.h"
+#include "nsIInputPortService.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+
+class InputPort;
+
+class InputPortListener final : public nsIInputPortListener
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(InputPortListener)
+  NS_DECL_NSIINPUTPORTLISTENER
+
+  void RegisterInputPort(InputPort* aPort);
+
+  void UnregisterInputPort(InputPort* aPort);
+
+private:
+  ~InputPortListener() {}
+
+  nsTArray<nsRefPtr<InputPort>> mInputPorts;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_InputPortListeners_h
new file mode 100644
--- /dev/null
+++ b/dom/inputport/InputPortManager.cpp
@@ -0,0 +1,215 @@
+/* -*- 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/. */
+
+#include "InputPortServiceFactory.h"
+#include "mozilla/dom/InputPort.h"
+#include "mozilla/dom/InputPortManager.h"
+#include "mozilla/dom/InputPortManagerBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "nsArrayUtils.h"
+#include "nsIInputPortService.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(InputPortManager,
+                                      mParent,
+                                      mInputPortService,
+                                      mPendingGetInputPortsPromises,
+                                      mInputPorts)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(InputPortManager)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(InputPortManager)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InputPortManager)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsIInputPortServiceCallback)
+NS_INTERFACE_MAP_END
+
+InputPortManager::InputPortManager(nsPIDOMWindow* aWindow)
+  : mParent(aWindow)
+  , mIsReady(false)
+{
+}
+
+InputPortManager::~InputPortManager()
+{
+}
+
+/* static */ already_AddRefed<InputPortManager>
+InputPortManager::Create(nsPIDOMWindow* aWindow, ErrorResult& aRv)
+{
+  nsRefPtr<InputPortManager> manager = new InputPortManager(aWindow);
+  manager->Init(aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+  return manager.forget();
+}
+
+void
+InputPortManager::Init(ErrorResult& aRv)
+{
+  mInputPortService = InputPortServiceFactory::AutoCreateInputPortService();
+  if (NS_WARN_IF(!mInputPortService)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  aRv = mInputPortService->GetInputPorts(this);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+}
+
+nsPIDOMWindow*
+InputPortManager::GetParentObject() const
+{
+  return mParent;
+}
+
+JSObject*
+InputPortManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return InputPortManagerBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+InputPortManager::RejectPendingGetInputPortsPromises(nsresult aRv)
+{
+  // Reject pending promises.
+  uint32_t length = mPendingGetInputPortsPromises.Length();
+  for(uint32_t i = 0; i < length; i++) {
+    mPendingGetInputPortsPromises[i]->MaybeReject(aRv);
+  }
+  mPendingGetInputPortsPromises.Clear();
+}
+
+nsresult
+InputPortManager::SetInputPorts(const nsTArray<nsRefPtr<InputPort>>& aPorts)
+{
+  MOZ_ASSERT(!mIsReady);
+  // Should be called only when InputPortManager hasn't been ready yet.
+  if (mIsReady) {
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  }
+
+  mInputPorts = aPorts;
+  mIsReady = true;
+
+  // Resolve pending promises.
+  uint32_t length = mPendingGetInputPortsPromises.Length();
+  for(uint32_t i = 0; i < length; i++) {
+    mPendingGetInputPortsPromises[i]->MaybeResolve(mInputPorts);
+  }
+  mPendingGetInputPortsPromises.Clear();
+  return NS_OK;
+}
+
+already_AddRefed<Promise>
+InputPortManager::GetInputPorts(ErrorResult& aRv)
+{
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
+  MOZ_ASSERT(global);
+
+  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  if (mIsReady) {
+    promise->MaybeResolve(mInputPorts);
+  } else {
+    mPendingGetInputPortsPromises.AppendElement(promise);
+  }
+
+  return promise.forget();
+}
+
+NS_IMETHODIMP
+InputPortManager::NotifySuccess(nsIArray* aDataList)
+{
+  MOZ_ASSERT(aDataList);
+
+  if (!aDataList) {
+    RejectPendingGetInputPortsPromises(NS_ERROR_DOM_ABORT_ERR);
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  uint32_t length;
+  nsresult rv = aDataList->GetLength(&length);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIInputPortListener> portListener;
+  rv = mInputPortService->GetInputPortListener(
+    getter_AddRefs(portListener));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  ErrorResult erv;
+  nsTArray<nsRefPtr<InputPort>> ports(length);
+  for (uint32_t i = 0; i < length; i++) {
+    nsCOMPtr<nsIInputPortData> portData = do_QueryElementAt(aDataList, i);
+    if (NS_WARN_IF(!portData)) {
+      continue;
+    }
+
+    InputPortData* data = static_cast<InputPortData*>(portData.get());
+    nsRefPtr<InputPort> port;
+    switch (data->GetType()) {
+    case InputPortType::Av:
+      port = AVInputPort::Create(GetParentObject(), portListener,
+                                 portData, erv);
+      break;
+    case InputPortType::Displayport:
+      port = DisplayPortInputPort::Create(GetParentObject(),
+                                          portListener, portData, erv);
+      break;
+    case InputPortType::Hdmi:
+      port = HDMIInputPort::Create(GetParentObject(), portListener,
+                                   portData, erv);
+      break;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unknown InputPort type");
+      break;
+    }
+    MOZ_ASSERT(port);
+
+    ports.AppendElement(port);
+  }
+
+  if (NS_WARN_IF(erv.Failed())) {
+    return erv.ErrorCode();
+  }
+
+  erv = SetInputPorts(ports);
+
+  return erv.ErrorCode();
+}
+
+NS_IMETHODIMP
+InputPortManager::NotifyError(uint16_t aErrorCode)
+{
+  switch (aErrorCode) {
+  case nsIInputPortServiceCallback::INPUTPORT_ERROR_FAILURE:
+  case nsIInputPortServiceCallback::INPUTPORT_ERROR_INVALID_ARG:
+    RejectPendingGetInputPortsPromises(NS_ERROR_DOM_ABORT_ERR);
+    return NS_OK;
+  case nsIInputPortServiceCallback::INPUTPORT_ERROR_NOT_SUPPORTED:
+    RejectPendingGetInputPortsPromises(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return NS_OK;
+  }
+
+  RejectPendingGetInputPortsPromises(NS_ERROR_DOM_ABORT_ERR);
+  return NS_ERROR_ILLEGAL_VALUE;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/inputport/InputPortManager.h
@@ -0,0 +1,62 @@
+/* -*- 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 mozilla_dom_InputPortManager_h
+#define mozilla_dom_InputPortManager_h
+
+#include "nsIInputPortService.h"
+#include "nsISupports.h"
+#include "nsWrapperCache.h"
+
+class nsIInputPortService;
+class nsPIDOMWindow;
+
+namespace mozilla {
+namespace dom {
+
+class Promise;
+class InputPort;
+
+class InputPortManager final : public nsIInputPortServiceCallback,
+                               public nsWrapperCache
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(InputPortManager)
+  NS_DECL_NSIINPUTPORTSERVICECALLBACK
+
+  static already_AddRefed<InputPortManager> Create(nsPIDOMWindow* aWindow, ErrorResult& aRv);
+
+  // WebIDL (internal functions)
+  nsPIDOMWindow* GetParentObject() const;
+
+  virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  // WebIDL (public APIs)
+  already_AddRefed<Promise> GetInputPorts(ErrorResult& aRv);
+
+private:
+  explicit InputPortManager(nsPIDOMWindow* aWindow);
+
+  ~InputPortManager();
+
+  void Init(ErrorResult& aRv);
+
+  void RejectPendingGetInputPortsPromises(nsresult aRv);
+
+  nsresult SetInputPorts(const nsTArray<nsRefPtr<InputPort>>& aPorts);
+
+  nsTArray<nsRefPtr<Promise>> mPendingGetInputPortsPromises;
+  nsTArray<nsRefPtr<InputPort>> mInputPorts;
+  nsCOMPtr<nsPIDOMWindow> mParent;
+  nsCOMPtr<nsIInputPortService> mInputPortService;
+  bool mIsReady;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_InputPortManager_h__
new file mode 100644
--- /dev/null
+++ b/dom/inputport/InputPortServiceFactory.cpp
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "FakeInputPortService.h"
+#include "InputPortListeners.h"
+#include "InputPortServiceFactory.h"
+#include "mozilla/Preferences.h"
+#include "nsIInputPortService.h"
+#include "nsServiceManagerUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+/* static */ already_AddRefed<FakeInputPortService>
+InputPortServiceFactory::CreateFakeInputPortService()
+{
+  nsRefPtr<FakeInputPortService> service = new FakeInputPortService();
+  return service.forget();
+}
+
+/* static */ already_AddRefed<nsIInputPortService>
+InputPortServiceFactory::AutoCreateInputPortService()
+{
+  nsresult rv;
+  nsCOMPtr<nsIInputPortService> service =
+    do_GetService(INPUTPORT_SERVICE_CONTRACTID);
+  if (!service) {
+    // Fallback to the fake service.
+    service = do_GetService(FAKE_INPUTPORT_SERVICE_CONTRACTID, &rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return nullptr;
+    }
+  }
+  MOZ_ASSERT(service);
+  rv = service->SetInputPortListener(new InputPortListener());
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  return service.forget();
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/inputport/InputPortServiceFactory.h
@@ -0,0 +1,30 @@
+/* -*- 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 mozilla_dom_InputPortServiceFactory_h
+#define mozilla_dom_InputPortServiceFactory_h
+
+#include "nsCOMPtr.h"
+
+class nsIInputPortService;
+
+namespace mozilla {
+namespace dom {
+
+class FakeInputPortService;
+
+class InputPortServiceFactory final
+{
+public:
+  static already_AddRefed<FakeInputPortService> CreateFakeInputPortService();
+
+  static already_AddRefed<nsIInputPortService> AutoCreateInputPortService();
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_InputPortServiceFactory_h
new file mode 100644
--- /dev/null
+++ b/dom/inputport/moz.build
@@ -0,0 +1,48 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+EXPORTS.mozilla.dom += [
+    'AVInputPort.h',
+    'DisplayPortInputPort.h',
+    'HDMIInputPort.h',
+    'InputPort.h',
+    'InputPortManager.h',
+]
+
+EXPORTS += [
+    'FakeInputPortService.h',
+    'InputPortData.h',
+    'InputPortListeners.h',
+    'InputPortServiceFactory.h',
+]
+
+UNIFIED_SOURCES += [
+    'AVInputPort.cpp',
+    'DisplayPortInputPort.cpp',
+    'FakeInputPortService.cpp',
+    'HDMIInputPort.cpp',
+    'InputPort.cpp',
+    'InputPortData.cpp',
+    'InputPortListeners.cpp',
+    'InputPortManager.cpp',
+    'InputPortServiceFactory.cpp',
+]
+
+XPIDL_SOURCES += [
+    'nsIInputPortService.idl',
+]
+
+XPIDL_MODULE = 'dom_inputport'
+
+MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
+
+XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell/xpcshell.ini']
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
+
+FAIL_ON_WARNINGS = True
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/inputport/nsIInputPortService.idl
@@ -0,0 +1,75 @@
+/* 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 "nsISupports.idl"
+
+interface nsIArray;
+
+%{C++
+#define INPUTPORT_DATA_CID \
+  { 0x90b192d1, 0x357a, 0x4793, { 0xab, 0x58, 0x04, 0xee, 0x21, 0x62, 0x27, 0xda } }
+#define INPUTPORT_DATA_CONTRACTID \
+  "@mozilla.org/inputport/inputportdata;1"
+%}
+
+/**
+ * XPCOM component which acts as the container for input port data.
+ */
+[scriptable, builtinclass, uuid(244a2b1d-aa1f-4188-a639-ddb56c554b6d)]
+interface nsIInputPortData : nsISupports
+{
+  attribute DOMString id;
+  attribute DOMString type;
+  attribute boolean connected;
+};
+
+[builtinclass, uuid(32a62e7c-f698-4846-81f7-617c87854d32)]
+interface nsIInputPortListener : nsISupports
+{
+  void notifyConnectionChanged(in DOMString portId,
+                               in boolean isConnected);
+};
+
+[builtinclass, uuid(c2a47757-25f6-4bc8-bd27-c23af2d87381)]
+interface nsIInputPortServiceCallback : nsISupports
+{
+  const unsigned short INPUTPORT_ERROR_OK = 0;
+  const unsigned short INPUTPORT_ERROR_FAILURE = 1;
+  const unsigned short INPUTPORT_ERROR_INVALID_ARG = 2;
+  const unsigned short INPUTPORT_ERROR_NOT_SUPPORTED = 3;
+
+  /**
+   * Called when something wrong happens.
+   *
+   * @param errorCode Error code listed above from the underlying layer.
+   */
+  void notifyError(in unsigned short errorCode);
+
+  /**
+   * Called when the operation succeeds.
+   *
+   * @param dataList A list of data.
+   *                 An array of |nsIInputPortData| when used for |getInputPorts()|.
+   *
+   * NOTE: |nsIArray| is adopted to prevent this interface from being split into
+   * multiple interfaces with different |notifySuccess|. Though the
+   * implementation of TV service may need |nsIMutableArray| to fill in the
+   * array, it doesn't seem necessary for other places to use the mutable one.
+   */
+  void notifySuccess([optional] in nsIArray dataList);
+};
+
+
+%{C++
+#define INPUTPORT_SERVICE_CONTRACTID \
+  "@mozilla.org/inputport/inputportservice;1"
+%}
+
+[uuid(6214dae0-840e-11e4-b4a9-0800200c9a66)]
+interface nsIInputPortService : nsISupports
+{
+  attribute nsIInputPortListener inputPortListener;
+
+  void getInputPorts(in nsIInputPortServiceCallback callback);
+};
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -61,16 +61,17 @@ DIRS += [
     'events',
     'fetch',
     'filehandle',
     'filesystem',
     'fmradio',
     'geolocation',
     'html',
     'icc',
+    'inputport',
     'json',
     'jsurl',
     'asmjscache',
     'mathml',
     'media',
     'messages',
     'mobileconnection',
     'notification',
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -158,16 +158,18 @@ var interfaceNamesInGlobalScope =
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "AudioNode",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "AudioParam",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "AudioProcessingEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "AudioStreamTrack",
+    // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "AVInputPort", b2g: true, pref: "dom.inputport.enabled", permission: ["inputport"]},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "BarProp",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "BatteryManager",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "BeforeAfterKeyboardEvent", b2g: true,
      pref: "dom.beforeAfterKeyboardEvent.enabled",
      permission: ["embed-apps", "before-after-keyboard-event"]},
@@ -339,16 +341,18 @@ var interfaceNamesInGlobalScope =
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DeviceOrientationEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DeviceProximityEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "DeviceStorage", pref: "device.storage.enabled" },
 // IMPORTANT: Do not change this list without review from a DOM peer!
     { name: "DeviceStorageChangeEvent", pref: "device.storage.enabled" },
+    // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "DisplayPortInputPort", b2g: true, pref: "dom.inputport.enabled", permission: ["inputport"]},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Document",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DocumentFragment",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "DocumentType",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "DOMConstructor", xbl: true},
@@ -435,16 +439,18 @@ var interfaceNamesInGlobalScope =
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "GamepadEvent", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HashChangeEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Headers",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "History",
+    // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "HDMIInputPort", b2g: true, pref: "dom.inputport.enabled", permission: ["inputport"]},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "HMDVRDevice", pref: "dom.vr.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLAllCollection",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLAnchorElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLAppletElement",
@@ -630,16 +636,20 @@ var interfaceNamesInGlobalScope =
     {name: "ImageCapture", pref: "dom.imagecapture.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "ImageCaptureErrorEvent", pref: "dom.imagecapture.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ImageData",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "InputEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "InputPort", b2g: true, pref: "dom.inputport.enabled", permission: ["inputport"]},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "InputPortManager", b2g: true, pref: "dom.inputport.enabled", permission: ["inputport"]},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "InstallTrigger", b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "KeyEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "KeyboardEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "LocalMediaStream",
 // IMPORTANT: Do not change this list without review from a DOM peer!
new file mode 100644
--- /dev/null
+++ b/dom/webidl/AVInputPort.webidl
@@ -0,0 +1,9 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ */
+
+[Pref="dom.inputport.enabled", CheckPermissions="inputport", AvailableIn=CertifiedApps]
+ interface AVInputPort : InputPort {
+ };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/DisplayPortInputPort.webidl
@@ -0,0 +1,9 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ */
+
+[Pref="dom.inputport.enabled", CheckPermissions="inputport", AvailableIn=CertifiedApps]
+ interface DisplayPortInputPort : InputPort {
+ };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/HDMIInputPort.webidl
@@ -0,0 +1,9 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ */
+
+[Pref="dom.inputport.enabled", CheckPermissions="inputport", AvailableIn=CertifiedApps]
+ interface HDMIInputPort : InputPort {
+ };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/InputPort.webidl
@@ -0,0 +1,16 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ *
+ * Reference https://wiki.mozilla.org/User:Shellylin/InputPort#Basic_Port_Interface
+ */
+
+[Pref="dom.inputport.enabled", CheckPermissions="inputport", AvailableIn=CertifiedApps]
+interface InputPort : EventTarget {
+  readonly attribute DOMString id;
+  readonly attribute MediaStream stream;
+  readonly attribute boolean connected;
+  attribute EventHandler onconnect;
+  attribute EventHandler ondisconnect;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/InputPortManager.webidl
@@ -0,0 +1,13 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ *
+ * Reference https://wiki.mozilla.org/User:Shellylin/InputPort#InputPortManager
+ */
+
+[Pref="dom.inputport.enabled", CheckPermissions="inputport", AvailableIn=CertifiedApps]
+ interface InputPortManager {
+   [Throws]
+   Promise<sequence<InputPort>> getInputPorts();
+ };
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -407,16 +407,21 @@ partial interface Navigator {
                      optional (ArrayBufferView or Blob or DOMString or FormData)? data = null);
 };
 
 partial interface Navigator {
   [Pref="dom.tv.enabled", CheckPermissions="tv", Func="Navigator::HasTVSupport"]
   readonly attribute TVManager? tv;
 };
 
+partial interface Navigator {
+  [Throws, Pref="dom.inputport.enabled", CheckPermissions="inputport", AvailableIn=CertifiedApps]
+  readonly attribute InputPortManager inputPortManager;
+};
+
 #ifdef MOZ_EME
 partial interface Navigator {
   [Pref="media.eme.apiVisible", NewObject]
   Promise<MediaKeySystemAccess>
   requestMediaKeySystemAccess(DOMString keySystem,
                               optional sequence<MediaKeySystemOptions> supportedConfigurations);
 };
 #endif
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -42,16 +42,17 @@ WEBIDL_FILES = [
     'AudioListener.webidl',
     'AudioNode.webidl',
     'AudioParam.webidl',
     'AudioProcessingEvent.webidl',
     'AudioStreamTrack.webidl',
     'AudioTrack.webidl',
     'AudioTrackList.webidl',
     'AutocompleteInfo.webidl',
+    'AVInputPort.webidl',
     'BarProp.webidl',
     'BatteryManager.webidl',
     'BeforeAfterKeyboardEvent.webidl',
     'BeforeUnloadEvent.webidl',
     'BiquadFilterNode.webidl',
     'Blob.webidl',
     'BoxObject.webidl',
     'BroadcastChannel.webidl',
@@ -98,16 +99,17 @@ WEBIDL_FILES = [
     'DataStoreImpl.webidl',
     'DataTransfer.webidl',
     'DedicatedWorkerGlobalScope.webidl',
     'DelayNode.webidl',
     'DesktopNotification.webidl',
     'DeviceMotionEvent.webidl',
     'DeviceStorage.webidl',
     'Directory.webidl',
+    'DisplayPortInputPort.webidl',
     'Document.webidl',
     'DocumentFragment.webidl',
     'DocumentType.webidl',
     'DOMCursor.webidl',
     'DOMError.webidl',
     'DOMException.webidl',
     'DOMImplementation.webidl',
     'DOMMatrix.webidl',
@@ -147,16 +149,17 @@ WEBIDL_FILES = [
     'FontFaceSet.webidl',
     'FontFaceSource.webidl',
     'FormData.webidl',
     'Function.webidl',
     'GainNode.webidl',
     'Geolocation.webidl',
     'GeometryUtils.webidl',
     'GetUserMediaRequest.webidl',
+    'HDMIInputPort.webidl',
     'Headers.webidl',
     'History.webidl',
     'HTMLAllCollection.webidl',
     'HTMLAnchorElement.webidl',
     'HTMLAppletElement.webidl',
     'HTMLAreaElement.webidl',
     'HTMLAudioElement.webidl',
     'HTMLBaseElement.webidl',
@@ -244,16 +247,18 @@ WEBIDL_FILES = [
     'IDBRequest.webidl',
     'IDBTransaction.webidl',
     'IDBVersionChangeEvent.webidl',
     'ImageCapture.webidl',
     'ImageData.webidl',
     'ImageDocument.webidl',
     'InputEvent.webidl',
     'InputMethod.webidl',
+    'InputPort.webidl',
+    'InputPortManager.webidl',
     'InspectorUtils.webidl',
     'InstallEvent.webidl',
     'InterAppConnection.webidl',
     'InterAppConnectionRequest.webidl',
     'InterAppMessagePort.webidl',
     'KeyAlgorithm.webidl',
     'KeyboardEvent.webidl',
     'KeyEvent.webidl',
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -236,16 +236,21 @@ static void Shutdown();
 #include "nsITelephonyService.h"
 #include "nsIVoicemailService.h"
 
 #include "mozilla/dom/FakeTVService.h"
 #include "mozilla/dom/TVServiceFactory.h"
 #include "mozilla/dom/TVTypes.h"
 #include "nsITVService.h"
 
+#include "FakeInputPortService.h"
+#include "InputPortData.h"
+#include "InputPortServiceFactory.h"
+#include "nsIInputPortService.h"
+
 #ifdef MOZ_WIDGET_GONK
 #include "GonkGPSGeolocationProvider.h"
 #endif
 #include "MediaManager.h"
 
 #include "GMPService.h"
 
 #include "mozilla/dom/presentation/PresentationDeviceManager.h"
@@ -378,17 +383,19 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR
                                          NS_CreateVoicemailService)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(FakeTVService,
                                          TVServiceFactory::CreateFakeTVService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(TVTunerData)
 NS_GENERIC_FACTORY_CONSTRUCTOR(TVChannelData)
 NS_GENERIC_FACTORY_CONSTRUCTOR(TVProgramData)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PresentationDeviceManager)
 NS_GENERIC_FACTORY_CONSTRUCTOR(TextInputProcessor)
-
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(FakeInputPortService,
+                                         InputPortServiceFactory::CreateFakeInputPortService)
+NS_GENERIC_FACTORY_CONSTRUCTOR(InputPortData)
 //-----------------------------------------------------------------------------
 
 static bool gInitialized = false;
 
 // Perform our one-time intialization for this module
 
 // static
 nsresult
@@ -821,16 +828,19 @@ NS_DEFINE_NAMED_CID(NS_SYNTHVOICEREGISTR
 #ifdef ACCESSIBILITY
 NS_DEFINE_NAMED_CID(NS_ACCESSIBILITY_SERVICE_CID);
 #endif
 NS_DEFINE_NAMED_CID(FAKE_TV_SERVICE_CID);
 NS_DEFINE_NAMED_CID(TV_TUNER_DATA_CID);
 NS_DEFINE_NAMED_CID(TV_CHANNEL_DATA_CID);
 NS_DEFINE_NAMED_CID(TV_PROGRAM_DATA_CID);
 
+NS_DEFINE_NAMED_CID(FAKE_INPUTPORT_SERVICE_CID);
+NS_DEFINE_NAMED_CID(INPUTPORT_DATA_CID);
+
 NS_DEFINE_NAMED_CID(GECKO_MEDIA_PLUGIN_SERVICE_CID);
 
 NS_DEFINE_NAMED_CID(PRESENTATION_DEVICE_MANAGER_CID);
 
 NS_DEFINE_NAMED_CID(TEXT_INPUT_PROCESSOR_CID);
 
 static nsresult
 CreateWindowCommandTableConstructor(nsISupports *aOuter,
@@ -1117,16 +1127,18 @@ static const mozilla::Module::CIDEntry k
   { &kNS_MOBILE_CONNECTION_SERVICE_CID, false, NULL, nsIMobileConnectionServiceConstructor },
   { &kNS_VOICEMAIL_SERVICE_CID, false, nullptr, nsIVoicemailServiceConstructor },
   { &kFAKE_TV_SERVICE_CID, false, nullptr, FakeTVServiceConstructor },
   { &kTV_TUNER_DATA_CID, false, nullptr, TVTunerDataConstructor },
   { &kTV_CHANNEL_DATA_CID, false, nullptr, TVChannelDataConstructor },
   { &kTV_PROGRAM_DATA_CID, false, nullptr, TVProgramDataConstructor },
   { &kPRESENTATION_DEVICE_MANAGER_CID, false, nullptr, PresentationDeviceManagerConstructor },
   { &kTEXT_INPUT_PROCESSOR_CID, false, nullptr, TextInputProcessorConstructor },
+  { &kFAKE_INPUTPORT_SERVICE_CID, false, nullptr, FakeInputPortServiceConstructor },
+  { &kINPUTPORT_DATA_CID, false, nullptr, InputPortDataConstructor },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
   XPCONNECT_CONTRACTS
   { "@mozilla.org/layout/xul-boxobject;1", &kNS_BOXOBJECT_CID },
 #ifdef MOZ_XUL
   { "@mozilla.org/layout/xul-boxobject-listbox;1", &kNS_LISTBOXOBJECT_CID },
@@ -1278,16 +1290,18 @@ static const mozilla::Module::ContractID
   { TV_TUNER_DATA_CONTRACTID, &kTV_TUNER_DATA_CID },
   { TV_CHANNEL_DATA_CONTRACTID, &kTV_CHANNEL_DATA_CID },
   { TV_PROGRAM_DATA_CONTRACTID, &kTV_PROGRAM_DATA_CID },
   { "@mozilla.org/gecko-media-plugin-service;1",  &kGECKO_MEDIA_PLUGIN_SERVICE_CID },
   { NS_MOBILE_CONNECTION_SERVICE_CONTRACTID, &kNS_MOBILE_CONNECTION_SERVICE_CID },
   { NS_VOICEMAIL_SERVICE_CONTRACTID, &kNS_VOICEMAIL_SERVICE_CID },
   { PRESENTATION_DEVICE_MANAGER_CONTRACTID, &kPRESENTATION_DEVICE_MANAGER_CID },
   { "@mozilla.org/text-input-processor;1", &kTEXT_INPUT_PROCESSOR_CID },
+  { FAKE_INPUTPORT_SERVICE_CONTRACTID, &kFAKE_INPUTPORT_SERVICE_CID },
+  { INPUTPORT_DATA_CONTRACTID, &kINPUTPORT_DATA_CID },
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kLayoutCategories[] = {
   XPCONNECT_CATEGORIES
   { "content-policy", NS_DATADOCUMENTCONTENTPOLICY_CONTRACTID, NS_DATADOCUMENTCONTENTPOLICY_CONTRACTID },
   { "content-policy", NS_NODATAPROTOCOLCONTENTPOLICY_CONTRACTID, NS_NODATAPROTOCOLCONTENTPOLICY_CONTRACTID },
   { "content-policy", "CSPService", CSPSERVICE_CONTRACTID },