Google Cast SDK released

Google Cast SDK released
mars 14, 2014 erik.lupander@squeed.com

Back in the autumn of 2013 I wrote a series of blog posts about how to develop software for Googles Chromecast device. Those blog posts were based on the beta / preview SDK and when Google finally released the final SDK there were many changes to API:s and development environment setup.

In this blog post, I will outline some of the changes and direct would-be chromecasters to updated samples from Google.

Business Changes, Whitelisting etc

Thankfully, the Whitelisting is no more – instead you now pay $5 to get access to your very own Google Cast SDK Developer Console where you can register Chromecast serial numbers for development use, create your own applications and yourself choose when to publish them. As far as I can tell, Google does not have any kind of ”screening” or validation process for Google Cast applications – mine were pushed into the Chromecast Lookup tables and working within 15 minutes.

A new requirement on published receiver applications is that they _must_ be served from a trusted HTTPS address.

—- Android Sender changes —-

There are major changes to how you develop and write your Android-based Sender applications. See below.

Android Support Libraries

Creating an Android Sender application still requires a number of Android libraries with a somewhat tedious setup process for the Eclipse-based IDE. The main difference is that there is no standalone GoogleCastApi’s jar file anymore – all the Google Cast stuff is now part of the Google Play Services add-on library which needs to be added to your IDE and/or Gradle-based command-line builds. The appcompat and mediarouter libraries are still required to successfully develop and build Android Cast Sender applications.

Media Router and Cast API change examples

The Media Router and Cast API’s has undergone a number of changes that also affects how the Android Activity that interfaces with the MediaRouter should be coded. Well – the changes are so extensive that I would recommend starting over from some sample code rather than refactoring legacy pre-final SDK code. But a short summary might be in order.

The first difference is that the Activity shouldn’t implement the MediaRouteAdapter interface anymore. Actually, it seems as the MediaRouteAdapter interface has been removed altogether from the SDK.

Initializing the MediaRouter has changed somewhat:

// Preview SDK
mMediaRouter = MediaRouter.getInstance(getApplicationContext());
mMediaRouteSelector = MediaRouteHelper.buildMediaRouteSelector(
                MediaRouteHelper.CATEGORY_CAST, APP_NAME, null);
// 1.0 SDK
mMediaRouter = MediaRouter.getInstance(getApplicationContext());
mMediaRouteSelector = new MediaRouteSelector.Builder().addControlCategory(
CastMediaControlIntent.categoryForCast(APP_KEY)).build();

Another difference is how the onRouteSelected callback should invoke the necessary code to interface with the Google Cast API.

// Preview SDK
private void onRouteSelected(MediaRouter.RouteInfo route) {
        MediaRouteHelper.requestCastDeviceForRoute(route);
    }
// 1.0 SDK
public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo route) {
    mSelectedDevice = CastDevice.getFromBundle(route.getExtras());
    launchReceiver();
}

In the preview SDK, the invocation of the static requestCastDeviceForRoute method transparently did some stuff behind the scenes and the onDeviceAvailable callback was invoked, which in it’s turn called our setSelectedDevice method:

   // Preview SDK
   private void setSelectedDevice(CastDevice device) {

        mSelectedDevice = device;

        if (mSelectedDevice != null) {
         Log.i(TAG, "ENTER - setSelectedDevice: " + device.toString());
            mSession = new ApplicationSession(mCastContext, mSelectedDevice);
            mSession.setListener(mSessionListener);

            try {
                mSession.startSession(APP_NAME);
                mInfoView.setText("Session started!");
            } catch (IOException e) {
                Log.e(TAG, "Failed to open a session", e);
                mInfoView.setText("Failed to open a session");
            }
        } else {
            endSession();
        }
    }

In the final SDK, we directly call our ”launchReceiver” method in the Activity that performs the actual Google Cast stuff.

// 1.0 SDK
private void launchReceiver() {
    try {
        mCastListener = new Cast.Listener() {

            @Override
            public void onApplicationDisconnected(int errorCode) {
                teardown();
            }
        };
        // Connect to Google Play services
        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();
    } catch (Exception e) {
         Log.e(TAG, "Failed launchReceiver", e);
    }
}

