Set playback policies

The player enforces playback policies on cloud queues to determine how users can play individual items or a container consisting of a radio station or a group of items. This enables you to offer programmed radio compliant with a set of standards, such as the Digital Millennium Copyright Act (DMCA). For example, you can set policies that:

  • Limit the number of times a user can skip to the next item
  • Prevent users from skipping an item consisting of an advertisement
  • Limit whether users can shuffle or crossfade items in the queue

There are policies for playback contexts, such as a programmed radio station, and policies for individual items, such as items. The player calculates the policy for the currently playing item by using the policy for the playback context and overriding it with the policy for the individual item if it is different. For example, if the canSeek policy for the context is true and the canSeek policy for an item is false, the canSeek policy for the item overrides the policy for the playback context and prevents the user from seeking within the item.

Use playback policies to enforce rules on your content

Your cloud queue sets playback policies on the player. These policies affect player behavior. For example, to allow a user to jump to a new position (seek) in a track, set the canSeek value to true. To prevent a user from seeking within a track, set the canSeek value to false. Players only load playback policies after processing a loadCloudQueue command. Players ignore any playback policies sent in subsequent GET /context responses until the next loadCloudQueue command.

Players use a default value if you omit a policy from your GET /context response. See Playback Policy List for a complete list of playback policies and their default values.

Use your GET /context response to send playback policies to the player

A user action sends the loadCloudQueue command to a player to start a cloud queue. The player then sends a GET /context request to your service to get the container metadata, reporting options, and playback policies. The player stores the playback policies and sends  GET /itemWindow to request a list of tracks. Here's an example workflow:

To reduce latency, you may want to play the track immediately, to do so provide track metadata and set playOnCompletion to true in the loadCloudQueue command. Here's an example workflow:

In this case, there's a period of time when the player is playing audio but hasn't loaded any playback policies. This is between processing the loadCloudQueue command and receiving your GET /context response. During this period most playback capabilities are disabled. Users can only pause, stop, or change playback until the player processes your GET /context response.

Players periodically send GET /version requests to poll your cloud queue. If the context version changes, the player sends GET /context to update the context.

Provide listeners with a limited ability to skip tracks

When listeners play your content on Sonos they will be able to skip the track currently playing. This could mean skipping to the next track (skipToNextTrack), skipping to the previous track (skipToPreviousTrack), or skipping to a track that is neither the previous or next track (skipToItem). Your service might need to limit the number of times a user can skip to follow a set of standards like the Digital Millenium Copyright Act (DMCA). You can use Sonos playback policies to enforce limits on the number of times a user can skip tracks.

For skipping, the playback policies you want to look at are canSkip, canSkipBack, and canSkipToItem. These policies are true by default. Setting them to false will prevent users from skipping to the next track, the previous track, or another track. But these policies don’t limit skips, they enable or disable the skip capabilities for a container or track.

To limit skips, your service can use the limitedSkips policy. When this policy is true, your service should send the limitedSkipsState object in your GET /itemWindow responses. Players look at the skipLimitReached parameter in this object to find out if the user has reached the skip limit. Players disable skipping capabilities when skipLimitReached is true.

When you set limitedSkips to true, players send GET /itemWindow requests on user actions, such as skipping. Players use the reason parameter in GET /itemWindow requests to report skipping to your service and find out if they should allow this skip. Players wait for your response before playing the next track. Send the skipLimitReached parameter in the limitedSkipsState object in your response.

Note that you can use the notifyUserIntent playback policy to keep track of skips without enforcing skip limits. When you enable this policy, players send GET /itemWindow requests on user actions and wait for your response before playing the next track. Unlike the skipLimits policy, this isn't tied to any skip limiting behavior.

If the user has skips available, return skipLimitReached with a value of false in your response. If the user is out of skips, set skipLimitReached to true to tell the player not to skip the track. You can set skipLimitReached back to false when your service restores skips to this user or account. Here is an example of a limitedSkipsState object:

...
"limitedSkipsState": {
  "skipsRemaining": 2,
  "skipLimitReached": false
 },
...

Sonos reserves the skipsRemaining parameter in the limitedSkipsState object for future use. Even though this value is not exposed to the player, you may find it useful for debugging as you develop this feature.

Use playback policies for individual items to prevent users from skipping advertisements

You can use playback policies for individual items to prevent users from skipping advertisements while still allowing them to skip other content.

For example, a user is listening to a programmed radio station that allows for a limited number of skips. The current song finishes and an advertisement starts playing. The user attempts to skip the advertisement but the player doesn’t allow the skip, even though this user has skips available.

You can instruct the player to deny the skip by setting canSkip and canSkipBack to false for this individual item, even though the container context allows for skipping. Additionally, your service could set the isVisible policy to false for an item to prevent it from appearing in the queue.

When you set playback policies for individual items, they override any values that you set in in the context. We recommend doing this for advertisements, as described above.

Here is an example of a policies object for an advertisement:

 policies : {
    "canSkip": false,
    "canSkipToItem": false,
    "canCrossfade": false,
    "isVisible": false
}

 For this item, we also set the canCrossfade policy to false so that the advertisement won’t crossfade with either the track before or after it.

Understand the errors associated with skip limit enforcement

There are two playback errors that players event when a skip command fails. When players deny a skip because the playback policies don’t allow it, they send the ERROR_DISALLOWED_BY_POLICY. This is the error the player sends in the previous example with the advertisements.

The other playback error that players event when a skip command fails is ERROR_SKIP_LIMIT_REACHED. Players send this error when a user tries to skip but the account has already reached the limit of skips allowed by your service.

Skip enforcement workflow

Here is a sample flow for a cloud queue with a service that allows only one skip:

See Playback Policy List for a complete list of playback policies and their default values.