# Media Session Standard

## Editor’s Draft, 1 January 1970

This version:
  https://w3c.github.io/mediasession
Editors:
  Mounir Lamouri (Google Inc.)
  Becca Hughes (Google Inc.)
Former Editors:
  Zhiqiang Zhang (Google Inc.)
  Rich Tibbett (Opera)
Participate:
  We are on GitHub
  File an issue
  Open issues
Version History:
  https://github.com/w3c/mediasession/commits

Copyright © 1970 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and permissive document license rules apply.

## Abstract

This specification enables web developers to show customized media metadata on platform UI, customize available platform media controls, and access platform media keys such as hardware keys found on keyboards, headsets, remote controls, and software keys found in notification areas and on lock screens of mobile devices.

## Status of this document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

This document was published by the Media Working Group as an Editors' Draft. This document is intended to become a W3C Recommendation. Feedback and comments on this specification are welcome. Please use Github issues. Discussions may also be found in the public-media-wg@w3.org archives.

Publication as an Editors' Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 1 March 2019 W3C Process Document.

## 1. Introduction

This section is non-normative.

Media is used extensively today, and the Web is one of the primary means of consuming media content. Many platforms can display media metadata, such as title, artist, album and album art on various UI elements such as notification, media control center, device lockscreen and wearable devices. This specification aims to enable web pages to specify the media metadata to be displayed in platform UI, and respond to media controls which may come from platform UI or media keys, thereby improving the user experience.

## 2. Conformance

All diagrams, examples, and notes in this specification are non-normative, as are all sections explicitly marked non-normative. Everything else in this specification is normative.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. For readability, these words do not appear in all uppercase letters in this specification. [RFC2119]

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and terminate these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps may be implemented in any manner, so long as the end result is equivalent. (In particular, the algorithms defined in this specification are intended to be easy to follow, and not intended to be performant.)

User agents may impose implementation-specific limits on otherwise unconstrained inputs, e.g. to prevent denial of service attacks, to guard against running out of memory, or to work around platform-specific limitations.

When a method or an attribute is said to call another method or attribute, the user agent must invoke its internal API for that attribute or method so that e.g. the author can’t change the behavior by overriding attributes or methods with custom properties or functions in JavaScript.

Unless otherwise stated, string comparisons are done in a case-sensitive manner.

## 3. Dependencies

The IDL fragments in this specification must be interpreted as required for conforming IDL fragments, as described in the Web IDL specification. [WEBIDL]

## 4. Security and Privacy Considerations

This section is non-normative.

The API introduced in this specification has very low impact with regards to security and privacy. Part of the API allows a website to expose metadata that can be used by the user agent. The user agent obviously needs to use this data with care. Another part of the API allows a website to receive commands from the user via buttons or other form of controls which might sometimes introduce a new input layer between the user and the website.

### 4.1. User interface guidelines

The `MediaMetadata` introduced in this specification allows a website to offer more information with regards to what is being played. The user agent is meant to use this information in any UI related to media playback, either internal to the user agent or within the platform.

The `MediaMetadata` are expected to be used in the context of media playback, making spoofing harder but because the `MediaMetadata` has text fields and image fields, a malicious website could try to spoof another website’s identity. It is recommended that the user agent offers a way to find the origin or clearly expose the origin of the website which the metadata are coming from.

If a user agent offers a mechanism to go back to a website from a UI element created based on the `MediaMetadata`, it is recommended that the action should not be noticeable by the website, thus reducing the chances of spoofing.

In general, all security and privacy considerations related to the display of notifications from a website should apply here. It is worth noting that the `MediaMetadata` offer less customization than regular web notifications, thus would be harder to spoof.

### 4.2. Incognito mode

For privacy purposes, when in incognito mode, the user agent should be careful when sharing the information from `MediaMetadata` with the system and make sure they will not be used in a way that would harm the user. Displaying this information in a way that is very visible would be against the user’s intent of browsing in incognito mode. When available, the UI elements should be advertized as private to the platform.

### 4.3. Media Session Actions

Media session actions expose a new input layer to the web platform. User agents should make sure users are aware that their actions might be routed to the website with the active media session. Especially, when the actions are coming from remote devices such as a headset or other remote device. It is recommended for the user agent to follow the platform conventions when listening to these inputs in order to facilitate the user understanding.

## 5. Model

### 5.1. Playback State

In order to make play and pause actions work properly, the user agent SHOULD be able to determine if a browsing context of the active media session is playing media or not, which is called the guessed playback state. The RECOMMENDED way for determining the guessed playback state is to monitor the media elements whose node document’s browsing context is the browsing context. The browsing context’s guessed playback state is playing if any of them is potentially playing and not muted, and is paused otherwise. Other information SHOULD also be considered, such as WebAudio and plugins.

The playbackState attribute specifies the declared playback state from the browsing context. The state is combined with the guessed playback state to compute the actual playback state, which is a finalized state and will be used for play and pause actions.

The actual playback state is computed in the following way:

- If the declared playback state is playing, return playing.
- Otherwise, return the guessed playback state.

The `playbackState` attribute could be useful when the page wants to do some preparation steps when the media is paused but it allows the preparation steps to be interrupted by pause action. See Setting playbackState for example.

When the actual playback state of the active media session changes, the user agent MUST run the media session actions update algorithm.

### 5.2. Routing

There could be multiple `MediaSession` objects existing at the same time since the user agent could have multiple tabs, each tab could contain a top-level browsing context and multiple nested browsing contexts, and each browsing context could have a `MediaSession` object.

The user agent MUST select at most one of the `MediaSession` objects to present to the user, which is called the active media session. The active media session may be null. The selection is up to the user agent and SHOULD be based on preferred user experience. Note that the `playbackState` attribute MUST not affect media session routing. It only takes effect for the active media session.

It is RECOMMENDED that the user agent selects the active media session by managing audio focus. A tab or browsing context is said to have audio focus if it is currently playing audio or the user expects to control the media in it. The AudioFocus API targets this area and could be used once it’s finished.

Whenever the active media session is changed, the user agent MUST run the media session actions update algorithm and the update metadata algorithm.

### 5.3. Metadata

The media metadata for the active media session MAY be displayed in the platform UI depending on platform conventions. Whenever the active media session changes or setting `metadata` of the active media session, the user agent MUST run the update metadata algorithm. The steps are as follows:

1. If the active media session is null, unset the media metadata presented to the platform, and terminate these steps.
2. If the `metadata` of the active media session is an empty metadata, unset the media metadata presented to the platform, and terminate these steps.
3. Update the media metadata presented to the platform to match the `metadata` for the active media session.
4. If the user agent wants to display an artwork image, it is RECOMMENDED to run the fetch image algorithm.

The RECOMMENDED fetch image algorithm is as follows:

1. If there are other fetch image algorithms running, cancel existing algorithm execution instances.
2. If metadata’s `artwork` of the active media session is empty, then terminate these steps.
3. If the platform supports displaying media artwork, select a preferred artwork image from metadata’s `artwork` of the active media session.
4. Fetch the preferred artwork image’s `src`.

   Then, in parallel:

   1. Wait for the response.
   2. If the response’s internal response’s type is default, attempt to decode the resource as an image.
   3. If the image format is supported, use the image as the artwork for display in platform UI. Otherwise the fetch image algorithm fails and terminates.

If no images are fetched in the fetch image algorithm, the user agent MAY have fallback behavior such as displaying a default image as artwork.

### 5.4. Actions

A media session action is an action that the page can handle in order for the user to interact with the `MediaSession`. For example, a page can handle some actions that will then be triggered when the user presses buttons from a headset or other remote device.

A media session action source is a source that might produce a media session action. Such a source can be the platform or the UI surfaces created by the user agent.

A media session action is represented by a `MediaSessionAction` which can have one of the following value:

- `play`: the action intent is to resume the playback.
- `pause`: the action intent is to pause the currently active playback.
- `seekbackward`: the action intent is to move the playback time backward by a short period (eg. a few seconds).
- `seekforward`: the action intent is to move the playback time forward by a short period (eg. a few seconds).
- `previoustrack`: the action intent is to either start the current playback from the beginning if the playback has a notion of beginning, or move to the previous item in the playlist if the playback has a notion of playlist.
- `nexttrack`: the action is to move to the playback to the next item in the playlist if the playback has a notion of playlist.
- `skipad`: the action intent is to skip the advertisement that is currently playing.
- `stop`: the action intent is to stop the playback and clear the state if appropriate.
- `seekto`: the action intent is to move the playback time to a specific time.

All `MediaSession`s have a map of supported media session actions with, as a key, a media session action and as a value a `MediaSessionActionHandler`.

When the update action handler algorithm on a given `MediaSession` with action and handler parameters is invoked, the user agent MUST run the following steps:

1. If handler is `null`, remove action from the supported media session actions for `MediaSession` and abort these steps.
2. Add action to the supported media session actions for `MediaSession` and associate to it the handler.

When the supported media session actions are changed, the user agent SHOULD run the media session actions update algorithm. The user agent MAY queue a task in order to run the media session actions update algorithm in order to avoid UI flickering when multiple actions are modified in the same event loop.

When the user agent is notified by a media session action source that a media session action named action has been triggered, the user agent MUST run the handle media session action steps as follows and consider it triggered by user activation:

1. If the active media session is `null`, abort these steps.
2. Let actions be the active media session’s supported media session actions.
3. If actions does not contain the key action, abort these steps.
4. Let handler be the `MediaSessionActionHandler` associated with the key action in actions.
5. Run handler with the details parameter set to:
   - `MediaSessionSeekActionDetails` if action is seekbackward or seekforward.
   - `MediaSessionSeekToActionDetails` if action is seekto.
   - Otherwise, with `MediaSessionActionDetails`.

When the user agent receives a joint command for play and pause, such as a headset button click, it MUST run the following steps:

1. If the active media session is `null`, abort these steps.
2. Let action be a media session action.
3. If the actual playback state of the active media session is playing, set action to pause.
4. Otherwise, set action to play.
5. Run the handle media session action steps with action.

It is RECOMMENDED for user agents to implement a default handler for the play and pause media session actions if none was provided for the active media session.

A page should only register a `MediaSessionActionHandler` for a media session action when it can handle the action given that the user agent will list this as a supported media session action and update the media session action sources.

When the media session actions update algorithm is invoked, the user agent MUST run the following steps:

1. Let available actions be an array of media session actions.
2. If the active media session is null, set available actions to the empty array.
3. Otherwise, set the available actions to the list of keys available in the active media session’s supported media session actions.
4. For each media session action source source, run the following substeps:
   1. Optionally, if the active media session is not null:
      1. If the active media session’s actual playback state is playing, remove play from available actions.
      2. Otherwise, remove pause from available actions.
   2. If the source is a UI element created by the user agent, it MAY remove some elements from available actions if there are too many of them compared to the available space.
   3. Notify the source with the updated list of available actions.

### 5.5. Position State

A user agent MAY display the current playback position and duration of a media session in the platform UI depending on platform conventions. The position state is the combination of the following:

- The duration of the media in seconds.
- The playback rate of the media. It is a coefficient.
- The last reported playback position of the media. This is the playback position of the media in seconds when the position state was created.

The position state is represented by a `MediaPositionState` which MUST always be stored with the last position updated time. This is the time the position state was last updated in seconds.

The RECOMMENDED way to determine the position state is to monitor the media elements whose node document’s browsing context is the browsing context.

The actual playback rate is a coefficient computed in the following way:

- If the actual playback state is paused, then return zero.
- Return playback rate.

The current playback position in seconds is computed in the following way:

- Set time elapsed to the system time in seconds minus the last position updated time.
- Mutliply time elapsed with actual playback rate.
- Set position to time elapsed added to last reported playback position.
- If position is less than zero, return zero.
- If position is greater than duration, return duration.
- Return position.

## 6. The `MediaSession` interface

    [Exposed=Window]
    partial interface Navigator {
      [SameObject] readonly attribute MediaSession mediaSession;
    };

    enum MediaSessionPlaybackState {
      "none",
      "paused",
      "playing"
    };

    enum MediaSessionAction {
      "play",
      "pause",
      "seekbackward",
      "seekforward",
      "previoustrack",
      "nexttrack",
      "skipad",
      "stop",
      "seekto"
    };

    callback MediaSessionActionHandler = void(MediaSessionActionDetails details);

    [Exposed=Window]
    interface MediaSession {
      attribute MediaMetadata? metadata;

      attribute MediaSessionPlaybackState playbackState;

      void setActionHandler(MediaSessionAction action, MediaSessionActionHandler? handler);

      void setPositionState(optional MediaPositionState state = {});
    };

A `MediaSession` object represents a media session for a given document and allows a document to communicate to the user agent some information about the playback and how to handle it.

A `MediaSession` has an associated metadata object represented by a `MediaMetadata`. It is initially `null`.

The `mediaSession` attribute MUST return the `MediaSession` instance associated with the `Navigator` object.

The `metadata` attribute reflects the `MediaSession`'s metadata. On getting, it MUST return the `MediaSession`'s metadata. On setting, it MUST run the following steps with value being the new value being set:

1. If the `MediaSession`'s metadata is not `null`, set its media session to `null`.
2. Set the `MediaSession`'s metadata to value.
3. If the `MediaSession`'s metadata is not `null`, set its media session to the current `MediaSession`.
4. In parallel, run the update metadata algorithm.

The `playbackState` attribute represents the declared playback state of the media session, by which the session declares whether its browsing context is playing media or not. The initial value is none. On setting, the user agent MUST set the IDL attribute to the new value if it is a valid `MediaSessionPlaybackState` value. On getting, the user agent MUST return the last valid value that was set. The `playbackState` attribute is a hint for the user agent to determine whether the browsing context is playing or paused.

Setting `playbackState` may cause the actual playback state to change and run the media session actions update algorithm.

The `MediaSessionPlaybackState` enum is used to indicate whether a browsing context is playing media or not, the values are described as follows:

- `none` means the browsing context does not specify whether it’s playing or paused, it can only be used in the `playbackState` attribute.
- `playing` means the browsing context is currently playing media and it can be paused.
- `paused` means the browsing context has paused media and it can be resumed.

The `setActionHandler()` method, when invoked, MUST run the update action handler algorithm with action and handler on the `MediaSession`.

The `setPositionState()` method, when invoked MUST perform the following steps:

- If the state is an empty dictionary then clear the position state.
- If the duration is not present or its value is null, throw a TypeError.
- If the duration is negative, throw a TypeError.
- If the position is not present or its value is null, set it to zero.
- If the position is negative or greater than duration, throw a TypeError.
- If the playbackRate is not present or its value is null, set it to 1.0.
- If the playbackRate is zero throw a TypeError.
- Update the position state and last position updated time.

## 7. The `MediaMetadata` interface

    [Exposed=Window]
    interface MediaMetadata {
      constructor(optional MediaMetadataInit init = {});
      attribute DOMString title;
      attribute DOMString artist;
      attribute DOMString album;
      attribute FrozenArray<MediaImage> artwork;
    };

    dictionary MediaMetadataInit {
      DOMString title = "";
      DOMString artist = "";
      DOMString album = "";
      sequence<MediaImage> artwork = [];
    };

A `MediaMetadata` object is a representation of the metadata associated with a `MediaSession` that can be used by user agents to provide customized user interface.

A `MediaMetadata` can have an associated media session.

A `MediaMetadata` has an associated title, artist and album which are DOMString.

A `MediaMetadata` has an associated list of artwork images.

A `MediaMetadata` is said to be an empty metadata if it is equal to `null` or all the following conditions are true:

- Its title is the empty string.
- Its artist is the empty string.
- Its album is the empty string.
- Its artwork images length is `0`.

The `MediaMetadata(init)` constructor, when invoked, MUST run the following steps:

1. Let metadata be a new `MediaMetadata` object.
2. Set metadata’s `title` to init’s `title`.
3. Set metadata’s `artist` to init’s `artist`.
4. Set metadata’s `album` to init’s `album`.
5. Run the convert artwork algorithm with init’s `artwork` as input and set metadata’s artwork images as the result if it succeeded.
6. Return metadata.

When the convert artwork algorithm with input parameter is invoked, the user agent MUST run the following steps:

1. Let output be an empty list of type `MediaImage`.
2. For each entry in input’s `artwork`, perform the following steps:
   1. Let image be a new `MediaImage`.
   2. Let baseURL be the API base URL specified by the entry settings object.
   3. Parse entry’s `src` using baseURL. If it does not return failure, set image’s `src` to the return value. Otherwise, throw a TypeError and abort these steps.
   4. Set image’s `sizes` to entry’s `sizes`.
   5. Set image’s `type` to entry’s `type`.
   6. Append image to the output.
3. Return output as result.

The `title` attribute reflects the `MediaMetadata`'s title. On getting, it MUST return the `MediaMetadata`'s title. On setting, it MUST set the `MediaMetadata`'s title to the given value.

The `artist` attribute reflects the `MediaMetadata`'s artist. On getting, it MUST return the `MediaMetadata`'s artist. On setting, it MUST set the `MediaMetadata`'s artist to the given value.

The `album` attribute reflects the `MediaMetadata`'s album. On getting, it MUST return the `MediaMetadata`'s album. On setting, it MUST set the `MediaMetadata`'s album to the given value.

The `artwork` attribute reflects the `MediaMetadata`'s artwork images. On getting, it MUST return the result of the following steps:

1. Let frozenArtwork be an empty list of type `MediaImage`.
2. For each entry in the `MediaMetadata`'s artwork images, perform the following steps:
   1. Let image be a new `MediaImage`.
   2. Set image’s `src` to entry’s `src`.
   3. Set image’s `sizes` to entry’s `sizes`.
   4. Set image’s `type` to entry’s `type`.
   5. Call Object.freeze on image, to prevent accidental mutation by scripts.
   6. Append image to frozenArtwork.
3. Create a frozen array from frozenArtwork.

On setting, it MUST run the convert artwork algorithm with the new value as input, and set the `MediaMetadata`'s artwork images as the result if it succeeded.

When `MediaMetadata`'s title, artist, album or artwork images are modified, the user agent MUST run the following steps:

1. If the instance has no associated media session, abort these steps.
2. Otherwise, queue a task to run the following substeps:
   1. If the instance no longer has an associated media session, abort these steps.
   2. Otherwise, in parallel, run the update metadata algorithm.

## 8. The `MediaImage` dictionary

    dictionary MediaImage {
      required USVString src;
      DOMString sizes = "";
      DOMString type = "";
    };

The `MediaImage` dictionary members are inspired by the image objects in Web App Manifest.

The `src` dictionary member is used to specify the `MediaImage` object’s source. It is a URL from which the user agent can fetch the image’s data.

The `sizes` dictionary member is used to specify the `MediaImage` object’s `sizes`. It follows the spec of `sizes` attribute in the HTML `link` element, which is a string consisting of an unordered set of unique space-separated tokens which are ASCII case-insensitive that represents the dimensions of an image. Each keyword is either an ASCII case-insensitive match for the string "any", or a value that consists of two valid non-negative integers that do not have a leading U+0030 DIGIT ZERO (0) character and that are separated by a single U+0078 LATIN SMALL LETTER X or U+0058 LATIN CAPITAL LETTER X character. The keywords represent icon sizes in raw pixels (as opposed to CSS pixels). When multiple image objects are available, a user agent MAY use the value to decide which icon is most suitable for a display context (and ignore any that are inappropriate). The parsing steps for the `sizes` attribute MUST follow the parsing steps for HTML `link` element `sizes` attribute.

The `type` dictionary member is used to specify the `MediaImage` object’s MIME type. It is a hint as to the media type of the image. The purpose of this attribute is to allow a user agent to ignore images of media types it does not support.

## 9. The `MediaPositionState` dictionary

    dictionary MediaPositionState {
      double duration;
      double playbackRate;
      double position;
    };

The `MediaPositionState` dictionary is a representation of the current playback position associated with a `MediaSession` that can be used by user agents to provide a user interface that displays the current playback position and duration.

The `duration` dictionary member is used to specify the duration in seconds. It should always be positive and positive infinity can be used to indicate media without a defined end such as live playback.

The `playbackRate` dictionary member is used to specify the playback rate. It can be positive to represent forward playback or negative to represent backwards playback. It should not be zero.

The `position` dictionary member is used to specify the last reported playback position in seconds. It should always be positive.

## 10. The `MediaSessionActionDetails` dictionary

    dictionary MediaSessionActionDetails {
      required MediaSessionAction action;
    };

    dictionary MediaSessionSeekActionDetails : MediaSessionActionDetails {
      double? seekOffset;
    };

    dictionary MediaSessionSeekToActionDetails : MediaSessionActionDetails {
      required double seekTime;
      boolean? fastSeek;
    };

The `MediaSessionActionHandler` MUST be run with the details parameter which is represented by a dictionary inherited from `MediaSessionActionDetails`.

The `action` dictionary member is used to specify the action that the `MediaSessionActionHandler` is associated with.

The `seekOffset` dictionary member MAY be provided and is the time in seconds to move the playback time by. If it is not provided then the site should choose a sensible time (e.g. a few seconds).

The `seekTime` dictionary member MUST be provided and is the time in seconds to move the playback time to.

The `fastSeek` dictionary member MAY be provided and will be true if the seekto action is being called multiple times as part of a sequence and this is not the last call in that sequence.

## 11. Examples

This section is non-normative.

Setting metadata:

    navigator.mediaSession.metadata = new MediaMetadata({
      title: "Episode Title",
      artist: "Podcast Host",
      album: "Podcast Title",
      artwork: [{src: "podcast.jpg"}]
    });

Alternatively, providing multiple artwork images in the metadata can let the user agent be able to select different artwork images for different display purposes and better fit for different screens:

    navigator.mediaSession.metadata = new MediaMetadata({
      title: "Episode Title",
      artist: "Podcast Host",
      album: "Podcast Title",
      artwork: [
        {src: "podcast.jpg", sizes: "128x128", type: "image/jpeg"},
        {src: "podcast_hd.jpg", sizes: "256x256"},
        {src: "podcast_xhd.jpg", sizes: "1024x1024", type: "image/jpeg"},
        {src: "podcast.png", sizes: "128x128", type: "image/png"},
        {src: "podcast_hd.png", sizes: "256x256", type: "image/png"},
        {src: "podcast.ico", sizes: "128x128 256x256", type: "image/x-icon"}
      ]
    });

For example, if the user agent wants to use an image as icon, it may choose `"podcast.jpg"` or `"podcast.png"` for a low-pixel-density screen, and `"podcast_hd.jpg"` or `"podcast_hd.png"` for a high-pixel-density screen. If the user agent wants to use an image for lockscreen background, `"podcast_xhd.jpg"` will be preferred.

Changing metadata:

For playlists or chapters of an audio book, multiple media elements can share a single media session.

    var audio1 = document.createElement("audio");
    audio1.src = "chapter1.mp3";

    var audio2 = document.createElement("audio");
    audio2.src = "chapter2.mp3";

    audio1.play();
    audio1.addEventListener("ended", function() {
      audio2.play();
    });

Because the session is shared, the metadata must be updated to reflect what is currently playing.

    function updateMetadata(event) {
      navigator.mediaSession.metadata = new MediaMetadata({
        title: event.target == audio1 ? "Chapter 1" : "Chapter 2",
        artist: "An Author",
        album: "A Book",
        artwork: [{src: "cover.jpg"}]
      });
    }

    audio1.addEventListener("play", updateMetadata);
    audio2.addEventListener("play", updateMetadata);

Handling media session actions:

    var tracks = ["chapter1.mp3", "chapter2.mp3", "chapter3.mp3"];
    var trackId = 0;

    var audio = document.createElement("audio");
    audio.src = tracks[trackId];

    function updatePlayingMedia() {
      audio.src = tracks[trackId];
      // Update metadata (omitted)
    }

    navigator.mediaSession.setActionHandler("previoustrack", function() {
      trackId = (trackId + tracks.length - 1) % tracks.length;
      updatePlayingMedia();
    });

    navigator.mediaSession.setActionHandler("nexttrack", function() {
      trackId = (trackId + 1) % tracks.length;
      updatePlayingMedia();
    });

    navigator.mediaSession.setActionHandler("seekto", function(details) {
      audio.currentTime = details.seekTime;
    });

Setting `playbackState`:

When a page pauses its media and plays a third-party ad in an iframe, the UA might consider the session as "not playing", however the page wants to allow the user to pause the ad playback and cancel the pending playback after the ad finishes.

    var adFrame;
    var audio = document.createElement("audio");
    audio.src = "foo.mp3";

    function resetActionHandlers() {
      navigator.mediaSession.setActionHandler("play", _ => audio.play());
      navigator.mediaSession.setActionHandler("pause", _ => audio.pause());
    }

    resetActionHandlers();

    // This method will be called when the page wants to play some ad.
    function pauseAudioAndPlayAd() {
      audio.pause();
      navigator.mediaSession.playbackState = "playing";
      setUpAdFrame();
      adFrame.contentWindow.postMessage("play_ad");
      navigator.mediaSession.setActionHandler("pause", pauseAd);
    }

    function pauseAd() {
      adFrame.contentWindow.postMessage("pause_ad");
      navigator.mediaSession.playbackState = "paused";
      navigator.mediaSession.setActionHandler("play", resumeAd);
    }

    function resumeAd() {
      adFrame.contentWindow.postMessage("resume_ad");
      navigator.mediaSession.playbackState = "playing";
      navigator.mediaSession.setActionHandler("pause", pauseAd);
    }

    window.onmessage = function(e) {
      if (e.data === "ad finished") {
        removeAdFrame();
        navigator.mediaSession.playbackState = "none";
        resetActionHandlers();
      }
    }

    function setUpAdFrame() {
      adFrame = document.createElement("iframe");
      adFrame.src = "https://example.com/ad-iframe.html";
      document.body.appendChild(adFrame);
    }

    function removeAdFrame() {
      adFrame.remove();
    }

Setting position state:

    // Media is loaded, set the duration.
    navigator.mediaSession.setPositionState({
      duration: 60
    });

    // Media starts playing at the beginning.
    navigator.mediaSession.playbackState = "playing";

    // Media starts playing at 2x 10 seconds in.
    navigator.mediaSession.setPositionState({
      duration: 60,
      playbackRate: 2,
      position: 10
    });

    // Media is paused.
    navigator.mediaSession.playbackState = "paused";

    // Media is reset.
    navigator.mediaSession.setPositionState(null);

## Acknowledgments

The editors would like to thank Paul Adenot, Jake Archibald, Tab Atkins, Jonathan Bailey, François Beaufort, Marcos Caceres, Domenic Denicola, Ralph Giles, Anne van Kesteren, Tobie Langel, Michael Mahemoff, Jer Noble, Elliott Sprehn, Chris Wilson, and Jörn Zaefferer for their participation in technical discussions that ultimately made this specification possible.

Special thanks go to Philip Jägenstedt and David Vest for their help in designing every aspect of media sessions and for their seemingly infinite patience in working through the initial design issues; Jer Noble for his help in building a model that also works well within the iOS audio focus model; and Mounir Lamouri and Anton Vayvod for their early involvement, feedback and support in making this specification happen.

## Index

### Terms defined by this specification

- action, in §10
- active media session, in §5.2
- actual playback rate, in §5.5
- actual playback state, in §5.1
- album
  - attribute for MediaMetadata, in §7
  - dfn for MediaMetadata, in §7
  - dict-member for MediaMetadataInit, in §7
- artist
  - attribute for MediaMetadata, in §7
  - dfn for MediaMetadata, in §7
  - dict-member for MediaMetadataInit, in §7
- artwork
  - attribute for MediaMetadata, in §7
  - dict-member for MediaMetadataInit, in §7
- artwork images, in §7
- audio focus, in §5.2
- constructor(), in §7
- constructor(init), in §7
- convert artwork algorithm, in §7
- current playback position, in §5.5
- declared playback state, in §6
- duration
  - definition of, in §5.5
  - dict-member for MediaPositionState, in §9
- empty metadata, in §7
- fastSeek, in §10
- fetch image algorithm, in §5.3
- guessed playback state, in §5.1
- handle media session action, in §5.4
- last position updated time, in §5.5
- last reported playback position, in §5.5
- MediaImage, in §8
- MediaMetadata, in §7
- MediaMetadata(), in §7
- MediaMetadata(init), in §7
- MediaMetadataInit, in §7
- MediaPositionState, in §9
- media session, in §7
- MediaSession, in §6
- mediaSession, in §6
- media session action, in §5.4
- MediaSessionAction, in §6
- MediaSessionActionDetails, in §10
- MediaSessionActionHandler, in §6
- media session action source, in §5.4
- media session actions update algorithm, in §5.4
- MediaSessionPlaybackState, in §6
- MediaSessionSeekActionDetails, in §10
- MediaSessionSeekToActionDetails, in §10
- metadata
  - attribute for MediaSession, in §6
  - dfn for MediaSession, in §6
- "nexttrack", in §5.4
- nexttrack, in §5.4
- "none", in §6
- none, in §6
- "pause", in §5.4
- pause, in §5.4
- "paused", in §6
- paused, in §6
- "play", in §5.4
- play, in §5.4
- playback rate, in §5.5
- playbackRate, in §9
- playbackState, in §6
- "playing", in §6
- playing, in §6
- position, in §9
- position state, in §5.5
- preferred artwork image, in §5.3
- "previoustrack", in §5.4
- previoustrack, in §5.4
- "seekbackward", in §5.4
- seekbackward, in §5.4
- "seekforward", in §5.4
- seekforward, in §5.4
- seekOffset, in §10
- seekTime, in §10
- "seekto", in §5.4
- seekto, in §5.4
- setActionHandler(), in §6
- setActionHandler(action, handler), in §6
- setPositionState(), in §6
- setPositionState(state), in §6
- sizes, in §8
- "skipad", in §5.4
- skipad, in §5.4
- source, in §8
- src, in §8
- "stop", in §5.4
- stop, in §5.4
- supported media session actions, in §5.4
- title
  - attribute for MediaMetadata, in §7
  - dfn for MediaMetadata, in §7
  - dict-member for MediaMetadataInit, in §7
- type, in §8
- update action handler algorithm, in §5.4
- update metadata algorithm, in §5.3

https://www.w3.org/TR/appmanifest/#dfn-image-object Referenced in:

- 8. The MediaImage dictionary

https://fetch.spec.whatwg.org/#concept-fetch Referenced in:

- 5.3. Metadata

https://fetch.spec.whatwg.org/#concept-internal-response Referenced in:

- 5.3. Metadata

https://fetch.spec.whatwg.org/#concept-response Referenced in:

- 5.3. Metadata (2)

https://fetch.spec.whatwg.org/#concept-response-type Referenced in:

- 5.3. Metadata

https://html.spec.whatwg.org/multipage/system-state.html#navigator Referenced in:

- 6. The MediaSession interface (2)

https://html.spec.whatwg.org/multipage/infrastructure.html#ascii-case-insensitive Referenced in:

- 8. The MediaImage dictionary (2)

https://html.spec.whatwg.org/multipage/browsers.html#browsing-context Referenced in:

- 5.1. Playback State (2) (3) (4)
- 5.2. Routing (2)
- 5.5. Position State
- 6. The MediaSession interface (2) (3) (4) (5) (6)

https://html.spec.whatwg.org/multipage/infrastructure.html#case-sensitivity-and-string-comparison Referenced in:

- 2. Conformance

https://html.spec.whatwg.org/multipage/webappapis.html#entry-settings-object Referenced in:

- 7. The MediaMetadata interface

https://html.spec.whatwg.org/multipage/infrastructure.html#in-parallel Referenced in:

- 5.3. Metadata
- 6. The MediaSession interface
- 7. The MediaMetadata interface

https://html.spec.whatwg.org/multipage/semantics.html#the-link-element Referenced in:

- 8. The MediaImage dictionary

https://html.spec.whatwg.org/multipage/embedded-content.html#media-element Referenced in:

- 11. Examples

https://html.spec.whatwg.org/multipage/infrastructure.html#mime-type Referenced in:

- 8. The MediaImage dictionary

https://html.spec.whatwg.org/multipage/embedded-content.html#concept-media-muted Referenced in:

- 5.1. Playback State

https://html.spec.whatwg.org/multipage/browsers.html#nested-browsing-context Referenced in:

- 5.2. Routing

https://html.spec.whatwg.org/multipage/embedded-content.html#potentially-playing Referenced in:

- 5.1. Playback State

https://html.spec.whatwg.org/multipage/webappapis.html#queue-a-task Referenced in:

- 5.4. Actions
- 7. The MediaMetadata interface

https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes Referenced in:

- 8. The MediaImage dictionary (2)

https://html.spec.whatwg.org/multipage/browsers.html#top-level-browsing-context Referenced in:

- 5.2. Routing

https://html.spec.whatwg.org/multipage/interaction.html#triggered-by-user-activation Referenced in:

- 5.4. Actions

https://html.spec.whatwg.org/multipage/infrastructure.html#unordered-set-of-unique-space-separated-tokens Referenced in:

- 8. The MediaImage dictionary

https://url.spec.whatwg.org/#concept-url-parser Referenced in:

- 7. The MediaMetadata interface

https://heycam.github.io/webidl/#idl-DOMString Referenced in:

- 7. The MediaMetadata interface (2) (3) (4) (5) (6)
- 8. The MediaImage dictionary (2)

https://heycam.github.io/webidl/#Exposed Referenced in:

- 6. The MediaSession interface (2)
- 7. The MediaMetadata interface

https://heycam.github.io/webidl/#SameObject Referenced in:

- 6. The MediaSession interface

https://heycam.github.io/webidl/#idl-USVString Referenced in:

- 8. The MediaImage dictionary

https://heycam.github.io/webidl/#idl-boolean Referenced in:

- 10. The MediaSessionActionDetails dictionary

https://heycam.github.io/webidl/#dfn-create-frozen-array Referenced in:

- 7. The MediaMetadata interface

https://heycam.github.io/webidl/#dfn-dictionary-member Referenced in:

- 8. The MediaImage dictionary (2) (3)
- 9. The MediaPositionState dictionary (2) (3)
- 10. The MediaSessionActionDetails dictionary (2) (3) (4)

https://heycam.github.io/webidl/#idl-double Referenced in:

- 9. The MediaPositionState dictionary (2) (3)
- 10. The MediaSessionActionDetails dictionary (2)

### Terms defined by reference

- [appmanifest] defines the following terms:
  - image object
- [FETCH] defines the following terms:
  - fetch
  - internal response
  - response
  - response type
- [HTML] defines the following terms:
  - Navigator
  - ascii case-insensitive
  - browsing context
  - case-sensitive
  - entry settings object
  - in parallel
  - link
  - media element
  - mime type
  - muted
  - nested browsing context
  - potentially playing
  - queue a task
  - sizes
  - top-level browsing context
  - triggered by user activation
  - unordered set of unique space-separated tokens
- [URL] defines the following terms:
  - url parser
- [WEBIDL] defines the following terms:
  - DOMString
  - Exposed
  - SameObject
  - USVString
  - boolean
  - create a frozen array
  - dictionary members
  - double

## References

### Normative References

[APPMANIFEST]
  Marcos Caceres; et al. Web App Manifest. 31 May 2019. WD. URL: https://www.w3.org/TR/appmanifest/
[FETCH]
  Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
  Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[RFC2119]
  S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[URL]
  Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/
[WEBIDL]
  Boris Zbarsky. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/

## IDL Index

    [Exposed=Window]
    partial interface Navigator {
      [SameObject] readonly attribute MediaSession mediaSession;
    };

    enum MediaSessionPlaybackState {
      "none",
      "paused",
      "playing"
    };

    enum MediaSessionAction {
      "play",
      "pause",
      "seekbackward",
      "seekforward",
      "previoustrack",
      "nexttrack",
      "skipad",
      "stop",
      "seekto"
    };

    callback MediaSessionActionHandler = void(MediaSessionActionDetails details);

    [Exposed=Window]
    interface MediaSession {
      attribute MediaMetadata? metadata;

      attribute MediaSessionPlaybackState playbackState;

      void setActionHandler(MediaSessionAction action, MediaSessionActionHandler? handler);

      void setPositionState(optional MediaPositionState state = {});
    };

    [Exposed=Window]
    interface MediaMetadata {
      constructor(optional MediaMetadataInit init = {});
      attribute DOMString title;
      attribute DOMString artist;
      attribute DOMString album;
      attribute FrozenArray<MediaImage> artwork;
    };

    dictionary MediaMetadataInit {
      DOMString title = "";
      DOMString artist = "";
      DOMString album = "";
      sequence<MediaImage> artwork = [];
    };

    dictionary MediaImage {
      required USVString src;
      DOMString sizes = "";
      DOMString type = "";
    };

    dictionary MediaPositionState {
      double duration;
      double playbackRate;
      double position;
    };

    dictionary MediaSessionActionDetails {
      required MediaSessionAction action;
    };

    dictionary MediaSessionSeekActionDetails : MediaSessionActionDetails {
      double? seekOffset;
    };

    dictionary MediaSessionSeekToActionDetails : MediaSessionActionDetails {
      required double seekTime;
      boolean? fastSeek;
    };

#guessed-playback-state Referenced in:

- 5.1. Playback State (2) (3) (4)

#actual-playback-state Referenced in:

- 5.1. Playback State (2)
- 5.4. Actions (2)
- 5.5. Position State
- 6. The MediaSession interface

#active-media-session Referenced in:

- 4.3. Media Session Actions
- 5.1. Playback State (2)
- 5.2. Routing (2) (3) (4)
- 5.3. Metadata (2) (3) (4) (5) (6) (7) (8)
- 5.4. Actions (2) (3) (4) (5) (6) (7) (8) (9)

#audio-focus Referenced in:

- 5.2. Routing

#update-metadata-algorithm Referenced in:

- 5.2. Routing
- 6. The MediaSession interface
- 7. The MediaMetadata interface

#fetch-image-algorithm Referenced in:

- 5.3. Metadata (2) (3) (4)

#preferred-artwork-image Referenced in:

- 5.3. Metadata

#media-session-action Referenced in:

- 4.3. Media Session Actions
- 5.4. Actions (2) (3) (4) (5) (6) (7) (8)
- 11. Examples

#media-session-action-source Referenced in:

- 5.4. Actions (2) (3)

#dom-mediasessionaction-play Referenced in:

- 5.1. Playback State (2)
- 5.4. Actions (2) (3) (4)
- 6. The MediaSession interface

#dom-mediasessionaction-pause Referenced in:

- 5.1. Playback State (2) (3)
- 5.4. Actions (2) (3) (4)
- 6. The MediaSession interface

#dom-mediasessionaction-seekbackward Referenced in:

- 5.4. Actions
- 6. The MediaSession interface

#dom-mediasessionaction-seekforward Referenced in:

- 5.4. Actions
- 6. The MediaSession interface

#dom-mediasessionaction-previoustrack Referenced in:

- 6. The MediaSession interface

#dom-mediasessionaction-nexttrack Referenced in:

- 6. The MediaSession interface

#dom-mediasessionaction-skipad Referenced in:

- 6. The MediaSession interface

#dom-mediasessionaction-stop Referenced in:

- 6. The MediaSession interface

#dom-mediasessionaction-seekto Referenced in:

- 5.4. Actions
- 6. The MediaSession interface
- 10. The MediaSessionActionDetails dictionary

#supported-media-session-actions Referenced in:

- 5.4. Actions (2) (3) (4) (5) (6)

#update-action-handler-algorithm Referenced in:

- 6. The MediaSession interface

#handle-media-session-action Referenced in:

- 5.4. Actions

#media-session-actions-update-algorithm Referenced in:

- 5.1. Playback State
- 5.2. Routing
- 5.4. Actions (2)
- 6. The MediaSession interface

#position-state① Referenced in:

- 5.5. Position State (2) (3) (4)
- 6. The MediaSession interface (2)
- 11. Examples

#duration Referenced in:

- 5.5. Position State (2) (3)
- 9. The MediaPositionState dictionary

#playback-rate Referenced in:

- 5.5. Position State
- 9. The MediaPositionState dictionary

#last-reported-playback-position Referenced in:

- 5.5. Position State
- 9. The MediaPositionState dictionary

#last-position-updated-time Referenced in:

- 5.5. Position State
- 6. The MediaSession interface

#actual-playback-rate Referenced in:

- 5.5. Position State

