getMediaURI

Sonos players use the getMediaURI message to resolve a URI for the actual audio data from a unique track ID. Players send a single id parameter and expect your server to return a fully qualified URI to the track. The player uses the SOAP header to send credential information. See SOAP requests and responses and Streaming basics for details.

The player then issues an HTTP GET request for the music stream. If your server requires a list of HTTP headers and values, you can include them in the httpHeader object. The player will include these headers as part of the GET request.


Request parameters

NameTypeDescription
idstring (128)Unique ID of the item. This will be URL-encoded in firmware so pay attention to length when approaching the 128 character limit.
actionstringYou can find out whether a player played a track due to an explicit action by the user, such as when the user presses the play button, or due to an implicit action by the Sonos household, such as when a player plays the next track in the queue. Set the "Support the ability to receive implicit or explicit actions for getMediaURI requests" capability to receive these actions. See Test your service for details. The values are:

- IMPLICIT - The Sonos household requested the audio stream URI.
- EXPLICIT:PLAY - The user pressed the play button.
- EXPLICIT:SEEK - The user scrubbed through the track.
- EXPLICIT:SKIP_FORWARD - The user skipped forward.
- EXPLICIT:SKIP_BACK - The user skipped back.
secondsSinceExplicitintMeasures the time since the last queue-based activity. For example, the last time a track was added, removed, or reordered in the queue, or any of the EXPLICIT play actions listed above was performed by a user.
deviceSessionTokenstring (2048)(Optional) A token representing the session between a specific Sonos player and your service. The player caches the value that you send in your response and sends it back in this parameter. The Sonos player performs a straight string comparison on the previous value for replacement of the cached value. Thus, the first time the player sends this response, it may not have a value for this parameter.

This data is opaque to Sonos, and is passed as context. It's offered as a lower cost shortcut for encoding session keys. By using tokens, your service does not have to re-validate the device certificate.

While this can be any XML-encoded string, we suggest using hexadecimal characters or base64.

See Encrypt content for details.

Response

NameTypeDescription
getMediaURIResulturiThe full URI to the audio stream data.
positionInformationcomplex(Optional) Position information identifies the play position to resume if the requested track is resumable. The sub-elements include id, index, and offsetMillis. See the SMAPI object types for details on the components of this object. See Save & resume playback for details on usage.
httpHeaderscomplex(Optional) A list of httpHeader elements, each containing an HTTP header and value to be included with the HTTP GET request for an actual stream. See SMAPI object types for details.
deviceSessionTokenstring (2048)(Optional) A token provided by your service representing the session between your service and a Sonos player. The token is opaque to Sonos and passed back in subsequent calls to use as session context. See the description of the deviceSessionToken in the request parameters above for details.
deviceSessionKeystring(Optional) A key for the Sonos player to decrypt the contentKey. If this is not included, the contentKey should not be encrypted.

This string should be encrypted using the device certificate and RSA with OAEP. The player will decrypt the string and use the result to decrypt the contentKey string.

This element should have a "type" attribute that describes the type of encryption your service used to encrypt the contentKey. This attribute should be one of the following values:

- NONE for no encryption (this is functionally equivalent to omitting this element).
- AES-ECB for advanced encryption standard electronic codebook encryption.
- AES-CBC for advanced encryption standard cipher block chaining encryption. Separate the key and IV with a colon. See the remarks for details.See Encrypt content for details.
contentKeystring(Optional) The encryption key to decrypt the audio stream identified by the getMediaURIResult. The player uses the unencrypted result of the deviceSessionKey to decrypt the contentKey, then uses the result to decrypt the content.

This element should have a type attribute that describes the type of encryption your service used to encrypt the content. This attribute should be one of the following values (see the example below):

- NONE for no encryption.
- AES-ECB for advanced encryption standard electronic codebook encryption.
- AES-CBC for advanced encryption standard cipher block chaining encryption. Separate the key and IV with a colon. See the remarks for details.See Encrypt content for details.

Best practices

Here are some best practices when implementing getMediaURI.

Use implicit and explicit actions to track user actions

We added implicit and explicit actions so that you track user actions on Sonos. For example, you can see whether the user chose to play a track, scrub through it (seek), skip forward, or skip back. If the user chose an action, it's called an explicit action. If the Sonos system chose an action, it's an implicit action. The one implicit action Sonos returns is when a player requests the audio stream URI. This happens most often when the player plays the next song in the queue.

You may want to receive these actions if you limit the number of devices that can stream your music at once. A Sonos Household counts as one device. Other devices might include a mobile phone, tablet, or computer. Turn this on with the "Support the ability to receive implicit or explicit actions for getMediaURI requests" capability. See Test your service for details.

Encrypt tracks for Digital Rights Management (DRM)

You can encrypt the tracks that Sonos accesses and provide decryption information to Sonos using fields in the getMediaURI response. See Encrypt content for details.

If you're sending audio using HLS, Sonos players send getContentKey requests for keys to decrypt individual segments. See HTTP Live Streaming (HLS) for details.

URIs should not expire before Sonos can finish playing

If you use expiring URIs (sometimes known as time-bomb URIs), you must ensure that the URI will not expire before Sonos can finish playing the content. Sonos cannot recover gracefully if the URI suddenly expires. Base the URI's expiration time on when your service responds to a getMediaURI request. If you get another getMediaURI request for the same ID, reset the URI's expiration time. This will help to ensure that the player has enough time to buffer and play the content. Do not base a URI's expiration on any other criteria. For example, do not use criteria such as, "the URI must be opened within X amount of time".

📘

Calculate the minimum URI expiration time as follows:

URI-expiration-time > track-duration + 30-minutes-paused + additional-listener-actions

The duration of a track and the Sonos player's buffer are factors when you set a URI expiration time. The Sonos player stores the URI's content in a buffer. The player rarely stores an entire track in the buffer. Since the player will likely need to access the URI's content more than once while the track plays, the URI expiration time must be greater than the track duration.

If the listener pauses for at least 30 minutes, the player will send a new getMediaURI request. A new request obtains a fresh URI from your service with a reset expiration time. To take into account a pause shorter than 30 minutes, the URI expiration time must add at least 30 minutes to the track duration.

Multiple pause and seek actions by the listener require additional expiration time that is impossible to predict. Ensure you add more to the URI expiration time to account for extra pause and seek actions.

Specify the encryption schema for AES-CBC encryption

For AES-CBC, specify the encryption schema using a colon between the key and initialization vector (IV). Both the key and IV should be in hexadecimal format. The number of characters in the key shall define the size of the key, so for example, a 128-bit decryption key will include 32 hex characters. The IV should always be 128-bits (32 hex characters). Valid key lengths are 128-bits (32-chars), 196-bits (48-chars), and 256-bits (64-chars).

Handling multiple getMediaURI requests

Sonos players make multiple getMediaURI requests when playing content, such as after a long pause, seeking position, or changing group coordinators. This does not mean that a new playback session has begun. The getMediaURIResult returned in response to getMediaURI should not change within a user's playback session. Players may behave poorly if the getMediaURIResult changes mid-stream. You can use values in Sonos requests to associate a current getMediaURI request to a previous getMediaURI request so that you can send the same getMediaURIResult. The values are:

  • In the getMediaURI request:
    • X-Sonos-Playback-Id HTTP request header.
    • action parameter to indicate why the player is sending the call.
  • In the POST /timePlayed request:
    • SMAPI track ID in the objectId.
    • Dereferenced media URL in the mediaUrl.
  • SMAPI credentials header (see SOAP requests and responses for details):
    • zonePlayerId.
    • householdId in loginToken.

If you have an implementation that generates a unique getMediaURIResult responses for each request, you should develop an approach to determine if the getMediaURI request was a unique play or triggered by other reasons. For example:

  1. Create a database by caching getMediaURI requests sent to Sonos players, using a key for each entry to identify a unique track in a session.
  2. You can create the key by hashing the householdId, X-Sonos-Playback-Id, and objectId.
  3. In each database entry, include the mediaUrl, zonePlayerId, and any other custom tokens specific to your integration.

Handling seek actions

When the getMediaURI action is EXPLICIT:SEEK, it indicates that the user scrubbed through the track. To handle this, look up the entry in the database and return the same mediaUrl returned in the first call.

