зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1228474 - Support sending blob/arraybuffer for data channel. r=smaug
This commit is contained in:
Родитель
e2d5d5425f
Коммит
6c373070a1
|
@ -9,6 +9,7 @@
|
|||
#include "ControllerConnectionCollection.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/MessageEvent.h"
|
||||
#include "mozilla/dom/MessageEventBinding.h"
|
||||
#include "mozilla/dom/PresentationConnectionClosedEvent.h"
|
||||
|
@ -54,6 +55,7 @@ PresentationConnection::PresentationConnection(nsPIDOMWindowInner* aWindow,
|
|||
, mUrl(aUrl)
|
||||
, mState(PresentationConnectionState::Connecting)
|
||||
, mOwningConnectionList(aList)
|
||||
, mBinaryType(PresentationConnectionBinaryType::Arraybuffer)
|
||||
{
|
||||
MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
|
||||
aRole == nsIPresentationService::ROLE_RECEIVER);
|
||||
|
@ -169,6 +171,18 @@ PresentationConnection::State() const
|
|||
return mState;
|
||||
}
|
||||
|
||||
PresentationConnectionBinaryType
|
||||
PresentationConnection::BinaryType() const
|
||||
{
|
||||
return mBinaryType;
|
||||
}
|
||||
|
||||
void
|
||||
PresentationConnection::SetBinaryType(PresentationConnectionBinaryType aType)
|
||||
{
|
||||
mBinaryType = aType;
|
||||
}
|
||||
|
||||
void
|
||||
PresentationConnection::Send(const nsAString& aData,
|
||||
ErrorResult& aRv)
|
||||
|
@ -182,13 +196,107 @@ PresentationConnection::Send(const nsAString& aData,
|
|||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if(NS_WARN_IF(!service)) {
|
||||
aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
|
||||
AsyncCloseConnectionWithErrorMsg(
|
||||
NS_LITERAL_STRING("Unable to send message due to an internal error."));
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = service->SendSessionMessage(mId, mRole, aData);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
|
||||
const uint32_t kMaxMessageLength = 256;
|
||||
nsAutoString data(Substring(aData, 0, kMaxMessageLength));
|
||||
|
||||
AsyncCloseConnectionWithErrorMsg(
|
||||
NS_LITERAL_STRING("Unable to send message: \"") + data +
|
||||
NS_LITERAL_STRING("\""));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresentationConnection::Send(Blob& aData,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if(NS_WARN_IF(!service)) {
|
||||
AsyncCloseConnectionWithErrorMsg(
|
||||
NS_LITERAL_STRING("Unable to send message due to an internal error."));
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = service->SendSessionBlob(mId, mRole, &aData);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
AsyncCloseConnectionWithErrorMsg(
|
||||
NS_LITERAL_STRING("Unable to send binary message for Blob message."));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresentationConnection::Send(const ArrayBuffer& aData,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if(NS_WARN_IF(!service)) {
|
||||
AsyncCloseConnectionWithErrorMsg(
|
||||
NS_LITERAL_STRING("Unable to send message due to an internal error."));
|
||||
return;
|
||||
}
|
||||
|
||||
aData.ComputeLengthAndData();
|
||||
|
||||
static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
|
||||
|
||||
uint32_t length = aData.Length();
|
||||
char* data = reinterpret_cast<char*>(aData.Data());
|
||||
nsDependentCSubstring msgString(data, length);
|
||||
|
||||
nsresult rv = service->SendSessionBinaryMsg(mId, mRole, msgString);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
AsyncCloseConnectionWithErrorMsg(
|
||||
NS_LITERAL_STRING("Unable to send binary message for ArrayBuffer message."));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresentationConnection::Send(const ArrayBufferView& aData,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if(NS_WARN_IF(!service)) {
|
||||
AsyncCloseConnectionWithErrorMsg(
|
||||
NS_LITERAL_STRING("Unable to send message due to an internal error."));
|
||||
return;
|
||||
}
|
||||
|
||||
aData.ComputeLengthAndData();
|
||||
|
||||
static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
|
||||
|
||||
uint32_t length = aData.Length();
|
||||
char* data = reinterpret_cast<char*>(aData.Data());
|
||||
nsDependentCSubstring msgString(data, length);
|
||||
|
||||
nsresult rv = service->SendSessionBinaryMsg(mId, mRole, msgString);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
AsyncCloseConnectionWithErrorMsg(
|
||||
NS_LITERAL_STRING("Unable to send binary message for ArrayBufferView message."));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,7 +460,8 @@ PresentationConnection::ProcessStateChanged(nsresult aReason)
|
|||
|
||||
NS_IMETHODIMP
|
||||
PresentationConnection::NotifyMessage(const nsAString& aSessionId,
|
||||
const nsACString& aData)
|
||||
const nsACString& aData,
|
||||
bool aIsBinary)
|
||||
{
|
||||
PRES_DEBUG("connection %s:id[%s], data[%s], role[%d]\n", __func__,
|
||||
NS_ConvertUTF16toUTF8(aSessionId).get(),
|
||||
|
@ -367,6 +476,18 @@ PresentationConnection::NotifyMessage(const nsAString& aSessionId,
|
|||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(DoReceiveMessage(aData, aIsBinary)))) {
|
||||
AsyncCloseConnectionWithErrorMsg(
|
||||
NS_LITERAL_STRING("Unable to receive a message."));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationConnection::DoReceiveMessage(const nsACString& aData, bool aIsBinary)
|
||||
{
|
||||
// Transform the data.
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(GetOwner())) {
|
||||
|
@ -374,9 +495,30 @@ PresentationConnection::NotifyMessage(const nsAString& aSessionId,
|
|||
}
|
||||
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;
|
||||
|
||||
nsresult rv;
|
||||
if (aIsBinary) {
|
||||
if (mBinaryType == PresentationConnectionBinaryType::Blob) {
|
||||
rv = nsContentUtils::CreateBlobBuffer(cx, GetOwner(), aData, &jsData);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
} else if (mBinaryType == PresentationConnectionBinaryType::Arraybuffer) {
|
||||
JS::Rooted<JSObject*> arrayBuf(cx);
|
||||
rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
jsData.setObject(*arrayBuf);
|
||||
} else {
|
||||
NS_RUNTIMEABORT("Unknown binary type!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
} else {
|
||||
NS_ConvertUTF8toUTF16 utf16Data(aData);
|
||||
if(NS_WARN_IF(!ToJSValue(cx, utf16Data, &jsData))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return DispatchMessageEvent(jsData);
|
||||
|
@ -396,7 +538,8 @@ PresentationConnection::NotifyReplaced()
|
|||
nsresult
|
||||
PresentationConnection::DispatchConnectionClosedEvent(
|
||||
PresentationConnectionClosedReason aReason,
|
||||
const nsAString& aMessage)
|
||||
const nsAString& aMessage,
|
||||
bool aDispatchNow)
|
||||
{
|
||||
if (mState != PresentationConnectionState::Closed) {
|
||||
MOZ_ASSERT(false, "The connection state should be closed.");
|
||||
|
@ -413,6 +556,11 @@ PresentationConnection::DispatchConnectionClosedEvent(
|
|||
init);
|
||||
closedEvent->SetTrusted(true);
|
||||
|
||||
if (aDispatchNow) {
|
||||
bool ignore;
|
||||
return DOMEventTargetHelper::DispatchEvent(closedEvent, &ignore);
|
||||
}
|
||||
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, static_cast<Event*>(closedEvent));
|
||||
return asyncDispatcher->PostDOMEvent();
|
||||
|
@ -579,3 +727,39 @@ PresentationConnection::RemoveFromLoadGroup()
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
PresentationConnection::AsyncCloseConnectionWithErrorMsg(const nsAString& aMessage)
|
||||
{
|
||||
if (mState == PresentationConnectionState::Terminated) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsString message = nsString(aMessage);
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableFunction([this, message]() -> void {
|
||||
// Set |mState| to |PresentationConnectionState::Closed| here to avoid
|
||||
// calling |ProcessStateChanged|.
|
||||
mState = PresentationConnectionState::Closed;
|
||||
|
||||
// Make sure dispatching the event and closing the connection are invoked
|
||||
// at the same time by setting |aDispatchNow| to true.
|
||||
Unused << NS_WARN_IF(NS_FAILED(
|
||||
DispatchConnectionClosedEvent(PresentationConnectionClosedReason::Error,
|
||||
message,
|
||||
true)));
|
||||
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if(NS_WARN_IF(!service)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Unused << NS_WARN_IF(NS_FAILED(
|
||||
service->CloseSession(mId,
|
||||
mRole,
|
||||
nsIPresentationService::CLOSED_REASON_ERROR)));
|
||||
});
|
||||
|
||||
Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(r)));
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#define mozilla_dom_PresentationConnection_h
|
||||
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "mozilla/dom/PresentationConnectionBinding.h"
|
||||
#include "mozilla/dom/PresentationConnectionClosedEventBinding.h"
|
||||
|
@ -18,6 +19,7 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Blob;
|
||||
class PresentationConnectionList;
|
||||
|
||||
class PresentationConnection final : public DOMEventTargetHelper
|
||||
|
@ -52,9 +54,22 @@ public:
|
|||
|
||||
PresentationConnectionState State() const;
|
||||
|
||||
PresentationConnectionBinaryType BinaryType() const;
|
||||
|
||||
void SetBinaryType(PresentationConnectionBinaryType aType);
|
||||
|
||||
void Send(const nsAString& aData,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void Send(Blob& aData,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void Send(const ArrayBuffer& aData,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void Send(const ArrayBufferView& aData,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void Close(ErrorResult& aRv);
|
||||
|
||||
void Terminate(ErrorResult& aRv);
|
||||
|
@ -83,7 +98,8 @@ private:
|
|||
nsresult ProcessStateChanged(nsresult aReason);
|
||||
|
||||
nsresult DispatchConnectionClosedEvent(PresentationConnectionClosedReason aReason,
|
||||
const nsAString& aMessage);
|
||||
const nsAString& aMessage,
|
||||
bool aDispatchNow = false);
|
||||
|
||||
nsresult DispatchMessageEvent(JS::Handle<JS::Value> aData);
|
||||
|
||||
|
@ -93,12 +109,17 @@ private:
|
|||
|
||||
nsresult RemoveFromLoadGroup();
|
||||
|
||||
void AsyncCloseConnectionWithErrorMsg(const nsAString& aMessage);
|
||||
|
||||
nsresult DoReceiveMessage(const nsACString& aData, bool aIsBinary);
|
||||
|
||||
nsString mId;
|
||||
nsString mUrl;
|
||||
uint8_t mRole;
|
||||
PresentationConnectionState mState;
|
||||
RefPtr<PresentationConnectionList> mOwningConnectionList;
|
||||
nsWeakPtr mWeakLoadGroup;;
|
||||
nsWeakPtr mWeakLoadGroup;
|
||||
PresentationConnectionBinaryType mBinaryType;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -27,7 +27,7 @@ function PresentationDataChannelDescription(aDataChannelSDP) {
|
|||
PresentationDataChannelDescription.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
|
||||
get type() {
|
||||
return nsIPresentationChannelDescription.TYPE_DATACHANNEL;
|
||||
return Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL;
|
||||
},
|
||||
get tcpAddress() {
|
||||
return null;
|
||||
|
@ -94,6 +94,8 @@ PresentationTransportBuilder.prototype = {
|
|||
case Ci.nsIPresentationService.ROLE_RECEIVER:
|
||||
this._peerConnection.ondatachannel = aEvent => {
|
||||
this._dataChannel = aEvent.channel;
|
||||
// Ensure the binaryType of dataChannel is blob.
|
||||
this._dataChannel.binaryType = "blob";
|
||||
this._setDataChannel();
|
||||
}
|
||||
break;
|
||||
|
@ -134,7 +136,7 @@ PresentationTransportBuilder.prototype = {
|
|||
// Handoff the ownership of _peerConnection and _dataChannel to
|
||||
// _sessionTransport
|
||||
this._sessionTransport = new PresentationTransport();
|
||||
this._sessionTransport.init(this._peerConnection, this._dataChannel);
|
||||
this._sessionTransport.init(this._peerConnection, this._dataChannel, this._window);
|
||||
this._peerConnection = this._dataChannel = null;
|
||||
|
||||
this._listener.onSessionTransport(this._sessionTransport);
|
||||
|
@ -243,11 +245,12 @@ PresentationTransport.prototype = {
|
|||
contractID: PRESENTATIONTRANSPORT_CONTRACTID,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransport]),
|
||||
|
||||
init: function(aPeerConnection, aDataChannel) {
|
||||
init: function(aPeerConnection, aDataChannel, aWindow) {
|
||||
log("initWithDataChannel");
|
||||
this._enableDataNotification = false;
|
||||
this._dataChannel = aDataChannel;
|
||||
this._peerConnection = aPeerConnection;
|
||||
this._window = aWindow;
|
||||
|
||||
this._dataChannel.onopen = () => {
|
||||
log("data channel reopen. Should never touch here");
|
||||
|
@ -269,7 +272,7 @@ PresentationTransport.prototype = {
|
|||
this._messageQueue.push(aEvent.data);
|
||||
return;
|
||||
}
|
||||
this._callback.notifyData(aEvent.data);
|
||||
this._doNotifyData(aEvent.data);
|
||||
};
|
||||
|
||||
this._dataChannel.onerror = aError => {
|
||||
|
@ -299,6 +302,23 @@ PresentationTransport.prototype = {
|
|||
this._dataChannel.send(aData);
|
||||
},
|
||||
|
||||
sendBinaryMsg: function(aData) {
|
||||
log("sendBinaryMsg");
|
||||
|
||||
let array = new Uint8Array(aData.length);
|
||||
for (let i = 0; i < aData.length; i++) {
|
||||
array[i] = aData.charCodeAt(i);
|
||||
}
|
||||
|
||||
this._dataChannel.send(array);
|
||||
},
|
||||
|
||||
sendBlob: function(aBlob) {
|
||||
log("sendBlob");
|
||||
|
||||
this._dataChannel.send(aBlob);
|
||||
},
|
||||
|
||||
enableDataNotification: function() {
|
||||
log("enableDataNotification");
|
||||
if (this._enableDataNotification) {
|
||||
|
@ -311,7 +331,7 @@ PresentationTransport.prototype = {
|
|||
|
||||
this._enableDataNotification = true;
|
||||
|
||||
this._messageQueue.forEach(aData => this._callback.notifyData(aData));
|
||||
this._messageQueue.forEach(aData => this._doNotifyData(aData));
|
||||
this._messageQueue = [];
|
||||
},
|
||||
|
||||
|
@ -330,6 +350,23 @@ PresentationTransport.prototype = {
|
|||
}
|
||||
this._callback = null;
|
||||
this._messageQueue = [];
|
||||
this._window = null;
|
||||
},
|
||||
|
||||
_doNotifyData: function(aData) {
|
||||
if (!this._callback) {
|
||||
throw NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (aData instanceof this._window.Blob) {
|
||||
let reader = new this._window.FileReader();
|
||||
reader.addEventListener("load", (aEvent) => {
|
||||
this._callback.notifyData(aEvent.target.result, true);
|
||||
});
|
||||
reader.readAsBinaryString(aData);
|
||||
} else {
|
||||
this._callback.notifyData(aData, false);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -776,6 +776,44 @@ PresentationService::SendSessionMessage(const nsAString& aSessionId,
|
|||
return info->Send(aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::SendSessionBinaryMsg(const nsAString& aSessionId,
|
||||
uint8_t aRole,
|
||||
const nsACString &aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aData.IsEmpty());
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
|
||||
aRole == nsIPresentationService::ROLE_RECEIVER);
|
||||
|
||||
RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return info->SendBinaryMsg(aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::SendSessionBlob(const nsAString& aSessionId,
|
||||
uint8_t aRole,
|
||||
nsIDOMBlob* aBlob)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
|
||||
aRole == nsIPresentationService::ROLE_RECEIVER);
|
||||
MOZ_ASSERT(aBlob);
|
||||
|
||||
RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return info->SendBlob(aBlob);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::CloseSession(const nsAString& aSessionId,
|
||||
uint8_t aRole,
|
||||
|
|
|
@ -284,6 +284,34 @@ PresentationSessionInfo::Send(const nsAString& aData)
|
|||
return mTransport->Send(aData);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationSessionInfo::SendBinaryMsg(const nsACString& aData)
|
||||
{
|
||||
if (NS_WARN_IF(!IsSessionReady())) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mTransport)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return mTransport->SendBinaryMsg(aData);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationSessionInfo::SendBlob(nsIDOMBlob* aBlob)
|
||||
{
|
||||
if (NS_WARN_IF(!IsSessionReady())) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!mTransport)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return mTransport->SendBlob(aBlob);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationSessionInfo::Close(nsresult aReason,
|
||||
uint32_t aState)
|
||||
|
@ -475,7 +503,7 @@ PresentationSessionInfo::NotifyTransportClosed(nsresult aReason)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationSessionInfo::NotifyData(const nsACString& aData)
|
||||
PresentationSessionInfo::NotifyData(const nsACString& aData, bool aIsBinary)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -487,7 +515,7 @@ PresentationSessionInfo::NotifyData(const nsACString& aData)
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return mListener->NotifyMessage(mSessionId, aData);
|
||||
return mListener->NotifyMessage(mSessionId, aData, aIsBinary);
|
||||
}
|
||||
|
||||
// nsIPresentationSessionTransportBuilderListener
|
||||
|
|
|
@ -99,6 +99,10 @@ public:
|
|||
|
||||
nsresult Send(const nsAString& aData);
|
||||
|
||||
nsresult SendBinaryMsg(const nsACString& aData);
|
||||
|
||||
nsresult SendBlob(nsIDOMBlob* aBlob);
|
||||
|
||||
nsresult Close(nsresult aReason,
|
||||
uint32_t aState);
|
||||
|
||||
|
|
|
@ -417,6 +417,18 @@ PresentationTCPSessionTransport::Send(const nsAString& aData)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationTCPSessionTransport::SendBinaryMsg(const nsACString& aData)
|
||||
{
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationTCPSessionTransport::SendBlob(nsIDOMBlob* aBlob)
|
||||
{
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationTCPSessionTransport::Close(nsresult aReason)
|
||||
{
|
||||
|
@ -573,5 +585,5 @@ PresentationTCPSessionTransport::OnDataAvailable(nsIRequest* aRequest,
|
|||
}
|
||||
|
||||
// Pass the incoming data to the listener.
|
||||
return mCallback->NotifyData(data);
|
||||
return mCallback->NotifyData(data, false);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,8 @@ interface nsIPresentationSessionListener : nsISupports
|
|||
* Called when receive messages.
|
||||
*/
|
||||
void notifyMessage(in DOMString sessionId,
|
||||
in ACString data);
|
||||
in ACString data,
|
||||
in boolean isBinary);
|
||||
|
||||
/*
|
||||
* Called when this listener is replaced by another one.
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMBlob;
|
||||
interface nsIDOMEventTarget;
|
||||
interface nsIInputStream;
|
||||
interface nsIPresentationAvailabilityListener;
|
||||
|
@ -95,6 +96,28 @@ interface nsIPresentationService : nsISupports
|
|||
in uint8_t role,
|
||||
in DOMString data);
|
||||
|
||||
/*
|
||||
* Send the binary message to the session.
|
||||
*
|
||||
* @param sessionId: An ID to identify presentation session.
|
||||
* @param role: Identify the function called by controller or receiver.
|
||||
* @param data: the message being sent out.
|
||||
*/
|
||||
void sendSessionBinaryMsg(in DOMString sessionId,
|
||||
in uint8_t role,
|
||||
in ACString data);
|
||||
|
||||
/*
|
||||
* Send the blob to the session.
|
||||
*
|
||||
* @param sessionId: An ID to identify presentation session.
|
||||
* @param role: Identify the function called by controller or receiver.
|
||||
* @param blob: The input blob to be sent.
|
||||
*/
|
||||
void sendSessionBlob(in DOMString sessionId,
|
||||
in uint8_t role,
|
||||
in nsIDOMBlob blob);
|
||||
|
||||
/*
|
||||
* Close the session.
|
||||
*
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMBlob;
|
||||
interface nsIInputStream;
|
||||
interface nsINetAddr;
|
||||
|
||||
|
@ -20,7 +21,7 @@ interface nsIPresentationSessionTransportCallback : nsISupports
|
|||
{
|
||||
void notifyTransportReady();
|
||||
void notifyTransportClosed(in nsresult reason);
|
||||
void notifyData(in ACString data);
|
||||
void notifyData(in ACString data, in boolean isBinary);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -48,6 +49,18 @@ interface nsIPresentationSessionTransport : nsISupports
|
|||
*/
|
||||
void send(in DOMString data);
|
||||
|
||||
/*
|
||||
* Send the binary message to the remote endpoint.
|
||||
* @param data: the message being sent out.
|
||||
*/
|
||||
void sendBinaryMsg(in ACString data);
|
||||
|
||||
/*
|
||||
* Send the blob to the remote endpoint.
|
||||
* @param blob: The input blob to be sent.
|
||||
*/
|
||||
void sendBlob(in nsIDOMBlob blob);
|
||||
|
||||
/*
|
||||
* Close this session transport.
|
||||
* @param reason The reason for closing this session transport.
|
||||
|
|
|
@ -79,7 +79,7 @@ child:
|
|||
async NotifySessionStateChange(nsString aSessionId,
|
||||
uint16_t aState,
|
||||
nsresult aReason);
|
||||
async NotifyMessage(nsString aSessionId, nsCString aData);
|
||||
async NotifyMessage(nsString aSessionId, nsCString aData, bool aIsBinary);
|
||||
async NotifySessionConnect(uint64_t aWindowId, nsString aSessionId);
|
||||
|
||||
async PPresentationBuilder(nsString aSessionId, uint8_t aRole);
|
||||
|
|
|
@ -112,10 +112,13 @@ PresentationChild::RecvNotifySessionStateChange(const nsString& aSessionId,
|
|||
|
||||
bool
|
||||
PresentationChild::RecvNotifyMessage(const nsString& aSessionId,
|
||||
const nsCString& aData)
|
||||
const nsCString& aData,
|
||||
const bool& aIsBinary)
|
||||
{
|
||||
if (mService) {
|
||||
Unused << NS_WARN_IF(NS_FAILED(mService->NotifyMessage(aSessionId, aData)));
|
||||
Unused << NS_WARN_IF(NS_FAILED(mService->NotifyMessage(aSessionId,
|
||||
aData,
|
||||
aIsBinary)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,8 @@ public:
|
|||
|
||||
virtual bool
|
||||
RecvNotifyMessage(const nsString& aSessionId,
|
||||
const nsCString& aData) override;
|
||||
const nsCString& aData,
|
||||
const bool& aIsBinary) override;
|
||||
|
||||
virtual bool
|
||||
RecvNotifySessionConnect(const uint64_t& aWindowId,
|
||||
|
|
|
@ -35,6 +35,26 @@ PresentationContentSessionInfo::Send(const nsAString& aData)
|
|||
return mTransport->Send(aData);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationContentSessionInfo::SendBinaryMsg(const nsACString& aData)
|
||||
{
|
||||
if (NS_WARN_IF(!mTransport)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return mTransport->SendBinaryMsg(aData);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationContentSessionInfo::SendBlob(nsIDOMBlob* aBlob)
|
||||
{
|
||||
if (NS_WARN_IF(!mTransport)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return mTransport->SendBlob(aBlob);
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationContentSessionInfo::Close(nsresult aReason)
|
||||
{
|
||||
|
@ -71,7 +91,8 @@ PresentationContentSessionInfo::NotifyTransportClosed(nsresult aReason)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationContentSessionInfo::NotifyData(const nsACString& aData)
|
||||
PresentationContentSessionInfo::NotifyData(const nsACString& aData,
|
||||
bool aIsBinary)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -81,7 +102,7 @@ PresentationContentSessionInfo::NotifyData(const nsACString& aData)
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
return static_cast<PresentationIPCService*>(service.get())->
|
||||
NotifyMessage(mSessionId, aData);
|
||||
NotifyMessage(mSessionId, aData, aIsBinary);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -42,6 +42,10 @@ public:
|
|||
|
||||
nsresult Send(const nsAString& aData);
|
||||
|
||||
nsresult SendBinaryMsg(const nsACString& aData);
|
||||
|
||||
nsresult SendBlob(nsIDOMBlob* aBlob);
|
||||
|
||||
nsresult Close(nsresult aReason);
|
||||
|
||||
private:
|
||||
|
|
|
@ -101,6 +101,46 @@ PresentationIPCService::SendSessionMessage(const nsAString& aSessionId,
|
|||
nsString(aData)));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationIPCService::SendSessionBinaryMsg(const nsAString& aSessionId,
|
||||
uint8_t aRole,
|
||||
const nsACString &aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aData.IsEmpty());
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
|
||||
aRole == nsIPresentationService::ROLE_RECEIVER);
|
||||
|
||||
RefPtr<PresentationContentSessionInfo> info;
|
||||
// data channel session transport is maintained by content process
|
||||
if (mSessionInfos.Get(aSessionId, getter_AddRefs(info))) {
|
||||
return info->SendBinaryMsg(aData);
|
||||
}
|
||||
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationIPCService::SendSessionBlob(const nsAString& aSessionId,
|
||||
uint8_t aRole,
|
||||
nsIDOMBlob* aBlob)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
|
||||
aRole == nsIPresentationService::ROLE_RECEIVER);
|
||||
MOZ_ASSERT(aBlob);
|
||||
|
||||
RefPtr<PresentationContentSessionInfo> info;
|
||||
// data channel session transport is maintained by content process
|
||||
if (mSessionInfos.Get(aSessionId, getter_AddRefs(info))) {
|
||||
return info->SendBlob(aBlob);
|
||||
}
|
||||
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationIPCService::CloseSession(const nsAString& aSessionId,
|
||||
uint8_t aRole,
|
||||
|
@ -332,14 +372,15 @@ PresentationIPCService::NotifySessionStateChange(const nsAString& aSessionId,
|
|||
// Only used for OOP RTCDataChannel session transport case.
|
||||
nsresult
|
||||
PresentationIPCService::NotifyMessage(const nsAString& aSessionId,
|
||||
const nsACString& aData)
|
||||
const nsACString& aData,
|
||||
const bool& aIsBinary)
|
||||
{
|
||||
nsCOMPtr<nsIPresentationSessionListener> listener;
|
||||
if (NS_WARN_IF(!mSessionListeners.Get(aSessionId, getter_AddRefs(listener)))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return listener->NotifyMessage(aSessionId, aData);
|
||||
return listener->NotifyMessage(aSessionId, aData, aIsBinary);
|
||||
}
|
||||
|
||||
// Only used for OOP RTCDataChannel session transport case.
|
||||
|
|
|
@ -37,7 +37,8 @@ public:
|
|||
nsresult aReason);
|
||||
|
||||
nsresult NotifyMessage(const nsAString& aSessionId,
|
||||
const nsACString& aData);
|
||||
const nsACString& aData,
|
||||
const bool& aIsBinary);
|
||||
|
||||
nsresult NotifySessionConnect(uint64_t aWindowId,
|
||||
const nsAString& aSessionId);
|
||||
|
|
|
@ -315,10 +315,13 @@ PresentationParent::NotifyReplaced()
|
|||
|
||||
NS_IMETHODIMP
|
||||
PresentationParent::NotifyMessage(const nsAString& aSessionId,
|
||||
const nsACString& aData)
|
||||
const nsACString& aData,
|
||||
bool aIsBinary)
|
||||
{
|
||||
if (NS_WARN_IF(mActorDestroyed ||
|
||||
!SendNotifyMessage(nsString(aSessionId), nsCString(aData)))) {
|
||||
!SendNotifyMessage(nsString(aSessionId),
|
||||
nsCString(aData),
|
||||
aIsBinary))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
|
|
|
@ -296,7 +296,7 @@ const mockedSessionTransport = {
|
|||
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportReady();
|
||||
},
|
||||
simulateIncomingMessage: function(message) {
|
||||
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message);
|
||||
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message, false);
|
||||
},
|
||||
onOffer: function(aOffer) {
|
||||
},
|
||||
|
|
|
@ -77,6 +77,18 @@ const mockControlChannelOfSender = {
|
|||
reconnect: function(presentationId, url) {
|
||||
sendAsyncMessage('start-reconnect', url);
|
||||
},
|
||||
sendIceCandidate: function(candidate) {
|
||||
mockControlChannelOfReceiver.notifyIceCandidate(candidate);
|
||||
},
|
||||
notifyIceCandidate: function(candidate) {
|
||||
if (!this._listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._listener
|
||||
.QueryInterface(Ci.nsIPresentationControlChannelListener)
|
||||
.onIceCandidate(candidate);
|
||||
},
|
||||
};
|
||||
|
||||
// control channel of receiver
|
||||
|
@ -130,7 +142,19 @@ const mockControlChannelOfReceiver = {
|
|||
sendAsyncMessage('control-channel-receiver-closed', reason);
|
||||
},
|
||||
terminate: function(presentaionId) {
|
||||
}
|
||||
},
|
||||
sendIceCandidate: function(candidate) {
|
||||
mockControlChannelOfReceiver.notifyIceCandidate(candidate);
|
||||
},
|
||||
notifyIceCandidate: function(candidate) {
|
||||
if (!this._listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._listener
|
||||
.QueryInterface(Ci.nsIPresentationControlChannelListener)
|
||||
.onIceCandidate(candidate);
|
||||
},
|
||||
};
|
||||
|
||||
const mockDevice = {
|
||||
|
|
|
@ -134,7 +134,7 @@ function loadPrivilegedScriptTest() {
|
|||
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportReady();
|
||||
},
|
||||
simulateIncomingMessage: function(message) {
|
||||
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message);
|
||||
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message, false);
|
||||
},
|
||||
onOffer: function(aOffer) {
|
||||
this._listener.sendAnswer(mockedChannelDescription);
|
||||
|
|
|
@ -36,6 +36,27 @@ function finish() {
|
|||
}
|
||||
|
||||
var connection;
|
||||
const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0];
|
||||
const DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length);
|
||||
const TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER);
|
||||
TYPED_DATA_ARRAY.set(DATA_ARRAY);
|
||||
|
||||
function is_same_buffer(recv_data, expect_data) {
|
||||
let recv_dataview = new Uint8Array(recv_data);
|
||||
let expected_dataview = new Uint8Array(expect_data);
|
||||
|
||||
if (recv_dataview.length !== expected_dataview.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < recv_dataview.length; i++) {
|
||||
if (recv_dataview[i] != expected_dataview[i]) {
|
||||
info('discover byte differenct at ' + i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function testConnectionAvailable() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
|
@ -105,6 +126,19 @@ function testSendMessage() {
|
|||
});
|
||||
}
|
||||
|
||||
function testIncomingBlobMessage() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
info('Receiver: --- testIncomingBlobMessage ---');
|
||||
connection.send('testIncomingBlobMessage');
|
||||
connection.addEventListener('message', function messageHandler(evt) {
|
||||
connection.removeEventListener('message', messageHandler);
|
||||
let recvData= String.fromCharCode.apply(null, new Uint8Array(evt.data));
|
||||
is(recvData, "Hello World", 'expected same string data');
|
||||
aResolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testConnectionClosed() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
info('Receiver: --- testConnectionClosed ---');
|
||||
|
@ -130,13 +164,46 @@ function testReconnectConnection() {
|
|||
});
|
||||
}
|
||||
|
||||
function testIncomingArrayBuffer() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
info('Receiver: --- testIncomingArrayBuffer ---');
|
||||
connection.binaryType = "blob";
|
||||
connection.send('testIncomingArrayBuffer');
|
||||
connection.addEventListener('message', function messageHandler(evt) {
|
||||
connection.removeEventListener('message', messageHandler);
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function() {
|
||||
ok(is_same_buffer(DATA_ARRAY_BUFFER, this.result), "expected same buffer data");
|
||||
aResolve();
|
||||
};
|
||||
fileReader.readAsArrayBuffer(evt.data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testIncomingArrayBufferView() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
info('Receiver: --- testIncomingArrayBufferView ---');
|
||||
connection.binaryType = "arraybuffer";
|
||||
connection.send('testIncomingArrayBufferView');
|
||||
connection.addEventListener('message', function messageHandler(evt) {
|
||||
connection.removeEventListener('message', messageHandler);
|
||||
ok(is_same_buffer(evt.data, TYPED_DATA_ARRAY), "expected same buffer data");
|
||||
aResolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
testConnectionAvailable()
|
||||
.then(testConnectionReady)
|
||||
.then(testIncomingMessage)
|
||||
.then(testSendMessage)
|
||||
.then(testIncomingBlobMessage)
|
||||
.then(testConnectionClosed)
|
||||
.then(testReconnectConnection)
|
||||
.then(testIncomingArrayBuffer)
|
||||
.then(testIncomingArrayBufferView)
|
||||
.then(testConnectionClosed);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,10 @@ var request;
|
|||
var connection;
|
||||
var receiverIframe;
|
||||
var presentationId;
|
||||
const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0];
|
||||
const DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length);
|
||||
const TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER);
|
||||
TYPED_DATA_ARRAY.set(DATA_ARRAY);
|
||||
|
||||
function postMessageToIframe(aType) {
|
||||
receiverIframe.src = receiverUrl + "#" +
|
||||
|
@ -159,6 +163,46 @@ function testIncomingMessage() {
|
|||
});
|
||||
}
|
||||
|
||||
function testSendBlobMessage() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
info('Sender: --- testSendBlobMessage ---');
|
||||
connection.addEventListener('message', function messageHandler(evt) {
|
||||
connection.removeEventListener('message', messageHandler);
|
||||
let msg = evt.data;
|
||||
is(msg, "testIncomingBlobMessage", "Sender: Sender should receive message from Receiver");
|
||||
let blob = new Blob(["Hello World"], {type : 'text/plain'});
|
||||
connection.send(blob);
|
||||
aResolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testSendArrayBuffer() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
info('Sender: --- testSendArrayBuffer ---');
|
||||
connection.addEventListener('message', function messageHandler(evt) {
|
||||
connection.removeEventListener('message', messageHandler);
|
||||
let msg = evt.data;
|
||||
is(msg, "testIncomingArrayBuffer", "Sender: Sender should receive message from Receiver");
|
||||
connection.send(DATA_ARRAY_BUFFER);
|
||||
aResolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testSendArrayBufferView() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
info('Sender: --- testSendArrayBufferView ---');
|
||||
connection.addEventListener('message', function messageHandler(evt) {
|
||||
connection.removeEventListener('message', messageHandler);
|
||||
let msg = evt.data;
|
||||
is(msg, "testIncomingArrayBufferView", "Sender: Sender should receive message from Receiver");
|
||||
connection.send(TYPED_DATA_ARRAY);
|
||||
aResolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testCloseConnection() {
|
||||
info('Sender: --- testCloseConnection ---');
|
||||
// Test terminate immediate after close.
|
||||
|
@ -269,8 +313,11 @@ function runTests() {
|
|||
.then(testStartConnection)
|
||||
.then(testSendMessage)
|
||||
.then(testIncomingMessage)
|
||||
.then(testSendBlobMessage)
|
||||
.then(testCloseConnection)
|
||||
.then(testReconnect)
|
||||
.then(testSendArrayBuffer)
|
||||
.then(testSendArrayBufferView)
|
||||
.then(testCloseConnection)
|
||||
.then(testTerminateAfterClose)
|
||||
.then(teardown);
|
||||
|
@ -284,11 +331,12 @@ SpecialPowers.pushPermissions([
|
|||
], () => {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
|
||||
/* Mocked TCP session transport builder in the test */
|
||||
["dom.presentation.session_transport.data_channel.enable", false],
|
||||
["dom.presentation.session_transport.data_channel.enable", true],
|
||||
["dom.presentation.controller.enabled", true],
|
||||
["dom.presentation.receiver.enabled", true],
|
||||
["dom.presentation.test.enabled", true],
|
||||
["dom.presentation.test.stage", 0],
|
||||
["dom.mozBrowserFramesEnabled", true]]},
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["media.navigator.permission.disabled", true]]},
|
||||
runTests);
|
||||
});
|
||||
|
|
|
@ -20,6 +20,12 @@ enum PresentationConnectionState
|
|||
"terminated"
|
||||
};
|
||||
|
||||
enum PresentationConnectionBinaryType
|
||||
{
|
||||
"blob",
|
||||
"arraybuffer"
|
||||
};
|
||||
|
||||
[Pref="dom.presentation.enabled"]
|
||||
interface PresentationConnection : EventTarget {
|
||||
/*
|
||||
|
@ -41,6 +47,7 @@ interface PresentationConnection : EventTarget {
|
|||
attribute EventHandler onconnect;
|
||||
attribute EventHandler onclose;
|
||||
attribute EventHandler onterminate;
|
||||
attribute PresentationConnectionBinaryType binaryType;
|
||||
|
||||
/*
|
||||
* After a communication channel has been established between the controlling
|
||||
|
@ -48,13 +55,19 @@ interface PresentationConnection : EventTarget {
|
|||
* event handler "onmessage" will be invoked at the remote side.
|
||||
*
|
||||
* This function only works when the state is "connected".
|
||||
*
|
||||
* TODO bug 1228474 Implement PresentationSessionTransport with DataChannel to
|
||||
* support other binary types.
|
||||
*/
|
||||
[Throws]
|
||||
void send(DOMString data);
|
||||
|
||||
[Throws]
|
||||
void send(Blob data);
|
||||
|
||||
[Throws]
|
||||
void send(ArrayBuffer data);
|
||||
|
||||
[Throws]
|
||||
void send(ArrayBufferView data);
|
||||
|
||||
/*
|
||||
* It is triggered when receiving messages.
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче