The Cast plugin for the Native SDK for Android

Product(s)
Video Cloud
Brightcove Player
Role(s)
Device SDK Developer
Task(s)
Develop with the Native SDKs
Topic(s)
Playback
SDK
Android

In this topic, you will learn how to cast your videos to a Chromecast-connected TV, using the Cast plugin for the Brightcove Player SDK for Android.

Overview

With Google Cast technology, you can initiate and control streamed video content from your mobile devices to high-definition TV and home audio systems. From your app, you will be able to tap the Cast button to stream your content on a big screen.

To build a Cast application, you need the following components:

  • A sender application - This resides on your mobile device, and detects receiver devices, establishes a secure connection and mirrors your content. The sender app is the local player that is cast to the Chromecast. After you cast to the receiver app, you can think of it as a remote control for the Chromecast.

    The sender app is provided by the Cast plugin for the Brightcove Player SDK for Android. You will learn about it in this topic.

  • A receiver application - This is the code that runs on the Chromecast device. It can be thought of as a single page HTML app with CSS and JS assets.

    You can use Google's Default Media Receiver for testing. For production, you will want to create your own receiver app. For details, see Google's Cast Receiver Applications documentation.

Cast plugin

The Cast plugin is built on top of the new ExoPlayer Cast Extension and the Google Play Services Cast Framework. After adding the cast plugin dependency, gradle will pull the Play Services Cast Framework dependency, ExoPlayer Cast Extension dependency along with other needed dependencies. To learn more about the dependencies used, see the Cast Plugin dependencies section.

Supported SDK version

For the Cast plugin, you must use the Brightcove Native SDK for Android version 6.3.0+.

Getting started

To start using the Cast plugin, follow these steps:

  1. In your build.gradle file, add the following dependency to include the Cast plugin:
    implementation "com.brightcove.player:android-cast-plugin:6.3.0"

Options Provider

Next, you need to specify the OptionsProvider implementation for the Google Cast framework. The OptionsProvider interface helps to set up several options needed to initialize the CastContext class. This is where you will set the Cast Receiver App ID. To learn more about integrating the OptionsProvider, see Google’s document: Initialize the Cast Context.

The Brightcove Cast plugin includes a DefaultOptionsProvider class, where a default Google Demo Cast Receiver App ID is set through a string key set in the strings.xml file. For more details and to learn how to overwrite it, see the Cast Receiver App ID section.

  1. Whether you use the DefaultOptionsProvider class or your own OptionsProvider implementation, you need to set the OptionsProvider implementation class name in your app’s AndroidManifest.xml file as a key-value pair metadata, as shown here:
    <meta-data
    android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
    android:value="com.brightcove.cast.DefaultOptionsProvider" />

If you use the DefaultOptionsProvider class, you will be able to set the ExpandedControllerActivity and turn on on/off the Cast Notification by setting similar metadata information in your AndroidManifest.

Expanded Controller Activity

The ExpandedControllerActivity comes with the Google Cast library and allows you to control the video being cast on your Chromecast device. This class provides some customization flexibility. For example, there are five slots available to show buttons, where the third slot is reserved for the non-configurable Play button. The rest of the buttons can be set as other predefined buttons or as your own customized buttons.

The Brightcove Cast plugin provides the subclass DefaultExpandedControllerActivity. We have enabled the following buttons in the following order:

  • Closed Captions
  • Skip Previous
  • Play
  • Skip Next
  • Mute Toggle

In addition, the Seek Bar sets the same default drawable as the one used in the standard BrightcoveMediaController:

  • The Progress Drawable:
    R.drawable.default_scrubber_progress_horizontal
  • The Thumb Drawable:
    R.drawable.default_scrubber_thumb

To learn how to customize the Seek Bar, see the SeekBarColorsSampleApp.

  1. In order to set the DefaultExpandedControllerActivity or your own ExpandedControllerActivity, set the following metadata in your AndroidManifest.xml file:
    <meta-data  android:name="com.brightcove.cast.DefaultOptionsProvider.EXPANDED_CONTROLLER_ACTIVITY_CLASS_NAME"
    android:value="com.brightcove.cast.DefaultExpandedControllerActivity" />

Cast Notification

