Core — Audio URL
GET /meetings/:id/audio-url returning a time-limited signed URL, with mime_type and duration_ms in the response, and the recoverable-error contract for expired or forged links.
Core — Audio URL
Owner: Core Engineer Domain: core Complexity: S Prerequisite: Milestone 05 merged (composed
audio.webmexists)
When this slice is complete, GET /meetings/{id}/audio-url returns a time-limited playback link — never a raw storage path — with {url, mime_type, duration_ms, expires_at}, bounded by RECORDING_AUDIO_URL_TTL_SECONDS (900s default). The link serves the composed audio without a bearer token. A forged, tampered, replayed, or otherwise-scoped signature is refused 403; an expired link answers 410 with problem type audio_url_expired; a meeting with no recorded audio answers 404; and requesting a fresh link at any later time recovers playback.
Required Capabilities
-
GET /meetings/{id}/audio-urlreturns{url, mime_type, duration_ms, expires_at}. -
urlis never a raw storage object path (no bucket-relative path, no bare.webm/.wavsuffix exposed). -
expires_atis no further out thanRECORDING_AUDIO_URL_TTL_SECONDS(900s) from issuance. - The link serves the composed audio bytes with the declared
mime_type, without requiring a bearer token — a media element can consume it directly. - A missing, tampered, or forged signature on the link is refused
403. - A signature replayed with a different expiry, or under a different user id, is refused
403— the link is scoped to its exact signed parameters and to the issuing user. - Once past
expires_at, the link answers410with problem typeaudio_url_expired. -
GET /meetings/{id}/audio-urlfor a meeting with no recorded audio answers404. - Requesting a fresh link (
GET /audio-urlagain) always recovers playback, regardless of any earlier link's state.
Dependencies
- Milestone 05 (
live-audio-durability-recovery) must be merged — the composedaudio.webmobject this endpoint links to.
Test Cases
Test cases map to tests/bets/meeting-recording/test_milestone_10_audio_playback_and_review.py. Run via ./dev test bet meeting-recording.
| Test | Location | Assertion |
|---|---|---|
test_finalized_meeting_review_shows_expected_tabs | test_milestone_10 | A finalized meeting exposes every surface the review tabs read: completed transcription, non-empty synthesis, a tasks list, and GET /audio-url returning 200. |
test_audio_playback_uses_signed_url | test_milestone_10 | GET /audio-url returns all four required fields; the URL is never a raw storage path; it carries a valid signature (or is an HTTPS GCS-signed URL); mime_type starts with audio/; duration_ms > 0; expires_at is in the future and bounded by 900s; fetching the URL with no bearer token returns the audio bytes with matching Content-Type. |
test_user_can_play_pause_and_seek_audio | test_milestone_10 | The composed audio object is fully fetchable (Content-Length matches the byte count), non-empty, and duration_ms is consistent with the captured audio — sufficient for player seek support. |
test_expired_signed_url_has_recoverable_error | test_milestone_10 | A missing signature, a tampered signature, a signature replayed with a different exp, and a signature reused under a different uid are all refused 403; a genuinely expired link answers 410 with type: "audio_url_expired"; a meeting with no recorded audio answers 404; a freshly requested link plays again. |
Completion Checklist
- Code merged and deployed
- Bet progress tests pass (
./dev test bet meeting-recording) - Permanent service tests implemented per testing strategy
- Code review completed
- API review completed (
GET /meetings/{id}/audio-urlsigned-link contract) - Testing review completed
- System documentation updated (as applicable)
App — Audio Playback UI
Audio player component wired to the signed URL, active segment highlight synced to currentTime, click-to-seek on transcript rows, and recoverable error UI for expired links.
ML — Timestamped Transcript
start_ms / end_ms timestamps on every final transcript segment from batch AssemblyAI output, ordered and seekable within the audio duration.