Bug 1234492 - Part 1 - Add direction in PresentationService. r=smaug
☠☠ backed out by 1450d0e37119 ☠ ☠
authorTommy Kuo <kuoe0.tw@gmail.com>
Mon, 21 Mar 2016 01:52:00 +0100
changeset 328839 f74a43d0b9eb6b7a3ae5e03c508eab14ac01620e
parent 328838 2ba85d06b69b916f1e65c946a022b617b74ffb27
child 328840 75aff80f34a50705e0d0bed418ba7ff546869e49
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1234492
milestone48.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 1234492 - Part 1 - Add direction in PresentationService. r=smaug
dom/ipc/ContentChild.cpp
dom/presentation/PresentationCallbacks.cpp
dom/presentation/PresentationConnection.cpp
dom/presentation/PresentationConnection.h
dom/presentation/PresentationReceiver.cpp
dom/presentation/PresentationService.cpp
dom/presentation/PresentationService.h
dom/presentation/PresentationSessionInfo.cpp
dom/presentation/PresentationSessionInfo.h
dom/presentation/interfaces/nsIPresentationService.idl
dom/presentation/ipc/PPresentation.ipdl
dom/presentation/ipc/PresentationIPCService.cpp
dom/presentation/ipc/PresentationParent.cpp
dom/presentation/ipc/PresentationParent.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1695,17 +1695,17 @@ ContentChild::RecvNotifyPresentationRece
 
 bool
 ContentChild::RecvNotifyPresentationReceiverCleanUp(const nsString& aSessionId)
 {
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   NS_WARN_IF(!service);
 
-  NS_WARN_IF(NS_FAILED(service->UntrackSessionInfo(aSessionId)));
+  NS_WARN_IF(NS_FAILED(service->UntrackSessionInfo(aSessionId, nsIPresentationService::ROLE_RECEIVER)));
 
   return true;
 }
 
 bool
 ContentChild::RecvNotifyGMPsChanged()
 {
   GMPDecoderModule::UpdateUsableCodecs();
--- a/dom/presentation/PresentationCallbacks.cpp
+++ b/dom/presentation/PresentationCallbacks.cpp
@@ -45,16 +45,17 @@ NS_IMETHODIMP
 PresentationRequesterCallback::NotifySuccess()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // At the sender side, this function must get called after the transport
   // channel is ready. So we simply set the connection state as connected.
   RefPtr<PresentationConnection> connection =
     PresentationConnection::Create(mRequest->GetOwner(), mSessionId,
+                                   nsIPresentationService::ROLE_CONTROLLER,
                                    PresentationConnectionState::Connected);
   if (NS_WARN_IF(!connection)) {
     mPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
     return NS_OK;
   }
 
   mPromise->MaybeResolve(connection);
 
--- a/dom/presentation/PresentationConnection.cpp
+++ b/dom/presentation/PresentationConnection.cpp
@@ -30,68 +30,75 @@ NS_IMPL_ADDREF_INHERITED(PresentationCon
 NS_IMPL_RELEASE_INHERITED(PresentationConnection, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PresentationConnection)
   NS_INTERFACE_MAP_ENTRY(nsIPresentationSessionListener)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 PresentationConnection::PresentationConnection(nsPIDOMWindowInner* aWindow,
                                                const nsAString& aId,
+                                               const uint8_t aRole,
                                                PresentationConnectionState aState)
   : DOMEventTargetHelper(aWindow)
   , mId(aId)
   , mState(aState)
 {
+  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+             aRole == nsIPresentationService::ROLE_RECEIVER);
+  mRole = aRole;
 }
 
 /* virtual */ PresentationConnection::~PresentationConnection()
 {
 }
 
 /* static */ already_AddRefed<PresentationConnection>
 PresentationConnection::Create(nsPIDOMWindowInner* aWindow,
                                const nsAString& aId,
+                               const uint8_t aRole,
                                PresentationConnectionState aState)
 {
+  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+             aRole == nsIPresentationService::ROLE_RECEIVER);
   RefPtr<PresentationConnection> connection =
-    new PresentationConnection(aWindow, aId, aState);
+    new PresentationConnection(aWindow, aId, aRole, aState);
   return NS_WARN_IF(!connection->Init()) ? nullptr : connection.forget();
 }
 
 bool
 PresentationConnection::Init()
 {
   if (NS_WARN_IF(mId.IsEmpty())) {
     return false;
   }
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if(NS_WARN_IF(!service)) {
     return false;
   }
 
-  nsresult rv = service->RegisterSessionListener(mId, this);
+  nsresult rv = service->RegisterSessionListener(mId, mRole, this);
   if(NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
   return true;
 }
 
 void
 PresentationConnection::Shutdown()
 {
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!service)) {
     return;
   }
 
