Add experimental --no-audio-advertise option (narrow AirPlay advertisement) - #534
Add experimental --no-audio-advertise option (narrow AirPlay advertisement)#534erseco wants to merge 2 commits into
Conversation
macOS/iOS may auto-select UxPlay as the system audio output during mirroring even when -a/-as 0 is used, since that flag only disables local server-side playback and does not change the AirPlay/DNS-SD advertisement. Add an opt-in, experimental --no-audio-advertise [bits|raop|both] flag that narrows the actual advertisement (clearing the audio-support feature bits and/or skipping _raop._tcp registration), add a startup warning when -a is used alone, and add a CTest-based unit test harness (the project had none) covering the new CLI parsing, the exact AirPlay feature-bitmask regression, and help text. Per upstream issues FDH2#303/FDH2#442/FDH2#489, clearing the audio-support feature bit is known to cause some AirPlay clients to TEARDOWN mirroring after ~60 seconds, with no fix found so far; this is documented as a known, unresolved risk in specs/no-audio-advertisement.md rather than claimed as solved.
The raop TXT buffer is only built by dnssd_register_raop(), so with --no-audio-advertise raop|both the BLE service-discovery/GET /info response carried an empty txtRAOP data node. Skip emitting a TXT record whose buffer was never built (length 0), keeping the GET /info path consistent with the mDNS advertisement while preserving the existing fallback where a failed (not skipped) _raop._tcp registration still serves its TXT over BLE (both backends build the TXT before the network registration step). Verified on real hardware (Ubuntu 25.10 server, macOS Mac17,3 client): the CSeq-less 'GET /info?txtAirPlay?txtRAOP RTSP/1.0' probe now returns txtAirPlay only in raop/both modes.
|
Pushed 9072b77 addressing the BLE service-discovery gap @fduncanh pointed out in #533: I've also now run the manual test plan on real hardware (Ubuntu 25.10 server / macOS
I also tested the event-channel hypothesis from #489 (full details and a significant finding in #533: a receiver-initiated "hot audio downgrade" over the event channel gets indefinite video-only mirroring — the ~60s watchdog only applies to sessions that start without audio). That experiment lives on a separate branch (https://github.com/erseco/UxPlay/tree/event-channel-experiment) and is deliberately not part of this PR. |
97faa76 to
9c24ed2
Compare
|
this is very interesting for experiments, but won't get added to the uxplay codebase. It was interesting to learn that an event channel can be used modify the FEATURES bitstring stored by the client . |
|
Thanks for taking the time to review this, and sorry I didn’t follow up sooner. I eventually stopped pursuing this approach because, although the event-channel experiment was very interesting, it still couldn’t make macOS automatically switch back to the local audio output. For my actual use case, I ended up using a small macOS automation to select the correct audio device after mirroring starts. Still, I learned a lot from the experiment, and I’m glad some of the findings were useful. A bit of overengineering for a small problem, but that’s part of the fun! Please feel free to close #533 as well. Thanks again for your time and feedback. |
Summary
--no-audio-advertise [bits|raop|both]option that narrows the AirPlay/DNS-SD advertisement (clearing the feature bits claiming audio support and/or skipping_raop._tcpregistration) so macOS/iOS are less likely to route audio to UxPlay during mirroring.-a/-as 0behavior is unchanged; they now emit a startup warning explaining they don't affect the advertisement.specs/no-audio-advertisement.mdanddocs/manual-test-no-audio-advertise.md.Context
Relates to #533, and to the discussion in #303, #442, #463, #489. Clearing the audio-support feature bit (
bitsmode) reproduces the known ~60s clientTEARDOWNwith no fix found — this PR documents that rather than claiming to solve it, and adds araop-only mode (untested before) in case it behaves differently. Opening mainly for feedback given your deeper protocol knowledge here.Test plan
cmake -B build && cmake --build build --parallel && ctest --test-dir build --output-on-failure(all green locally)Mac17,3, srcvers 940.23.1); results in Option to avoid being selected as macOS audio output when audio is disabled #533 and summarized belowUpdate (2026-07-04)
GET /infohandler now omits a TXT record whose buffer was never built, closing the BLE service-discovery gap @fduncanh pointed out in Option to avoid being selected as macOS audio output when audio is disabled #533 (an emptytxtRAOPnode was previously returned inraop/bothmodes). Wire-verified with a CSeq-less RTSP probe; the failed-registration BLE fallback is unaffected.Mac17,3client, srcvers 940.23.1) — full results in Option to avoid being selected as macOS audio output when audio is disabled #533. Summary:bothmode achieves the goal (macOS keeps its current audio output; the client doesn't even request a type-96 stream) but reproduces the known client watchdog teardown at ~37–92s;raopmode shows_raop._tcpis not required for mirroring (bit 30 covers it) but doesn't affect audio routing or the watchdog.Scope — what this PR is, and what a complete "video-only mirroring" needs
To be upfront about how far this actually gets, after real-hardware testing:
Solid and mergeable on its own (independent of the audio-routing question):
GET /infoBLE-path fix (9072b77).--no-audio-advertiseis an honest but incomplete advertisement lever:bothkeeps audio on the Mac, but the client tears the video down after ~30–90s (the #303/#442/#489 watchdog). So it is opt-in/experimental and not a standalone "video-only" mode.A genuinely working indefinite video-only mirror is possible, but takes two more pieces beyond this PR (documented in #533; the receiver half is on a separate
event-channel-experimentbranch, intentionally not included here):updateInfo(audio feature bits cleared) and withdraw_raop._tcp/ clear the live_airplayaudio bits. The client then tears down only its audio stream and mirrors video indefinitely (verified 240s+, no watchdog). This is new: it defeats the teardown that No obvious solution to "iOS clients do play audio on client with video mirrored on server if feature bit 9 (audio support) is disabled on server" , but close video connection after 60 secs(was:Can the audio be directed to Bluetooth headphones or remain on the mobile phone? #303/Is there a way to run UxPlay so that only video is streamed, and the iPhone leaves the audio paths alone #442/Feature request: need video only mode so that audio can be played with no latency #489 concluded was unsolvable.supportedFormats,statusFlags, mDNS withdrawal all tested negative), and it is not receiver-fixable: even a real Mac acting as an AirPlay receiver advertises full audio support (features=0x4A7FCFD5,_raop._tcpregistered) — Apple has no "video-only" receiver mode. So a complete experience needs either a one-time manual switch of the Mac's audio output back to local, or a small macOS-side CoreAudio helper that reverts the default output when it becomes AirPlay.In short: this PR's
--no-audio-advertise+ the event-channel branch get "video mirrors forever, audio stays off the receiver," but the last step (macOS keeping/returning its output to local) is inherently client-side. Happy to take any of this in whatever direction you prefer — merge just the BLE fix + tests, keep the experimental flag, or fold in the event-channel work.