#current-playback-position Referenced in:

- 5.5. Position State

#enumdef-mediasessionplaybackstate Referenced in:

- 6. The MediaSession interface (2) (3)

#enumdef-mediasessionaction Referenced in:

- 5.4. Actions
- 6. The MediaSession interface
- 10. The MediaSessionActionDetails dictionary

#callbackdef-mediasessionactionhandler Referenced in:

- 5.4. Actions (2) (3)
- 6. The MediaSession interface
- 10. The MediaSessionActionDetails dictionary (2)

#mediasession Referenced in:

- 5.2. Routing (2) (3)
- 5.4. Actions (2) (3) (4) (5)
- 6. The MediaSession interface (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12)
- 7. The MediaMetadata interface
- 9. The MediaPositionState dictionary

#mediasession-metadata Referenced in:

- 6. The MediaSession interface (2) (3) (4) (5)
- 11. Examples (2)

#dom-navigator-mediasession Referenced in:

- 6. The MediaSession interface

#dom-mediasession-metadata Referenced in:

- 5.3. Metadata (2) (3)
- 6. The MediaSession interface

#dom-mediasession-playbackstate Referenced in:

- 5.1. Playback State (2)
- 5.2. Routing
- 6. The MediaSession interface (2) (3) (4)
- 11. Examples

#declared-playback-state Referenced in:

- 5.1. Playback State (2)

#dom-mediasessionplaybackstate-none Referenced in:

- 6. The MediaSession interface (2)

#dom-mediasessionplaybackstate-playing Referenced in:

- 5.1. Playback State (2) (3)
- 5.4. Actions (2)
- 6. The MediaSession interface

#dom-mediasessionplaybackstate-paused Referenced in:

- 5.1. Playback State
- 5.5. Position State
- 6. The MediaSession interface

#dom-mediasession-setpositionstate Referenced in:

- 6. The MediaSession interface

#mediametadata Referenced in:

- 4.1. User interface guidelines (2) (3) (4) (5)
- 4.2. Incognito mode
- 6. The MediaSession interface (2)
- 7. The MediaMetadata interface (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) (20)

#dictdef-mediametadatainit Referenced in:

- 7. The MediaMetadata interface

#dom-mediametadatainit-title Referenced in:

- 7. The MediaMetadata interface

#dom-mediametadatainit-artist Referenced in:

- 7. The MediaMetadata interface

#dom-mediametadatainit-album Referenced in:

- 7. The MediaMetadata interface

#dom-mediametadatainit-artwork Referenced in:

- 7. The MediaMetadata interface (2)

#mediametadata-media-session Referenced in:

- 6. The MediaSession interface (2) (3)
- 7. The MediaMetadata interface (2)
- 11. Examples

#mediametadata-title Referenced in:

- 7. The MediaMetadata interface (2) (3) (4) (5)

#mediametadata-artist Referenced in:

- 7. The MediaMetadata interface (2) (3) (4) (5)

#mediametadata-album Referenced in:

- 7. The MediaMetadata interface (2) (3) (4) (5)

#mediametadata-artwork-images Referenced in:

- 5.3. Metadata
- 7. The MediaMetadata interface (2) (3) (4) (5) (6)
- 11. Examples

#empty-metadata Referenced in:

- 5.3. Metadata

#dom-mediametadata-mediametadata Referenced in:

- 7. The MediaMetadata interface

#convert-artwork-algorithm Referenced in:

- 7. The MediaMetadata interface (2)

#dom-mediametadata-title Referenced in:

- 7. The MediaMetadata interface (2)

#dom-mediametadata-artist Referenced in:

- 7. The MediaMetadata interface (2)

#dom-mediametadata-album Referenced in:

- 7. The MediaMetadata interface (2)

#dom-mediametadata-artwork Referenced in:

- 5.3. Metadata (2)
- 7. The MediaMetadata interface

#dictdef-mediaimage Referenced in:

- 7. The MediaMetadata interface (2) (3) (4) (5) (6)
- 8. The MediaImage dictionary (2) (3) (4) (5)

#dom-mediaimage-src Referenced in:

- 5.3. Metadata
- 7. The MediaMetadata interface (2) (3) (4)
- 8. The MediaImage dictionary

#dom-mediaimage-sizes Referenced in:

- 7. The MediaMetadata interface (2) (3) (4)
- 8. The MediaImage dictionary (2) (3)

#dom-mediaimage-type Referenced in:

- 7. The MediaMetadata interface (2) (3) (4)
- 8. The MediaImage dictionary

#dictdef-mediapositionstate Referenced in:

- 5.5. Position State
- 6. The MediaSession interface
- 9. The MediaPositionState dictionary (2)

#dom-mediapositionstate-duration Referenced in:

- 6. The MediaSession interface (2) (3)
- 9. The MediaPositionState dictionary

#dom-mediapositionstate-playbackrate Referenced in:

- 6. The MediaSession interface (2)
- 9. The MediaPositionState dictionary

#dom-mediapositionstate-position Referenced in:

- 6. The MediaSession interface (2)
- 9. The MediaPositionState dictionary

#dictdef-mediasessionactiondetails Referenced in:

- 5.4. Actions
- 6. The MediaSession interface
- 10. The MediaSessionActionDetails dictionary (2) (3) (4)

#dictdef-mediasessionseekactiondetails Referenced in:

- 5.4. Actions

#dictdef-mediasessionseektoactiondetails Referenced in:

- 5.4. Actions

#dom-mediasessionactiondetails-action Referenced in:

- 10. The MediaSessionActionDetails dictionary

#dom-mediasessionseekactiondetails-seekoffset Referenced in:

- 10. The MediaSessionActionDetails dictionary

#dom-mediasessionseektoactiondetails-seektime Referenced in:

- 10. The MediaSessionActionDetails dictionary

#dom-mediasessionseektoactiondetails-fastseek Referenced in:

- 10. The MediaSessionActionDetails dictionary