-  nsresult rv = service->UnregisterSessionListener(mId);
+  nsresult rv = service->UnregisterSessionListener(mId, mRole);
   NS_WARN_IF(NS_FAILED(rv));
 }
 
 /* virtual */ void
 PresentationConnection::DisconnectFromOwner()
 {
   Shutdown();
   DOMEventTargetHelper::DisconnectFromOwner();
@@ -143,17 +150,17 @@ PresentationConnection::Send(const nsASt
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if(NS_WARN_IF(!service)) {
     aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
     return;
   }
 
-  rv = service->SendSessionMessage(mId, stream);
+  rv = service->SendSessionMessage(mId, mRole, stream);
   if(NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
   }
 }
 
 void
 PresentationConnection::Close(ErrorResult& aRv)
 {
@@ -176,17 +183,17 @@ PresentationConnection::Terminate(ErrorR
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if(NS_WARN_IF(!service)) {
     aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
     return;
   }
 
-  NS_WARN_IF(NS_FAILED(service->TerminateSession(mId)));
+  NS_WARN_IF(NS_FAILED(service->TerminateSession(mId, mRole)));
 }
 
 NS_IMETHODIMP
 PresentationConnection::NotifyStateChange(const nsAString& aSessionId,
                                        uint16_t aState)
 {
   if (!aSessionId.Equals(mId)) {
     return NS_ERROR_INVALID_ARG;
@@ -217,17 +224,17 @@ PresentationConnection::NotifyStateChang
   // Unregister session listener if the session is no longer connected.
   if (mState == PresentationConnectionState::Terminated) {
     nsCOMPtr<nsIPresentationService> service =
       do_GetService(PRESENTATION_SERVICE_CONTRACTID);
     if (NS_WARN_IF(!service)) {
       return NS_ERROR_NOT_AVAILABLE;
     }
 
-    nsresult rv = service->UnregisterSessionListener(mId);
+    nsresult rv = service->UnregisterSessionListener(mId, mRole);
     if(NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   return DispatchStateChangeEvent();
 }
 
--- a/dom/presentation/PresentationConnection.h
+++ b/dom/presentation/PresentationConnection.h
@@ -20,16 +20,17 @@ class PresentationConnection final : pub
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PresentationConnection,
                                            DOMEventTargetHelper)
   NS_DECL_NSIPRESENTATIONSESSIONLISTENER
 
   static already_AddRefed<PresentationConnection> Create(nsPIDOMWindowInner* aWindow,
                                                          const nsAString& aId,
+                                                         const uint8_t aRole,
                                                          PresentationConnectionState aState);
 
   virtual void DisconnectFromOwner() override;
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
   // WebIDL (public APIs)
@@ -45,28 +46,30 @@ public:
   void Terminate(ErrorResult& aRv);
 
   IMPL_EVENT_HANDLER(statechange);
   IMPL_EVENT_HANDLER(message);
 
 private:
   PresentationConnection(nsPIDOMWindowInner* aWindow,
                          const nsAString& aId,
+                         const uint8_t aRole,
                          PresentationConnectionState aState);
 
   ~PresentationConnection();
 
   bool Init();
 
   void Shutdown();
 
   nsresult DispatchStateChangeEvent();
 
   nsresult DispatchMessageEvent(JS::Handle<JS::Value> aData);
 
   nsString mId;
+  uint8_t mRole;
   PresentationConnectionState mState;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_PresentationConnection_h
--- a/dom/presentation/PresentationReceiver.cpp
+++ b/dom/presentation/PresentationReceiver.cpp
@@ -167,16 +167,17 @@ PresentationReceiver::NotifySessionConne
   }
 
   if (NS_WARN_IF(aWindowId != GetOwner()->WindowID())) {
     return NS_ERROR_INVALID_ARG;
   }
 
   RefPtr<PresentationConnection> connection =
     PresentationConnection::Create(GetOwner(), aSessionId,
+                                   nsIPresentationService::ROLE_RECEIVER,
                                    PresentationConnectionState::Closed);
   if (NS_WARN_IF(!connection)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   mConnections.AppendElement(connection);
 
   // Resolve pending |GetConnection| promises if any.
   if (!mPendingGetConnectionPromises.IsEmpty()) {
--- a/dom/presentation/PresentationService.cpp
+++ b/dom/presentation/PresentationService.cpp
@@ -1,9 +1,10 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ipc/PresentationIPCService.h"
 #include "mozilla/Services.h"
 #include "mozIApplication.h"
 #include "nsIAppsService.h"
@@ -95,17 +96,18 @@ PresentationDeviceRequest::Select(nsIPre
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!service)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Update device in the session info.
   RefPtr<PresentationSessionInfo> info =
-    static_cast<PresentationService*>(service.get())->GetSessionInfo(mId);
+    static_cast<PresentationService*>(service.get())->
+      GetSessionInfo(mId, nsIPresentationService::ROLE_CONTROLLER);
   if (NS_WARN_IF(!info)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   info->SetDevice(aDevice);
 
   // Establish a control channel. If we failed to do so, the callback is called
   // with an error message.
   nsCOMPtr<nsIPresentationControlChannel> ctrlChannel;
@@ -128,17 +130,18 @@ PresentationDeviceRequest::Cancel()
 {
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!service)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   RefPtr<PresentationSessionInfo> info =
-    static_cast<PresentationService*>(service.get())->GetSessionInfo(mId);
+    static_cast<PresentationService*>(service.get())->
+      GetSessionInfo(mId, nsIPresentationService::ROLE_CONTROLLER);
   if (NS_WARN_IF(!info)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return info->ReplyError(NS_ERROR_DOM_ABORT_ERR);
 }
 
 /*
@@ -219,17 +222,18 @@ PresentationService::Observe(nsISupports
 
 void
 PresentationService::HandleShutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mAvailabilityListeners.Clear();
   mRespondingListeners.Clear();
-  mSessionInfo.Clear();
+  mSessionInfoAtController.Clear();
+  mSessionInfoAtReceiver.Clear();
   mRespondingSessionIds.Clear();
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (obs) {
     obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
     obs->RemoveObserver(this, PRESENTATION_DEVICE_CHANGE_TOPIC);
     obs->RemoveObserver(this, PRESENTATION_SESSION_REQUEST_TOPIC);
   }
@@ -306,31 +310,32 @@ PresentationService::HandleSessionReques
 
   if (NS_WARN_IF(isApp && !IsAppInstalled(uri))) {
     ctrlChannel->Close(NS_ERROR_DOM_NOT_FOUND_ERR);
     return NS_OK;
   }
 #endif
 
   // Create or reuse session info.
-  RefPtr<PresentationSessionInfo> info = GetSessionInfo(sessionId);
+  RefPtr<PresentationSessionInfo> info =
+    GetSessionInfo(sessionId, nsIPresentationService::ROLE_RECEIVER);
   if (NS_WARN_IF(info)) {
     // TODO Bug 1195605. Update here after session join/resume becomes supported.
     ctrlChannel->Close(NS_ERROR_DOM_OPERATION_ERR);
     return NS_ERROR_DOM_ABORT_ERR;
   }
 
   info = new PresentationPresentingInfo(url, sessionId, device);
   rv = info->Init(ctrlChannel);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     ctrlChannel->Close(rv);
     return rv;
   }
 
-  mSessionInfo.Put(sessionId, info);
+  mSessionInfoAtReceiver.Put(sessionId, info);
 
   // Notify the receiver to launch.
   nsCOMPtr<nsIPresentationRequestUIGlue> glue =
     do_CreateInstance(PRESENTATION_REQUEST_UI_GLUE_CONTRACTID);
   if (NS_WARN_IF(!glue)) {
     ctrlChannel->Close(NS_ERROR_DOM_OPERATION_ERR);
     return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
   }
@@ -393,17 +398,17 @@ PresentationService::StartSession(const 
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aCallback);
   MOZ_ASSERT(!aSessionId.IsEmpty());
 
   // Create session info  and set the callback. The callback is called when the
   // request is finished.
   RefPtr<PresentationSessionInfo> info =
     new PresentationControllingInfo(aUrl, aSessionId, aCallback);
-  mSessionInfo.Put(aSessionId, info);
+  mSessionInfoAtController.Put(aSessionId, info);
 
   nsCOMPtr<nsIPresentationDeviceRequest> request =
     new PresentationDeviceRequest(aUrl, aSessionId, aOrigin);
 
   if (aDeviceId.IsVoid()) {
     // Pop up a prompt and ask user to select a device.
     nsCOMPtr<nsIPresentationDevicePrompt> prompt =
       do_GetService(PRESENTATION_DEVICE_PROMPT_CONTRACTID);
@@ -455,51 +460,60 @@ PresentationService::StartSession(const 
   }
 
   // Reject if designated device is not available.
   return info->ReplyError(NS_ERROR_DOM_NOT_FOUND_ERR);
 }
 
 NS_IMETHODIMP
 PresentationService::SendSessionMessage(const nsAString& aSessionId,
+                                        uint8_t aRole,
                                         nsIInputStream* aStream)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aStream);
   MOZ_ASSERT(!aSessionId.IsEmpty());
+  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+             aRole == nsIPresentationService::ROLE_RECEIVER);
 
-  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
+  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
   if (NS_WARN_IF(!info)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return info->Send(aStream);
 }
 
 NS_IMETHODIMP
-PresentationService::CloseSession(const nsAString& aSessionId)
+PresentationService::CloseSession(const nsAString& aSessionId,
+                                  uint8_t aRole)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!aSessionId.IsEmpty());
+  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+             aRole == nsIPresentationService::ROLE_RECEIVER);
 
-  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
+  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
   if (NS_WARN_IF(!info)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return info->Close(NS_OK, nsIPresentationSessionListener::STATE_CLOSED);
 }
 
 NS_IMETHODIMP
-PresentationService::TerminateSession(const nsAString& aSessionId)
+PresentationService::TerminateSession(const nsAString& aSessionId,
+                                      uint8_t aRole)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!aSessionId.IsEmpty());
+  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+             aRole == nsIPresentationService::ROLE_RECEIVER);
 
-  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
+  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
   if (NS_WARN_IF(!info)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return info->Close(NS_OK, nsIPresentationSessionListener::STATE_TERMINATED);
 }
 
 NS_IMETHODIMP
@@ -521,22 +535,25 @@ PresentationService::UnregisterAvailabil
   MOZ_ASSERT(NS_IsMainThread());
 
   mAvailabilityListeners.RemoveElement(aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationService::RegisterSessionListener(const nsAString& aSessionId,
+                                             uint8_t aRole,
                                              nsIPresentationSessionListener* aListener)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aListener);
+  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+             aRole == nsIPresentationService::ROLE_RECEIVER);
 
-  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
+  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
   if (NS_WARN_IF(!info)) {
     // Notify the listener of TERMINATED since no correspondent session info is
     // available possibly due to establishment failure. This would be useful at
     // the receiver side, since a presentation session is created at beginning
     // and here is the place to realize the underlying establishment fails.
     nsresult rv = aListener->NotifyStateChange(aSessionId,
                                                nsIPresentationSessionListener::STATE_TERMINATED);
     if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -544,24 +561,27 @@ PresentationService::RegisterSessionList
     }
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return info->SetListener(aListener);
 }
 
 NS_IMETHODIMP
-PresentationService::UnregisterSessionListener(const nsAString& aSessionId)
+PresentationService::UnregisterSessionListener(const nsAString& aSessionId,
+                                               uint8_t aRole)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+             aRole == nsIPresentationService::ROLE_RECEIVER);
 
-  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
+  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
   if (info) {
     NS_WARN_IF(NS_FAILED(info->Close(NS_OK, nsIPresentationSessionListener::STATE_TERMINATED)));
-    UntrackSessionInfo(aSessionId);
+    UntrackSessionInfo(aSessionId, aRole);
     return info->SetListener(nullptr);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationService::RegisterRespondingListener(uint64_t aWindowId,
                                                 nsIPresentationRespondingListener* aListener)
@@ -601,52 +621,63 @@ PresentationService::GetExistentSessionI
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationService::NotifyReceiverReady(const nsAString& aSessionId,
                                          uint64_t aWindowId)
 {
-  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
+  RefPtr<PresentationSessionInfo> info =
+    GetSessionInfo(aSessionId, nsIPresentationService::ROLE_RECEIVER);
   if (NS_WARN_IF(!info)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Only track the responding info when an actual window ID, which would never
   // be 0, is provided (for an in-process receiver page).
   if (aWindowId != 0) {
     mRespondingSessionIds.Put(aWindowId, new nsAutoString(aSessionId));
     mRespondingWindowIds.Put(aSessionId, aWindowId);
   }
 
   return static_cast<PresentationPresentingInfo*>(info.get())->NotifyResponderReady();
 }
 
 NS_IMETHODIMP
-PresentationService::UntrackSessionInfo(const nsAString& aSessionId)
+PresentationService::UntrackSessionInfo(const nsAString& aSessionId,
+                                        uint8_t aRole)
 {
+  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+             aRole == nsIPresentationService::ROLE_RECEIVER);
   // Remove the session info.
-  mSessionInfo.Remove(aSessionId);
+  if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
+    mSessionInfoAtController.Remove(aSessionId);
+  } else {
+    mSessionInfoAtReceiver.Remove(aSessionId);
+  }
 
   // Remove the in-process responding info if there's still any.
   uint64_t windowId = 0;
   if(mRespondingWindowIds.Get(aSessionId, &windowId)) {
     mRespondingWindowIds.Remove(aSessionId);
     mRespondingSessionIds.Remove(windowId);
   }
 
   return NS_OK;
 }
 
 bool
 PresentationService::IsSessionAccessible(const nsAString& aSessionId,
+                                         const uint8_t aRole,
                                          base::ProcessId aProcessId)
 {
-  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
+  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+             aRole == nsIPresentationService::ROLE_RECEIVER);
+  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
   if (NS_WARN_IF(!info)) {
     return false;
   }
   return info->IsAccessible(aProcessId);
 }
 
 already_AddRefed<nsIPresentationService>
 NS_CreatePresentationService()
--- a/dom/presentation/PresentationService.h
+++ b/dom/presentation/PresentationService.h
@@ -28,24 +28,33 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIPRESENTATIONSERVICE
 
   PresentationService();
   bool Init();
 
   already_AddRefed<PresentationSessionInfo>
-  GetSessionInfo(const nsAString& aSessionId)
+  GetSessionInfo(const nsAString& aSessionId, const uint8_t aRole)
   {
+    MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+               aRole == nsIPresentationService::ROLE_RECEIVER);
+
     RefPtr<PresentationSessionInfo> info;
-    return mSessionInfo.Get(aSessionId, getter_AddRefs(info)) ?
-           info.forget() : nullptr;
+    if (aRole == nsIPresentationService::ROLE_CONTROLLER) {
+      return mSessionInfoAtController.Get(aSessionId, getter_AddRefs(info)) ?
+             info.forget() : nullptr;
+    } else {
+      return mSessionInfoAtReceiver.Get(aSessionId, getter_AddRefs(info)) ?
+             info.forget() : nullptr;
+    }
   }
 
   bool IsSessionAccessible(const nsAString& aSessionId,
+                           const uint8_t aRole,
                            base::ProcessId aProcessId);
 
 private:
   ~PresentationService();
   void HandleShutdown();
   nsresult HandleDeviceChange();
   nsresult HandleSessionRequest(nsIPresentationSessionRequest* aRequest);
   void NotifyAvailableChange(bool aIsAvailable);
@@ -56,17 +65,18 @@ private:
 
   // Store the responding listener based on the window ID of the (in-process or
   // OOP) receiver page.
   // TODO Bug 1195605 - Support many-to-one session.
   // So far responding listeners are registered but |notifySessionConnect| hasn't
   // been called in any place until many-to-one session becomes supported.
   nsRefPtrHashtable<nsUint64HashKey, nsIPresentationRespondingListener> mRespondingListeners;
 
-  nsRefPtrHashtable<nsStringHashKey, PresentationSessionInfo> mSessionInfo;
+  nsRefPtrHashtable<nsStringHashKey, PresentationSessionInfo> mSessionInfoAtController;
+  nsRefPtrHashtable<nsStringHashKey, PresentationSessionInfo> mSessionInfoAtReceiver;
 
   // Store the mapping between the window ID of the in-process page and the ID
   // of the responding session. It's used for an in-process receiver page to
   // retrieve the correspondent session ID. Besides, also keep the mapping
   // between the responding session ID and the window ID to help look up the
   // window ID.
   nsClassHashtable<nsUint64HashKey, nsString> mRespondingSessionIds;
   nsDataHashtable<nsStringHashKey, uint64_t> mRespondingWindowIds;
--- a/dom/presentation/PresentationSessionInfo.cpp
+++ b/dom/presentation/PresentationSessionInfo.cpp
@@ -322,17 +322,17 @@ PresentationSessionInfo::ReplyError(nsre
 /* virtual */ nsresult
 PresentationSessionInfo::UntrackFromService()
 {
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!service)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
-  static_cast<PresentationService*>(service.get())->UntrackSessionInfo(mSessionId);
+  static_cast<PresentationService*>(service.get())->UntrackSessionInfo(mSessionId, mRole);
 
   return NS_OK;
 }
 
 /* virtual */ bool
 PresentationSessionInfo::IsAccessible(base::ProcessId aProcessId)
 {
   // No restriction by default.
@@ -799,17 +799,17 @@ PresentationPresentingInfo::UntrackFromS
   }
 
   // Remove the session info (and the in-process responding info if there's any).
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!service)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
-  static_cast<PresentationService*>(service.get())->UntrackSessionInfo(mSessionId);
+  static_cast<PresentationService*>(service.get())->UntrackSessionInfo(mSessionId, mRole);
 
   return NS_OK;
 }
 
 bool
 PresentationPresentingInfo::IsAccessible(base::ProcessId aProcessId)
 {
   // Only the specific content process should access the responder info.
--- a/dom/presentation/PresentationSessionInfo.h
+++ b/dom/presentation/PresentationSessionInfo.h
@@ -30,40 +30,49 @@ class PresentationSessionInfo : public n
                               , public nsIPresentationControlChannelListener
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPRESENTATIONSESSIONTRANSPORTCALLBACK
 
   PresentationSessionInfo(const nsAString& aUrl,
                           const nsAString& aSessionId,
+                          const uint8_t aRole,
                           nsIPresentationServiceCallback* aCallback)
     : mUrl(aUrl)
     , mSessionId(aSessionId)
     , mIsResponderReady(false)
     , mIsTransportReady(false)
     , mState(nsIPresentationSessionListener::STATE_CLOSED)
     , mCallback(aCallback)
   {
     MOZ_ASSERT(!mUrl.IsEmpty());
     MOZ_ASSERT(!mSessionId.IsEmpty());
+    MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+               aRole == nsIPresentationService::ROLE_RECEIVER);
+    mRole = aRole;
   }
 
   virtual nsresult Init(nsIPresentationControlChannel* aControlChannel);
 
   const nsAString& GetUrl() const
   {
     return mUrl;
   }
 
   const nsAString& GetSessionId() const
   {
     return mSessionId;
   }
 
+  uint8_t GetRole() const
+  {
+    return mRole;
+  }
+
   void SetCallback(nsIPresentationServiceCallback* aCallback)
   {
     mCallback = aCallback;
   }
 
   nsresult SetListener(nsIPresentationSessionListener* aListener);
 
   void SetDevice(nsIPresentationDevice* aDevice)
@@ -127,16 +136,19 @@ protected:
     if (mListener) {
       nsresult rv = mListener->NotifyStateChange(mSessionId, mState);
       NS_WARN_IF(NS_FAILED(rv));
     }
   }
 
   nsString mUrl;
   nsString mSessionId;
+  // mRole should be nsIPresentationService::ROLE_CONTROLLER
+  //              or nsIPresentationService::ROLE_RECEIVER.
+  uint8_t mRole;
   bool mIsResponderReady;
   bool mIsTransportReady;
   uint32_t mState; // CONNECTED, CLOSED, TERMINATED
   nsCOMPtr<nsIPresentationServiceCallback> mCallback;
   nsCOMPtr<nsIPresentationSessionListener> mListener;
   nsCOMPtr<nsIPresentationDevice> mDevice;
   nsCOMPtr<nsIPresentationSessionTransport> mTransport;
   nsCOMPtr<nsIPresentationControlChannel> mControlChannel;
@@ -149,17 +161,20 @@ class PresentationControllingInfo final 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIPRESENTATIONCONTROLCHANNELLISTENER
   NS_DECL_NSISERVERSOCKETLISTENER
 
   PresentationControllingInfo(const nsAString& aUrl,
                               const nsAString& aSessionId,
                               nsIPresentationServiceCallback* aCallback)
-    : PresentationSessionInfo(aUrl, aSessionId, aCallback)
+    : PresentationSessionInfo(aUrl,
+                              aSessionId,
+                              nsIPresentationService::ROLE_CONTROLLER,
+                              aCallback)
   {
     MOZ_ASSERT(mCallback);
   }
 
   nsresult Init(nsIPresentationControlChannel* aControlChannel) override;
 
 private:
   ~PresentationControllingInfo()
@@ -184,20 +199,22 @@ class PresentationPresentingInfo final :
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIPRESENTATIONCONTROLCHANNELLISTENER
   NS_DECL_NSITIMERCALLBACK
 
   PresentationPresentingInfo(const nsAString& aUrl,
                              const nsAString& aSessionId,
                              nsIPresentationDevice* aDevice)
-    : PresentationSessionInfo(aUrl, aSessionId, nullptr)
+    : PresentationSessionInfo(aUrl,
+                              aSessionId,
+                              nsIPresentationService::ROLE_RECEIVER,
+                              nullptr)
   {
     MOZ_ASSERT(aDevice);
-
     SetDevice(aDevice);
   }
 
   nsresult Init(nsIPresentationControlChannel* aControlChannel) override;
 
   nsresult NotifyResponderReady();
 
   void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
--- a/dom/presentation/interfaces/nsIPresentationService.idl
+++ b/dom/presentation/interfaces/nsIPresentationService.idl
@@ -28,19 +28,22 @@ interface nsIPresentationServiceCallback
   /*
    * Called when the operation fails.
    *
    * @param error: error message.
    */
   void notifyError(in nsresult error);
 };
 
-[scriptable, uuid(2e360359-c45c-4949-bf95-410242ce483f)]
+[scriptable, uuid(5cac5d1f-f996-4d9a-b1fa-f2c7adbe02ca)]
 interface nsIPresentationService : nsISupports
 {
+  const unsigned short ROLE_CONTROLLER = 0x1;
+  const unsigned short ROLE_RECEIVER = 0x2;
+
   /*
    * Start a new presentation session and display a prompt box which asks users
    * to select a device.
    *
    * @param url: The url of presenting page.
    * @param sessionId: An ID to identify presentation session.
    * @param origin: The url of requesting page.
    * @param deviceId: The specified device of handling this request, null string
@@ -55,34 +58,40 @@ interface nsIPresentationService : nsISu
                     in DOMString origin,
                     in DOMString deviceId,
                     in nsIPresentationServiceCallback callback);
 
   /*
    * Send the message wrapped with an input stream to the session.
    *
    * @param sessionId: An ID to identify presentation session.
+   * @param role: Identify the function called by controller or receiver.
    * @param stream: The message is converted to an input stream.
    */
   void sendSessionMessage(in DOMString sessionId,
+                          in uint8_t role,
                           in nsIInputStream stream);
 
   /*
    * Close the session.
    *
    * @param sessionId: An ID to identify presentation session.
+   * @param role: Identify the function called by controller or receiver.
    */
-  void closeSession(in DOMString sessionId);
+  void closeSession(in DOMString sessionId,
+                    in uint8_t role);
 
   /*
    * Terminate the session.
    *
    * @param sessionId: An ID to identify presentation session.
+   * @param role: Identify the function called by controller or receiver.
    */
-  void terminateSession(in DOMString sessionId);
+  void terminateSession(in DOMString sessionId,
+                        in uint8_t role);
 
   /*
    * Register an availability listener. Must be called from the main thread.
    *
    * @param listener: The listener to register.
    */
   void registerAvailabilityListener(in nsIPresentationAvailabilityListener listener);
 
@@ -91,27 +100,31 @@ interface nsIPresentationService : nsISu
    * @param listener: The listener to unregister.
    */
   void unregisterAvailabilityListener(in nsIPresentationAvailabilityListener listener);
 
   /*
    * Register a session listener. Must be called from the main thread.
    *
    * @param sessionId: An ID to identify presentation session.
+   * @param role: Identify the function called by controller or receiver.
    * @param listener: The listener to register.
    */
   void registerSessionListener(in DOMString sessionId,
+                               in uint8_t role,
                                in nsIPresentationSessionListener listener);
 
   /*
    * Unregister a session listener. Must be called from the main thread.
    *
    * @param sessionId: An ID to identify presentation session.
+   * @param role: Identify the function called by controller or receiver.
    */
-  void unregisterSessionListener(in DOMString sessionId);
+  void unregisterSessionListener(in DOMString sessionId,
+                                 in uint8_t role);
 
   /*
    * Register a responding listener. Must be called from the main thread.
    *
    * @param windowId: The window ID associated with the listener.
    * @param listener: The listener to register.
    */
   void registerRespondingListener(in uint64_t windowId,
@@ -143,11 +156,12 @@ interface nsIPresentationService : nsISu
    */
   void notifyReceiverReady(in DOMString sessionId,
                            [optional] in uint64_t windowId);
 
   /*
    * Untrack the relevant info about the presentation session if there's any.
    *
    * @param sessionId: An ID to identify presentation session.
+   * @param role: Identify the function called by controller or receiver.
    */
-  void untrackSessionInfo(in DOMString sessionId);
+  void untrackSessionInfo(in DOMString sessionId, in uint8_t role);
 };
--- a/dom/presentation/ipc/PPresentation.ipdl
+++ b/dom/presentation/ipc/PPresentation.ipdl
@@ -18,27 +18,30 @@ struct StartSessionRequest
   nsString sessionId;
   nsString origin;
   nsString deviceId;
 };
 
 struct SendSessionMessageRequest
 {
   nsString sessionId;
+  uint8_t role;
   InputStreamParams data;
 };
 
 struct CloseSessionRequest
 {
   nsString sessionId;
+  uint8_t role;
 };
 
 struct TerminateSessionRequest
 {
   nsString sessionId;
+  uint8_t role;
 };
 
 union PresentationIPCRequest
 {
   StartSessionRequest;
   SendSessionMessageRequest;
   CloseSessionRequest;
   TerminateSessionRequest;
@@ -56,18 +59,18 @@ child:
   async NotifySessionConnect(uint64_t aWindowId, nsString aSessionId);
 
 parent:
   async __delete__();
 
   async RegisterAvailabilityHandler();
   async UnregisterAvailabilityHandler();
 
-  async RegisterSessionHandler(nsString aSessionId);
-  async UnregisterSessionHandler(nsString aSessionId);
+  async RegisterSessionHandler(nsString aSessionId, uint8_t aRole);
+  async UnregisterSessionHandler(nsString aSessionId, uint8_t aRole);
 
   async RegisterRespondingHandler(uint64_t aWindowId);
   async UnregisterRespondingHandler(uint64_t aWindowId);
 
   async PPresentationRequest(PresentationIPCRequest aRequest);
 
   async NotifyReceiverReady(nsString aSessionId);
 };
--- a/dom/presentation/ipc/PresentationIPCService.cpp
+++ b/dom/presentation/ipc/PresentationIPCService.cpp
@@ -55,43 +55,46 @@ PresentationIPCService::StartSession(con
   return SendRequest(aCallback, StartSessionRequest(nsAutoString(aUrl),
                                                     nsAutoString(aSessionId),
                                                     nsAutoString(aOrigin),
                                                     nsAutoString(aDeviceId)));
 }
 
 NS_IMETHODIMP
 PresentationIPCService::SendSessionMessage(const nsAString& aSessionId,
+                                           uint8_t aRole,
                                            nsIInputStream* aStream)
 {
   MOZ_ASSERT(!aSessionId.IsEmpty());
   MOZ_ASSERT(aStream);
 
   mozilla::ipc::OptionalInputStreamParams stream;
   nsTArray<mozilla::ipc::FileDescriptor> fds;
   SerializeInputStream(aStream, stream, fds);
   MOZ_ASSERT(fds.IsEmpty());
 
-  return SendRequest(nullptr, SendSessionMessageRequest(nsAutoString(aSessionId), stream));
+  return SendRequest(nullptr, SendSessionMessageRequest(nsAutoString(aSessionId), aRole, stream));
 }
 
 NS_IMETHODIMP
-PresentationIPCService::CloseSession(const nsAString& aSessionId)
+PresentationIPCService::CloseSession(const nsAString& aSessionId,
+                                     uint8_t aRole)
 {
   MOZ_ASSERT(!aSessionId.IsEmpty());
 
-  return SendRequest(nullptr, CloseSessionRequest(nsAutoString(aSessionId)));
+  return SendRequest(nullptr, CloseSessionRequest(nsAutoString(aSessionId), aRole));
 }
 
 NS_IMETHODIMP
-PresentationIPCService::TerminateSession(const nsAString& aSessionId)
+PresentationIPCService::TerminateSession(const nsAString& aSessionId,
+                                         uint8_t aRole)
 {
   MOZ_ASSERT(!aSessionId.IsEmpty());
 
-  return SendRequest(nullptr, TerminateSessionRequest(nsAutoString(aSessionId)));
+  return SendRequest(nullptr, TerminateSessionRequest(nsAutoString(aSessionId), aRole));
 }
 
 nsresult
 PresentationIPCService::SendRequest(nsIPresentationServiceCallback* aCallback,
                                     const PresentationIPCRequest& aRequest)
 {
   if (sPresentationChild) {
     PresentationRequestChild* actor = new PresentationRequestChild(aCallback);
@@ -123,38 +126,40 @@ PresentationIPCService::UnregisterAvaila
   if (sPresentationChild) {
     NS_WARN_IF(!sPresentationChild->SendUnregisterAvailabilityHandler());
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::RegisterSessionListener(const nsAString& aSessionId,
+                                                uint8_t aRole,
                                                 nsIPresentationSessionListener* aListener)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aListener);
 
   mSessionListeners.Put(aSessionId, aListener);
   if (sPresentationChild) {
-    NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(nsAutoString(aSessionId)));
+    NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(nsAutoString(aSessionId), aRole));
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PresentationIPCService::UnregisterSessionListener(const nsAString& aSessionId)
+PresentationIPCService::UnregisterSessionListener(const nsAString& aSessionId,
+                                                  uint8_t aRole)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  UntrackSessionInfo(aSessionId);
+  UntrackSessionInfo(aSessionId, aRole);
 
   mSessionListeners.Remove(aSessionId);
   if (sPresentationChild) {
-    NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(nsAutoString(aSessionId)));
+    NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(nsAutoString(aSessionId), aRole));
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationIPCService::RegisterRespondingListener(uint64_t aWindowId,
                                                    nsIPresentationRespondingListener* aListener)
 {
@@ -261,17 +266,18 @@ PresentationIPCService::NotifyReceiverRe
 
   // Release mCallback after using aSessionId
   // because aSessionId is held by mCallback.
   mCallback = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PresentationIPCService::UntrackSessionInfo(const nsAString& aSessionId)
+PresentationIPCService::UntrackSessionInfo(const nsAString& aSessionId,
+                                           uint8_t aRole)
 {
   // Remove the OOP responding info (if it has never been used).
   uint64_t windowId = 0;
   if(mRespondingWindowIds.Get(aSessionId, &windowId)) {
     mRespondingWindowIds.Remove(aSessionId);
     mRespondingSessionIds.Remove(windowId);
   }
 
--- a/dom/presentation/ipc/PresentationParent.cpp
+++ b/dom/presentation/ipc/PresentationParent.cpp
@@ -40,20 +40,27 @@ PresentationParent::Init()
   return NS_WARN_IF(!mService) ? false : true;
 }
 
 void
 PresentationParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   mActorDestroyed = true;
 
-  for (uint32_t i = 0; i < mSessionIds.Length(); i++) {
-    NS_WARN_IF(NS_FAILED(mService->UnregisterSessionListener(mSessionIds[i])));
+  for (uint32_t i = 0; i < mSessionIdsAtController.Length(); i++) {
+    NS_WARN_IF(NS_FAILED(mService->
+      UnregisterSessionListener(mSessionIdsAtController[i], nsIPresentationService::ROLE_CONTROLLER)));
   }
-  mSessionIds.Clear();
+  mSessionIdsAtController.Clear();
+
+  for (uint32_t i = 0; i < mSessionIdsAtReceiver.Length(); i++) {
+    NS_WARN_IF(NS_FAILED(mService->
+      UnregisterSessionListener(mSessionIdsAtReceiver[i], nsIPresentationService::ROLE_RECEIVER)));
+  }
+  mSessionIdsAtReceiver.Clear();
 
   for (uint32_t i = 0; i < mWindowIds.Length(); i++) {
     NS_WARN_IF(NS_FAILED(mService->UnregisterRespondingListener(mWindowIds[i])));
   }
   mWindowIds.Clear();
 
   mService->UnregisterAvailabilityListener(this);
   mService = nullptr;
@@ -123,38 +130,48 @@ bool
 PresentationParent::RecvUnregisterAvailabilityHandler()
 {
   MOZ_ASSERT(mService);
   NS_WARN_IF(NS_FAILED(mService->UnregisterAvailabilityListener(this)));
   return true;
 }
 
 /* virtual */ bool
-PresentationParent::RecvRegisterSessionHandler(const nsString& aSessionId)
+PresentationParent::RecvRegisterSessionHandler(const nsString& aSessionId,
+                                               const uint8_t& aRole)
 {
   MOZ_ASSERT(mService);
 
   // Validate the accessibility (primarily for receiver side) so that a
   // compromised child process can't fake the ID.
   if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
-                  IsSessionAccessible(aSessionId, OtherPid()))) {
+                  IsSessionAccessible(aSessionId, aRole, OtherPid()))) {
     return true;
   }
 
-  mSessionIds.AppendElement(aSessionId);
-  NS_WARN_IF(NS_FAILED(mService->RegisterSessionListener(aSessionId, this)));
+  if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
+    mSessionIdsAtController.AppendElement(aSessionId);
+  } else {
+    mSessionIdsAtReceiver.AppendElement(aSessionId);
+  }
+  NS_WARN_IF(NS_FAILED(mService->RegisterSessionListener(aSessionId, aRole, this)));
   return true;
 }
 
 /* virtual */ bool