When the Cast Notification is enabled, the notification will appear when you cast a video and put your app in the background; for example, after pressing the home key.

  1. To enable Cast Notification, set the following metadata in your AndroidManifest.xml file and provide the name of the Activity to launch when the notification is clicked:
    <meta-data android:name="com.brightcove.cast.DefaultOptionsProvider.NOTIFICATION_TARGET_ACTIVITY_CLASS_NAME"
    android:value="com.brightcove.cast.BrightcoveControllerActivity" />

If you do not provide com.brightcove.cast.DefaultOptionsProvider.NOTIFICATION_TARGET_ACTIVITY_CLASS_NAME or if the value has an invalid Activity name, the Cast Notification will be turned off.

Cast Receiver App Id

Next, set your Google Cast Receiver App Id in your project. The Cast Receiver Application is a web player responsible for playing your videos in the Chromecast device. To learn more about receiver applications, visit Google’s official guide. Your Receiver application will have a unique hexadecimal ID. This is the ID you will set in your the Android App.

  1. By default, the Brightcove Cast Plugin sets a Google Demo Receiver App ID, which is helpful for getting started and testing, but not for production. To overwrite this value with your Cast Receiver Application, define the following string value in your strings.xml file:
    <string name="cast_receiver_app_id">4F8B3483</string>

The Cast Button

The cast button allows you to select a Chromecast device in the same network as your device, and enables you to connect and create a session. To add the Cast Button to your application, follow Google’s document Integrate Cast: Add a Cast Button.

  1. The Brightcove Cast plugin provides a utility method to easily setup the Cast button. This is useful when you just want to add the Cast button to the Activity/Fragment menu. See the following code for details:
    //Activity
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
       super.onCreateOptionsMenu(menu);
       GoogleCastComponent.setUpMediaRouteButton(MainActivity.this, menu);
       return true;
    }

The Mini Controller

The Mini Controller is a Fragment that gets attached to your Activity, usually located in the bottom of the layout. The Mini Controller allows you to play and pause the video, and indicates when a video is playing in your Chromecast device. When the Mini Controller is clicked, the Expanded Controller will be launched.

  1. To enable the Mini Controller, add the following code to your Activity’s layout.
    <fragment
       android:id="@+id/castMiniController"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_alignParentBottom="true"
       android:visibility="gone"
       class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment" />

To learn best practices with the Mini Controller, see the Design Checklist: Sender Mini Controller document. For implementation details, see the Integrate Cast: Add Mini Controller document.

The Brightcove GoogleCastComponent

The GoogleCastComponentGoogleCastComponent class is the main class of the Brightcove Cast plugin. It instantiates the ExoPlayer CastPlayer and sets its listeners. It exposes some essential methods to load a video or to add it to the queue. The GoogleCastComponent class also adds several Brightcove Event listeners to handle Activity and Fragment lifecycle events, as well as other event listeners that you can use to emit Media Info to load a Video to your Chromecast device.

The Cast plugin was designed to require minimal effort with Video Cloud. When using Video Cloud, the BrightcoveCastMediaManager class gathers information from the Video Cloud response, such as the Brightcove Video and Source objects, every time the EventType.SET_SOURCE event is emitted. This information is cached and ready to use when the user selects play to queue the video.

  1. In order to create the GoogleCastComponent class, you need to pass the Context and EventEmitter:
    GoogleCastComponent googleCastComponent = new GoogleCastComponent(eventEmitter, context);

    Or you can subclass BrightcoveCastMediaManager to overwrite some of its behavior and pass it to the GoogleCastComponent:

    MyBrightcoveCastMediaManager myBrightcoveCastMediaManager = new MyBrightcoveCastMediaManager(context, eventEmitter);
    
    GoogleCastComponent googleCastComponent = new GoogleCastComponent(eventEmitter, context, myBrightcoveCastMediaManager);

This is all you need to start casting videos to your Chromecast device.

Listening for Cast session

If you want your app to react when the Cast connection starts or ends, you can add the GoogleCastEventType.CAST_SESSION_STARTED or GoogleCastEventType.CAST_SESSION_ENDED event listeners as shown here:

eventEmitter.on(GoogleCastEventType.CAST_SESSION_STARTED, new EventListener() {
   @Override
   public void processEvent(Event event) {
       // Session Started
   }
});
eventEmitter.on(GoogleCastEventType.CAST_SESSION_ENDED, new EventListener() {
   @Override
   public void processEvent(Event event) {
       // Session Ended
   }
});

