Bug 1148307 - Part 4 - use data channel in substitution for TCP session transport (in-process), r=smaug

--HG--
rename : dom/presentation/tests/mochitest/test_presentation_receiver.html => dom/presentation/tests/mochitest/test_presentation_tcp_receiver.html
rename : dom/presentation/tests/mochitest/test_presentation_receiver_establish_connection_error.html => dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_error.html
rename : dom/presentation/tests/mochitest/test_presentation_receiver_establish_connection_timeout.html => dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_timeout.html
rename : dom/presentation/tests/mochitest/test_presentation_receiver_oop.html => dom/presentation/tests/mochitest/test_presentation_tcp_receiver_oop.html
rename : dom/presentation/tests/mochitest/test_presentation_sender.html => dom/presentation/tests/mochitest/test_presentation_tcp_sender.html
rename : dom/presentation/tests/mochitest/test_presentation_sender_default_request.html => dom/presentation/tests/mochitest/test_presentation_tcp_sender_default_request.html
rename : dom/presentation/tests/mochitest/test_presentation_sender_disconnect.html => dom/presentation/tests/mochitest/test_presentation_tcp_sender_disconnect.html
rename : dom/presentation/tests/mochitest/test_presentation_sender_establish_connection_error.html => dom/presentation/tests/mochitest/test_presentation_tcp_sender_establish_connection_error.html
This commit is contained in:
Junior Hsu 2016-04-11 11:20:55 +08:00
Родитель fee05caf8c
Коммит a8a1aaba30
28 изменённых файлов: 651 добавлений и 136 удалений

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

@ -131,7 +131,7 @@ PresentationRequest::StartWithDevice(const nsAString& aDeviceId,
nsCOMPtr<nsIPresentationServiceCallback> callback =
new PresentationRequesterCallback(this, mUrl, id, promise);
rv = service->StartSession(mUrl, id, origin, aDeviceId, callback);
rv = service->StartSession(mUrl, id, origin, aDeviceId, GetOwner()->WindowID(), callback);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
}

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

