Recipe for MCP Music Computer

  • base netinst install of jessie - deselect everything from tasksel
    • hostname music – domain mcp.lcl
    • root on SSD (discard, noatime)
    • RAID-1 across two 1 TB drives, LVM with swap and music partitions
  • > /etc/motd
  • apt-get --no-install-recommends install aptitude
  • aptitude install ssh (this will pull in xauth, but that's okay)
  • aptitude install less fbset screen rsync psmisc file patch ethtool strace tcpdump vim bzip2 xz-utils
  • aptitude --without-recommends install dnsutils
  • adduser tdobes adm
  • adduser tdobes systemd-journal
  • aptitude install dbus
  • sed -i -e 's/^deb.* main$/& contrib non-free/g' /etc/apt/sources.list
  • aptitude update && aptitude forget-new
  • aptitude install intel-microcode
  • aptitude install firmware-realtek # for r8169 NIC's
  • aptitude install firmware-linux-nonfree # for ATI video card
  • adjust /etc/udev/rules.d/70-persistent-net.rules to set NIC with main network as eth0
    • if it was necessary to swap eth0/eth1, update etc/network/interfaces as well
  • aptitude install ifplugd
  • sed -i -e 's/^INTERFACES=""/INTERFACES="eth0"/g' /etc/default/ifplugd
  • sed -i -e 's/^allow-hotplug eth0/#allow-hotplug eth0/g' /etc/network/interfaces
  • Music-computer-specific network setup:
    echo $'\t# hack to work around MCSC Internet stupidity...' >> /etc/network/interfaces
    echo $'\t# route connections to mcpstars.org through the VPN' >> /etc/network/interfaces
    echo $'\tup route add -host 208.64.37.42 gw 10.2.25.229' >> /etc/network/interfaces
    echo $'\tdown route del -host 208.64.37.42 gw 10.2.25.229' >> /etc/network/interfaces
    echo >> /etc/network/interfaces
    echo '# Add-on NIC' >> /etc/network/interfaces
    echo '#allow-hotplug eth1' >> /etc/network/interfaces
    echo 'iface eth1 inet manual' >> /etc/network/interfaces
    echo $'\tpre-up ifconfig $IFACE up' >> /etc/network/interfaces
    echo $'\tpost-down ifconfig $IFACE down' >> /etc/network/interfaces
    echo $'\tup ifup eth1.2' >> /etc/network/interfaces
    echo $'\tup ifup eth1.11' >> /etc/network/interfaces
    echo $'\tdown ifdown eth1.2' >> /etc/network/interfaces
    echo $'\tdown ifdown eth1.11' >> /etc/network/interfaces
    echo >> /etc/network/interfaces
    echo '# DigitalSky network' >> /etc/network/interfaces
    echo 'iface eth1.2 inet dhcp' >> /etc/network/interfaces
    echo $'\tmetric 1' >> /etc/network/interfaces
    echo >> /etc/network/interfaces
    echo '# Theater automation network' >> /etc/network/interfaces
    echo 'iface eth1.11 inet static' >> /etc/network/interfaces
    echo $'\taddress 192.168.22.212' >> /etc/network/interfaces
    echo $'\tnetmask 255.255.255.0' >> /etc/network/interfaces
    
    sed -i -e 's/^INTERFACES="eth0"/INTERFACES="eth0 eth1"/g' /etc/default/ifplugd
    
    # this takes care of the two DHCP interfaces fighting over resolv.conf:
    aptitude install resolvconf
    systemctl enable resolvconf
    systemctl start resolvconf
    
    systemctl restart ifplugd
  • aptitude --without-recommends install ntp
    echo '[Unit]' > /etc/systemd/system/ntp.service
    echo 'Description=Network Time Protocol daemon' >> /etc/systemd/system/ntp.service
    echo 'After=network.target' >> /etc/systemd/system/ntp.service
    echo >> /etc/systemd/system/ntp.service
    echo '[Service]' >> /etc/systemd/system/ntp.service
    echo 'ExecStart=/usr/sbin/ntpd -n -g -u ntp:ntp' >> /etc/systemd/system/ntp.service
    echo >> /etc/systemd/system/ntp.service
    echo '[Install]' >> /etc/systemd/system/ntp.service
    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/ntp.service
    systemctl enable ntp.service
  • mkdir -p /etc/systemd/system/ssh.socket.d
    echo '[Socket]' > /etc/systemd/system/ssh.socket.d/port-2222.conf
    echo 'ListenStream=2222' >> /etc/systemd/system/ssh.socket.d/port-2222.conf
    systemctl disable ssh.service && systemctl enable ssh.socket
  • mkdir -p /etc/systemd/system/getty\@tty1.service.d
    echo '[Service]' > /etc/systemd/system/getty\@tty1.service.d/noclear.conf
    echo 'TTYVTDisallocate=no' >> /etc/systemd/system/getty\@tty1.service.d/noclear.conf
  • systemctl mask networking.service # we use ifplugd instead
    echo 'D /run/network 0755 root root' > /etc/tmpfiles.d/debian-networking.conf
    echo 'F /run/network/ifstate 0644 root root - lo=lo' >> /etc/tmpfiles.d/debian-networking.conf
  • aptitude purge acpid acpi-support-base # systemd-logind takes care of this
  • sed -i -e 's/^GRUB_CMDLINE_LINUX_DEFAULT="quiet"$/GRUB_CMDLINE_LINUX_DEFAULT="quiet panic=5"/g' /etc/default/grub && update-grub
  • systemctl mask keyboard-setup.service
    systemctl mask console-setup.service
    systemctl mask rc-local.service
  • aptitude --without-recommends install irqbalance
  • echo '/dev/mapper/raid-music        /mnt/music     ext4     rw,noatime     0       2' >> /etc/fstab
    mkdir -p /mnt/music
    mount /mnt/music
  • aptitude install xserver-xorg-video-intel xserver-xorg-input-evdev xserver-xorg-input-void
  • aptitude install xinit xinput evilwm xdotool x11vnc unclutter x11-xserver-utils
  • sed -i 's/START_UNCLUTTER="true"/START_UNCLUTTER="false"/g' /etc/default/unclutter
    sed -i -e 's/^use-ssh-agent$/#use-ssh-agent/g' /etc/X11/Xsession.options
  • dpkg-reconfigure x11-common – set “Users allowed to start the X server” to “Anybody”
  • aptitude install alsa-utils fonts-freefont-ttf
  • aptitude install exfat-fuse # for syncing music from large USB drives
  • adduser display # Name: Info Display (no password)
  • adduser spice # Name: Spice Listener (no password)
  • adduser spice dialout
  • sed -i -e 's/\(^spice:.*:\)\/home\/spice.*$/\1\/nonexistent:\/bin\/false/g' /etc/passwd
  • rm -r /home/spice
  • adduser tdobes audio
  • adduser tdobes video
  • adduser tdobes dialout
  • # Pull in backport of mpd: 0.19.1 in Jessie has an AAC stream decoding bug
    echo 'deb http://ftp.us.debian.org/debian/ jessie-backports main' > /etc/apt/sources.list.d/backports.list
    echo 'deb-src http://ftp.us.debian.org/debian/ jessie-backports main' >> /etc/apt/sources.list.d/backports.list
    
    echo 'Package: mpd' > /etc/apt/preferences.d/mpd-backport
    echo 'Pin: release a=jessie-backports' >> /etc/apt/preferences.d/mpd-backport
    echo 'Pin-Priority: 999' >> /etc/apt/preferences.d/mpd-backport
    
    aptitude update && aptitude forget-new
  • aptitude install mpd mpc ncmpc
  • aptitude --without-recommends install jackd # without recommends prevents pulling in Qt and firewire stuff; select “Yes” to realtime priority question
  • aptitude install icecast2 # select “No” to skip configuration; it seems to be broken and doesn't actually edit anything… WTF?
  • Configure icecast
    sed -i -e 's/\(<location>\).*\(<\/location>\)/\1Planetarium\2/g' -e 's/\(<admin>\).*\(<\/admin>\)/\1t.dobes@mcpstars.org\2/g' -e 's/\(<sources>\).*\(<\/sources>\)/\110\2/g' -e 's/\(<source-password>\).*\(<\/source-password>\)/\1**PASSWORD**\2/g' -e 's/\(<relay-password>\).*\(<\/relay-password>\)/\1**PASSWORD**\2/g' -e 's/\(<admin-password>\).*\(<\/admin-password>\)/\1**PASSWORD**\2/g' -e 's/\(<hostname>\).*\(<\/hostname>\)/\1music.mcp.lcl\2/g' /etc/icecast2/icecast.xml
    sed -i 's/ENABLE=false/ENABLE=true/g' /etc/default/icecast2
    systemctl restart icecast2
    systemctl enable icecast2
  • Set up JACK
    echo '[Unit]' > /etc/systemd/system/jackd.service
    echo 'Description=JACK Daemon' >> /etc/systemd/system/jackd.service
    echo >> /etc/systemd/system/jackd.service
    echo '[Service]' >> /etc/systemd/system/jackd.service
    echo 'ExecStart=/usr/bin/jackd -d alsa -d hw:M410 -r 44100' >> /etc/systemd/system/jackd.service
    echo 'User=mpd' >> /etc/systemd/system/jackd.service
    echo 'LimitRTPRIO=95' >> /etc/systemd/system/jackd.service # when running from a systemd service, it ignores /etc/security/limits.conf
    echo 'LimitMEMLOCK=infinity' >> /etc/systemd/system/jackd.service # when running from a systemd service, it ignores /etc/security/limits.conf
    echo 'Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/var/run/dbus/system_bus_socket' >> /etc/systemd/system/jackd.service # it wants to start a session-specific dbus; point it to the system one
    echo 'Restart=always' >> /etc/systemd/system/jackd.service
    echo 'RestartSec=1' >> /etc/systemd/system/jackd.service
    echo >> /etc/systemd/system/jackd.service
    echo '[Install]' >> /etc/systemd/system/jackd.service
    echo 'WantedBy=sound.target' >> /etc/systemd/system/jackd.service
    systemctl enable jackd.service
    
    # we're pointing to the system-level dbus, so we have to set permissions on it so that JACK can reserve the audio devices
    echo '<?xml version="1.0"?> <!--*-nxml-*-->' > /etc/dbus-1/system.d/mpd-audio-permissions.conf
    echo '<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"' >> /etc/dbus-1/system.d/mpd-audio-permissions.conf
    echo '        "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">' >> /etc/dbus-1/system.d/mpd-audio-permissions.conf
    echo >> /etc/dbus-1/system.d/mpd-audio-permissions.conf
    echo '<busconfig>' >> /etc/dbus-1/system.d/mpd-audio-permissions.conf
    echo '        <policy group="audio">' >> /etc/dbus-1/system.d/mpd-audio-permissions.conf
    echo '                <allow own="org.freedesktop.ReserveDevice1.Audio0"/>' >> /etc/dbus-1/system.d/mpd-audio-permissions.conf
    echo '                <allow own="org.freedesktop.ReserveDevice1.Audio1"/>' >> /etc/dbus-1/system.d/mpd-audio-permissions.conf
    echo '        </policy>' >> /etc/dbus-1/system.d/mpd-audio-permissions.conf
    echo '</busconfig>' >> /etc/dbus-1/system.d/mpd-audio-permissions.conf
    
    systemctl start jackd
  • # Set up MPD
    systemctl stop mpd.service mpd.socket ; systemctl disable mpd.service mpd.socket ; systemctl mask mpd.service mpd.socket
    rm /var/log/mpd/mpd.log /var/lib/mpd/state
    
    # this is a really terrible hack: wait for any NIC to come up
    # This is needed because apparently MPD can't find JACK and start playing until at least one NIC is up
    # Without running this before MPD, it fails to resume playing music at boot time
    # Bizarrely, we need this on startx too:
    # Something kills startx when the network comes up (WTH?).  This prevents a double launch.
    echo '#!/bin/sh' > /usr/local/bin/wait_network_up.sh
    echo >> /usr/local/bin/wait_network_up.sh
    echo 'echo -n waiting for any ethernet interface to come up' >> /usr/local/bin/wait_network_up.sh
    echo 'while ! ip link | grep "state UP" > /dev/null 2>/dev/null ; do' >> /usr/local/bin/wait_network_up.sh
    echo '  echo -n .' >> /usr/local/bin/wait_network_up.sh
    echo 'done' >> /usr/local/bin/wait_network_up.sh
    echo 'echo done!' >> /usr/local/bin/wait_network_up.sh
    chmod +x /usr/local/bin/wait_network_up.sh
    
    echo '[Unit]' > /etc/systemd/system/mpd\@.service
    echo 'Description=Music Player Daemon - %I' >> /etc/systemd/system/mpd\@.service
    echo 'After=network.target sound.target jackd.service icecast2.service' >> /etc/systemd/system/mpd\@.service
    echo >> /etc/systemd/system/mpd\@.service
    echo '[Service]' >> /etc/systemd/system/mpd\@.service
    echo 'ExecStart=/usr/bin/mpd --no-daemon /etc/mpd/%i.conf' >> /etc/systemd/system/mpd\@.service
    echo 'ExecStartPre=/usr/bin/jack_wait -w' >> /etc/systemd/system/mpd\@.service # ensures jackd is running before starting mpd
    echo 'ExecStartPre=/usr/local/bin/wait_network_up.sh' >> /etc/systemd/system/mpd\@.service # really terrible hack - apparently, MPD can't find jackd until at least one NIC is up
    echo 'User=mpd' >> /etc/systemd/system/mpd\@.service
    echo 'LimitMEMLOCK=infinity' >> /etc/systemd/system/mpd\@.service # to avoid jack_output error message
    echo >> /etc/systemd/system/mpd\@.service
    echo '# allow MPD to use real-time priority 50' >> /etc/systemd/system/mpd\@.service
    echo 'LimitRTPRIO=50' >> /etc/systemd/system/mpd\@.service
    echo 'LimitRTTIME=-1' >> /etc/systemd/system/mpd\@.service
    echo >> /etc/systemd/system/mpd\@.service
    echo 'Restart=always' >> /etc/systemd/system/mpd\@.service
    echo 'RestartSec=1' >> /etc/systemd/system/mpd\@.service
    echo >> /etc/systemd/system/mpd\@.service
    echo '[Install]' >> /etc/systemd/system/mpd\@.service
    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/mpd\@.service
    # don't enable yet - set up conf files first
    
    mkdir -p /etc/mpd
    
    sed -e 's/\(^music_directory[ \t]*"\).*$/\1\/mnt\/music\/jukebox"/g' -e 's/\(^log_file[ \t]*"\/var\/log\/mpd\).*$/\1\/output1.log"/g' -e 's/\(^pid_file[ \t]*"\/run\/mpd\).*$/\1\/output1.pid"/g' -e 's/\(^state_file[ \t]*"\/var\/lib\/mpd\).*$/\1\/output1.state"/g' -e 's/^#\(port[ \t]*"\).*$/\16601"/g' -e 's/^#\(password[ \t]*"\).*\(@.*$\)/\1**PASSWORD**\2/g' -e 's/^#\(default_permissions[ \t]*"\).*$/\1read"/g' -e 's/^#\(replaygain[ \t]*"\).*$/\1track"/g' /etc/mpd.conf > /etc/mpd/output1.conf
    sed -e 's/\(^music_directory[ \t]*"\).*$/\1\/mnt\/music\/jukebox"/g' -e 's/\(^log_file[ \t]*"\/var\/log\/mpd\).*$/\1\/output2.log"/g' -e 's/\(^pid_file[ \t]*"\/run\/mpd\).*$/\1\/output2.pid"/g' -e 's/\(^state_file[ \t]*"\/var\/lib\/mpd\).*$/\1\/output2.state"/g' -e 's/^#\(port[ \t]*"\).*$/\16602"/g' -e 's/^#\(password[ \t]*"\).*\(@.*$\)/\1**PASSWORD**\2/g' -e 's/^#\(default_permissions[ \t]*"\).*$/\1read"/g' -e 's/^#\(replaygain[ \t]*"\).*$/\1track"/g' /etc/mpd.conf > /etc/mpd/output2.conf
    sed -e 's/\(^music_directory[ \t]*"\).*$/\1\/mnt\/music\/jukebox"/g' -e 's/\(^log_file[ \t]*"\/var\/log\/mpd\).*$/\1\/output3.log"/g' -e 's/\(^pid_file[ \t]*"\/run\/mpd\).*$/\1\/output3.pid"/g' -e 's/\(^state_file[ \t]*"\/var\/lib\/mpd\).*$/\1\/output3.state"/g' -e 's/^#\(port[ \t]*"\).*$/\16603"/g' -e 's/^#\(password[ \t]*"\).*\(@.*$\)/\1**PASSWORD**\2/g' -e 's/^#\(default_permissions[ \t]*"\).*$/\1read"/g' -e 's/^#\(replaygain[ \t]*"\).*$/\1track"/g' /etc/mpd.conf > /etc/mpd/output3.conf
    sed -e 's/\(^music_directory[ \t]*"\).*$/\1\/mnt\/music\/jukebox"/g' -e 's/\(^log_file[ \t]*"\/var\/log\/mpd\).*$/\1\/output4.log"/g' -e 's/\(^pid_file[ \t]*"\/run\/mpd\).*$/\1\/output4.pid"/g' -e 's/\(^state_file[ \t]*"\/var\/lib\/mpd\).*$/\1\/output4.state"/g' -e 's/^#\(port[ \t]*"\).*$/\16604"/g' -e 's/^#\(password[ \t]*"\).*\(@.*$\)/\1**PASSWORD**\2/g' -e 's/^#\(default_permissions[ \t]*"\).*$/\1read"/g' -e 's/^#\(replaygain[ \t]*"\).*$/\1track"/g' /etc/mpd.conf > /etc/mpd/output4.conf
  • # in each of /etc/mpd/*.conf, comment out the existing audio_output lines and paste this stuff in:
    • /etc/mpd/output1.conf:
      audio_output {
        type "jack"
        name "mpd-output1"
        destination_ports "system:playback_1,system:playback_2"
        client_name "mpd-output1"
      }
      
      audio_output {
        type "shout"
        name "MCP Walk-in Music Stream"
        host "localhost"
        port "8000"
        mount "/walkin.ogg"
        password "**PASSWORD**"
        quality "6.0"
        format "44100:16:2"
        description "Walk-in Music (playing on output 1 by default... pushbutton 1 on AV distribution system)"
      }
    • /etc/mpd/output2.conf:
      audio_output {
        type "jack"
        name "mpd-output2"
        destination_ports "system:playback_3,system:playback_4"
        client_name "mpd-output2"
      }
      
      audio_output {
        type "shout"
        name "MCP Office Music Stream"
        host "localhost"
        port "8000"
        mount "/office.ogg"
        password "**PASSWORD**"
        quality "6.0"
        format "44100:16:2"
        description "Office Music (playing on output 2 by default... pushbutton 5 on AV distribution system)"
      }
    • /etc/mpd/output3.conf:
      audio_output {
        type "jack"
        name "mpd-output3"
        destination_ports "system:playback_5,system:playback_6"
        client_name "mpd-output3"
      }
      
      audio_output {
        type "shout"
        name "Output 3"
        host "localhost"
        port "8000"
        mount "/output3.ogg"
        password "**PASSWORD**"
        quality "6.0"
        format "44100:16:2"
        description "Output 3"
      }
    • /etc/mpd/output4.conf:
      audio_output {
        type "jack"
        name "mpd-output4"
        destination_ports "system:playback_7,system:playback_8"
        client_name "mpd-output4"
      }
      
      audio_output {
        type "shout"
        name "Output 4"
        host "localhost"
        port "8000"
        mount "/output4.ogg"
        password "**PASSWORD**"
        quality "6.0"
        format "44100:16:2"
        description "Output 4"
      }
  • Initial MPD database creation:
    systemctl start mpd@output1
    MPD_HOST="**PASSWORD**@localhost" MPD_PORT=6601 mpc update
    MPD_HOST="**PASSWORD**@localhost" MPD_PORT=6601 watch mpc
    # wait for database to finish updating
    
    systemctl restart mpd@output1
    systemctl start mpd@output2 mpd@output3 mpd@output4
    
    # systemctl enable mpd\@output1.service # doesn't work on old systemd releases
    ln -s /etc/systemd/system/mpd\@.service /etc/systemd/system/multi-user.target.wants/mpd\@output1.service
    # systemctl enable mpd\@output2.service # doesn't work on old systemd releases
    ln -s /etc/systemd/system/mpd\@.service /etc/systemd/system/multi-user.target.wants/mpd\@output2.service
    # systemctl enable mpd\@output3.service # doesn't work on old systemd releases
    ln -s /etc/systemd/system/mpd\@.service /etc/systemd/system/multi-user.target.wants/mpd\@output3.service
    # systemctl enable mpd\@output4.service # doesn't work on old systemd releases
    ln -s /etc/systemd/system/mpd\@.service /etc/systemd/system/multi-user.target.wants/mpd\@output4.service
  • Ability to save streams:
    echo '#!/bin/sh' > /usr/local/bin/mpd_state.sh
    echo >> /usr/local/bin/mpd_state.sh
    echo 'case "$1" in' >> /usr/local/bin/mpd_state.sh
    echo '  "output1") ;;' >> /usr/local/bin/mpd_state.sh
    echo '  "output2") ;;' >> /usr/local/bin/mpd_state.sh
    echo '  "output3") ;;' >> /usr/local/bin/mpd_state.sh
    echo '  "output4") ;;' >> /usr/local/bin/mpd_state.sh
    echo '  *)' >> /usr/local/bin/mpd_state.sh
    echo '    echo "ERROR: Invalid instance."' >> /usr/local/bin/mpd_state.sh
    echo '    exit 0' >> /usr/local/bin/mpd_state.sh
    echo '    ;;' >> /usr/local/bin/mpd_state.sh
    echo 'esac' >> /usr/local/bin/mpd_state.sh
    echo >> /usr/local/bin/mpd_state.sh
    echo 'case "$2" in' >> /usr/local/bin/mpd_state.sh
    echo '  "save")' >> /usr/local/bin/mpd_state.sh
    echo '    systemctl stop mpd@$1.service' >> /usr/local/bin/mpd_state.sh
    echo '    cp -a /var/lib/mpd/$1.state /var/lib/mpd/$1.state.saved' >> /usr/local/bin/mpd_state.sh
    echo '    systemctl start mpd@$1.service' >> /usr/local/bin/mpd_state.sh
    echo '    ;;' >> /usr/local/bin/mpd_state.sh
    echo '  "restore")' >> /usr/local/bin/mpd_state.sh
    echo '    systemctl stop mpd@$1.service' >> /usr/local/bin/mpd_state.sh
    echo '    cp -a /var/lib/mpd/$1.state.saved /var/lib/mpd/$1.state' >> /usr/local/bin/mpd_state.sh
    echo '    systemctl start mpd@$1.service' >> /usr/local/bin/mpd_state.sh
    echo '    ;;' >> /usr/local/bin/mpd_state.sh
    echo '  *)' >> /usr/local/bin/mpd_state.sh
    echo '    echo "ERROR: Invalid action."' >> /usr/local/bin/mpd_state.sh
    echo '    exit 0' >> /usr/local/bin/mpd_state.sh
    echo '    ;;' >> /usr/local/bin/mpd_state.sh
    echo 'esac' >> /usr/local/bin/mpd_state.sh
    chmod +x /usr/local/bin/mpd_state.sh
    
    aptitude install sudo
    
    echo >> /etc/sudoers
    echo 'www-data ALL=(ALL:ALL) NOPASSWD:/usr/local/bin/mpd_state.sh' >> /etc/sudoers
  • Set up live stream from theater:
    aptitude install darkice
    sed -i -e 's/RUN=no/RUN=yes/g' -e 's/USER=nobody/USER=mpd/g' /etc/default/darkice
    
    echo '[general]' > /etc/darkice.cfg
    echo 'duration        = 0         # duration of encoding, in seconds. 0 means forever' >> /etc/darkice.cfg
    echo 'bufferSecs      = 2         # size of internal slip buffer, in seconds' >> /etc/darkice.cfg
    echo 'reconnect       = yes       # reconnect to the server(s) if disconnected' >> /etc/darkice.cfg
    echo >> /etc/darkice.cfg
    echo '[input]' >> /etc/darkice.cfg
    echo 'device          = jack_auto' >> /etc/darkice.cfg
    echo 'sampleRate      = 44100' >> /etc/darkice.cfg
    echo 'bitsPerSample   = 16' >> /etc/darkice.cfg
    echo 'channel         = 2' >> /etc/darkice.cfg
    echo >> /etc/darkice.cfg
    echo '[icecast2-0]' >> /etc/darkice.cfg
    echo 'bitrateMode     = vbr' >> /etc/darkice.cfg
    echo 'format          = vorbis' >> /etc/darkice.cfg
    echo 'quality         = 0.6' >> /etc/darkice.cfg
    echo 'server          = localhost' >> /etc/darkice.cfg
    echo 'port            = 8000' >> /etc/darkice.cfg
    echo 'password        = **PASSWORD**' >> /etc/darkice.cfg
    echo 'mountPoint      = theater.ogg' >> /etc/darkice.cfg
    echo 'name            = MCP Live Theater Stream' >> /etc/darkice.cfg
    echo 'description     = Live streaming audio from the theater sound system (pushbutton 2 on AV distribution system)' >> /etc/darkice.cfg
    echo 'public          = yes' >> /etc/darkice.cfg
    
    echo '[Unit]' > /etc/systemd/system/darkice.service
    echo 'Description=DarkIce Live Audio Streamer' >> /etc/systemd/system/darkice.service
    echo 'After=sound.target jackd.service icecast2.service' >> /etc/systemd/system/darkice.service
    echo >> /etc/systemd/system/darkice.service
    echo '[Service]' >> /etc/systemd/system/darkice.service
    echo 'ExecStart=/usr/bin/darkice' >> /etc/systemd/system/darkice.service
    echo 'ExecStartPre=/usr/bin/jack_wait -w' >> /etc/systemd/system/darkice.service # ensures jackd is running before starting darkice
    echo 'User=mpd' >> /etc/systemd/system/darkice.service
    echo 'LimitRTPRIO=95' >> /etc/systemd/system/darkice.service # when running from a systemd service, it ignores /etc/security/limits.conf
    echo 'LimitMEMLOCK=infinity' >> /etc/systemd/system/darkice.service # when running from a systemd service, it ignores /etc/security/limits.conf
    echo >> /etc/systemd/system/darkice.service
    echo 'Restart=always' >> /etc/systemd/system/darkice.service
    echo 'RestartSec=1' >> /etc/systemd/system/darkice.service
    echo >> /etc/systemd/system/darkice.service
    echo '[Install]' >> /etc/systemd/system/darkice.service
    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/darkice.service
    
    systemctl enable darkice
    systemctl start darkice
  • Turn up sound card outputs:
    amixer -c M410 sset 'DAC',0 255
    amixer -c M410 sset 'DAC',1 255
    amixer -c M410 sset 'DAC',2 255
    amixer -c M410 sset 'DAC',3 255
    amixer -c M410 sset 'DAC',4 255
    amixer -c M410 sset 'DAC',5 255
    amixer -c M410 sset 'DAC',6 255
    amixer -c M410 sset 'DAC',7 255
    # not sure what the ADC channels are supposed to do... but this appears to be unnecessary and there are apparently crossed wires between these and DAC2+3
    #amixer -c M410 sset 'ADC',0 127
    #amixer -c M410 sset 'ADC',1 127
  • echo '0 6 * * * root /mnt/music/cycler/next-item.sh' > /etc/cron.d/walk-in_music_rotate
  • aptitude install samba winbind libnss-winbind libpam-winbind
  • mv /etc/samba/smb.conf /etc/samba/smb.conf.orig
  • Paste in /etc/samba/smb.conf:
    [global]
      security = ADS
      workgroup = MCP
      realm = MCP.LCL
      password server = ad1.mcp.lcl ad2.mcp.lcl *
      server string = Music Server
      idmap config MCP:backend = rid
      idmap config MCP:base_rid = 0
      idmap config MCP:range = 10000-20000
      idmap config *:backend = tdb
      idmap config *:range = 9000-9999
      winbind separator = +
      template homedir = /home/%U
    
      # disable shell logins by default
      template shell = /bin/false
      # don't try to become browse master
      local master = no
      # don't use DNS for NetBIOS lookups
      dns proxy = no
      # allow enumeration of users, groups (i.e. getent passwd; getent group)
      winbind enum users = yes
      winbind enum groups = yes
      # don't require domain name to login
      winbind use default domain = yes
      # cache login credentials
      winbind offline logon = true
      # don't flood DNS servers with useless queries (see manpage; DC lookup still uses DNS)... also disable broadcast resolution
      # name resolve order = wins
      name resolve order = wins host
      # manpage says this shouldn't be necessary
      ;auth methods = winbind
      # ensure that we follow PAM rules (hopefully this will enforce home directory auto-creation)
      obey pam restrictions = yes
      # no broadcast announcements (we're not using OS/2)
      lm announce = no
    
      # disable print server
      load printers = no
      show add printer wizard = no
      disable spoolss = yes
    
      # logging
      log file = /var/log/samba/log.%m
      # cap logfiles at 1MB
      max log size = 1000
      log level = 2
      # don't send anything to syslog
      syslog = 0
      # mail the admin if we crash
      panic action = /usr/share/samba/panic-action %d
    
      # performance tweaks
      socket options = TCP_NODELAY IPTOS_LOWDELAY SO_KEEPALIVE
      use sendfile = yes
      max protocol = SMB2
      strict allocate = yes
    
      # obtain permissions from parent dir
      inherit permissions = yes
      # drop connections with no open files after 15 minutes of inactivity
      deadtime = 15
      # allow Windows to handle inheritance correctly
      map acl inherit = yes
    
      # hide Apple-specific files from Windows, but delete them if we're deleting a folder
      veto files = /.AppleDesktop/Network Trash Folder/TheVolumeSettingsFolder/.AppleDouble/.AppleDB/.DS_Store/.TemporaryItems/
      delete veto files = yes
    
      create mask = 0664
      directory mask = 0775
    
      # this wreaks all sorts of havoc with symlinks
      unix extensions = no
    
      # emulate DOS attributes using xattr
      store dos attributes = yes
    
    [music]
      comment = Music Storage
      path = /mnt/music
      writable = yes
      hide files = /lost+found/
    
    [web]
      comment = Web Root
      path = /var/www
      writable = yes
      valid users = @"MCP+domain admins", @"MCP+adults"
  • Set up samba server:
    sed -i -e 's/^passwd:.*compat$/& winbind/g' -e 's/^group:.*compat$/& winbind/g' /etc/nsswitch.conf
    
    net ads join -U tdobes
    # the DNS update error is normal
    
    systemctl restart winbind
    # verify that users show up in "wbinfo -u" and "getent passwd"
    systemctl restart nmbd smbd
  • aptitude install etherwake fping
  • chmod u+s /usr/sbin/etherwake
  • aptitude install python-serial picocom
  • sed -i 's/GRUB_CMDLINE_LINUX=""/GRUB_CMDLINE_LINUX="8250.nr_uarts=8"/g' /etc/default/grub && update-grub # needed so that all eight serial ports on the PCI add-in card show up as /dev/ttyS* device nodes
  • Copy over /opt/spice_parser
  • Set up spice responder:
    echo '[Unit]' > /etc/systemd/system/spice_parser.service
    echo 'Description=Spice Responder' >> /etc/systemd/system/spice_parser.service
    echo 'After=network.target' >> /etc/systemd/system/spice_parser.service
    echo >> /etc/systemd/system/spice_parser.service
    echo '[Service]' >> /etc/systemd/system/spice_parser.service
    echo 'ExecStart=/opt/spice_parser/spice_recv.py' >> /etc/systemd/system/spice_parser.service
    echo 'WorkingDirectory=/opt/spice_parser' >> /etc/systemd/system/spice_parser.service
    echo 'User=spice' >> /etc/systemd/system/spice_parser.service
    echo 'Environment=PYTHONUNBUFFERED=1' >> /etc/systemd/system/spice_parser.service
    echo >> /etc/systemd/system/spice_parser.service
    echo 'Restart=always' >> /etc/systemd/system/spice_parser.service
    echo 'RestartSec=1' >> /etc/systemd/system/spice_parser.service
    echo >> /etc/systemd/system/spice_parser.service
    echo '[Install]' >> /etc/systemd/system/spice_parser.service
    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/spice_parser.service
    
    systemctl enable spice_parser
    systemctl start spice_parser
  • Set up mount of \\weather UNC share:
    aptitude install cifs-utils
    echo >> /etc/fstab
    echo '//oldweather/weather-info /mnt/weather_data cifs _netdev,ro,uid=root,credentials=/root/weather-cifspw,domain=OLDWEATHER 0 0' >> /etc/fstab
    
    echo 'username=weather' > /root/weather-cifspw
    echo 'password=**PASSWORD**' >> /root/weather-cifspw
    
    mkdir -p /mnt/weather_data
    mount /mnt/weather_data
  • aptitude install apache2 php5-fpm
  • aptitude --without-recommends install vncsnapshot libjpeg-turbo-progs
  • x11vnc -storepasswd **PASSWORD** /var/www/vnc-passwd
    chown root:www-data /var/www/vnc-passwd
    chmod 0640 /var/www/vnc-passwd
  • a2enmod proxy_fcgi
  • echo 'ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/var/run/php5-fpm.sock|fcgi://127.0.0.1/var/www/html/ disablereuse=off' > /etc/apache2/mods-enabled/proxy-php5-fpm.conf # note: apache docs talk about enablereuse=on, but apparently that was added in 2.4.11 and jessie is on 2.4.10; supposedly this does the same thing? # does not pass through special characters (e.g. spaces) properly
  • # This apache 2.4/php-fpm configuration works properly with paths including spaces (unlike the deleted one above). See https://wiki.archlinux.org/index.php/Apache_HTTP_Server#Using_php-fpm_and_mod_proxy_fcgi and comments on http://php.net/manual/en/features.http-auth.php about SetEnvIf line
    echo '<FilesMatch \.php$>' > /etc/apache2/mods-enabled/proxy-php5-fpm.conf
    echo '  SetHandler "proxy:unix:/var/run/php5-fpm.sock|fcgi://localhost/"' >> /etc/apache2/mods-enabled/proxy-php5-fpm.conf
    echo '  SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0' >> /etc/apache2/mods-enabled/proxy-php5-fpm.conf # gets apache to pass http auth credentials to PHP
    echo '</FilesMatch>' >> /etc/apache2/mods-enabled/proxy-php5-fpm.conf
    echo '<Proxy "fcgi://localhost/" disablereuse=off max=10>' >> /etc/apache2/mods-enabled/proxy-php5-fpm.conf
    echo '</Proxy>' >> /etc/apache2/mods-enabled/proxy-php5-fpm.conf
  • # custom error pages for information channel:
    echo '<Directory "/var/www/html/hires">' > /etc/apache2/sites-enabled/error-pages.conf
    echo '  ErrorDocument 403 /hires/errors/403.html' >> /etc/apache2/sites-enabled/error-pages.conf
    echo '  ErrorDocument 404 /hires/errors/404.html' >> /etc/apache2/sites-enabled/error-pages.conf
    echo '  ErrorDocument 500 /hires/errors/500.html' >> /etc/apache2/sites-enabled/error-pages.conf
    echo '  ErrorDocument 503 /hires/errors/503.html' >> /etc/apache2/sites-enabled/error-pages.conf
    echo '</Directory>' >> /etc/apache2/sites-enabled/error-pages.conf
    echo '<Directory "/var/www/html/internal/top-right">' >> /etc/apache2/sites-enabled/error-pages.conf
    echo '  ErrorDocument 403 /internal/top-right/errors/403.html' >> /etc/apache2/sites-enabled/error-pages.conf
    echo '  ErrorDocument 404 /internal/top-right/errors/404.html' >> /etc/apache2/sites-enabled/error-pages.conf
    echo '  ErrorDocument 500 /internal/top-right/errors/500.html' >> /etc/apache2/sites-enabled/error-pages.conf
    echo '  ErrorDocument 503 /internal/top-right/errors/503.html' >> /etc/apache2/sites-enabled/error-pages.conf
    echo '</Directory>' >> /etc/apache2/sites-enabled/error-pages.conf
    echo '<Directory "/var/www/html/info_mcp">' >> /etc/apache2/sites-enabled/error-pages.conf
    echo '  ErrorDocument 404 /info_mcp/missing.php' >> /etc/apache2/sites-enabled/error-pages.conf
    echo '</Directory>' >> /etc/apache2/sites-enabled/error-pages.conf
  • # disable client-side caching (at least without checking source) for information channel and morning briefing:
    echo '<Directory "/var/www/html/hires">' > /etc/apache2/sites-enabled/cache_control.conf
    echo '  Header set Cache-Control "no-cache"' >> /etc/apache2/sites-enabled/cache_control.conf
    echo '</Directory>' >> /etc/apache2/sites-enabled/cache_control.conf
    echo >> /etc/apache2/sites-enabled/cache_control.conf
    echo '<Directory "/var/www/html/internal">' > /etc/apache2/sites-enabled/cache_control.conf
    echo '  Header set Cache-Control "no-cache"' >> /etc/apache2/sites-enabled/cache_control.conf
    echo '</Directory>' >> /etc/apache2/sites-enabled/cache_control.conf
    echo >> /etc/apache2/sites-enabled/cache_control.conf
    echo '<Directory "/var/www/html/info_mcp">' >> /etc/apache2/sites-enabled/cache_control.conf
    echo '  Header set Cache-Control "no-cache"' >> /etc/apache2/sites-enabled/cache_control.conf
    echo '</Directory>' >> /etc/apache2/sites-enabled/cache_control.conf
    echo >> /etc/apache2/sites-enabled/cache_control.conf
    echo '<Directory "/var/www/html/morning_briefing">' >> /etc/apache2/sites-enabled/cache_control.conf
    echo '  Header set Cache-Control "no-cache"' >> /etc/apache2/sites-enabled/cache_control.conf
    echo '</Directory>' >> /etc/apache2/sites-enabled/cache_control.conf
  • systemctl restart apache2
  • rm /var/www/html/index.html
  • copy over webroot into /var/www/html/
  • adduser www-data dialout && systemctl restart php5-fpm
  • Set up X11:
echo '#!/bin/sh' > /usr/local/bin/display-xsession.sh
echo >> /usr/local/bin/display-xsession.sh
echo 'pkill -9 evilwm' >> /usr/local/bin/display-xsession.sh
echo 'pkill -9 x11vnc' >> /usr/local/bin/display-xsession.sh
echo >> /usr/local/bin/display-xsession.sh
echo 'xrandr --output HDMI1 --mode 1920x1080 --output HDMI2 --mode 1920x1080 --right-of HDMI1' >> /usr/local/bin/display-xsession.sh
echo >> /usr/local/bin/display-xsession.sh
echo 'x11vnc -rfbport 5900 -q -usepw -N -ncache 0 -shared -forever &' >> /usr/local/bin/display-xsession.sh
echo 'x11vnc -clip xinerama0 -rfbport 5901 -q -usepw -N -ncache 0 -shared -forever &' >> /usr/local/bin/display-xsession.sh
echo 'x11vnc -clip xinerama1 -rfbport 5902 -q -usepw -N -ncache 0 -shared -forever &' >> /usr/local/bin/display-xsession.sh
echo >> /usr/local/bin/display-xsession.sh
echo 'xset s off #disable screensaver' >> /usr/local/bin/display-xsession.sh
echo 'xset -dpms #disable automatic power saving' >> /usr/local/bin/display-xsession.sh
echo 'unclutter -grab -idle 2 & #daemon to auto-hide mouse' >> /usr/local/bin/display-xsession.sh
echo >> /usr/local/bin/display-xsession.sh
echo '#SHELL=/bin/bash xterm &' >> /usr/local/bin/display-xsession.sh
echo >> /usr/local/bin/display-xsession.sh
echo "# for some reason, this doesn't work unless you do it twice:" >> /usr/local/bin/display-xsession.sh
echo 'systemd-notify READY=1' >> /usr/local/bin/display-xsession.sh
echo 'systemd-notify READY=1' >> /usr/local/bin/display-xsession.sh
echo >> /usr/local/bin/display-xsession.sh
echo "exec evilwm -fn '*-clean-*'" >> /usr/local/bin/display-xsession.sh
chmod +x /usr/local/bin/display-xsession.sh
ln -s /usr/local/bin/display-xsession.sh /home/display/.xsession

echo '[Unit]' > /etc/systemd/system/startx\@.service
echo 'Description=Start Xorg for %I' >> /etc/systemd/system/startx\@.service
echo >> /etc/systemd/system/startx\@.service
echo '[Service]' >> /etc/systemd/system/startx\@.service
echo 'ExecStart=-/usr/bin/startx -- -layout infodisplay -nolisten tcp -sharevts' >> /etc/systemd/system/startx\@.service # when you specify additional Xorg parameters, you have to include "-nolisten tcp" since it overrides the Debian defaults
echo 'ExecStopPost=-/usr/bin/pkill -9 -U %I evilwm' >> /etc/systemd/system/startx\@.service
echo 'ExecStartPre=/usr/local/bin/wait_network_up.sh' >> /etc/systemd/system/startx\@.service # terrible hack to prevent double-start of X (something kills it when the network comes up - WTH?)
echo 'User=%I' >> /etc/systemd/system/startx\@.service
echo 'Type=notify' >> /etc/systemd/system/startx\@.service
echo 'NotifyAccess=all' >> /etc/systemd/system/startx\@.service
echo 'Restart=always' >> /etc/systemd/system/startx\@.service
echo 'RestartSec=1' >> /etc/systemd/system/startx\@.service
echo >> /etc/systemd/system/startx\@.service
echo '[Install]' >> /etc/systemd/system/startx\@.service
echo 'WantedBy=multi-user.target' >> /etc/systemd/system/startx\@.service
# systemctl enable startx\@display.service # doesn't work on old systemd releases
ln -s /etc/systemd/system/startx\@.service /etc/systemd/system/multi-user.target.wants/startx\@display.service

echo '[Unit]' > /etc/systemd/system/xterm.service
echo 'Description=xterm for troubleshooting' >> /etc/systemd/system/xterm.service
echo 'After=startx@display.service' >> /etc/systemd/system/xterm.service
echo 'Requires=startx@display.service' >> /etc/systemd/system/xterm.service
echo >> /etc/systemd/system/xterm.service
echo '[Service]' >> /etc/systemd/system/xterm.service
echo 'ExecStart=-/usr/bin/xterm' >> /etc/systemd/system/xterm.service
echo 'User=display' >> /etc/systemd/system/xterm.service
echo 'Environment=DISPLAY=:0' >> /etc/systemd/system/xterm.service
  • mkdir ~display/.vnc
    x11vnc -storepasswd **PASSWORD** ~display/.vnc/passwd
    chown -R display:display ~display/.vnc
    chmod 0600 ~display/.vnc/passwd
  • Paste into /etc/X11/xorg.conf:
    Section "ServerLayout"
      Identifier     "infodisplay"
      Screen      0  "infodisplay-screen" 0 0
      InputDevice    "Void" "CorePointer"
      InputDevice    "Void" "CoreKeyboard"
      Option         "AutoAddDevices" "Off"
    EndSection
    
    Section "InputDevice"
      Identifier  "Void"
      Driver      "void"
    EndSection
    
    Section "Monitor"
      Identifier   "HDMI1"
      ModeLine "1080p" 148.35 1920 2008 2052 2200 1080 1084 1089 1125 +HSync +VSync
      Option "PreferredMode" "1080p"
    EndSection
    
    Section "Monitor"
      Identifier "HDMI2"
      Option "RightOf" "HDMI1"
      ModeLine "1080p" 148.35 1920 2008 2052 2200 1080 1084 1089 1125 +HSync +VSync
      Option "PreferredMode" "1080p"
    EndSection
    
    Section "Device"
      Identifier  "Intel"
      Driver      "intel"
      BusID       "PCI:0:2:0"
      Option      "Monitor-HDMI1" "HDMI1"
      Option      "Monitor-HDMI2" "HDMI2"
    EndSection
    
    Section "Screen"
      Identifier "infodisplay-screen"
      Device     "Intel"
      #Monitor specified in Device section
      DefaultDepth 24
      SubSection "Display"
        Modes "1920x1080"
        Virtual 3840 1080
        Depth 24
      EndSubSection
    EndSection
  • systemctl start startx@display
  • aptitude install ttf-mscorefonts-installer ttf-bitstream-vera ttf-dejavu # for displaying information channel
  • aptitude install python-pyside.qtwebkit
    
    echo '#!/usr/bin/env python' > /usr/local/bin/simplebrowser.py
    echo >> /usr/local/bin/simplebrowser.py
    echo 'import sys' >> /usr/local/bin/simplebrowser.py
    echo 'from PySide.QtCore import *' >> /usr/local/bin/simplebrowser.py
    echo 'from PySide.QtGui import *' >> /usr/local/bin/simplebrowser.py
    echo 'from PySide.QtWebKit import *' >> /usr/local/bin/simplebrowser.py
    echo >> /usr/local/bin/simplebrowser.py
    echo 'app = QApplication(sys.argv)' >> /usr/local/bin/simplebrowser.py
    echo >> /usr/local/bin/simplebrowser.py
    echo 'if len(sys.argv) >= 2:' >> /usr/local/bin/simplebrowser.py
    echo '  url = QUrl(sys.argv[1])' >> /usr/local/bin/simplebrowser.py
    echo 'else:' >> /usr/local/bin/simplebrowser.py
    echo "  url = QUrl('http://www.google.com/')" >> /usr/local/bin/simplebrowser.py
    echo >> /usr/local/bin/simplebrowser.py
    echo 'web = QWebView()' >> /usr/local/bin/simplebrowser.py
    echo 'if len(sys.argv) >= 3:' >> /usr/local/bin/simplebrowser.py
    echo '  web.setWindowTitle(sys.argv[2])' >> /usr/local/bin/simplebrowser.py
    echo 'if len(sys.argv) >= 7:' >> /usr/local/bin/simplebrowser.py
    echo '  web.setGeometry(int(sys.argv[5]), int(sys.argv[6]), int(sys.argv[3]), int(sys.argv[4]))' >> /usr/local/bin/simplebrowser.py
    echo 'web.load(url)' >> /usr/local/bin/simplebrowser.py
    echo 'web.show()' >> /usr/local/bin/simplebrowser.py
    echo >> /usr/local/bin/simplebrowser.py
    echo 'sys.exit(app.exec_())' >> /usr/local/bin/simplebrowser.py
    chmod +x /usr/local/bin/simplebrowser.py
    
    # NOTE: If you're fighting a javascript problem, add this line after creating the QWebView:
    # web.settings().globalSettings().setAttribute(QWebSettings.WebAttribute.DeveloperExtrasEnabled, True)
  • Set up infodisplay web browser stuff:
    echo '#!/bin/sh' > /usr/local/bin/browser1.sh
    echo >> /usr/local/bin/browser1.sh
    echo 'echo -n waiting for local web server startup' >> /usr/local/bin/browser1.sh
    echo -n "while netstat -lnt | awk '" >> /usr/local/bin/browser1.sh
    echo -n '$4 ~ /:80$/ {exit 1}' >> /usr/local/bin/browser1.sh
    echo "'; do" >> /usr/local/bin/browser1.sh
    echo '  echo -n .' >> /usr/local/bin/browser1.sh
    echo 'done' >> /usr/local/bin/browser1.sh
    echo 'echo done!' >> /usr/local/bin/browser1.sh
    echo >> /usr/local/bin/browser1.sh
    echo 'move_browser.sh 1 &' >> /usr/local/bin/browser1.sh
    echo >> /usr/local/bin/browser1.sh
    echo '# start simplebrowser' >> /usr/local/bin/browser1.sh
    echo 'exec nice -n 1 simplebrowser.py http://music/hires/?channel=1 browser1 1920 1080 0 0' >> /usr/local/bin/browser1.sh
    chmod +x /usr/local/bin/browser1.sh
    
    echo '#!/bin/sh' > /usr/local/bin/browser2.sh
    echo >> /usr/local/bin/browser2.sh
    echo 'echo -n waiting for local web server startup' >> /usr/local/bin/browser2.sh
    echo -n "while netstat -lnt | awk '" >> /usr/local/bin/browser2.sh
    echo -n '$4 ~ /:80$/ {exit 1}' >> /usr/local/bin/browser2.sh
    echo "'; do" >> /usr/local/bin/browser2.sh
    echo '  echo -n .' >> /usr/local/bin/browser2.sh
    echo 'done' >> /usr/local/bin/browser2.sh
    echo 'echo done!' >> /usr/local/bin/browser2.sh
    echo >> /usr/local/bin/browser2.sh
    echo 'move_browser.sh 2 &' >> /usr/local/bin/browser2.sh
    echo >> /usr/local/bin/browser2.sh
    echo '# start simplebrowser' >> /usr/local/bin/browser2.sh
    echo 'exec nice -n 1 simplebrowser.py http://music/internal/ browser2 1920 1080 1920 0' >> /usr/local/bin/browser2.sh
    chmod +x /usr/local/bin/browser2.sh
    
    echo '#!/bin/sh' > /usr/local/bin/move_browser.sh
    echo >> /usr/local/bin/move_browser.sh
    echo 'case "$1" in' >> /usr/local/bin/move_browser.sh
    echo '  "1")' >> /usr/local/bin/move_browser.sh
    echo '    POS_X=0' >> /usr/local/bin/move_browser.sh
    echo '    POS_Y=0' >> /usr/local/bin/move_browser.sh
    echo '    SIZE_X=1920' >> /usr/local/bin/move_browser.sh
    echo '    SIZE_Y=1080' >> /usr/local/bin/move_browser.sh
    echo '    ;;' >> /usr/local/bin/move_browser.sh
    echo '  "2")' >> /usr/local/bin/move_browser.sh
    echo '    POS_X=1920' >> /usr/local/bin/move_browser.sh
    echo '    POS_Y=0' >> /usr/local/bin/move_browser.sh
    echo '    SIZE_X=1920' >> /usr/local/bin/move_browser.sh
    echo '    SIZE_Y=1080' >> /usr/local/bin/move_browser.sh
    echo '    ;;' >> /usr/local/bin/move_browser.sh
    echo '  *)' >> /usr/local/bin/move_browser.sh
    echo '    echo "WARNING: Unknown display; not moving browser window."' >> /usr/local/bin/move_browser.sh
    echo '    exit 0' >> /usr/local/bin/move_browser.sh
    echo '    ;;' >> /usr/local/bin/move_browser.sh
    echo 'esac' >> /usr/local/bin/move_browser.sh
    echo >> /usr/local/bin/move_browser.sh
    echo 'WINDOW_ID=' >> /usr/local/bin/move_browser.sh
    echo 'while [ -z "$WINDOW_ID" ]; do' >> /usr/local/bin/move_browser.sh
    echo -n '  WINDOW_ID=`xwininfo -name browser$1 2>/dev/null | grep "Window id" | awk ' >> /usr/local/bin/move_browser.sh
    echo -n "'" >> /usr/local/bin/move_browser.sh
    echo -n '{print $4}' >> /usr/local/bin/move_browser.sh
    echo -n "'" >> /usr/local/bin/move_browser.sh
    echo '`' >> /usr/local/bin/move_browser.sh
    echo 'done' >> /usr/local/bin/move_browser.sh
    echo >> /usr/local/bin/move_browser.sh
    echo 'xdotool set_window --overrideredirect 1 $WINDOW_ID windowunmap $WINDOW_ID windowmap $WINDOW_ID' >> /usr/local/bin/move_browser.sh
    echo >> /usr/local/bin/move_browser.sh
    echo "# try this three times to ensure window doesn't move again:" >> /usr/local/bin/move_browser.sh
    echo 'for i in $(seq 1 3); do' >> /usr/local/bin/move_browser.sh
    echo '  CUR_POS=' >> /usr/local/bin/move_browser.sh
    echo '  CUR_SIZE=' >> /usr/local/bin/move_browser.sh
    echo '  while [ "${POS_X},${POS_Y}" != "$CUR_POS" -o "${SIZE_X}x${SIZE_Y}" != "$CUR_SIZE" ]; do' >> /usr/local/bin/move_browser.sh
    echo '    xdotool windowmove $WINDOW_ID $POS_X $POS_Y windowsize $WINDOW_ID $SIZE_X $SIZE_Y' >> /usr/local/bin/move_browser.sh
    echo '    sleep 1' >> /usr/local/bin/move_browser.sh
    echo -n '    CUR_POS=`xdotool getwindowgeometry $WINDOW_ID | grep Position | awk ' >> /usr/local/bin/move_browser.sh
    echo -n "'" >> /usr/local/bin/move_browser.sh
    echo -n '{print $2}' >> /usr/local/bin/move_browser.sh
    echo -n "'" >> /usr/local/bin/move_browser.sh
    echo '`' >> /usr/local/bin/move_browser.sh
    echo -n '    CUR_SIZE=`xdotool getwindowgeometry $WINDOW_ID | grep Geometry | awk ' >> /usr/local/bin/move_browser.sh
    echo -n "'" >> /usr/local/bin/move_browser.sh
    echo -n '{print $2}' >> /usr/local/bin/move_browser.sh
    echo -n "'" >> /usr/local/bin/move_browser.sh
    echo '`' >> /usr/local/bin/move_browser.sh
    echo '  done' >> /usr/local/bin/move_browser.sh
    echo '  sleep 2' >> /usr/local/bin/move_browser.sh
    echo 'done' >> /usr/local/bin/move_browser.sh
    chmod +x /usr/local/bin/move_browser.sh
    
    echo '[Unit]' > /etc/systemd/system/browser1.service
    echo 'Description=Web Browser 1' >> /etc/systemd/system/browser1.service
    echo 'After=startx@display.service apache2.service php5-fpm.service network.target' >> /etc/systemd/system/browser1.service
    echo 'Requires=startx@display.service' >> /etc/systemd/system/browser1.service
    echo >> /etc/systemd/system/browser1.service
    echo '[Service]' >> /etc/systemd/system/browser1.service
    echo 'ExecStart=/usr/local/bin/browser1.sh' >> /etc/systemd/system/browser1.service
    echo 'User=display' >> /etc/systemd/system/browser1.service
    echo 'Environment=DISPLAY=:0' >> /etc/systemd/system/browser1.service
    echo 'Restart=always' >> /etc/systemd/system/browser1.service
    echo 'RestartSec=1' >> /etc/systemd/system/browser1.service
    echo >> /etc/systemd/system/browser1.service
    echo '[Install]' >> /etc/systemd/system/browser1.service
    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/browser1.service
    systemctl enable browser1.service
    
    echo '[Unit]' > /etc/systemd/system/browser2.service
    echo 'Description=Web Browser 2' >> /etc/systemd/system/browser2.service
    echo 'After=startx@display.service apache2.service php5-fpm.service network.target' >> /etc/systemd/system/browser2.service
    echo 'Requires=startx@display.service' >> /etc/systemd/system/browser2.service
    echo >> /etc/systemd/system/browser2.service
    echo '[Service]' >> /etc/systemd/system/browser2.service
    echo 'ExecStart=/usr/local/bin/browser2.sh' >> /etc/systemd/system/browser2.service
    echo 'User=display' >> /etc/systemd/system/browser2.service
    echo 'Environment=DISPLAY=:0' >> /etc/systemd/system/browser2.service
    echo 'Restart=always' >> /etc/systemd/system/browser2.service
    echo 'RestartSec=1' >> /etc/systemd/system/browser2.service
    echo >> /etc/systemd/system/browser2.service
    echo '[Install]' >> /etc/systemd/system/browser2.service
    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/browser2.service
    systemctl enable browser2.service
    
    systemctl start browser1 browser2
  • aptitude install mosquitto-clients python-mosquitto
  • Copy over /opt/mqtt_matrix_bridge
  • Set up MQTT matrix bridge:
    echo '[Unit]' > /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo 'Description=MQTT Matrix Bridge for Audio' >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo 'After=network.target' >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo '[Service]' >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo 'ExecStart=/opt/mqtt_matrix_bridge/audio.py' >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo 'WorkingDirectory=/opt/mqtt_matrix_bridge' >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo 'User=spice' >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo 'Environment=PYTHONUNBUFFERED=1' >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo 'Restart=always' >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo 'RestartSec=1' >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo 'StartLimitInterval=10s' >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo 'StartLimitBurst=10' >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo '[Install]' >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/mqtt_matrix_bridge_audio.service
    
    echo '[Unit]' > /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo 'Description=MQTT Matrix Bridge for Legacy Distro 1' >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo 'After=network.target' >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo '[Service]' >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo 'ExecStart=/opt/mqtt_matrix_bridge/distro1.py' >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo 'WorkingDirectory=/opt/mqtt_matrix_bridge' >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo 'User=spice' >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo 'Environment=PYTHONUNBUFFERED=1' >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo 'Restart=always' >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo 'RestartSec=1' >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo 'StartLimitInterval=10s' >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo 'StartLimitBurst=10' >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo '[Install]' >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/mqtt_matrix_bridge_distro1.service
    
    echo '[Unit]' > /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo 'Description=MQTT Matrix Bridge for Legacy Distro 2' >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo 'After=network.target' >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo '[Service]' >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo 'ExecStart=/opt/mqtt_matrix_bridge/distro2.py' >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo 'WorkingDirectory=/opt/mqtt_matrix_bridge' >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo 'User=spice' >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo 'Environment=PYTHONUNBUFFERED=1' >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo 'Restart=always' >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo 'RestartSec=1' >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo 'StartLimitInterval=10s' >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo 'StartLimitBurst=10' >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo '[Install]' >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/mqtt_matrix_bridge_distro2.service
    
    echo '[Unit]' > /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo 'Description=MQTT Matrix Bridge for HDMI' >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo 'After=network.target' >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo '[Service]' >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo 'ExecStart=/opt/mqtt_matrix_bridge/hdmi.py' >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo 'WorkingDirectory=/opt/mqtt_matrix_bridge' >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo 'User=spice' >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo 'Environment=PYTHONUNBUFFERED=1' >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo 'Restart=always' >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo 'RestartSec=1' >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo 'StartLimitInterval=10s' >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo 'StartLimitBurst=10' >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo '[Install]' >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/mqtt_matrix_bridge_hdmi.service
    
    echo '[Unit]' > /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo 'Description=MQTT Matrix Bridge for VGA' >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo 'After=network.target' >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo '[Service]' >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo 'ExecStart=/opt/mqtt_matrix_bridge/vga.py' >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo 'WorkingDirectory=/opt/mqtt_matrix_bridge' >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo 'User=spice' >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo 'Environment=PYTHONUNBUFFERED=1' >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo 'Restart=always' >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo 'RestartSec=1' >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo 'StartLimitInterval=10s' >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo 'StartLimitBurst=10' >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo '[Install]' >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/mqtt_matrix_bridge_vga.service
    
    systemctl enable mqtt_matrix_bridge_audio
    systemctl enable mqtt_matrix_bridge_distro1
    systemctl enable mqtt_matrix_bridge_distro2
    systemctl enable mqtt_matrix_bridge_hdmi
    systemctl enable mqtt_matrix_bridge_vga
    systemctl start mqtt_matrix_bridge_audio
    systemctl start mqtt_matrix_bridge_distro1
    systemctl start mqtt_matrix_bridge_distro2
    systemctl start mqtt_matrix_bridge_hdmi
    systemctl start mqtt_matrix_bridge_vga
  • #Chain some HDMI matrix outputs to Legacy AV matrix with remote control buttons:
    echo '[Unit]' > /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo 'Description=Control HDMI Matrix with Legacy AV Matrix' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo 'After=network.target' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo 'After=mqtt_matrix_bridge_distro1.service' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo 'After=mqtt_matrix_bridge_hdmi.service' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo '[Service]' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo 'ExecStart=/opt/mqtt_legacy_distro_control_hdmi/legacy_distro_control_hdmi.py' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo 'WorkingDirectory=/opt/mqtt_legacy_distro_control_hdmi' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo 'User=spice' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo 'Environment=PYTHONUNBUFFERED=1' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo 'Restart=always' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo 'RestartSec=1' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo 'StartLimitInterval=10s' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo 'StartLimitBurst=10' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo '[Install]' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/mqtt_legacy_distro_control_hdmi.service
    
    systemctl enable mqtt_legacy_distro_control_hdmi
    systemctl start mqtt_legacy_distro_control_hdmi
  • # Monitor and control computer power:
    echo '[Unit]' > /etc/systemd/system/mqtt_computer_power.service
    echo 'Description=Monitor and control computer power through MQTT' >> /etc/systemd/system/mqtt_computer_power.service
    echo 'After=network.target' >> /etc/systemd/system/mqtt_computer_power.service
    echo >> /etc/systemd/system/mqtt_computer_power.service
    echo '[Service]' >> /etc/systemd/system/mqtt_computer_power.service
    echo 'ExecStart=/opt/mqtt_computer_power/computer_power_app.py' >> /etc/systemd/system/mqtt_computer_power.service
    echo 'WorkingDirectory=/opt/mqtt_computer_power' >> /etc/systemd/system/mqtt_computer_power.service
    echo 'User=spice' >> /etc/systemd/system/mqtt_computer_power.service
    echo 'Environment=PYTHONUNBUFFERED=1' >> /etc/systemd/system/mqtt_computer_power.service
    echo 'RuntimeDirectory=mqtt_computer_power' >> /etc/systemd/system/mqtt_computer_power.service
    echo 'RuntimeDirectoryMode=0755' >> /etc/systemd/system/mqtt_computer_power.service
    echo >> /etc/systemd/system/mqtt_computer_power.service
    echo 'Restart=always' >> /etc/systemd/system/mqtt_computer_power.service
    echo 'RestartSec=1' >> /etc/systemd/system/mqtt_computer_power.service
    echo 'StartLimitInterval=10s' >> /etc/systemd/system/mqtt_computer_power.service
    echo 'StartLimitBurst=10' >> /etc/systemd/system/mqtt_computer_power.service
    echo >> /etc/systemd/system/mqtt_computer_power.service
    echo '[Install]' >> /etc/systemd/system/mqtt_computer_power.service
    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/mqtt_computer_power.service
    
    systemctl enable mqtt_computer_power
    systemctl start mqtt_computer_power
    
    # only exists while program is running; /run/ subdirectory created by systemd through RuntimeDirectory directive
    ln -sf /run/mqtt_computer_power/computer_power_status.txt /var/www/html/computer_status.txt
    
    # have to send a header to allow this file to be loaded from javascript hosted on other systems
    a2enmod headers
    echo '<Location "/computer_status.txt">' > /etc/apache2/sites-enabled/allow_ajax_computer_status.conf
    echo '  Header set Access-Control-Allow-Origin "*"' >> /etc/apache2/sites-enabled/allow_ajax_computer_status.conf
    echo '</Location>' >> /etc/apache2/sites-enabled/allow_ajax_computer_status.conf
    systemctl restart apache2
  • TODO: Web browsers apparently work okay, then something (???) triggers an X11 restart, then they display nothing until restarted. Why does X11 get killed and restarted? WTH? I added ExecStartPre=/usr/local/bin/wait_network_up.sh to startx@.service as a hacky workaround, but that only seems to work sometimes. When it breaks, the systemd auto-restart fixes things, but it's still irritating.
computer/mcp_music_computer.txt · Last modified: 2019/01/07 21:45 by tdobes
Recent changes RSS feed Driven by DokuWiki Valid XHTML 1.0 Valid CSS