ctx->guides->rpi-tv

Raspberry Pi console media center with TV remote on Arch Linux

This guide shows how to build a home entertainment system with the Raspberry Pi and Arch Linux on the console. I made this as a replacement to XBMC which I was using before for watching stuff; only this setup also integrates nicely with MPD for accessing our music fast!

Environment

Most TVs nowadays support the CEC (Consumer Electronics Control) capability through the HDMI connection. This lets us control other devices (such as the Raspberry Pi) using our remote. The available buttons for CEC on my TV remote control are: Up, Down, Left, Right, Select, Exit. The idea is to map those buttons to keyboard events using a libcec client and have programs configured to handle them. Previous versions of this guide were using the libcec-daemon client but we have now switched to ceckb which is simpler and easy to build natively:

https://git.2f30.org/ceckb/

At the moment of writing, the default configuration in config.h is this:

struct map bindings[] = {
    { CEC_USER_CONTROL_CODE_EXIT,    KEY_Q },
    { CEC_USER_CONTROL_CODE_SELECT,  KEY_ENTER },
    { CEC_USER_CONTROL_CODE_UP,      KEY_UP },
    { CEC_USER_CONTROL_CODE_DOWN,    KEY_DOWN },
    { CEC_USER_CONTROL_CODE_LEFT,    KEY_LEFT },
    { CEC_USER_CONTROL_CODE_RIGHT,   KEY_RIGHT },
};

And made the program start automatically as a service using our beloved init system.

/usr/local/lib/systemd/system/ceckb.service:

[Unit]
Description = libcec to uinput key event mapper
After = remote-fs.target

[Service]
User = root
Group = root
Type = simple
ExecStart = /home/tv/bin/ceckb
Restart = always

Note that similar results can be achieved using a LIRC setup. LIRC may be be a more flexible option simply because we'll probably have all buttons on the remote control to play with. We won't explore that here however.

So our keys now are:

Let's see the programs selection and their configuration.

The file browser

The other main component of this setup is the actual filesystem navigation. We will be using the noice file browser:

https://git.2f30.org/noice/

Build it with a custom config.h to match our available keys and file associations, using applications and wrapper scripts:

struct assoc assocs[] = {
    { "anime/.*\\.mkv$", "omxplayer-audio-stream-two" },
    { "\\.(avi|mp4|mkv)$", "omxplayer-wrapper" },
    { "\\.(mp3|ogg|flac|m4a)$", "mplayer" },
    { "\\.radio$", "mpc-add-from-file" },
    { ".*", "less" },
};

struct key bindings[] = {
    { 'q',        SEL_BACK },
    { KEY_ENTER,  SEL_GOIN },
    { KEY_DOWN,   SEL_NEXT },
    { KEY_UP,     SEL_PREV },
    { KEY_RIGHT,  SEL_PGDN },
    { KEY_LEFT,   SEL_PGUP },
};

Of course we can also retain all other key bindings and resort to the keyboard for operations that don't make sense to support from the remote control. With the wrappers we add functionality specific to our setup. For example using the mpc-add-from-file:

#!/bin/sh

cat $1 | mpc add

We can create files with the .radio extension that contain radio stream URLs and organise them like that. The action on them would add the stream to our running mpd queue. We'll see the omxplayer-wrapper in more detail later on.

Autostarting in file browser view

Create a local user, let's say tv:

$ useradd -m -g users -G audio,video tv

Create the script ~tv/bin/tv-shell:

#!/bin/sh

export PATH=$PATH:$HOME/bin
cd $HOME
noice menu/

Make this script the default shell for user tv by editing /etc/passwd.

And the menu will be the directory structure we will be navigating into using the remote control. The last part is to auto-login the tv user, and can be done with an init script like this.

/usr/local/lib/systemd/system/getty@tty1.service.d/autologin.conf:

[Service]
ExecStart=
ExecStart=-/usr/bin/agetty --autologin tv --noclear %I 38400 linux

The video player

Install omxplayer from packages and create the following files with the appropriate ownership and permissions.

~tv/bin/omxplayer-wrapper:

#!/bin/sh

args=
args="$args --font /usr/share/fonts/TTF/DejaVuSans-Bold.ttf"
args="$args --italic-font /usr/share/fonts/TTF/DejaVuSans-BoldOblique.ttf"
args="$args --align center"
args="$args --font-size 58"
args="$args --no-ghost-box --blank"

keyconf=~/.omxplayer/keys
test -f "$keyconf" && {
    args="$args --key-config $keyconf"
}

subs="${1%.*}.srt"
if test -f "$subs"; then
    omxplayer.bin $args --subtitle "$subs" "$1"
else
    omxplayer.bin $args "$1"
fi

~tv/.omxplayer/keys:

PAUSE: 
PAUSE:hex 0xa
SEEK_FORWARD_SMALL:right
SEEK_BACK_SMALL:left
SEEK_FORWARD_LARGE:up
SEEK_BACK_LARGE:down
EXIT:q

The wrapper script selects subtitle fonts and looks for SubRip subtitle files (under the same name ignoring the file extension), among other preferences. The other one specifies keybindings to match our remote control. Note that the first line is a Space key and the second one is the key code for the Enter key. You can use the showkey utility from the kbd package to identify key codes on the console.

Setup MPD over NFS

Create a link to our NFS mounted music directory:

$ ln -s /mnt/store/music /var/lib/mpd/music/master

We now create this configuration that uses the MPD database proxy plugin to receive metadata from a remote MPD instance instead of using it's local db file.

/etc/mpd.conf:

pid_file "/run/mpd/mpd.pid"
state_file "/var/lib/mpd/mpdstate"
playlist_directory "/home/tv/playlists"
music_directory "/var/lib/mpd/music"

database {
    plugin "proxy"
    host "store"
    port "6600"
}

input {
    plugin "curl"
}

audio_output {
    type            "alsa"
    name            "Speakers"
}

Care must be taken to have the file paths match in both our store host and here. In this setup all MPD file paths will start with master/. Another thing is that playlists are not handled by the database so we need to synchronise them manually. My choice is a private revision controlled playlists directory for that purpose.

Audio visualizer

We also build and install our console audio visualizer now:

https://git.2f30.org/nausea/

We need this to our /etc/mpd.conf:

audio_output {
    type            "fifo"
    name            "Pipe"
    path            "/tmp/audio.fifo"
    format          "44100:16:2"
}

Youtube

And if you need Youtube in your TV here is a Python package that deals with it:

$ pip2 install mps-youtube

To configure it to use our omxplayer wrapper script too:

$ mpsyt
> set player omxplayer-wrapper

And video is disabled by default, so enable it:

> set search_music false
> set show_video true

Note, however, that a keyboard will be needed for the searches here :)

The glue

Finally, under the ~tv/menu directory we will be creating simple scripts and symlinks to organise our media files.

$ ln -s /mnt/store/movies ~tv/menu/
$ ln -s /mnt/store/series ~tv/menu/

~tv/menu/music.sh:

#!/bin/sh

ncmpc

~tv/menu/music-off.sh:

#!/bin/sh

mpc stop

~tv/menu/nausea.sh:

#!/bin/sh

nausea -d 2

Font size

I've found that for my 32-inch 1366x768 native resolution TV, an 800x450 console resolution is acceptable for the characters to be legible. To change this edit /boot/config.txt:

framebuffer_width=800
framebuffer_height=450

Another option is to use a terminal emulator like fbterm. This way you get fontconfig and friends plus unicode support.

Cheers!

lostd@