XBMC on the Raspberry PI running ArchLinux

Finally after a very long time I’ve found the motivation to write a new post, yay :)

I’ve gotten myself a RPI a long long time ago with the primary target to use it as a htpc (Desktops are powerful, but also loud and power-hungry. ARM-SoC are the exact opposite.)
I’ve since used various setups to get the maximum performance out of this very nifty but also really slow device.
If you are a beginner and not that experienced with linux in general, I’d recommend Sam Nazarkos Raspbmc. Sam frequently adds new tweaks to the distribution and keeps the xbmc-builds updated.

But being an ArchLinux fanatic I just couldn’t stand the fact that there is an ArchLinuxARM version available for the Raspberry and not having it installed on mine. Also installing Arch-ARM is even easier than installing the ‘normal’ Arch (you just dd the image to the sd-card).
But after you have installed ‘xbmc-rbp’ from the repos you end up with a system that is too slow to play DTS tracks, doesn’t start xbmc at boot, has a slower GUI than raspbmc and boots slower than raspbmc. (You can fix the DTS-problem easily by using an AV-Receiver which does the DTS-Decoding, but as I don’t have such a device at the moment I had to find another solution…)
This is why im going to point out the modifications I’ve done to my system to make it as awesome as a £27.84 arm-development board could possibly be :)

Warning: I’ve noticed, that this post is still relevant and gets read a lot. I do not use my raspberry for xbmc anymore as I have bought a wandboard quad now (see some of the other posts here). Nearly all of the advice given in this blog is still totally valid, but the parts where I mention very specific build dates or versions should be taken with a grain of salt. Just keep in mind that most likely a lot has changed during those few months and the specific problems with specific versions I mention are most likely gone.

Changelog
20130707 – initial post.
20130816 – some updates, including kernel 3.10 and xbmc-rpb-git.
20130912 – updates to the f2fs section.
20130913 – updated python script.
20131020 – update f2fs section, added custom xbmc build
20131023 – added information about sqlite (see xbmc-rbp-git section)
20140125 – added notes about the wandboard

Overclocking
The most powerful and easiest solution to boost the performance is to run the device at a higher speed. In this post it even souns like if the Raspberry Foundation kinda ‘recommends’ overclocking. As far as I know (im not responsible for your raspberry overheating and creating another human-like species which threatens the life on our planet) there are no down-sides to the stability (provided you have a strong powersupply) or the lifetime of the device. (Using the this settings doesn’t even void your warranty).

All you have to do is include this snippet in your /boot/config.txt

arm_freq=1000
core_freq=500
sdram_freq=500
over_voltage=6
force_turbo=0

Using a modified version of memory-functions like memcpy
This is a library that implements standard system-functions like memcpy/memset/strcpy (and even more) in hand-written assembler. This improves general performance and made a noteable difference in playback-performance (at least for me).
On Arch-ARM all you have to do is install ‘arm-mem-git’ and reboot.

Using kernel 3.9 3.10 3.11 and f2fs
While f2fs does not affect playback performance (at least not over the network) it does greatly improve the booting-speed and speeds up the general performance.
F2FS (Flash-friendly FileSystem) is a file-system designed by Samsung specifically for flash-drives and is said to improve filesystem performance and is available since kernel 3.8.
To use it on the raspberry you have to install ‘linux-raspberrypi-latest’ and ‘linux-headers-raspberrypi-latest’ on the pi and then recreate your filesystems.
I did that on my archlinux-desktop (you have to use a recent kernel and have to have mkfs.f2fs, packaged in ‘f2fs-tools’). Just cp -a the contents of the /-partition to a temporary directory (don’t use a ntfs-volume, you’ll have to preserve the file-attributes), mkfs.f2fs on the partition and then cp -a it on the new filesystem. The only thing thats left to do now is to change the parameter “ext4” in /boot/cmdline.txt to “f2fs” and its going to boot off your new shiny f2fs.
Do not downgrade your kernel afterwards as 3.6 does not include f2fs.

Update: This does also work fine with kernel 3.10. Sadly, the current (3.10.6-1, 20130816) kernel does not boot on the raspi so you have to stick to 3.10.4-2 posted here. 3.10 does bring some changes to f2fs, the newest version of 3.10 (3.10.6) should also improve overall performance. Sadly its not available yet but it sure will be soon :)

Update: I’ve had some recent issues with f2fs like total corruption to the filesystem after a hardreset (On 3.10). I’ve therefore switched back to ext4 (you do notice the slower performance) :/ I have yet to try f2fs with 3.11.

