зеркало из https://github.com/mozilla/gecko-dev.git
Bug 901803 - Add a JS component for casting to native devices. r=mfinkle
This commit is contained in:
Родитель
ec9cd39258
Коммит
ed90150cc6
|
@ -25,6 +25,14 @@ var fireflyTarget = {
|
|||
}
|
||||
};
|
||||
|
||||
var mediaPlayerTarget = {
|
||||
target: "media:router",
|
||||
factory: function(aService) {
|
||||
Cu.import("resource://gre/modules/MediaPlayerApp.jsm");
|
||||
return new MediaPlayerApp(aService);
|
||||
}
|
||||
};
|
||||
|
||||
var CastingApps = {
|
||||
_castMenuId: -1,
|
||||
|
||||
|
@ -36,6 +44,7 @@ var CastingApps = {
|
|||
// Register targets
|
||||
SimpleServiceDiscovery.registerTarget(rokuTarget);
|
||||
SimpleServiceDiscovery.registerTarget(fireflyTarget);
|
||||
SimpleServiceDiscovery.registerTarget(mediaPlayerTarget);
|
||||
|
||||
// Search for devices continuously every 120 seconds
|
||||
SimpleServiceDiscovery.search(120 * 1000);
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
|
||||
/* 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";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["MediaPlayerApp"];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Messaging.jsm");
|
||||
let log = Cu.import("resource://gre/modules/AndroidLog.jsm", {}).AndroidLog.d.bind(null, "MediaPlayerApp");
|
||||
|
||||
// Helper function for sending commands to Java.
|
||||
function send(type, data, callback) {
|
||||
let msg = {
|
||||
type: type
|
||||
};
|
||||
|
||||
for (let i in data) {
|
||||
msg[i] = data[i];
|
||||
}
|
||||
|
||||
sendMessageToJava(msg, callback);
|
||||
}
|
||||
|
||||
/* These apps represent players supported natively by the platform. This class will proxy commands
|
||||
* to native controls */
|
||||
function MediaPlayerApp(service) {
|
||||
this.service = service;
|
||||
this.location = service.location;
|
||||
this.id = service.uuid;
|
||||
}
|
||||
|
||||
MediaPlayerApp.prototype = {
|
||||
start: function start(callback) {
|
||||
send("MediaPlayer:Start", { id: this.id }, (result) => {
|
||||
if (callback) callback(true);
|
||||
});
|
||||
},
|
||||
|
||||
stop: function stop(callback) {
|
||||
send("MediaPlayer:Stop", { id: this.id }, (result) => {
|
||||
if (callback) callback(true);
|
||||
});
|
||||
},
|
||||
|
||||
remoteMedia: function remoteMedia(callback, listener) {
|
||||
if (callback) {
|
||||
callback(new RemoteMedia(this.id, listener));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/* RemoteMedia provides a proxy to a native media player session.
|
||||
*/
|
||||
function RemoteMedia(id, listener) {
|
||||
this._id = id;
|
||||
this._listener = listener;
|
||||
|
||||
if ("onRemoteMediaStart" in this._listener) {
|
||||
Services.tm.mainThread.dispatch((function() {
|
||||
this._listener.onRemoteMediaStart(this);
|
||||
}).bind(this), Ci.nsIThread.DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
RemoteMedia.prototype = {
|
||||
shutdown: function shutdown() {
|
||||
this._send("MediaPlayer:End", {}, (result) => {
|
||||
this._status = "shutdown";
|
||||
if ("onRemoteMediaStop" in this._listener) {
|
||||
this._listener.onRemoteMediaStop(this);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
play: function play() {
|
||||
this._send("MediaPlayer:Play", {}, (result) => {
|
||||
this._status = "started";
|
||||
});
|
||||
},
|
||||
|
||||
pause: function pause() {
|
||||
this._send("MediaPlayer:Pause", {}, (result) => {
|
||||
this._status = "paused";
|
||||
});
|
||||
},
|
||||
|
||||
load: function load(aData) {
|
||||
this._send("MediaPlayer:Load", aData, (result) => {
|
||||
this._status = "started";
|
||||
})
|
||||
},
|
||||
|
||||
get status() {
|
||||
return this._status;
|
||||
},
|
||||
|
||||
_send: function(msg, data, callback) {
|
||||
data.id = this._id;
|
||||
send(msg, data, callback);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
|||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Messaging.jsm");
|
||||
|
||||
// Define the "log" function as a binding of the Log.d function so it specifies
|
||||
// the "debug" priority and a log tag.
|
||||
|
@ -169,6 +170,29 @@ var SimpleServiceDiscovery = {
|
|||
log("failed to convert to byte array: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// We also query Java directly here for any devices that Android might support natively (i.e. Chromecast or Miracast)
|
||||
this.getAndroidDevices();
|
||||
},
|
||||
|
||||
getAndroidDevices: function() {
|
||||
sendMessageToJava({ type: "MediaPlayer:Get" }, (result) => {
|
||||
for (let id in result.displays) {
|
||||
let display = result.displays[id];
|
||||
|
||||
// Convert the native data into something matching what is created in _processService()
|
||||
let service = {
|
||||
location: display.location,
|
||||
target: "media:router",
|
||||
friendlyName: display.friendlyName,
|
||||
uuid: display.uuid,
|
||||
manufacturer: display.manufacturer,
|
||||
modelName: display.modelName
|
||||
};
|
||||
|
||||
this._addService(service);
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
_searchFixedTargets: function _searchFixedTargets() {
|
||||
|
@ -313,22 +337,26 @@ var SimpleServiceDiscovery = {
|
|||
aService.manufacturer = doc.querySelector("manufacturer").textContent;
|
||||
aService.modelName = doc.querySelector("modelName").textContent;
|
||||
|
||||
// Filter out services that do not match the target filter
|
||||
if (!this._filterService(aService)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only add and notify if we don't already know about this service
|
||||
if (!this._services.has(aService.uuid)) {
|
||||
this._services.set(aService.uuid, aService);
|
||||
Services.obs.notifyObservers(null, EVENT_SERVICE_FOUND, aService.uuid);
|
||||
}
|
||||
|
||||
// Make sure we remember this service is not stale
|
||||
this._services.get(aService.uuid).lastPing = this._searchTimestamp;
|
||||
this._addService(aService);
|
||||
}
|
||||
}).bind(this), false);
|
||||
|
||||
xhr.send(null);
|
||||
},
|
||||
|
||||
_addService: function(service) {
|
||||
// Filter out services that do not match the target filter
|
||||
if (!this._filterService(service)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only add and notify if we don't already know about this service
|
||||
if (!this._services.has(service.uuid)) {
|
||||
this._services.set(service.uuid, service);
|
||||
Services.obs.notifyObservers(null, EVENT_SERVICE_FOUND, service.uuid);
|
||||
}
|
||||
|
||||
// Make sure we remember this service is not stale
|
||||
this._services.get(service.uuid).lastPing = this._searchTimestamp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ EXTRA_JS_MODULES += [
|
|||
'HomeProvider.jsm',
|
||||
'JNI.jsm',
|
||||
'LightweightThemeConsumer.jsm',
|
||||
'MediaPlayerApp.jsm',
|
||||
'Messaging.jsm',
|
||||
'Notifications.jsm',
|
||||
'OrderedBroadcast.jsm',
|
||||
|
|
Загрузка…
Ссылка в новой задаче