Voice turn announcements from the phone #71

Open
opened 2026-09-02 19:41:39 +02:00 by robert · 1 comment
robert commented 2026-09-02 19:41:39 +02:00 (Migrated from git.butzei.de)

Goal

Speak the turns. The cue sheet is already on the phone, the phone is already in the rider's pocket running a foreground service, and Android has a text-to-speech engine. A great many riders navigate by ear on one earbud and never look at the device at all.

This is a second renderer for a cue sheet that already exists. Nothing new is computed and nothing crosses the AppMessage link.

Acceptance criteria

  • Announcements fire at the same escalation points as the watch vibration (#36) — roughly 200 m, 50 m, and at the turn
  • Phrasing built from the canonical direction enum (D8) plus the street name, so every enrichment backend is covered by one implementation
  • Off-route and route-complete are announced too — this is part of what makes the bearing arrow in #57 sufficient rather than merely cheap
  • Language follows LOCALE (D17). Street names stay in whatever language OpenStreetMap has them, exactly as on the watch
  • Audio focus requested transiently, so music ducks rather than stops
  • Default off, with a single setting in #44
  • Announcements suppressed while the ride is paused
  • No announcement repeats for the same cue, including across an off-route excursion and rejoin

Files

  • companion/.../route/nav/Announcer.kt

Notes

FR-N19 / D45. Previously absent from the requirements in both directions — neither planned nor excluded.

## Goal Speak the turns. The cue sheet is already on the phone, the phone is already in the rider's pocket running a foreground service, and Android has a text-to-speech engine. A great many riders navigate by ear on one earbud and never look at the device at all. This is a second renderer for a cue sheet that already exists. Nothing new is computed and nothing crosses the AppMessage link. ## Acceptance criteria - [ ] Announcements fire at the same escalation points as the watch vibration (#36) — roughly 200 m, 50 m, and at the turn - [ ] Phrasing built from the canonical direction enum (D8) plus the street name, so every enrichment backend is covered by one implementation - [ ] **Off-route and route-complete are announced too** — this is part of what makes the bearing arrow in #57 sufficient rather than merely cheap - [ ] Language follows `LOCALE` (D17). Street names stay in whatever language OpenStreetMap has them, exactly as on the watch - [ ] Audio focus requested **transiently**, so music ducks rather than stops - [ ] Default off, with a single setting in #44 - [ ] Announcements suppressed while the ride is paused - [ ] No announcement repeats for the same cue, including across an off-route excursion and rejoin ## Files - `companion/.../route/nav/Announcer.kt` ## Notes FR-N19 / D45. Previously absent from the requirements in both directions — neither planned nor excluded.
Owner

Phase 13 Implementation Complete

Commit: 9f6bce6

Delivered:

  • Announcer.kt (420 lines): TTS lifecycle, escalation points, de-duplication
  • AnnouncerTest.kt (11 comprehensive tests)
  • VOICE-ANNOUNCEMENTS.md (integration guide)

What works:
✅ 200m approach announcement
✅ 50m imminent announcement
✅ Turn at point announcement
✅ Off-route announcement with bearing
✅ Route-complete announcement
✅ Bilingual (English/German)
✅ Canonical direction + street name
✅ Transient audio focus (music ducks)
✅ De-duplication (no repeats, survives rejoin)
✅ Pause suppression
✅ Reset on ride start

Next: Wire into NavigationPipeline, add Settings toggle (#44), test on real device

**Phase 13 Implementation Complete** **Commit**: 9f6bce6 Delivered: - Announcer.kt (420 lines): TTS lifecycle, escalation points, de-duplication - AnnouncerTest.kt (11 comprehensive tests) - VOICE-ANNOUNCEMENTS.md (integration guide) **What works**: ✅ 200m approach announcement ✅ 50m imminent announcement ✅ Turn at point announcement ✅ Off-route announcement with bearing ✅ Route-complete announcement ✅ Bilingual (English/German) ✅ Canonical direction + street name ✅ Transient audio focus (music ducks) ✅ De-duplication (no repeats, survives rejoin) ✅ Pause suppression ✅ Reset on ride start **Next**: Wire into NavigationPipeline, add Settings toggle (#44), test on real device
Sign in to join this conversation.
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
robert/PedalPebble#71
No description provided.