RaspberryPi 4 in an Argon ONE case as DLNA renderer with output to a Teufel Cinebar One+ via USB
Table of Contents
This is my braindump on setting up:
- Raspbian GNU/Linux 11 (bullseye) on a Raspberry Pi 4 Model B
- housed in an Argon ONE case with power button and fan
- USB audio to a Teufel Cinebar One+
- Playing music via DLNA
My previous DLNA renderer (a Philips Fidelio A3) started to become unreliable a few months ago and this is what I have replaced it with.
Overview
This setup allows me to use a RasPi, a small µSD card for booting plus a USB attached sound bar to play music using DLNA.
The music files themselves are hosted on one (or more) DLNA servers.
Controlling the music happens via one (or more) DLNA controllers.
Hardware Used
- Raspberry Pi 4 Model B
- Argon ONE case, please note that the URL points to the v2 case. I seem to have v1 (mine has the tiny HDMI plugs, if I were to get a new one I would anyway prefer full size HDMI ports like the v2 offers)
- Teufel Cinebar One+ connected via USB
The RasPi and case I had already but it was not in active use. The Cinebar was primarily purchased to output sound of my main workstation (games and videos), but since it has multiple inputs giving it a second task was kinda obvious to me.
While the RasPi 4 I had at hand has 4 GiB RAM, using a 2 GiB model is fine too. And since my setup is currently on a 32-bit OS, I could also have used an older RasPi model.
The following was collected while it was playing a song;
root@raspberrypi:~# uptime
18:27:05 up 1:56, 3 users, load average: 0,17, 0,09, 0,07
root@raspberrypi:~# free -h
total used free shared buff/cache available
Mem: 3,7Gi 79Mi 3,4Gi 0,0Ki 232Mi 3,5Gi
Swap: 99Mi 0B 99Mi
RasPi to Cinebar Connection
Since the RasPi’s built-in audio does not have the best reputation, I connected the Cinebar to the RasPi via USB. The Cinebar’s AUX input is anyway currently connected to my main workstation.
NOTE: I did quickly try audio over HDMI from the RasPi to the Cinebar out of curiosity,
but the RasPi’s power LED stayed on when it was shut down but HDMI still wired.
Since I run the RasPi headless, planned to use USB, and I had no inclination to try a dozen hdmi_…
settings in /boot/config.txt
,
I saw no reason to look into RasPi ←HDMI→ Cinebar further.
Case Fan and Powerbutton Setup
The vendor of the case describes this in the article Argon ONE Pi 3 B+ Case Overview. The article also applies to their RasPi4 case.
Basically they recommend
pi@raspberrypi:~ $ curl https://download.argon40.com/argon1.sh | bash
You can do that if you feel brave (or stupid).
But since curl … | bash
is generally a bad idea, I do recommend you download the script and read it before running it.
Operating System Used
While I first had a try with Raspberry Pi OS (Lite) aka “Raspbian GNU/Linux 10 (buster)”, the repo http://raspbian.raspberrypi.org/raspbian/ buster
only gave me version 0.0.7-git of gmrender-resurrect.
With that old version I got no time elapsed in Bubble UpnP (my DLNA control point) and when stopping a track it would immediately restart playing. :-(
But, gmrender-resurrect 0.0.9 was released on 2021-01-21, So I saw no point in wasting time on debugging an older version.
I upgraded to Raspbian GNU/Linux 11 (bullseye). Mainly because that has the wanted version available in the repos and this RasPi’s only job is to be a small headless UPnP media renderer and for that I want the latest upstream code and the luxury of retrieving binaries from maintained repos instead of building from source.
Debian 10 → 11 is described in greater detail in the post How to Upgrade Debian 10 Buster to 11 Bullseye Linux, but I went for repos hosted at raspberrypi.org since my buster install was also using that.
I adjusted from buster to bullseye in 2 files
pi@raspberrypi:/usr/share/doc/python-apt-doc/examples $ cat /etc/apt/sources.list
# try to go from debian 10 (buster) to 11 (bullseye)
# pcfe, 2021-06-12
#deb http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi
deb http://raspbian.raspberrypi.org/raspbian/ bullseye main contrib non-free rpi
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi
pi@raspberrypi:/usr/share/doc/python-apt-doc/examples $ cat /etc/apt/sources.list.d/raspi.list
#deb http://archive.raspberrypi.org/debian/ buster main
deb http://archive.raspberrypi.org/debian/ bullseye main
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://archive.raspberrypi.org/debian/ buster main
And then ran the upgrade
pi@raspberrypi:~ $ sudo apt update
[...] check for errors
pi@raspberrypi:~ $ sudo apt full-upgrade
[...] be sure to do as told on stdout, Debian calls interactive scripts on some package updates
pi@raspberrypi:~ $ sudo reboot
If by the time you read this Raspbian GNU/Linux 11 (bullseye) is available as arm64 install image, obviously go for latest and for 64bit, everything that follows should still work.
Setup with Ansible
Many steps were taken from Playing music on a Raspberry Pi using UPnP and DLNA (v3).
Follow the above post if you are not comfortable with Ansible, it shows you how do the setup via bash. The only reason I used Ansible is because a RasPi, especially the µSD card is cattle, not pets to me. So if something breaks, I want to be able to plonk a new one in, run a playbook that configures Raspbian and listen again to music in the home office room.
Setup Notes
For the apt:
module to work (the package:
module calls it) I had to explicitly set
ansible_python_interpreter: /usr/bin/python3
With the default setting, the RasPi would try to run an autodetected /usr/bin/python3.7
and fail to import needed (and installed) python modules.
Playbook Used
On my Ansible control node, I simply ran:
ansible-playbook --inventory ../ansible-inventory-housenet/hosts type__entertainment_raspi_dlna__prepare.yml
The Playbook type__entertainment_raspi_dlna__prepare.yml
should be self explanatory and includes links to the various posts I consumed when settign this up.
Again, if you do not have a working ansible setup including an inventory,
then follow the steps from the URLs shown in the Playbook instead.
####################################################################################
# author: Patrick C. F. Ernzer <pcfe@pcfe.net>
# description: Prepares the RasPi 4B (in an Argon ONE case) connected to the Teufel Cinebar One+
# license: Creative Commons Attribution-ShareAlike 4.0 International License
# min_ansible_version: 2.9
####################################################################################
# hardware specs at:
# - https://teufel.de/cinebar-one-105396000 Teufel Cinebar One+
# - https://www.raspberrypi.org/products/raspberry-pi-4-model-b/ Raspberry Pi 4 Model B
# - https://www.argon40.com/learn/index.php/2020/03/10/argon-one-case-overview/ Argon ONE case
# 2021-06-12: had a armhf debian 10 (buster) that I pulled up to 11 (bullseye)
# as per https://www.how2shout.com/linux/how-to-upgrade-debain-10-buster-to-11-bullseye-linux/
---
- name: Ensure the Raspberry Pi 4 in the Argon ONE case is ready for DLNA renderer duties
hosts: raspi4b
become: yes
vars:
gmediarender_logging: false
ansible_python_interpreter: /usr/bin/python3
handlers:
- name: newaliases | run
command: newaliases
- name: gmediarender | restart
service:
name: gmediarender.service
state: restarted
tasks:
# enable persistent journal
- name: ensure persistent logging for the systemd journal is possible
file:
path: /var/log/journal
state: directory
owner: root
group: systemd-journal
# ensure the needed packages are installed
# Raspberry Pi OS (Lite) is "Raspbian GNU/Linux 10 (buster)"
- name: ensure wanted packages (that are not part of Raspberry Pi OS Lite Debian 10) are present
package:
name:
- gstreamer1.0-alsa
- python-apt
state: present
when: ansible_distribution == "Debian" and ansible_distribution_major_version == "10"
# Manually upgraded to Debian 11 (buster), specifically
# http://raspbian.raspberrypi.org/raspbian bullseye
# http://archive.raspberrypi.org/debian bullseye
- name: ensure wanted packages (that are not part of Raspian 11) are present
package:
name:
- gstreamer1.0-alsa
- python3-apt
state: present
when: ansible_distribution == "Debian" and ansible_distribution_major_version == "11"
- name: Ensure directory /home/pi/Downloads exists
file:
path: /home/pi/Downloads
state: directory
owner: pi
group: pi
mode: 0755
- name: ensure the Argon ONE software installer is downloaded
get_url:
url: https://download.argon40.com/argon1.sh
dest: /home/pi/Downloads/argon1.sh
checksum: "sha256:f4dcf4a845e4022156ee73e6a97df144962597add4fba1ea45280033e0023aed"
# USB audio, see all of the following links
# https://learn.adafruit.com/usb-audio-cards-with-a-raspberry-pi/updating-alsa-config
# https://raspberrypi.stackexchange.com/questions/80072/how-can-i-use-an-external-usb-sound-card-and-set-it-as-default
# https://cweiske.de/tagebuch/gmediarenderer.htm (gstreamer1.0-alsa needs installing)
#
# defaults.ctl.card 0 and defaults.pcm.card 0 need to be set to 1
# unless I disable the snd_bcm2835 audio, which I do not want to do.
# https://raspberrypi.stackexchange.com/questions/39928/unable-to-set-default-input-and-output-audio-device-on-raspberry-jessie
- name: ensure the default options snd-usb-audio index=-2 in /lib/modprobe.d/aliases.conf is overridden
lineinfile:
path: /lib/modprobe.d/aliases.conf
regexp: '^options snd-usb-audio '
line: 'options snd-usb-audio index=1'
- name: alsa.conf, ensure defaults.ctl.card 1 is set
lineinfile:
path: /usr/share/alsa/alsa.conf
regexp: '^defaults.ctl.card '
line: 'defaults.ctl.card 1'
- name: alsa.conf, ensure defaults.pcm.card 1 is set
lineinfile:
path: /usr/share/alsa/alsa.conf
regexp: '^defaults.pcm.card '
line: 'defaults.pcm.card 1'
# Now the steps from http://blog.scphillips.com/posts/2014/05/playing-music-on-a-raspberry-pi-using-upnp-and-dlna-v3/
# that are still applicable today (that post was with a way older Raspian release)
- name: ensure all updates are applied
package:
update_cache: yes
name: '*'
state: latest
tags: apply_errata
- name: ensure gmrender-resurrect is present, package name is gmediarender
package:
name: gmediarender
state: present
- name: ensure gmediarender has no ALSA_DEVICE set, it should use the gstreamer default an earlier task set
lineinfile:
path: /etc/default/gmediarender
regexp: '^ALSA_DEVICE'
state: absent
notify: gmediarender | restart
- name: ensure gmediarender has a more reasonable start volume of 50/100 than the default 75/100
lineinfile:
path: /etc/default/gmediarender
regexp: '^INITIAL_VOLUME_DB='
line: 'INITIAL_VOLUME_DB=-20'
notify: gmediarender | restart
# For logging on/off, use the variable gmediarender_logging (bool)
- name: Ensure directory /var/log/gmediarender exists
file:
path: /var/log/gmediarender
state: directory
owner: root
group: audio
mode: 0775
when: gmediarender_logging
- name: ensure gmediarender DOES have logging enabled
lineinfile:
path: /etc/default/gmediarender
regexp: '^DAEMON_EXTRA_ARGS='
insertafter: '^# DAEMON_EXTRA_ARGS='
line: 'DAEMON_EXTRA_ARGS="--logfile /var/log/gmediarender/gmediarender.log"'
notify: gmediarender | restart
when: gmediarender_logging
- name: ensure gmediarender does NOT have logging enabled
lineinfile:
path: /etc/default/gmediarender
regexp: '^DAEMON_EXTRA_ARGS='
insertafter: '^# DAEMON_EXTRA_ARGS='
line: '# DAEMON_EXTRA_ARGS="--logfile /var/log/gmediarender/gmediarender.log"'
notify: gmediarender | restart
when: not gmediarender_logging
- name: ensure gmediarender.service is enabled and started
service:
name: gmediarender.service
enabled: true
state: started
- name: check to see if we need a reboot, Debian style
stat:
path: /var/run/reboot-required
register: reboot_required_file
when: ansible_pkg_mgr == "apt"
- name: reboot RasPi if Debian style hint file is present
reboot:
when:
- reboot_required_file is defined
- reboot_required_file.stat.exists is defined
- reboot_required_file.stat.exists
Playing Music via DLNA
Obvious if you used DLNA before, but in case this is your first use of DLNA;
- If off, boot the RasPi by shortly pressing the power button on the case
- Ensure the Cinebar is on and set to Bluetooth input, LED is blue (USB and BT use the same input)
- Open your preferred DLNA control point on a device of your choice (on Android I use BubbleUPnP)
- select a media library of your choice (I use ReadyMedia (aka minidlna) on a Linux server)
- select your RasPi as renderer, by default it is called gmediarender on $(hostname)
- via your DLNA control point, you manage
- choice of song
- playlist (n.b. the playlist resides on your control point, not the renderer)
- volume
- play, pause, seek, stop, next/previous track
- cleanly shut down the RasPi by pressing the power button ≥ 3 (but < 5) seconds
Be patient when waiting for DLNA devices to appear, if your setup is suboptimal, wait easily 10 minutes or more for devices to appear.
Usage Notes
Ideally you would shut down both the RasPi and the Cinebar when not in use, to save some energy.
The Argon ONE case comes with a nice power button, use it (RTFM on Argon ONE Power Button Functions here). You will need to install their software for the button and fan to work as advertised.
Pressing the button for ≥ 5 seconds does a hard poweroff. Avoid doing that, prefer the clean shutown.
The Cinebar will enter low power mode (LED is red) by itself if no audio is played for a while.
UPnP Tweaks
Bubble offers finer control than many other control points I tried, and it even does it on a per renderer basis.
Currently I am trying Gapless control for this DLNA renderer. But having lived without gapless playback on many DLNA renderers, I am not going to sink a lot of thought on this.
For now I’m mainly happy that I have once again a DLNA renderer to listen to music without any hassle when I sit in my work room.
Update 2021-08-20; WLAN and BT off
As I use neither WLAN nor Bluetooth, those were switched off as follows in /boot/config.txt
;
# Disable WLAN and Bluetooth
# pcfe, 2021-08-20
dtoverlay=disable-bt
dtoverlay=disable-wifi
kudos to Robert G for the `disable-… overlays hint.
Update 2022-07-10; minor textual additions
- added an overview section
- attempted to clarify that you can but do not need to use Ansible to do this setup