mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 16:25:38 +00:00
Bug 1305351 - Add ChromeCastDisplay for Presentation API. r=snorp
MozReview-Commit-ID: A9yXeADOA0Y --HG-- extra : rebase_source : cebed59abe241a81e8e116245a85be7488931ba9
This commit is contained in:
parent
0b06159c5f
commit
11677f5c9c
@ -105,8 +105,10 @@ android {
|
||||
}
|
||||
|
||||
if (!mozconfig.substs.MOZ_NATIVE_DEVICES) {
|
||||
exclude 'org/mozilla/gecko/ChromeCast.java'
|
||||
exclude 'org/mozilla/gecko/ChromeCastDisplay.java'
|
||||
exclude 'org/mozilla/gecko/ChromeCastPlayer.java'
|
||||
exclude 'org/mozilla/gecko/GeckoMediaPlayer.java'
|
||||
exclude 'org/mozilla/gecko/GeckoPresentationDisplay.java'
|
||||
exclude 'org/mozilla/gecko/MediaPlayerManager.java'
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,66 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* vim: ts=4 sw=4 expandtab:
|
||||
* 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/. */
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONException;
|
||||
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
|
||||
import com.google.android.gms.cast.CastDevice;
|
||||
import com.google.android.gms.cast.CastRemoteDisplayLocalService;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GooglePlayServicesUtil;
|
||||
import com.google.android.gms.common.api.Status;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v7.media.MediaRouter.RouteInfo;
|
||||
import android.util.Log;
|
||||
|
||||
public class ChromeCastDisplay implements GeckoPresentationDisplay {
|
||||
|
||||
static final String REMOTE_DISPLAY_APP_ID = "4574A331";
|
||||
|
||||
private static final String LOGTAG = "GeckoChromeCastDisplay";
|
||||
private final RouteInfo route;
|
||||
private CastDevice castDevice;
|
||||
|
||||
public ChromeCastDisplay(Context context, RouteInfo route) {
|
||||
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
|
||||
if (status != ConnectionResult.SUCCESS) {
|
||||
throw new IllegalStateException("Play services are required for Chromecast support (got status code " + status + ")");
|
||||
}
|
||||
|
||||
this.route = route;
|
||||
this.castDevice = CastDevice.getFromBundle(route.getExtras());
|
||||
}
|
||||
|
||||
public JSONObject toJSON() {
|
||||
final JSONObject obj = new JSONObject();
|
||||
try {
|
||||
if (castDevice == null) {
|
||||
return null;
|
||||
}
|
||||
obj.put("uuid", route.getId());
|
||||
obj.put("friendlyName", castDevice.getFriendlyName());
|
||||
obj.put("type", "chromecast");
|
||||
} catch (JSONException ex) {
|
||||
Log.d(LOGTAG, "Error building route", ex);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(EventCallback callback) { }
|
||||
|
||||
@Override
|
||||
public void stop(EventCallback callback) { }
|
||||
}
|
@ -34,7 +34,7 @@ import android.support.v7.media.MediaRouter.RouteInfo;
|
||||
import android.util.Log;
|
||||
|
||||
/* Implementation of GeckoMediaPlayer for talking to ChromeCast devices */
|
||||
class ChromeCast implements GeckoMediaPlayer {
|
||||
class ChromeCastPlayer implements GeckoMediaPlayer {
|
||||
private static final boolean SHOW_DEBUG = false;
|
||||
|
||||
static final String MIRROR_RECEIVER_APP_ID = "08FF1091";
|
||||
@ -168,7 +168,7 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
public ChromeCast(Context context, RouteInfo route) {
|
||||
public ChromeCastPlayer(Context context, RouteInfo route) {
|
||||
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
|
||||
if (status != ConnectionResult.SUCCESS) {
|
||||
throw new IllegalStateException("Play services are required for Chromecast support (got status code " + status + ")");
|
||||
@ -493,7 +493,7 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
apiClient.connect();
|
||||
}
|
||||
|
||||
private static final String LOGTAG = "GeckoChromeCast";
|
||||
private static final String LOGTAG = "GeckoChromeCastPlayer";
|
||||
private void debug(String msg, Exception e) {
|
||||
if (SHOW_DEBUG) {
|
||||
Log.e(LOGTAG, msg, e);
|
@ -0,0 +1,22 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
* 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/. */
|
||||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
|
||||
/**
|
||||
* Wrapper for MediaRouter types supported by Android to use for
|
||||
* Presentation API, such as Chromecast, Miracast, etc.
|
||||
*/
|
||||
interface GeckoPresentationDisplay {
|
||||
/**
|
||||
* Can return null.
|
||||
*/
|
||||
JSONObject toJSON();
|
||||
void start(EventCallback callback);
|
||||
void stop(EventCallback callback);
|
||||
}
|
@ -64,7 +64,8 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
||||
}
|
||||
|
||||
protected MediaRouter mediaRouter = null;
|
||||
protected final Map<String, GeckoMediaPlayer> displays = new HashMap<String, GeckoMediaPlayer>();
|
||||
protected final Map<String, GeckoMediaPlayer> players = new HashMap<String, GeckoMediaPlayer>();
|
||||
protected final Map<String, GeckoPresentationDisplay> displays = new HashMap<String, GeckoPresentationDisplay>(); // used for Presentation API
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@ -100,9 +101,9 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
||||
public void handleMessage(String event, final NativeJSObject message, final EventCallback callback) {
|
||||
debug(event);
|
||||
|
||||
final GeckoMediaPlayer display = displays.get(message.getString("id"));
|
||||
if (display == null) {
|
||||
Log.e(LOGTAG, "Couldn't find a display for this id: " + message.getString("id") + " for message: " + event);
|
||||
final GeckoMediaPlayer player = players.get(message.getString("id"));
|
||||
if (player == null) {
|
||||
Log.e(LOGTAG, "Couldn't find a player for this id: " + message.getString("id") + " for message: " + event);
|
||||
if (callback != null) {
|
||||
callback.sendError(null);
|
||||
}
|
||||
@ -110,24 +111,24 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
||||
}
|
||||
|
||||
if ("MediaPlayer:Play".equals(event)) {
|
||||
display.play(callback);
|
||||
player.play(callback);
|
||||
} else if ("MediaPlayer:Start".equals(event)) {
|
||||
display.start(callback);
|
||||
player.start(callback);
|
||||
} else if ("MediaPlayer:Stop".equals(event)) {
|
||||
display.stop(callback);
|
||||
player.stop(callback);
|
||||
} else if ("MediaPlayer:Pause".equals(event)) {
|
||||
display.pause(callback);
|
||||
player.pause(callback);
|
||||
} else if ("MediaPlayer:End".equals(event)) {
|
||||
display.end(callback);
|
||||
player.end(callback);
|
||||
} else if ("MediaPlayer:Mirror".equals(event)) {
|
||||
display.mirror(callback);
|
||||
player.mirror(callback);
|
||||
} else if ("MediaPlayer:Message".equals(event) && message.has("data")) {
|
||||
display.message(message.getString("data"), callback);
|
||||
player.message(message.getString("data"), callback);
|
||||
} else if ("MediaPlayer:Load".equals(event)) {
|
||||
final String url = message.optString("source", "");
|
||||
final String type = message.optString("type", "video/mp4");
|
||||
final String title = message.optString("title", "");
|
||||
display.load(title, url, type, callback);
|
||||
player.load(title, url, type, callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,9 +137,15 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
||||
@Override
|
||||
public void onRouteRemoved(MediaRouter router, RouteInfo route) {
|
||||
debug("onRouteRemoved: route=" + route);
|
||||
displays.remove(route.getId());
|
||||
|
||||
// Remove from media player list.
|
||||
players.remove(route.getId());
|
||||
GeckoAppShell.notifyObservers("MediaPlayer:Removed", route.getId());
|
||||
updatePresentation();
|
||||
|
||||
// Remove from presentation display list.
|
||||
displays.remove(route.getId());
|
||||
GeckoAppShell.notifyObservers("AndroidCastDevice:Removed", route.getId());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ -164,21 +171,44 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
||||
@Override
|
||||
public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) {
|
||||
debug("onRouteAdded: route=" + route);
|
||||
final GeckoMediaPlayer display = getMediaPlayerForRoute(route);
|
||||
saveAndNotifyOfDisplay("MediaPlayer:Added", route, display);
|
||||
final GeckoMediaPlayer player = getMediaPlayerForRoute(route);
|
||||
saveAndNotifyOfPlayer("MediaPlayer:Added", route, player);
|
||||
updatePresentation();
|
||||
|
||||
final GeckoPresentationDisplay display = getPresentationDisplayForRoute(route);
|
||||
saveAndNotifyOfDisplay("AndroidCastDevice:Added", route, display);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo route) {
|
||||
debug("onRouteChanged: route=" + route);
|
||||
final GeckoMediaPlayer display = displays.get(route.getId());
|
||||
saveAndNotifyOfDisplay("MediaPlayer:Changed", route, display);
|
||||
final GeckoMediaPlayer player = players.get(route.getId());
|
||||
saveAndNotifyOfPlayer("MediaPlayer:Changed", route, player);
|
||||
updatePresentation();
|
||||
|
||||
final GeckoPresentationDisplay display = displays.get(route.getId());
|
||||
saveAndNotifyOfDisplay("AndroidCastDevice:Changed", route, display);
|
||||
}
|
||||
|
||||
private void saveAndNotifyOfPlayer(final String eventName,
|
||||
MediaRouter.RouteInfo route,
|
||||
final GeckoMediaPlayer player) {
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final JSONObject json = player.toJSON();
|
||||
if (json == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
players.put(route.getId(), player);
|
||||
GeckoAppShell.notifyObservers(eventName, json.toString());
|
||||
}
|
||||
|
||||
private void saveAndNotifyOfDisplay(final String eventName,
|
||||
MediaRouter.RouteInfo route, final GeckoMediaPlayer display) {
|
||||
MediaRouter.RouteInfo route,
|
||||
final GeckoPresentationDisplay display) {
|
||||
if (display == null) {
|
||||
return;
|
||||
}
|
||||
@ -196,7 +226,7 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
||||
private GeckoMediaPlayer getMediaPlayerForRoute(MediaRouter.RouteInfo route) {
|
||||
try {
|
||||
if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
|
||||
return new ChromeCast(getActivity(), route);
|
||||
return new ChromeCastPlayer(getActivity(), route);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
debug("Error handling presentation", ex);
|
||||
@ -205,6 +235,17 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
||||
return null;
|
||||
}
|
||||
|
||||
private GeckoPresentationDisplay getPresentationDisplayForRoute(MediaRouter.RouteInfo route) {
|
||||
try {
|
||||
if (route.supportsControlCategory(CastMediaControlIntent.categoryForCast(ChromeCastDisplay.REMOTE_DISPLAY_APP_ID))) {
|
||||
return new ChromeCastDisplay(getActivity(), route);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
debug("Error handling presentation", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
@ -225,7 +266,8 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
||||
final MediaRouteSelector selectorBuilder = new MediaRouteSelector.Builder()
|
||||
.addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)
|
||||
.addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
|
||||
.addControlCategory(CastMediaControlIntent.categoryForCast(ChromeCast.MIRROR_RECEIVER_APP_ID))
|
||||
.addControlCategory(CastMediaControlIntent.categoryForCast(ChromeCastPlayer.MIRROR_RECEIVER_APP_ID))
|
||||
.addControlCategory(CastMediaControlIntent.categoryForCast(ChromeCastDisplay.REMOTE_DISPLAY_APP_ID))
|
||||
.build();
|
||||
mediaRouter.addCallback(selectorBuilder, callback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
|
||||
}
|
||||
|
@ -839,8 +839,10 @@ moz_native_devices_jars = [
|
||||
CONFIG['ANDROID_PLAY_SERVICES_CAST_AAR_LIB'],
|
||||
]
|
||||
moz_native_devices_sources = ['java/org/mozilla/gecko/' + x for x in [
|
||||
'ChromeCast.java',
|
||||
'ChromeCastDisplay.java',
|
||||
'ChromeCastPlayer.java',
|
||||
'GeckoMediaPlayer.java',
|
||||
'GeckoPresentationDisplay.java',
|
||||
'MediaPlayerManager.java',
|
||||
'PresentationMediaPlayerManager.java',
|
||||
]]
|
||||
|
Loading…
Reference in New Issue
Block a user