Conversation
At the end of probing, cache_host_is_known() treats any cached A or AAAA record for our host name as a conflict, and umdns stops announcing on that interface for good. On a network with an mDNS reflector, umdns receives its own probe and its own answers back, caches them, and so finds a conflict with itself: the host OpenWrt.local already exists. stopping announce service It then never announces its host or services on that interface. RFC 6762 section 9 only treats records with different data as a conflict. Ignore cached address records that carry one of our own interface addresses. Signed-off-by: Michaël Guay-Lambert <michaelguaylambert@me.com>
Since commit a2b4979 ("service: announce all services in single dns answer"), service_announce_services() only sends the service type PTR records, so an interface coming up announces the host records and the service types but not the service instances themselves (instance PTR, SRV and TXT). A service registered before its interface has an address, as happens at boot when a DHCP lease arrives after the service starts, is therefore never announced, and a browser that already dropped it only finds it again on its next query. RFC 6762 section 8.3 requires announcing all newly registered records. Send the service instances once probing succeeds, without adding them to the periodic refresh of STATE_ANNOUNCE. Signed-off-by: Michaël Guay-Lambert <michaelguaylambert@me.com>
This was referenced Sep 14, 2026
This was referenced Sep 20, 2026
Merged
mguaylam
added a commit
to mguaylam/packages
that referenced
this pull request
Sep 22, 2026
Sendspin is the synchronized multi-room audio protocol used by Music Assistant, and sendspin-cli is its headless player. It plays through ALSA, so a router with a USB DAC becomes a player in the same way snapcast and shairport-sync already allow here. Upstream builds its dependencies with CMake FetchContent. Rather than patch that out, each archive is downloaded through its own Download block and handed to CMake with FETCHCONTENT_SOURCE_DIR_<NAME>, with FETCHCONTENT_FULLY_DISCONNECTED=ON so the build never reaches the network. micro-opus, which bundles a copy of Opus, is replaced by a small CMake shim that links the feed's libopus through pkg-config. The package therefore carries no patches and no vendored code. The init script is procd-based and validates its UCI section with uci_load_validate. The player is built without mDNS and announced by umdns through procd_add_mdns instead. Two behaviours are worth explaining rather than leaving to be found: service_stopped() waits for the player to exit and then reloads umdns. The player says goodbye with reason 'shutdown' whenever it stops, and a server reconnects only once mDNS announces it again; umdns announces a service when it appears and withdraws it when it disappears, but a restart that swaps a service for an identical one does neither. The iface hotplug script restarts the player when a network umdns announces on comes up. The umdns in 25.12 does not announce service instances when a network comes up, and on a network with an mDNS reflector it takes its own reflected probe for a name conflict and stops announcing, so the player is not rediscovered after a reboot. Both are addressed by a pending pull request, openwrt/mdnsd#36; the script goes away when it ships. The package is not offered on big-endian targets. Software volume, the Opus decoder and micro-flac's sample packing all write samples in host byte order into buffers the ALSA sink opens as _LE, so playback there would be wrong rather than merely imperfect. All three are reproduced under qemu-mips-static and reported upstream; the guard is one line and comes off when they are fixed. Tested on ramips/mt7621 (D-Link DIR-3040, mipsel_24kc) with a USB DAC: over 49 hours of uninterrupted playback, no XRUN or underrun, 1.45 MiB installed, 5 MiB resident, and 6.3% of one 880 MHz thread decoding FLAC 48 kHz/16-bit with software volume. The in-place upgrade path and config preservation were verified on the same device. Signed-off-by: Michaël Guay-Lambert <michaelguaylambert@me.com>
mguaylam
added a commit
to mguaylam/packages
that referenced
this pull request
Sep 22, 2026
Sendspin is the synchronized multi-room audio protocol used by Music Assistant, and sendspin-cli is its headless player. It plays through ALSA, so a router with a USB DAC becomes a player in the same way snapcast and shairport-sync already allow here. Upstream builds its dependencies with CMake FetchContent. Rather than patch that out, each archive is downloaded through its own Download block and handed to CMake with FETCHCONTENT_SOURCE_DIR_<NAME>, with FETCHCONTENT_FULLY_DISCONNECTED=ON so the build never reaches the network. micro-opus, which bundles a copy of Opus, is replaced by a small CMake shim that links the feed's libopus through pkg-config. The package therefore carries no patches and no vendored code. The init script is procd-based and validates its UCI section with uci_load_validate. The player is built without mDNS and announced by umdns through procd_add_mdns instead. Two behaviours are worth explaining rather than leaving to be found: service_stopped() waits for the player to exit and then reloads umdns. The player says goodbye with reason 'shutdown' whenever it stops, and a server reconnects only once mDNS announces it again; umdns announces a service when it appears and withdraws it when it disappears, but a restart that swaps a service for an identical one does neither. The iface hotplug script restarts the player when a network umdns announces on comes up. The umdns in 25.12 does not announce service instances when a network comes up, and on a network with an mDNS reflector it takes its own reflected probe for a name conflict and stops announcing, so the player is not rediscovered after a reboot. Both are addressed by a pending pull request, openwrt/mdnsd#36; the script goes away when it ships. The package is not offered on big-endian targets. Software volume, the Opus decoder and micro-flac's sample packing all write samples in host byte order into buffers the ALSA sink opens as _LE, so playback there would be wrong rather than merely imperfect. All three are reproduced under qemu-mips-static and reported upstream; the guard is one line and comes off when they are fixed. Tested on ramips/mt7621 (D-Link DIR-3040, mipsel_24kc) with a USB DAC: over 49 hours of uninterrupted playback, no XRUN or underrun, 1.45 MiB installed, 5 MiB resident, and 6.3% of one 880 MHz thread decoding FLAC 48 kHz/16-bit with software volume. The in-place upgrade path and config preservation were verified on the same device. Signed-off-by: Michaël Guay-Lambert <mguaylam.dev@gmail.com>
mguaylam
added a commit
to mguaylam/packages
that referenced
this pull request
Sep 22, 2026
Sendspin is the synchronized multi-room audio protocol used by Music Assistant, and sendspin-cli is its headless player. It plays through ALSA, so a router with a USB DAC becomes a player in the same way snapcast and shairport-sync already allow here. Upstream builds its dependencies with CMake FetchContent. Rather than patch that out, each archive is downloaded through its own Download block and handed to CMake with FETCHCONTENT_SOURCE_DIR_<NAME>, with FETCHCONTENT_FULLY_DISCONNECTED=ON so the build never reaches the network. micro-opus, which bundles a copy of Opus, is replaced by a small CMake shim that links the feed's libopus through pkg-config. The package therefore carries no patches and no vendored code. The init script is procd-based and validates its UCI section with uci_load_validate. The player is built without mDNS and announced by umdns through procd_add_mdns instead. Two behaviours are worth explaining rather than leaving to be found: service_stopped() waits for the player to exit and then reloads umdns. The player says goodbye with reason 'shutdown' whenever it stops, and a server reconnects only once mDNS announces it again; umdns announces a service when it appears and withdraws it when it disappears, but a restart that swaps a service for an identical one does neither. The iface hotplug script restarts the player when a network umdns announces on comes up. The umdns in 25.12 does not announce service instances when a network comes up, and on a network with an mDNS reflector it takes its own reflected probe for a name conflict and stops announcing, so the player is not rediscovered after a reboot. Both are addressed by a pending pull request, openwrt/mdnsd#36; the script goes away when it ships. The package is not offered on big-endian targets. Software volume, the Opus decoder and micro-flac's sample packing all write samples in host byte order into buffers the ALSA sink opens as _LE, so playback there would be wrong rather than merely imperfect. All three are reproduced under qemu-mips-static and reported upstream; the guard is one line and comes off when they are fixed. Tested on ramips/mt7621 (D-Link DIR-3040, mipsel_24kc) with a USB DAC: over 49 hours of uninterrupted playback, no XRUN or underrun, 1.45 MiB installed, 5 MiB resident, and 6.3% of one 880 MHz thread decoding FLAC 48 kHz/16-bit with software volume. The in-place upgrade path and config preservation were verified on the same device. Signed-off-by: Michaël Guay-Lambert <mguaylam.dev@gmail.com>
mguaylam
added a commit
to mguaylam/packages
that referenced
this pull request
Sep 22, 2026
Sendspin is the synchronized multi-room audio protocol used by Music Assistant, and sendspin-cli is its headless player. It plays through ALSA, so a router with a USB DAC becomes a player in the same way snapcast and shairport-sync already allow here. Upstream builds its dependencies with CMake FetchContent. Rather than patch that out, each archive is downloaded through its own Download block and handed to CMake with FETCHCONTENT_SOURCE_DIR_<NAME>, with FETCHCONTENT_FULLY_DISCONNECTED=ON so the build never reaches the network. micro-opus, which bundles a copy of Opus, is replaced by a small CMake shim that links the feed's libopus through pkg-config. The package therefore carries no patches and no vendored code. The init script is procd-based and validates its UCI section with uci_load_validate. The player is built without mDNS and announced by umdns through procd_add_mdns instead. Two behaviours are worth explaining rather than leaving to be found: service_stopped() waits for the player to exit and then reloads umdns. The player says goodbye with reason 'shutdown' whenever it stops, and a server reconnects only once mDNS announces it again; umdns announces a service when it appears and withdraws it when it disappears, but a restart that swaps a service for an identical one does neither. The iface hotplug script restarts the player when a network umdns announces on comes up. The umdns in 25.12 does not announce service instances when a network comes up, and on a network with an mDNS reflector it takes its own reflected probe for a name conflict and stops announcing, so the player is not rediscovered after a reboot. Both are addressed by a pending pull request, openwrt/mdnsd#36; the script goes away when it ships. The package is not offered on big-endian targets. Software volume, the Opus decoder and micro-flac's sample packing all write samples in host byte order into buffers the ALSA sink opens as _LE, so playback there would be wrong rather than merely imperfect. All three are reproduced under qemu-mips-static and reported upstream; the guard is one line and comes off when they are fixed. Tested on ramips/mt7621 (D-Link DIR-3040, mipsel_24kc) with a USB DAC: over 49 hours of uninterrupted playback, no XRUN or underrun, 1.45 MiB installed, 5 MiB resident, and 6.3% of one 880 MHz thread decoding FLAC 48 kHz/16-bit with software volume. The in-place upgrade path and config preservation were verified on the same device. Signed-off-by: Michaël Guay-Lambert <mguaylam.dev@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On a router behind a network that runs an mDNS reflector, services registered through
procd_add_mdnswere never announced after a reboot. A Sendspin audio player announced this way was not rediscovered by its server for over ten minutes, until the server happened to query again. Two independent issues combine; one commit each.1.
cache: our own address records are taken for a probe conflictWith
umdns -d, umdns receives its ownANY OpenWrt.localprobe and its own answers back from the reflector, cachesA OpenWrt.localwith its own address, and atSTATE_PROBE_END:It then never announces anything on that interface. RFC 6762 §9 only treats records whose data differs as conflicts, so cached address records carrying one of our own interface addresses are now ignored.
This is complementary to #33, which renames the host when a conflict is detected: on such a network, #33 alone would rename the host because of its own echo.
2.
announce: service instances are not announced when an interface comes upSince a2b4979 ("service: announce all services in single dns answer"),
service_announce_services()sends only the service type PTRs. An instance is announced when it is added, but if that happens before its interface has an address (a DHCP lease arriving after the service starts at boot), the instance PTR/SRV/TXT records are never announced. RFC 6762 §8 and §8.3 ask for all records to be announced on startup and link change. They are now sent once, when probing succeeds, and are not added to the periodicSTATE_ANNOUNCErefresh.Testing
OpenWrt 25.12.5,
ramips/mt7621, umdns announcing on a DHCP-configured bridge, network with an mDNS reflector, Music Assistant as the Sendspin server:1b5e7bf1)Both commits apply to and build on current
master(dbee550) with the project's-Werror, cross-compiled with the 25.12.5 SDK.