Save & resume playback

Your service can provide resumable content in the form of audiobooks and individual tracks, such as podcasts. Sonos will send you the position in the track or audiobook at which the Sonos listener paused, so that you can resume it again. You can also send position information for Sonos to start an audiobook or track at a specific position.

For example, a listener could listen to an audiobook on your service and then switch to listening to it on Sonos. You can set this content as resumable and send the position information for Sonos to start the audio. Likewise, a listener could pause an audiobook on Sonos and continue listening to it on your service, using the position information sent to you by the player. The examples below talk about podcasts for individual tracks of resumable content and audiobooks for containers.


You can resume audiobooks & podcasts

When a listener selects a podcast, the Sonos app sends your service a getMetadata request for the podcast. To specify that the content is resumable, return mediaMetadata with an itemType of track and trackMetadata that includes canResume set to true.

Audiobooks are handled differently than resumable tracks because chapters are a set of tracks that we want to keep together and in order. For example, it would not make sense to let listeners shuffle or crossfade audiobook chapters in the queue like music tracks.

To keep audiobook chapters together, you specify an audiobook in its container. When a listener selects a container of audiobooks, the Sonos app sends your service a getMetadata request for the container. To specify audiobooks in the container, return a mediaCollection element for each audiobook with itemType set to audiobook and canResume set to true. When a listener selects an audiobook from the container, the Sonos app does not add the audiobook to the queue but instead the Sonos app passes along the audiobook ID to the Sonos player. Then, the Sonos player sends your service a getMetadata request for the audiobook, for which your service returns a set of chapters as mediaMetadata tracks.

The only resumable item types are audiobook and track.


Enabling status reporting

In order for the Sonos player to provide your service play position information for resumable content, you need to set up a reporting endpoint. See Add reporting for details. Reports include a positionMillis value, which is the current playhead position at the time of the report.


Managing position information

Your service needs to maintain play position information for the audiobooks and resumable tracks listeners listen to. This includes the following tasks:

  • Store position information during play
  • Handle pause and continue
  • Store position information when track play ends

Information for resumable content includes offsetMillis, representing the position into the track in milliseconds.

When the Sonos player starts playing resumable content, it sends play position information in a periodic playback update report to your service, which you should store for the resumable content and Sonos listener. The Sonos player continues to send this report regularly until the listener decides to play something else or pause the player.

If the listener explicitly pauses the content, such as by pressing the pause button in the Sonos app or on the Sonos product while listening to resumable content, the Sonos player reports the play position to your service. Your service needs to store this information for the resumable content and listener. See the sections below for details about what happens when Sonos pauses and continues playback.

When the playing track changes to a different track, the Sonos player sends a final playback report to your service with the total amount of time the track played, which you should store for the resumable content and listener. This occurs no matter how the track changes, such as when a track completes playing, when a listener chooses to skip to the next chapter of a book, or when a listener starts to listen to something else. Sonos players send a final playback report after 30 minutes of no playback activity to indicate that playback has stopped.

See Add reporting for details about these reports.


Providing resume position information

When a listener returns to listen to resumable content they did not finish, your service supplies to Sonos the latest play position in a positionInformation element so that the Sonos player can resume playing the content where the listener left off. If your service determines that the listener is just beginning to listen to a particular resumable content, simply omit the position information and the Sonos player starts at the beginning.


Implementing audiobooks

While an audiobook plays, the Sonos app displays the current chapter and other audiobook information on the now-playing screen. The listener can skip to the next or previous chapter but cannot view and select any specific chapter in the book. Following is the workflow for an audiobook, which highlights in green the tasks your service needs to implement. Also included below are examples of returned results your service needs to provide.


Defining audiobooks

The workflow starts by showing how the Sonos app obtains an audiobook ID and provides it to the Sonos player. A listener browses the Sonos app to the container that has an audiobook, and the Sonos app sends your service a getMetadata request to your service to get positionInformation request for the container.

Your service returns a getMetadataResult that holds a list of items in the container, where each audiobook is a mediaCollection element that includes the following minimum settings:

  • itemType set to audiobook
  • canResume set to true
  • title
  • authorId
  • author
  • narratorId
  • narrator
  • canPlay set to true

​​The following is a sample service response to a getMetadata request to your service to get positionInformation request for a container with two audiobooks:

