Repository navigation
Control TTS playback from the OS media session - #43
Merged
Merged
Conversation
Registers TTS audio with the OS-level media session (macOS Now Playing, hardware media keys, Bluetooth headset buttons) so play/pause and word-level seek work outside the app. Also wires up metadata (title/artist/artwork) for the OS Now Playing display, with an app-icon fallback when a book has no cover. A raw AudioContext graph is invisible to the OS media session bridge in Chromium/Firefox, so a near-silent, file-backed decoy <audio> element is played alongside the real TTS output purely to register the tab as playing real media. It's armed as soon as the Audio panel opens (primed then paused, so the OS state honestly reflects that nothing is playing yet) so the OS Play button works immediately.
skipWords() was syncing ttsStore.currentWordIndex to the new target even while paused, which made the reader position and the TTS store position match again. handleToggle's paused-resume path uses that same equality to decide whether to reseek, so it concluded nothing had moved and resumed playback from ttsPlayer's own stale internal sentence index instead of the skipped-to one. Leaving ttsStore.currentWordIndex untouched while paused lets that mismatch check do its job again — startFromSentence() sets it correctly once real playback actually restarts.
Low-amplitude noise was audible as static/hum on some devices, iOS Safari in particular where it made TTS unusable, and a random noise loop has no zero-crossing at the seam, causing an audible click every loop. All-zero samples fix both: no perceptible output, and a click-free loop.
tomazzinko
marked this pull request as draft
August 20, 2026 17:02
tomazzinko
marked this pull request as ready for review
August 20, 2026 17:08
Owner
|
sick lol |
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.
Summary
<audio>element is played alongside the real TTS output purely to register the tab as playing real media. It's armed (primed then paused) as soon as the Audio panel opens, so the OS Play button works immediately, without leaving the decoy audibly playing before the user actually starts playback.ttsPlayer's internal position wasn't being told about the skip).Test plan
npm run build(typecheck + full test suite via pre-commit hook) — 801 tests passingplay/pause/seekforward/seekbackwardhandlers correctly control real TTS playback and reflect state back tonavigator.mediaSession