Sunday, 22 June 2014

Using Google Chromecast from Delphi desktop application

I have done a small example of a desktop application, starting the YouTube app on the Chromecast device and playing a video on your TV. Using some Indy components and a couple of the new REST components that came with XE6. Not bothering with the API's from Google.


This example does not really have any real life usage - since installing Google cast in your Chrome browser or using the YouTube app on your phone would make more sense. So unless you for some reason don't use Chrome as a browser or do not have an iOS or Android phone, this example is not that useful - but it shows the concept.

And I think that the Chromecast is a nice $30 device, that like "almost" anything else can be accessed from Delphi :-D (Update: I might end up using Mozilla's cast device, if the rumors are true - see update at the end of post).

A little while back, I bought a Google Chromecast dongle - a nice inexpensive casting device for your TV, it has built-in support for Netflix, YouTube and various others.

Google does provide an API for iOS, Android and there is an extension for the Chrome browser.

I wanted to access the Chromecast from my desktop application, so a simple description of the protocol, would be more helpful, than digging into some API and converting this to my needs.

It seems that the Chromecast uses a form of DIAL protocol - using UDP to discover and TCP/REST to communicate.

A word of warning: this is a prof of concept - not ready for production or deployment - you need to do some work yourself to make it fit your needs. I have tried to use as little code as possible - leaving out all exception handling :-).

Start with a new Desktop application - could also be a mobile application, but since the mobile YouTube app already has support for Chromecast - it would make little sense :-).

Place a TIdUDPClient, a TIdHTTP, a TLabeledEdit, a TButton, a RESTClient and a RESTRequest component on the form - which all should end up looking a bit like this:


Part 1 - Chromecast discovery.

On the IdUDPClient we set the property BoundIP to the IP address of the PC you will run the application from. In a real application you would of cause get the IP by code - but making that both OS independent and handling multiple IP/Adapters - would add more that 2 lines of code :-). Also set the BroadcastEnabled and the Active properties to true.

On the onClick event of the button, add the following code to broadcast for dial-multiscreen devices:

  // DIAL Service Discovery
  IdUDPClient1.Send('239.255.255.250', 1900, 'M-SEARCH * HTTP/1.1' + #13#10 +
     'HOST: 239.255.255.250:1900' + #13#10 +
     'MAN: "ssdp:discover"'+ #13#10 +
     'MX: 3'+ #13#10 +
     'ST: urn:dial-multiscreen-org:service:dial:1'+ #13#10 +
  //   'ST: ssdp:all'+ #13#10 +
     #13#10);
  IdUDPClient1.ReceiveTimeout := 1000;
  r := IdUDPClient1.ReceiveString(ip, p);
  desc := '';
  if p<>0 then
  begin
    res := TStringList.Create;
    res.Text := r;
    for r in res do
    begin
      if Pos('LOCATION: ', r)=1 then
      begin
        desc := Copy(r, 11 , 9999);
        Break;
      end;
    end;
    res.Free;
  end;
  IdHTTP1.Get(desc);
  servURL := IdHTTP1.Response.RawHeaders.Values['Application-URL'];
  servURL := copy(servURL,1,Length(servURL)-1);  // DIAL REST Service URL

As you can see I only care for the first device that I get on my list of devices that response - but you can play around and see what other devices you can find using the SSDP protocol, using the commented ST: ssdp:all - and throw the response to a TMemo. The DIAL protocol used is explained in more detail here.

Part 2 - Start YouTube app and start video.

Now have the service URL, which is the address the Chromecast device responds to. We add the name of the app - here YouTube to the service URL to get the application URL. If the YouTube app responds, we post a REST request, adding the parameter of the unique id of the video - parsing the the YouTube URL in the TLabeledEdit to only get the unique id.

  // DIAL REST Service
  appURL := servURL+'/YouTube';
  IdHTTP1.Get(appURL);
  if (IdHTTP1.ResponseCode=200) then
  begin
    RESTRequest1.Resource := appURL;
    RESTRequest1.AddParameter('v', Copy(LabeledEdit1.Text, Pos('?v=', LabeledEdit1.Text)+3, 9999));
    RESTRequest1.Method := rmPOST;
    RESTRequest1.Execute;
  end;

Now you can sit back and enjoy the video on your big screen TV :-)

If you do want to dig deeper into the Chromecast - by making your own receiver and sender app - you have to look into the APIs and also get a cast appid from Google.

It would be nice if someone spend the time wrapping the API - for us Delphi/C++ users, or did an example of an mobile app and a receiver app :-)

Update.

It seems like Mozilla has been working on a similar casting device, that might not be that restricted as Google wants to make the Chromecast: http://gigaom.com/2014/06/20/this-firefox-os-powered-streaming-stick-is-mozillas-answer-to-chromecast-exclusive-video/

Links:

The source code: FoilcastClient.
DIAL homepage: http://www.dial-multiscreen.org/
UPnP related: http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf
Google Cast developer page: https://developers.google.com/cast/