Update: Back to f2fs, it just feels much faster, especially while navigating with the shell. I’ve not found anything to counter corruption, it seems to happen more or less randomly. I just keep a backup of my root-filesystem and write it over as soon as it corrupts :/

Use kernel-space nfs implementation with big buffers
While xbmc does have the feature to use nfs shares, I’d recommend using mount.nfs4 for maximum performance. I’ve played around with the values a bit and this is what my /etc/fstab looks like:

192.168.178.200:/media /media/ nfs4 ro,auto,rsize=32768,udp,noatime 0 0

Using udp and rsize=32768 gave me the best results in raw transfer performance.
Also, nfs uses less CPU than smb which frees capacity for those DTS-tracks

Update: I switched back to tcp because udp seems to be a bit unreliable, even over very reliable networks (around 2m cable distance, 1 gigabit switch). TCP is still fast enough to play the samples I am using.

Use xbmc-rbp-git
The newest versions of xbmc (Gotham alpha 7 or later builds or builds off the master-branch) include a sick patch for the dts decoder. According to the pull request, some guys hand-optimized the dts-decoder for the SoC of the raspberry in assembly which in turn runs 36% faster now! On archlinux, all you have to do is ‘pacman -S xbmc-rbp-git’.

According to the database table versions 12.2 and 13 alpha7 do not share the same database version, this means you should backup your .xbmc-folder in case you want to switch back later.

Update: xbmc-rbp-git has not been updated for a very long time (nearly 2 months now). I’ve chosen to compile my own build and got it working by modifyin the PKGBUILD slighty (issue is filed, info supplied to upstream) and im going to provide the binaries here!
You’ll have to download the tar file, extract it and install all the packages I’ve provided. The new firmware is necessary because xbmc relies on a never version of the userspace-libraries than the one which is provided in the repos (surely they will update it some time in the future…).
As always: back up your .xbmc folder :)

Update: I’ve submitted my changes to archlinux PKBUILDs master. The firmware was updated and xbmc should also be built but I’ve not been able to verify it yet).

Download:
20131019 – (xbmc at 37a0959099ce6589221c10097f2161558d1710ce, firmware at 4c1456944b5f6cc9e5141077ed4e158398811fc1)

Altough this build technically works, I’ve experienced some issues such as tv shows not being listed etc. I’ll provide a new build as soon as this changes :)
Update: According to the archlinux bug-tracker and the xbmc bug-tracke the problem with the library seems to be related the the 3.8.1 version of sqlite. As a workaround, you can downgrade to the previous version of sqlite until this is fixed.

Autostart xbmc and change governors on the fly
Most likely, you’ll want to have xbmc autostarted at boot, so you have to create a service for starting it.
I’ve added a small wrapper script and some python code to change the cpu-governor to RoundRobin and change the io scheduler of the xbmc performance as soon as you hit play.
The Round-Robin governor does improve the performance on playback, but decreases it if you want to browse through the library, thats why I decided to switch it on demand.
The python-script does only wirk with python 2.7, not with python 3 or higher.

The bash start-script does also stop policy-kit which uses a few megabytes of ram if its running. You can stop it and reboot/shutdown in xbmc still works, I’ve yet to discover any downsides.

I don’t know if changing the governor to performance is equivalent to force_turbo=1 which (if you used my overclocking settings) does void your warranty!. If you don’t want the script to change the governor, remove the appropriate lines in the python-file.

Im running xbmc as user ‘xbmc’ in ‘/home/xbmc’

#Start my pthon-script with 15 sec delay
(sleep 15 && python2.7 /home/xbmc/watchdog.py) &
#stop policy-kit after 15 sec
(sleep 15 && systemctl stop polkit) &
#Chmod the tty0 input, fixes problems with keyboard input in xbmc
chmod 0777 /dev/tty0
#start xbmc as user xbmc
su - xbmc -c "LD_LIBRARY_PATH=/opt/vc/lib/ xbmc-standalone"
#!/usr/bin/python2

# this script is supposed to connect to xbmc on port 9090 and wait for incoming event-notifications
# on the onPlay-Event it changes the xbmc-process-priority to 10 and its scheduler to SHED_RR. It also changes the cpu-governor to performance.
# on the onStop-Event it reverts the process-priority to its default state and changes the cpu-governor to ondemand.
#
# coded by CruX (crux@project-insanity.org)

import socket
import time
import subprocess

def countOpen (input):
        return input.count('{')

def countClose (input):
        return input.count('}')

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
elapsed = 0

