Skip to content

Add announcement role (announcement@v1) skeleton - #101

Draft
marcelveldt wants to merge 2 commits into
mainfrom
announcement-role
Draft

marcelveldt wants to merge 2 commits into
mainfrom
announcement-role

Conversation

@marcelveldt

@marcelveldt marcelveldt commented Jul 23, 2026

Copy link
Copy Markdown

Draft client-side reference implementation for the announcement@v1 role proposed in Sendspin/spec#126: short per-client audio clips (TTS, chimes, alerts) decoded on a second pipeline next to the media stream, with the ducking policy handed to the embedder. Opened alongside the spec PR so the discussion has a concrete client shape to poke at; it tracks the spec.

What's here

  • Wire surface: announcement@v1 role id, AnnouncementSupportObject (formats + own buffer_capacity) in client/hello, stream/start.announcement parsing (codec params, a single required start_timestamp, media_duck_db 0-50 / duck_ramp_ms 0-2000 / optional volume / optional override_mute, out-of-range values dropped to defaults), client/state.announcement, and binary type 24 (SENDSPIN_ROLE_ANNOUNCEMENT = 6, routed through get_binary_role() unchanged). Chunks are untimed: the stream's single start time rides the codec header.
  • AnnouncementRole following the add-a-role pattern, with an AnnouncementRoleListener the embedder implements: on_announcement_write() (PCM, task thread) plus on_announcement_start/end() (main loop). on_announcement_start() carries the duck params, start_timestamp and override_mute (that's where e.g. ESPHome calls apply_ducking()); it also re-fires when the server re-sends stream/start to update config in place. on_announcement_end() fires on server end, local completion, abort, and transport loss alike, so media can never stay stuck ducked.
  • AnnouncementTask: a dedicated lightweight decode task (own ring buffer + decoder, one extra thread). No sync machinery: output begins at the single start_timestamp via the time filter (or as soon as possible), which is also what aligns a coordinated multi-speaker start; chunks are never dropped for lateness and a stalled stream ends locally after 5 s.
  • Lifecycle: stream/end with omitted roles ends announcements too; stream/clear is media-scoped and never touches the announcement stream (replacing a clip is a stream/end then a new stream/start).
  • Build gate: SENDSPIN_ENABLE_ANNOUNCEMENT (Kconfig default n while the spec settles; depends on SENDSPIN_ENABLE_PLAYER, which supplies the ring buffer and decoder).
  • Tests: protocol round-trip coverage (hello support, stream/start defaults/validation including the required start_timestamp and override_mute, client/state, binary allocation) plus a config-update-in-place test. Host build is clean under -Wall -Wextra -Wpedantic; the full suite passes.

Not here yet

  • The ESPHome layer (a SendspinAnnouncementSource feeding the speaker_source pipeline plus duck-parameter plumbing) lives in the esphome repo and needs a released sendspin-cpp first.
  • Gain handling: duck, announcement volume, and override_mute are applied by the embedder at the sink/mixer; the library only transports the parameters.

Marked draft until the spec PR settles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant