Dev Week 12

Screenshot of the podcast player web user interface.

The past two weeks, my main focus has been on my podcast/playlist app! It's received some serious improvements. The most important new functionality is that the audio plays directly in the webapp instead of on the server, so you can take it with you!

We could simply feed up the full audio file to the client, but this has several problems. If you had already listened to some of the episode and wanted to continue where you left off, and you were in a bandwidth-constrained environment (using mobile in a building that doesn't get good connection speed), it means you'd have to wait for the entire full-size file to download up to the point you had been listening before you could continue where you left off.

There are two primary technologies which support mobile-friendly streaming called HLS and DASH. I implemented HLS, but in writing up this blog post I realized HLS is Apple-specific. I'll be implementing support for DASH in a bit.

HLS and DASH both support capabilities that allow audio and video data to be streamed in chunks. This is what you see when you are watching a Youtube video and see the little loading bar load slightly past your current listening position, rather than loading the entire video. This makes it easier to jump around the episode, and also reduces bandwidth waste, especially if you end up not wanting to watch the whole video.

HLS and DASH also support streaming with an adaptive bitrate. This means that if your internet connection is very slow, the client (your phone or other device) can request the audio/video data at a lower bitrate, so it can continue streaming with low or no interruption, just at a lower quality.

Because the audio is streamed directly to the device, we were able to rip out all of the audio controls from both the client and the server. The server only has to serve up metadata and audio data, while the client has full control over playback and requesting the media chunks it needs as it needs them.

Another feature added is registration with your device's media controls so that you can use your OS-based player or headphones' media keys such as playpause, next/forward, and back/previous controls. This is called "Media Session" in web browser parlance.

A minor feature added is showing correct episode information on the page. The screenshot from the previous blog post (dev week 10) shows the episode's date and the url to the original media file; now it shows the episode number, actual title, and the description. Although m3u8 doesn't appear to directly support the concept of an "episode description", we're able to fit it into the metadata and then parse it out properly to include that data anyway. Now the date isn't showing, but we'll be adding that back in. That requires a few steps to get the date to propagate all the way through, but it's not difficult at all.

My main upcoming goal is to speed up the loading of audio. We managed to make it much faster and less buggy already by using a few tricks, primarily ensuring that different parts of the UI load on the client at the right times and stay loaded when they need to be; however, it's still too slow for my liking. In particular, if you use the arrow keys to switch between episodes too quickly (i.e. try to switch episodes twice in a row before the first one loads), the whole app will hang while your queued requests to the server get processed one-by-one. In particular, it loads the entire audio file of the switched-to episode, hanging the server and the client.

There are a few main next steps to support this.

The first one is to make the server asynchronous, which should be pretty straightforward, and would allow the server to provide metadata for the next episode even if it's still loading audio data for another episode.

One of the main problems slowing things down is that using the pydub python library for extracting the audio segments, it loads the entire audio file into memory before it can break it into chunks and serve them to the client. Perhaps pydub has a lazy-loading capability; otherwise we'll have to figure out another way to load chunks out of an audio file more quickly. Maybe even a secondary simple ffmpeg command that's used only if pydub hasn't finished loading the file into memory yet, so it can respond as quickly as possible, and use pydub for all subsequent requests when the audio has been loaded into memory. Either way, the goal is to make this very fast and user-friendly.

We have lots of other fantasies of features, for example, a listing of every episode where you can scroll through and click to switch between them arbitrarily. Right now the user must manually type a number into the box, which is especially unfriendly right now because of instant React re-renders (debouncing would improve this but I haven't done that yet), or click the "next" button and wait for each episode to load individually before being able to fully skip to the next-next-next one.

Right now this whole project is still a little bit toy-like, but for my slim use case, it's 100% usable and delightful. I'm excited to share that I've managed to reach episode 99 of Security Now!! I think I may have surpassed the point I had reached the last time I started listening from episode 1 around 2021, as I recently recognized some episode content but now it's less familiar. Also, right now, this week marks episode 999 and next week will be 1000!!!! Congratulations to Steve Gibson, Leo Laporte, TWiT, and the whole Security Now community!!

I'd love to hear feedback, especially if anyone has any feature requests or feature priority feedback. Feel free to post an issue on https://github.com/violet4/playlist_player/issues or go through my contact page and email me at the email address described there. Apologies to anyone who attempted to send me an email to the address that was listed there (which wasn't and still isn't valid); I had to delete that address a while back after receiving too much spam, and apparently never went in and replaced that address with a new working one. I also made a new PGP key and ensured all is working (I highly recommend kleopatra).

Thanks for joining us for Dev Week 12!

Posted in Dev

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.