@ -388,6 +388,7 @@ PresentationService::StartSession(const nsAString& aUrl,
const nsAString& aSessionId,
const nsAString& aOrigin,
const nsAString& aDeviceId,
uint64_t aWindowId,
nsIPresentationServiceCallback* aCallback)
{
MOZ_ASSERT(NS_IsMainThread());
@ -400,6 +401,13 @@ PresentationService::StartSession(const nsAString& aUrl,
new PresentationControllingInfo(aUrl, aSessionId, aCallback);
mSessionInfo.Put(aSessionId, info);
// Only track the info when an actual window ID, which would never be 0, is
// provided (for an in-process sender page).
if (aWindowId != 0) {
mRespondingSessionIds.Put(aWindowId, new nsString(aSessionId));
mRespondingWindowIds.Put(aSessionId, aWindowId);
}
nsCOMPtr<nsIPresentationDeviceRequest> request =
new PresentationDeviceRequest(aUrl, aSessionId, aOrigin);
@ -614,7 +622,7 @@ PresentationService::NotifyReceiverReady(const nsAString& aSessionId,
// 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));
mRespondingSessionIds.Put(aWindowId, new nsString(aSessionId));
mRespondingWindowIds.Put(aSessionId, aWindowId);
}
@ -637,6 +645,16 @@ PresentationService::UntrackSessionInfo(const nsAString& aSessionId)
return NS_OK;
}
NS_IMETHODIMP
PresentationService::GetWindowIdBySessionId(const nsAString& aSessionId,
uint64_t* aWindowId)
{
if (mRespondingWindowIds.Get(aSessionId, aWindowId)) {
return NS_OK;
}
return NS_ERROR_NOT_AVAILABLE;
}
bool
PresentationService::IsSessionAccessible(const nsAString& aSessionId,
base::ProcessId aProcessId)

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

@ -13,6 +13,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "nsContentUtils.h"
#include "nsGlobalWindow.h"
#include "nsIDocShell.h"
#include "nsIFrameLoader.h"
#include "nsIMutableArray.h"
@ -153,8 +154,6 @@ TCPPresentationChannelDescription::GetType(uint8_t* aRetVal)
return NS_ERROR_INVALID_POINTER;
}
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
// Only support TCP socket for now.
*aRetVal = nsIPresentationChannelDescription::TYPE_TCP;
return NS_OK;
}
@ -171,11 +170,9 @@ TCPPresentationChannelDescription::GetTcpAddress(nsIArray** aRetVal)
return NS_ERROR_OUT_OF_MEMORY;
}
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
// Ultimately we may use all the available addresses. DataChannel appears
// more robust upon handling ICE. And at the first stage Presentation API is
// only exposed on Firefox OS where the first IP appears enough for most
// scenarios.
// TODO bug 1228504 Take all IP addresses in PresentationChannelDescription
// into account. And at the first stage Presentation API is only exposed on
// Firefox OS where the first IP appears enough for most scenarios.
nsCOMPtr<nsISupportsCString> address = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
if (NS_WARN_IF(!address)) {
return NS_ERROR_OUT_OF_MEMORY;
@ -202,8 +199,6 @@ TCPPresentationChannelDescription::GetTcpPort(uint16_t* aRetVal)
NS_IMETHODIMP
TCPPresentationChannelDescription::GetDataChannelSDP(nsAString& aDataChannelSDP)
{
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
// Only support TCP socket for now.
aDataChannelSDP.Truncate();
return NS_OK;
}
@ -241,6 +236,8 @@ PresentationSessionInfo::Shutdown(nsresult aReason)
}
mIsResponderReady = false;
mBuilder = nullptr;
}
nsresult
@ -333,6 +330,22 @@ PresentationSessionInfo::UntrackFromService()
return NS_OK;
}
nsPIDOMWindowInner*
PresentationSessionInfo::GetWindow()
{
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
if (NS_WARN_IF(!service)) {
return nullptr;
}
uint64_t windowId = 0;
if (NS_WARN_IF(NS_FAILED(service->GetWindowIdBySessionId(mSessionId, &windowId)))) {
return nullptr;
}
return nsGlobalWindow::GetInnerWindowWithId(windowId)->AsInner();
}
/* virtual */ bool
PresentationSessionInfo::IsAccessible(base::ProcessId aProcessId)
{
@ -428,11 +441,10 @@ PresentationSessionInfo::OnSessionTransport(nsIPresentationSessionTransport* tra
NS_IMETHODIMP
PresentationSessionInfo::OnError(nsresult reason)
{
return NS_ERROR_NOT_IMPLEMENTED;
return ReplyError(reason);
}
/*
/**
* Implementation of PresentationControllingInfo
*
* During presentation session establishment, the sender expects the following
@ -527,11 +539,10 @@ PresentationControllingInfo::GetAddress()
return NS_ERROR_FAILURE;
}
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
// Ultimately we may use all the available addresses. DataChannel appears
// more robust upon handling ICE. And at the first stage Presentation API is
// only exposed on Firefox OS where the first IP appears enough for most
// scenarios.
// TODO bug 1228504 Take all IP addresses in PresentationChannelDescription
// into account. And at the first stage Presentation API is only exposed on
// Firefox OS where the first IP appears enough for most scenarios.
nsAutoString ip;
ip.Assign(ips[0]);
@ -633,9 +644,29 @@ NS_IMETHODIMP
PresentationControllingInfo::NotifyOpened()
{
MOZ_ASSERT(NS_IsMainThread());
if (!Preferences::GetBool("dom.presentation.session_transport.data_channel.enable")) {
// Build TCP session transport
return GetAddress();
}
nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder> builder =
do_CreateInstance("@mozilla.org/presentation/datachanneltransportbuilder;1");
if (NS_WARN_IF(!builder)) {
return NS_ERROR_NOT_AVAILABLE;
}
mBuilder = builder;
mTransportType = nsIPresentationChannelDescription::TYPE_DATACHANNEL;
return builder->BuildDataChannelTransport(nsIPresentationSessionTransportBuilder::TYPE_SENDER,
GetWindow(),
mControlChannel,
this);
}
NS_IMETHODIMP
PresentationControllingInfo::NotifyClosed(nsresult aReason)
{
@ -677,6 +708,7 @@ PresentationControllingInfo::OnSocketAccepted(nsIServerSocket* aServerSocket,
return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
}
mTransportType = nsIPresentationChannelDescription::TYPE_TCP;
return builder->BuildTCPSenderTransport(aTransport, this);
}
@ -703,7 +735,7 @@ PresentationControllingInfo::OnStopListening(nsIServerSocket* aServerSocket,
return NS_OK;
}
/*
/**
* Implementation of PresentationPresentingInfo
*
* During presentation session establishment, the receiver expects the following
@ -766,16 +798,21 @@ PresentationPresentingInfo::Shutdown(nsresult aReason)
NS_IMETHODIMP
PresentationPresentingInfo::OnSessionTransport(nsIPresentationSessionTransport* transport)
{
PresentationSessionInfo::OnSessionTransport(transport);
nsresult rv = PresentationSessionInfo::OnSessionTransport(transport);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// send answer for TCP session transport
if (mTransportType == nsIPresentationChannelDescription::TYPE_TCP) {
// Prepare and send the answer.
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
// In the current implementation of |PresentationSessionTransport|,
// |GetSelfAddress| cannot return the real info when it's initialized via
// |InitWithChannelDescription|. Yet this deficiency only affects the channel
// |buildTCPReceiverTransport|. Yet this deficiency only affects the channel
// description for the answer, which is not actually checked at requester side.
nsCOMPtr<nsINetAddr> selfAddr;
nsresult rv = mTransport->GetSelfAddress(getter_AddRefs(selfAddr));
rv = mTransport->GetSelfAddress(getter_AddRefs(selfAddr));
NS_WARN_IF(NS_FAILED(rv));
nsCString address;
@ -790,6 +827,9 @@ PresentationPresentingInfo::OnSessionTransport(nsIPresentationSessionTransport*
return mControlChannel->SendAnswer(description);
}
return NS_OK;
}
NS_IMETHODIMP
PresentationPresentingInfo::OnError(nsresult reason)
{
@ -799,6 +839,13 @@ PresentationPresentingInfo::OnError(nsresult reason)
nsresult
PresentationPresentingInfo::InitTransportAndSendAnswer()
{
uint8_t type = 0;
nsresult rv = mRequesterDescription->GetType(&type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (type == nsIPresentationChannelDescription::TYPE_TCP) {
// Establish a data transport channel |mTransport| to the sender and use
// |this| as the callback.
nsCOMPtr<nsIPresentationTCPSessionTransportBuilder> builder =
@ -807,9 +854,43 @@ PresentationPresentingInfo::InitTransportAndSendAnswer()
return NS_ERROR_NOT_AVAILABLE;
}
mBuilder = builder;
mTransportType = nsIPresentationChannelDescription::TYPE_TCP;
return builder->BuildTCPReceiverTransport(mRequesterDescription, this);
}
if (type == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder> builder =
do_CreateInstance("@mozilla.org/presentation/datachanneltransportbuilder;1");
if (NS_WARN_IF(!builder)) {
return NS_ERROR_NOT_AVAILABLE;
}
mBuilder = builder;
mTransportType = nsIPresentationChannelDescription::TYPE_DATACHANNEL;
rv = builder->BuildDataChannelTransport(nsIPresentationSessionTransportBuilder::TYPE_RECEIVER,
GetWindow(),
mControlChannel,
this);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// delegate |onOffer| to builder
nsCOMPtr<nsIPresentationControlChannelListener> listener(do_QueryInterface(builder));
if (NS_WARN_IF(!listener)) {
return NS_ERROR_NOT_AVAILABLE;
}
return listener->OnOffer(mRequesterDescription);
}
MOZ_ASSERT(false, "Unknown nsIPresentationChannelDescription type!");
return NS_ERROR_UNEXPECTED;
}
nsresult
PresentationPresentingInfo::UntrackFromService()
{

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

@ -111,10 +111,7 @@ protected:
nsresult ReplySuccess();
bool IsSessionReady()
{
return mIsResponderReady && mIsTransportReady;
}
virtual bool IsSessionReady() = 0;
virtual nsresult UntrackFromService();
@ -133,6 +130,11 @@ protected:
}
}
// Should be nsIPresentationChannelDescription::TYPE_TCP/TYPE_DATACHANNEL
uint8_t mTransportType = 0;
nsPIDOMWindowInner* GetWindow();
nsString mUrl;
nsString mSessionId;
bool mIsResponderReady;
@ -143,6 +145,7 @@ protected:
nsCOMPtr<nsIPresentationDevice> mDevice;
nsCOMPtr<nsIPresentationSessionTransport> mTransport;
nsCOMPtr<nsIPresentationControlChannel> mControlChannel;
nsCOMPtr<nsIPresentationSessionTransportBuilder> mBuilder;
};
// Session info with controlling browsing context (sender side) behaviors.
@ -177,6 +180,18 @@ private:
nsresult OnGetAddress(const nsACString& aAddress);
nsCOMPtr<nsIServerSocket> mServerSocket;
protected:
bool IsSessionReady() override
{
if (mTransportType == nsIPresentationChannelDescription::TYPE_TCP) {
return mIsResponderReady && mIsTransportReady;
} else if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
// Established RTCDataChannel implies responder is ready.
return mIsTransportReady;
}
return false;
}
};
// Session info with presenting browsing context (receiver side) behaviors.
@ -236,6 +251,12 @@ private:
// The content parent communicating with the content process which the OOP
// receiver page belongs to.
nsCOMPtr<nsIContentParent> mContentParent;
protected:
bool IsSessionReady() override
{
return mIsResponderReady && mIsTransportReady;
}
};
} // namespace dom

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

@ -151,11 +151,9 @@ PresentationTCPSessionTransport::BuildTCPReceiverTransport(nsIPresentationChanne
return rv;
}
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
// Ultimately we may use all the available addresses. DataChannel appears
// more robust upon handling ICE. And at the first stage Presentation API is
// only exposed on Firefox OS where the first IP appears enough for most
// scenarios.
// TODO bug 1228504 Take all IP addresses in PresentationChannelDescription
// into account. And at the first stage Presentation API is only exposed on
// Firefox OS where the first IP appears enough for most scenarios.
nsCOMPtr<nsISupportsCString> supportStr = do_QueryElementAt(serverHosts, 0);
if (NS_WARN_IF(!supportStr)) {
return NS_ERROR_INVALID_ARG;

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

@ -33,11 +33,6 @@ namespace dom {
* presenting receiver side. The lifetime is managed in either
* |PresentationControllingInfo| (sender side) or |PresentationPresentingInfo|
* (receiver side) in PresentationSessionInfo.cpp.
*
* TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
* The implementation over the TCP channel is primarily used for the early stage
* of Presentation API (without SSL) and should be migrated to DataChannel with
* full support soon.
*/
class PresentationTCPSessionTransport final : public nsIPresentationSessionTransport
, public nsIPresentationTCPSessionTransportBuilder

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

@ -39,6 +39,6 @@ interface nsIPresentationRespondingListener : nsISupports
/*
* Called when an incoming session connects.
*/
void notifySessionConnect(in uint64_t windowId,
void notifySessionConnect(in unsigned long long windowId,
in DOMString sessionId);
};

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

@ -33,7 +33,7 @@ interface nsIPresentationServiceCallback : nsISupports
void notifyError(in nsresult error);
};
[scriptable, uuid(61864149-9838-4aa1-a21a-63eaf0b84a8c)]
[scriptable, uuid(de42b741-5619-4650-b961-c2cebb572c95)]
interface nsIPresentationService : nsISupports
{
/*
@ -45,6 +45,10 @@ interface nsIPresentationService : nsISupports
* @param origin: The url of requesting page.
* @param deviceId: The specified device of handling this request, null string
for prompt device selection dialog.
* @param windowId: The inner window ID associated with the presentation
* session. (0 implies no window ID since no actual window
* uses 0 as its ID. Generally it's the case the window is
* located in different process from this service)
* @param callback: Invoke the callback when the operation is completed.
* NotifySuccess() is called with |id| if a session is
* established successfully with the selected device.
@ -54,6 +58,7 @@ interface nsIPresentationService : nsISupports
in DOMString sessionId,
in DOMString origin,
in DOMString deviceId,
in unsigned long long windowId,
in nsIPresentationServiceCallback callback);
/*
@ -114,14 +119,14 @@ interface nsIPresentationService : nsISupports
* @param windowId: The window ID associated with the listener.
* @param listener: The listener to register.
*/
void registerRespondingListener(in uint64_t windowId,
void registerRespondingListener(in unsigned long long windowId,
in nsIPresentationRespondingListener listener);
/*
* Unregister a responding listener. Must be called from the main thread.
* @param windowId: The window ID associated with the listener.
*/
void unregisterRespondingListener(in uint64_t windowId);
void unregisterRespondingListener(in unsigned long long windowId);
/*
* Check if the presentation instance has an existent session ID at launch.
@ -131,7 +136,7 @@ interface nsIPresentationService : nsISupports
*
* @param windowId: The inner window ID used to look up the session ID.
*/
DOMString getExistentSessionIdAtLaunch(in uint64_t windowId);
DOMString getExistentSessionIdAtLaunch(in unsigned long long windowId);
/*
* Notify the receiver page is ready for presentation use.
@ -139,10 +144,11 @@ interface nsIPresentationService : nsISupports
* @param sessionId: An ID to identify presentation session.
* @param windowId: The inner window ID associated with the presentation
* session. (0 implies no window ID since no actual window
* uses 0 as its ID.)
* uses 0 as its ID. Generally it's the case the window is
* located in different process from this service)
*/
void notifyReceiverReady(in DOMString sessionId,
[optional] in uint64_t windowId);
[optional] in unsigned long long windowId);
/*
* Untrack the relevant info about the presentation session if there's any.
@ -150,4 +156,9 @@ interface nsIPresentationService : nsISupports
* @param sessionId: An ID to identify presentation session.
*/
void untrackSessionInfo(in DOMString sessionId);
/*
* The windowId for building RTCDataChannel session transport
*/
unsigned long long getWindowIdBySessionId(in DOMString sessionId);
};

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

@ -6,7 +6,7 @@
interface nsIPresentationChannelDescription;
interface nsISocketTransport;
interface nsIDOMWindow;
interface mozIDOMWindow;
interface nsIPresentationControlChannel;
interface nsIPresentationSessionTransport;
@ -58,7 +58,7 @@ interface nsIPresentationDataChannelSessionTransportBuilder : nsIPresentationSes
* |buildDataChannelTransport|.
*/
void buildDataChannelTransport(in uint8_t aType,
in nsIDOMWindow aWindow,
in mozIDOMWindow aWindow,
in nsIPresentationControlChannel aControlChannel,
in nsIPresentationSessionTransportBuilderListener aListener);
};

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

