Implementing cast in android

Preview:

Citation preview

Google Cast with Android How to Implement Google Cast into Android Apps

+Angelo Rüggeberg @s3xy4ngyc

agenda

-  Introduction to Google Cast

-  Connecting an Android App to an

Cast App

-  Launching the Cast App

-  Interacting with the Cast App

-  using the CastCompanionLibrary

for Media

Introduction to Google Cast

Biggest, most beautiful screen in the house...

Your app on the TV!

Simple to get started with the SDK

Connecting technology

Start with your existing app

e.g. Phone app

e.g. Phone app

e.g. Phone app

Tablets

Web Apps

Your app is ‘The Sender’

Receiving device

Receiver app runs on Cast receiving device

Cast SDK app looks for Cast devices

Cast icon shown on discovery of Cast devices

Selection activates connected icon look

developers.google.com/cast/docs/ux_guidelines

Consistent UX fully documented

developers.google.com/cast/ docs/ux_guidelines

●  Selecting Cast Device ●  Pausing & Scrubbing ●  Visual Consistency

Sender triggers Receiver loading

https://…

Content loads direct from the cloud

https://…

Sender manages playback control

developers.google.com/cast/docs/receiver_apps

Images

Leader Board

1st Scotty 145

2nd Andrea 109

3rd Ralph 94

developers.google.com/cast/docs/downloads

Connecting an Android App to an Cast App

Environment: ●  Real Device

○  with Google Play Services Installed

●  Cast Device ○  e.g. Chromecast

Prequesites

Dependencies: play-services-cast

Handles Connection to Cast 'com.google.android.gms:play-services-cast:8.3.0'

support-media-router

Button to Connect to Cast 'com.android.support:mediarouter-v7:23.1.0'

Dependencies - build.gradle

dependencies { compile 'com.android.support:mediarouter-v7:23.1.0' compile 'com.google.android.gms:play-services-cast:8.3.0' }

Permissions - Manifest.xml

<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

Adding Media Route Button via Menu

<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/media_route_menu_item" android:title="@string/media_route_menu_title" app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider" app:showAsAction="always"/> </menu>

Adding Media Route Button via Menu

<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/media_route_menu_item" android:title="@string/media_route_menu_title" app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider" app:showAsAction="always"/> </menu>

Adding Media Route Button to an Layout

<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" /> <android.support.v7.app.MediaRouteButton android:id="@+id/media_route_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:mediaRouteTypes="user" /> … </RelativeLayout>

Adding Media Route Button to an Layout

<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" /> <android.support.v7.app.MediaRouteButton android:id="@+id/media_route_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:mediaRouteTypes="user" /> … </RelativeLayout>

Adding Media Route Button to an Layout

<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" /> <android.support.v7.app.MediaRouteButton android:id="@+id/media_route_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:mediaRouteTypes="user" /> … </RelativeLayout>

Fields - MainActivity.java

private MediaRouteButton mMediaRouteButton; private MediaRouter mMediaRouter; private MediaRouteSelector mMediaRouteSelector; private MediaRouter.Callback mMediaRouterCallback; private CastDevice mSelectedDevice;

Fields - MainActivity.java

private MediaRouteButton mMediaRouteButton; private MediaRouter mMediaRouter; private MediaRouteSelector mMediaRouteSelector; private MediaRouter.Callback mMediaRouterCallback; private CastDevice mSelectedDevice;

The Button added To the Layout

Fields - MainActivity.java

private MediaRouteButton mMediaRouteButton; private MediaRouter mMediaRouter; private MediaRouteSelector mMediaRouteSelector; private MediaRouter.Callback mMediaRouterCallback; private CastDevice mSelectedDevice;

The Media Router. This handles the Connection to our Cast Device

Fields - MainActivity.java

private MediaRouteButton mMediaRouteButton; private MediaRouter mMediaRouter; private MediaRouteSelector mMediaRouteSelector; private MediaRouter.Callback mMediaRouterCallback; private CastDevice mSelectedDevice; The Route Selector.

This is the Configuration for our Connection e.g the Device to Interact with

Fields - MainActivity.java

private MediaRouteButton mMediaRouteButton; private MediaRouter mMediaRouter; private MediaRouteSelector mMediaRouteSelector; private MediaRouter.Callback mMediaRouterCallback; private CastDevice mSelectedDevice;

The Router Callbacks. These Callbacks are used to Notify the Application on Select and Deselction of an Device Route and enables us to react to these events e.g by printing the Connected Device to the User.

Fields - MainActivity.java

private MediaRouteButton mMediaRouteButton; private MediaRouter mMediaRouter; private MediaRouteSelector mMediaRouteSelector; private MediaRouter.Callback mMediaRouterCallback; private CastDevice mSelectedDevice;

The Cast Device we are Connected to. It contains Informations like Device Name, Model, Capabilities, etc.

Initializing - MainActivity.java

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); mConnectionStatus = (TextView) findViewById(R.id.text_connection); mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button); initCast(); }

Initializing - MainActivity.java

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); mConnectionStatus = (TextView) findViewById(R.id.text_connection); mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button); initCast(); }

Initializing - MainActivity.java

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); mConnectionStatus = (TextView) findViewById(R.id.text_connection); mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button); initCast(); }

Initializing - MainActivity.java

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); mConnectionStatus = (TextView) findViewById(R.id.text_connection); mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button); initCast(); }

Initializing - MainActivity.java private void initCast() { // Configure Cast device discovery mMediaRouter = MediaRouter.getInstance(getApplicationContext()); }

Initializing - MainActivity.java private void initCast() { // Configure Cast device discovery mMediaRouter = MediaRouter.getInstance(getApplicationContext()); mMediaRouteSelector = new MediaRouteSelector.Builder() .addControlCategory( CastMediaControlIntent.categoryForCast(getResources().getString(R.string.app_id))) .build(); }

Initializing - MainActivity.java private void initCast() { // Configure Cast device discovery mMediaRouter = MediaRouter.getInstance(getApplicationContext()); mMediaRouteSelector = new MediaRouteSelector.Builder() .addControlCategory( CastMediaControlIntent.categoryForCast(getResources().getString(R.string.app_id))) .build(); } The Cast Application ID.

E.g “794B7BBF” (Cast Sample Helloworld)

Initializing - MainActivity.java private void initCast() { // Configure Cast device discovery 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.setRouteSelector(mMediaRouteSelector); }

Initializing - MainActivity.java @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat .getActionProvider(mediaRouteMenuItem); // Set the MediaRouteActionProvider selector for device discovery. mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector); return true; }

Initializing - MainActivity.java @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat .getActionProvider(mediaRouteMenuItem); // Set the MediaRouteActionProvider selector for device discovery. mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector); return true; }

Initializing - MainActivity.java @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat .getActionProvider(mediaRouteMenuItem); // Set the MediaRouteActionProvider selector for device discovery. mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector); return true; }

Initializing - MainActivity.java @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat .getActionProvider(mediaRouteMenuItem); // Set the MediaRouteActionProvider selector for device discovery. mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector); return true; }

Adding Callbacks - MainActivity.java private void initCast() { // Configure Cast device discovery 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.setRouteSelector(mMediaRouteSelector); mMediaRouterCallback = new MyMediaRouterCallback(); }

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Called after we Selected an Cast Device we want to Connect with. This does not mean we are Connected to the Cast Application yet!

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Called after we Decided to Disconnect from an Cast Device. This does not mean we are Disconnected from the Application yet!

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Adding Callbacks - MainActivity.java private class MyMediaRouterCallback extends MediaRouter.Callback { @Override public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) { // Handle the user route selection. mSelectedDevice = CastDevice.getFromBundle(info.getExtras()); mConnectionStatus.setText("Connected to: " + mSelectedDevice.getFriendlyName()); } @Override public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) { mSelectedDevice = null; mConnectionStatus.setText("Not Connected"); } }

Starting Discovery - MainActivity.java @Override protected void onStart() { super.onStart(); // Start media router discovery mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); } @Override protected void onStop() { // End media router discovery mMediaRouter.removeCallback(mMediaRouterCallback); super.onStop(); }

Starting Discovery - MainActivity.java @Override protected void onStart() { super.onStart(); // Start media router discovery mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); } @Override protected void onStop() { // End media router discovery mMediaRouter.removeCallback(mMediaRouterCallback); super.onStop(); }

Starting Discovery - MainActivity.java @Override protected void onStart() { super.onStart(); // Start media router discovery mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); } @Override protected void onStop() { // End media router discovery mMediaRouter.removeCallback(mMediaRouterCallback); super.onStop(); }

Demo

Launching the Cast Application

New Fields - MainActivity.java

private GoogleApiClient mApiClient; private Cast.Listener mCastListener; private ConnectionCallbacks mConnectionCallbacks; private ConnectionFailedListener mConnectionFailedListener; private boolean mApplicationStarted; private boolean mWaitingForReconnect; private String mSessionId;

New Fields - MainActivity.java

private GoogleApiClient mApiClient; private Cast.Listener mCastListener; private ConnectionCallbacks mConnectionCallbacks; private ConnectionFailedListener mConnectionFailedListener; private boolean mApplicationStarted; private boolean mWaitingForReconnect; private String mSessionId;

The Api Client is used to Interact with The Chromecast e.g. Sending Messages

New Fields - MainActivity.java

private GoogleApiClient mApiClient; private Cast.Listener mCastListener; private ConnectionCallbacks mConnectionCallbacks; private ConnectionFailedListener mConnectionFailedListener; private boolean mApplicationStarted; private boolean mWaitingForReconnect; private String mSessionId;

Our Callbacks to Notify us about Connection Events e.g. disconnection

New Fields - MainActivity.java

private GoogleApiClient mApiClient; private Cast.Listener mCastListener; private ConnectionCallbacks mConnectionCallbacks; private ConnectionFailedListener mConnectionFailedListener; private boolean mApplicationStarted; private boolean mWaitingForReconnect; private String mSessionId;

The Connection Callbacks. e.G. we get disconnected due to application errors

New Fields - MainActivity.java

private GoogleApiClient mApiClient; private Cast.Listener mCastListener; private ConnectionCallbacks mConnectionCallbacks; private ConnectionFailedListener mConnectionFailedListener; private boolean mApplicationStarted; private boolean mWaitingForReconnect; private String mSessionId;

Our Callback if the connection Fails

New Fields - MainActivity.java

private GoogleApiClient mApiClient; private Cast.Listener mCastListener; private ConnectionCallbacks mConnectionCallbacks; private ConnectionFailedListener mConnectionFailedListener; private boolean mApplicationStarted; private boolean mWaitingForReconnect; private String mSessionId;

We keep Some Information for our Application stored in these Fields

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { @Override public void onApplicationDisconnected(int errorCode) { Log.d(TAG, "application has stopped"); teardown(true); } }; }

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); }

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions .builder(mSelectedDevice, mCastListener); }

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions .builder(mSelectedDevice, mCastListener); }

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions .builder(mSelectedDevice, mCastListener); mApiClient = new GoogleApiClient.Builder(this) .addApi(Cast.API, apiOptionsBuilder.build()) .addConnectionCallbacks(mConnectionCallbacks) .addOnConnectionFailedListener(mConnectionFailedListener) .build(); }

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions .builder(mSelectedDevice, mCastListener); mApiClient = new GoogleApiClient.Builder(this) .addApi(Cast.API, apiOptionsBuilder.build()) .addConnectionCallbacks(mConnectionCallbacks) .addOnConnectionFailedListener(mConnectionFailedListener) .build(); }

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions .builder(mSelectedDevice, mCastListener); mApiClient = new GoogleApiClient.Builder(this) .addApi(Cast.API, apiOptionsBuilder.build()) .addConnectionCallbacks(mConnectionCallbacks) .addOnConnectionFailedListener(mConnectionFailedListener) .build(); }

Launching the Cast Application - MainActivity.java

private void launchReceiver() { mCastListener = new Cast.Listener() { … }; mConnectionCallbacks = new ConnectionCallbacks(); mConnectionFailedListener = new ConnectionFailedListener(); Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions .builder(mSelectedDevice, mCastListener); mApiClient = new GoogleApiClient.Builder(this) .addApi(Cast.API, apiOptionsBuilder.build()) .addConnectionCallbacks(mConnectionCallbacks) .addOnConnectionFailedListener(mConnectionFailedListener) .build(); mApiClient.connect(); }

Launching the Cast Application - MainActivity.java

private class ConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks { @Override public void onConnected(Bundle connectionHint) { ... // Launch the receiver app Cast.CastApi.launchApplication(mApiClient, getString(R.string.app_id), false) .setResultCallback( new ResultCallback<Cast.ApplicationConnectionResult>() { @Override public void onResult(Cast.ApplicationConnectionResult result) {

… } }

Launching the Cast Application - MainActivity.java

private class ConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks { @Override public void onConnected(Bundle connectionHint) { ... // Launch the receiver app Cast.CastApi.launchApplication(mApiClient, getString(R.string.app_id), false) .setResultCallback( new ResultCallback<Cast.ApplicationConnectionResult>() { @Override public void onResult(Cast.ApplicationConnectionResult result) {

… } }

Launching the Cast Application - MainActivity.java

Status status = result.getStatus(); if (status.isSuccess()) { ApplicationMetadata applicationMetadata = result .getApplicationMetadata(); mSessionId = result.getSessionId(); mApplicationStarted = true; } else { Log.e(TAG, "application could not launch"); teardown(true); }

Launching the Cast Application - MainActivity.java

Status status = result.getStatus(); if (status.isSuccess()) { ApplicationMetadata applicationMetadata = result .getApplicationMetadata(); mSessionId = result.getSessionId(); mApplicationStarted = true; } else { Log.e(TAG, "application could not launch"); teardown(true); }

Launching the Cast Application - MainActivity.java

Status status = result.getStatus(); if (status.isSuccess()) { ApplicationMetadata applicationMetadata = result .getApplicationMetadata(); mSessionId = result.getSessionId(); mApplicationStarted = true; } else { Log.e(TAG, "application could not launch"); teardown(true); }

Launching the Cast Application - MainActivity.java

Status status = result.getStatus(); if (status.isSuccess()) { ApplicationMetadata applicationMetadata = result .getApplicationMetadata(); mSessionId = result.getSessionId(); mApplicationStarted = true; } else { Log.e(TAG, "application could not launch"); teardown(true); }

Launching the Cast Application - MainActivity.java

private void teardown(boolean selectDefaultRoute) { if (mApiClient != null) { if (mApplicationStarted) { if (mApiClient.isConnected() || mApiClient.isConnecting()) { Cast.CastApi.stopApplication(mApiClient, mSessionId); mApiClient.disconnect(); } mApplicationStarted = false; } mApiClient = null; } mSelectedDevice = null; mWaitingForReconnect = false; mSessionId = null; }

Launching the Cast Application - MainActivity.java

private void teardown(boolean selectDefaultRoute) { if (mApiClient != null) { if (mApplicationStarted) { if (mApiClient.isConnected() || mApiClient.isConnecting()) { Cast.CastApi.stopApplication(mApiClient, mSessionId); mApiClient.disconnect(); } mApplicationStarted = false; } mApiClient = null; } mSelectedDevice = null; mWaitingForReconnect = false; mSessionId = null; }

Launching the Cast Application - MainActivity.java

private void teardown(boolean selectDefaultRoute) { if (mApiClient != null) { if (mApplicationStarted) { if (mApiClient.isConnected() || mApiClient.isConnecting()) { Cast.CastApi.stopApplication(mApiClient, mSessionId); mApiClient.disconnect(); } mApplicationStarted = false; } mApiClient = null; } mSelectedDevice = null; mWaitingForReconnect = false; mSessionId = null; }

Launching the Cast Application - MainActivity.java

private void teardown(boolean selectDefaultRoute) { if (mApiClient != null) { if (mApplicationStarted) { if (mApiClient.isConnected() || mApiClient.isConnecting()) { Cast.CastApi.stopApplication(mApiClient, mSessionId); mApiClient.disconnect(); } mApplicationStarted = false; } mApiClient = null; } mSelectedDevice = null; mWaitingForReconnect = false; mSessionId = null; }

Demo

Interacting with the Cast Application

Sending Messages - MainActivity.java

class HelloWorldChannel implements Cast.MessageReceivedCallback { public String getNamespace() { return getString(R.string.namespace); } @Override public void onMessageReceived(CastDevice castDevice, String namespace, String message) { } }

Sending Messages - MainActivity.java

class HelloWorldChannel implements Cast.MessageReceivedCallback { public String getNamespace() { return getString(R.string.namespace); } @Override public void onMessageReceived(CastDevice castDevice, String namespace, String message) { } }

Sending Messages - MainActivity.java

class HelloWorldChannel implements Cast.MessageReceivedCallback { public String getNamespace() { return getString(R.string.namespace); } @Override public void onMessageReceived(CastDevice castDevice, String namespace, String message) { } }

Our Custom Namespace. This is defined in our reciever app. e.g. urn:x-cast:com.google.cast.sample.helloworld

Sending Messages - MainActivity.java

class HelloWorldChannel implements Cast.MessageReceivedCallback { public String getNamespace() { return getString(R.string.namespace); } @Override public void onMessageReceived(CastDevice castDevice, String namespace, String message) { } } This gets Triggered when the Reciever Sends Data

To our Client. e.g. Updated Scores on Games

Sending Messages - MainActivity.java

// Launch the receiver app Cast.CastApi.launchApplication(mApiClient, getString(R.string.app_id), false) …. // Create the custom message // channel mHelloWorldChannel = new HelloWorldChannel(); try { Cast.CastApi.setMessageReceivedCallbacks( mApiClient, mHelloWorldChannel.getNamespace(), mHelloWorldChannel); } catch (IOException e) { Log.e(TAG, "Exception while creating channel", e); }

Sending Messages - MainActivity.java

// Launch the receiver app Cast.CastApi.launchApplication(mApiClient, getString(R.string.app_id), false) …. // Create the custom message // channel mHelloWorldChannel = new HelloWorldChannel(); try { Cast.CastApi.setMessageReceivedCallbacks( mApiClient, mHelloWorldChannel.getNamespace(), mHelloWorldChannel); } catch (IOException e) { Log.e(TAG, "Exception while creating channel", e); }

Sending Messages - MainActivity.java

// Launch the receiver app Cast.CastApi.launchApplication(mApiClient, getString(R.string.app_id), false) …. // Create the custom message // channel mHelloWorldChannel = new HelloWorldChannel(); try { Cast.CastApi.setMessageReceivedCallbacks( mApiClient, mHelloWorldChannel.getNamespace(), mHelloWorldChannel); } catch (IOException e) { Log.e(TAG, "Exception while creating channel", e); }

Sending Messages - MainActivity.java

// Launch the receiver app Cast.CastApi.launchApplication(mApiClient, getString(R.string.app_id), false) …. // Create the custom message // channel mHelloWorldChannel = new HelloWorldChannel(); try { Cast.CastApi.setMessageReceivedCallbacks( mApiClient, mHelloWorldChannel.getNamespace(), mHelloWorldChannel); } catch (IOException e) { Log.e(TAG, "Exception while creating channel", e); }

Sending Messages - MainActivity.java

private void sendMessage(String message) { if (mApiClient != null && mHelloWorldChannel != null) { try { Cast.CastApi.sendMessage(mApiClient, mHelloWorldChannel.getNamespace(), message).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status result) { if (!result.isSuccess()) { Log.e(TAG, "Sending message failed"); } } }); } catch (Exception e) { Log.e(TAG, "Exception while sending message", e); } }

Sending Messages - MainActivity.java

private void sendMessage(String message) { if (mApiClient != null && mHelloWorldChannel != null) { try { Cast.CastApi.sendMessage(mApiClient, mHelloWorldChannel.getNamespace(), message).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status result) { if (!result.isSuccess()) { Log.e(TAG, "Sending message failed"); } } }); } catch (Exception e) { Log.e(TAG, "Exception while sending message", e); } }

Sending Messages - MainActivity.java

private void sendMessage(String message) { if (mApiClient != null && mHelloWorldChannel != null) { try { Cast.CastApi.sendMessage(mApiClient, mHelloWorldChannel.getNamespace(), message).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status result) { if (!result.isSuccess()) { Log.e(TAG, "Sending message failed"); } } }); } catch (Exception e) { Log.e(TAG, "Exception while sending message", e); } }

Sending Messages - MainActivity.java

private void sendMessage(String message) { if (mApiClient != null && mHelloWorldChannel != null) { try { Cast.CastApi.sendMessage(mApiClient, mHelloWorldChannel.getNamespace(), message).setResultCallback( new ResultCallback<Status>() { @Override public void onResult(Status result) { if (!result.isSuccess()) { Log.e(TAG, "Sending message failed"); } } }); } catch (Exception e) { Log.e(TAG, "Exception while sending message", e); } }

Sending Messages - MainActivity.java

mSendButton = (Button) findViewById(R.id.button_send); mSendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendMessage(mTextInput.getText().toString()); } });

Sending Messages - MainActivity.java

mSendButton = (Button) findViewById(R.id.button_send); mSendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendMessage(mTextInput.getText().toString()); } });

Demo

Wrap up

Wrap up

●  Initialize via MediaRouter ●  Select Device via MediaRouteSelector ●  Connect via GoogleApiClient ●  Setup Message Bus ●  Send Messages via CastApi through ApiClient

Using the CastCompanionLibrary for Media Streaming

Getting Started

●  Checkout CastCompanionLibrary from Github ○  https://github.com/googlecast/CastCompanionLibrary-android

●  Compile AAR file

○  ./gradlew build

●  copy compiled AAR to Project ○  rename to CastCompanionLibrary-2.6.aar ○  add repository flat dir to build.gradle ○  compile 'com.google.sample.castcompanionlibrary:CastCompanionLibrary:2.6@aar'

Cast Companion - build.gradle

repositories { flatDir { dirs 'libs' } } dependencies { ... compile 'com.android.support:mediarouter-v7:23.1.0' compile 'com.google.android.gms:play-services-cast:8.3.0' companionCompile 'com.google.sample.castcompanionlibrary:CastCompanionLibrary:2.6@aar' }

Cast Companion - AndroidManifest.xml

<activity android:name="com.google.android.libraries.cast.companionlibrary.cast.player.VideoCastControllerActivity" android:theme="@style/AppTheme.NoActionBar" />

Cast Companion - MainActivity.java

private VideoCastManager mCastManager; private VideoCastConsumer mCastConsumer = new VideoCastConsumerImpl() {};

Cast Companion - MainActivity.java

@Override protected void onResume() { Log.d(TAG, "onResume() was called"); mCastManager = VideoCastManager.getInstance(); mCastManager.addVideoCastConsumer(mCastConsumer); mCastManager.incrementUiCounter(); super.onResume(); }

Cast Companion - MainActivity.java

private void initCast() { // initialize VideoCastManager VideoCastManager. initialize(this, getString(R.string.app_id), VideoCastControllerActivity.class, null). setVolumeStep(VOLUME_INCREMENT). enableFeatures(VideoCastManager.FEATURE_NOTIFICATION | VideoCastManager.FEATURE_LOCKSCREEN | VideoCastManager.FEATURE_WIFI_RECONNECT | VideoCastManager.FEATURE_AUTO_RECONNECT | VideoCastManager.FEATURE_CAPTIONS_PREFERENCE | VideoCastManager.FEATURE_DEBUGGING); }

Cast Companion - MainActivity.java

private void initCast() { // initialize VideoCastManager VideoCastManager. initialize(this, getString(R.string.app_id), VideoCastControllerActivity.class, null). setVolumeStep(VOLUME_INCREMENT). enableFeatures(VideoCastManager.FEATURE_NOTIFICATION | VideoCastManager.FEATURE_LOCKSCREEN | VideoCastManager.FEATURE_WIFI_RECONNECT | VideoCastManager.FEATURE_AUTO_RECONNECT | VideoCastManager.FEATURE_CAPTIONS_PREFERENCE | VideoCastManager.FEATURE_DEBUGGING); }

The Cast Controller Activity. Provided By Cast Companion Library

Cast Companion - MainActivity.java

private void initCast() { // initialize VideoCastManager VideoCastManager. initialize(this, getString(R.string.app_id), VideoCastControllerActivity.class, null). setVolumeStep(VOLUME_INCREMENT). enableFeatures(VideoCastManager.FEATURE_NOTIFICATION | VideoCastManager.FEATURE_LOCKSCREEN | VideoCastManager.FEATURE_WIFI_RECONNECT | VideoCastManager.FEATURE_AUTO_RECONNECT | VideoCastManager.FEATURE_CAPTIONS_PREFERENCE | VideoCastManager.FEATURE_DEBUGGING); }

Custom Namespace Like Message Channel from Previous Example

Cast Companion - MainActivity.java

private void initCast() { // initialize VideoCastManager VideoCastManager. initialize(this, getString(R.string.app_id), VideoCastControllerActivity.class, null). setVolumeStep(VOLUME_INCREMENT). enableFeatures(VideoCastManager.FEATURE_NOTIFICATION | VideoCastManager.FEATURE_LOCKSCREEN | VideoCastManager.FEATURE_WIFI_RECONNECT | VideoCastManager.FEATURE_AUTO_RECONNECT | VideoCastManager.FEATURE_CAPTIONS_PREFERENCE | VideoCastManager.FEATURE_DEBUGGING); }

Cast Companion - MainActivity.java

@Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); mCastManager.addMediaRouterButton(menu, R.id.media_route_menu_item); return true; }

Cast Companion - MainActivity.java

@Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); mCastManager.addMediaRouterButton(menu, R.id.media_route_menu_item); return true; }