<ns:getMetadataResponse>
    <ns:getMetadataResult>
        <ns:index>0</ns:index>
        <ns:count>2</ns:count>
        <ns:total>2</ns:total>
        <ns:mediaCollection>
            <ns:id>bk:1</ns:id>
            <ns:itemType>audiobook</ns:itemType>
            <ns:displayType>booksEditorial</ns:displayType>
            <ns:title>The Adventures of Sherlock Holmes</ns:title>
            <ns:summary>Robie Robot reads the mystery classics of Sir Arthur Conan Doyle. Listen
                with excitement as Mr. Holmes and Dr. Watson scamper about ye olde country solving
                crime.
            </ns:summary>
            <ns:isFavorite>false</ns:isFavorite>
            <ns:authorId>ar:30</ns:authorId>
            <ns:author>Sir Arthur Conan Doyle</ns:author>
            <ns:narratorId>ar:33</ns:narratorId>
            <ns:narrator>Microsoft Sam</ns:narrator>
            <ns:canPlay>true</ns:canPlay>
            <ns:albumArtURI>
                https://acme.example.com/assets/images/book_sherlockholmes.jpg
            </ns:albumArtURI>
            <ns:canResume>true</ns:canResume>
        </ns:mediaCollection>
        <ns:mediaCollection>
            <ns:id>bk:2</ns:id>
            <ns:itemType>audiobook</ns:itemType>
            <ns:displayType>booksEditorial</ns:displayType>
            <ns:title>The Adventures of Static HLS 1</ns:title>
            <ns:summary>PLX Narrator</ns:summary>
            <ns:isFavorite>false</ns:isFavorite>
            <ns:authorId>ar:34</ns:authorId>
            <ns:author>PLX Author</ns:author>
            <ns:narratorId>ar:35</ns:narratorId>
            <ns:narrator>PLX Narrator</ns:narrator>
            <ns:canPlay>true</ns:canPlay>
            <ns:albumArtURI>https://acme.example.com/assets/images/test.jpg
            </ns:albumArtURI>
            <ns:canResume>true</ns:canResume>
        </ns:mediaCollection>
    </ns:getMetadataResult>
</ns:getMetadataResponse>

When the listener selects an audiobook from the container, the Sonos app will not put the audiobook in the queue so that the chapters remain together and in order when the book plays.

If the listener selects "About this Book" from the Sonos app's Info View screen, Sonos makes a getExtendedMetadata request to your service with the audiobook ID. You can choose to display audiobook notes to the listener by returning the relatedText element with the type set to BOOK_NOTES. For details on Info View, see Add actions.


Providing resume book position

Before the Sonos player begins to play the audiobook, it determines where to resume play by first sending your service a getMetadata request to your service to get positionInformation request with the audiobook ID.

Your service returns a getMetadataResult to the Sonos player that includes positionInformation and mediaMetadata sub-elements representing the chapters. Include the positionInformation sub-element if your service determines this listener is resuming listening. If your service determines this listener is just beginning to listen, you can omit positionInformation. The data includes the following:

  • id—The identifier of the chapter track where play is to resume.
  • index—For future use. Set this value to "0".
  • offsetMillis—The number of milliseconds into the chapter where playback is to resume.

Represent the audiobook chapters with a set of mediaMetadata elements. There is a hard upper limit of 200 chapters per audiobook, but the actual limit may be lower depending on the length of the chapter metadata returned. Each chapter includes a trackMetadata sub-element with authorId, author, narratorId, narrator, bookId, book, duration, and albumArtURI data. Also include:

  • canPlay set to true for an audiobook chapter.
  • canAddToFavorites set to false for an audiobook chapter.

Note, do not set canResume to true for individual chapters of an audiobook. Set this flag only at the audiobook level of the container in the mediaCollection. The following is an example of a getMetadataResult for an audiobook:

<ns:getMetadataResponse>
    <ns:getMetadataResult>
        <ns:index>0</ns:index>
        <ns:count>2</ns:count>
        <ns:total>2</ns:total>
        <ns:positionInformation>
            <ns:id>tr:473</ns:id>
            <ns:index>0</ns:index>
            <ns:offsetMillis>408191</ns:offsetMillis>
        </ns:positionInformation>
        <ns:mediaMetadata>
            <ns:id>tr:472</ns:id>
            <ns:itemType>track</ns:itemType>
            <ns:title>Chapter 1</ns:title>
            <ns:mimeType>audio/mp3</ns:mimeType>
            <ns:trackMetadata>
                <ns:authorId>ar:30</ns:authorId>
                <ns:author>Sir Arthur Conan Doyle</ns:author>
                <ns:narratorId>ar:33</ns:narratorId>
                <ns:narrator>Microsoft Sam</ns:narrator>
                <ns:bookId>bk:1</ns:bookId>
                <ns:book>The Adventures of Sherlock Holmes</ns:book>
                <ns:duration>3069</ns:duration>
                <ns:albumArtURI>
                    https://acme.example.com/assets/images/book_sherlockholmes.jpg
                </ns:albumArtURI>
                <ns:canPlay>true</ns:canPlay>
                <ns:canAddToFavorites>false</ns:canAddToFavorites>
            </ns:trackMetadata>
        </ns:mediaMetadata>
        <ns:mediaMetadata>
            <ns:id>tr:473</ns:id>
            <ns:itemType>track</ns:itemType>
            <ns:title>Chapter 2</ns:title>
            <ns:mimeType>audio/mp3</ns:mimeType>
            <ns:trackMetadata>
                <ns:authorId>ar:30</ns:authorId>
                <ns:author>Sir Arthur Conan Doyle</ns:author>
                <ns:narratorId>ar:33</ns:narratorId>
                <ns:narrator>Microsoft Sam</ns:narrator>
                <ns:bookId>bk:1</ns:bookId>
                <ns:book>The Adventures of Sherlock Holmes</ns:book>
                <ns:duration>3258</ns:duration>
                <ns:albumArtURI>
                    https://acme.example.com/assets/images/book_sherlockholmes.jpg
                </ns:albumArtURI>
                <ns:canPlay>true</ns:canPlay>
                <ns:canAddToFavorites>false</ns:canAddToFavorites>
            </ns:trackMetadata>
        </ns:mediaMetadata>
    </ns:getMetadataResult>
</ns:getMetadataResponse>

The Sonos player determines the chapter and offset from where play will resume based on the positionInformation your service supplied. The Sonos player then repeatedly sends your service getMediaURI requests for the chapters starting with the resume chapter, and your service returns a getMediaURIResult for each chapter. If the audiobook has no positionInformation, the requests start with the first chapter and playback will start at the beginning.


Storing audiobook position during play

When playing an audiobook, the Sonos player periodically sends an update to POST /timePlayed to send play position information to your service. Store this information for the audiobook and listener. A reply is optional. By default, the player continues to send updates at 60 second intervals.


Handling audiobook pause and continue

If the listener pauses playback, the Sonos player sends an update to POST /timePlayed to send play position information to your service. You can store this, but you do not need to reply. During a pause, the player also suspends POST /timePlayed updates to your service. Note the following:

  • If the listener selects continue within 30 minutes: The Sonos player continues playing at the paused position and resumes POST /timePlayed updates to your service.
  • If 30 minutes pass during a pause: Sonos players send a final update to POST /timePlayed to indicate that playback has stopped. The Sonos app leaves only the play button enabled. It also disables controls for changing the play position and does not display any current position information as the listener may have decided to listen to the audiobook on a different device.
  • If the listener selects continue after 30 minutes: ​The Sonos player sends a getMetadata request to your service to get positionInformation. If you send a value, Sonos resumes playback as described earlier in the workflow, but at the new position. If you don't send a value, Sonos starts playback at the beginning of the content.

Storing position when chapter play ends

When the listener stops listening to a chapter, the Sonos player sends a final update to POST /timePlayed to your service. Store the playback information if necessary. You do not need to reply to this post. The listener can stop listening to a chapter track in any number of ways, such as when the chapter is complete, when the listener selects the next chapter, or if the listener starts listening to something else.


Adding controls for audiobooks

During play, the listener can select Sonos app controls to change the play position. The following controls are available:

  • Progress bar: Play moves to the newly selected position in the chapter.
  • Next button: Play moves to the next chapter.
  • Previous button: Play moves to the previous chapter.
  • Fast Forward 30 Seconds button: Play moves 30 seconds ahead in the chapter.
  • Rewind 30 Seconds button: Play moves 30 seconds back in the chapter.

Some of these controls end the play of the current chapter and cause a new chapter to play. If this occurs, the Sonos player will send an update to POST /timePlayed to your service with playback information.


Implementing resumable tracks

