\documentclass{report} \author{xengineering} \title{soundbox documentation} \usepackage{graphicx} \graphicspath{ {./diagrams/} } \usepackage{hyperref} \usepackage{parskip} \begin{document} \maketitle \newpage \tableofcontents \newpage \listoffigures \newpage \chapter{Introduction} \label{chap:introduction} \texttt{soundbox} is a device to connect classic audio systems to the network. \section{Versioning} This device is versioned with Semantic Versioning\footnote{\href{https://semver.org}{https://semver.org}}. The resulting version numbers have the format \texttt{..} like e.g. \texttt{2.0.3}. While Semantic Versioning is usually targeted at software only it is here used for the whole device. This includes mechanical, electronic and software aspects as shown in figure \ref{diagram:device-semver}. \begin{figure}[h] \centering \includegraphics[width=\textwidth]{device-semver.pdf} \caption{API for a device versioned with Semantic Versioning} \label{diagram:device-semver} \end{figure} This versioning makes sure that users do not have to care about the device internals at all. Devices can be seen as atomic from a user's perspective. This level of granularity is choosen because users are not expected to disassemble devices or to care about the software internals. %\section{Licensing} \chapter{User guide} In addition to \autoref{chap:introduction} `\nameref{chap:introduction}` the following sections document everything required to use \texttt{soundbox} devices. \section{Discover soundbox IP address} If the IP address of the soundbox device is not known it can be discovered via the Link Layer Discovery Protocol (LLDP). This can be done with a software like lldpd\footnote{\href{https://lldpd.github.io/}{https://lldpd.github.io/}}. If the corresponding service is running the currently discovered devices can be looked up with \texttt{lldpcli}. Root privileges are required to use this command. \begin{verbatim} lldpcli show neighbors \end{verbatim} A device with the system name \texttt{soundbox.local} should show up. Every 30 seconds a new discovery packet is emitted by soundbox. Thus it can take up to 30 seconds until it shows up. \section{Playing audio} \label{playing-audio} Audio can be streamed to \texttt{soundbox} devices with the \texttt{ffmpeg} command. Audio files or internet stream addresses can be passed as input. \begin{verbatim} ffmpeg -re -i -acodec libmp3lame -f matroska \ udp://224.0.0.99:5316 \end{verbatim} More details about FFmpeg streaming can be read from the FFmpeg streaming guide\footnote{\href{https://trac.ffmpeg.org/wiki/StreamingGuide}{https://trac.ffmpeg.org/wiki/StreamingGuide}}. % TODO alsa loop device explanation goes here \begin{verbatim} modprobe snd-aloop aplay -l ffmpeg -re -f alsa -i hw:3,1,1 -acodec libmp3lame -f matroska udp://224.0.0.99:5316 mplayer -ao alsa:device=hw=3,0,1 \end{verbatim} \chapter{Production} The given chapter contains documentation about how to produce a \texttt{soundbox} device. %\section{Printing mechanical parts} \section{Alpine Linux installation on a Raspberry Pi} Alpine Linux for the Raspberry Pi can be downloaded from the Alpine Linux\footnote{\href{https://alpinelinux.org/}{https://alpinelinux.org/}} download page. This section describes the installation procedure for the variant targeting the AArch64 architecture provided as a compressed tar archive. It can be downloaded and verified against a checksum with the \texttt{wget} and \texttt{sha256sum} utilities. \begin{verbatim} wget https://dl-cdn.alpinelinux.org/alpine/v3.19/releases\ /aarch64/alpine-rpi-3.19.0-aarch64.tar.gz wget https://dl-cdn.alpinelinux.org/alpine/v3.19/releases\ /aarch64/alpine-rpi-3.19.0-aarch64.tar.gz.sha256 sha256sum -c alpine-rpi-3.19.0-aarch64.tar.gz.sha256 \end{verbatim} The image has to be flashed to a SD card which will be inserted into the Raspberry Pi. This SD card has to be put into a Linux PC first. In Linux every SD card is represented as a block device like \texttt{sda} or \texttt{sdb} with a file path like \texttt{/dev/sda}. Possibly existing partitions on the SD card are represented with that path and a number as suffix like in \texttt{/dev/sda1}. The program \texttt{lsblk} gives an overview of the currently connected block devices. The correct device name for the SD card can be identified by its size. \begin{verbatim} $ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8:0 1 59,5G 0 disk `-sda1 8:1 1 59,5G 0 part \end{verbatim} The SD card has to be formatted with a single bootable FAT32 partition. This can be achieved with the command line program \texttt{parted}. First a \texttt{msdos} partition table has to be created followed by a partition taking the full size of the SD card. The boot flag of the partition is enabled and a FAT32 file system is created with \texttt{mkfs.vfat}. All of these operations require \texttt{root} privileges. \textbf{Warning:} These operations might cause data loss if the wrong device is specified. It has to be asserted that not the wrong block device (e.g. the PC disk) is chosen. \begin{verbatim} parted /dev/ mklabel msdos parted /dev/ mkpart primary fat32 0% 100% parted /dev/ toggle 1 boot mkfs.vfat /dev/1 \end{verbatim} After the file system is created the downloaded Alpine Linux tar archive has to be extracted to it. A temporary mount point can be created with \texttt{mktemp}. After mounting with \texttt{mount} the archive can be extracted with \texttt{tar}. Finally the file system is unmounted and it is waited for all buffered write operations to the SD card with \texttt{sync}. Also these command require \texttt{root} privileges. \begin{verbatim} mountpoint=$(mktemp -d) mount /dev/1 "$mountpoint" tar -C "$mountpoint" -xf alpine-rpi-3.19.0-aarch64.tar.gz umount /dev/1 sync \end{verbatim} Afterwards the SD card can be inserted into the Raspberry Pi. To do initial configuration it should be connected to a screen via HDMI. Also a keyboard has to be connected via USB. A mouse is not required. Finally the Pi should be powered up by connecting a USB power supply to the corresponding USB power input of the Raspberry Pi. Text from the boot process should be displayed on the screen. After logging in with the username \texttt{root} and no password basic system configuration on Alpine Linux can be done interactively with \texttt{setup-alpine}. The Alpine Linux installation guide\footnote{\href{https://wiki.alpinelinux.org/wiki/Installation}{https://wiki.alpinelinux.org/wiki/Installation}} contains further details. When a diskless installation is chosen the configuration changes have to be made persistent with the \texttt{lbu} command. Otherwise they will be lost on the next reboot. \begin{verbatim} setup-alpine lbu commit -d \end{verbatim} With this setup the Alpine Linux installation is completed. \section{Configure Alpine Linux for soundbox} \subsection{Package installation} soundbox requires packages from the Alpine Linux community package repository. Since this is not enabled by default it has to be done manually. This can be done by editing the \texttt{/etc/apk/repositories} file with an editor like \texttt{vi}. The hash sign \texttt{\#} in front of the URL to the community repository has to be removed. Instead also \texttt{sed} can remove this sign on a fresh installation quite easily since the community repository is the only one with such a sign in front of it. \begin{verbatim} sed -i 's/^#//g' /etc/apk/repositories \end{verbatim} With an enabled community repository all required packages for soundbox can be installed. The list with required packages can be written to the \texttt{/etc/apk/world} file with \texttt{echo}. Running \texttt{apk add} after it will install all of these packages including their dependencies and removes everything else. This makes sure that always exactly the same set of packages is used for a soundbox device. \begin{verbatim} echo 'alpine-base alsa-utils alsaconf busybox-mdev-openrc chrony ffplay iw lldpd lldpd-openrc openssh openssl wpa_supplicant' > /etc/apk/world apk add \end{verbatim} \subsection{LLDP network discovery} To make the soundbox device discoverable inside the network the Link Layer Discovery Protocol (LLDP) is used. With \texttt{echo} a new configuration file for the \texttt{lldpd} software can be added. After configuration the \texttt{lldpd} service is enabled via \texttt{rc-update} to start by default with the next reboot. \begin{verbatim} echo 'configure system hostname soundbox.local configure lldp agent-type nearest-customer-bridge' \ > /etc/lldpd.d/soundbox.conf rc-update add lldpd default \end{verbatim} \subsection{Audio configuration} The only user on a soundbox device is \texttt{root}. Even that super user has to be added to the \texttt{audio} group to be able to play sound via ALSA. This can be achieved with \texttt{addgroup}. \begin{verbatim} addgroup root audio \end{verbatim} soundbox uses the HiFiBerry shield to output high-quality audio. This shield needs to be enabled as an audio output by specifying a Devicetree overlay in the Raspberry Pi configuration file with \texttt{echo}. Since this file is stored on the SD card only which is mounted as read-only it has to be remounted with the read-write option first. \begin{verbatim} mount -o remount,rw /media/mmcblk0p1 echo 'dtoverlay=hifiberry-dac' >> /media/mmcblk0p1/config.txt \end{verbatim} If the builtin audio of e.g. a Raspberry Pi 4 should be used another Devicetree option has to be inserted instead: \begin{verbatim} echo 'dtparam=audio=on' >> /media/mmcblk0p1/config.txt \end{verbatim} \subsection{Service configuration} To receive audio streams via the network it is required to run the \texttt{ffplay} command continuously. This is possible by creating a service file for the OpenRC init system with \texttt{echo} and enabling the service with \texttt{rc-update}. \begin{verbatim} echo '#!/sbin/openrc-run name="soundbox" command="/usr/bin/ffplay" command_args="udp://224.0.0.99:5316" pidfile="/run/soundbox.pid" command_background=true' > /etc/init.d/soundbox rc-update add soundbox default \end{verbatim} \subsection{Persistence of changes and reboot} Since a diskless Alpine Linux installation is preferred for soundbox the changes have to be made persistent with \texttt{lbu}. Rebooting after it makes sure the SD card is again mounted in read-only mode and all Kernel-affecting changes can be applied. \begin{verbatim} lbu commit -d reboot \end{verbatim} After this reboot the soundbox device should be able to play audio like described in section~\ref{playing-audio}. %\section{Final assembly} %\chapter{Device internals} %\section{Mechanical design} %\section{Electronics} %\section{Operating system} %\section{Software} \end{document}