@ -50,12 +50,18 @@ PresentationIPCService::StartSession(const nsAString& aUrl,
const nsAString& aSessionId,
const nsAString& aOrigin,
const nsAString& aDeviceId,
uint64_t aWindowId,
nsIPresentationServiceCallback* aCallback)
{
return SendRequest(aCallback, StartSessionRequest(nsAutoString(aUrl),
nsAutoString(aSessionId),
nsAutoString(aOrigin),
nsAutoString(aDeviceId)));
if (aWindowId != 0) {
mRespondingSessionIds.Put(aWindowId, new nsString(aSessionId));
mRespondingWindowIds.Put(aSessionId, aWindowId);
}
return SendRequest(aCallback, StartSessionRequest(nsString(aUrl),
nsString(aSessionId),
nsString(aOrigin),
nsString(aDeviceId)));
}
NS_IMETHODIMP
@ -65,8 +71,8 @@ PresentationIPCService::SendSessionMessage(const nsAString& aSessionId,
MOZ_ASSERT(!aSessionId.IsEmpty());
MOZ_ASSERT(!aData.IsEmpty());
return SendRequest(nullptr, SendSessionMessageRequest(nsAutoString(aSessionId),
nsAutoString(aData)));
return SendRequest(nullptr, SendSessionMessageRequest(nsString(aSessionId),
nsString(aData)));
}
NS_IMETHODIMP
@ -74,7 +80,7 @@ PresentationIPCService::CloseSession(const nsAString& aSessionId)
{
MOZ_ASSERT(!aSessionId.IsEmpty());
return SendRequest(nullptr, CloseSessionRequest(nsAutoString(aSessionId)));
return SendRequest(nullptr, CloseSessionRequest(nsString(aSessionId)));
}
NS_IMETHODIMP
@ -82,7 +88,7 @@ PresentationIPCService::TerminateSession(const nsAString& aSessionId)
{
MOZ_ASSERT(!aSessionId.IsEmpty());
return SendRequest(nullptr, TerminateSessionRequest(nsAutoString(aSessionId)));
return SendRequest(nullptr, TerminateSessionRequest(nsString(aSessionId)));
}
nsresult
@ -131,7 +137,7 @@ PresentationIPCService::RegisterSessionListener(const nsAString& aSessionId,
mSessionListeners.Put(aSessionId, aListener);
if (sPresentationChild) {
NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(nsAutoString(aSessionId)));
NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(nsString(aSessionId)));
}
return NS_OK;
}
@ -145,7 +151,7 @@ PresentationIPCService::UnregisterSessionListener(const nsAString& aSessionId)
mSessionListeners.Remove(aSessionId);
if (sPresentationChild) {
NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(nsAutoString(aSessionId)));
NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(nsString(aSessionId)));
}
return NS_OK;
}
@ -175,6 +181,16 @@ PresentationIPCService::UnregisterRespondingListener(uint64_t aWindowId)
return NS_OK;
}
NS_IMETHODIMP
PresentationIPCService::GetWindowIdBySessionId(const nsAString& aSessionId,
uint64_t* aWindowId)
{
if (mRespondingWindowIds.Get(aSessionId, aWindowId)) {
return NS_OK;
}
return NS_ERROR_NOT_AVAILABLE;
}
nsresult
PresentationIPCService::NotifySessionStateChange(const nsAString& aSessionId,
uint16_t aState)
@ -250,10 +266,10 @@ PresentationIPCService::NotifyReceiverReady(const nsAString& aSessionId,
}
// Track the responding info for an OOP receiver page.
mRespondingSessionIds.Put(aWindowId, new nsAutoString(aSessionId));
mRespondingSessionIds.Put(aWindowId, new nsString(aSessionId));
mRespondingWindowIds.Put(aSessionId, aWindowId);
NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsAutoString(aSessionId)));
NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsString(aSessionId)));
// Release mCallback after using aSessionId
// because aSessionId is held by mCallback.

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

