LimeplayLimeplay

use-media-session

Utility hook for synchronizing browser Media Session metadata, playback state, position, and action handlers.

Installation

npx shadcn add @limeplay/use-media-session

Feature Registration

use-media-session is a utility hook, not a media feature. It does not need to be registered in createMediaKit.

Use it inside a client component that can read your current media state:

components/player/media-session.tsx
"use client"

import * as React from "react"

import { useMediaSession } from "@/hooks/limeplay/use-media-session"

export function MediaSessionController() {
  const mediaSession = useMediaSession()

  React.useEffect(() => {
    mediaSession.setMetadata({
      artist: "Creator",
      artwork: [{ sizes: "512x512", src: "/poster.jpg" }],
      title: "Current asset",
    })

    return () => mediaSession.clearMetadata()
  }, [mediaSession])

  return null
}

Store

useMediaSession does not create a store slice. It wraps navigator.mediaSession and no-ops safely when the browser does not support the API.

State

FieldTypeDescription
supportedbooleanWhether navigator.mediaSession is available.
MetadataBrowserStored on navigator.mediaSession.metadata.
PositionBrowserStored through navigator.mediaSession.setPositionState.

Actions

MethodDescription
setMetadata(metadata)Sets browser media metadata using MediaMetadata.
clearMetadata()Clears browser media metadata.
setPlaybackState(state)Sets browser playback state to none, paused, or playing.
setPositionState(state)Sets duration, playback rate, and position when values are valid.
clearPositionState()Clears browser position state.
setActionHandler(action, handler)Registers a browser media action handler and returns a cleanup.

Sync Hook

Use useMediaSessionSync when a component can derive the current metadata, playback state, position, and handlers from existing player stores. Pass playback status to getMediaSessionPlaybackState so loading and buffering are reported as paused while the current position remains explicitly published. This prevents the platform from falling back to an independently advancing media-element clock. Guard onPlay with canStartMediaSessionPlayback so platform controls can retry loading or buffering media, but cannot start before initialization or from an unrecovered error state.

components/player/media-session.tsx
import {
  canStartMediaSessionPlayback,
  getMediaSessionPlaybackState,
  getMediaSessionPositionState,
  useMediaSessionActionHandlers,
  useMediaSessionSync,
} from "@/hooks/limeplay/use-media-session"

interface Asset {
  creator?: string
  poster?: string
  title?: string
}

interface CustomMediaSessionControllerProps {
  asset: Asset | null
  currentTime: number
  duration: number
  onPause: () => void
  onPlay: () => Promise<void>
  onSeek: (time: number) => void
  playbackRate: number
  status: string
}

function CustomMediaSessionController({
  asset,
  currentTime,
  duration,
  onPause,
  onPlay,
  onSeek,
  playbackRate,
  status,
}: CustomMediaSessionControllerProps) {
  const active = Boolean(asset)
  const actions = useMediaSessionActionHandlers({
    getCurrentTime: () => currentTime,
    onPause,
    onPlay: () => {
      if (!canStartMediaSessionPlayback(status)) return

      return onPlay()
    },
    onSeek,
  })

  useMediaSessionSync({
    actions,
    active,
    claim: status === "playing",
    metadata: asset
      ? {
          artist: asset.creator,
          artwork: asset.poster ? [{ src: asset.poster }] : [],
          title: asset.title,
        }
      : null,
    playbackState: getMediaSessionPlaybackState({
      active,
      status,
    }),
    position: getMediaSessionPositionState({
      active,
      currentTime,
      duration,
      playbackRate,
    }),
  })

  return null
}

Use claim when a player should take ownership of the global navigator.mediaSession. This matters when a page renders multiple players: only the current owner publishes metadata, position state, and action handlers. The default blocks claim ownership while they are playing and release ownership when their active media is cleared or unmounted.

Action Handlers

useMediaSessionActionHandlers builds the common media action map used by the default blocks.

ActionOptionDescription
playonPlayStarts playback.
pauseonPausePauses playback.
seektoonSeekSeeks to the requested absolute media time.
seekbackward / seekforwardgetCurrentTime, onSeekSeeks relative to the current media time.
nexttrackcanGoNext, onNextTrackMoves to the next playlist item when available.
previoustrackcanGoPrevious, onPreviousTrackMoves to the previous playlist item when available.
enterpictureinpicturecanEnterPictureInPicture, onEnterPictureInPictureLets supported browsers request PiP from Media Session.
skipadonSkipAdHandles ad-skip requests when provided.
stoponStopHandles stop requests when provided.

Events

use-media-session does not emit Limeplay media events.

EventPayloadWhen
NoneBrowser Media Session callbacks call the handlers you register.

Browser Behavior

Media Session support varies by browser and action. Unsupported browsers and unsupported actions no-op safely. The enterpictureinpicture action is mainly a browser integration hook for automatic or browser-initiated Picture-in-Picture; it is not guaranteed to appear as a visible operating-system media control.

API Reference

Prop

Type

Prop

Type

Prop

Type

On this page