Android: Get Current Playing Media On Chromecast?
I'm working on an app that controls the Chromecast and whatever's playing on it. I don't want a sender app, I don't want to register anything to get an api key, none of that stuff.
Solution 1:
I finally figured it out. I had to use the google play services and the google cast sdk v2 but without registering the application.
Libraries included in the project:
compile'com.android.support:mediarouter-v7:24.0.0'compile'com.google.android.gms:play-services-cast-framework:9.2.0'
Beware that in the code below onCreate() and onDestroy() aren't methods in an Activity, Fragment or Service, so don't copy/paste the code and expect it works. The code in those methods must pe copy/pasted in your own methods.
Here are the steps of what's happening:
- You select a route either via the cast button either by calling getActiveMediaRoute() which checks for which Chromecast is active (it won't work if nobody is connected to the Chromecast). Override the method or getActiveChromecastRoute() to select based on your preferences
- When onRouteSelected() is called a new Cast GoogleApiClient is instanced with options for the selected chromecast
- When onApplicationMetadataChanged() is called the code will connect to the current application running on the Chromecast
- After the application is successfully connected a new RemoteMediaPlayer is instanced and the MediaStatus is requested
- You should get a callback in onStatusUpdated() and after that you can call mRemoteMediaPlayer.getMediaStatus() and it will contain the data about what's being played on the Chromecast.
publicstatic final StringCHROMECAST_SIGNATURE = "cast.media.CastMediaRouteProviderService";
private final MediaRouteSelector mSelector;
private final MediaRouter mMediaRouter;
privateCastDevice mSelectedDevice;
privateCast.Listener mCastClientListener;
privateRemoteMediaPlayer mRemoteMediaPlayer;
@OverridepublicvoidonCreate() {
mMediaRouter = MediaRouter.getInstance(context);
mSelector = newMediaRouteSelector.Builder()
// These are the framework-supported intents
.addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO)
.addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)
.addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
.build();
mMediaRouter.addCallback(mSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY | MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS);
}
@OverridepublicvoidonDestroy() {
mMediaRouter.removeCallback(mMediaRouterCallback);
}
@UiThreadprivatebooleanisChromecastActive() {
returngetActiveChromecastRoute() != null;
}
@UiThreadprivateBooleanisChromecastPlaying() {
if (mRemoteMediaPlayer == null || mRemoteMediaPlayer.getMediaStatus() == null) {
returnnull;
}
// Here you can get the playback status and the metadata for what's playing// But only after the onStatusUpdated() method is called in the mRemoteMediaPlayer callback
int state = mRemoteMediaPlayer.getMediaStatus().getPlayerState();
return (state == MediaStatus.PLAYER_STATE_BUFFERING || state == MediaStatus.PLAYER_STATE_PLAYING);
}
@UiThreadprivateMediaRouter.RouteInfogetActiveChromecastRoute() {
for (MediaRouter.RouteInfo route : mMediaRouter.getRoutes()) {
if (isCastDevice(route)) {
if (route.getConnectionState() == MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTED) {
return route;
}
}
}
returnnull;
}
private int getMediaRouteVolume(@NonNull MediaRouter.RouteInfo route) {
return route.getVolume();
}
privatevoidsetMediaRouteVolume(@NonNull MediaRouter.RouteInfo route, int volume) {
route.requestSetVolume(volume);
}
private int getMediaRouteMaxVolume(@NonNull MediaRouter.RouteInfo route) {
return route.getVolumeMax();
}
@UiThreadprivateMediaRouter.RouteInfogetActiveMediaRoute() {
if (isChromecastActive()) {
MediaRouter.RouteInfo route = getActiveChromecastRoute();
if (route != null) {
if (!route.isSelected()) {
mMediaRouter.selectRoute(route);
}
}
elseif (mSelectedDevice != null) {
mSelectedDevice = null;
}
return route;
}
returnnull;
}
privatebooleanisCastDevice(MediaRouter.RouteInfo routeInfo) {
return routeInfo.getId().contains(CHROMECAST_SIGNATURE);
}
privateMediaRouter.Callback mMediaRouterCallback = newMediaRouter.Callback() {
@OverridepublicvoidonRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) {
if (isCastDevice(route)) {
Log.i("MediaRouter", "Chromecast found: " + route);
}
}
@OverridepublicvoidonRouteChanged(MediaRouter router, MediaRouter.RouteInfo route) {
if (isCastDevice(route)) {
Log.i("MediaRouter", "Chromecast changed: " + route);
}
}
@OverridepublicvoidonRouteSelected(MediaRouter router, MediaRouter.RouteInfo route) {
if (mSelectedDevice == null && isCastDevice(route)) {
Log.i("MediaRouter", "Chromecast selected: " + route);
mSelectedDevice = CastDevice.getFromBundle(route.getExtras());
mCastClientListener = newCast.Listener() {
@OverridepublicvoidonApplicationStatusChanged() {
Log.i("MediaRouter", "Cast.Listener.onApplicationStatusChanged()");
}
@OverridepublicvoidonApplicationMetadataChanged(ApplicationMetadata applicationMetadata) {
Log.i("MediaRouter", "Cast.Listener.onApplicationMetadataChanged(" + applicationMetadata + ")");
if (applicationMetadata != null) {
LaunchOptions launchOptions = newLaunchOptions.Builder().setRelaunchIfRunning(false).build();
Cast.CastApi.launchApplication(mApiClient, applicationMetadata.getApplicationId(), launchOptions).setResultCallback(newResultCallback<Cast.ApplicationConnectionResult>() {
@OverridepublicvoidonResult(@NonNull Cast.ApplicationConnectionResult applicationConnectionResult) {
Log.i("MediaRouter", "Cast.CastApi.joinApplication.onResult() " + applicationConnectionResult.getSessionId());
mRemoteMediaPlayer = newRemoteMediaPlayer();
mRemoteMediaPlayer.setOnStatusUpdatedListener( newRemoteMediaPlayer.OnStatusUpdatedListener() {
@OverridepublicvoidonStatusUpdated() {
MediaStatus mediaStatus = mRemoteMediaPlayer.getMediaStatus();
Log.i("MediaRouter", "Remote media player status " + mediaStatus.getPlayerState());
// TODO: you can call isChromecastPlaying() now
}
});
try {
Cast.CastApi.setMessageReceivedCallbacks(mApiClient, mRemoteMediaPlayer.getNamespace(), mRemoteMediaPlayer);
} catch(IOException e) {
Log.e("MediaRouter", "Exception while creating media channel ", e );
} catch(NullPointerException e) {
Log.e("MediaRouter", "Something wasn't reinitialized for reconnectChannels", e);
}
mRemoteMediaPlayer.requestStatus(mApiClient).setResultCallback(newResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
@OverridepublicvoidonResult(@NonNull RemoteMediaPlayer.MediaChannelResult mediaChannelResult) {
Log.i("MediaRouter", "requestStatus() " + mediaChannelResult);
}
});
try {
Cast.CastApi.requestStatus(mApiClient);
} catch (IOException e) {
Log.e("MediaRouter", "Couldn't request status", e);
}
}
});
}
}
@OverridepublicvoidonApplicationDisconnected(int i) {
Log.i("MediaRouter", "Cast.Listener.onApplicationDisconnected(" + i + ")");
}
@OverridepublicvoidonActiveInputStateChanged(int i) {
Log.i("MediaRouter", "Cast.Listener.onActiveInputStateChanged(" + i + ")");
}
@OverridepublicvoidonStandbyStateChanged(int i) {
Log.i("MediaRouter", "Cast.Listener.onStandbyStateChanged(" + i + ")");
}
@OverridepublicvoidonVolumeChanged() {
Log.i("MediaRouter", "Cast.Listener.onVolumeChanged()");
}
};
Cast.CastOptions.Builder apiOptionsBuilder = newCast.CastOptions.Builder(mSelectedDevice, mCastClientListener);
mApiClient = newGoogleApiClient.Builder(getContext())
.addApi( Cast.API, apiOptionsBuilder.build() )
.addConnectionCallbacks(newGoogleApiClient.ConnectionCallbacks() {
@OverridepublicvoidonConnected(@Nullable Bundle bundle) {
Log.i("MediaRouter", "GoogleApiClient.onConnected()");
Log.i("MediaRouter", "Bundle " + bundle);
}
@OverridepublicvoidonConnectionSuspended(int i) {
Log.i("MediaRouter", "GoogleApiClient.onConnectionSuspended(" + i + ")");
}
})
.addOnConnectionFailedListener(newGoogleApiClient.OnConnectionFailedListener() {
@OverridepublicvoidonConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.i("MediaRouter", "GoogleApiClient.onConnectionFailed()");
}
})
.build();
mApiClient.connect();
}
else {
mSelectedDevice = null;
mRemoteMediaPlayer = null;
}
}
@OverridepublicvoidonRouteRemoved(MediaRouter router, MediaRouter.RouteInfo route) {
if (isCastDevice(route)) {
if (mSelectedDevice != null && mSelectedDevice.isSameDevice(CastDevice.getFromBundle(route.getExtras()))) {
mSelectedDevice = null;
}
Log.i("MediaRouter", "Chromecast lost: " + route);
}
}
};
Post a Comment for "Android: Get Current Playing Media On Chromecast?"