-PresentationParent::RecvUnregisterSessionHandler(const nsString& aSessionId)
+PresentationParent::RecvUnregisterSessionHandler(const nsString& aSessionId,
+                                                 const uint8_t& aRole)
 {
   MOZ_ASSERT(mService);
-  mSessionIds.RemoveElement(aSessionId);
-  NS_WARN_IF(NS_FAILED(mService->UnregisterSessionListener(aSessionId)));
+  if (nsIPresentationService::ROLE_CONTROLLER == aRole) {
+    mSessionIdsAtController.RemoveElement(aSessionId);
+  } else {
+    mSessionIdsAtReceiver.RemoveElement(aSessionId);
+  }
+  NS_WARN_IF(NS_FAILED(mService->UnregisterSessionListener(aSessionId, aRole)));
   return true;
 }
 
 /* virtual */ bool
 PresentationParent::RecvRegisterRespondingHandler(const uint64_t& aWindowId)
 {
   MOZ_ASSERT(mService);
 
@@ -258,65 +275,65 @@ PresentationRequestParent::DoRequest(con
 nsresult
 PresentationRequestParent::DoRequest(const SendSessionMessageRequest& aRequest)
 {
   MOZ_ASSERT(mService);
 
   // Validate the accessibility (primarily for receiver side) so that a
   // compromised child process can't fake the ID.
   if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
-                  IsSessionAccessible(aRequest.sessionId(), OtherPid()))) {
+                  IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
     return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
   }
 
   nsTArray<mozilla::ipc::FileDescriptor> fds;
   nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aRequest.data(), fds);
   if(NS_WARN_IF(!stream)) {
     return NotifyError(NS_ERROR_NOT_AVAILABLE);
   }
 
