UNPKG

audio-tracker

Version:

A headless JavaScript library that gives you full control over web audio — playback, tracking, and Media Session integration made simple.

160 lines 5.03 kB
/** * Media Session module for AudioTracker * Integrates with the browser's Media Session API to display playback controls in system UI * @param tracker - AudioTracker instance to attach Media Session functionality * @returns Cleanup function to remove Media Session handlers and metadata * @example * const tracker = new AudioTracker('audio.mp3', { * mediaSession: { * title: 'Song Title', * artist: 'Artist Name', * album: 'Album Name', * artwork: [{ src: 'cover.jpg', sizes: '512x512', type: 'image/jpeg' }] * } * }); * tracker.use(mediaSessionModule); */ export function mediaSessionModule(tracker) { if (!("mediaSession" in navigator)) { console.warn("MediaSessionModule: Media Session API not supported"); return () => { }; } if (tracker.options.mediaSession) { navigator.mediaSession.metadata = new MediaMetadata(tracker.options.mediaSession); } /** * Update Media Session metadata dynamically * @param metadata - New metadata to display in system UI * @example * tracker.updateMediaSessionMetadata({ * title: 'New Song', * artist: 'New Artist', * artwork: [{ src: 'new-cover.jpg' }] * }); */ tracker.updateMediaSessionMetadata = (metadata) => { try { navigator.mediaSession.metadata = new MediaMetadata(metadata); } catch (error) { console.warn("Failed to update MediaSession metadata:", error); } }; function updatePlaybackState(state) { try { navigator.mediaSession.playbackState = state; } catch (error) { console.warn("Failed to update Media Session playback state:", error); } } function updatePositionState() { const { duration, playbackRate, currentTime } = tracker.audio; if (duration && !isNaN(duration)) { try { navigator.mediaSession.setPositionState({ duration, playbackRate, position: currentTime, }); } catch (error) { console.warn("Failed to update Media Session position:", error); } } } const actions = [ [ "play", async () => { await tracker.play(); updatePlaybackState("playing"); }, ], [ "pause", () => { tracker.pause(); updatePlaybackState("paused"); }, ], [ "seekbackward", (details) => { tracker.backward(details.seekOffset || 10); }, ], [ "seekforward", (details) => { tracker.forward(details.seekOffset || 10); }, ], [ "seekto", (details) => { if (details.fastSeek && "fastSeek" in tracker.audio) { tracker.audio.fastSeek(details.seekTime); } else { tracker.audio.currentTime = details.seekTime ?? 0; } updatePositionState(); }, ], [ "stop", () => { tracker.pause(); tracker.audio.currentTime = 0; updatePlaybackState("paused"); }, ], ]; // Register handlers for (const [action, handler] of actions) { try { navigator.mediaSession.setActionHandler(action, handler); } catch { console.warn(`Media Session action "${action}" not supported`); } } // Playback event handlers const handleEnded = () => { updatePositionState(); updatePlaybackState("paused"); }; const handlePlay = () => { updatePositionState(); updatePlaybackState("playing"); }; const handlePause = () => { updatePositionState(); updatePlaybackState("paused"); }; const subscriptions = [ ["loadedmetadata", updatePositionState], ["seeked", updatePositionState], ["ratechange", updatePositionState], ["timeupdate", updatePositionState], ["ended", handleEnded], ["play", handlePlay], ["pause", handlePause], ]; subscriptions.forEach(([event, handler]) => tracker.subscribe(event, handler)); return () => { actions.forEach(([action]) => { try { navigator.mediaSession.setActionHandler(action, null); } catch { // optionally log or ignore } }); subscriptions.forEach(([event, handler]) => tracker.unsubscribe(event, handler)); navigator.mediaSession.metadata = null; navigator.mediaSession.playbackState = "none"; }; } //# sourceMappingURL=mediaSessionModule.js.map