Audio Player & Media Session
Relevant source files
The following files were used as context for generating this wiki page:
- apps/web/src/features/audio/components/AudioPlayerBar.tsx
- apps/web/src/features/audio/hooks/useMediaSession.ts
- apps/web/src/features/audio/components/PublicNarrationPlayer.tsx
- apps/web/src/features/audio/hooks/useAudioPlayerController.ts
- apps/api/src/test/kotlin/com/briefy/api/api/SourceNarrationControllerTest.kt
- apps/web/src/lib/api/sources.ts
- apps/web/src/lib/api/types.ts
The Audio Player & Media Session system provides the infrastructure for users to listen to AI-generated narrations of sources. It encompasses frontend UI components for playback control, custom React hooks for state management and OS-level media integration, and backend API support for managing narration states and audio delivery.
The system is designed to handle both authenticated users through the main application and anonymous users via public share links. It ensures a seamless listening experience by synchronizing the browser's playback state with the operating system's media controls using the Media Session API.
Sources: apps/web/src/features/audio/components/AudioPlayerBar.tsx, apps/web/src/features/audio/components/PublicNarrationPlayer.tsx, apps/web/src/lib/api/types.ts
System Architecture
The audio system is divided into a centralized state controller for the authenticated application and an isolated player for public content. Both implementations share logic for handling HTML5 Audio elements and browser events.
Audio Playback Flow
The following diagram illustrates the lifecycle of an audio playback session, from initiation to termination.
Core Components
Audio Player Bar
The AudioPlayerBar is a persistent UI component docked at the bottom of the web application. It consumes the useAudioPlayer context to provide global controls, including play/pause, seeking, skipping (15s back, 30s forward), and a progress visualization.
- Cover Art: Displays a default or source-specific artwork image.
- Progress Slider: An invisible range input overlaid on a visual progress bar for precise seeking.
- Safe Area Handling: Uses
env(safe-area-inset-bottom)for mobile compatibility.
Sources: apps/web/src/features/audio/components/AudioPlayerBar.tsx:28-118
Public Narration Player
An isolated player designed for shareable links where the standard application context is unavailable. It manages its own HTMLAudioElement instance and includes internal logic to handle expiring presigned URLs by attempting a single refresh upon encountering a media error.
Sources: apps/web/src/features/audio/components/PublicNarrationPlayer.tsx:32-60
Media Session Integration
The useMediaSession hook synchronizes the web player with the browser/OS media controller (e.g., lock screen controls, hardware media keys).
Media Session Metadata & Actions
| Feature | Implementation | Source |
|---|---|---|
| Metadata | Updates navigator.mediaSession.metadata with title and artwork. | useMediaSession.ts:18-25 |
| Playback State | Syncs navigator.mediaSession.playbackState to 'playing' or 'paused'. | useMediaSession.ts:27-29 |
| Action Handlers | Maps 'play', 'pause', 'seekbackward', 'seekforward', and 'stop'. | useMediaSession.ts:31-40 |
Sequence: OS Media Interaction
API and Data Models
The system relies on specific backend endpoints to manage the narration lifecycle and provide secure access to audio files.
Narration States
Narration status is tracked via the narrationState field in the Source object:
not_generated: Default state.pending: AI generation is currently in progress.succeeded: Audio is ready for playback.failed: An error occurred during generation.
Sources: apps/web/src/lib/api/types.ts:41-55
Audio Delivery API
| Endpoint | Method | Description |
|---|---|---|
/api/sources/{id}/narrate | POST | Triggers the narration generation process. |
/api/sources/{id}/audio | GET | Returns a presigned URL (audioUrl) for secure streaming. |
/api/sources/{id}/narrate/estimate | GET | Provides character count and model info for cost estimation. |
Sources: apps/web/src/lib/api/sources.ts:121-149, apps/api/src/test/kotlin/com/briefy/api/api/SourceNarrationControllerTest.kt:60-120
Error Handling and Resilience
The system implements a retry mechanism to handle expiring presigned URLs. Both the global controller and the public player track refreshAttemptsRef. If an error event is fired by the HTMLAudioElement, the player attempts to fetch a fresh URL from the API and resume playback at the same currentTime.
Conclusion
The Audio Player & Media Session module provides a robust, resilient interface for consuming source narrations. By leveraging browser-native APIs like the Media Session and implementing proactive URL refreshing, the system maintains high availability and a native-feeling experience across different platforms and user authentication states.