-  nsresult rv = mService->SendSessionMessage(aRequest.sessionId(), stream);
+  nsresult rv = mService->SendSessionMessage(aRequest.sessionId(), aRequest.role(), stream);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return NotifyError(rv);
   }
   return NotifySuccess();
 }
 
 nsresult
 PresentationRequestParent::DoRequest(const CloseSessionRequest& aRequest)
 {
   MOZ_ASSERT(mService);
 
   // Validate the accessibility (primarily for receiver side) so that a
   // compromised child process can't fake the ID.
   if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
-                  IsSessionAccessible(aRequest.sessionId(), OtherPid()))) {
+                  IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
     return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
   }
 
-  nsresult rv = mService->CloseSession(aRequest.sessionId());
+  nsresult rv = mService->CloseSession(aRequest.sessionId(), aRequest.role());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return NotifyError(rv);
   }
   return NotifySuccess();
 }
 
 nsresult
 PresentationRequestParent::DoRequest(const TerminateSessionRequest& aRequest)
 {
   MOZ_ASSERT(mService);
 
   // Validate the accessibility (primarily for receiver side) so that a
   // compromised child process can't fake the ID.
   if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
-                  IsSessionAccessible(aRequest.sessionId(), OtherPid()))) {
+                  IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
     return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
   }
 
