Bug 1069230 - Presentation API implementation. Part 7 - Presentation session. r=smaug

This commit is contained in:
Sean Lin 2015-04-22 16:01:38 +08:00
Родитель 4e9ad23c31
Коммит 905d6d07e3
6 изменённых файлов: 240 добавлений и 21 удалений

Просмотреть файл

@ -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