def loop():
        pid = int(subprocess.check_output(["/bin/pidof", "xbmc.bin"]))
        print pid
        while True:
                opening = 0
                closing = 0
                s.setblocking(1)
                data = ""
                tmp = s.recv(8)
                if (tmp == ""):
                        break
                opening += countOpen(tmp)
                closing += countClose(tmp)
                data += tmp

                s.setblocking(0)
                while True:
                        tmp = bytearray(128)
                        count = s.recv_into(tmp, 128)
                        opening += countOpen(tmp[:count])
                        closing += countClose(tmp[:count])
                        data += tmp[:count].decode("utf-8")

                        if opening == closing:
                                break

                        time.sleep(.1)

                if (data.count("\"type\":\"movie\"") > 0 or data.count("\"type\":\"episode\"") > 0):
                        if (data.count("\"method\":\"Player.OnPlay\"") > 0):
                                subprocess.check_output(["/usr/bin/chrt", "-a", "-p", "10", str(pid)])
                                gov = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "w")
                                gov.write("performance")
                                gov.close()
                        elif (data.count("\"method\":\"Player.OnStop\"") > 0):
                                subprocess.check_output(["/usr/bin/chrt", "-a", "-o", "-p", "0", str(pid)])
                                gov = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "w")
                                gov.write("ondemand")
                                gov.close()
        s.close()

while elapsed < 120:
        try:
                s.connect(("127.0.0.1", 9090))
                loop()
                elapsed = 0
        except socket.error:
                time.sleep(1)
                elapsed += 1
[Unit]
Description = Starts instance of XBMC
After = remote-fs.target

[Service]
Type = simple
ExecStart = /bin/bash /home/xbmc/xbmc.sh
Restart = always

[Install]
WantedBy = multi-user.target

While you should definitely not start to learn python off this code, it does work as expected and I have no intents to refactor it :)

Update: I’ve been having some weird issues with xbmc-git lately where it does only listen on ipv6, not on ipv4 which means 127.0.0.1 doesn’t work there. You can see if xbmc sends its event via the socket by telnetting to 127.0.0.1:9090. If you get permission denied or similar, try ::1:9090. If it works change the address in the script aswell as the socket to AF_INET6.

Update: I’ve updated the script and fixed an issue where the script did not change governors if you playback a ‘episode’ rather than a ‘movie’. Earlier xbmc versions did not make a difference here.
Thinking about rewriting the whole thing in go, not sure what the benefits would be…

These modifications greatly increase booting speed, render the xbmc-ui useable and improve the playback-performance in xbmc. I’ve some mkv Files which are about 20g in size and have 3 different DTS-tracks at around 1500kbit/s and they play smoothly (played over nfs of course :))

I can’t remember any more modifications I applied, but if I find something else I’ll keep this post updated!
If you know of any other things I can do to improve performance, I’d be more than happy to read about them in the comments :)

💬 Are you interested in our work or have some questions? Join us in our public Signal chat pi crew 👋
🪙 If you like our work or want to supprot us, you can donate MobileCoins to our address.

