From 23946b53b3bf903207fbc539577d865a2d241f01 Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Sun, 15 Oct 2023 22:24:50 +0100 Subject: [PATCH 01/74] Update CAR INSTALL.md --- CAR INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CAR INSTALL.md b/CAR INSTALL.md index 767410eea..7b1c55386 100644 --- a/CAR INSTALL.md +++ b/CAR INSTALL.md @@ -9,7 +9,7 @@ Note that Android devices can not, so far, do this trick of using the two networ ## Example -**Important Note** This guide can not be used for the latest (time of writing: October 2023) version of Rasberry Pi OS (Bookworm) because the `dhcpd` package is no longer part of the system. It does work for Rasberry Pi OS (Bullseye) +**Important Note** This guide can not be used for the latest (time of writing: October 2023) version of Rasberry Pi OS (Bookworm) because the `dhcpcd` package is no longer part of the system. It does work for Rasberry Pi OS (Bullseye) In this example, a Raspberry Pi Zero 2 W and a Pimoroni PHAT DAC are used. Shairport Sync will be built for AirPlay 2 operation, but you can build it for "classic" AirPlay (aka AirPlay 1) operation if you prefer. A Pi Zero W is powerful enough for classic AirPlay. From fef5adaf54b0865400749ca4121def18f3fa0f84 Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Sun, 22 Oct 2023 13:06:45 +0100 Subject: [PATCH 02/74] Update CAR INSTALL.md Update for Bookworm and simplify some steps. Add some information about updating. --- CAR INSTALL.md | 173 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 115 insertions(+), 58 deletions(-) diff --git a/CAR INSTALL.md b/CAR INSTALL.md index 7b1c55386..01b9a309c 100644 --- a/CAR INSTALL.md +++ b/CAR INSTALL.md @@ -4,19 +4,22 @@ If your car audio has an AUX input, you can get AirPlay in your car using Shairp ## The Basic Idea The basic idea is to use a small Linux computer to create an isolated WiFi network (a "car network") and run Shairport Sync on it to provide an AirPlay service. An iPhone or an iPad with cellular capability can simultaneously connect to internet radio, YouTube, Apple Music, Spotify, etc. over the cellular network and send AirPlay audio through the car network to the AirPlay service provided by Shairport Sync. This sends the audio to the computer's DAC which is connected to the AUX input of your car audio. - -Note that Android devices can not, so far, do this trick of using the two networks simultaneously. +### Notes +1. **Android:** Android phones and tablets can not, so far, do this trick of using the two networks simultaneously. +2. **Volume Control, AirPlay 2:** In iOS 17 and later, if Shairport Sync is built for AirPlay 2, you won't be able to control the volume from your iOS device. This is because volume control settings are not sent from the iOS device to Shairport Sync in this mode. +In practice, this should not be a problem -- you control the volume using the car audio's volume control, the same as any other source. +3. **Volume Control, classic AirPlay ("AirPlay 1"):** if Shairport Sync is built for classic AirPlay, you can control the volume from your iOS device. ## Example -**Important Note** This guide can not be used for the latest (time of writing: October 2023) version of Rasberry Pi OS (Bookworm) because the `dhcpcd` package is no longer part of the system. It does work for Rasberry Pi OS (Bullseye) +If you are updating an existing installation, please refer to the Updating section below. In this example, a Raspberry Pi Zero 2 W and a Pimoroni PHAT DAC are used. Shairport Sync will be built for AirPlay 2 operation, but you can build it for "classic" AirPlay (aka AirPlay 1) operation if you prefer. A Pi Zero W is powerful enough for classic AirPlay. Please note that some of the details of setting up networks are specific to the version of Linux used. ### Prepare the initial SD Image -* Download Raspberry Pi OS Bullseye (Lite) and install it onto an SD Card using `Raspberry Pi Imager`. The Lite version is preferable to the Desktop version as it doesn't include a sound server like PulseAudio or PipeWire that can prevent direct access to the audio output device. +* Download Raspberry Pi OS (Lite) and install it onto an SD Card using `Raspberry Pi Imager`. The Lite version is preferable to the Desktop version as it doesn't include a sound server like PulseAudio or PipeWire that can prevent direct access to the audio output device. * Before writing the image to the card, use the Settings control on `Raspberry Pi Imager` to set hostname, enable SSH and provide a username and password to use while building the system. Similarly, you can specify a wireless network the Pi will connect to while building the system. Later on, the Pi will be configured to start its own isolated network. * The next few steps are to add the overlay needed for the sound card. This may not be necessary in your case, but in this example a Pimoroni PHAT is being used. If you do not need to add an overlay, skip these steps. * Mount the card on a Linux machine. Two drives should appear – a `boot` drive and a `rootfs` drive. @@ -64,6 +67,7 @@ Download Shairport Sync, check out the `development` branch and configure, compi ``` $ git clone https://github.com/mikebrady/shairport-sync.git $ cd shairport-sync +$ git checkout development $ autoreconf -fi $ ./configure --sysconfdir=/etc --with-alsa \ --with-soxr --with-avahi --with-ssl=openssl --with-systemd --with-airplay-2 @@ -91,17 +95,22 @@ alsa = }; ``` -Two `general` settings are worth noting. First, the option to ignore the sending device's volume control is enabled. This means that the car audio's volume control is the only one that affects the audio volume. Of course this is a matter of personal preference. -Second, the maximum output offered by the DAC to the AUX port of the car audio can be reduced if it is overloading the input circuits. Again, that's a matter for personal selection and adjustment. +Two `general` settings are worth noting. +1. First, the option to ignore the sending device's volume control is enabled. This means that the car audio's volume control is the only one that affects the audio volume. + As of iOS 17 it appears that volume control information is not forwarded to Shairport Sync when it is used like this. For this reason, it is important to set the `ignore_volume_control` setting in the configuration file to `"YES"`. This will allow audio to be forwarded to the car audio using the full volume range of the DAC instead of at the default initial volume, which may be quite low and which can't be changed from the iOS device. + +2. Second, the maximum output offered by the DAC to the AUX port of the car audio can be reduced if it is overloading the car audio's input circuits. Again, that's a matter for personal selection and adjustment. The `alsa` settings are for the Pimoroni PHAT – it does not have a hardware mixer, so no `mixer_control_name` is given. -Note that the DAC's 32-bit capability is automatically selected if available, so there is no need to set it here. Similarly, since `soxr` support is included in the build, `soxr` interpolation will be automatically enabled if the device is fast enough. +The DAC's 32-bit capability is automatically selected if available, so there is no need to set it here. Similarly, since `soxr` support is included in the build, `soxr` interpolation will be automatically enabled if the device is fast enough. + +Note that if you're upgrading the operating system to e.g. from Bullseye to Bookworm, the location of the output devices may change, and the names of the mixer controls may also change. You can use [`sps-alsa-explore`](https://github.com/mikebrady/sps-alsa-explore) to investigate device names and mixer names. ### Extra Packages A number of packages to enable the Pi to work as a WiFi base station are needed: ``` -# apt-get install hostapd isc-dhcp-server +# apt install --no-install-recommends hostapd isc-dhcp-server ``` Disable both of these services from starting at boot time (this is because we will launch them sequentially later on): ``` @@ -166,11 +175,9 @@ Configure the startup sequence by adding commands to `/etc/rc.local` to start `h # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. -# -# In order to enable or disable this script just change the execution -# bits. -# -# By default this script does nothing. + +# Uncomment the next line to exit the script, skipping the remainder of the script where the WiFi access point and Shairport Sync itself are started. +# exit 0 # uncomment this line to exit the script here /sbin/iw dev wlan0 set power_save off /usr/sbin/hostapd -B -P /run/hostapd.pid /etc/hostapd/hostapd.conf @@ -180,36 +187,46 @@ Configure the startup sequence by adding commands to `/etc/rc.local` to start `h /bin/sleep 2 /bin/systemctl start shairport-sync -exit 0 - +exit 0 # normal exit here ``` As you can see, the effect of these commands is to start the WiFi transmitter, give the base station the IP address `10.0.10.1`, start a DHCP server and finally start the Shairport Sync service. ### Final Steps -Up to now, if you reboot the Pi, it will reconnect to your WiFi network, ignoring the instructions and settings you have given it to act as a base station. That is because the `wlan0` interface is still under the control of the `dhcpcd` service. So, the final step is to instruct the `dhcpcd` service not to manage `wlan0`. To do this, edit `/etc/dhcpcd.conf` and insert the following line at the start: +You should now disable the `NetworkManager` or the `dhcpcd` service -- whichever of them is in your system -- so that they won't run when the system reboots. +To do this, perform the appropriate one of the following commands: + +``` +# systemctl disable NetworkManager +``` +or ``` -denyinterfaces wlan0 +# systemctl disable dhcpcd ``` -From this point on, at least on the Raspberry Pi, if you reboot the machine, it will not reconnect to your network. Instead, it will act as the WiFi base station you have configured with `hostapd` and `isc-dhcp-server`. -### Optimise startup time – Raspberry Pi Specific +From this point on, at least on the Raspberry Pi, if you were to power off and reboot the machine, it would not reconnect to your network. Instead, it would act as the WiFi base station you have configured with `hostapd` and `isc-dhcp-server`. -This is applicable to a Raspberry Pi only. Some of it may be applicable to other systems, but it has not been tested on them. +Next, the WiFi credentials you used to connect to the initial network (e.g. your home network) will have been stored in the system in plain text. This is convenient for when you want to reconnect to update (see later), but if you wish to delete them for any reason, they will be in `/etc/wpa_supplicant/wpa_supplicant.conf` + +When you are finished (including any optional steps below), carefully power down the machine before unplugging it from power: +``` +# poweroff +``` + +### Optional: Optimise startup time – Raspberry Pi Specific + +This is applicable to a Raspberry Pi only and is optional. Some of it may be applicable to other systems, but it has not been tested on them. There are quite a few services that are not necessary for this setup. Disabling them can improve startup time. Running these commands disables them: ``` -sudo systemctl disable systemd-timesyncd.service -sudo systemctl disable keyboard-setup.service -sudo systemctl disable triggerhappy.service -sudo systemctl disable dhcpcd.service -sudo systemctl disable wpa_supplicant.service -sudo systemctl disable dphys-swapfile.service -sudo systemctl disable networking.service +# systemctl disable systemd-timesyncd +# systemctl disable keyboard-setup +# systemctl disable triggerhappy +# systemctl disable dphys-swapfile ``` -### Read-only mode – Raspberry Pi Specific -Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem` and choose to enable the overlay filesystem, and to set the boot partition to be write-protected. +### Optional: Read-only mode – Raspberry Pi Specific +This is applicable to a Raspberry Pi only and is optional. Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem` and choose to enable the overlay filesystem, and to set the boot partition to be write-protected. ### Ready Install the Raspberry Pi in your car. It should be powered from a source that is switched off when you leave the car, otherwise the slight current drain will eventually flatten the car's battery. @@ -221,39 +238,79 @@ When the power source is switched on, typically when you start the car, it will --- ## Updating -From time to time, you may wish to update this installation. However, in order to update Shairport Sync, you must reconnect the system to a network that can access the internet. The easiest thing is to temporarily reconnect to the network you used when you created the system. To do that, you have to temporarily undo the "Final Steps" and some of the "Raspberry Pi Specific" steps you used. This will enable you to connect your device back to the network it was created on. You should then be able to update the operating system and libraries in the normal way and then update Shairport Sync. +From time to time, you may wish to update this installation. Assuming you haven't deleted your original WiFi network credentials, the easiest thing is to temporarily reconnect to the network you used when you created the system. To do that, you have to temporarily undo the "Final Steps" and some of the "Raspberry Pi Specific" steps you used. This will enable you to connect your device back to the network it was created on. You should then be able to update the operating system and libraries in the normal way and then update Shairport Sync. So, take the following steps: - +### Temporarily reconnect to the original network and update 1. If it's a Raspberry Pi and you have enabled the Read-only mode, you must take the device out of Read-only mode: Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem` and choose to disable the overlay filesystem and to set the boot partition not to be write-protected. This is so that changes can be written to the file system; you can make the filesystem read-only again later. Save the changes and reboot the system. -2. If you have disabled the `dhcpcd`, `wpa_supplicant` or `systemd-timesyncd` services as suggested in the "Optimise startup time -- Raspberry Pi Specific" section, you need to temporarily re-enable them: -`# systemctl enable dhcpcd.service` -`# systemctl enable wpa_supplicant.service` -`# systemctl enable systemd-timesyncd.service` -Reboot. +2. Undo a number of modification you may have made during previous installations. + 1. Remove a possible modification from a file. If there is a file called `/etc/dhcpcd.conf` and if the first line reads: + ``` + denyinterfaces wlan0 + ``` + then delete that line or comment it out -- it it no longer needed going forward. + If the file `/etc/dhcpcd.conf` doesn't exist, or the first line is not `denyinterfaces wlan0` as given here, then you don't need to do anything. + + (The reason for this suggestion is that a simpler way of preventing the `dhcpcd` service from trying to manage the `wlan0` interface is now used -- the `dhcpcd` service is now completely disabled.) + 3. Make sure you disable the `wpa_supplicant` service: + ``` + # systemctl disable wpa_supplicant + ``` + + (The reason for this suggestion is that it is important that the `wpa_supplicant` service not be running when the system is operating as a WiFi access point. Previous advice to enable the `wpa_supplicant` service when updating may result in it continuing to run even when the `dhcpcd` or `NetworkManager` has been disabled. So, please be sure to disable the `wpa_supplicant` service.) + +4. Re-enable either `NetworkManager` or `dhcpcd` as appropriate: + ``` + # systemctl enable NetworkManager + ``` + or + ``` + # systemctl enable dhcpcd + ``` +5. If you had disabled the `systemd-timesyncd` service as suggested in the "Optimise startup time -- Raspberry Pi Specific" section, you need to temporarily re-enable it: + ``` + # systemctl enable systemd-timesyncd + ``` +6. Edit `/etc/rc.local` to exit the script before enabling the WiFi access point and starting Shairport Sync. Do this by uncommenting the line: + ``` + # exit 0 # uncomment this line to exit the script here + ``` + so that it looks like this: + ``` + exit 0 # uncomment this line to exit the script here + ``` +Save the changes. -3. To allow your device to reconnect to the network it was created on, edit `/etc/dhcpcd.conf` and comment out the following line at the start: -`denyinterfaces wlan0` -so that it looks like this: -`# denyinterfaces wlan0` From this point on, if you reboot the machine, it will connect to the network it was configured on, i.e. the network you used when you set it up for the first time. This is because the name and password of the network it was created on would have been placed in `/etc/wpa_supplicant/wpa_supplicant` when the system was initially configured and will still be there. - -4. Reboot and do Normal Updating - - You can perform updates in the normal way. When you are finished, you need to undo the temporary changes you made to the setup, as follows: - -5. If you had temporarily re-enabled services that are normally disabled, then it's time to disable them again: -`# systemctl disable dhcpcd.service` -`# systemctl disable wpa_supplicant.service` -`# systemctl disable systemd-timesyncd.service` - -6. To re-enable the system to create its own network, edit `/etc/dhcpcd.conf` and uncomment the line that you had temporarily commented out at the start of the update. Change: -`# denyinterfaces wlan0` -so that it looks like this: -`denyinterfaces wlan0` - -7. Reboot. The system should start as it would if it was in the car. - -8. If the device is a Raspberry Pi and you wish to make the file system read-only, connect to the system, run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem`. In there, choose to enable the overlay filesystem, and to set the boot partition to be write-protected. Do a final reboot and check that everyting is in order. +7. Reboot and do normal updating. + +### Revert to normal operation +When you are finished updating, you need to undo the temporary changes you made to the setup, as follows: + +1. First, disable `NetworkManager` or `dhcpcd` as appropriate: + ``` + # systemctl disable NetworkManager + ``` + or + ``` + # systemctl disable dhcpcd + ``` +2. Next, if you had temporarily re-enabled services that are normally disabled, then it's time to disable them again: + ``` + # systemctl disable systemd-timesyncd + ``` +3. Edit `/etc/rc.local` to perform the entire script before exiting, so that it enables the WiFi access point and starts Shairport Sync. Do this by commenting out the line: + ``` + exit 0 # uncomment this line to exit the script now + ``` + so that it loooks like this: + ``` + # exit 0 # uncomment this line to exit the script now + ``` +Save the changes. + +4. Reboot. The system should start as it would if it was in the car. + +5. If the device is a Raspberry Pi and you wish to make the file system read-only, connect to the system, run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem`. In there, choose to enable the overlay filesystem, and to set the boot partition to be write-protected. Do a final reboot and check that everyting is in order. From 2a5c49d3c1ad4e0513bee5fc4b0e39af09987c4b Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 23 Oct 2023 10:07:53 +0100 Subject: [PATCH 03/74] Bookworm and simplifications Update for Bookworm and make some simplifications. --- CAR INSTALL.md | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/CAR INSTALL.md b/CAR INSTALL.md index 01b9a309c..efcdb548f 100644 --- a/CAR INSTALL.md +++ b/CAR INSTALL.md @@ -4,11 +4,8 @@ If your car audio has an AUX input, you can get AirPlay in your car using Shairp ## The Basic Idea The basic idea is to use a small Linux computer to create an isolated WiFi network (a "car network") and run Shairport Sync on it to provide an AirPlay service. An iPhone or an iPad with cellular capability can simultaneously connect to internet radio, YouTube, Apple Music, Spotify, etc. over the cellular network and send AirPlay audio through the car network to the AirPlay service provided by Shairport Sync. This sends the audio to the computer's DAC which is connected to the AUX input of your car audio. -### Notes -1. **Android:** Android phones and tablets can not, so far, do this trick of using the two networks simultaneously. -2. **Volume Control, AirPlay 2:** In iOS 17 and later, if Shairport Sync is built for AirPlay 2, you won't be able to control the volume from your iOS device. This is because volume control settings are not sent from the iOS device to Shairport Sync in this mode. -In practice, this should not be a problem -- you control the volume using the car audio's volume control, the same as any other source. -3. **Volume Control, classic AirPlay ("AirPlay 1"):** if Shairport Sync is built for classic AirPlay, you can control the volume from your iOS device. + +Please note that Android phones and tablets can not, so far, do this trick of using the two networks simultaneously. ## Example @@ -31,7 +28,7 @@ Please note that some of the details of setting up networks are specific to the * Close the file and carefully dismount and eject the two drives. *Be sure to dismount and eject the drives properly; otherwise they may be corrupted.* * Remove the SD card from the Linux machine, insert it into the Pi and reboot. -After a short time, the Pi should appear on your network – it may take a minute or so. To check, try to `ping` it at the `.local`, e.g. if the hostname is `bmw` then use `$ ping bmw.local`. Once it has appeared, you can SSH into it and configure it. +After a short time, the Pi should appear on your network – it may take a couple of minutes. To check, try to `ping` it at the `.local`, e.g. if the hostname is `bmw` then use `$ ping bmw.local`. Once it has appeared, you can SSH into it and configure it. ### Boot, Configure, Update The first thing to do on a Pi would be to use the `raspi-config` tool to expand the file system to use the entire card. Next, do the usual update and upgrade: @@ -96,16 +93,15 @@ alsa = ``` Two `general` settings are worth noting. -1. First, the option to ignore the sending device's volume control is enabled. This means that the car audio's volume control is the only one that affects the audio volume. - As of iOS 17 it appears that volume control information is not forwarded to Shairport Sync when it is used like this. For this reason, it is important to set the `ignore_volume_control` setting in the configuration file to `"YES"`. This will allow audio to be forwarded to the car audio using the full volume range of the DAC instead of at the default initial volume, which may be quite low and which can't be changed from the iOS device. +1. First, the option to ignore the sending device's volume control is enabled. This means that the car audio's volume control is the only one that affects the audio volume. This is a matter of personal preference. -2. Second, the maximum output offered by the DAC to the AUX port of the car audio can be reduced if it is overloading the car audio's input circuits. Again, that's a matter for personal selection and adjustment. +2. Second, the maximum output offered by the DAC to the AUX port of the car audio can be reduced if it is overloading the car audio's input circuits and causing distortion. Again, that's a matter for personal selection and adjustment. The `alsa` settings are for the Pimoroni PHAT – it does not have a hardware mixer, so no `mixer_control_name` is given. The DAC's 32-bit capability is automatically selected if available, so there is no need to set it here. Similarly, since `soxr` support is included in the build, `soxr` interpolation will be automatically enabled if the device is fast enough. -Note that if you're upgrading the operating system to e.g. from Bullseye to Bookworm, the location of the output devices may change, and the names of the mixer controls may also change. You can use [`sps-alsa-explore`](https://github.com/mikebrady/sps-alsa-explore) to investigate device names and mixer names. +Note that if you're upgrading the operating system to e.g. from Bullseye to Bookworm, the names and index numbers of the output devices may change, and the names of the mixer controls may also change. You can use [`sps-alsa-explore`](https://github.com/mikebrady/sps-alsa-explore) to discover device names and mixer names. ### Extra Packages A number of packages to enable the Pi to work as a WiFi base station are needed: @@ -176,7 +172,7 @@ Configure the startup sequence by adding commands to `/etc/rc.local` to start `h # Make sure that the script will "exit 0" on success or any other # value on error. -# Uncomment the next line to exit the script, skipping the remainder of the script where the WiFi access point and Shairport Sync itself are started. +# Uncomment the next line to exit the script here, skipping the remainder of the script where the WiFi access point and Shairport Sync itself are started. # exit 0 # uncomment this line to exit the script here /sbin/iw dev wlan0 set power_save off @@ -192,9 +188,12 @@ exit 0 # normal exit here As you can see, the effect of these commands is to start the WiFi transmitter, give the base station the IP address `10.0.10.1`, start a DHCP server and finally start the Shairport Sync service. ### Final Steps -You should now disable the `NetworkManager` or the `dhcpcd` service -- whichever of them is in your system -- so that they won't run when the system reboots. -To do this, perform the appropriate one of the following commands: - +You should now disable either the `NetworkManager` or the `dhcpcd` service (whichever is in your system) so that they won't run when the system reboots. You can find out which is in your system using the `ps -aux` command and looking for either `NetworkManager` or `dhcpcd`. Here is an example from a system running `dhcpcd`: +``` +$ ps aux | grep 'NetworkManager\|dhcpcd' | grep -v grep +root 596 0.0 0.2 3112 2216 ? Ss Oct08 0:51 /usr/sbin/dhcpcd -w -q +``` +Once you have identified which service to disable, perform the appropriate one of the following commands: ``` # systemctl disable NetworkManager ``` @@ -211,22 +210,17 @@ When you are finished (including any optional steps below), carefully power down ``` # poweroff ``` - ### Optional: Optimise startup time – Raspberry Pi Specific - -This is applicable to a Raspberry Pi only and is optional. Some of it may be applicable to other systems, but it has not been tested on them. - -There are quite a few services that are not necessary for this setup. Disabling them can improve startup time. Running these commands disables them: - +These optional steps have been tested on a Raspberry Pi only. They have not been tested on other systems. +Some services are not necessary for this setup. These commands disable them: ``` # systemctl disable systemd-timesyncd # systemctl disable keyboard-setup # systemctl disable triggerhappy # systemctl disable dphys-swapfile ``` - ### Optional: Read-only mode – Raspberry Pi Specific -This is applicable to a Raspberry Pi only and is optional. Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem` and choose to enable the overlay filesystem, and to set the boot partition to be write-protected. +This optional step is applicable to a Raspberry Pi only. Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem` and choose to enable the overlay filesystem, and to set the boot partition to be write-protected. ### Ready Install the Raspberry Pi in your car. It should be powered from a source that is switched off when you leave the car, otherwise the slight current drain will eventually flatten the car's battery. @@ -234,9 +228,7 @@ Install the Raspberry Pi in your car. It should be powered from a source that is When the power source is switched on, typically when you start the car, it will take maybe a minute for the system to boot up. ### Enjoy! - --- - ## Updating From time to time, you may wish to update this installation. Assuming you haven't deleted your original WiFi network credentials, the easiest thing is to temporarily reconnect to the network you used when you created the system. To do that, you have to temporarily undo the "Final Steps" and some of the "Raspberry Pi Specific" steps you used. This will enable you to connect your device back to the network it was created on. You should then be able to update the operating system and libraries in the normal way and then update Shairport Sync. @@ -253,13 +245,12 @@ Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesys then delete that line or comment it out -- it it no longer needed going forward. If the file `/etc/dhcpcd.conf` doesn't exist, or the first line is not `denyinterfaces wlan0` as given here, then you don't need to do anything. - (The reason for this suggestion is that a simpler way of preventing the `dhcpcd` service from trying to manage the `wlan0` interface is now used -- the `dhcpcd` service is now completely disabled.) + (The reason for this suggestion is that a simpler way is now used to prevent the `dhcpcd` service from trying to manage the interface -- the `dhcpcd` service is now completely disabled.) 3. Make sure you disable the `wpa_supplicant` service: ``` # systemctl disable wpa_supplicant ``` - - (The reason for this suggestion is that it is important that the `wpa_supplicant` service not be running when the system is operating as a WiFi access point. Previous advice to enable the `wpa_supplicant` service when updating may result in it continuing to run even when the `dhcpcd` or `NetworkManager` has been disabled. So, please be sure to disable the `wpa_supplicant` service.) + (The reason for this suggestion is that previous advice may result in the `wpa_supplicant` service continuing to run even when the `dhcpcd` or `NetworkManager` has been disabled. This can cause connectivity problems.) 4. Re-enable either `NetworkManager` or `dhcpcd` as appropriate: ``` @@ -273,6 +264,8 @@ Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesys ``` # systemctl enable systemd-timesyncd ``` + This is needed because the correct time is necessary for detemininig what has been updated. + 6. Edit `/etc/rc.local` to exit the script before enabling the WiFi access point and starting Shairport Sync. Do this by uncommenting the line: ``` # exit 0 # uncomment this line to exit the script here @@ -284,6 +277,7 @@ Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesys Save the changes. From this point on, if you reboot the machine, it will connect to the network it was configured on, i.e. the network you used when you set it up for the first time. This is because the name and password of the network it was created on would have been placed in `/etc/wpa_supplicant/wpa_supplicant` when the system was initially configured and will still be there. + 7. Reboot and do normal updating. ### Revert to normal operation From c9c90332610e554c1c9215860b8cc11171e36ca3 Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 23 Oct 2023 10:17:33 +0100 Subject: [PATCH 04/74] Update RELEASENOTES-DEVELOPMENT.md --- RELEASENOTES-DEVELOPMENT.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/RELEASENOTES-DEVELOPMENT.md b/RELEASENOTES-DEVELOPMENT.md index 9d81e0244..c037e946d 100644 --- a/RELEASENOTES-DEVELOPMENT.md +++ b/RELEASENOTES-DEVELOPMENT.md @@ -1,5 +1,12 @@ +Version 4.3.3-dev-3-g2a5c49d3 +=== +* Update [CAR INSTALL.md]() for Bookworm, which uses `NetworkManager` and does not use `dhcpcd`. +* Changes to the setup may result in more stable WiFi operation. + Version 4.3.2-dev-58-gb70dd463 === +This becamse Release 4.3.2, approximately. + **Investigation -- continued** * Return `501` ("Not Implemented") instead of `200` ("OK") in response to a `POST` message with the argument `/feedback` on a Classic AirPlay connection. From 1d8a509ed724adc379e8fbc3b0800e6496de1b28 Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 23 Oct 2023 10:18:12 +0100 Subject: [PATCH 05/74] Update RELEASENOTES-DEVELOPMENT.md --- RELEASENOTES-DEVELOPMENT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES-DEVELOPMENT.md b/RELEASENOTES-DEVELOPMENT.md index c037e946d..3e9d4bbc3 100644 --- a/RELEASENOTES-DEVELOPMENT.md +++ b/RELEASENOTES-DEVELOPMENT.md @@ -1,6 +1,6 @@ Version 4.3.3-dev-3-g2a5c49d3 === -* Update [CAR INSTALL.md]() for Bookworm, which uses `NetworkManager` and does not use `dhcpcd`. +* Update [CAR INSTALL.md](https://github.com/mikebrady/shairport-sync/blob/development/CAR%20INSTALL.md) for Bookworm, which uses `NetworkManager` and does not use `dhcpcd`. * Changes to the setup may result in more stable WiFi operation. Version 4.3.2-dev-58-gb70dd463 From 626f986a1885338f5db7279dcd0be96dbc4aa63c Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 23 Oct 2023 11:41:20 +0100 Subject: [PATCH 06/74] Stop some warnings during build for Docker. --- player.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/player.c b/player.c index 8c1752722..b411fb333 100644 --- a/player.c +++ b/player.c @@ -2057,9 +2057,9 @@ void *player_thread_func(void *arg) { int64_t tsum_of_sync_errors, tsum_of_corrections, tsum_of_insertions_and_deletions, tsum_of_drifts; int64_t previous_sync_error = 0, previous_correction = 0; - uint64_t minimum_dac_queue_size; - int32_t minimum_buffer_occupancy; - int32_t maximum_buffer_occupancy; + uint64_t minimum_dac_queue_size = 0; + int32_t minimum_buffer_occupancy = 0; + int32_t maximum_buffer_occupancy = 0; #ifdef CONFIG_AIRPLAY_2 conn->ap2_audio_buffer_minimum_size = -1; From 31d24a89caa460f9c49d76356808ffb14c0ae17b Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 23 Oct 2023 11:46:20 +0100 Subject: [PATCH 07/74] Update RELEASENOTES-DEVELOPMENT.md --- RELEASENOTES-DEVELOPMENT.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/RELEASENOTES-DEVELOPMENT.md b/RELEASENOTES-DEVELOPMENT.md index 3e9d4bbc3..f7ab6c6d7 100644 --- a/RELEASENOTES-DEVELOPMENT.md +++ b/RELEASENOTES-DEVELOPMENT.md @@ -1,6 +1,10 @@ +Version 4.3.3-dev-7-ga7603893 +=== +* Remove the a few compilation warnings during a Docker build -- the warnings were that some variables possibly being used uninitialised. + Version 4.3.3-dev-3-g2a5c49d3 === -* Update [CAR INSTALL.md](https://github.com/mikebrady/shairport-sync/blob/development/CAR%20INSTALL.md) for Bookworm, which uses `NetworkManager` and does not use `dhcpcd`. +* Update [CAR INSTALL](https://github.com/mikebrady/shairport-sync/blob/development/CAR%20INSTALL.md) for Bookworm, which uses `NetworkManager` and does not use `dhcpcd`. * Changes to the setup may result in more stable WiFi operation. Version 4.3.2-dev-58-gb70dd463 From 95d81341c9cea5b1ad578bfc3824f08a837815b6 Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 23 Oct 2023 11:48:13 +0100 Subject: [PATCH 08/74] Update RELEASENOTES-DEVELOPMENT.md --- RELEASENOTES-DEVELOPMENT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES-DEVELOPMENT.md b/RELEASENOTES-DEVELOPMENT.md index f7ab6c6d7..416dc00f3 100644 --- a/RELEASENOTES-DEVELOPMENT.md +++ b/RELEASENOTES-DEVELOPMENT.md @@ -5,7 +5,7 @@ Version 4.3.3-dev-7-ga7603893 Version 4.3.3-dev-3-g2a5c49d3 === * Update [CAR INSTALL](https://github.com/mikebrady/shairport-sync/blob/development/CAR%20INSTALL.md) for Bookworm, which uses `NetworkManager` and does not use `dhcpcd`. -* Changes to the setup may result in more stable WiFi operation. +* Changes to the car installation setup may result in more stable WiFi operation. Version 4.3.2-dev-58-gb70dd463 === From bc363160ba0109304635c1888dac75533ba79bab Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:49:02 +0100 Subject: [PATCH 09/74] Update CAR INSTALL.md --- CAR INSTALL.md | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/CAR INSTALL.md b/CAR INSTALL.md index efcdb548f..da5e7cd0b 100644 --- a/CAR INSTALL.md +++ b/CAR INSTALL.md @@ -201,10 +201,15 @@ or ``` # systemctl disable dhcpcd ``` +Now you should also disable the `wpa_supplicant` service. + +``` +# systemctl disable wpa_supplicant +``` From this point on, at least on the Raspberry Pi, if you were to power off and reboot the machine, it would not reconnect to your network. Instead, it would act as the WiFi base station you have configured with `hostapd` and `isc-dhcp-server`. -Next, the WiFi credentials you used to connect to the initial network (e.g. your home network) will have been stored in the system in plain text. This is convenient for when you want to reconnect to update (see later), but if you wish to delete them for any reason, they will be in `/etc/wpa_supplicant/wpa_supplicant.conf` +**Note:** The WiFi credentials you used to connect to the initial network (e.g. your home network) will have been stored in the system in plain text. This is convenient for when you want to reconnect to update (see later), but if you wish to delete them for any reason, they will be in `/etc/wpa_supplicant/wpa_supplicant.conf` When you are finished (including any optional steps below), carefully power down the machine before unplugging it from power: ``` @@ -237,20 +242,16 @@ So, take the following steps: 1. If it's a Raspberry Pi and you have enabled the Read-only mode, you must take the device out of Read-only mode: Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem` and choose to disable the overlay filesystem and to set the boot partition not to be write-protected. This is so that changes can be written to the file system; you can make the filesystem read-only again later. Save the changes and reboot the system. -2. Undo a number of modification you may have made during previous installations. - 1. Remove a possible modification from a file. If there is a file called `/etc/dhcpcd.conf` and if the first line reads: - ``` - denyinterfaces wlan0 - ``` - then delete that line or comment it out -- it it no longer needed going forward. - If the file `/etc/dhcpcd.conf` doesn't exist, or the first line is not `denyinterfaces wlan0` as given here, then you don't need to do anything. +2. Undo a modification you may have made during previous installations. + + Remove a possible modification from a file. If there is a file called `/etc/dhcpcd.conf` and if the first line reads: + ``` + denyinterfaces wlan0 + ``` + then delete that line or comment it out -- it it no longer needed going forward. + If the file `/etc/dhcpcd.conf` doesn't exist, or if the first line is not `denyinterfaces wlan0` as given here, then you don't need to do anything. - (The reason for this suggestion is that a simpler way is now used to prevent the `dhcpcd` service from trying to manage the interface -- the `dhcpcd` service is now completely disabled.) - 3. Make sure you disable the `wpa_supplicant` service: - ``` - # systemctl disable wpa_supplicant - ``` - (The reason for this suggestion is that previous advice may result in the `wpa_supplicant` service continuing to run even when the `dhcpcd` or `NetworkManager` has been disabled. This can cause connectivity problems.) + (The reason for this suggestion is that a simpler way is now used to prevent the `dhcpcd` service from trying to manage the interface -- the `dhcpcd` service is now completely disabled.) 4. Re-enable either `NetworkManager` or `dhcpcd` as appropriate: ``` @@ -260,6 +261,8 @@ Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesys ``` # systemctl enable dhcpcd ``` + (Just FYI, even though the `wpa_supplicant` service has previously been disabled from starting automatically, it will be turned on by `NetworkManager` or `dhcpcd` after reboot.) + 5. If you had disabled the `systemd-timesyncd` service as suggested in the "Optimise startup time -- Raspberry Pi Specific" section, you need to temporarily re-enable it: ``` # systemctl enable systemd-timesyncd @@ -291,11 +294,15 @@ When you are finished updating, you need to undo the temporary changes you made ``` # systemctl disable dhcpcd ``` -2. Next, if you had temporarily re-enabled services that are normally disabled, then it's time to disable them again: +2. Also, ensure that the `wpa_supplicant` service is disabled. + ``` + # systemctl disable wpa_supplicant + ``` +3. Next, if you had temporarily re-enabled services that are normally disabled, then it's time to disable them again: ``` # systemctl disable systemd-timesyncd ``` -3. Edit `/etc/rc.local` to perform the entire script before exiting, so that it enables the WiFi access point and starts Shairport Sync. Do this by commenting out the line: +4. Edit `/etc/rc.local` to perform the entire script before exiting, so that it enables the WiFi access point and starts Shairport Sync. Do this by commenting out the line: ``` exit 0 # uncomment this line to exit the script now ``` @@ -303,8 +310,8 @@ When you are finished updating, you need to undo the temporary changes you made ``` # exit 0 # uncomment this line to exit the script now ``` -Save the changes. + Save the changes. -4. Reboot. The system should start as it would if it was in the car. +5. Reboot. The system should start as it would if it was in the car. 5. If the device is a Raspberry Pi and you wish to make the file system read-only, connect to the system, run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem`. In there, choose to enable the overlay filesystem, and to set the boot partition to be write-protected. Do a final reboot and check that everyting is in order. From 40306cc742441b00036f50edf8b85538c672d53b Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 23 Oct 2023 15:10:54 +0100 Subject: [PATCH 10/74] Update CAR INSTALL.md --- CAR INSTALL.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CAR INSTALL.md b/CAR INSTALL.md index da5e7cd0b..e22a98ba2 100644 --- a/CAR INSTALL.md +++ b/CAR INSTALL.md @@ -9,7 +9,7 @@ Please note that Android phones and tablets can not, so far, do this trick of us ## Example -If you are updating an existing installation, please refer to the Updating section below. +If you are updating an existing installation, please refer to the [updating](#updating) section below. In this example, a Raspberry Pi Zero 2 W and a Pimoroni PHAT DAC are used. Shairport Sync will be built for AirPlay 2 operation, but you can build it for "classic" AirPlay (aka AirPlay 1) operation if you prefer. A Pi Zero W is powerful enough for classic AirPlay. @@ -101,8 +101,6 @@ The `alsa` settings are for the Pimoroni PHAT – it does not have a hardware mi The DAC's 32-bit capability is automatically selected if available, so there is no need to set it here. Similarly, since `soxr` support is included in the build, `soxr` interpolation will be automatically enabled if the device is fast enough. -Note that if you're upgrading the operating system to e.g. from Bullseye to Bookworm, the names and index numbers of the output devices may change, and the names of the mixer controls may also change. You can use [`sps-alsa-explore`](https://github.com/mikebrady/sps-alsa-explore) to discover device names and mixer names. - ### Extra Packages A number of packages to enable the Pi to work as a WiFi base station are needed: ``` @@ -215,7 +213,7 @@ When you are finished (including any optional steps below), carefully power down ``` # poweroff ``` -### Optional: Optimise startup time – Raspberry Pi Specific +#### Optional: Optimise startup time – Raspberry Pi Specific These optional steps have been tested on a Raspberry Pi only. They have not been tested on other systems. Some services are not necessary for this setup. These commands disable them: ``` @@ -224,7 +222,7 @@ Some services are not necessary for this setup. These commands disable them: # systemctl disable triggerhappy # systemctl disable dphys-swapfile ``` -### Optional: Read-only mode – Raspberry Pi Specific +#### Optional: Read-only mode – Raspberry Pi Specific This optional step is applicable to a Raspberry Pi only. Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem` and choose to enable the overlay filesystem, and to set the boot partition to be write-protected. ### Ready @@ -237,7 +235,9 @@ When the power source is switched on, typically when you start the car, it will ## Updating From time to time, you may wish to update this installation. Assuming you haven't deleted your original WiFi network credentials, the easiest thing is to temporarily reconnect to the network you used when you created the system. To do that, you have to temporarily undo the "Final Steps" and some of the "Raspberry Pi Specific" steps you used. This will enable you to connect your device back to the network it was created on. You should then be able to update the operating system and libraries in the normal way and then update Shairport Sync. -So, take the following steps: +Note that if you're upgrading the operating system to e.g. from Bullseye to Bookworm, the names and index numbers of the output devices may change, and the names of the mixer controls may also change. You can use [`sps-alsa-explore`](https://github.com/mikebrady/sps-alsa-explore) to discover device names and mixer names. + +To update, take the following steps: ### Temporarily reconnect to the original network and update 1. If it's a Raspberry Pi and you have enabled the Read-only mode, you must take the device out of Read-only mode: Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem` and choose to disable the overlay filesystem and to set the boot partition not to be write-protected. This is so that changes can be written to the file system; you can make the filesystem read-only again later. Save the changes and reboot the system. From 84a214d4d0b683ac1145bd1a98115cff58de6435 Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 30 Oct 2023 17:07:28 +0000 Subject: [PATCH 11/74] Update CAR INSTALL.md --- CAR INSTALL.md | 195 +++++++++++++++++++++++-------------------------- 1 file changed, 90 insertions(+), 105 deletions(-) diff --git a/CAR INSTALL.md b/CAR INSTALL.md index e22a98ba2..efd4e5033 100644 --- a/CAR INSTALL.md +++ b/CAR INSTALL.md @@ -70,11 +70,10 @@ $ ./configure --sysconfdir=/etc --with-alsa \ --with-soxr --with-avahi --with-ssl=openssl --with-systemd --with-airplay-2 $ make # make install +# systemctl enable shairport-sync ``` The `autoreconf` step may take quite a while – please be patient! -**Note:** *Do not* enable Shairport Sync to start automatically at boot time – later on in this installation, we will arrange for it to start after the network has been set up. - ### Configure Shairport Sync Here are the important options for the Shairport Sync configuration file at `/etc/shairport-sync.conf`: ``` @@ -106,6 +105,8 @@ A number of packages to enable the Pi to work as a WiFi base station are needed: ``` # apt install --no-install-recommends hostapd isc-dhcp-server ``` +(The installer will get errors trying to set up both of these services; the errors can be ignored.) + Disable both of these services from starting at boot time (this is because we will launch them sequentially later on): ``` # systemctl unmask hostapd @@ -160,158 +161,142 @@ INTERFACESv4="wlan0" INTERFACESv6="" ``` ### Set up the Startup Sequence -Configure the startup sequence by adding commands to `/etc/rc.local` to start `hostapd` and the `dhcp` server and then to start `shairport-sync` automatically after startup. Its contents should look like this: +Configure the startup sequence by adding commands to `/etc/rc.local` to start `hostapd` and the `dhcp` automatically after startup. Its contents should look like this: ``` #!/bin/sh -e # # rc.local # -# This script is executed at the end of each multiuser runlevel. -# Make sure that the script will "exit 0" on success or any other -# value on error. -# Uncomment the next line to exit the script here, skipping the remainder of the script where the WiFi access point and Shairport Sync itself are started. -# exit 0 # uncomment this line to exit the script here +# Shairport Sync is automatically started as a service on startup. -/sbin/iw dev wlan0 set power_save off -/usr/sbin/hostapd -B -P /run/hostapd.pid /etc/hostapd/hostapd.conf -/sbin/ip addr add 10.0.10.1/24 dev wlan0 -/bin/sleep 1 -/bin/systemctl start isc-dhcp-server -/bin/sleep 2 -/bin/systemctl start shairport-sync +# If MODE is set to RUN, the system will start the WiFi access point. -exit 0 # normal exit here -``` -As you can see, the effect of these commands is to start the WiFi transmitter, give the base station the IP address `10.0.10.1`, start a DHCP server and finally start the Shairport Sync service. +# If MODE is set to anything else, e.g. DEV, the system will not start the WiFi access point. +# Instead, you can connect the system to a network. +# If it still has the WiFi credentials of the last WiFi network it connected to, +# it can connect to it automatically. -### Final Steps -You should now disable either the `NetworkManager` or the `dhcpcd` service (whichever is in your system) so that they won't run when the system reboots. You can find out which is in your system using the `ps -aux` command and looking for either `NetworkManager` or `dhcpcd`. Here is an example from a system running `dhcpcd`: -``` -$ ps aux | grep 'NetworkManager\|dhcpcd' | grep -v grep -root 596 0.0 0.2 3112 2216 ? Ss Oct08 0:51 /usr/sbin/dhcpcd -w -q -``` -Once you have identified which service to disable, perform the appropriate one of the following commands: -``` -# systemctl disable NetworkManager -``` -or -``` -# systemctl disable dhcpcd -``` -Now you should also disable the `wpa_supplicant` service. +MODE=RUN -``` -# systemctl disable wpa_supplicant -``` +/sbin/iw dev wlan0 set power_save off # always do this -From this point on, at least on the Raspberry Pi, if you were to power off and reboot the machine, it would not reconnect to your network. Instead, it would act as the WiFi base station you have configured with `hostapd` and `isc-dhcp-server`. +if test $MODE = RUN ; then -**Note:** The WiFi credentials you used to connect to the initial network (e.g. your home network) will have been stored in the system in plain text. This is convenient for when you want to reconnect to update (see later), but if you wish to delete them for any reason, they will be in `/etc/wpa_supplicant/wpa_supplicant.conf` + # If script execution gets in here, it starts the WiFi access point. + /usr/sbin/hostapd -B -P /run/hostapd.pid /etc/hostapd/hostapd.conf + /sbin/ip addr add 10.0.10.1/24 dev wlan0 + /bin/systemctl start isc-dhcp-server + +else -When you are finished (including any optional steps below), carefully power down the machine before unplugging it from power: -``` -# poweroff + # If script execution gets in here, it starts services needed for normal operation. + /bin/systemctl start systemd-timesyncd || : + /bin/systemctl start dhcpcd || /bin/systemctl start NetworkManager || : + +fi + +exit 0 # normal exit here ``` -#### Optional: Optimise startup time – Raspberry Pi Specific -These optional steps have been tested on a Raspberry Pi only. They have not been tested on other systems. -Some services are not necessary for this setup. These commands disable them: + +#### Disable Unused Services +These optional steps have been tested on a Raspberry Pi only -- they have not been tested on other systems. +Some services are not necessary for this setup and can be disabled as follows: ``` -# systemctl disable systemd-timesyncd # systemctl disable keyboard-setup # systemctl disable triggerhappy # systemctl disable dphys-swapfile ``` #### Optional: Read-only mode – Raspberry Pi Specific -This optional step is applicable to a Raspberry Pi only. Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem` and choose to enable the overlay filesystem, and to set the boot partition to be write-protected. +This optional step is applicable to a Raspberry Pi only. Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem` and choose to enable the overlay filesystem, and to set the boot partition to be write-protected. (The idea here is that this offers more protection against files being corrupted by the sudden removal of power.) +### Final Steps + +You now need to disable some services; that is, you need to stop them starting automatically on power-up. This is because they either interfere with the system's operation in WiFi Access Point mode, or because they won't work when the system isn't connected to the Internet. Only one of the `NetworkManager` and the `dhcpcd` service will be present in your system, but it's no harm to try to disable both. +``` +# systemctl disable dhcpcd +# systemctl disable NetworkManager +# systemctl disable wpa_supplicant +# systemctl disable systemd-timesyncd +``` +Lastly, note that the WiFi credentials you used initially to connect to your network (e.g. your home network) will have been stored in the system in plain text. This is convenient for when you want to reconnect to update (see later), but if you prefer to delete them, they will be in `/etc/wpa_supplicant/wpa_supplicant.conf` + +When you are finished, carefully power down the machine before unplugging it from power: +``` +# poweroff +``` ### Ready Install the Raspberry Pi in your car. It should be powered from a source that is switched off when you leave the car, otherwise the slight current drain will eventually flatten the car's battery. -When the power source is switched on, typically when you start the car, it will take maybe a minute for the system to boot up. +When the power source is switched on -- typically when you start the car -- it will take around 35 seconds for the system to become available (timing based on a Raspberry Pi Zero 2 W running Bookworm). ### Enjoy! --- ## Updating -From time to time, you may wish to update this installation. Assuming you haven't deleted your original WiFi network credentials, the easiest thing is to temporarily reconnect to the network you used when you created the system. To do that, you have to temporarily undo the "Final Steps" and some of the "Raspberry Pi Specific" steps you used. This will enable you to connect your device back to the network it was created on. You should then be able to update the operating system and libraries in the normal way and then update Shairport Sync. +From time to time, you may wish to update this installation. Assuming you haven't deleted your original WiFi network credentials, the easiest thing is to temporarily reconnect to the network you used when you created the system. You can then update the operating system and libraries in the normal way and then update Shairport Sync. -Note that if you're upgrading the operating system to e.g. from Bullseye to Bookworm, the names and index numbers of the output devices may change, and the names of the mixer controls may also change. You can use [`sps-alsa-explore`](https://github.com/mikebrady/sps-alsa-explore) to discover device names and mixer names. +However, if you're *upgrading* the operating system to e.g. from Bullseye to Bookworm, the names and index numbers of the output devices may change, and the names of the mixer controls may also change. You can use [`sps-alsa-explore`](https://github.com/mikebrady/sps-alsa-explore) to discover device names and mixer names. -To update, take the following steps: -### Temporarily reconnect to the original network and update -1. If it's a Raspberry Pi and you have enabled the Read-only mode, you must take the device out of Read-only mode: +#### Exit Raspberry Pi Read-Only Mode +If it's a Raspberry Pi and you have optionally enabled the read-only mode, you must take the device out of Read-only mode: Run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem` and choose to disable the overlay filesystem and to set the boot partition not to be write-protected. This is so that changes can be written to the file system; you can make the filesystem read-only again later. Save the changes and reboot the system. +#### Undo Optimisations +If you have disabled any of the services listed in the [Disable Unused Services](#disable-unused-services) section, you should re-enable them. (But *do not* re-eneable `NetworkManager`, `dhcpcd`, `wpa_supplicant` or `systemd-timesyncd` -- they are handled specially by the startup script.) +#### Perform Legacy Updates +Over time, the arrangements by which the system is prepared for operation has changed to make it easier to revert to normal operation when necessary for maintenance, updates, etc. A small number of the old settings need to be changed to bring them up to date with the present arrangements. Once the required changes have been made, your system will be ready for the update process detailed below. Here are those legacy changes you need to make, just once: -2. Undo a modification you may have made during previous installations. - - Remove a possible modification from a file. If there is a file called `/etc/dhcpcd.conf` and if the first line reads: +1. If there is a file called `/etc/dhcpcd.conf` and if the first line reads: ``` denyinterfaces wlan0 ``` - then delete that line or comment it out -- it it no longer needed going forward. - If the file `/etc/dhcpcd.conf` doesn't exist, or if the first line is not `denyinterfaces wlan0` as given here, then you don't need to do anything. - - (The reason for this suggestion is that a simpler way is now used to prevent the `dhcpcd` service from trying to manage the interface -- the `dhcpcd` service is now completely disabled.) + then delete that line -- it is no longer needed and will cause problems in future if it remains there. + + If the file `/etc/dhcpcd.conf` doesn't exist, or if the first line is not `denyinterfaces wlan0`, then you don't need to do anything. + +2. Replace the contents of the file `/etc/rc.local` with the new contents given [above](#set-up-the-startup-sequence). -4. Re-enable either `NetworkManager` or `dhcpcd` as appropriate: +3. Disable a number of services as follows. Only one of the `NetworkManager` and the `dhcpcd` service will be present in your system, but it's no harm to try to disable both. ``` - # systemctl enable NetworkManager - ``` - or - ``` - # systemctl enable dhcpcd + # systemctl disable dhcpcd + # systemctl disable NetworkManager + # systemctl disable wpa_supplicant + # systemctl disable systemd-timesyncd ``` - (Just FYI, even though the `wpa_supplicant` service has previously been disabled from starting automatically, it will be turned on by `NetworkManager` or `dhcpcd` after reboot.) - -5. If you had disabled the `systemd-timesyncd` service as suggested in the "Optimise startup time -- Raspberry Pi Specific" section, you need to temporarily re-enable it: +4. Enable the `shairport-sync` service itself: ``` - # systemctl enable systemd-timesyncd + # systemctl enable shairport-sync ``` - This is needed because the correct time is necessary for detemininig what has been updated. - -6. Edit `/etc/rc.local` to exit the script before enabling the WiFi access point and starting Shairport Sync. Do this by uncommenting the line: +Once you have made these one-off legacy updates, you can proceed to the next stage -- performing the update. +### Performing the Update +To update, take the following steps: +#### Temporarily reconnect to a network and update +1. Edit the startup script in `/etc/rc.local` to so that the system is no longer in the RUN mode. + To do that, change line 15 so that it goes from this: ``` - # exit 0 # uncomment this line to exit the script here + MODE=RUN ``` - so that it looks like this: + to this: ``` - exit 0 # uncomment this line to exit the script here + MODE=DEV ``` -Save the changes. - -From this point on, if you reboot the machine, it will connect to the network it was configured on, i.e. the network you used when you set it up for the first time. This is because the name and password of the network it was created on would have been placed in `/etc/wpa_supplicant/wpa_supplicant` when the system was initially configured and will still be there. + Do not be tempted to insert any spaces anywhere -- Unix scripting syntax is very strict! -7. Reboot and do normal updating. +2. Save and close the file and reboot. From this point on, the system will start normally and can be connected to a network. If it still has the WiFi credentials of the last network it was connected to, then it could automatically reconnect. -### Revert to normal operation -When you are finished updating, you need to undo the temporary changes you made to the setup, as follows: +The system is now ready for updating in the normal way. +#### Revert to normal operation +When you are finished updating, you need to put the system back into its RUN mode, as follows: -1. First, disable `NetworkManager` or `dhcpcd` as appropriate: - ``` - # systemctl disable NetworkManager +1. Edit the startup script in `/etc/rc.local` to so that the MODE variable is set to RUN. + To do that, change line 15 so that it goes from this: ``` - or + MODE=DEV ``` - # systemctl disable dhcpcd - ``` -2. Also, ensure that the `wpa_supplicant` service is disabled. - ``` - # systemctl disable wpa_supplicant + to this: ``` -3. Next, if you had temporarily re-enabled services that are normally disabled, then it's time to disable them again: + MODE=RUN ``` - # systemctl disable systemd-timesyncd - ``` -4. Edit `/etc/rc.local` to perform the entire script before exiting, so that it enables the WiFi access point and starts Shairport Sync. Do this by commenting out the line: - ``` - exit 0 # uncomment this line to exit the script now - ``` - so that it loooks like this: - ``` - # exit 0 # uncomment this line to exit the script now - ``` - Save the changes. - -5. Reboot. The system should start as it would if it was in the car. + Once again, do insert any spaces anywhere. -5. If the device is a Raspberry Pi and you wish to make the file system read-only, connect to the system, run `sudo raspi-config` and then choose `Performance Options` > `Overlay Filesystem`. In there, choose to enable the overlay filesystem, and to set the boot partition to be write-protected. Do a final reboot and check that everyting is in order. + +2. Save and close the file and reboot. The system should start as it would if it was in the car. From 9ab85989f3db64ccfb4306efe3f30abf6c8b4643 Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 30 Oct 2023 17:46:12 +0000 Subject: [PATCH 12/74] A bit late, but tag this as 4.3.3-dev. Also merge in the commit history of the master branch. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4c61a810f..d13795a65 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.50]) -AC_INIT([shairport-sync], [4.3.2], [4265913+mikebrady@users.noreply.github.com]) +AC_INIT([shairport-sync], [4.3.3-dev], [4265913+mikebrady@users.noreply.github.com]) AM_INIT_AUTOMAKE([subdir-objects]) AC_CONFIG_SRCDIR([shairport.c]) AC_CONFIG_HEADERS([config.h]) From d8c741e3916f4e6aa3b4d4bfbc60ffcf3681236b Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 30 Oct 2023 17:51:52 +0000 Subject: [PATCH 13/74] Update RELEASENOTES-DEVELOPMENT.md --- RELEASENOTES-DEVELOPMENT.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/RELEASENOTES-DEVELOPMENT.md b/RELEASENOTES-DEVELOPMENT.md index 416dc00f3..7deabd798 100644 --- a/RELEASENOTES-DEVELOPMENT.md +++ b/RELEASENOTES-DEVELOPMENT.md @@ -1,3 +1,8 @@ +Version 4.3.3-dev-1-g9ab85989 +=== +* Forgot to push tag 4.3.3-dev, so "back" to 4.3.3-dev-1. Apologies for the confusion. The commit hash is good. +* Further updates to [CAR INSTALL](https://github.com/mikebrady/shairport-sync/blob/development/CAR%20INSTALL.md), hopefully to make updates a bit simpler. + Version 4.3.3-dev-7-ga7603893 === * Remove the a few compilation warnings during a Docker build -- the warnings were that some variables possibly being used uninitialised. From 5f9a88fb74604fad410b9fbecd3be3f85b51c834 Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Tue, 31 Oct 2023 09:01:24 +0000 Subject: [PATCH 14/74] Use pthread_rwlock_wrlock instead of the incorrect use of pthread_rdlock_wrlock when tearing down a connection. --- rtsp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rtsp.c b/rtsp.c index 26883471d..e7903cc55 100644 --- a/rtsp.c +++ b/rtsp.c @@ -594,7 +594,8 @@ int get_play_lock(rtsp_conn_info *conn, int allow_session_interruption) { principal_conn->connection_number); } else if (allow_session_interruption != 0) { rtsp_conn_info *previous_principal_conn = principal_conn; - principal_conn = NULL; // no longer the principal conn + // important -- demote the principal conn before cancelling it + principal_conn = NULL; pthread_cancel(previous_principal_conn->thread); // the previous principal thread will block on the principal conn lock when exiting // so it's important not to wait for it here, e.g. don't put in a pthread_join here. @@ -2715,7 +2716,7 @@ void teardown_phase_two(rtsp_conn_info *conn) { } // only update these things if you're (still) the principal conn - pthread_rwlock_rdlock(&principal_conn_lock); // don't let the principal_conn be changed + pthread_rwlock_wrlock(&principal_conn_lock); // don't let the principal_conn be changed pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock); if (principal_conn == conn) { if (conn->airplay_stream_category == ptp_stream) { @@ -2781,7 +2782,7 @@ void teardown(rtsp_conn_info *conn) { } // only update these things if you're (still) the principal conn - pthread_rwlock_rdlock(&principal_conn_lock); // don't let the principal_conn be changed + pthread_rwlock_wrlock(&principal_conn_lock); // don't let the principal_conn be changed pthread_cleanup_push(rwlock_unlock, (void *)&principal_conn_lock); if (principal_conn == conn) { #ifdef CONFIG_AIRPLAY_2 From 7e7414658f19c8ddfbc3c0a9ad5f2cf347783b96 Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 6 Nov 2023 11:07:06 +0000 Subject: [PATCH 15/74] Update CAR INSTALL.md --- CAR INSTALL.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CAR INSTALL.md b/CAR INSTALL.md index efd4e5033..a7e09d199 100644 --- a/CAR INSTALL.md +++ b/CAR INSTALL.md @@ -179,6 +179,7 @@ Configure the startup sequence by adding commands to `/etc/rc.local` to start `h MODE=RUN +/bin/sleep 2 # may be necessary while wlan0 becomes available /sbin/iw dev wlan0 set power_save off # always do this if test $MODE = RUN ; then From 9f54a7512796a2447c5fa6bc6370a3f4493a9587 Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Mon, 6 Nov 2023 11:15:58 +0000 Subject: [PATCH 16/74] Update RELEASENOTES-DEVELOPMENT.md --- RELEASENOTES-DEVELOPMENT.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/RELEASENOTES-DEVELOPMENT.md b/RELEASENOTES-DEVELOPMENT.md index 7deabd798..784092098 100644 --- a/RELEASENOTES-DEVELOPMENT.md +++ b/RELEASENOTES-DEVELOPMENT.md @@ -1,3 +1,10 @@ +Version 4.3.3-dev-4-g7e741465 +=== +* A slight change to [CAR INSTALL](https://github.com/mikebrady/shairport-sync/blob/development/CAR%20INSTALL.md), to add a two-second delay when accessing the WiFi device for the first time. It may be necessary in some cases, e.g. the Pi 3B. + +**Bug Fix** +* Use `pthread_rwlock_wrlock` instead of the incorrect use of `pthread_rdlock_wrlock` when tearing down a connection. (This didn't seem to cause any problems, but it was definitely a bug, now fixed.) + Version 4.3.3-dev-1-g9ab85989 === * Forgot to push tag 4.3.3-dev, so "back" to 4.3.3-dev-1. Apologies for the confusion. The commit hash is good. From e36ec5c45d872cd1bdc59a24b805560b5e7029aa Mon Sep 17 00:00:00 2001 From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Sun, 12 Nov 2023 11:50:21 +0000 Subject: [PATCH 17/74] Quieten some debug messages. --- rtsp.c | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/rtsp.c b/rtsp.c index e7903cc55..b9992366f 100644 --- a/rtsp.c +++ b/rtsp.c @@ -708,7 +708,7 @@ void cleanup_threads(void) { conns[i] = NULL; } if (conns[i] != NULL) { - debug(2, "Airplay Volume for connection %d is %.6f.", conns[i]->connection_number, + debug(3, "Airplay Volume for connection %d is %.6f.", conns[i]->connection_number, suggested_volume(conns[i])); connection_count++; } @@ -724,7 +724,7 @@ void cleanup_threads(void) { debug(2, "%d active connections.", connection_count); old_connection_count = connection_count; } - debug(2, "Airplay Volume for new connections is %.6f.", suggested_volume(NULL)); + debug(3, "Airplay Volume for new connections is %.6f.", suggested_volume(NULL)); } // park a null at the line ending, and return the next line pointer @@ -1533,7 +1533,7 @@ int msg_write_response(rtsp_conn_info *conn, rtsp_message *resp) { // Here, if there's content, write the Content-Length header ... if (resp->contentlength) { - debug(2, "Responding with content of length %d", resp->contentlength); + debug(3, "Responding with content of length %d", resp->contentlength); n = snprintf(p, pktfree, "Content-Length: %d\r\n", resp->contentlength); pktfree -= n; p += n; @@ -1675,7 +1675,7 @@ void handle_record(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) { - debug_log_rtsp_message(2, "GET /info:", req); + debug_log_rtsp_message(3, "GET /info:", req); if (rtsp_message_contains_plist(req)) { // it's stage one // get version of AirPlay -- it might be too old. Not using it yet. char *hdr = msg_get_header(req, "User-Agent"); @@ -1684,7 +1684,7 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r hdr = hdr + strlen("AirPlay/"); // double airplay_version = 0.0; // airplay_version = atof(hdr); - debug(2, "Connection %d: GET_INFO: Source AirPlay Version is: %s.", conn->connection_number, + debug(3, "Connection %d: GET_INFO: Source AirPlay Version is: %s.", conn->connection_number, hdr); } } @@ -1707,7 +1707,7 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r debug(1, "GET /info Stage 1: first item in qualifier array not a string"); goto user_fail; } - debug(2, "GET /info Stage 1: qualifier: %s", qualifier_array_val_cstr); + debug(3, "GET /info Stage 1: qualifier: %s", qualifier_array_val_cstr); plist_free(info_plist); free(qualifier_array_val_cstr); @@ -1794,7 +1794,7 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r free(qualifier_response_data); } msg_add_header(resp, "Content-Type", "application/x-apple-binary-plist"); - debug_log_rtsp_message(2, "GET /info Stage 1 Response:", resp); + debug_log_rtsp_message(3, "GET /info Stage 1 Response:", resp); resp->respcode = 200; return; @@ -1819,7 +1819,7 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r plist_to_bin(response_plist, &resp->content, &resp->contentlength); plist_free(response_plist); msg_add_header(resp, "Content-Type", "application/x-apple-binary-plist"); - debug_log_rtsp_message(2, "GET /info Stage 2 Response", resp); + debug_log_rtsp_message(3, "GET /info Stage 2 Response", resp); resp->respcode = 200; return; } @@ -2037,9 +2037,9 @@ void handle_setrateanchori(rtsp_conn_info *conn, rtsp_message *req, rtsp_message } void handle_get(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) { - debug(2, "Connection %d: GET %s :: Content-Length %d", conn->connection_number, req->path, + debug(3, "Connection %d: GET %s :: Content-Length %d", conn->connection_number, req->path, req->contentlength); - debug_log_rtsp_message(2, "GET request", req); + debug_log_rtsp_message(3, "GET request", req); if (strcmp(req->path, "/info") == 0) { handle_get_info(conn, req, resp); } else { @@ -2202,7 +2202,7 @@ void handle_pair_verify(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *r uint8_t *body = NULL; size_t body_len = 0; struct pair_result *result; - debug(2, "Connection %d: pair-verify Content-Length %d", conn->connection_number, + debug(3, "Connection %d: pair-verify Content-Length %d", conn->connection_number, req->contentlength); if (!conn->ap2_pairing_context.verify_ctx) { @@ -2238,7 +2238,7 @@ void handle_pair_verify(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *r resp->contentlength = body_len; if (body) msg_add_header(resp, "Content-Type", "application/octet-stream"); - debug_log_rtsp_message(2, "pair-verify response", resp); + debug_log_rtsp_message(3, "pair-verify response", resp); } void handle_pair_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) { @@ -2284,7 +2284,7 @@ void handle_pair_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *re resp->contentlength = body_len; if (body) msg_add_header(resp, "Content-Type", "application/octet-stream"); - debug_log_rtsp_message(2, "pair-setup response", resp); + debug_log_rtsp_message(3, "pair-setup response", resp); } void handle_fp_setup(__attribute__((unused)) rtsp_conn_info *conn, rtsp_message *req, @@ -2427,9 +2427,9 @@ void handle_configure(rtsp_conn_info *conn __attribute__((unused)), void handle_feedback(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *req, __attribute__((unused)) rtsp_message *resp) { - debug(2, "Connection %d: POST %s Content-Length %d", conn->connection_number, req->path, + debug(3, "Connection %d: POST %s Content-Length %d", conn->connection_number, req->path, req->contentlength); - debug_log_rtsp_message(2, NULL, req); + debug_log_rtsp_message(3, NULL, req); if (conn->airplay_stream_category == remote_control_stream) { plist_t array_plist = plist_new_array(); @@ -2440,7 +2440,7 @@ void handle_feedback(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message plist_free(response_plist); msg_add_header(resp, "Content-Type", "application/x-apple-binary-plist"); - debug_log_rtsp_message(2, "FEEDBACK response (remote_control_stream):", resp); + debug_log_rtsp_message(3, "FEEDBACK response (remote_control_stream):", resp); } /* not finished yet @@ -2468,7 +2468,7 @@ void handle_command(__attribute__((unused)) rtsp_conn_info *conn, rtsp_message * __attribute__((unused)) rtsp_message *resp) { debug(2, "Connection %d: POST %s Content-Length %d", conn->connection_number, req->path, req->contentlength); - debug_log_rtsp_message(2, NULL, req); + debug_log_rtsp_message(3, NULL, req); if (rtsp_message_contains_plist(req)) { plist_t command_dict = NULL; plist_from_memory(req->content, req->contentlength, &command_dict); @@ -2580,9 +2580,9 @@ void handle_post(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) { } void handle_setpeers(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) { - debug(2, "Connection %d: SETPEERS %s Content-Length %d", conn->connection_number, req->path, + debug(3, "Connection %d: SETPEERS %s Content-Length %d", conn->connection_number, req->path, req->contentlength); - debug_log_rtsp_message(2, "SETPEERS request", req); + debug_log_rtsp_message(3, "SETPEERS request", req); /* char timing_list_message[4096]; timing_list_message[0] = 'T'; @@ -2868,7 +2868,7 @@ static void check_and_send_plist_metadata(plist_t messagePlist, const char *plis void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) { int err; debug(2, "Connection %d: SETUP (AirPlay 2)", conn->connection_number); - debug_log_rtsp_message(2, "SETUP (AirPlay 2) SETUP incoming message", req); + debug_log_rtsp_message(3, "SETUP (AirPlay 2) SETUP incoming message", req); plist_t messagePlist = plist_from_rtsp_content(req); plist_t setupResponsePlist = plist_new_dict(); @@ -2965,7 +2965,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) 0) // it should be open already, but just in case it isn't... die("Can not access the NQPTP service. Has it stopped running?"); // clear_ptp_clock(); - debug_log_rtsp_message(2, "SETUP \"PTP\" message", req); + debug_log_rtsp_message(3, "SETUP \"PTP\" message", req); plist_t groupUUID = plist_dict_get_item(messagePlist, "groupUUID"); if (groupUUID) { char *gid = NULL; @@ -3451,7 +3451,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) plist_free(messagePlist); if (clientNameString != NULL) free(clientNameString); - debug_log_rtsp_message(2, " SETUP response", resp); + debug_log_rtsp_message(3, " SETUP response", resp); } #endif @@ -5219,7 +5219,7 @@ static void *rtsp_conversation_thread_func(void *pconn) { #endif while (conn->stop == 0) { - int debug_level = 2; // for printing the request and response + int debug_level = 3; // for printing the request and response // check to see if a conn has been zeroed @@ -5302,7 +5302,7 @@ static void *rtsp_conversation_thread_func(void *pconn) { obfp += 2; }; *obfp = 0; - debug(2, "Content: \"%s\".", obf); + debug(dl, "Content: \"%s\".", obf); } } } @@ -5586,7 +5586,7 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) { pthread_cleanup_push(malloc_cleanup, conn); memset(conn, 0, sizeof(rtsp_conn_info)); conn->connection_number = RTSP_connection_index++; - debug(2, "Connection %d is at: 0x%" PRIxPTR ".", conn->connection_number, conn); + // debug(2, "Connection %d is at: 0x%" PRIxPTR ".", conn->connection_number, conn); #ifdef CONFIG_AIRPLAY_2 conn->airplay_type = ap_2; // changed if an ANNOUNCE is received conn->timing_type = ts_ptp; // changed if an ANNOUNCE is received From 6dd311a1a81a0f1c89521f332f3b1a04b6a752b1 Mon Sep 17 00:00:00 2001 From: Klemens Nanni Date: Sat, 27 Jan 2024 08:27:46 +0100 Subject: [PATCH 18/74] Connect to NQPTP control socket on localhost nqptp.c listens on "localhost", but shairport-sync connectes to the wildcard address 0/0. This apparently works on Linux and FreeBSD, but OpenBSD fails: ``` $ ktrace shairport-sync -v -u [...] 0.000038288 "ptp-utilities.c:243" *fatal error: error sending timing_peer_list to NQPTP 0.000021868 "shairport.c:1728" emergency exit $ kdump [...] 2319 shairport-sync STRU struct sockaddr { AF_INET, 0.0.0.0:9000 } 2319 shairport-sync RET sendto -1 errno 51 Network is unreachable [...] ``` Resolve and connect to "localhost" just like NQPTP does, resulting in 127.0.0.1 or ::1 as socket addresses. This is required to run when configured `--with-airplay-2`. Tested on OpenBSD/amd64 7.4-current with shairport-sync 2.4.3 and nqptp 1.2.5-dev cfa8315 (plus OpenBSD fixes). I expect Linux and FreeBSD to work as before, but have not tested it. --- ptp-utilities.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/ptp-utilities.c b/ptp-utilities.c index 958f65420..e575996fc 100644 --- a/ptp-utilities.c +++ b/ptp-utilities.c @@ -35,8 +35,10 @@ #include #ifdef COMPILE_FOR_FREEBSD #include -#include #endif +#include +#include +#include #define __STDC_FORMAT_MACROS #include "common.h" #include "ptp-utilities.h" @@ -222,28 +224,38 @@ void ptp_send_control_message_string(const char *msg) { msg); debug(2, "Send control message to NQPTP: \"%s\"", full_message); int s; - unsigned short port = htons(NQPTP_CONTROL_PORT); - struct sockaddr_in server; + int ret; + struct addrinfo hints, *info; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; + + /* nqptp is only controllable via localhost */ + char portstr[20]; + snprintf(portstr, 20, "%d", NQPTP_CONTROL_PORT); + + ret = getaddrinfo("localhost", portstr, &hints, &info); + if (ret) { + die("getaddrinfo: %s", gai_strerror(ret)); + } /* Create a datagram socket in the internet domain and use the * default protocol (UDP). */ - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((s = socket(info->ai_family, info->ai_socktype, 0)) < 0) { die("Can't open a socket to NQPTP"); } - /* Set up the server name */ - server.sin_family = AF_INET; /* Internet Domain */ - server.sin_port = port; /* Server Port */ - server.sin_addr.s_addr = 0; /* Server's Address */ - /* Send the message in buf to the server */ - if (sendto(s, full_message, full_message_size, 0, (struct sockaddr *)&server, sizeof(server)) < + if (sendto(s, full_message, full_message_size, 0, info->ai_addr, info->ai_addrlen) < 0) { die("error sending timing_peer_list to NQPTP"); } /* Deallocate the socket */ close(s); + freeaddrinfo(info); /* deallocate the message string */ free(full_message); From dc235275ac628be29ae283870e16817d537da963 Mon Sep 17 00:00:00 2001 From: Klemens Nanni Date: Sat, 27 Jan 2024 19:15:07 +0100 Subject: [PATCH 19/74] No per-socket TCP keepidle on OpenBSD A system-wide sysctl(2) net.inet.tcp.keepidle exists, but there is no setsockopt(2) equivalent. --- definitions.h | 4 ++++ rtsp.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/definitions.h b/definitions.h index f62630261..3eeaf79c7 100644 --- a/definitions.h +++ b/definitions.h @@ -30,6 +30,10 @@ #define COMPILE_FOR_FREEBSD 1 #endif +#if defined(__OpenBSD__) +#define COMPILE_FOR_OPENBSD 1 +#endif + // struct sockaddr_in6 is bigger than struct sockaddr. derp #ifdef AF_INET6 #define SOCKADDR struct sockaddr_storage diff --git a/rtsp.c b/rtsp.c index b9992366f..6ac850504 100644 --- a/rtsp.c +++ b/rtsp.c @@ -5623,6 +5623,7 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) { #define KEEP_ALIVE_OR_IDLE_OPTION TCP_KEEPIDLE #endif +#ifndef COMPILE_FOR_OPENBSD if (setsockopt(conn->fd, SOL_OPTION, KEEP_ALIVE_OR_IDLE_OPTION, (void *)&keepAliveIdleTime, sizeof(keepAliveIdleTime))) { debug(1, "can't set the keepidle wait time"); @@ -5636,6 +5637,7 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) { sizeof(keepAliveInterval))) { debug(1, "can't set the keepidle missing count interval"); }; +#endif // initialise the connection info void *client_addr = NULL, *self_addr = NULL; From 8ae635e78ed93d7029689f39b8c62ded9eef1453 Mon Sep 17 00:00:00 2001 From: Klemens Nanni Date: Sat, 27 Jan 2024 19:40:04 +0100 Subject: [PATCH 20/74] Move shairport-sync manual from section 7 to 1 From mandoc man(1) [-s] section: 1 General commands (tools and utilities). [...] 7 Miscellaneous information. From GNU man(1) DESCRIPTION: 1 Executable programs or shell commands [...] 7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7) shairport-sync is an executable, shairport-sync(1) ought to be its documentation, not merely miscellaneous information. OpenBSD adjusts this in its audio/shairport-sync port/package ever since. --- Makefile.am | 2 +- docker/Dockerfile | 2 +- docker/classic/Dockerfile | 2 +- man/Makefile | 12 ++++++------ man/{shairport-sync.7 => shairport-sync.1} | 2 +- man/{shairport-sync.7.xml => shairport-sync.1.xml} | 2 +- shairport-sync.spec | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) rename man/{shairport-sync.7 => shairport-sync.1} (99%) rename man/{shairport-sync.7.xml => shairport-sync.1.xml} (99%) diff --git a/Makefile.am b/Makefile.am index d9cfbf6ec..9c2bed222 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ARFLAGS = cr -man_MANS = $(top_srcdir)/man/shairport-sync.7 +man_MANS = $(top_srcdir)/man/shairport-sync.1 lib_pair_ap_a_CFLAGS = -Wall -g -DCONFIG_GCRYPT -pthread lib_tinyhttp_a_CFLAGS = -pthread diff --git a/docker/Dockerfile b/docker/Dockerfile index da8688ed3..c6da2efdb 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -95,7 +95,7 @@ RUN apk -U add \ # Copy build files. COPY --from=builder /shairport-sync/build/install/usr/local/bin/shairport-sync /usr/local/bin/shairport-sync -COPY --from=builder /shairport-sync/build/install/usr/local/share/man/man7 /usr/share/man/man7 +COPY --from=builder /shairport-sync/build/install/usr/local/share/man/man1 /usr/share/man/man1 COPY --from=builder /nqptp/nqptp /usr/local/bin/nqptp COPY --from=builder /usr/local/lib/libalac.* /usr/local/lib/ COPY --from=builder /shairport-sync/build/install/etc/shairport-sync.conf /etc/ diff --git a/docker/classic/Dockerfile b/docker/classic/Dockerfile index 9f5c0fe62..d59784107 100644 --- a/docker/classic/Dockerfile +++ b/docker/classic/Dockerfile @@ -75,7 +75,7 @@ RUN apk -U add \ # Copy build files. COPY --from=builder /shairport-sync/build/install/usr/local/bin/shairport-sync /usr/local/bin/shairport-sync -COPY --from=builder /shairport-sync/build/install/usr/local/share/man/man7 /usr/share/man/man7 +COPY --from=builder /shairport-sync/build/install/usr/local/share/man/man1 /usr/share/man/man1 COPY --from=builder /usr/local/lib/libalac.* /usr/local/lib/ COPY --from=builder /shairport-sync/build/install/etc/shairport-sync.conf /etc/ COPY --from=builder /shairport-sync/build/install/etc/shairport-sync.conf.sample /etc/ diff --git a/man/Makefile b/man/Makefile index 0c30fe4b2..53cceef80 100644 --- a/man/Makefile +++ b/man/Makefile @@ -1,11 +1,11 @@ -shairport-sync.7: shairport-sync.7.xml - xmltoman shairport-sync.7.xml > shairport-sync.7 +shairport-sync.1: shairport-sync.1.xml + xmltoman shairport-sync.1.xml > shairport-sync.1 -shairport-sync.html: shairport-sync.7.xml - xsltproc xmltoman.xsl shairport-sync.7.xml > shairport-sync.html +shairport-sync.html: shairport-sync.1.xml + xsltproc xmltoman.xsl shairport-sync.1.xml > shairport-sync.html -all: shairport-sync.7 shairport-sync.html +all: shairport-sync.1 shairport-sync.html clean: - rm shairport-sync.7 + rm shairport-sync.1 rm shairport-sync.html diff --git a/man/shairport-sync.7 b/man/shairport-sync.1 similarity index 99% rename from man/shairport-sync.7 rename to man/shairport-sync.1 index 345e75ded..2d2de85d3 100644 --- a/man/shairport-sync.7 +++ b/man/shairport-sync.1 @@ -1,4 +1,4 @@ -.TH shairport-sync 7 User Manuals +.TH shairport-sync 1 User Manuals .SH NAME shairport-sync \- AirPlay and AirPlay 2 Audio Player .SH SYNOPSIS diff --git a/man/shairport-sync.7.xml b/man/shairport-sync.1.xml similarity index 99% rename from man/shairport-sync.7.xml rename to man/shairport-sync.1.xml index 43dd4b15e..240a8e45d 100644 --- a/man/shairport-sync.7.xml +++ b/man/shairport-sync.1.xml @@ -29,7 +29,7 @@ OTHER DEALINGS IN THE SOFTWARE. --> - +