Sunday, 1 March 2020

NymphCast: a casual attempt at an open alternative to ChromeCast and kin

For the past half year or thereabouts I have been working on a little project of mine that I call 'NymphCast' [1]. The initial idea for it originated at the beginning of 2019, when I found myself perplexed at the usability and compatibility issues that exist with streaming solutions like ChromeCast (Google proprietary) and AirPlay (Apple proprietary). Also how this was not improved much with PulseAudio (Linux-exclusive). It should be possible to have an open standard that would just work on any platform for streaming audio and video across a network.

First step was scraping together existing software solutions for handling the boring parts like shovelling bytes across the network and decoding and playing back audio and video. For the network communication part between server and client I was happy to use my own NymphRPC [2] remote procedure call library, as this provided the required functionality to transfer data between client and server in a light-weight library, which I also know to have been used in production environments. For the video and audio decoding, and the playback I settled on Ffmpeg [3] with LibSDL [4]. I also tried the gstreamer and LibVLC libraries, but could not make either of them work for the project.

It's interesting to essentially rebuild an existing system. The requirements for NymphCast were rather obvious: same as for ChromeCast, Roku and Amazon's dongle. That 'just' left implementing it. Playing back audio and video from a memory buffer and keeping that memory buffer filled while also allowing for efficient seek operations on the remote file gives one a lot of insight in where the bottlenecks lie on a computer and a network, but is mostly tedious work. Most of the work probably went into the other aspect of ChromeCast and kin: custom apps that add functionality, such as streaming from online services like YouTube, Netflix and SoundCloud.

Since ChromeCast's server solution (what runs on a ChromeCast dongle) is essentially a Chrome browser instance, these ChromeCast apps are simply HTML pages with JavaScript that get loaded from a remote server. Because NymphCast is a native C++ application it's free to use whatever approach it wants for NymphCast apps. Here I wanted a scripting language that's easy to integrate with C++ and both easy and powerful enough to be used for whatever such a custom app might require. Having embedded both Lua and Python in the past, I wanted something less clunky and ideally statically typed, which led me to AngelScript [5].

AngelScript has essentially C++ syntax and supports most C++ concepts directly, allowing it to be embedded in a C++ application without any jumping through hoops and with no overhead. What it also shares with C++ is that it is statically typed, meaning that when the script file is compiled, the AngelScript compiler will perform type and syntax checks, informing you where you made a mistake instead of the runtime throwing an error and bailing out while the app is running. I really appreciated this feature while developing the SoundCloud demonstration app.

As an aside, people have asked me over the past months why I didn't just implement the AirPlay or ChromeCast protocols (both of which have been more or less reverse engineered). The primary reason is that both are proprietary protocols which have been altered by the companies behind them and very likely will be changed again in the future. There is also limited use in supporting those protocols, as one isn't simply going to support ChromeCast apps or such, as these have been cryptographically locked away so unless you'll crack those AES or similar keys, it'd be at best a half-hearted kludge and a worst a massive waste of time and effort.

Considering that I managed to implement a basic SoundCloud NymphCast app within an hour using the public (HTTP) API, it would seem to me that it would be a more productive approach to get NymphCast into a state where I could contact SoundCloud and similar companies on whether they'd want to produce an official NymphCast app (hosted on their own servers) and thus get NymphCast on a level playing field with the competition, rather than acting like a trojan and constantly having to fix things whenever Google or Apple change something on their end. That's not the kind of 'competing' which I am into.

This leads me to the current state of NymphCast: I have used the NymphCast server on Windows, Linux x86 and Linux ARM on Raspberry Pi SBCs and other ARM-based SBCs. The client runs on all desktop platforms and on Android (Qt-based). While I would definitely call it Alpha-level software, with some features such as seeking support still being implemented, I am rapidly running out of missing features to implement. Leaving seeking support as one of the final features to implement for the first release was mostly because it is less essential than stabilising the other features.

One interesting thing which I have found during testing is that even if one were to never want to skip through an audio track or film, seeking support is still needed, as the MP4 container format for one has this nice feature where by default it puts the 'header' with the container details at the end of the file. This means that the player has to first seek to the end of the file, read the 'header', set the configuration, seek back to the file beginning and then start playing.

All taken together, this seeking support and some functions to get real-time playback information in the client are the only things that still need to be implemented before the first NymphCast release goes into Beta, meaning the shaking out of bugs and any other issues that may pop up during testing. Here I want to make it as easy as possible for people to help with testing, by providing an easy way to get NymphCast on a few supported platforms, such as the Raspberry Pi for the server, and for the client desktop platforms as well as Android devices. Compiling the client for iOS smartphones is harder, as this requires one to have a Mac system, which I do not, but this can be solved as well.

So what is it that I want to accomplish with NymphCast? Most of all to have a nice platform that I can use myself for streaming audio and video to any (powered) speakers and displays that I have standing around, along with the extensibility offered by NymphCast apps. I also hope that others will start using it, even adding NymphCast support to their (smartphone) apps. It would be wonderful to see private companies embrace it and release official apps that would allow people to use their services from NymphCast, cutting out proprietary ChromeCast, Airplay, Sonos and various SmartTV platforms.

The open nature of NymphCast (3-clause BSD licenced) is one big benefit, but also the ability to install the server on any Raspberry Pi board or equivalent without any hardware devices having to be produced, shipped, purchased and eventually tossed away, like the dongles for Google and Amazon's solutions, or entire speakers and devices as in the case of Sonos and Roku. NymphCast will work with any general purpose system, whether it is a Raspberry Pi, OrangePi, Intel NUC, some AMD APU-based board or a full-blown gaming PC.

Call me nuts, but I think that it might just be crazy enough to work.




Spiffelight said...

Very interesting! I've had issues with all of these, ChromeCast and AirPlay, what not. Looking forward seeing yours in action.

Take care!

SvenneK said...

Cool project.

I have also been looking for a chromecast (audio) alternative.

Do you have any support or plans for multi-device casting? I have multiple speakers, each with a ChromeCast Audio, that play in a group...


Maya Posch said...

@Spiffelight - Feel free to give the binary builds a try once the project enters beta stage. Shouldn't be very long now, I imagine :)

@SvenneK - Full network-based synchronisation of NymphCast instances is planned, yes, both in a client-server configuration (one client playing a file back on multiple servers) and in a peer-based configuration (multiple servers streaming the same content).

Unknown said...

Hi, how hard do you think it would be to implement screen mirroring for android and iphones on NymphCast ?

Bob Appleyard said... have some Mac's you can use to build stuff on. I think there is a free service available.

Ruben said...

Very nice project! For multiroom audio, I've been using which works well.
Maybe you can implement it for your multiroom audio part?

mfoltz said...

Hello Maya,

I'm the TL for Open Screen, which implements multi-device media protocols in Chrome.

Our PM forwarded me a link to your blog post, and your effort is very cool :-) I'll take a look at your GitHub repo. From the description, it sounds similar to what we call "remote playback", where one device has a media file in a containerized format, and wants to play it out on another device.

We have been working with Apple, Mozilla, and other companies to standardize a protocol for media streaming and device control. Although the implementation is not yet complete, we have a draft spec here.

Most of the complexity deals with authentication, and getting devices to agree on what format(s) they understand. Our open source library is written in C++, and if you want to learn more (or contribute!) I'm happy to share more details.