MediaTomb and BBC/Playlist Radio Streams

Well for a while now I have been using MediaTomb as a mediaserver, serving content to my PS3. Aside from the restricted set of mimetypes supported by the PS3 all has been working well.

I recently decided that it was a good idea to start getting Internet radio to stream as well. I had other devices handling this before, but if I could combine these all into one then, all would be good. I had checked the MediaTomb forums (here) for this and although there were many topics around transcoding they didn’t seem to fit my need.

The problem is that the streams for BBC change regularly. There is however a static URL to a playlist that will generate the necessary links. I have posted a resolution to this in the MediaTomb forums (here) but have since then enhanced the script and config.xml to be more generic.

So, here goes with the details…

  • Track down the URL for the stream (I have found the following site useful for that: www.radiofeeds.co.uk
  • Create an External Link (URL) item in the MediaTomb web interface
    MediaTomb External Link (URL)
  • Ensure that transcoding is enabled in the config.xml
  • Update the mimetype-profile-mappings section to include the following:

    <transcode mimetype="audio/x-plsradio" using="pls2pcm"/>

  • In the profiles section add:

        <profile name="pls2pcm" enabled="yes" type="external">
          <mimetype>audio/L16</mimetype>
          <first-resource>yes</first-resource>
          <accept-url>yes</accept-url>
          <sample-frequency>44100</sample-frequency>
          <audio-channels>2</audio-channels>
          <hide-original-resource>yes</hide-original-resource>
          <agent command="/scripts/mediatomb-transcode.sh" arguments="-f transcode_playlist_to_pcm -i %in -o %out -t pls"/>
          <buffer size="1048576" chunk-size="4096" fill-size="1024"/>
        </profile>
      

  • Now, this will instruct MediaTomb to invoke the /scripts/mediatomb-transcode.sh script file when the audio/x-plsradio mimetype is encountered. So let’s have a look at what is in the script shall we…

    All comments have been removed from the displayed version, the fully commented version can be downloaded from here

    The script essentially downloads the specified playlist to a temporary location and based upon the -t argument parsed in will process accordingly. Playlist processing is very rudimentary but seems to hold up against all of the playlists I have tried.

    #!/bin/bash
    display_usage() {
    
      USAGE="
      Usage:
        mediatomb-transcode -f function_name -i input -o output [function_arguments]
    
      Generic Options:
       -h, --help                  Display this help message.
       -i, --input                 Input file that is meant to be transcoded.
       -o, --output                Output file that will be read back by MediaTomb.
       -f, --func                  Function to execute from the script.
      "
      echo "${USAGE}"
      echo "Available Functions:"
      FUNCTIONS=($(compgen -A function | grep "^transcode_*"))
      printf " %s\n" "${FUNCTIONS[@]}"
      exit 1
    
    }
    
    transcode_to_pcm() {
    
      PROG=$(which avconv)
      if [ -z "$PROG" ]; then
        PROG=$(which ffmpeg)
      fi
      if [ -n "$PROG" ]; then
        exec "$PROG" -i "$1" -ac 2 -ar 44100 -y -f s16be "$2"
      fi
    
    }
    
    transcode_playlist_to_pcm() {
    
      INPUT=$1
      OUT_FILE=/tmp/playlist.tmp
      wget -q -O $OUT_FILE $INPUT
      if [ $? -eq 0 ]; then
        PLAYLIST_TYPE=${FUNC_ARGS["-t"],,}
        case "$PLAYLIST_TYPE" in
          "asx")
            RADIO_URL=$(grep -iE "^([[:space:]]*)<ref href.*=" $OUT_FILE | head -n 1 | tr -d '\"')
            RADIO_URL=${RADIO_URL#*=}
            RADIO_URL=${RADIO_URL//'/>'/}
            ;;
          "pls")
            RADIO_URL=$(grep -i "^file.*=" $OUT_FILE | head -n 1)
            RADIO_URL=${RADIO_URL#*=}
            ;;
          "m3u")
            LINE=$(head -n 1 $OUT_FILE)
            if [ "$LINE" == "#EXTM3U" ]; then
              RADIO_URL=$(grep -viE "(^#EXT|^$)" $OUT_FILE | head -n 1)
            else #normal m3u
              RADIO_URL=$LINE
            fi
            ;;
          *)
            echo "Invalid playlist type provided ($PLAYLIST_TYPE)"
            exit 1
            ;;
        esac
        if [ -a $OUT_FILE ]; then
          rm $OUT_FILE
        fi
        if [ "$RADIO_URL" != "" ]; then
          RADIO_URL=$(echo $RADIO_URL | tr -d '\r')
          transcode_to_pcm "$RADIO_URL" "$2"
        fi
      fi
    }
    
    declare -A FUNC_ARGS
    while [ "$#" -gt "0" ]
    do
      case "$1" in
          -f|--func)
            FUNCTION=$2
            shift; shift;
            ;;
          -i|--input)
            INPUT=$2
            shift; shift;
            ;;
          -o|--output)
            OUTPUT=$2
            shift; shift;
            ;;
          -h|--help)
            display_usage
            ;;
          *)
            FUNC_ARGS+=([$1]="$2")
            shift; shift;
            ;;
      esac
    done
    
    if [[ "$FUNCTION" != "" && "$INPUT" != "" && "$OUTPUT" != "" ]] ; then
      ${FUNCTION} "$INPUT" "$OUTPUT"
    else
      display_usage
    fi