Last active
January 7, 2024 09:34
-
-
Save Mohawi/9a119dcdfae51514a2bae24975f2de4d to your computer and use it in GitHub Desktop.
This script sets up a specific architecture that serves as the central node of a multiroom audio system
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
############################################################################################################################################################################################################ | |
############################################################################################################################################################################################################ | |
############################################################################################################################################################################################################ | |
# # | |
# SYSTEM ARCHITECTURE - SOMMS (SNAPCAST - OCTO - MOPIDY - MULTIROOM - STREAMER) # | |
# # | |
############################################################################################################################################################################################################ | |
# # | |
# +------------------------------------------------------------------------------------------------+ # | |
# | | # | |
# | RaspberryPi4/2GB + Audio Injector Octo | # | |
# +--------------------+ | (6ADC / 8DAC) | +-----------------------+ # | |
# | | | (96kHz/24Bit) | | | # | |
# | ANALOG_IN1/2 +--+ | | +--+ ANALOG_OUT1/2 | # | |
# | TV | | | +----------------------------------------------+ | | | Snapclient_Out | # | |
# | | | | +-----------+ | | +------------+ | | | | # | |
# +--------------------+ | | | | | JACKd | | | | | +-----------------------+ # | |
# +--------------------+ ALSA_IN/6 +->+ +->+ ALSA_OUT/8 +------+ # | |
# +--------------------+ | | | | | 96kHz / 24Bit | | | | | +-----------------------+ # | |
# | | | | +-----------+ | | +------------+ | | | | # | |
# | ANALOG_IN2/2 +--+ | +-+------------------------------------------+-+ | +--+ ANALOG_OUT2/2 | # | |
# | CD | | | | ^ | | | TV_Mirror | # | |
# | | | | | +------------+ +------------+ | | | | | # | |
# +--------------------+ | | | | | | | | | | +-----------------------+ # | |
# | | +->+ ALSA_IN1/2 +-->+ | | | | # | |
# +--------------------+ | | | | | | | +------+------+ | | +-----------------------+ # | |
# | | | | | +------------+ | | | | | | | | # | |
# | ANALOG_IN3/2 +--+ | | | | | ALSA_OUT1/2 | | +--+ ANALOG_OUT3/2 | # | |
# | Vinyl | | | +------------+ | | | | | | | CD_Mirror | # | |
# | | | | | | | | +------+------+ | | | | # | |
# +--------------------+ | +->+ ALSA_IN2/2 +-->+ | ^ | | +-----------------------+ # | |
# | | | | | | | | | # | |
# | | +------------+ | | | | | +-----------------------+ # | |
# | | | | | | | | | # | |
# | | +------------+ | | +------+------+ | | | ANALOG_OUT4/2 | # | |
# | | | | | | | | | +--+ Vinyl_Mirror | # | |
# | +->+ ALSA_IN3/2 +-->+ | | SNAPCLIENT1 | | | | # | |
# | | | | | | | | +-----------------------+ # | |
# | +------------+ | SNAPSERVER | +------+------+ | # | |
# | | | ^ | +------------------------------------+ # | |
# | +----------------+ | | | LAN | | | # | |
# | +-------------+ | | | 96kHz +---------+------------------------+ | RaspberryPi Zero W + Hifiberry DAC | # | |
# | | | +->+ Mopidy_Stream1 +-->+ | | | | | | # | |
# +------------>+ HASS | | | | | 16Bit | v | | | +-------------+ +------------+ | +--------------+ # | |
# | | | Backend | | +----------------+ | | +-----+-------+ | | | | | | | | | | # | |
# | | | | | | | | | | +----->+ SNAPCLIENT2 +->+ ALSA_OUT/2 +------+ ANALOG_OUT/2 | # | |
# | | +-------------+ | +----------------+ | | | SNAPCLIENT4 | | | | | | | | | | | # | |
# | | | | | | | | | | | | +-------------+ +------------+ | +--------------+ # | |
# +-----+------+ | +->+ Mopidy_Stream2 +-->+ | +-----+-------+ | | | | # | |
# | | | +----------+ | | | | v | | +------------------------------------+ # | |
# | HASS | | Control | | +----------------+ | | +-----+-------+ | | # | |
# | Frontend +---------------------+ | | | | | | | +------------------------------------+ # | |
# | | | +---+ | +----------------+ | | | PULSEAUDIO | | | | | # | |
# +------------+ | | | | | | | | | | | | RaspberryPi Zero W + Hifiberry DAC | # | |
# | | +->+ Mopidy_Stream3 +-->+ | +-----+-------+ | | | | # | |
# | | | | | | v | | | +-------------+ +------------+ | +--------------+ # | |
# +----------------+ | | +----------------+ +-----+------+ +-----+-------+ | | | | | | | | | | # | |
# | | | v | | | | +----->+ SNAPCLIENT3 +->+ ALSA_OUT/2 +------+ ANALOG_OUT/2 | # | |
# | Snapcontrol +-------------------------+------------------------------------+ | BLUEZ +-------+ | | | | | | | | | # | |
# | | | Snapcontrol | | | | | +-------------+ +------------+ | +--------------+ # | |
# +----------------+ | +-------------+ | | | | # | |
# +-------------------------------------------------------------------------------------------|----+ +------------------------------------+ # | |
# | # | |
# | +-------------------+ # | |
# +-----------+ Bluetooth speaker | # | |
# +-------------------+ # | |
# # | |
# # | |
############################################################################################################################################################################################################ | |
############################################################################################################################################################################################################ | |
############################################################################################################################################################################################################ | |
# This runs fine on a Raspberry Pi 4 with 2GB of RAM. The IP of the central node needs to be statically set to 192.168.2.101 or to the one you choose. | |
# Also the mopidy plugins youtube, soundcloud and bandcamp need authentication tokens, which you will need to provide manually | |
# | |
# NO GUARANTEES GIVEN | |
# If you observe anything odd, please let me know! | |
# | |
# on first start you might need to configure the HASS through the webpage (like setup an user account). | |
echo 'Downloading and installing packages...' | |
sudo -i | |
apt update -y | |
apt upgrade -y | |
# install snapserver | |
wget https://github.com/badaix/snapcast/releases/download/v0.26.0/snapserver_0.27.0-1_armhf.deb | |
apt install ./snapserver_0.27.0-1_armhf.deb -y | |
rm snapserver_0.27.0-1_armhf.deb | |
#install snapclient | |
wget https://github.com/badaix/snapcast/releases/download/v0.26.0/snapclient_0.27.0-1_without-pulse_armhf.deb | |
apt install ./snapclient_0.27.0-1_without-pulse_armhf.deb -y | |
rm snapclient_0.27.0-1_without-pulse_armhf.deb | |
#install jackd | |
apt install jackd2 -y | |
apt install jack-tools -y | |
echo "Install RT patched kernel" | |
#install RT patched kernel | |
wget https://github.com/kdoren/linux/releases/download/rpi_6.1.54-rt15/linux-image-6.1.54-rt15-v8+_6.1.54-1_arm64.deb | |
# if installing 64-bit kernel on 32-bit system: | |
dpkg --add-architecture arm64 | |
sed -i 's|^deb http|deb [ arch=armhf ] http|g' /etc/apt/sources.list | |
sed -i 's|^deb http|deb [ arch=armhf ] http|g' /etc/apt/sources.list.d/raspi.list | |
apt install ./linux-image-6.1.54-rt15-v8+_6.1.54-1_arm64.deb -y | |
KERN=6.1.54-rt15-v8+ # 64-bit kernel | |
mkdir -p /boot/$KERN/overlays/ | |
cp -d /usr/lib/linux-image-$KERN/overlays/* /boot/$KERN/overlays/ | |
cp -dr /usr/lib/linux-image-$KERN/* /boot/$KERN/ | |
[[ -d /usr/lib/linux-image-$KERN/broadcom ]] && cp -d /usr/lib/linux-image-$KERN/broadcom/* /boot/$KERN/ | |
touch /boot/$KERN/overlays/README | |
mv /boot/vmlinuz-$KERN /boot/$KERN/ | |
mv /boot/initrd.img-$KERN /boot/$KERN/ | |
mv /boot/System.map-$KERN /boot/$KERN/ | |
mv /boot/config-$KERN /boot/$KERN/ | |
cat >> /boot/config.txt << EOF | |
[all] | |
kernel=vmlinuz-$KERN | |
# initramfs initrd.img-$KERN | |
os_prefix=$KERN/ | |
overlay_prefix=overlays/$(if [[ "$KERN" =~ 'v8' ]]; then echo -e "\narm_64bit=1"; fi) | |
[all] | |
EOF | |
rm /boot/cmdline.txt | |
cat >> /boot/cmdline.txt << EOF | |
boot=overlay console=serial0,115200 console=/dev/null root=PARTUUID=28f38267-02 rootfstype=ext4 fsck.repair=yes rootwait quiet splash plymoth.ignore-serial-consoles logo.nologo | |
EOF | |
cp /boot/cmdline.txt /boot/$KERN/ | |
echo "Configure Jackd" | |
#fill jackdsound.conf | |
cat >> /etc/dbus-1/system.d/jackdsound.conf << EOF | |
<?xml version="1.0"?> <!--*-nxml-*--> | |
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" | |
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> | |
<busconfig> | |
<policy context="default"> | |
<allow own="org.freedesktop.ReserveDevice1.Audio0"/> | |
<allow own="org.freedesktop.ReserveDevice1.Audio1"/> | |
<allow own="org.freedesktop.ReserveDevice1.Audio2"/> | |
</policy> | |
</busconfig> | |
EOF | |
echo "Setup Audioinjector Octo" | |
#setup octo | |
sed -i 's/dtparam=audio=on/#dtparam=audio=on/g' /boot/config.txt | |
echo "Setup extra boot settings" | |
cat >> /boot/config.txt << EOF | |
[all] | |
dtoverlay=audioinjector-addons,non-stop-clocks=false | |
EOF | |
#disable LEDs | |
cat >> /boot/config.txt << EOF | |
[all] | |
#Disable the PWR LED | |
dtparam=pwr_led_trigger=none | |
dtparam=pwr_led_activelow=off | |
#Disable the Activity LED | |
dtparam=act_led_trigger=none | |
dtparam=act_led_activelow=off | |
#rotate lcd display 180deg | |
lcd_rotate=2 | |
EOF | |
echo "continue setting up jackd" | |
#setup asound.conf | |
cat >> /etc/asound.conf << EOF | |
pcm.rawjack_snapclient_out { | |
type jack | |
playback_ports { | |
0 system:playback_1 | |
1 system:playback_2 | |
} | |
} | |
pcm.rawjack_snapserver_LineIn1 { | |
type jack | |
capture_ports { | |
0 system:capture_1 | |
1 system:capture_2 | |
} | |
} | |
pcm.rawjack_snapserver_LineIn2 { | |
type jack | |
capture_ports { | |
0 system:capture_3 | |
1 system:capture_4 | |
} | |
} | |
pcm.rawjack_snapserver_LineIn3 { | |
type jack | |
capture_ports { | |
0 system:capture_5 | |
1 system:capture_6 | |
} | |
} | |
pcm.plugjack_snapclient_out { | |
type plug | |
slave { pcm "rawjack_snapclient_out" } | |
hint { | |
description "JACK Audio Connection Kit sink for the snapclient" | |
} | |
} | |
pcm.plugjack_snapserver_LineIn1 { | |
type plug | |
slave { pcm "rawjack_snapserver_LineIn1" } | |
hint { | |
description "JACK Audio Connection Kit source for the LineIn1 channel" | |
} | |
} | |
pcm.plugjack_snapserver_LineIn2 { | |
type plug | |
slave { pcm "rawjack_snapserver_LineIn2" } | |
hint { | |
description "JACK Audio Connection Kit source for the LineIn2 channel" | |
} | |
} | |
pcm.plugjack_snapserver_LineIn3 { | |
type plug | |
slave { pcm "rawjack_snapserver_LineIn3" } | |
hint { | |
description "JACK Audio Connection Kit source for the LineIn3 channel" | |
} | |
} | |
EOF | |
#setup jack_config | |
cat >> /etc/jack_config.conf << EOF | |
JACKD_OPTIONS="-R -P75 -dalsa -dhw:audioinjectoroc -r96000 -p512 -n3" | |
EOF | |
cat >> /etc/jack-plumbing << EOF | |
(disconnect "system:capture_(.*)" "system:playback_(.*)") | |
(connect "system:capture_1" "system:playback_3") | |
(connect "system:capture_2" "system:playback_4") | |
(connect "system:capture_3" "system:playback_5") | |
(connect "system:capture_4" "system:playback_6") | |
(connect "system:capture_5" "system:playback_7") | |
(connect "system:capture_6" "system:playback_8") | |
EOF | |
echo "Setup snapcast" | |
# setup snapclient | |
sed -i 's/SNAPCLIENT_OPTS=""/SNAPCLIENT_OPTS="--host 127.0.0.1 --port 1710 --soundcard plugjack_snapclient_out"/g' /etc/default/snapclient1 | |
sed -i 's/SNAPCLIENT_OPTS=""/SNAPCLIENT_OPTS="--host 127.0.0.1 --port 1710 --soundcard pulse"/g' /etc/default/snapclient2 | |
#setup snapserver | |
sed -i 's|^source =.*|source = alsa://?name=TV&device=plugjack_snapserver_LineIn1&sampleformat=96000:16:2&silence_threshold_percent=0.2&idle_threshold=100\nsource = alsa://?name=CD&device=plugjack_snapserver_LineIn2&sampleformat=96000:16:2&silence_threshold_percent=0.1&idle_threshold=100\nsource = alsa://?name=Vinyl&device=plugjack_snapserver_LineIn3&sampleformat=96000:16:2&silence_threshold_percent=1.5&idle_threshold=100\nsource = tcp://127.0.0.1:4953?name=Livingroom(Stream)\nsource = tcp://127.0.0.1:4954?name=Library(Stream)\nsource = tcp://127.0.0.1:4955?name=Office(Stream)\nsource = meta:///Vinyl/CD/Livingroom(Stream)?name=Livingroom_Music\nsource = meta:///Livingroom_Music/TV?name=Livingroom_Music_And_Tv|g' /etc/snapserver.conf | |
sed -i '/^#sampleformat = 48000:16:2/a sampleformat = 96000:16:2' /etc/snapserver.conf | |
sed -i '/^#port = 1705/a port = 1711' /etc/snapserver.conf | |
sed -i '/^#port = 1704/a port = 1710' /etc/snapserver.conf | |
echo "setup services" | |
#setup services | |
cat >> /etc/systemd/system/restartOcto.service << EOF | |
[Unit] | |
Description=AudioInjector Octo | |
After=sound.target time-sync.target | |
Requires=sound.target | |
PartOf=audioOcto.target | |
[Service] | |
Type=oneshot | |
#ExecStartPre=sleep 5 | |
ExecStart=/home/pi/restartOcto.sh | |
RemainAfterExit=yes | |
[Install] | |
WantedBy=audioOcto.target | |
EOF | |
cat >> /etc/systemd/system/jackd.service << EOF | |
[Unit] | |
Description=JACK Audio Connection Kit | |
After=sound.target ntp.service time-sync.target restartOcto.service | |
#Wants=restartOcto.service | |
Requires=restartOcto.service | |
BindsTo=restartOcto.service | |
PartOf=audioOcto.target | |
#StartLimitBurst=4 | |
#StartLimitIntervalSec=60 | |
#StartLimitAction=reboot | |
[Service] | |
EnvironmentFile=-/etc/jack_config.conf | |
LimitRTPRIO=infinity | |
LimitMEMLOCK=infinity | |
User=pi | |
Environment="DBUS_SESSION_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket" | |
#ExecStartPre=/bin/sleep 5 | |
ExecStart=/usr/bin/jackd \$JACKD_OPTIONS | |
RestartSec=5 | |
Restart=on-failure | |
[Install] | |
WantedBy=audioOcto.target | |
EOF | |
cat >> /etc/systemd/system/snapserver.service << EOF | |
[Unit] | |
Description=Snapcast server | |
Documentation=man:snapserver(1) | |
Wants=avahi-daemon.service jackd.service | |
After=network.target time-sync.target avahi-daemon.service jackd.service | |
Requires=jackd.service | |
PartOf=audioOcto.target | |
[Service] | |
EnvironmentFile=-/etc/default/snapserver | |
LimitRTPRIO=infinity | |
LimitMEMLOCK=infinity | |
Nice=-20 | |
#ExecStartPre=/bin/sleep 5 | |
ExecStart=/usr/bin/snapserver --server.datadir=\${HOME} \$SNAPSERVER_OPTS | |
User=pi | |
#Group=snapserver | |
RestartSec=5 | |
Restart=on-failure | |
[Install] | |
WantedBy=audioOcto.target | |
EOF | |
cat >> /etc/systemd/system/snapclient.service << EOF | |
[Unit] | |
Description=Snapcast client | |
Documentation=man:snapclient(1) | |
Wants=avahi-daemon.service jackd.service | |
After=network-online.target time-sync.target sound.target avahi-daemon.service jackd.service | |
Requires=jackd.service | |
PartOf=audioOcto.target | |
[Service] | |
EnvironmentFile=-/etc/default/snapclient1 | |
Nice=-15 | |
LimitRTPRIO=infinity | |
LimitMEMLOCK=infinity | |
#ExecStartPre=/bin/sleep 10 | |
ExecStart=/usr/bin/snapclient --logsink=null \$SNAPCLIENT_OPTS | |
User=pi | |
Group=audio | |
Restart=on-failure | |
[Install] | |
WantedBy=audioOcto.target | |
EOF | |
cat >> /etc/systemd/system/audioOcto.target << EOF | |
[Unit] | |
Description=This target sums up the services to make the Octo interface work | |
Requires=sound.target | |
Requires=network.target | |
Requires=time-sync.target | |
PartOf=jackd.service | |
[Install] | |
WantedBy=multi-user.target | |
EOF | |
cat >> /etc/systemd/system/jackd_connect.service << EOF | |
[Unit] | |
Description = connect JACK ports according to /etc/jack-plumbing | |
Wants=jackd.service | |
After=jackd.service | |
Requires=jackd.service | |
#BindsTo=jackd.service | |
PartOf=audioOcto.target | |
[Service] | |
ExecStartPre=sleep 3 | |
ExecStart=jack-plumbing -d | |
User=pi | |
Restart=on-failure | |
[Install] | |
WantedBy=audioOcto.target | |
EOF | |
echo "Install bluetooth and pulseaudio" | |
apt install bluetooth pi-bluetooth bluez pulseaudio pulseaudio-module-bluetooth | |
cat >> /etc/systemd/user/snapclient_pulse.service << EOF | |
[Unit] | |
Description=Snapcast client for pulse | |
Documentation=man:snapclient(1) | |
[Service] | |
EnvironmentFile=-/etc/default/snapclient2 | |
Nice=-15 | |
LimitRTPRIO=infinity | |
LimitMEMLOCK=infinity | |
ExecStart=/usr/bin/snapclient --logsink=null $SNAPCLIENT_OPTS | |
Restart=on-failure | |
[Install] | |
WantedBy=default.target | |
EOF | |
systemctl daemon-reload | |
systemctl enable restartOcto | |
systemctl enable jackd | |
systemctl enable jack_config | |
systemctl enable snapserver | |
systemctl enable snapclient | |
systemctl enable audioOcto.target | |
sudo -u pi -H -s | |
systemctl --user daemon-reload | |
systemctl --user enable snapclient_pulse | |
exit | |
cat >> /home/pi/restartOcto.sh << EOF | |
#!/bin/bash | |
modprobe -r snd_soc_audioinjector_octo_soundcard | |
modprobe -r snd_soc_cs42xx8_i2c | |
modprobe -r snd_soc_cs42xx8 | |
modprobe snd_soc_cs42xx8 | |
modprobe snd_soc_cs42xx8_i2c | |
modprobe snd_soc_audioinjector_octo_soundcard | |
EOF | |
chmod +x /home/pi/restartOcto.sh | |
cat /var/lib/alsa/asound.state << EOF | |
state.Headphones { | |
control.1 { | |
iface MIXER | |
name 'Headphone Playback Volume' | |
value 0 | |
comment { | |
access 'read write' | |
type INTEGER | |
count 1 | |
range '-10239 - 400' | |
dbmin -9999999 | |
dbmax 400 | |
dbvalue.0 0 | |
} | |
} | |
control.2 { | |
iface MIXER | |
name 'Headphone Playback Switch' | |
value true | |
comment { | |
access 'read write' | |
type BOOLEAN | |
count 1 | |
} | |
} | |
} | |
state.vc4hdmi0 { | |
control.1 { | |
iface PCM | |
name 'Playback Channel Map' | |
value.0 0 | |
value.1 0 | |
value.2 0 | |
value.3 0 | |
value.4 0 | |
value.5 0 | |
value.6 0 | |
value.7 0 | |
comment { | |
access read | |
type INTEGER | |
count 8 | |
range '0 - 36' | |
} | |
} | |
control.2 { | |
iface PCM | |
name 'IEC958 Playback Mask' | |
value ffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
comment { | |
access read | |
type IEC958 | |
count 1 | |
} | |
} | |
control.3 { | |
iface PCM | |
name 'IEC958 Playback Default' | |
value '0400000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' | |
comment { | |
access 'read write' | |
type IEC958 | |
count 1 | |
} | |
} | |
control.4 { | |
iface PCM | |
name ELD | |
value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' | |
comment { | |
access 'read volatile' | |
type BYTES | |
count 128 | |
} | |
} | |
} | |
state.vc4hdmi1 { | |
control.1 { | |
iface PCM | |
name 'Playback Channel Map' | |
value.0 0 | |
value.1 0 | |
value.2 0 | |
value.3 0 | |
value.4 0 | |
value.5 0 | |
value.6 0 | |
value.7 0 | |
comment { | |
access read | |
type INTEGER | |
count 8 | |
range '0 - 36' | |
} | |
} | |
control.2 { | |
iface PCM | |
name 'IEC958 Playback Mask' | |
value ffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
comment { | |
access read | |
type IEC958 | |
count 1 | |
} | |
} | |
control.3 { | |
iface PCM | |
name 'IEC958 Playback Default' | |
value '0400000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' | |
comment { | |
access 'read write' | |
type IEC958 | |
count 1 | |
} | |
} | |
control.4 { | |
iface PCM | |
name ELD | |
value '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' | |
comment { | |
access 'read volatile' | |
type BYTES | |
count 128 | |
} | |
} | |
} | |
state.audioinjectoroc { | |
control.1 { | |
iface MIXER | |
name 'ADC3 Capture Volume' | |
value.0 129 | |
value.1 129 | |
comment { | |
access 'read write' | |
type INTEGER | |
count 2 | |
range '0 - 176' | |
dbmin -6400 | |
dbmax 2400 | |
dbvalue.0 50 | |
dbvalue.1 50 | |
} | |
} | |
control.2 { | |
iface MIXER | |
name 'ADC3 Invert Switch' | |
value.0 false | |
value.1 false | |
comment { | |
access 'read write' | |
type BOOLEAN | |
count 2 | |
} | |
} | |
control.3 { | |
iface MIXER | |
name 'ADC3 Single Ended Mode Switch' | |
value Single-Ended | |
comment { | |
access 'read write' | |
type ENUMERATED | |
count 1 | |
item.0 Differential | |
item.1 Single-Ended | |
} | |
} | |
control.4 { | |
iface MIXER | |
name 'DAC1 Playback Volume' | |
value.0 255 | |
value.1 255 | |
comment { | |
access 'read write' | |
type INTEGER | |
count 2 | |
range '0 - 255' | |
dbmin -9999999 | |
dbmax 0 | |
dbvalue.0 0 | |
dbvalue.1 0 | |
} | |
} | |
control.5 { | |
iface MIXER | |
name 'DAC2 Playback Volume' | |
value.0 255 | |
value.1 255 | |
comment { | |
access 'read write' | |
type INTEGER | |
count 2 | |
range '0 - 255' | |
dbmin -9999999 | |
dbmax 0 | |
dbvalue.0 0 | |
dbvalue.1 0 | |
} | |
} | |
control.6 { | |
iface MIXER | |
name 'DAC3 Playback Volume' | |
value.0 255 | |
value.1 255 | |
comment { | |
access 'read write' | |
type INTEGER | |
count 2 | |
range '0 - 255' | |
dbmin -9999999 | |
dbmax 0 | |
dbvalue.0 0 | |
dbvalue.1 0 | |
} | |
} | |
control.7 { | |
iface MIXER | |
name 'DAC4 Playback Volume' | |
value.0 255 | |
value.1 255 | |
comment { | |
access 'read write' | |
type INTEGER | |
count 2 | |
range '0 - 255' | |
dbmin -9999999 | |
dbmax 0 | |
dbvalue.0 0 | |
dbvalue.1 0 | |
} | |
} | |
control.8 { | |
iface MIXER | |
name 'ADC1 Capture Volume' | |
value.0 152 | |
value.1 152 | |
comment { | |
access 'read write' | |
type INTEGER | |
count 2 | |
range '0 - 176' | |
dbmin -6400 | |
dbmax 2400 | |
dbvalue.0 1200 | |
dbvalue.1 1200 | |
} | |
} | |
control.9 { | |
iface MIXER | |
name 'ADC2 Capture Volume' | |
value.0 104 | |
value.1 104 | |
comment { | |
access 'read write' | |
type INTEGER | |
count 2 | |
range '0 - 176' | |
dbmin -6400 | |
dbmax 2400 | |
dbvalue.0 -1200 | |
dbvalue.1 -1200 | |
} | |
} | |
control.10 { | |
iface MIXER | |
name 'DAC1 Invert Switch' | |
value.0 false | |
value.1 false | |
comment { | |
access 'read write' | |
type BOOLEAN | |
count 2 | |
} | |
} | |
control.11 { | |
iface MIXER | |
name 'DAC2 Invert Switch' | |
value.0 false | |
value.1 false | |
comment { | |
access 'read write' | |
type BOOLEAN | |
count 2 | |
} | |
} | |
control.12 { | |
iface MIXER | |
name 'DAC3 Invert Switch' | |
value.0 false | |
value.1 false | |
comment { | |
access 'read write' | |
type BOOLEAN | |
count 2 | |
} | |
} | |
control.13 { | |
iface MIXER | |
name 'DAC4 Invert Switch' | |
value.0 false | |
value.1 false | |
comment { | |
access 'read write' | |
type BOOLEAN | |
count 2 | |
} | |
} | |
control.14 { | |
iface MIXER | |
name 'ADC1 Invert Switch' | |
value.0 false | |
value.1 false | |
comment { | |
access 'read write' | |
type BOOLEAN | |
count 2 | |
} | |
} | |
control.15 { | |
iface MIXER | |
name 'ADC2 Invert Switch' | |
value.0 false | |
value.1 false | |
comment { | |
access 'read write' | |
type BOOLEAN | |
count 2 | |
} | |
} | |
control.16 { | |
iface MIXER | |
name 'ADC High-Pass Filter Switch' | |
value true | |
comment { | |
access 'read write' | |
type BOOLEAN | |
count 1 | |
} | |
} | |
control.17 { | |
iface MIXER | |
name 'DAC De-emphasis Switch' | |
value false | |
comment { | |
access 'read write' | |
type BOOLEAN | |
count 1 | |
} | |
} | |
control.18 { | |
iface MIXER | |
name 'ADC1 Single Ended Mode Switch' | |
value Single-Ended | |
comment { | |
access 'read write' | |
type ENUMERATED | |
count 1 | |
item.0 Differential | |
item.1 Single-Ended | |
} | |
} | |
control.19 { | |
iface MIXER | |
name 'ADC2 Single Ended Mode Switch' | |
value Single-Ended | |
comment { | |
access 'read write' | |
type ENUMERATED | |
count 1 | |
item.0 Differential | |
item.1 Single-Ended | |
} | |
} | |
control.20 { | |
iface MIXER | |
name 'DAC Single Volume Control Switch' | |
value 0 | |
comment { | |
access 'read write' | |
type INTEGER | |
count 1 | |
range '0 - 1' | |
} | |
} | |
control.21 { | |
iface MIXER | |
name 'DAC Soft Ramp & Zero Cross Control Switch' | |
value 'Immediate Change' | |
comment { | |
access 'read write' | |
type ENUMERATED | |
count 1 | |
item.0 'Immediate Change' | |
item.1 'Zero Cross' | |
item.2 'Soft Ramp' | |
item.3 'Soft Ramp on Zero Cross' | |
} | |
} | |
control.22 { | |
iface MIXER | |
name 'DAC Auto Mute Switch' | |
value true | |
comment { | |
access 'read write' | |
type BOOLEAN | |
count 1 | |
} | |
} | |
control.23 { | |
iface MIXER | |
name 'Mute ADC Serial Port Switch' | |
value false | |
comment { | |
access 'read write' | |
type BOOLEAN | |
count 1 | |
} | |
} | |
control.24 { | |
iface MIXER | |
name 'ADC Single Volume Control Switch' | |
value 0 | |
comment { | |
access 'read write' | |
type INTEGER | |
count 1 | |
range '0 - 1' | |
} | |
} | |
control.25 { | |
iface MIXER | |
name 'ADC Soft Ramp & Zero Cross Control Switch' | |
value 'Immediate Change' | |
comment { | |
access 'read write' | |
type ENUMERATED | |
count 1 | |
item.0 'Immediate Change' | |
item.1 'Zero Cross' | |
item.2 'Soft Ramp' | |
item.3 'Soft Ramp on Zero Cross' | |
} | |
} | |
} | |
EOF | |
echo "Install Mopidy" | |
apt install mopidy -y | |
python3 -m pip install mopidy-youtube | |
python3 -m pip install mopidy-soundcloud | |
python3 -m pip install mopidy-tunein | |
python3 -m pip install mopidy-local | |
python3 -m pip install mopidy-iris | |
python3 -m pip install mopidy-mpd | |
python3 -m pip install mopidy-bandcamp | |
echo "mopidy ALL=NOPASSWD: /usr/local/lib/python3.9/dist-packages/mopidy_iris/system.sh" >> /etc/sudoers | |
rm /etc/mopidy/mopidy.conf | |
cat >> /etc/mopidy/mopidy.conf << EOF | |
\# For information about configuration values that can be set in this file see: | |
\# | |
\# https://docs.mopidy.com/en/latest/config/ | |
\# | |
\# Run `sudo mopidyctl config` to see the current effective config, based on | |
\# both defaults and this configuration file. | |
[youtube] | |
enabled = true | |
youtube_api_key = <<get your own key>> | |
api_enabled = true | |
search_results = 15 | |
playlist_max_videos = 20 | |
autoplay_enabled = true | |
strict_autoplay = true | |
max_autoplay_length = 15000 | |
[http] | |
enabled = true | |
hostname = 0.0.0.0 | |
default_app = iris | |
[mpd] | |
enabled = true | |
hostname = 0.0.0.0 | |
[soundcloud] | |
auth_token = <<get your own key>> | |
[bandcamp] | |
identity = <<get your own key>> | |
[local] | |
media_dir = /home/pi/Music | |
included_file_extensions = .flac, .mp3, .wma | |
scan_timeout = 5000 | |
album_art_files = *.jpg | |
use_artist_sortname = true | |
[autoplay] | |
enabled=true | |
tracklist.uris = auto | |
tracklist.index = auto | |
tracklist.consume = auto | |
tracklist.random = auto | |
tracklist.repeat = auto | |
tracklist.single = auto | |
playback.state = auto | |
playback.time_position = auto | |
mixer.volume = auto | |
mixer.mute = auto | |
EOF | |
cat >> /etc/mopidy/mopidy0.conf << EOF | |
[audio] | |
output = audioresample ! audioconvert ! audio/x-raw,rate=96000,channels=2,format=S16LE ! wavenc ! tcpclientsink host=127.0.0.1 port=4953 | |
[http] | |
port=6680 | |
zeroconf = Mopidy | |
[mpd] | |
port = 6600 | |
EOF | |
cat >> /etc/mopidy/mopidy1.conf << EOF | |
[audio] | |
output = audioresample ! audioconvert ! audio/x-raw,rate=96000,channels=2,format=S16LE ! wavenc ! tcpclientsink host=127.0.0.1 port=4954 | |
[http] | |
port=6681 | |
allowed_origins = 192.168.2.112:6680 | |
[mpd] | |
port = 6601 | |
EOF | |
cat >> /etc/mopidy/mopidy2.conf << EOF | |
[audio] | |
output = audioresample ! audioconvert ! audio/x-raw,rate=96000,channels=2,format=S16LE ! wavenc ! tcpclientsink host=127.0.0.1 port=4955 | |
[http] | |
port=6682 | |
allowed_origins = 192.168.2.112:6680 | |
[mpd] | |
port = 6602 | |
EOF | |
cat >> /etc/systemd/system/mopidy@.service << EOF | |
[Unit] | |
Description=Mopidy music server #%i | |
After=avahi-daemon.service | |
After=dbus.service | |
After=network.target | |
After=nss-lookup.target | |
After=pulseaudio.service | |
After=remote-fs.target | |
After=sound.target | |
[Service] | |
User=mopidy | |
PermissionsStartOnly=true | |
ExecStartPre=/bin/mkdir -p /var/cache/mopidy | |
ExecStartPre=/bin/chown mopidy:audio /var/cache/mopidy | |
Environment=XDG_RUNTIME_DIR=/var/cache/mopidy | |
ExecStart=/usr/bin/mopidy --config /usr/share/mopidy/conf.d:/etc/mopidy/mopidy.conf:/etc/mopidy/mopidy%i.conf | |
[Install] | |
WantedBy=multi-user.target | |
EOF | |
systemctl enable mopidy@0 | |
systemctl enable mopidy@1 | |
systemctl enable mopidy@2 | |
cat >> /etc/systemd/system/mountMediaServer.service << EOF | |
[Unit] | |
Description=Trigger mounting of media server | |
After=network-online.target | |
Requires=network-online.target | |
[Service] | |
Type=oneshot | |
#User=pi | |
ExecStart=/home/pi/MountMediaServer.sh | |
[Install] | |
WantedBy=multi-user.target | |
EOF | |
systemctl enable mountMediaServer | |
cat >> /home/pi/MountMediaServer.sh << EOF | |
#!/bin/bash | |
sudo mount -t cifs -o user=mopidy,pass=<<not of interest>>,vers=3.0 //192.168.2.3/mm/music /home/pi/Music | |
while ! (mountpoint -q /home/pi/Music); do | |
sleep 5 | |
sudo mount -t cifs -o user=mopidy,pass=<<not of interest>>,vers=3.0 //192.168.2.3/mm/music /home/pi/Music | |
done | |
EOF | |
chmod +x /home/pi/MountMediaServer.sh | |
echo "install homeassistant" | |
apt-get install -y python3 python3-dev python3-venv python3-pip libffi-dev libssl-dev libjpeg-dev zlib1g-dev autoconf build-essential libopenjp2-7 libtiff5 libturbojpeg0-dev tzdata | |
useradd -rm homeassistant -G dialout,gpio,i2c | |
mkdir /srv/homeassistant | |
chown homeassistant:homeassistant /srv/homeassistant | |
sudo -u homeassistant -H -s | |
cd /srv/homeassistant | |
python3.9 -m venv . | |
source bin/activate | |
python3 -m pip install wheel | |
pip3 install homeassistant | |
deactivate | |
cat >> ~/.homeassistant/configuration.yaml << EOF | |
panel_iframe: | |
music1: | |
title: 'Music - Livingroom (Stream)' | |
icon: 'mdi:music-box-outline' | |
url: 'http://192.168.2.101:6680' | |
music3: | |
title: 'Music - Library (Stream)' | |
icon: 'mdi:music-box-outline' | |
url: 'http://192.168.2.101:6681' | |
music2: | |
title: 'Music - Office (Stream)' | |
icon: 'mdi:music-box-outline' | |
url: 'http://192.168.2.101:6682' | |
EOF | |
exit | |
cat >> /etc/systemd/system/hassio.service << EOF | |
[Unit] | |
Description=Home Assistant | |
After=network-online.target | |
Wants=network-online.target | |
[Service] | |
Type=simple | |
User=homeassistant | |
WorkingDirectory=/home/homeassistant/.homeassistant | |
ExecStartPre=/bin/sleep 20 | |
ExecStart=/srv/homeassistant/bin/hass -c "/home/homeassistant/.homeassistant" | |
Restart=always | |
[Install] | |
WantedBy=multi-user.target | |
EOF | |
systemctl daemon-reload | |
systemctl enable hassio.service | |
systemctl start hassio.service | |
echo "setup autostart of chrome" | |
cat >> /etc/xdg/autostart/chromium_kiosk.desktop << EOF | |
[Desktop Entry] | |
Type=Application | |
Name=Chromium-Iris | |
Comment=Chromium in Kiosk mode for iris | |
NoDisplay=false | |
Exec=bash -c "sleep 15 && chromium-browser http://localhost:8123/music1 –-start-fullscreen –-kiosk –-noerrdialogs –-no-first-run" | |
EOF | |
echo "install virtual keyboard" | |
apt install -y at-spi2-core | |
apt install -y onboard | |
gsettings set org.gnome.desktop.a11y.applications screen-keyboard-enabled true | |
apt install -y dconf-cli | |
cat >> ~/onboard.settings << EOF | |
[/] | |
current-settings-page=1 | |
layout='/usr/share/onboard/layouts/Small.onboard' | |
schema-version='2.3' | |
show-status-icon=false | |
system-theme-associations={'HighContrast': 'HighContrast', 'HighContrastInverse': 'HighContrastInverse', 'LowContrast': 'LowContrast', 'ContrastHighInverse': 'HighContrastInverse', 'Default': '', 'PiXflat': '/usr/share/onboard/themes/DarkRoom.theme'} | |
theme='/usr/share/onboard/themes/DarkRoom.theme' | |
use-system-defaults=false | |
[auto-show] | |
enabled=true | |
hide-on-key-press=false | |
tablet-mode-detection-enabled=false | |
[keyboard] | |
key-press-modifiers=@a{ss} {} | |
[scanner] | |
enabled=false | |
[theme-settings] | |
color-scheme='/usr/share/onboard/themes/DarkRoom.colors' | |
key-fill-gradient=5.0 | |
key-gradient-direction=-2.0 | |
key-shadow-size=30.0 | |
key-shadow-strength=50.0 | |
key-size=95.0 | |
key-stroke-gradient=15.0 | |
key-style='gradient' | |
roundrect-radius=20.0 | |
[window] | |
docking-enabled=false | |
docking-shrink-workarea=false | |
force-to-top=true | |
transparent-background=false | |
[window/landscape] | |
dock-expand=true | |
width=810 | |
x=0 | |
y=278 | |
EOF | |
cat onboard.settings | dconf load -f /org/onboard/ | |
sed -i 's/Exec=onboard --not-show-in=GNOME,GNOME-Classic:GNOME --startup-delay=3.0/Exec=onboard --startup-delay=3.0/g' /etc/xdg/autostart/onboard-autostart.desktop | |
sed -i '/^OnlyShowIn=Unity;MATE;/d' /etc/xdg/autostart/onboard-autostart.desktop | |
apt install ufw -y | |
ufw allow ssh | |
ufw allow 6680 | |
ufw allow 6681 | |
ufw allow 6682 | |
ufw allow 8123 | |
ufw allow 1710 | |
ufw allow 1711 | |
ufw allow 1780 | |
ufw deny from 192.168.2.1 proto tcp to any port 22 | |
ufw deny from 192.168.2.2 proto tcp to any port 22 | |
ufw deny from 192.168.2.3 proto tcp to any port 22 | |
ufw allow proto udp to any port 137 from 192.168.2.0/24 | |
ufw allow proto udp to any port 138 from 192.168.2.0/24 | |
ufw allow proto tcp to any port 139 from 192.168.2.0/24 | |
ufw allow proto tcp to any port 445 from 192.168.2.0/24 | |
ufw enable | |
apt install unattended-upgrades -y | |
sed -i 's|^//\(.*}-updates\)| \1|g' /etc/apt/apt.conf.d/50unattended-upgrades | |
sed -i 's|^//\(.*Remove-Unused-Kernel-Packages\)|\1|g' /etc/apt/apt.conf.d/50unattended-upgrades | |
sed -i 's|^//\(.*Remove-Unused-Dependencies "\)false\(";\)|\1true\2|g' /etc/apt/apt.conf.d/50unattended-upgrades | |
sed -i 's|^//\(.*Automatic-Reboot-WithUsers\)|\1|g' /etc/apt/apt.conf.d/50unattended-upgrades | |
sed -i 's|^//\(.*Automatic-Reboot-Time "\).*\(";\)|\105:00\2|g' /etc/apt/apt.conf.d/50unattended-upgrades | |
cat >> /etc/apt/apt.conf.d/20auto-upgrades << EOF | |
APT::Periodic::Download-Upgradeable-Packages "1"; | |
APT::Periodic::AutocleanInterval "7"; | |
EOF | |
echo "Scan local media for mopidy" | |
systemctl start mountMediaServer.service | |
/usr/bin/mopidy --config /usr/share/mopidy/conf.d:/etc/mopidy/mopidy.conf:/etc/mopidy/mopidy0.conf local scan | |
echo "Setup screen blanking" | |
cat >> /etc/xdg/lxsession/LXDE/autostart << EOF | |
@xset s 30 | |
EOF | |
echo rebooting | |
reboot |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment