зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1069230 - Presentation API implementation. Part 7 - Presentation session. r=smaug
This commit is contained in:
Родитель
4e9ad23c31
Коммит
905d6d07e3
|
@ -432,9 +432,12 @@ PresentationService::SendSessionMessage(const nsAString& aSessionId,
|
|||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
|
||||
// TODO: Send input stream to the session.
|
||||
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return info->Send(aStream);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -443,9 +446,12 @@ PresentationService::Terminate(const nsAString& aSessionId)
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
|
||||
// TODO: Terminate the session.
|
||||
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return info->Close(NS_OK);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -505,6 +511,8 @@ PresentationService::UnregisterSessionListener(const nsAString& aSessionId)
|
|||
|
||||
nsRefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId);
|
||||
if (info) {
|
||||
NS_WARN_IF(NS_FAILED(info->Close(NS_OK)));
|
||||
RemoveSessionInfo(aSessionId);
|
||||
return info->SetListener(nullptr);
|
||||
}
|
||||
return NS_OK;
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
* 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/AsyncEventDispatcher.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIDOMMessageEvent.h"
|
||||
#include "nsIPresentationService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "PresentationSession.h"
|
||||
|
@ -25,6 +28,7 @@ NS_IMPL_ADDREF_INHERITED(PresentationSession, DOMEventTargetHelper)
|
|||
NS_IMPL_RELEASE_INHERITED(PresentationSession, DOMEventTargetHelper)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PresentationSession)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIPresentationSessionListener)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
|
||||
PresentationSession::PresentationSession(nsPIDOMWindow* aWindow,
|
||||
|
@ -57,7 +61,16 @@ PresentationSession::Init()
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO: Register listener for session state changes.
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if(NS_WARN_IF(!service)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = service->RegisterSessionListener(mId, this);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -65,7 +78,14 @@ PresentationSession::Init()
|
|||
void
|
||||
PresentationSession::Shutdown()
|
||||
{
|
||||
// TODO: Unregister listener for session state changes.
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if (NS_WARN_IF(!service)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = service->UnregisterSessionListener(mId);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
/* virtual */ JSObject*
|
||||
|
@ -84,7 +104,6 @@ PresentationSession::GetId(nsAString& aId) const
|
|||
PresentationSessionState
|
||||
PresentationSession::State() const
|
||||
{
|
||||
// TODO: Dispatch event when the value of |mState| is changed.
|
||||
return mState;
|
||||
}
|
||||
|
||||
|
@ -102,18 +121,28 @@ PresentationSession::Send(const nsAString& aData,
|
|||
nsCOMPtr<nsIStringInputStream> stream =
|
||||
do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ConvertUTF16toUTF8 msgString(aData);
|
||||
rv = stream->SetData(msgString.BeginReading(), msgString.Length());
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Send the message to the stream.
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if(NS_WARN_IF(!service)) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
rv = service->SendSessionMessage(mId, stream);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -124,5 +153,132 @@ PresentationSession::Close()
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: Terminate the socket.
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if(NS_WARN_IF(!service)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NS_WARN_IF(NS_FAILED(service->Terminate(mId)));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationSession::NotifyStateChange(const nsAString& aSessionId,
|
||||
uint16_t aState)
|
||||
{
|
||||
if (!aSessionId.Equals(mId)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
PresentationSessionState state;
|
||||
switch (aState) {
|
||||
case nsIPresentationSessionListener::STATE_CONNECTED:
|
||||
state = PresentationSessionState::Connected;
|
||||
break;
|
||||
case nsIPresentationSessionListener::STATE_DISCONNECTED:
|
||||
state = PresentationSessionState::Disconnected;
|
||||
break;
|
||||
case nsIPresentationSessionListener::STATE_TERMINATED:
|
||||
state = PresentationSessionState::Terminated;
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("Unknown presentation session state.");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (mState == state) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mState = state;
|
||||
|
||||
// Unregister session listener if the session is no longer connected.
|
||||
if (mState == PresentationSessionState::Terminated) {
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if (NS_WARN_IF(!service)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsresult rv = service->UnregisterSessionListener(mId);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return DispatchStateChangeEvent();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationSession::NotifyMessage(const nsAString& aSessionId,
|
||||
const nsACString& aData)
|
||||
{
|
||||
if (!aSessionId.Equals(mId)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// No message should be expected when the session is not connected.
|
||||
if (NS_WARN_IF(mState != PresentationSessionState::Connected)) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
// Transform the data.
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(GetOwner())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JS::Value> jsData(cx);
|
||||
NS_ConvertUTF8toUTF16 utf16Data(aData);
|
||||
if(NS_WARN_IF(!ToJSValue(cx, utf16Data, &jsData))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return DispatchMessageEvent(jsData);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationSession::DispatchStateChangeEvent()
|
||||
{
|
||||
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, NS_LITERAL_STRING("statechange"), false);
|
||||
return asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationSession::DispatchMessageEvent(JS::Handle<JS::Value> aData)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
||||
if (NS_WARN_IF(!global)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Get the origin.
|
||||
nsAutoString origin;
|
||||
nsresult rv = nsContentUtils::GetUTFOrigin(global->PrincipalOrNull(), origin);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
rv = NS_NewDOMMessageEvent(getter_AddRefs(event), this, nullptr, nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMMessageEvent> messageEvent = do_QueryInterface(event);
|
||||
rv = messageEvent->InitMessageEvent(NS_LITERAL_STRING("message"),
|
||||
false, false,
|
||||
aData,
|
||||
origin,
|
||||
EmptyString(), nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
event->SetTrusted(true);
|
||||
|
||||
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, event);
|
||||
return asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
|
|
@ -9,16 +9,19 @@
|
|||
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/dom/PresentationSessionBinding.h"
|
||||
#include "nsIPresentationListener.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class PresentationSession final : public DOMEventTargetHelper
|
||||
, public nsIPresentationSessionListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PresentationSession,
|
||||
DOMEventTargetHelper)
|
||||
NS_DECL_NSIPRESENTATIONSESSIONLISTENER
|
||||
|
||||
static already_AddRefed<PresentationSession>
|
||||
Create(nsPIDOMWindow* aWindow,
|
||||
|
@ -44,6 +47,8 @@ private:
|
|||
|
||||
bool Init();
|
||||
void Shutdown();
|
||||
nsresult DispatchStateChangeEvent();
|
||||
nsresult DispatchMessageEvent(JS::Handle<JS::Value> aData);
|
||||
|
||||
nsString mId;
|
||||
PresentationSessionState mState;
|
||||
|
|
|
@ -40,20 +40,16 @@ PresentationSessionInfo::Shutdown(nsresult aReason)
|
|||
{
|
||||
// Close the control channel if any.
|
||||
if (mControlChannel) {
|
||||
mControlChannel->SetListener(nullptr);
|
||||
NS_WARN_IF(NS_FAILED(mControlChannel->Close(aReason)));
|
||||
mControlChannel = nullptr;
|
||||
}
|
||||
|
||||
// Close the data transport channel if any.
|
||||
if (mTransport) {
|
||||
mTransport->SetCallback(nullptr);
|
||||
// |mIsTransportReady| will be unset once |NotifyTransportClosed| is called.
|
||||
NS_WARN_IF(NS_FAILED(mTransport->Close(aReason)));
|
||||
mTransport = nullptr;
|
||||
}
|
||||
|
||||
mIsResponderReady = false;
|
||||
mIsTransportReady = false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -76,14 +72,29 @@ PresentationSessionInfo::SetListener(nsIPresentationSessionListener* aListener)
|
|||
nsresult
|
||||
PresentationSessionInfo::Send(nsIInputStream* aData)
|
||||
{
|
||||
// TODO Send data to |mTransport|.
|
||||
return NS_OK;
|
||||
if (NS_WARN_IF(!IsSessionReady())) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mTransport)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return mTransport->Send(aData);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationSessionInfo::Close(nsresult aReason)
|
||||
{
|
||||
// TODO Close |mTransport|.
|
||||
// The session is disconnected and it's a normal close. Simply change the
|
||||
// state to TERMINATED.
|
||||
if (!IsSessionReady() && NS_SUCCEEDED(aReason) && mListener) {
|
||||
nsresult rv = mListener->NotifyStateChange(mSessionId,
|
||||
nsIPresentationSessionListener::STATE_TERMINATED);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
Shutdown(aReason);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -150,6 +161,9 @@ PresentationSessionInfo::NotifyTransportClosed(nsresult aReason)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Nullify |mTransport| here so it won't try to re-close |mTransport| in
|
||||
// potential subsequent |Shutdown| calls.
|
||||
mTransport->SetCallback(nullptr);
|
||||
mTransport = nullptr;
|
||||
|
||||
if (!IsSessionReady()) {
|
||||
|
@ -157,6 +171,9 @@ PresentationSessionInfo::NotifyTransportClosed(nsresult aReason)
|
|||
return ReplyError(aReason);
|
||||
}
|
||||
|
||||
// Unset |mIsTransportReady| here so it won't affect |IsSessionReady()| above.
|
||||
mIsTransportReady = false;
|
||||
|
||||
Shutdown(aReason);
|
||||
|
||||
if (mListener) {
|
||||
|
@ -175,9 +192,15 @@ PresentationSessionInfo::NotifyData(const nsACString& aData)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// TODO Notify the listener.
|
||||
if (NS_WARN_IF(!IsSessionReady())) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
if (NS_WARN_IF(!mListener)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return mListener->NotifyMessage(mSessionId, aData);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -266,9 +289,18 @@ PresentationRequesterInfo::NotifyClosed(nsresult aReason)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Unset control channel here so it won't try to re-close it in potential
|
||||
// subsequent |Shutdown| calls.
|
||||
SetControlChannel(nullptr);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(aReason))) {
|
||||
if (mListener) {
|
||||
// The presentation session instance at receiver side may already exist.
|
||||
// Change the state to TERMINATED since it never succeeds.
|
||||
return mListener->NotifyStateChange(mSessionId,
|
||||
nsIPresentationSessionListener::STATE_TERMINATED);
|
||||
}
|
||||
|
||||
// Reply error for an abnormal close.
|
||||
return ReplyError(aReason);
|
||||
}
|
||||
|
@ -461,9 +493,18 @@ PresentationResponderInfo::NotifyClosed(nsresult aReason)
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Unset control channel here so it won't try to re-close it in potential
|
||||
// subsequent |Shutdown| calls.
|
||||
SetControlChannel(nullptr);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(aReason))) {
|
||||
if (mListener) {
|
||||
// The presentation session instance at receiver side may already exist.
|
||||
// Change the state to TERMINATED since it never succeeds.
|
||||
return mListener->NotifyStateChange(mSessionId,
|
||||
nsIPresentationSessionListener::STATE_TERMINATED);
|
||||
}
|
||||
|
||||
// Reply error for an abnormal close.
|
||||
return ReplyError(aReason);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,12 @@ 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])));
|
||||
}
|
||||
mSessionIds.Clear();
|
||||
|
||||
mService->UnregisterListener(this);
|
||||
mService = nullptr;
|
||||
}
|
||||
|
@ -114,6 +120,7 @@ PresentationParent::RecvUnregisterHandler()
|
|||
PresentationParent::RecvRegisterSessionHandler(const nsString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
mSessionIds.AppendElement(aSessionId);
|
||||
NS_WARN_IF(NS_FAILED(mService->RegisterSessionListener(aSessionId, this)));
|
||||
return true;
|
||||
}
|
||||
|
@ -122,6 +129,7 @@ PresentationParent::RecvRegisterSessionHandler(const nsString& aSessionId)
|
|||
PresentationParent::RecvUnregisterSessionHandler(const nsString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
mSessionIds.RemoveElement(aSessionId);
|
||||
NS_WARN_IF(NS_FAILED(mService->UnregisterSessionListener(aSessionId)));
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ private:
|
|||
|
||||
bool mActorDestroyed;
|
||||
nsCOMPtr<nsIPresentationService> mService;
|
||||
nsTArray<nsString> mSessionIds;
|
||||
};
|
||||
|
||||
class PresentationRequestParent final : public PPresentationRequestParent
|
||||
|
|
Загрузка…
Ссылка в новой задаче