Android: Internet Radio App: Transistor

Table of Contents

I'm not the one to promote android apps usually, but here is a nice one that does exactly what I desire, and follows some sort of Unix philosophy.

Internet Radio - audio streaming - works nicely on all my GNU/Linux computers:

  • get a playlist or create a playlist from one or two streaming links
  • save it to some folder
  • open it with my favorite lightweight audio player (MOC here)

But this approach has always been a bit of a problem on app-centric Android, and my particular phone. Standard media players won't open remote streams. Why, is beyond me. Many Radio/streaming apps exist, but they all seem to insist on finding my radio stations for me, and usually default to 128kbps mp3 streams. Why, when i can often get 64kbps AAC which gives sufficient quality with half the bandwidth? Playing straight from the browser is cumbersome, and it does not continue playing in the background, i.e. when the phone is dark and in my pocket. Once I do get something to play there's often buffering problems: playback is fine for a while and then stops. It usually resumes when I switch the screen on, but sometimes not (in these cases I suspect that the server "has had enough of me" and kicked me out, and I have to re-initiate the connection, i.e. stop the stream completely and restart it).

Why is this so difficult even with dedicated radio apps? Maybe because I'm using a mobile broadband flatrate, and no wifi. And my phone does not have 4G, only 3G; throughput can be patchy. I use it while cycling, so moving from cell to cell constantly.
But it seems many apps assume that you don't use mobile broadband, instead constantly surf wifi networks, because everybody has a mobile data plan that is already used up for this month?
...really I just don't know. Android will never have the sort of transparency for me that GNU/Linux has.

Enter Transistor:

Transistor is a bare bones app for listening to radio programs over the internet. The app stores stations as files on your device's external storage. It currently understands streams encoded in MP3, AAC and Ogg/Opus(*).
Important note: This is an app of type BYOS ("bring your own station"). It does not feature any kind of built-in search option. You will have to manually add radio stations.
(...)
During Playback Transistor acquires a so called partial wake lock. That prevents the Android system to stop playback for power saving reasons.

AAC streaming? Why didn't I see this earlier? It's been around for a while. and it sounds like it's born from a unix philosophy: plain text files and folders, not intents and databases.

Long story short, it works. I've been using it for a few days with SomaFM's 64kbps streams (update March 2019: stll using it almost daily with all sorts of music and talk radio), and it's definitely much better. no more going to sleep, almost no dropouts, and very reasonable sound quality.

The UI is simple, usable. Just a list of stations, and once you click on one, a play/stop button. if the station supports it, it also shows currently playing song.

Caveat

Transistor wants .M3U playlists.

So, here's a gratuitous conversion script that will convert a PLS playlist to m3u and push the result to an android device of your choice:

sh
#!/bin/bash # convert (somafm's) pls playlists to m3u playlists. # a list of files as arguments. # output stored in temp folder in current dir. me="${0##*/}" folder="$me$(date +%s)" if ! mkdir -p "$folder"; then echo "Could not create output folder" exit 1 fi trap "rmdir $folder 2>/dev/null 1>&2" EXIT grep="$(which grep 2>/dev/null)" [[ "$grep" == "" ]] && echo "grep not found in PATH. Can't continue." && exit 1 # for pushing .m3us to android device with adb # if you don't want to use this, better comment it out completely # because adb takes a while to fire up. device="XXXXXXXXXXX" # find out your device number with 'adb devices' pushpath="/mnt/sdcard/Android/data/org.y20k.transistor/files/Collection/" adb="$(which adb 2>/dev/null)" if [[ "$adb" == "" ]]; then echo "adb not found in PATH." else if ! $adb devices | $grep "$device"; then adb="" echo "adb: device $device not found." fi fi for input in $@; do if [ -r "$input" ] && [[ "${input,,}" = *.pls ]]; then oldifs="$IFS" IFS=$'\n' file=( $($grep -E "File.?=" "$input") ) title=( $($grep -E "Title.?=" "$input") ) length=( $($grep -E "Length.?=" "$input") ) IFS="$oldifs" output="$folder/${input%.*}.m3u" echo "Converting $input to $output" echo -e "#EXTM3U" > "$output" for (( i=0 ; i<${#file[@]}; i++ )); do file*="${file*#*=}" # the file (url) is the most important bit - if that's missing, skip to the next array member if [[ "${file*}" != "" ]]; then title*="${title*#*: }" title*="${title*/ (*)/}" # if title is empty after cutting out some stuff, replace it with the file name (url) [[ "${title*}" == "" ]] && title*="${file*#http*://}" length*="${length*#*=}" # if length is empty, make it -1 [[ "${length*}" == "" ]] && length*="-1" echo -e "#EXTINF:${length*},${title*}\n${file*}" >> "$output" fi done [[ "$adb" != "" ]] && $adb push "$output" "$pushpath" else echo "File $input does not end in .pls or is not readable - skipping." fi done exit 0

save to ~/bin, make executable.
if you want adb push functionality, replace the device="XXXXXXXX" string with your device number (get it with 'adb devices').

Let's say you have all somafm stations in one folder and you want 64kbps stations only on your phone, like me - then connect your phone, and run the script like this:

pls2m3upush *64.pls

Let me know how it goes, i have only one phone for testing.