I'm building a chromecast application. I'm able to launch the receiver with static text. However, I'm unable to interact with it(play media) and am getting
10-27 10:01:20.192 2292-6161/? E/MDM: [217] b.run: Couldn't connect to Google API client: ConnectionResult{statusCode=API_UNAVAILABLE, resolution=null, message=null}
in which I think could be the problem why I'm getting a timeout(Status code 15) when launching the application. I also notice that the Receiver screen stops casting after a while and my sender device doesn't detect this and still thinks it's an ongoing session. Does anyone see the problem?
See the code below for reference.
public class MediaRouterButtonActivity extends FragmentActivity {
private static final String TAG = MediaRouterButtonActivity.class
.getSimpleName();
private MediaRouter mMediaRouter;
private MediaRouteSelector mMediaRouteSelector;
private MediaRouter.Callback mMediaRouterCallback;
private MediaRouteButton mMediaRouteButton;
private int mRouteCount = 0;
private MediaMetadata mMediaMetadata;
private CastDevice mSelectedDevice;
private GoogleApiClient mApiClient;
private Cast.Listener mCastListener;
private ConnectionCallbacks mConnectionCallbacks;
private RemoteMediaPlayer mRemoteMediaPlayer;
private boolean mWaitingForReconnect;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.media_router_button);
mMediaRouter = MediaRouter.getInstance(getApplicationContext());
mMediaRouteSelector = new MediaRouteSelector.Builder()
.addControlCategory(
CastMediaControlIntent.categoryForCast(getResources().getString(R.string.app_id))).build();
// Set the MediaRouteButton selector for device discovery.
mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button);
mMediaRouteButton.setRouteSelector(mMediaRouteSelector);
mMediaRouterCallback = new MediaRouterCallback();
mCastListener = new CastListener();
mConnectionCallbacks = new ConnectionCallbacks();
mConnectionFailedListener = new ConnectionFailedListener();
mWaitingForReconnect = false;
mRemoteMediaPlayer = new RemoteMediaPlayer();
}
@Override
protected void onStart() {
super.onStart();
mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
}
@Override
protected void onResume() {
super.onResume();
// Add the callback to start device discovery
mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
}
@Override
protected void onPause() {
mMediaRouter.removeCallback(mMediaRouterCallback);
super.onPause();
}
@Override
protected void onStop() {
setSelectedDevice(null);
mMediaRouter.removeCallback(mMediaRouterCallback);
super.onStop();
}
private class MediaRouterCallback extends MediaRouter.Callback {
@Override
public void onRouteAdded(MediaRouter router, RouteInfo route) {
Log.d(TAG, "onRouteAdded");
if (++mRouteCount >= 1) {
// Show the button when a device is discovered.
mMediaRouteButton.setVisibility(View.VISIBLE);
}
}
@Override
public void onRouteRemoved(MediaRouter router, RouteInfo route) {
Log.d(TAG, "onRouteRemoved");
if (--mRouteCount == 0) {
// Hide the button if there are no devices discovered.
mMediaRouteButton.setVisibility(View.GONE);
}
}
@Override
public void onRouteSelected(MediaRouter router, RouteInfo info) {
Log.d(TAG, "onRouteSelected");
// Handle route selection
mSelectedDevice = CastDevice.getFromBundle(info.getExtras());
setSelectedDevice(mSelectedDevice);
}
@Override
public void onRouteUnselected(MediaRouter router, RouteInfo info) {
Log.d(TAG, "onRouteUnselected: info=" + info);
setSelectedDevice(null);
}
}
private void setSelectedDevice(CastDevice device) {
Log.d(TAG, "setSelectedDevice: " + device);
mSelectedDevice = device;
if (mSelectedDevice != null) {
try {
disconnectApiClient();
connectApiClient();
} catch (IllegalStateException e) {
Log.w(TAG, "Exception while connecting API client", e);
disconnectApiClient();
}
} else {
if (mApiClient != null) {
disconnectApiClient();
}
mMediaRouter.selectRoute(mMediaRouter.getDefaultRoute());
}
}
private void connectApiClient() {
Cast.CastOptions apiOptions = Cast.CastOptions.builder(mSelectedDevice, mCastListener)
.build();
mApiClient = new GoogleApiClient.Builder(getApplicationContext())
.addApi(Cast.API, apiOptions)
.addConnectionCallbacks(mConnectionCallbacks)
.addOnConnectionFailedListener(mConnectionFailedListener)
.build();
Log.d(TAG, "connectApiClient");
mApiClient.connect();
}
private void disconnectApiClient() {
if (mApiClient != null) {
if (mApiClient.isConnected() || mApiClient.isConnecting()) {
mApiClient.disconnect();
Log.d(TAG, "disconnectApiClient");
}
mApiClient = null;
}
}
private class ConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks {
@Override
public void onConnectionSuspended(int cause) {
mWaitingForReconnect = true;
Log.d(TAG, "ConnectionCallbacks.onConnectionSuspended");
}
@Override
public void onConnected(Bundle connectionHint) {
Log.d(TAG, "ConnectionCallbacks.onConnected");
if (mWaitingForReconnect) {
mWaitingForReconnect = false;
} else {
Cast.CastApi.launchApplication(mApiClient, getResources().getString(R.string.app_id))
.setResultCallback(new ConnectionResultCallback());
}
}
}
private final class ConnectionResultCallback implements
ResultCallback<ApplicationConnectionResult> {
@Override
public void onResult(ApplicationConnectionResult result) {
Status status = result.getStatus();
Log.d(TAG, "onResultOnConnected" + status.isSuccess());
if (status.isSuccess()) {
try {
Cast.CastApi.setMessageReceivedCallbacks(mApiClient,
mRemoteMediaPlayer.getNamespace(),
mRemoteMediaPlayer);
JSONObject customData = new JSONObject();
String accessToken = "asdkfalksdjfkaljsdfla";
try {
customData.put("X-At", accessToken);
} catch (JSONException e) {
Log.e(TAG, "Empty Access Token", e);
}
Log.d(TAG, "mediaMetaDataDebug");
mMediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
mMediaMetadata.putString(MediaMetadata.KEY_TITLE, "Demo Video");
MediaInfo mediaInfo = new MediaInfo.Builder(
"https://abcdef.com") //link Instead
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setCustomData(customData)
.build();
try {
mRemoteMediaPlayer.load(mApiClient, mediaInfo, true)
.setResultCallback(new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
@Override
public void onResult(RemoteMediaPlayer.MediaChannelResult mediaChannelResult) {
Status status = mediaChannelResult.getStatus();
if (status.isSuccess()) {
//allow users to pause video somehow;
}
}
});
} catch (Exception e) {
Log.e(TAG, "Problem while loading media", e);
}
Log.d(TAG, "wtf");
} catch (IOException e) {
Log.e(TAG, "Exception while creating channel", e);
}
} else {
Log.d(TAG, "ConnectionResultCallback. Unable to launch the application. statusCode: "
+ status.getStatusCode());
}
}
}
//google play services crap, fix later
private class CastListener extends Cast.Listener {
@Override
public void onApplicationDisconnected(int statusCode) {
Log.d(TAG, "onApplicationDisconnected");
setSelectedDevice(null);
try {
Cast.CastApi.removeMessageReceivedCallbacks(mApiClient,
mRemoteMediaPlayer.getNamespace());
} catch (IOException e) {
Log.w(TAG, "Exception while launching application", e);
}
}
}
}
This is the relevant log I'm getting
10-27 10:01:20.192 2292-6161/? E/MDM: [217] b.run: Couldn't connect to Google API client: ConnectionResult{statusCode=API_UNAVAILABLE, resolution=null, message=null}
10-27 10:59:54.962 2292-19493/? D/DeviceConnectionService: client connected with version: 8115000
10-27 11:01:12.922 27024-27024/? D/MediaRouterButtonActivity: ConnectionCallbacks.onConnected
10-27 11:01:13.002 2292-6727/? D/DeviceConnectionService: client connected with version: 8115000
10-27 11:01:33.952 27024-27024/? D/MediaRouterButtonActivity: ConnectionResultCallback. Unable to launch the application. statusCode: 15
The following changes made it work in my environment:
Then I was able to launch the app and see the media playing by clicking on "Media Route Button"