diff options
Diffstat (limited to 'dom/presentation/provider/AndroidCastDeviceProvider.js')
-rw-r--r-- | dom/presentation/provider/AndroidCastDeviceProvider.js | 461 |
1 files changed, 0 insertions, 461 deletions
diff --git a/dom/presentation/provider/AndroidCastDeviceProvider.js b/dom/presentation/provider/AndroidCastDeviceProvider.js deleted file mode 100644 index cf555f77b..000000000 --- a/dom/presentation/provider/AndroidCastDeviceProvider.js +++ /dev/null @@ -1,461 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/* jshint esnext:true, globalstrict:true, moz:true, undef:true, unused:true */ -/* globals Components, dump */ -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -// globals XPCOMUtils -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -// globals Services -Cu.import("resource://gre/modules/Services.jsm"); -// globals Messaging -Cu.import("resource://gre/modules/Messaging.jsm"); - -function log(str) { - // dump("-*- AndroidCastDeviceProvider -*-: " + str + "\n"); -} - -// Helper function: transfer nsIPresentationChannelDescription to json -function descriptionToString(aDescription) { - let json = {}; - json.type = aDescription.type; - switch(aDescription.type) { - case Ci.nsIPresentationChannelDescription.TYPE_TCP: - let addresses = aDescription.tcpAddress.QueryInterface(Ci.nsIArray); - json.tcpAddress = []; - for (let idx = 0; idx < addresses.length; idx++) { - let address = addresses.queryElementAt(idx, Ci.nsISupportsCString); - json.tcpAddress.push(address.data); - } - json.tcpPort = aDescription.tcpPort; - break; - case Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL: - json.dataChannelSDP = aDescription.dataChannelSDP; - break; - } - return JSON.stringify(json); -} - -const TOPIC_ANDROID_CAST_DEVICE_SYNCDEVICE = "AndroidCastDevice:SyncDevice"; -const TOPIC_ANDROID_CAST_DEVICE_ADDED = "AndroidCastDevice:Added"; -const TOPIC_ANDROID_CAST_DEVICE_REMOVED = "AndroidCastDevice:Removed"; -const TOPIC_ANDROID_CAST_DEVICE_START = "AndroidCastDevice:Start"; -const TOPIC_ANDROID_CAST_DEVICE_STOP = "AndroidCastDevice:Stop"; -const TOPIC_PRESENTATION_VIEW_READY = "presentation-view-ready"; - -function LocalControlChannel(aProvider, aDeviceId, aRole) { - log("LocalControlChannel - create new LocalControlChannel for : " - + aRole); - this._provider = aProvider; - this._deviceId = aDeviceId; - this._role = aRole; -} - -LocalControlChannel.prototype = { - _listener: null, - _provider: null, - _deviceId: null, - _role: null, - _isOnTerminating: false, - _isOnDisconnecting: false, - _pendingConnected: false, - _pendingDisconnect: null, - _pendingOffer: null, - _pendingCandidate: null, - /* For the controller, it would be the control channel of the receiver. - * For the receiver, it would be the control channel of the controller. */ - _correspondingControlChannel: null, - - set correspondingControlChannel(aCorrespondingControlChannel) { - this._correspondingControlChannel = aCorrespondingControlChannel; - }, - - get correspondingControlChannel() { - return this._correspondingControlChannel; - }, - - notifyConnected: function LCC_notifyConnected() { - this._pendingDisconnect = null; - - if (!this._listener) { - this._pendingConnected = true; - } else { - this._listener.notifyConnected(); - } - }, - - onOffer: function LCC_onOffer(aOffer) { - if (this._role == Ci.nsIPresentationService.ROLE_CONTROLLER) { - log("LocalControlChannel - onOffer of controller should not be called."); - return; - } - if (!this._listener) { - this._pendingOffer = aOffer; - } else { - this._listener.onOffer(aOffer); - } - }, - - onAnswer: function LCC_onAnswer(aAnswer) { - if (this._role == Ci.nsIPresentationService.ROLE_RECEIVER) { - log("LocalControlChannel - onAnswer of receiver should not be called."); - return; - } - this._listener.onAnswer(aAnswer); - }, - - notifyIceCandidate: function LCC_notifyIceCandidate(aCandidate) { - if (!this._listener) { - this._pendingCandidate = aCandidate; - } else { - this._listener.onIceCandidate(aCandidate); - } - }, - - // nsIPresentationControlChannel - get listener() { - return this._listener; - }, - - set listener(aListener) { - this._listener = aListener; - - if (!this._listener) { - return; - } - - if (this._pendingConnected) { - this.notifyConnected(); - this._pendingConnected = false; - } - - if (this._pendingOffer) { - this.onOffer(this._pendingOffer); - this._pendingOffer = null; - } - - if (this._pendingCandidate) { - this.notifyIceCandidate(this._pendingCandidate); - this._pendingCandidate = null; - } - - if (this._pendingDisconnect != null) { - this.disconnect(this._pendingDisconnect); - this._pendingDisconnect = null; - } - }, - - sendOffer: function LCC_sendOffer(aOffer) { - if (this._role == Ci.nsIPresentationService.ROLE_RECEIVER) { - log("LocalControlChannel - sendOffer of receiver should not be called."); - return; - } - log("LocalControlChannel - sendOffer aOffer=" + descriptionToString(aOffer)); - this._correspondingControlChannel.onOffer(aOffer); - }, - - sendAnswer: function LCC_sendAnswer(aAnswer) { - if (this._role == Ci.nsIPresentationService.ROLE_CONTROLLER) { - log("LocalControlChannel - sendAnswer of controller should not be called."); - return; - } - log("LocalControlChannel - sendAnswer aAnswer=" + descriptionToString(aAnswer)); - this._correspondingControlChannel.onAnswer(aAnswer); - }, - - sendIceCandidate: function LCC_sendIceCandidate(aCandidate) { - log("LocalControlChannel - sendAnswer aCandidate=" + aCandidate); - this._correspondingControlChannel.notifyIceCandidate(aCandidate); - }, - - launch: function LCC_launch(aPresentationId, aUrl) { - log("LocalControlChannel - launch aPresentationId=" - + aPresentationId + " aUrl=" + aUrl); - // Create control channel for receiver directly. - let controlChannel = new LocalControlChannel(this._provider, - this._deviceId, - Ci.nsIPresentationService.ROLE_RECEIVER); - - // Set up the corresponding control channels for both controller and receiver. - this._correspondingControlChannel = controlChannel; - controlChannel._correspondingControlChannel = this; - - this._provider.onSessionRequest(this._deviceId, - aUrl, - aPresentationId, - controlChannel); - controlChannel.notifyConnected(); - }, - - terminate: function LCC_terminate(aPresentationId) { - log("LocalControlChannel - terminate aPresentationId=" - + aPresentationId); - - if (this._isOnTerminating) { - return; - } - - // Create control channel for corresponding role directly. - let correspondingRole = this._role == Ci.nsIPresentationService.ROLE_CONTROLLER - ? Ci.nsIPresentationService.ROLE_RECEIVER - : Ci.nsIPresentationService.ROLE_CONTROLLER; - let controlChannel = new LocalControlChannel(this._provider, - this._deviceId, - correspondingRole); - // Prevent the termination recursion. - controlChannel._isOnTerminating = true; - - // Set up the corresponding control channels for both controller and receiver. - this._correspondingControlChannel = controlChannel; - controlChannel._correspondingControlChannel = this; - - this._provider.onTerminateRequest(this._deviceId, - aPresentationId, - controlChannel, - this._role == Ci.nsIPresentationService.ROLE_RECEIVER); - controlChannel.notifyConnected(); - }, - - disconnect: function LCC_disconnect(aReason) { - log("LocalControlChannel - disconnect aReason=" + aReason); - - if (this._isOnDisconnecting) { - return; - } - - this._pendingOffer = null; - this._pendingCandidate = null; - this._pendingConnected = false; - - // this._pendingDisconnect is a nsresult. - // If it is null, it means no pending disconnect. - // If it is NS_OK, it means this control channel is disconnected normally. - // If it is other nsresult value, it means this control channel is - // disconnected abnormally. - - // Remote endpoint closes the control channel with abnormal reason. - if (aReason == Cr.NS_OK && - this._pendingDisconnect != null && - this._pendingDisconnect != Cr.NS_OK) { - aReason = this._pendingDisconnect; - } - - if (!this._listener) { - this._pendingDisconnect = aReason; - return; - } - - this._isOnDisconnecting = true; - this._correspondingControlChannel.disconnect(aReason); - this._listener.notifyDisconnected(aReason); - }, - - reconnect: function LCC_reconnect(aPresentationId, aUrl) { - log("1-UA on Android doesn't support reconnect."); - throw Cr.NS_ERROR_FAILURE; - }, - - classID: Components.ID("{c9be9450-e5c7-4294-a287-376971b017fd}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]), -}; - -function ChromecastRemoteDisplayDevice(aProvider, aId, aName, aRole) { - this._provider = aProvider; - this._id = aId; - this._name = aName; - this._role = aRole; -} - -ChromecastRemoteDisplayDevice.prototype = { - _id: null, - _name: null, - _role: null, - _provider: null, - _ctrlChannel: null, - - update: function CRDD_update(aName) { - this._name = aName || this._name; - }, - - // nsIPresentationDevice - get id() { return this._id; }, - - get name() { return this._name; }, - - get type() { return "chromecast"; }, - - establishControlChannel: function CRDD_establishControlChannel() { - this._ctrlChannel = new LocalControlChannel(this._provider, - this._id, - this._role); - - if (this._role == Ci.nsIPresentationService.ROLE_CONTROLLER) { - // Only connect to Chromecast for controller. - // Monitor the receiver being ready. - Services.obs.addObserver(this, TOPIC_PRESENTATION_VIEW_READY, true); - - // Launch Chromecast service in Android. - Messaging.sendRequestForResult({ - type: TOPIC_ANDROID_CAST_DEVICE_START, - id: this.id - }).then(result => { - log("Chromecast is connected."); - }).catch(error => { - log("Can not connect to Chromecast."); - // If Chromecast can not be launched, remove the observer. - Services.obs.removeObserver(this, TOPIC_PRESENTATION_VIEW_READY); - this._ctrlChannel.disconnect(Cr.NS_ERROR_FAILURE); - }); - } else { - // If establishControlChannel called from the receiver, we don't need to - // wait the 'presentation-view-ready' event. - this._ctrlChannel.notifyConnected(); - } - - return this._ctrlChannel; - }, - - disconnect: function CRDD_disconnect() { - // Disconnect from Chromecast. - Messaging.sendRequestForResult({ - type: TOPIC_ANDROID_CAST_DEVICE_STOP, - id: this.id - }); - }, - - isRequestedUrlSupported: function CRDD_isRequestedUrlSupported(aUrl) { - let url = Cc["@mozilla.org/network/io-service;1"] - .getService(Ci.nsIIOService) - .newURI(aUrl, null, null); - return url.scheme == "http" || url.scheme == "https"; - }, - - // nsIPresentationLocalDevice - get windowId() { return this._id; }, - - // nsIObserver - observe: function CRDD_observe(aSubject, aTopic, aData) { - if (aTopic == TOPIC_PRESENTATION_VIEW_READY) { - log("ChromecastRemoteDisplayDevice - observe: aTopic=" - + aTopic + " data=" + aData); - if (this.windowId === aData) { - Services.obs.removeObserver(this, TOPIC_PRESENTATION_VIEW_READY); - this._ctrlChannel.notifyConnected(); - } - } - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice, - Ci.nsIPresentationLocalDevice, - Ci.nsISupportsWeakReference, - Ci.nsIObserver]), -}; - -function AndroidCastDeviceProvider() { -} - -AndroidCastDeviceProvider.prototype = { - _listener: null, - _deviceList: new Map(), - - onSessionRequest: function APDP_onSessionRequest(aDeviceId, - aUrl, - aPresentationId, - aControlChannel) { - log("AndroidCastDeviceProvider - onSessionRequest" - + " aDeviceId=" + aDeviceId); - let device = this._deviceList.get(aDeviceId); - let receiverDevice = new ChromecastRemoteDisplayDevice(this, - device.id, - device.name, - Ci.nsIPresentationService.ROLE_RECEIVER); - this._listener.onSessionRequest(receiverDevice, - aUrl, - aPresentationId, - aControlChannel); - }, - - onTerminateRequest: function APDP_onTerminateRequest(aDeviceId, - aPresentationId, - aControlChannel, - aIsFromReceiver) { - log("AndroidCastDeviceProvider - onTerminateRequest" - + " aDeviceId=" + aDeviceId - + " aPresentationId=" + aPresentationId - + " aIsFromReceiver=" + aIsFromReceiver); - let device = this._deviceList.get(aDeviceId); - this._listener.onTerminateRequest(device, - aPresentationId, - aControlChannel, - aIsFromReceiver); - }, - - // nsIPresentationDeviceProvider - set listener(aListener) { - this._listener = aListener; - - // When unload this provider. - if (!this._listener) { - // remove observer - Services.obs.removeObserver(this, TOPIC_ANDROID_CAST_DEVICE_ADDED); - Services.obs.removeObserver(this, TOPIC_ANDROID_CAST_DEVICE_REMOVED); - return; - } - - // Sync all device already found by Android. - Services.obs.notifyObservers(null, TOPIC_ANDROID_CAST_DEVICE_SYNCDEVICE, ""); - // Observer registration - Services.obs.addObserver(this, TOPIC_ANDROID_CAST_DEVICE_ADDED, false); - Services.obs.addObserver(this, TOPIC_ANDROID_CAST_DEVICE_REMOVED, false); - }, - - get listener() { - return this._listener; - }, - - forceDiscovery: function APDP_forceDiscovery() { - // There is no API to do force discovery in Android SDK. - }, - - // nsIObserver - observe: function APDP_observe(aSubject, aTopic, aData) { - switch (aTopic) { - case TOPIC_ANDROID_CAST_DEVICE_ADDED: { - let deviceInfo = JSON.parse(aData); - let deviceId = deviceInfo.uuid; - - if (!this._deviceList.has(deviceId)) { - let device = new ChromecastRemoteDisplayDevice(this, - deviceInfo.uuid, - deviceInfo.friendlyName, - Ci.nsIPresentationService.ROLE_CONTROLLER); - this._deviceList.set(device.id, device); - this._listener.addDevice(device); - } else { - let device = this._deviceList.get(deviceId); - device.update(deviceInfo.friendlyName); - this._listener.updateDevice(device); - } - break; - } - case TOPIC_ANDROID_CAST_DEVICE_REMOVED: { - let deviceId = aData; - let device = this._deviceList.get(deviceId); - this._listener.removeDevice(device); - this._deviceList.delete(deviceId); - break; - } - } - }, - - classID: Components.ID("{7394f24c-dbc3-48c8-8a47-cd10169b7c6b}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, - Ci.nsIPresentationDeviceProvider]), -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AndroidCastDeviceProvider]); |