"It is no surprise to see Rich Internet Applications (RIAs) take the prize for technology of the year; however, seeing the open source project Mono 2.0 grab the honors for .NET tool is a surprise," stated Bradley Jones, Senior Executive Editor of Internet.com’s Developer Channel.

Moonshine is a project based on Moonlight that leverages the built-in Windows Media capabilities of Silverlight to bring Windows Media playback to Linux in a fully legitimate way, without forcing the end user worry about what a codec is. This is possible because Microsoft provides the codecs directly to all Moonlight users, regardless of their choice of Linux distribution.

Of course you’ll also need Moonlight installed. If you don’t have the
proper version installed, the Moonshine page will tell you.

On the Moonshine page, there is an XPI available to install for Firefox. You must have the latest Moonlight installed and Firefox 3.0 or newer. The Firefox shell that provides local media playback however is not part of the XPI. You must build Moonshine from source to have this feature. Packages will soon be available for openSUSE, and hopefully for other distributions soon.

Additionally, you must disable the Totem GMP/Windows Media plugin in Firefox, since it basically tells Firefox it can handle the same Windows Media mime types, even if the codec is not installed for GStreamer. It would be really great if Totem would only advertise mime types that GStreamer actually supports on a given user’s system.

Moonshine Overview

The project consists of three components:

A media player written in Silverlight/JavaScript that stands on its own.

A Firefox/NPAPI plugin written in C that claims support for Windows Media mime types and enables embedded playback of Windows Media on the web.

A Desktop Application that allows local playback of Windows Media content, implemented in JavaScript as a XUL overlay that re-purposes Firefox’s user interface to be more appropriate to media playback instead of web browsing.

If you do not care about the really technical details of Moonshine, I’d advise you to stop reading now, and just install Moonshine and try it out! If you’re interested in the details of my life over the last month, read on!

The Silverlight Application

The actual media player for Moonshine is implemented in Silverlight/JavaScript using my MTK widget library. MTK uses the basic approach in GTK for widgetry. Many of the base concepts are similar: size requisitioning, allocation, parenting, realization, etc. To write the Moonshine player, I basically implemented GObject, GtkWindow, GtkWidget, GtkContainer, GtkBox, GtkHBox, GtkVBox, GtkButton, GtkLabel, and GtkScale, hastily of course.

It was still a really entertaining hack: MtkObject for example contains a simple virtual method and event implementation, which greatly simplified writing widgets. JavaScript purists who know better than I will probably bash this though, screaming something about “but think of the prototypes!”

All this effort was necessary as unfortunately Silverlight 1.0 (which Moonlight currently targets) does not offer a toolkit – it really is just a glorified canvas/stage. When Moonlight 2.0 is released, the MTK side of Moonshine will go away, though it would be very interesting to re-target MTK from XAML to say, SVG. I would love to see someone try that, it should be relatively straightforward.

What’s interesting about the Silverlight player is that it works as an entirely standalone Silverlight application, suitable for embedding on any web page. Of course though my JavaScript is very specific to Firefox 3.0+ I assume, so that kills a little value there. Patches welcome.

The Firefox Plugin

Finally, Moonshine provides an NPAPI plugin that advertises it supports Windows Media to Firefox. When Firefox comes across said media, it loads the Moonshine plugin. Moonshine in turn loads Moonlight, and proxies NPAPI calls directly to Moonlight. Moonshine then injects the Silverlight JavaScript into the browser, and binds it to the Moonlight plugin instance. From the browser perspective, it’s Windows Media, but the real stuff under the hood is just pure unadulterated Moonlight, driving a standard Silverlight application.

Additionally, a further piece of JavaScript is bound to the plugin object that emulates pieces of the standard Windows Media ActiveX/object API for further compatibility.

The implementation details on the Moonshine plugin are a bit interesting:

Inside of NP_Initialize, Moonshine calls Moonlight’s NP_Intialize, and then overrides three NPP functions to be returned to the browser: NPP_New, NPP_StreamAsFile, and NPP_Destroy.

The NPP_StreamAsFile override simply prevents Moonlight from receiving that call, which would cause Moonlight to try to load WM content as XAML. The NPP_Destroy override just allows Moonshine to clean up its Moonlight binding on an instance, and then call’s Moonlight’s version of the function.

And finally, the juicy NPP_New override actually creates its own NPP_New call against Moonlight. All it sends to Moonlight is the width, height, and HTML DOM ID of the requested WM player, and sets the onload and source attributes on Moonlight to appropriate values for binding to the injected XAML/JavaScript player.

So this all means that Moonlight has absolutely no idea that the content its driving wasn’t hard coded in the web page. For all Moonlight is concerned, Moonshine is the browser. Plugins helping plugins, that’s what it’s all about.

And it all started as an extension

Moonshine was a really annoying project at first, and it took a while to come together. Most of the real progress and code that ultimately became Moonshine was written over the last two weeks.

Originally I wanted to avoid writing an NPAPI plugin and instead opted for writing a Firefox extension. What a mistake. I have learned way too much about Firefox and the Mozilla platform. It’s huge. But I must say, it was actually pretty pleasant to work with. Most APIs are pretty well documented. MDC is your friend, but a checkout of the Firefox source code is your better friend.

The mistake isn’t really the fault of the Mozilla platform, but a misunderstanding on my part of what I really needed to accomplish. My original version listened to the DOM, listened for new streams, etc. to intercept Windows Media mime types. This finally was working fairly well, but really was just a giant hack. I could not stomach the abuse I was causing inside the browser, and in no way was comfortable with releasing it.

However, the final nail in the extension approach was when I encountered web sites that actually check the plugin registry for a Windows Media plugin, and do not even create DOM content I could bind to if no plugin exists (ahh, gotta love the web). And of course the only way I could find to actually modify this registry was to be an NPAPI plugin.

So I threw away all of that code… about 1000 lines of JavaScript replaced with about a 1000 lines of C, an impressive trade-off — all things considered.

Going Forward, Looking Back

It’s been a very interesting few weeks, but I am so tired of working on this. I am aching to get back to Banshee. I do however want to make this work on the Mac under Microsoft’s own Silverlight. Or maybe someone out there can do it for me? It would be a fun hack!

Additionally, I am pretty interested in MTK, but can’t afford to work on it. I would be absolutely thrilled if someone would rebase the code on top of SVG. SVG needs a toolkit! It’s pretty pointless to continue working on MTK if it just targets XAML, since Silverlight 2.0 provides a toolkit. Any SVG/HTML5/Canvas enthusiasts out there are more than welcome to the MTK code. Keep me posted!

UPDATE: Last night I fixed a bug in Moonshine that prevented Moonlight from downloading the Windows Media codecs if you were running in plugin mode. If you experienced a “Bad address” error, please install the 0.2 XPI.