Mohammad Reza Mrg
Mohammad Reza Mrg

Reputation: 2043

MediaSession.setPositionState() and seekto not working

MediaSession.setPositionState() not showing the audio time, also seekbar not showing as expected.

const audio= document.querySelector('audio');

function updatePositionState() {
  if ('setPositionState' in navigator.mediaSession) {
    navigator.mediaSession.setPositionState({
      duration: audio.duration,
      playbackRate: audio.playbackRate,
      position: audio.currentTime,
    });
  }
}

await audio.play();
updatePositionState();

navigator.mediaSession.setActionHandler('seekto', (details) => {
  updatePositionState();
});

enter image description here

Upvotes: 0

Views: 1054

Answers (3)

user3116272
user3116272

Reputation: 21

function setup_media_session_action_handlers() {
    if (!("mediaSession" in navigator)) {
        write2log(`No mediaSession in navigator.`,2);
    }
    const audio_element = document.querySelector('audio');
    const default_skip_time = 60; /* Time to skip in seconds by default */

    const action_handlers = [
        ['play',            () => { audio_element.play(); }],
        ['pause',           () => { audio_element.pause(); }],
        ['previoustrack',   () => { audio_element.currentTime = 0; }],
        ['nexttrack',       () => { load_song_from_index(); }],
        ['stop',            () => {audio_element.pause(); }],
        ['seekbackward',    (details) => {  const skip_time = details.seekOffset || default_skip_time; audio_element.currentTime = Math.max(audio_element.currentTime - skip_time, 0); navigator.mediaSession.setPositionState({duration: audio_element.duration, playbackRate: audio_element.playbackRate, position: audio_element.currentTime});}],
        ['seekforward',     (details) => {  const skip_time = details.seekOffset || default_skip_time; audio_element.currentTime = Math.min(audio_element.currentTime + skip_time, 0); navigator.mediaSession.setPositionState({duration: audio_element.duration, playbackRate: audio_element.playbackRate, position: audio_element.currentTime});}],
        ['seekto',      (details) => {  if (details.fastSeek && 'fastSeek' in audio_element) { audio_element.fastSeek(details.seekTime); } else { audio_element.currentTime = details.seekTime; } navigator.mediaSession.setPositionState({duration: audio_element.duration, playbackRate: audio_element.playbackRate, position: audio_element.currentTime});}],

        // Not implemented: ['togglemicrophone', 'togglecamera', 'hangup', 'previousslide', and 'nextslide'];
        /* Video conferencing actions */
        //['togglemicrophone',  () => { await audio_element.pause(); /* On any microphone usage (on or off), just set the audio to pause. */ }],
        //['togglecamera',  () => { await audio_element.pause(); /* On any camera usage (on or off), just set the audio to pause. */ }],
        //['hangup',        () => { if (audio_element.currentTime > 0) { await audio_element.play(); } /* On hangup, simplified (not bulletproof) version of unmute if we were playing music before */}],
        /* Presenting slides actions */ // Not implemented at this time, placeholder for future? idk.
        //['previousslide', () => { /* ... */ }],
        //['nextslide',     () => { /* ... */ }],
    ];
    for (const [action, handler] of action_handlers) {
        try {
            navigator.mediaSession.setActionHandler(action, handler);
        } catch (error) {
            write2log(`The media session action "${action}" is not supported yet.`,2);
        }
    }
    try {
        // Set playback event listeners
        audio_element.addEventListener('play', () => { navigator.mediaSession.playbackState = 'playing'; });
        audio_element.addEventListener('pause', () => { navigator.mediaSession.playbackState = 'paused'; });
    }
    catch (err) {
        write2log(`Failed to set navigator.mediaSession.playbackState play/pause handlers`,2);
    }
}

See https://github.com/Noah-Jaffe/Mixcloud_player/blob/main/MUSICPLAYER.html for a use case of this exact function, all of the audio media controls are implemented inside the setup_media_session_action_handlers() function.

in action on android device viewing html page with Android Chrome it looks like the following in action on android device viewing html page with Android Chrome

Upvotes: 1

Marcus Wright
Marcus Wright

Reputation: 11

This is what worked for me:

audio = document.querySelector("audio");
navigator.mediaSession.setActionHandler('seekto', (details) => {
        audio.currentTime = details.seekTime;
    });

Upvotes: 1

fromage9747
fromage9747

Reputation: 344

I encountered the same thing.

Then I was doing some cleaning up and decided that the below was not required for now:

navigator.mediaSession.setActionHandler("seekbackward", (data) => {
        console.log('seekBackward: data: ', data);
        // seekBackward: data: { action: 'seekbackward' }
      });
      navigator.mediaSession.setActionHandler("seekforward", (data) => {
        console.log('seekForward: data: ', data);
        // seekForward: data:  {action: 'seekforward'}
      });

Once I had commented this out, the seek bar was now visible on my Mobile Device. On the desktop it was still not visible. I suspect that maybe the way the MediaSession API works is if you have the skip forward and backward buttons, then the seekTo is disabled.

Now, the seekTo bar is visible and can be triggered but it is incorrect. When a track starts, it's already a quarter of the way through.

I can't seem to find a way to set the runtime of the track in the MedaSession API on a stream.

I had read somewhere that it was not possible to even have a seek bar on a stream. 🤷‍♀️

Upvotes: 0

Related Questions