Implementation of Chromecast support for video player based on ExoPlayer
By: Piotr Kozlowski
Tags: Exoplayer, Videoplayer, Android, Chromecast

In this article, I’d like to present how to easily implement casting video to the Chromecast devices using ExoPlayer’s Cast Extension.

Casting

What’s casting?

Casting is simply streaming the content (e.g. videos or music) from your mobile device to the big screen (usually TV). Not all devices support this feature (especially older TVs) and here Chromecast devices come to the rescue.

Google Chromecast

Chromecast is a name for Google’s family of products that can easily add SmartTV features to your old TV. The only thing you have to do while turning your old TV device into Smart TV is to plug the Chromecast into your TV’s HDMI port and configure it using Google Home App.

Starting point

Let’s assume that we have a simple video player already implemented, which can look like the code below. I made this code sample as simple as possible because I want to focus on the topic at hand and leave architecture patterns, dependency injection approach, etc. up to you :)

I also assume that you’re somehow familiar with the ExoPlayer basics, so I won’t explain a lot at this stage.

Below you can see the ExoPlayer’s dependencies needed to be added.

And here there’s a layout file, where PlayerView is defined.

As you can see I use SimpleExoPlayer within the PlayerView class to implement a simple video player, which loads and plays video from provided URL. That’s pretty it. All actions like pausing, resuming, rewinding, and so on are provided out of the box, and we do not have to handle it on our side.

Casting implementation in the sample app

Thanks to ExoPlayer Cast Extension, the implementation of the casting functionality is easy and smooth.

At the beginning, we need to declare cast extension dependency in the build.gradle file. So our updated file should look like:

Next, we need to declare OptionProvider in the AndroidManifest file.

Note: Using the default provider will cause displaying the “ExoPlayer Default Receiver” text on the receiver app.

If you want to change it or make further customization of the receiver app’s UI, you should create your own custom OptionsProvider which should implement the OptionsProvider interface.

Now, we will add a MediaRouteButton to the activity layout file. That’s the button responsible for establishing or closing the casting session. Its states are handled automatically by the SDK, so you don’t have to worry about it.

At this step, I’ll introduce VideoPlayer class which is kind of a wrapper for SimpleExoPlayer (responsible for displaying video on the device) and CastPlayer (responsible for playing the video remotely on Chromecast).

As you can see, VideoPlayer has injected two instances of different players inside:

localPlayer, which is an instance of SimpleExoPlayer class, responsible for displaying the video on the mobile device,

class, responsible for displaying the video on the mobile device, castPlayer, which is an instance of CastPlayer, responsible for casting.

Both of them implement ExoPlayer’s Player interface. That’s why there is a variable currentPlayer that holds currently used player. By default, it’s set to localPlayer.

The most important code fragments of the snippet above are the following:

CastAvailabilityListener has two methods:

onCastSessionAvailable(), which is invoked when cast session (connection to the Chromecast device) is established,

onCastSessionUnavailable(), which is called when the session is finished.

When the session is available, and the callback is triggered, the castVideo() method is fired. It:

takes the current progress of the video from local player, as we want to continue casting the video from the same moment. assigns cast player to the current player variable. builds a media item via MediaItem.Builder and sets it to cast player.

When the user closes the casting session, the stopCasting() function is called − it fetches current progress from cast player, sets the local player as the current player, builds a media item, and plays it on local player.