@ -186,7 +186,7 @@ PresentationParent::NotifyStateChange(const nsAString& aSessionId,
uint16_t aState)
{
if (NS_WARN_IF(mActorDestroyed ||
!SendNotifySessionStateChange(nsAutoString(aSessionId), aState))) {
!SendNotifySessionStateChange(nsString(aSessionId), aState))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
@ -197,7 +197,7 @@ PresentationParent::NotifyMessage(const nsAString& aSessionId,
const nsACString& aData)
{
if (NS_WARN_IF(mActorDestroyed ||
!SendNotifyMessage(nsAutoString(aSessionId), nsAutoCString(aData)))) {
!SendNotifyMessage(nsString(aSessionId), nsCString(aData)))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
@ -208,7 +208,7 @@ PresentationParent::NotifySessionConnect(uint64_t aWindowId,
const nsAString& aSessionId)
{
if (NS_WARN_IF(mActorDestroyed ||
!SendNotifySessionConnect(aWindowId, nsAutoString(aSessionId)))) {
!SendNotifySessionConnect(aWindowId, nsString(aSessionId)))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
@ -218,6 +218,8 @@ bool
PresentationParent::RecvNotifyReceiverReady(const nsString& aSessionId)
{
MOZ_ASSERT(mService);
// Set window ID to 0 since the window is from content process.
NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId, 0)));
return true;
}
@ -251,8 +253,10 @@ nsresult
PresentationRequestParent::DoRequest(const StartSessionRequest& aRequest)
{
MOZ_ASSERT(mService);
// Set window ID to 0 since the window is from content process.
return mService->StartSession(aRequest.url(), aRequest.sessionId(),
aRequest.origin(), aRequest.deviceId(), this);
aRequest.origin(), aRequest.deviceId(), 0, this);
}
nsresult

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

