HydraIssues

Phase 4: playback control (play/stop/volume) on venue audio via hydraroar
closed feature Priority: low Project: hydraroar Reporter: anonymous 26 Aug 2026 23:41

Description

Phase 4 of the venue audio layer (#540, closed): drive playback on venue audio systems through hydraroar. All control lives in hydraroar as new commands and API endpoints; never a separate service, and hydravoice (the mic relay) stays untouched.

Scope (v1)

  1. Mechanics: Sonos S2 local UPnP on the same port 1400 surface the probe already uses. AVTransport SetAVTransportURI + Play/Stop for network streams, RenderingControl for volume, existing ZoneGroupTopology data for room targeting. No Sonos cloud account, no API keys; local-first like the scan.
  2. CLI: hydraroar play --target <ip|room> <stream-url>, hydraroar stop [--target ...|--all], hydraroar volume --target <ip|room> <0-100>. Room names resolve via a probe first, so targets can be human ("Bar") not just IPs.
  3. Serve API: token-guarded POST /api/v1/play, /api/v1/stop, /api/v1/volume mirroring the CLI, same JSON discipline as /api/v1/probe (additive fields only). Callers: operators first; experiences via hydracluster later, always through this API, never speaking UPnP themselves.
  4. Reach: identical to the probe path. Routed venues go through the scale; cloud-seven runs through the CLI on cosmic-pretzel-98 until #550/#554 land. Both cloud-seven units are Sonos Ports feeding the venue PA, so "play on the Sonos" means "play over the venue PA".

Design questions to settle before code

  • Authorization: playback is a physical actuator in a client space, not a read. A single bearer token is not enough. Decide: venue-scoped tokens or claims, an operator kill switch (stop --all must always work with the base token), and whether volume gets a cap per venue.
  • Guardrails: default volume on play, max volume, and whether play is refused outside configured venue hours.
  • Audit: every play/stop/volume call logged with caller identity (the serve log already logs probes; extend the pattern).

Non-goals (v1)

  • Streaming body/experience audio INTO Sonos (needs a stream the player can pull; possible follow-on once basic control works).
  • Scheduling, playlists, announcements/TTS.
  • Non-Sonos audio systems (the API shape should not preclude them, but no second vendor in v1).

Acceptance

On a venue with a reachable player: play a test stream to one room via CLI and via the API, change volume, stop, and stop-all; unauthorized calls rejected; every action in the log. Runbook section for operators plus a testbook procedure, per the repo docs convention. Smoke on cloud-seven runs through cosmic until reach lands.

Depends on: #550 or #554 only for scale-side control at cloud-seven; CLI-side control is testable as soon as v1 exists.

UPDATE 2026-08-27: downgraded to nice-to-have (priority low). Venue staff already control playback through the Sonos app; active control from Hydra adds little until an experience needs it. The valuable near-term piece is READ-ONLY playback state, split out as its own issue (hydraroar status). Revisit this one when an experience actually needs to drive the PA.

DONE 2026-09-10, hydraroar v0.4.0 (guards deferred by owner decision)

play/stop/volume shipped: SetAVTransportURI (stream URL or own line-in), Play/Pause/Stop, SetVolume/SetMute in pkg/sonos; CLI play --target <ip> [--uri|--line-in], stop, volume; token-guarded POST /api/v1/play|stop|volume on the scale. NO caps or venue scoping for now, per owner: the bearer token is the whole guard; every action logged. The auth/guardrail design questions above stay parked until more callers than the owner exist.

Verified silently on cosmic against the Yoga Port (volume 0): play line-in -> PLAYING/line-in (first live PLAYING observation), stop -> PAUSED_PLAYBACK (line-in nuance, documented). Deployed as scale v0.4.0 via the now fully working stateless one-command update (hydraskin v0.14.1: the v0.13.0 fix only gated the command-level check, Apply's own guard refused; fixed and covered by a rebuild-reaching test).