diff options
Diffstat (limited to 'mobile/android/modules/TabMirror.jsm')
-rw-r--r-- | mobile/android/modules/TabMirror.jsm | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/mobile/android/modules/TabMirror.jsm b/mobile/android/modules/TabMirror.jsm new file mode 100644 index 000000000..72a640ec8 --- /dev/null +++ b/mobile/android/modules/TabMirror.jsm @@ -0,0 +1,153 @@ +/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */ +/* 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/. */ +"use strict"; +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Messaging.jsm"); + +const CONFIG = { iceServers: [{ "urls": ["stun:stun.services.mozilla.com"] }] }; + +var log = Cu.import("resource://gre/modules/AndroidLog.jsm", + {}).AndroidLog.d.bind(null, "TabMirror"); + +var failure = function(x) { + log("ERROR: " + JSON.stringify(x)); +}; + +var TabMirror = function(deviceId, window) { + + this.deviceId = deviceId; + // Save RTCSessionDescription and RTCIceCandidate for later when the window object is not available. + this.RTCSessionDescription = window.RTCSessionDescription; + this.RTCIceCandidate = window.RTCIceCandidate; + + Services.obs.addObserver((aSubject, aTopic, aData) => this._processMessage(aData), "MediaPlayer:Response", false); + this._sendMessage({ start: true }); + this._window = window; + this._pc = new window.RTCPeerConnection(CONFIG, {}); + if (!this._pc) { + throw "Failure creating Webrtc object"; + } + +}; + +TabMirror.prototype = { + _window: null, + _screenSize: { width: 1280, height: 720 }, + _pc: null, + _start: function() { + this._pc.onicecandidate = this._onIceCandidate.bind(this); + + let windowId = this._window.BrowserApp.selectedBrowser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID; + let constraints = { + video: { + mediaSource: "browser", + browserWindow: windowId, + scrollWithPage: true, + advanced: [ + { width: { min: 0, max: this._screenSize.width }, + height: { min: 0, max: this._screenSize.height } + }, + { aspectRatio: this._screenSize.width / this._screenSize.height } + ] + } + }; + + this._window.navigator.mozGetUserMedia(constraints, this._onGumSuccess.bind(this), this._onGumFailure.bind(this)); + }, + + _processMessage: function(data) { + if (!data) { + return; + } + + let msg = JSON.parse(data); + + if (!msg) { + return; + } + + if (msg.sdp && msg.type === "answer") { + this._processAnswer(msg); + } else if (msg.type == "size") { + if (msg.height) { + this._screenSize.height = msg.height; + } + if (msg.width) { + this._screenSize.width = msg.width; + } + this._start(); + } else if (msg.candidate) { + this._processIceCandidate(msg); + } else { + log("dropping unrecognized message: " + JSON.stringify(msg)); + } + }, + + // Signaling methods + _processAnswer: function(msg) { + this._pc.setRemoteDescription(new this.RTCSessionDescription(msg), + this._setRemoteAnswerSuccess.bind(this), failure); + }, + + _processIceCandidate: function(msg) { + // WebRTC generates a warning if the success and fail callbacks are not passed in. + this._pc.addIceCandidate(new this.RTCIceCandidate(msg), () => log("Ice Candiated added successfuly"), () => log("Failed to add Ice Candidate")); + }, + + _setRemoteAnswerSuccess: function() { + }, + + _setLocalSuccessOffer: function(sdp) { + this._sendMessage(sdp); + }, + + _createOfferSuccess: function(sdp) { + this._pc.setLocalDescription(sdp, () => this._setLocalSuccessOffer(sdp), failure); + }, + + _onIceCandidate: function (msg) { + log("NEW Ice Candidate: " + JSON.stringify(msg.candidate)); + this._sendMessage(msg.candidate); + }, + + _ready: function() { + this._pc.createOffer(this._createOfferSuccess.bind(this), failure); + }, + + _onGumSuccess: function(stream){ + this._pc.addStream(stream); + this._ready(); + }, + + _onGumFailure: function() { + log("Could not get video stream"); + this._pc.close(); + }, + + _sendMessage: function(msg) { + if (this.deviceId) { + let obj = { + type: "MediaPlayer:Message", + id: this.deviceId, + data: JSON.stringify(msg) + }; + Messaging.sendRequest(obj); + } + }, + + stop: function() { + if (this.deviceId) { + let obj = { + type: "MediaPlayer:End", + id: this.deviceId + }; + Services.androidBridge.handleGeckoMessage(obj); + } + }, +}; + + +this.EXPORTED_SYMBOLS = ["TabMirror"]; |