A session that plays remotely, potentially across multiple devices.
Conform to this protocol to represent playback happening outside of the current device.
This object is expected to interact with a remote device, and thus may require some
form of remote connection that you set up on initialization.
Your session provides metadata and supported commands, as well as the list of devices playing
in this session. It also handles volume changes and commands targeting the remote session.
> Important: The system may request updates about this session via ``update(_:)``,
where an instance of a `Codable` type your app defines passes into the function.
Your implementation uses the passed ``Attributes`` instance to update the model objects
from your session, which informs the system of any metadata or command changes.
Your app donates remote sessions to the system in two ways: from the main app, or through push notifications.
See ``RemoteMediaSession`` for the in-app API to donate a remote session.
To start, update, or end remote sessions using push notifications, see: <doc:publishing-remote-media-sessions>
The following example shows a basic implementation:
```swift
// A struct representing the current playback information from a remote device.
struct PlayerSnapshot: Codable {
let trackId: String
let title: String
let artist: String
let album: String
let duration: Double
let elapsedTime: Double
let timestamp: Date
let isPlaying: Bool
let playingDevices: [PlayingDevice]
}
struct PlayingDevice: Codable {
let id: String
let name: String
let volume: Float
}
@Observable
class RemotePlayerModel {
var server: ServerConnection
var snapshot: PlayerSnapshot
}
class MySession: RemoteMediaSessionRepresentable {
struct Attributes: RemoteMediaSessionAttributes {
let id: String
var snapshot: PlayerSnapshot
}
let id: String
var remotePlayer: RemotePlayerModel
var devices: [MediaDevice] {
remotePlayer.snapshot.playingDevices.map { device in
MediaDevice(
id: device.id,
name: device.name,
type: .speaker,
capabilities: [
.absoluteVolume(device.volume) { newLevel in
// Communicate with an external server to issue the volume change
try await remotePlayer.server.setVolume(newLevel, forDevice: device.id)
}
]
)
}
}
var content: (any MediaContentRepresentable)? {
let snapshot = remotePlayer.snapshot
return MusicContent(
id: snapshot.trackId,
songTitle: snapshot.title,
artistName: snapshot.artist,
albumName: snapshot.album,
type: .audio,
duration: .finite(snapshot.duration),
artwork: Artwork(id: snapshot.trackId) { size in
let data = await remotePlayer.server.loadArtworkData(for: snapshot.trackId, size: size)
return try ArtworkRepresentation(data: data)
}
)
}
var playbackSnapshot: MediaPlaybackSnapshot {
let snapshot = remotePlayer.snapshot
if snapshot.isPlaying {
return MediaPlaybackSnapshot(
state: .playing(rate: 1.0),
elapsedTime: snapshot.elapsedTime,
timestamp: snapshot.timestamp
)
} else {
return MediaPlaybackSnapshot(
state: .paused,
elapsedTime: snapshot.elapsedTime,
timestamp: snapshot.timestamp
)
}
}
var commands: [MediaCommand] {[
.play {
// Communicate with an external server to issue the command
try await remotePlayer.server.play()
},
.pause {
try await remotePlayer.server.pause()
},
// … more supported commands …
]}
func update(_ attributes: Attributes) {
// Incorporate the incoming attributes into your existing model
remotePlayer.update(with: attributes)
}
// …
}
```
Members (2)
get · iOS 27.0+
pushTokenUpdates
Swift declaration
@MainActor var pushTokenUpdates: AsyncStream<Data> { get }
An asynchronous sequence you use to observe changes to the push token of this remote session.
Monitor this sequence to receive updated push tokens. When the token changes,
transmit the new token securely to your server so the server can continue to send update
and end push notifications for this session. Invalidate the outdated token promptly so it
cannot be reused, and retain the token only as long as needed to deliver session updates.
For additional information, see <doc:publishing-remote-media-sessions>
- Note: Push tokens are device-scoped identifiers. Handle them securely on your
server (for example, over HTTPS) and follow your app's privacy policy for any
data collected alongside them.
get · iOS 27.0+
pushToken
Swift declaration
@MainActor var pushToken: Data? { get }
The token you use to send push notifications to update this remote session.
The push token for a remote session may change over time. Use ``pushTokenUpdates``
to receive the updated push token.
- Note: When you receive an updated push token, transmit it securely to your server
(for example, over HTTPS) and invalidate the outdated token promptly so it cannot
be reused. The push token is a device-scoped identifier — handle it securely and
retain it only as long as needed.