@ -65,6 +65,10 @@ IPDL_SOURCES += [
'ipc/PPresentationRequest.ipdl'
]
LOCAL_INCLUDES += [
'../base'
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

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

@ -6,6 +6,8 @@
const { classes: Cc, interfaces: Ci, manager: Cm, utils: Cu, results: Cr } = Components;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/Timer.jsm');
function registerMockedFactory(contractId, mockedClassId, mockedFactory) {
var originalClassId, originalFactory;
@ -49,7 +51,12 @@ addresses.appendElement(address, false);
const mockedChannelDescription = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
type: 1,
get type() {
if (Services.prefs.getBoolPref("dom.presentation.session_transport.data_channel.enable")) {
return Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL;
}
return Ci.nsIPresentationChannelDescription.TYPE_TCP;
},
tcpAddress: addresses,
tcpPort: 1234,
};
@ -199,6 +206,8 @@ const mockedDevicePrompt = {
const mockedSessionTransport = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransport,
Ci.nsIPresentationTCPSessionTransportBuilder,
Ci.nsIPresentationDataChannelSessionTransportBuilder,
Ci.nsIPresentationControlChannelListener,
Ci.nsIFactory]),
createInstance: function(aOuter, aIID) {
if (aOuter) {
@ -220,10 +229,11 @@ const mockedSessionTransport = {
this._listener = listener;
this._type = Ci.nsIPresentationSessionTransportBuilder.TYPE_SENDER;
setTimeout(()=>{
this._listener.onSessionTransport(this);
this._listener = null;
this.simulateTransportReady();
}, 0);
},
buildTCPReceiverTransport: function(description, listener) {
this._listener = listener;
@ -237,8 +247,25 @@ const mockedSessionTransport = {
port: description.QueryInterface(Ci.nsIPresentationChannelDescription).tcpPort,
};
setTimeout(()=>{
this._listener.onSessionTransport(this);
this._listener = null;
}, 0);
},
// in-process case
buildDataChannelTransport: function(type, window, controlChannel, listener) {
dump("build data channel transport\n");
this._listener = listener;
this._type = type;
var hasNavigator = window ? (typeof window.navigator != "undefined") : false;
sendAsyncMessage('check-navigator', hasNavigator);
setTimeout(()=>{
this._listener.onSessionTransport(this);
this._listener = null;
this.simulateTransportReady();
}, 0);
},
enableDataNotification: function() {
sendAsyncMessage('data-transport-notification-enabled');
@ -256,6 +283,10 @@ const mockedSessionTransport = {
simulateIncomingMessage: function(message) {
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message);
},
onOffer: function(aOffer) {
},
onAnswer: function(aAnswer) {
}
};
const mockedNetworkInfo = {
@ -311,6 +342,9 @@ originalFactoryData.push(registerMockedFactory("@mozilla.org/network/server-sock
originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation/presentationtcpsessiontransport;1",
uuidGenerator.generateUUID(),
mockedSessionTransport));
originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation/datachanneltransportbuilder;1",
uuidGenerator.generateUUID(),
mockedSessionTransport));
originalFactoryData.push(registerMockedFactory("@mozilla.org/network/manager;1",
uuidGenerator.generateUUID(),
mockedNetworkManager));

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

@ -9,23 +9,28 @@ support-files =
file_presentation_receiver_inner_iframe_oop.html
file_presentation_non_receiver_inner_iframe_oop.html
[test_presentation_dc_sender.html]
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
[test_presentation_dc_receiver.html]
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
[test_presentation_device_info.html]
[test_presentation_device_info_permission.html]
[test_presentation_sender_disconnect.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_sender_establish_connection_error.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_sender.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_sender_default_request.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_sender_startWithDevice.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_receiver_establish_connection_error.html]
[test_presentation_tcp_sender_disconnect.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_tcp_sender_establish_connection_error.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_tcp_sender.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_tcp_sender_default_request.html]
skip-if = toolkit == 'android' # Bug 1129785
[test_presentation_tcp_receiver_establish_connection_error.html]
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android' || os == 'mac' || os == 'win' || buildapp == 'mulet') # Bug 1129785, Bug 1204709
[test_presentation_receiver_establish_connection_timeout.html]
[test_presentation_tcp_receiver_establish_connection_timeout.html]
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
[test_presentation_receiver.html]
[test_presentation_tcp_receiver.html]
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
[test_presentation_receiver_oop.html]
[test_presentation_tcp_receiver_oop.html]
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785

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

@ -0,0 +1,136 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G PresentationConnection API at receiver side</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1148307">Test for B2G PresentationConnection API at receiver side</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script type="application/javascript">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver.html');
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
.getService(SpecialPowers.Ci.nsIObserverService);
function setup() {
return new Promise(function(aResolve, aReject) {
gScript.sendAsyncMessage('trigger-device-add');
var iframe = document.createElement('iframe');
iframe.setAttribute('src', receiverUrl);
// This event is triggered when the iframe calls "postMessage".
window.addEventListener('message', function listener(aEvent) {
var message = aEvent.data;
if (/^OK /.exec(message)) {
ok(true, "Message from iframe: " + message);
} else if (/^KO /.exec(message)) {
ok(false, "Message from iframe: " + message);
} else if (/^INFO /.exec(message)) {
info("Message from iframe: " + message);
} else if (/^COMMAND /.exec(message)) {
var command = JSON.parse(message.replace(/^COMMAND /, ''));
gScript.sendAsyncMessage(command.name, command.data);
} else if (/^DONE$/.exec(message)) {
ok(true, "Messaging from iframe complete.");
window.removeEventListener('message', listener);
teardown();
}
}, false);
var promise = new Promise(function(aResolve, aReject) {
document.body.appendChild(iframe);
aResolve(iframe);
});
obs.notifyObservers(promise, 'setup-request-promise', null);
gScript.addMessageListener('offer-received', function offerReceivedHandler() {
gScript.removeMessageListener('offer-received', offerReceivedHandler);
info("An offer is received.");
});
gScript.addMessageListener('answer-sent', function answerSentHandler(aIsValid) {
gScript.removeMessageListener('answer-sent', answerSentHandler);
ok(aIsValid, "A valid answer is sent.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed normally.");
});
gScript.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
gScript.removeMessageListener('check-navigator', checknavigatorHandler);
ok(aSuccess, "buildDataChannel get correct window object");
});
gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
info("Data notification is enabled for data transport channel.");
});
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
is(aReason, SpecialPowers.Cr.NS_OK, "The data transport should be closed normally.");
});
aResolve();
});
}
function testIncomingSessionRequest() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
info("Trying to launch receiver page.");
ok(navigator.presentation, "navigator.presentation should be available in in-process pages.");
ok(!navigator.presentation.receiver, "Non-receiving in-process pages shouldn't get a presentation receiver instance.");
aResolve();
});
gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
setup().
then(testIncomingSessionRequest);
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'presentation', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.session_transport.data_channel.enable", true]]},
runTests);
});
</script>
</body>
</html>

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

