Streaming basics

Regardless of which type of music service you support, you will be streaming audio files to Sonos.

If you need your streaming media encrypted, Sonos supports digital rights management as described in Encrypt content. If you need to use expiring URIs for content (sometimes known as time-bombed URIs), see getMediaURI for guidelines.


Streaming Process

SMAPI is used to gather all of the information needed to determine which tracks to request and where the relevant audio files are stored. However, all of the actual streaming process happens outside of SMAPI Sonos uses a fairly standard process to retrieve the music from your service involving HTTP GET requests. Sonos does not cache the entire file before starting playback, but instead buffers and processes as needed until the entire file has been played. One or more GET requests will be sent to the URI obtained via SMAPI for each music file. For most file formats, playback from the beginning of the file will result in one GET request.

In some cases, such as resuming from pause, seeking within a track, or with specific file formats, the data flow must start in the middle of the file. To service this, Sonos sends a GET request using a Range header asking for the rest of the track starting from the resumption point. Your music service must understand this request and either send the requested partial file segment along with standard 206 HTTP status codes or send 416 HTTP status code errors if the requested byte range is invalid in some way and you cannot respond with the matching file segment.

Your service may require using other HTTP headers with the streaming GET requests. Those, too, can be passed to Sonos via SMAPI along with the values you expect Sonos to use for each of these headers (both the headers and the URI are obtained using the getMediaURI call). This is a direct passthrough; Sonos will use the specified headers and their related values verbatim as headers in the GET request to the supplied URI.

In addition to returning the requested music, your service must return an accurate Content-Length HTTP header in the response. Sonos requires this to support seeking to any point in the file for formats where the time position doesn't map linearly to byte positions. In some situations, Sonos players may send a HEAD request to get the Content-Length header. Make sure that your service can accept and respond to this request or listeners won’t be able to seek in these situations.

For example, suppose Sonos players need to retrieve "Lobachevsky" by Tom Lehrer from your music service. According to SMAPI, it can be retrieved from URI http://music‑mymusicservice.example.com/files/lehrer_lobachevsky.mp3 and the request should include HTTP header referrer set to sonos-mymusicservice.example.com to indicate that the request came from Sonos. The song file at that location is 4570936 bytes long.

After receiving the URI from SMAPI, Sonos sends the following GET request to your music service:

GET 
http://music-mymusicservice.example.com/files/lehrer_lobachevsky.mp3
Referer:sonos-mymusicservice.example.com

Your service should then send back the entire file in the response along with the following status code and HTTP headers:

HTTP/1.1 200 Success
Content-Type: application/mp3
Accept-Ranges: bytes
Content-Length: 4570936

The user pauses the file at byte 3480314. A few minutes later he resumes play. At that time Sonos sends your service the following request for the rest of the file:

GET 
http://music-mymusicservice.example.com/files/lehrer_lobachevsky.mp3
Referer:sonos-mymusicservice.example.com
Range:3480315-

Your service then sends back the section of the file starting with byte 3480315 until the end along with the following status code and HTTP headers:

HTTP/1.1 206 Partial Content
Content-Type: application/mp3
Accept-Ranges: bytes
Content-Range: bytes 3480315-/4570936
Content-Length: 1090621

The user pauses their music again and happens to hit the very last byte of the file. When the user resumes, the following request is made:

GET 
http://music-mymusicservice.example.com/files/lehrer_lobachevsky.mp3
Referer:sonos-mymusicservice.example.com
Range:4570937-

Your service sends back a 416 error indicating that the requested range is invalid:

HTTP/1.1 416 Requested Range Not Satisfiable

Sonos moves on and requests the next music file.

More information about HTTP Range headers and how byte ranges work is available in the Range entry in the Header Field Definitions portion of the HTTP/1.1 specification.

See getMediaURI for details.


Optimizing Files for Streaming