Comments

  1. There are some problems with data loss on SD-Card when overclocking. The informations i found so far are not very reliable so i will not get into detail. If you encounter errors, you might return to default clockings and see if they return.

  2. You are right. I think that bug has been said to be fixed long ago but I’ve been experiencing it from time to time. All I can say it that those overclock-settings combined with the newest kernel and f2fs have worked great so far!
    No corruption!

  3. I suppose i give it another shot then, this time with your suggestions on f2fs. Perhaps that helps. If not my memory card might not be suited. Who knows

  4. Hallo,

    toller Artikel, vielen Dank dafür.
    Ich wollte das watchdog.py Script bei mir nun ebenfalls testen.
    So bald ich es aber starte, bekomme ich folgende Fehlermeldung:

    File “watchdog.py”, line 14
    return input.count(‘{‘)
    ^
    IndentationError: expected an indented block

    Können Sie mir da evtl. weiterhelfen?

    Gruß Saboti

  5. Danke für die Rückmeldung :)

    Ich merke, dass das Ganze mal wieder nur mit python2.7 läuft, ich werde das im Artikel ergänzen. Danke für den Hinweis.

    Grüße

  6. Hi,
    wollte nur kurz mitteilen das jetzt alles klappt bei mir. Danke nochmal für Deine Hilfe und das Script :-)

  7. Hallo,

    super Idee mit den verschiedenen Schedulern. Wenn das ganze nur mit python2.7 läuft, sollte dann nicht die Shebang #!/usr/bin/env python2 heißen?

    Gruß, Georg

  8. Hello,

    I am trying to get an xbmc install that will be able to transmit sound using a bluetooth dongle, so I can hook it up to a video projector while the sound system is in the other end of the room.

    I have been reading posts and it seems that Raspbmc, OpenElec, and Xbian are not able to do this (incompatibilities between alsa and xmbc on rpb).

    I am not familiarized with BT sound on Arch, and nothing in your post indicates that you do, but just in case, do you think that it worth trying to get BT audio to work with xmbx on Arch?

    Best,

  9. Hey there,

    as you suspected I have no knowledge about this topic but from what I could gather it seems to be a load of work.
    Normally you’d use alsa, but as explained here xbmc does use a close-source broadcom OpenMAX implementation because of the hardware-acceleration.
    There seems to be some progress over at raspbmc, you may want to try that.

    Other that that I have no clue but I wish you best of luck :)

    Greets

  10. Hi,

    how fast is the xbmc with arch arm? I tried Openelec and xbian, they are pretty fast and now want to try arch because I’m using it for years… but if its slow I’ll stay with openelec/xbian… Tnx :)

  11. Hey there,
    I don’t have a synthetic benchmark or anything like that to measure the difference, but I think there is a slight difference in UI speed and I am pretty sure that my installation is a bit smoother in playback for heavy files.
    Also you have to take the hassle of setting and maintaining the installation into account, you should be familiar with linux in general to do this.

    I for one think its worth it, but I guess you’ll have to find out on your own. (Just make a backup of your existing install and you’ll be fine :))

    Cheers

  12. Thanks. Being playing with Pi for two weeks, I’m a new user. Openelec flies, xbian is buggy, forward and rewind doesn’t work, you can’t power it off… Will try arch and raspbian, hope xbmc is stable enough. No hassle for me, I’ve been using arch for years on my two desktops :)

  13. Wow, it flies! It the speediest of them all :D I shuoldn’t doubt it, cause on desktop it also flies…

    Although there is something odd, I didn’t use your systemd service for xbmc, I just enabled it: “systemctl enable xbmc” – the one that comes with the package. But there is some bug, look at the processes:

    root 2631 336 0 19:54 pts/0 00:00:00 /bin/sh /usr/bin/xbmc-standalone
    root 2633 2631 0 19:54 pts/0 00:00:00 /bin/sh /usr/bin/xbmc –standalone
    root 2636 2633 82 19:54 pts/0 00:00:04 /usr/lib/xbmc/xbmc.bin –standalone

    This is when I execute only xbmc:
    root 2670 336 0 19:59 pts/0 00:00:00 /bin/sh /usr/bin/xbmc
    root 2673 2670 82 19:59 pts/0 00:00:04 /usr/lib/xbmc/xbmc.bin

    And this is when I execute only “xmbc –standalone”:
    root 2715 336 1 20:00 pts/0 00:00:00 /bin/sh /usr/bin/xbmc –standalone
    root 2718 2715 99 20:00 pts/0 00:00:01 /usr/lib/xbmc/xbmc.bin –standalone

    The systemd xbmc.service obviously adds one more process which introduce double keypresses on my remote…I’m using remote and CEC and every couple of presses are interpreted like double ones… Odd.
    So there is some bug in running “xbmc-standalone”, but not in just running “xbmc” or “xbmc –standalone”.

    Do you know maybe the difference between xbmc-standalone and xbmc –standalone or jsut xbmc?

  14. Hey again,

    Im sorry but I actually don’t know the difference. All I do is start xbmc via my service files (I named it xbmc2) and I’ve no issues with CEC (I use it very often).

    Good to hear you’re having positive experiences so far :)

    Cheers

  15. I will modify xbmx.service script to use “xbmc –standalone” instead “xbmc-standalone” ant that’s it :)

    I did install arm-mem-git ::)

    Best regards,
    Clouseau

  16. Hi,

    I’m not sure whether your current problems with the TV series not being listed properly is connected to the newer build.
    I think it’s related to some recent add-on update, since I’m experiencing the same problems with the version in the tree.

  17. Hey,

    good to know! Please keep me updated about this issue. Moonman merged my PR and xbmc-rbp-git should get updated in the repos soon.

    Cheers!

  18. Update on CEC problem. Everything is ok, even the stock xbmc.service. The problem is in priority of xbmc process. If I set it wiht nice on -12, no more double pressess of cec remote. So basically just install xbmc-rbp-git over stock arch arm image, give higher priority on xbmc process and you’re good to go :)

  19. Thanks a lot for this guide!
    The bug concerning sqlite-3.8.1 seems to be fixed as of now.

  20. Wow that was odd. I just wrote an extremely long comment but after I clicked submit my comment didn’t show up. Grrrr well I’m not writing all that over again. Anyway, just wanted to say superb blog! kkeeffaddfde

Leave a Reply

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