feat(messaging): voice messages with record + waveform #92
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/voice-messages"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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>