feat(messaging): voice messages with record + waveform #92

Merged
nrupard merged 1 commit from feat/voice-messages into main 2026-05-14 17:28:04 +02:00
Owner

Adds browser-recorded voice messages that render in the timeline as a playable clip with a waveform.

Recording: a mic button in the composer captures audio via MediaRecorder with the browser's default audio processing; the clip is decoded client-side to compute a normalized waveform and its exact duration, then uploaded through the existing /api/upload endpoint with a kind=voice flag and a waveform JSON blob.

Storage: the upload handler canonicalizes the sniffed container MIME (Chrome webm / Firefox ogg / Safari mp4) to a stable audio/* type, validates and clamps the waveform, and stores it in a new nullable file_uploads.waveform column (migration 0022) as {"d":duration,"p":[peaks]}.

Playback: messages render a canvas waveform player wired by a persistent script in layout.html. Playback uses the Web Audio API (decodeAudioData + AudioBufferSourceNode) rather than an element, which avoids a start-of-clip decode glitch on MediaRecorder webm/opus; the stored duration drives an accurate progress bar since the container itself carries none. Seeking restarts the source node synchronously.

Composer: a voice (or file) attachment alone, with no text, is now a valid send via both the send button and the Enter key.

Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com

Adds browser-recorded voice messages that render in the timeline as a playable clip with a waveform. Recording: a mic button in the composer captures audio via MediaRecorder with the browser's default audio processing; the clip is decoded client-side to compute a normalized waveform and its exact duration, then uploaded through the existing /api/upload endpoint with a kind=voice flag and a waveform JSON blob. Storage: the upload handler canonicalizes the sniffed container MIME (Chrome webm / Firefox ogg / Safari mp4) to a stable audio/* type, validates and clamps the waveform, and stores it in a new nullable file_uploads.waveform column (migration 0022) as {"d":duration,"p":[peaks]}. Playback: messages render a canvas waveform player wired by a persistent script in layout.html. Playback uses the Web Audio API (decodeAudioData + AudioBufferSourceNode) rather than an <audio> element, which avoids a start-of-clip decode glitch on MediaRecorder webm/opus; the stored duration drives an accurate progress bar since the container itself carries none. Seeking restarts the source node synchronously. Composer: a voice (or file) attachment alone, with no text, is now a valid send via both the send button and the Enter key. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
feat(messaging): voice messages with record + waveform
Some checks failed
Check / clippy + fmt + tests (pull_request) Failing after 11s
bff87414ee
Adds browser-recorded voice messages that render in the timeline as a playable clip with a waveform.

Recording: a mic button in the composer captures audio via MediaRecorder with the browser's default audio processing; the clip is decoded client-side to compute a normalized waveform and its exact duration, then uploaded through the existing /api/upload endpoint with a kind=voice flag and a waveform JSON blob.

Storage: the upload handler canonicalizes the sniffed container MIME (Chrome webm / Firefox ogg / Safari mp4) to a stable audio/* type, validates and clamps the waveform, and stores it in a new nullable file_uploads.waveform column (migration 0022) as {"d":duration,"p":[peaks]}.

Playback: messages render a canvas waveform player wired by a persistent script in layout.html. Playback uses the Web Audio API (decodeAudioData + AudioBufferSourceNode) rather than an <audio> element, which avoids a start-of-clip decode glitch on MediaRecorder webm/opus; the stored duration drives an accurate progress bar since the container itself carries none. Seeking restarts the source node synchronously.

Composer: a voice (or file) attachment alone, with no text, is now a valid send via both the send button and the Enter key.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
nrupard deleted branch feat/voice-messages 2026-05-14 17:28:04 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!92
No description provided.