DIY : Roll your own streaming music service with Kotlin – Ken Gilmer – Medium
Finally let’s add a little polish and handle our input parameters in a friendly way. Kotlin’s elvis operator gives us a concise way of expressing conditional execution based on something being null. In this case if the file path parameter is not specified let’s assume it’s the working directory of the program:
And let’s add a second parameter for the case in which the user wants to write to a file rather than stdout. In this case we utilize the fact that Kotlin’s
if is an expression that returns a value. This allows for the following construction:
And that should be all we need to generate our manifest file. Here is the final program:
Since our player uses HTTP to read the manifest and music files, we just need to add a HTTP server on a machine that our player can access. This might be a VPC or other server you have access to. We could just run an existing HTTP server like Apache but let’s see what we can do with Kotlin. Happily, Java 8 provides a built-in HTTP server that we can just customize to serve our music files. Rather than build this out line by line let’s spice it up and show the whole program and talk about the interesting parts:
There is a lot of code here, let’s break it down. The Sun HttpServer class and friends are doing the heavy lifting, we just customize for our usecase. We define the port and path that we listen on or provide defaults (lines 11–12). Next we construct an HttpServer and provide a callback in
createContext() from which we implement as a lambda to handle client requests (line 14–15). Within the lambda we try and resolve the request URI to a local file. If we find the file we send the bytes back to the client, otherwise return 404 (lines 15–26).
What’s left is a few functions that allow us to filter requests to determine validity. First we need to determine if the request itself is valid, so we check the method and make sure a user agent is specified:
Next we need to convert the user supplied path (as the request URI) to our local filesystem. The Google music player truncates part of the request path when making requests. We could change the client app but that would mean more Java changes in a code base we’d prefer to leave as-is. Perhaps it’s best just to deal with this in our server. So we need a way of removing an arbitrary number of path elements from the request when they overlap with the base path where our server runs from:
To be honest, there is too much code here for what it does but I have yet to find the more concise yet readable way of writing this function. Let me know if you have any ideas!
The last function simply looks to see if there is a local file that matches the request:
And that is our HTTP server. The nice thing about writing this code as opposed to using an existing HTTP server is that we can inspect and modify the behavior, and learn how it works!
If you’re intending on running the server you’ll need to run it such that it is publicly accessible (so that your phone can get to it.) You’ll want run it by specifying the path to the directory where the Manifest Generator script ran that produced the manifest of your music files. To test, you should be able to load
http://<your IP or URL>/music.json in a browser and see your music data.
Writing a mobile music player from scratch would be a major effort and probably not something to cover in a step-by-step detail. Instead we’re going to customize some existing open source software to do most of the heavy lifting. Google provides a sample music player that demonstrates integration with various services like Chromecast and Android Auto. This music player is intended as example code for other projects but it happens to be just usable enough to be the basis of our own Android music player. The player uses HTTP to get a manifest of music files in JSON format from a server. It loads this JSON into model instances and from there you can browse, search, and play the music as you would expect. Initially, all we need to do is change one line of code:
That’s right, just change the URL from Google’s server to the IP address or URL of wherever you are hosting your music on line 12. Then, simply build and install the APK onto your phone. Depending on how much music you have in your manifest, it may take some time to load. Once it does you should be able to see your tracks via the implemented browse by genre functionality or search for a specific track.
This post covered a lot of ground to get us to a basic but workable streaming music system in which we host our own music via HTTP and use Google’s music player demo to do the hard work. Once you get this working you’ll find a lot of things you’ll want to add or change. For example the player only let’s us browse by genre. And the generator program will only allow us to index MP3s with all of the required metadata as ID3 tags. And then of course there is security (access control). Nonetheless, there is a lot of functionality here for relatively little coding, and many interesting areas to explore to make it even better! All the programs covered in this post are available on Github.