When the action is not EXPLICIT:SEEK, return a brand new URL in all cases except when the zonePlayerId in the new getMediaURI request doesn’t match the one from the previous request. This exception handles situations when the music moves from one group coordinator to another.

If the zonePlayerId is different, the key remains the same, but the calling player is different (e.g., getMediaURI/credentials/zonePlayerId is not equal to database[key].zonePlayerId). The zonePlayerId records which player is currently managing the playback session. When Sonos sends the getMediaURI request, you can compare the zonePlayerId in the header with the value in the database entry for the previous getMediaURI request. If the values are different, it indicates that the user must have moved playback to another player. In this case you should record the new zonePlayerId in order to make the same comparison later, if the user moves the session again, as it could move multiple times.


Samples

Here are some sample requests and responses.

Sample request

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
  <soap:Header>
   ...
  </soap:Header>
  <soap:Body>
    <ns:getMediaURI>
      <ns:id>track001</ns:id>
    </ns:getMediaURI>
  </soap:Body>
</soap:Envelope>

Sample request with implicit and explicit actions

<soap:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
  <soap:Header>
   ...
  </soap:Header>
   <soap:Body>
      <ns:getMediaURI>
         <ns:id>track001</ns:id>
         <ns:action>IMPLICIT</ns:action>
         <ns:secondsSinceExplicit>200</ns:secondsSinceExplicit>
      </ns:getMediaURI>
   </soap:Body>
</soap:Envelope>

Sample response

Your response would be the same for both sample requests above:

<soap:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
   <soap:Body>
      <ns:getMediaURIResponse>
         <ns:getMediaURIResult>http://acme.example.com/music/track001.mp3</ns:getMediaURIResult>
      </ns:getMediaURIResponse>
   </soap:Body>
</soap:Envelope>

Sample response with custom HTTP headers

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://www.sonos.com/Services/1.1">
  <soap:Body>
    <ns:getMediaURIResponse>
      <ns:getMediaURIResult>
         http://acme.example.com/music/track001.mp3
      </ns:getMediaURIResult>
      <ns:httpHeaders>
        <ns:httpHeader>
          <ns:header>Referer</ns:header>
          <ns:value>acme.example.com</ns:value>
        </ns:httpHeader>
        <ns:httpHeader>
          <ns:header>Cookie</ns:header>
          <ns:value>a398mx02348n</ns:value>
        </ns:httpHeader>
      </ns:httpHeaders>
   </ns:getMediaURIResponse>
  </soap:Body>
</soap:Envelope>

Sample request for DRM

<soap:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
    <soap:Header>
        <ns:credentials>
            <ns:deviceId>A8-F9-32-B0-01-23:0</ns:deviceId>
            <ns:deviceCert>....</ns:deviceCert>
            <ns:zonePlayerId>B8-E9-37-C0-01-18:0</ns:zonePlayerId>
            <ns:deviceProvider>Sonos</ns:deviceProvider>
            <ns:loginToken>
              <ns:token>12345678</ns:token>
              <ns:key>123456789</ns:key>
            </ns:loginToken>
        </ns:credentials>
    </soap:Header>
   <soap:Body>
      <ns:getMediaURI>
         <ns:id>track*65220557</ns:id>
         <ns:action>IMPLICIT</ns:action>
         <ns:secondsSinceExplicit>200</ns:secondsSinceExplicit>
         <ns:deviceSessionToken>234567890-90</ns:deviceSessionToken>
      </ns:getMediaURI>
   </soap:Body>
</soap:Envelope>

Sample response for DRM

<soap:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.sonos.com/Services/1.1">
  <soap:Body>
    <ns:getMediaURIResponse>
      <ns:getMediaURIResult>https://mediacdn.example.com/1234567890123ABC.128.mp3?1a2b3c4d5e6f</ns:getMediaURIResult>
      <ns:deviceSessionToken>234567890-90</ns:deviceSessionToken>
      <ns:deviceSessionKey type="AES-ECB">FEDBCA9876543210FEDBCA9876543210</ns:deviceSessionKey>
      <ns:contentKey type="AES-CBC">0123456789ABCDEF0123456789ABCDEF:FEDBCA9876543210FEDBCA9876543210</ns:contentKey>
    </ns:getMediaURIResponse>
  </soap:Body>
</soap:Envelope>