Cast Companion - MainActivity.java

private void loadRemoteMedia(int position, MediaInfo media, boolean autoPlay) { mCastManager.startVideoCastControllerActivity(this, media, position, autoPlay); }

Cast Companion - MainActivity.java

mCastButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MediaMetadata metadata = new MediaMetadata(); MediaInfo media = new MediaInfo .Builder(mTextVideoUrl.getText().toString()) .setContentType("video/mp4") .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setMetadata(metadata) .setStreamDuration(596) .build(); loadRemoteMedia(0, media, true); } });

Cast Companion - MainActivity.java

mCastButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MediaMetadata metadata = new MediaMetadata(); MediaInfo media = new MediaInfo .Builder(mTextVideoUrl.getText().toString()) .setContentType("video/mp4") .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setMetadata(metadata) .setStreamDuration(596) .build(); loadRemoteMedia(0, media, true); } });

The Url to our Video e.g. .mp4 file

Cast Companion - MainActivity.java

mCastButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MediaMetadata metadata = new MediaMetadata(); MediaInfo media = new MediaInfo .Builder(mTextVideoUrl.getText().toString()) .setContentType("video/mp4") .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setMetadata(metadata) .setStreamDuration(596) .build(); loadRemoteMedia(0, media, true); } });

Required. Contains Metadata like Studio, Production Year, etc.

Cast Companion - MainActivity.java

mCastButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MediaMetadata metadata = new MediaMetadata(); MediaInfo media = new MediaInfo .Builder(mTextVideoUrl.getText().toString()) .setContentType("video/mp4") .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setMetadata(metadata) .setStreamDuration(596) .build(); loadRemoteMedia(0, media, true); } });

Recommended