# ChromeCast Home Media Server: Xamarin.iOS FTW!

As I blogged about last weekend, I got a ChromeCast and had a simple-enough time creating an iOS-binding library for Xamarin.iOS, allowing me to program the ChromeCast in C# (or F#, maybe next weekend…).

This weekend, I wrote a simple Home Media Server that allows me to stream… well, all my ChromeCast-compatible media, primarily mp4s. Here's how I did it…

ChromeCast Programming: Intro

Essentially the ChromeCast is nothing but a Chrome browser on your TV. If you want to display HTML, no problem, but what you probably want to display is a great big video div:

<video id="vid" style="position:absolute;top:100;left:0;height:80%;width:100%">

But where does this HTML come from? Here's the first kind-of-bummer about ChromeCast: Every ChromeCast application is associated with a GUID that Google provides you. Google maintains a map of GUID->URLs. And, since you have to send them your ChromeCast serial to get a GUID, it's a safe bet they check the hardware, too. When you start an application with: session.StartSessionWithApplication("93d43262-ffff-ffff-ffff-fff9f0766cc1"), the ChromeCast always loads the associated URL (in my case, "http://10.0.1.35/XamCast"):

So, as a prerequisite, you need:

  • A ChromeCast that's been "whitelisted" for development by Google;
  • A Google-supplied GUID that maps to a URL on your home network (a URL you decided during the "whitelist" application to Google)
  • A WebServer at that URL

It's important to realize that what's at that URL is not your media, but your "receiver app": which might be plain HTML but which is likely to be HTML with some JavaScript using the ChromeCast Receiver API that allows you to manipulate things like volume and playback position, etc. I basically just use this file from Google's demo, with minor tweaks.

Home Media Server : Intro

So if you want to stream your home media, you need a WebServer configured to serve your media. This doesn't have to be the same as your App Server (it probably will be, but conceptually it doesn't have to be):

The structure is straightforward:

  1. The mobile controller gets a list of media from the Media Server
  2. The application user selects a piece of media
  3. The controller sends the selected URL (and other data) to the ChromeCast
  4. The ChromeCast loads the media-URL from the Media Server

For me, the "App Server" and "Media Server" are the same thing: an Apache instance running on my desktop Mac.

ChromeCast Media-Serving : Components and Life-Cycle

This is a rough sequence diagram showing the steps in getting a piece of media playing on the ChromeCast using the Xamarin.iOS binding:

  1. Initialization
    1. Create a GCKContext;
    2. Create a GCKDeviceManager, passing the GCKContext;
    3. Create a GCKDeviceManagerListener; hand it to the GCKDeviceManager;
    4. Call GCKDeviceManager.StartScan
  2. Configuring a session
    1. When GCKDeviceManagerListener.CameOnline is called…
    2. Create a GCKApplicationSession;
    3. Create a GCKSessionDelegate, passing the GCKApplicationSession
  3. Playing media
    1. After GCKSessionDelegate.ApplicationSessionDidStart is called…
    2. Create a GCKMediaProtocolMessageStream;
    3. Get the Channel property of the GCKApplicationSession (type GCKApplicationChannel);
    4. Attach the GCKMediaProtocolMessageStream to the GCKApplicationChannel
    5. Create a GCKContentMetadata with the selected media's URL
    6. Call GCKMediaProtocolMessageStream.LoadMediaWithContentId, passing in the GCKContentMetadata

Here's the core code:

public override void ApplicationSessionDidStart()
{
    var channel = session.Channel; 
    if(channel == null)
    {
        Console.WriteLine("Channel is null");
    }
    else
    {
        Console.WriteLine("We have a channel");
        mpms = new GCKMediaProtocolMessageStream();
        Console.WriteLine("Initiated ramp");
        channel.AttachMessageStream(mpms);

        LoadMedia();
    }
}

private void LoadMedia()
{
    Console.WriteLine("Loading media...");
    var mediaUrl = Media.Url;
    var mediaContentId = mediaUrl.ToString();
    var dict = new NSDictionary();
    var mData = new GCKContentMetadata(Media.Title, Media.ThumbnailUrl, dict);

    Console.WriteLine(mData);
    var cmd = mpms.LoadMediaWithContentID(mediaContentId, mData, true);
    Console.WriteLine("Command executed?  " + cmd);
}

Plans

The core of a real home media server for the ChromeCast is the Web Server and the UI of the mobile application that browses it and chooses media. To turn this hack into a turnkey solution, you'd need to:

  • Run a public Chromecast application server that
    • Deferred the URL of the media server to the client
  • Write the media server, with all the necessary admin
  • Write a nice client app, that stored the mapping between the public ChromeCast app server and the (strictly-local) media server
  • Make a great user interface for selecting media
  • Make a great user interface for controlling the media

I have no plans on doing any of that stuff. What I plan on doing once ChromeCast and iOS 7 are out of beta is:

  • Make a nicer binding of the ChromeCast API and put it up for free on the Xamarin Component Store; and
  • Play around with serving media and blogging about anything interesting that comes up

Conclusion

The real thing that I wanted to do was see if Xamarin.iOS worked well with ChromeCast (resounding "Yes!") and come up with a hack for my own use.

Achievement Unlocked.