Alternatively, you can call GoogleCastComponent.isSessionAvailable() to check for an available session.

Casting a Video

In order to cast a Video to Chromecast after a successful connection, you can either use the EventEmitter and emit the Media Info information or you can directly use the GoogleCastComponent methods.

If you prefer to emit the Media Info you can use the following events:

  • GoogleCastEventType.LOAD_MEDIA_INFO
  • GoogleCastEventType.LOAD_MEDIA_QUEUE_ITEM
  • GoogleCastEventType.ADD_MEDIA_INFO
  • GoogleCastEventType.ADD_MEDIA_QUEUE_ITEM

The following table shows the expected properties for each event:

Event Name Properties
Key Value Class type
LOAD_MEDIA_INFO GoogleCastComponent.CAST_MEDIA_INFO
GoogleCastComponent.CAST_MEDIA_PLAY_POSITION
MediaInfo Integer
LOAD_MEDIA_QUEUE_ITEM GoogleCastComponent.CAST_MEDIA_QUEUE_ITEM MediaQueueItem
ADD_MEDIA_INFO GoogleCastComponent.CAST_MEDIA_INFO
GoogleCastComponent.CAST_MEDIA_PLAY_POSITION
MediaInfo Integer
ADD_MEDIA_QUEUE_ITEM GoogleCastComponent.CAST_MEDIA_QUEUE_ITEM MediaQueueItem

Alternatively, you can use the following GoogleCastComponent methods:

  • public void loadMediaInfo(MediaInfo mediaInfo, long positionMs)
  • public void loadMediaInfo(MediaInfo mediaInfo)
  • public PendingResult<RemoteMediaClient.MediaChannelResult> loadItem(MediaQueueItem mediaQueue, int playheadPosition)
  • public PendingResult<RemoteMediaClient.MediaChannelResult> addItems(MediaQueueItem... mediaQueue )

Changing the default MediaInfo data

By default, the Cast plugin gathers information about the current Video and Source object emitted by the EventType.SET_SOURCE event. If you want to change or add additional information, such as adding a custom JSON object to your MediaInfo that your App receiver understands, you can do it by overwriting the loadMediaInfo() and addMediaInfo() methods from the BrightcoveCastMediaManager. Then, your BrightcoveCastMediaManager subclass is passed as a constructor parameter to the GoogleCastComponent class.

Inside these methods, you can create your MediaInfo objects and emit the appropriate events as shown previously. Be sure to check com.brightcove.cast.util.CastMediaUtil, as it provides some utility methods to create a MediaInfo from the Video and Source objects.

Configuring the Cast MediaController

To change the controller layout that appears in your Brightcove Video View when a Cast session has started, follow these steps.

  1. Extend the BrightcoveCastMediaManager
  2. Set the MediaControllerConfig
  3. Overwrite the control bar setup

Extend the BrightcoveCastMediaManager

To change the default behavior of the BrightcoveCastMediaManager, create a subclass and overwrite some key methods:

  • public void updateBrightcoveMediaController(boolean isRemote)

    This method is called by the GoogleCastComponent when the session changes; that is, when the session has started or has ended. When the session has started, the isRemote parameter will be true and the setupRemoteController method is called. Otherwise, the isRemote will be false and the resetToLocalController is called.

  • protected void setupRemoteController()

    This method emits the event EventType.SET_MEDIA_CONTROLLER_CONFIG with the MediaControllerConfig object. We will talk more about MediaControllerConfig later in this section. This method also listens to the BrightcoveMediaController.CONTROL_BAR_CREATED event and reacts by calling the setupBrightcoveControlBar method.

  • protected void resetToLocalController()

    This method is responsible for resetting the BrightcoveMediaController to the original controller layout by emitting the EventType.RESTORE_DEFAULT_MEDIA_CONTROLLER.

  • protected void setupBrightcoveControlBar(BrightcoveControlBar controlBar)

    Once the BrightcoveMediaController has been recreated with the layout provided in the MediaControllerConfig, you will get access to the BrightcoveControlBar view. From here, you can access your UI views, like Buttons, where you can add OnClickListener's to them.

Set the MediaControllerConfig

The MediaControllerConfig is a configuration class that you can use to change the default control layout of the BrightcoveMediaController class. In this class, you can set the layout and the OnTouchListener. Once created and configured, you can emit this object as shown below:

Map<String, Object> properties = new HashMap<>();
properties.put(Event.MEDIA_CONTROLLER_CONFIG, myMediaControllerConfig);
eventEmitter.emit(EventType.SET_MEDIA_CONTROLLER_CONFIG,properties);

The default MediaControllerConfig object sets the R.layout.cast_media_controller as the layout with a single Play button. When clicked, it will open a dialog with two options:

  • Play Now - When selected, the loadMediaInfo() method is called and the video will load and play in Chromecast.
  • Add to Queue - When selected, the addMediaInfo() method is called and the video is added to the end of the queue.

Overwrite the control bar setup

When your media controller layout is set by emitting the MediaControllerConfig, the BrightcoveControlBar view will be created and the BrightcoveCastMediaManager.setupBrightcoveControlBar() method will be called. It’s here where you can get your UI components by Id and add the appropriate listeners.

@Override
protected void setupBrightcoveControlBar(BrightcoveControlBar controlBar) {
   Button playButton = controlBar.findViewById(R.id.cast_play);
   if (playButton != null) {
       playButton.setOnClickListener(new View.OnClickListener() {...});
   }
}

Cast plugin dependencies

The Cast plugin depends on the ExoPlayer Cast Extension:

compile 'com.google.android.exoplayer:extension-cast:2.7.0'

The extension have several dependencies which are listed in the table below:

Name Full notation and current version
Mediarouter v7 com.android.support:mediarouter-v7:27.0.0
Appcompat v7 com.android.support:appcompat-v7:27.0.0
Support v4 com.android.support:support-v4:27.0.0
Cast Framework com.google.android.gms:play-services-cast-framework:11.4.2
ExoPlayer Core com.google.android.exoplayer:exoplayer-core:2.7.0
ExoPlayer UI com.google.android.exoplayer:exoplayer-ui:2.7.0

Limitations

With the current Brightcove Native SDK for Android release, certain Video Cloud features have limited support, or are not supported when using the Cast plugin with the Google sample receiver app:

  • Captions
    • Only in-manifest captions with Dynamic Delivery DASH display as expected when using the Cast plugin with the Google sample receiver app.
    • In-manifest captions with HLS and Sidecar captions in any video configuration are not currently supported when using the Cast plugin with the Google sample receiver app.
  • Widevine Modular DRM is not supported when using the Cast plugin with the Google sample receiver app.
  • Multiple Audio Tracks are not supported when using the Cast plugin with the Google sample receiver app.
  • Client-side and Server-side Advertising is not supported when using the Cast plugin with the Google sample receiver app.
  • Live and Live DVR streams are not supported when using the Cast plugin with the Google sample receiver app.
  • Casting Offline Videos is not currently supported. When you download a video, the Source url is changed to point to a local file. If you then try casting that Video, the plugin will pick the local source but the Chromecast device will not be able to request the video.

Handling currently unsupported features

The Cast plugin is responsible for gathering MediaInfo data, such as video url, title, description, and poster image, and casting it to your connected Chromecast device. Note that successful playback of the Video and display of the metadata ultimately depends on the Application Receiver.

It is the developer's responsibility to evaluate the Application Receiver for what it supports, and its limitations. Therefore, the developer should implement UI elements that inform the user what can or can’t be cast. For example, if the Application Receiver does not support Videos with DRM or Ads, your Android app must handle these scenarios.

Known Issues

Android 9

When using Chromecast with Android 9, you will need to include a FOREGROUND_SERVICE permission. This allows the app to use notifications to control a casting session when the app is backgrounded and brought back to the foreground.

The uses-permission tag should be added to the app's AndroidManifest.xml file, as follows:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

Volume control

The volume control in the Cast dialog may not decrease all the way to zero on the sending device. When using the volume control in the Cast dialog, or the volume buttons on the sending device, the displayed volume level may jump back up slightly to show a non-zero value on the sender. However, the receiver will display a non-zero value. This is a behavior with the Google Cast dialog, and not within the Brightcove Android SDK.

Google Play services

The Casting connection may not be created if the sender’s Google Play Services version is not up to date. When the sender’s Google Play Services, in particular the Cast Services framework, are out of date, you may be unsuccessful in creating a Cast connection. This is remedied by updating the sender’s Google Play Services through the Google Play Store.