Following is the workflow for selecting and playing a podcast, which is a typical resumable track. Green highlights the tasks your service needs to implement. Included below are examples of returned results your service needs to provide to implement resumable tracks.


Defining resumable tracks

The workflow shows that when a listener browses the Sonos app and selects a podcast, the Sonos app sends your service a getMetadata request to your service to get positionInformation request with the podcast's ID (workflow steps 1 through 3).

Your service needs to return to the Sonos app a that holds a resumable track represented as a element with the sub-element containing set to true. The following is a sample service response to a getMetadata request to your service to get positionInformation request for a podcast:

<ns:getMetadataResponse>
  <ns:getMetadataResult>
    <ns:index>0</ns:index>
    <ns:count>1</ns:count>
    <ns:total>1</ns:total>
    <ns:mediaMetadata>
      <ns:id>tr:480</ns:id>
      <ns:itemType>track</ns:itemType>
      <ns:title>Episode1185-SmugglingAcrossBorders</ns:title>
      <ns:isFavorite>false</ns:isFavorite>
      <ns:mimeType>audio/mp3</ns:mimeType>
      <ns:trackMetadata>
        <ns:artistId>ar:31</ns:artistId>
        <ns:artist>ESLPodcast</ns:artist>
        <ns:albumId>al:41</ns:albumId>
        <ns:album>TheESLPodcast</ns:album>
        <ns:duration>1166</ns:duration>
        <ns:albumArtURI>https://acme.example.com/assets/images/ESL_400.png</ns:albumArtURI>
        <ns:canPlay>true</ns:canPlay>
        <ns:canAddToFavorites>true</ns:canAddToFavorites>
        <ns:canResume>true</ns:canResume>
      </ns:trackMetadata>
      <ns:dynamic>
        <ns:property>
          <ns:name>LIKED</ns:name>
          <ns:value>0</ns:value>
        </ns:property>
      </ns:dynamic>
    </ns:mediaMetadata>
  </ns:getMetadataResult>
</ns:getMetadataResponse>

Providing resume track position

Before the Sonos player begins to play the podcast, it determines where to resume play by first sending your service a getMediaURI request to your service to get positionInformation request for the track ID (workflow steps 5 through 8).

Your service returns to the Sonos player a that includes along with the podcast's URI. Include if your service determines this listener is resuming listening. If your service determines this listener is just beginning to listen, you can omit ​. The data includes the following:

  • The current track ID which is the same as the requested ID.
  • For future use. Set this value to "0".
  • The number of milliseconds into the track where playback is to resume.

The following is an example of a service response to getMediaURI for a resumable track that includes position information:

<getMediaURIResponse xmlns="http://www.sonos.com/Services/1.1">
    <getMediaURIResult>
     http://example.com/12345.mp3
  </getMediaURIResult>
    <positionInformation>
        <id>tr:480</id>
        <index>0</index>
        <offsetMillis>54690</offsetMillis>
    </positionInformation>
</getMediaURIResponse>

Storing track position during play

When playing a resumable track, the Sonos player periodically sends an update to POST /timePlayed to send play position information to your service. Store this information for the audiobook and listener. A reply is optional. By default, the player continues to send updates at 60 second intervals.


Handling track pause and continue

If the listener pauses playback, the Sonos player sends an update to POST /timePlayed to send play position information to your service. You can store this, but you do not need to reply. During a pause, the player also suspends POST /timePlayed updates to your service. Note the following:

  • If the listener selects continue within 30 minutes: The Sonos player continues playing at the paused position and resumes POST /timePlayed updates to your service.
  • If 30 minutes pass during a pause: Sonos players send a final update to POST /timePlayed to indicate that playback has stopped. The Sonos app leaves only the play button enabled. It also disables controls for changing the play position and does not display any current position information as the listener may have decided to listen to the audiobook on a different device.
  • If the listener selects continue after 30 minutes: ​The Sonos player sends a getMetadata request to your service to get positionInformation. If you send a value, Sonos resumes playback as described earlier in the workflow, but at the new position. If you don't send a value, Sonos starts playback at the beginning of the content.

Storing position when track play ends

When the listener stops listening to a resumable track, the Sonos player sends a final update to POST /timePlayed to your service. Store the playback information if necessary. You do not need to reply to this post. The listener can stop listening to a chapter track in any number of ways, such as when the chapter is complete, when the listener selects the next chapter, or if the listener starts listening to something else.