You should optimize all music files for streaming to ensure the best possible experience for users. In particular, for formats like MP4 that don't require that music be placed in a single continuous byte range within the file, you should optimize the files to place as much data as possible contiguously. This reduces seek time within a file and helps to ensure that the next few seconds of music required to smoothly play a file is always waiting within the buffer and available as needed.

While placing as much data as possible in a single continuous stream is the most important consideration, the location of the data within the file can also make a difference to the user experience. Placing the metadata at the front of the file can result in fewer connections before Sonos is actively reading music data. If the metadata is at the front of the file, Sonos may be able to read all of the metadata and move on to music data with a single HTTP GET request. Even if the metadata is too long to do this, Sonos should be able to reconnect and finish reading the metadata with a second request. If the metadata is placed at the end of the file, this same process will likely require three connections: one to determine that the file starts with music data, a second connection to go to the end of the file to get the metadata, and a third connection to return to the front of the file to actually start reading music data. Of course, this is still better than having metadata located somewhere in the middle splitting the data in half or having the data broken up into chunks throughout the file, both of which require repeated seeking.

Another thing you can do to optimize music files is omit the album art from the included metadata (if possible). SMAPI provides alternate methods for sending Sonos album art to display so this content is superfluous. It can also be very large, often upwards of a few megabytes of data. This can sometimes be the difference between being able to seek past metadata in a single file read versus timing out, particularly for users with slower connections or who are fairly distant from the streaming server. If you cannot omit the album art, placing it at the end of the file can be helpful. However, if you are required to place all of the metadata together and have the choice of placing it all at the start or all at the end of the file, it is generally better to place everything at the start of the file even if it does increase the time it takes to get to the initial read of music data.

For example, consider the following three tracks:

Streaming example

The diagrams represent the bytes within each track with the left side representing the start of the file and the right its end. In Track 1, the metadata consumes the first X bytes of the file, then the actual music is written in chunks 1-5 in that order. Because Sonos requests the content of a track from the beginning, it needs to retrieve almost half of the file before it can play any of the music and has to seek repeatedly to play the entire file. Furthermore, the data may not fit into the local buffer and multiple GET requests may be required to play the song instead of using a single request where Sonos gets, buffers, consumes, and releases bytes as they are used in the order obtained. Track 2 is the most optimized option; Sonos skips over the X bytes of the metadata section and begins playing from byte X+1. Track 3 is also reasonably optimized in that the data is contiguous. However, it is not optimized as well as track 2 because Sonos has to recognize the file starts with music data, jump to the end of the file to read the metadata, then jump back to the beginning of the file to start playing music.


Content Delivery Network Considerations

As mentioned above, Sonos requires that your successful streaming responses with partial audio file content return 206 HTTP status codes per the HTTP specification. Some Content Delivery Networks (CDNs) violate the specification and return 200 HTTP status codes instead. You may not use these products with Sonos.

Your CDN should be able to accept and respond to HEAD requests. Sonos players send these requests in some situations to get the Content-Length header. If your CDN doesn’t accept or respond to these requests, users will not be able to seek within a track.

Another consideration when using CDNs is how they request and cache music. There is already a built-in delay when Sonos requests a music file. CDNs can add another layer of delay to the process because the CDN has to get the data being requested if it is not already in its cache. Furthermore, the CDN may start serving data before it has the entire file available. If Sonos has to do any seeking on files being served by CDNs and the CDN does not yet have the necessary data available, the connection will likely time out. Using music files with contiguous data and with the metadata at the start of the file is particularly important if you are using a CDN.

Configuring your CDN appropriately can also make a big difference to the user experience. Since music files rarely change once created, using very long cache refresh times or turning off automatic cache refresh entirely (if supported by your CDN) may help ensure that files are available immediately when requested by Sonos. If your CDN has an option to pre-cache data, doing so will make requests much faster and ensure that the entire file is available as soon as Sonos starts receiving data for a particular track. If that option is not available, setting up caching rules so that the most popular songs remain in the cache as much as possible will also help the user experience. Of course, users with more eclectic taste may still experience some delays, general slowness, or time outs if only popular files are consistently maintained in cache.