You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/content/docs/client/music/playback.md
+8-5Lines changed: 8 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,17 +4,21 @@ title: Playback
4
4
5
5
The `IMusicPlayer` interface provides full playback control for music tracks from the device library.
6
6
7
+
On iOS, the player supports two modes that are automatically selected based on the track's properties:
8
+
-**Local playback** via `AVPlayer` when `ContentUri` is available (purchased/synced tracks)
9
+
-**Streaming playback** via `MPMusicPlayerController.SystemMusicPlayer` when `StoreId` is available (Apple Music subscription tracks)
10
+
7
11
## Playing a Track
8
12
9
13
```csharp
10
14
vartracks=await_library.GetAllTracksAsync();
11
15
await_player.PlayAsync(tracks[0]);
12
16
```
13
17
14
-
Calling `PlayAsync` stops any currently playing track, loads the new one, and begins playback immediately.
18
+
Calling `PlayAsync` stops any currently playing track, loads the new one, and begins playback immediately. The player automatically selects the appropriate playback engine based on whether `StoreId` or `ContentUri` is available.
15
19
16
20
:::caution
17
-
`PlayAsync` will throw an `InvalidOperationException` if the track's `ContentUri`is empty (DRM-protected on iOS) or if the platform player fails to initialize. Always check `ContentUri` before playing.
21
+
`PlayAsync` will throw an `InvalidOperationException` if both `ContentUri`and `StoreId` are empty, or if the platform player fails to initialize.
18
22
:::
19
23
20
24
## Pause, Resume, and Stop
@@ -98,9 +102,8 @@ If you register the player as a singleton in DI, it will be disposed when the ap
98
102
- Seeking uses millisecond precision.
99
103
100
104
### iOS
101
-
- Playback uses `AVFoundation.AVAudioPlayer` with the track's `ipod-library://` asset URL.
102
-
- The `AVAudioSession` category is set to `Playback` to support background audio (if configured).
103
-
- Seeking uses second precision.
105
+
-**Local tracks** (with `ContentUri`): Playback uses `AVPlayer` with the track's `ipod-library://` asset URL. The `AVAudioSession` category is set to `Playback` to support background audio (if configured). Seeking uses second precision.
106
+
-**Streaming tracks** (with `StoreId`): Playback uses `MPMusicPlayerController.SystemMusicPlayer` with the Apple Music catalog ID. This enables playback of DRM-protected Apple Music subscription content. The system player manages its own audio session.
104
107
105
108
:::note
106
109
Music library access requires a **physical device**. Simulators and emulators typically have no music content and cannot test playback.
Copy file name to clipboardExpand all lines: src/content/docs/client/music/querying.md
+17-12Lines changed: 17 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -39,40 +39,45 @@ Each track is represented by a `MusicMetadata` record with the following propert
39
39
| Property | Type | Description |
40
40
|---|---|---|
41
41
|`Id`|`string`| Platform-specific unique identifier. On Android, this is the MediaStore row ID. On iOS, it is the `MPMediaItem` persistent ID. |
42
-
|`Title`|`string`| The track title. |
43
-
|`Artist`|`string`| The artist or performer. |
44
-
|`Album`|`string`| The album name. |
42
+
|`Title`|`string?`| The track title, or `null` if not available. |
43
+
|`Artist`|`string?`| The artist or performer, or `null` if not available. |
44
+
|`Album`|`string?`| The album name, or `null` if not available. |
45
45
|`Genre`|`string?`| The genre, or `null` if unavailable. |
46
46
|`Duration`|`TimeSpan`| The playback duration. |
47
47
|`AlbumArtUri`|`string?`| URI to album artwork. Available on Android via MediaStore; `null` on iOS where artwork is accessed through `MPMediaItem.Artwork`. |
48
48
|`IsExplicit`|`bool?`| Whether the track is marked as explicit content. iOS only via `MPMediaItem.IsExplicitItem`; always `null` on Android. |
49
49
|`ContentUri`|`string`| URI used for playback and file operations. On Android, this is a `content://` URI. On iOS, this is an `ipod-library://` asset URL. **Empty for DRM-protected Apple Music subscription tracks.**|
50
+
|`StoreId`|`string?`| Apple Music catalog ID (from `PlayParams.Id`). Enables streaming playback via `MPMusicPlayerController` on iOS. Always `null` on Android. |
50
51
51
-
## ContentUri and DRM
52
+
## ContentUri, StoreId, and DRM
52
53
53
-
The `ContentUri`property is critical for understanding what operations are available for a track:
54
+
The `ContentUri`and `StoreId` properties determine what operations are available for a track:
// Locally synced or purchased track — full access
64
+
Console.WriteLine($"✅ {track.Title} - available for local playback and copy");
65
+
}
66
+
elseif (!string.IsNullOrEmpty(track.StoreId))
67
+
{
68
+
// Apple Music subscription track with catalog ID — streaming playback only
69
+
Console.WriteLine($"🎧 {track.Title} - available for streaming playback (no copy)");
65
70
}
66
71
else
67
72
{
68
-
//Locally synced or purchased track — full access
69
-
Console.WriteLine($"✅ {track.Title} - available for playback and copy");
73
+
//No playback or copy available
74
+
Console.WriteLine($"⚠️ {track.Title} - not playable or copyable");
70
75
}
71
76
}
72
77
```
73
78
74
79
:::note
75
-
On Android, `ContentUri` is always populated for all music files. The DRM limitation only applies to iOS Apple Music subscription tracks.
80
+
On Android, `ContentUri` is always populated for all music files. `StoreId` is always `null` on Android. The DRM and streaming distinction only applies to iOS Apple Music subscription tracks.
Copy file name to clipboardExpand all lines: src/content/docs/client/music/release-notes.mdx
+5-2Lines changed: 5 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,7 +13,10 @@ import RN from '/src/components/ReleaseNote.astro';
13
13
<RNtype="feature">Audio playback — play, pause, resume, and stop music files with state change and completion events</RN>
14
14
<RNtype="feature">File copying — copy music files to app-local storage (where DRM permits)</RN>
15
15
<RNtype="feature">Dependency injection — `AddShinyMusic()` extension method for `IServiceCollection` registration</RN>
16
+
<RNtype="feature">`HasStreamingSubscriptionAsync()` — check for active Apple Music subscription capability on iOS</RN>
17
+
<RNtype="feature">`StoreId` property on `MusicMetadata` — Apple Music catalog ID enabling streaming playback of subscription content</RN>
16
18
<RNtype="feature"platform="Android">Android implementation using `MediaStore.Audio.Media` and `Android.Media.MediaPlayer`</RN>
17
-
<RNtype="feature"platform="iOS">iOS implementation using `MPMediaQuery` and `AVFoundation.AVAudioPlayer`</RN>
18
-
<RNtype="feature"platform="iOS">DRM-aware — `ContentUri` is empty for Apple Music subscription tracks that cannot be played or copied</RN>
19
+
<RNtype="feature"platform="iOS">iOS implementation using `MPMediaQuery` and `AVPlayer`</RN>
20
+
<RNtype="feature"platform="iOS">Streaming playback of Apple Music subscription tracks via `MPMusicPlayerController.SystemMusicPlayer` using `StoreId`</RN>
21
+
<RNtype="feature"platform="iOS">DRM-aware — `ContentUri` is empty for Apple Music subscription tracks that cannot be copied, but streaming playback is available via `StoreId`</RN>
19
22
<RNtype="feature"platform="iOS">`IsExplicit` property on `MusicMetadata` — reports whether a track is marked as explicit content via `MPMediaItem.IsExplicitItem`</RN>
0 commit comments