While the code above is a bit too complex to go through in detail in this context, it is clearly visible that the actual Google Cast API’s are fundamentally changed. A lot goes on with the Cast class and the Cast.CastApi interface which I recommend as starting points for Google Cast API familiarization for Android development.

Messaging Protocol

In the Preview SDK, one would establish the messaging protocol between the sender and receiver through subclassing of a ‘com.google.cast.MessageStream’ base class. This implementation would declare your own API for bi-directional communication through onMessage callbacks and sendMessage provided by the superclass.

Well – as you might have suspected by now – things have changed and the com.google.cast.MessageStream is no more. The interface is not present anymore. Instead, the 1.0 SDK lets you send messages once everything is connected thorugh the Cast.CastApi.sendMessage method. An example use of this method could be something like this:

// 1.0 SDK
Cast.CastApi.sendMessage(mApiClient, MY_NAMESPACE, "{\"msg\",\"My JSON Message\"}");

To consume messages, you attach a CallbackListener through the Cast.CastApi interface:

// 1.0 SDK
Cast.CastApi.setMessageReceivedCallbacks(mApiClient, myChannel.getNamespace(), myChannel);

Where myChannel is an implementation of the MessageReceivedCallback interface that declares an onMessageReceived method that’s invoked by the Cast framework when the receiver sends a message to the sender.

Android Sender – what hasn’t changed?

Well – a very legitimate question if you’ve read this far. One should note that the overall programming model remains unchanged – it’s more or less the same basic mechanics but with changes API:s. For example, the old ‘MessageStream’ stuff have been replaced by the pretty similar ‘MessageReceivedCallback’ abstraction etc.

—- Receiver Changes —-

On the other side of cast ecosystem we have the HTML/JS/CSS based receiver apps. In my very humble opinion, the changes on this side are definitely for the better with lower complexity and more ease-of-use.

First of all – the javascript to include is changed:

// Preview SDK
https://www.gstatic.com/cast/js/receiver/1.0/cast_receiver.js

// 1.0 SDK
https://www.gstatic.com/cast/sdk/libs/receiver/2.0.0/cast_receiver.js

Furthermore, the actual boilerplate code is more compact and easier to work with now. The first example below is from my now defunct HipstaCaster demo application:

// Preview SDK
var chromecastApp = new cast.receiver.Receiver("fc91668a-cf4b-4a18-9611-f2c120d0bf07_1",
 [ cast.HipstaCaster.PROTOCOL ], "", 5);

window.hipstacaster = new cast.HipstaCaster();
window.hipstacaster.mChannelHandler.addChannelFactory(
                    chromecastApp.createChannelFactory(cast.HipstaCaster.PROTOCOL));
chromecastApp.start();

Then, you had to add a lot of boilerplate stuff to your equiv of the cast.HipstaCaster object above. For 1.0, I think the code is much cleaner and easier to work with. It may in part be due to my javascript coding skills – though both the above and below examples are based on Google’s own demo applications.

// 1.0 SDK
window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
window.castReceiverManager.onSenderDisconnected = function (event) {
    if (window.castReceiverManager.getSenders().length == 0) {
        window.close();
    }
};

window.messageBus =
window.castReceiverManager.getCastMessageBus('urn:x-cast:com.squeed.myapp');
window.messageBus.onMessage = function (event) {
      // Messages are received here. The 'event' is the actual (JSON) payload
}
window.castReceiverManager.start({statusText: "Application is starting"});

// Send example
window.messageBus.send(senderId, 'READY!');

The receiver application API’s have been beefed up with quite a lot of new changes and Google are continuously adding more features such as the new Media Player library to support various content streaming technologies such as HTTP Live Streaming (HLS), MPEG-DASH, and Smooth Streaming as well as a number of DRM technologies required by content suppliers serving commercial class content. Keep an eye on the Google Cast Release Notes to stay up to date with what’s happening with the SDK.

This concludes this update on the Chromecast SDK. I will not update the HipstaCaster samples to work with the new SDK. Instead, I’m planning on releasing something brand new for interested readers to have a look at. Watch this space…

0 Kommentarer

Lämna ett svar

E-postadressen publiceras inte. Obligatoriska fält är märkta *

*

Denna webbplats använder Akismet för att minska skräppost. Lär dig hur din kommentardata bearbetas.