@ -0,0 +1,208 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for B2G Presentation API at sender side</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1148307">Test for B2G Presentation API at sender side</a>
<script type="application/javascript;version=1.8">
'use strict';
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
var request;
var connection;
function testSetup() {
return new Promise(function(aResolve, aReject) {
request = new PresentationRequest("http://example.com");
request.getAvailability().then(
function(aAvailability) {
aAvailability.onchange = function() {
aAvailability.onchange = null;
ok(aAvailability.value, "Device should be available.");
aResolve();
}
},
function(aError) {
ok(false, "Error occurred when getting availability: " + aError);
teardown();
aReject();
}
);
gScript.sendAsyncMessage('trigger-device-add');
});
}
function testStartConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
gScript.removeMessageListener('device-prompt', devicePromptHandler);
info("Device prompt is triggered.");
gScript.sendAsyncMessage('trigger-device-prompt-select');
});
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
info("A control channel is established.");
gScript.sendAsyncMessage('trigger-control-channel-open');
});
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
info("The control channel is opened.");
});
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
info("The control channel is closed. " + aReason);
});
gScript.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
gScript.removeMessageListener('check-navigator', checknavigatorHandler);
ok(aSuccess, "buildDataChannel get correct window object");
});
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
gScript.removeMessageListener('offer-sent', offerSentHandler);
ok(aIsValid, "A valid offer is sent out.");
gScript.sendAsyncMessage('trigger-incoming-transport');
});
gScript.addMessageListener('answer-received', function answerReceivedHandler() {
gScript.removeMessageListener('answer-received', answerReceivedHandler);
info("An answer is received.");
});
gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
info("Data transport channel is initialized.");
gScript.sendAsyncMessage('trigger-incoming-answer');
});
gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
info("Data notification is enabled for data transport channel.");
});
var connectionFromEvent;
request.onconnectionavailable = function(aEvent) {
request.onconnectionavailable = null;
connectionFromEvent = aEvent.connection;
ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
if (connection) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
aResolve();
}
};
request.start().then(
function(aConnection) {
connection = aConnection;
ok(connection, "Connection should be available.");
ok(connection.id, "Connection ID should be set.");
is(connection.state, "connected", "Connection state at sender side should be connected by default.");
if (connectionFromEvent) {
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
aResolve();
}
},
function(aError) {
ok(false, "Error occurred when establishing a connection: " + aError);
teardown();
aReject();
}
);
});
}
function testSend() {
return new Promise(function(aResolve, aReject) {
const outgoingMessage = "test outgoing message";
gScript.addMessageListener('message-sent', function messageSentHandler(aMessage) {
gScript.removeMessageListener('message-sent', messageSentHandler);
is(aMessage, outgoingMessage, "The message is sent out.");
aResolve();
});
connection.send(outgoingMessage);
});
}
function testIncomingMessage() {
return new Promise(function(aResolve, aReject) {
const incomingMessage = "test incoming message";
connection.addEventListener('message', function messageHandler(aEvent) {
connection.removeEventListener('message', messageHandler);
is(aEvent.data, incomingMessage, "An incoming message should be received.");
aResolve();
});
gScript.sendAsyncMessage('trigger-incoming-message', incomingMessage);
});
}
function testTerminateConnection() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
info("The data transport is closed. " + aReason);
});
connection.onstatechange = function() {
connection.onstatechange = null;
is(connection.state, "terminated", "Connection should be terminated.");
aResolve();
};
connection.terminate();
});
}
function teardown() {
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
gScript.destroy();
info('teardown-complete');
SimpleTest.finish();
});
gScript.sendAsyncMessage('teardown');
}
function runTests() {
ok(window.PresentationRequest, "PresentationRequest should be available.");
testSetup().
then(testStartConnection).
then(testSend).
then(testIncomingMessage).
then(testTerminateConnection).
then(teardown);
}
SimpleTest.expectAssertions(0, 5);
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'presentation', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.session_transport.data_channel.enable", true]]},
runTests);
});
</script>
</body>
</html>

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