-  nsresult rv = mService->TerminateSession(aRequest.sessionId());
+  nsresult rv = mService->TerminateSession(aRequest.sessionId(), aRequest.role());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return NotifyError(rv);
   }
   return NotifySuccess();
 }
 
 NS_IMETHODIMP
 PresentationRequestParent::NotifySuccess()
--- a/dom/presentation/ipc/PresentationParent.h
+++ b/dom/presentation/ipc/PresentationParent.h
@@ -43,32 +43,35 @@ public:
   DeallocPPresentationRequestParent(PPresentationRequestParent* aActor) override;
 
   virtual bool Recv__delete__() override;
 
   virtual bool RecvRegisterAvailabilityHandler() override;
 
   virtual bool RecvUnregisterAvailabilityHandler() override;
 
-  virtual bool RecvRegisterSessionHandler(const nsString& aSessionId) override;
+  virtual bool RecvRegisterSessionHandler(const nsString& aSessionId,
+                                          const uint8_t& aRole) override;
 
-  virtual bool RecvUnregisterSessionHandler(const nsString& aSessionId) override;
+  virtual bool RecvUnregisterSessionHandler(const nsString& aSessionId,
+                                            const uint8_t& aRole) override;
 
   virtual bool RecvRegisterRespondingHandler(const uint64_t& aWindowId) override;
 
   virtual bool RecvUnregisterRespondingHandler(const uint64_t& aWindowId) override;
 
   virtual bool RecvNotifyReceiverReady(const nsString& aSessionId) override;
 
 private:
   virtual ~PresentationParent();
 
   bool mActorDestroyed;
   nsCOMPtr<nsIPresentationService> mService;
-  nsTArray<nsString> mSessionIds;
+  nsTArray<nsString> mSessionIdsAtController;
+  nsTArray<nsString> mSessionIdsAtReceiver;
   nsTArray<uint64_t> mWindowIds;
 };
 
 class PresentationRequestParent final : public PPresentationRequestParent
                                       , public nsIPresentationServiceCallback
 {
   friend class PresentationParent;