@ -156,7 +156,6 @@ function runTests() {
then(teardown);
}
//SimpleTest.expectAssertions(0, 5);
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: true, context: document},

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

@ -116,15 +116,13 @@ function runTests() {
then(testIncomingSessionRequest);
}
SimpleTest.expectAssertions(0, 5);
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'presentation', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.test.enabled", true],
["dom.presentation.test.stage", 0]]},
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});

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

@ -91,15 +91,13 @@ function runTests() {
then(testIncomingSessionRequest);
}
SimpleTest.expectAssertions(0, 5);
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'presentation', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.test.enabled", true],
["dom.presentation.test.stage", 0]]},
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});

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

@ -65,15 +65,13 @@ function runTests() {
then(teardown);
}
SimpleTest.expectAssertions(0, 5);
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'presentation', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.test.enabled", true],
["dom.presentation.test.stage", 0],
["dom.presentation.session_transport.data_channel.enable", false],
["presentation.receiver.loading.timeout", 10]]},
runTests);
});

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

@ -157,7 +157,6 @@ function runTests() {
then(testIncomingSessionRequest);
}
SimpleTest.expectAssertions(0, 5);
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
@ -165,8 +164,7 @@ SpecialPowers.pushPermissions([
{type: 'browser', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.test.enabled", true],
["dom.presentation.test.stage", 0],
["dom.presentation.session_transport.data_channel.enable", false],
["dom.mozBrowserFramesEnabled", true],
["dom.ipc.browser_frames.oop_by_default", true]]},
runTests);

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

@ -186,15 +186,13 @@ function runTests() {
then(teardown);
}
SimpleTest.expectAssertions(0, 5);
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'presentation', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.test.enabled", true],
["dom.presentation.test.stage", 0]]},
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});

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

@ -134,15 +134,13 @@ function runTests() {
then(teardown);
}
SimpleTest.expectAssertions(0, 5);
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'presentation', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.test.enabled", true],
["dom.presentation.test.stage", 0]]},
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});

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

@ -140,15 +140,13 @@ function runTests() {
then(teardown);
}
SimpleTest.expectAssertions(0, 5);
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'presentation', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.test.enabled", true],
["dom.presentation.test.stage", 0]]},
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});

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

@ -344,15 +344,13 @@ function runTests() {
then(teardown);
}
SimpleTest.expectAssertions(0, 5);
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPermissions([
{type: 'presentation-device-manage', allow: false, context: document},
{type: 'presentation', allow: true, context: document},
], function() {
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
["dom.presentation.test.enabled", true],
["dom.presentation.test.stage", 0]]},
["dom.presentation.session_transport.data_channel.enable", false]]},
runTests);
});

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

@ -43,7 +43,7 @@ interface PresentationConnection : EventTarget {
*
* This function only works when the state is "connected".
*
* TODO bug 1148307 Implement PresentationSessionTransport with DataChannel to
* TODO bug 1228474 Implement PresentationSessionTransport with DataChannel to
* support other binary types.
*/
[Throws]

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

@ -5064,6 +5064,7 @@ pref("dom.presentation.tcp_server.debug", false);
pref("dom.presentation.discovery.enabled", false);
pref("dom.presentation.discovery.timeout_ms", 10000);
pref("dom.presentation.discoverable", false);
pref("dom.presentation.session_transport.data_channel.enable", true);
#ifdef XP_MACOSX
#if !defined(RELEASE_BUILD) || defined(DEBUG)