capacitor-plugin-playlist 0.10.3 → 0.10.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1133 -137
- package/android/src/main/java/org/dwbn/plugins/playlist/PlaylistPlugin.kt +7 -3
- package/android/src/main/java/org/dwbn/plugins/playlist/RmxAudioPlayer.java +20 -5
- package/android/src/main/java/org/dwbn/plugins/playlist/playlist/AudioPlaylistHandler.java +10 -11
- package/dist/docs.json +66 -33
- package/dist/esm/definitions.d.ts +119 -7
- package/dist/esm/web.d.ts +3 -1
- package/dist/esm/web.js +1 -1
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +1 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +1 -1
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/PlaylistPlugin/Plugin.swift +6 -2
- package/ios/Sources/PlaylistPlugin/RmxAudioPlayer.swift +55 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,104 +1,155 @@
|
|
|
1
1
|
# capacitor-plugin-playlist
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Capacitor plugin for **Android**, **iOS**, and **Web** with native audio playlist playback, background support, lock-screen / notification controls, and video handoff.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Requires **Capacitor 8+** (peer dependency `@capacitor/core >= 8.0.0`).
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Index
|
|
8
8
|
|
|
9
|
-
1. [
|
|
10
|
-
2. [
|
|
11
|
-
3. [
|
|
12
|
-
4. [
|
|
13
|
-
5. [
|
|
14
|
-
6. [
|
|
15
|
-
7. [
|
|
9
|
+
1. [Features](#features)
|
|
10
|
+
2. [Background](#background)
|
|
11
|
+
3. [Notes](#notes)
|
|
12
|
+
4. [Installation](#installation)
|
|
13
|
+
5. [Usage](#usage)
|
|
14
|
+
6. [Events](#events)
|
|
15
|
+
7. [Video handoff](#video-handoff)
|
|
16
|
+
8. [API](#api)
|
|
17
|
+
9. [Migrating from cordova-plugin-playlist](#migrating-from-cordova-plugin-playlist)
|
|
18
|
+
10. [Changes](#changes)
|
|
19
|
+
11. [Credits](#credits)
|
|
20
|
+
12. [License](#license)
|
|
16
21
|
|
|
17
|
-
##
|
|
22
|
+
## Features
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
Due to upgrades and further development of the app, which used the plugin we decided to go for capacitor instead of
|
|
21
|
-
cordova, and here we wanna give back to the community our outcome, any help is appreciated!
|
|
24
|
+
### Playlist management
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
- `setPlaylistItems` — replace entire playlist (optional position retention)
|
|
27
|
+
- `addItem` / `addAllItems` — append tracks
|
|
28
|
+
- `removeItem` / `removeItems` / `clearAllItems` — remove tracks
|
|
29
|
+
- `getPlaylist` — snapshot of current items
|
|
30
|
+
- `setLoop` — loop entire playlist when the last track completes
|
|
24
31
|
|
|
25
|
-
###
|
|
32
|
+
### Playback controls
|
|
26
33
|
|
|
27
|
-
|
|
34
|
+
- `play` / `pause`
|
|
35
|
+
- `skipForward` / `skipBack`
|
|
36
|
+
- `seekTo` (seconds)
|
|
37
|
+
- `playTrackByIndex` / `playTrackById` — jump and play
|
|
38
|
+
- `selectTrackByIndex` / `selectTrackById` — select without playing
|
|
39
|
+
- `setPlaybackVolume` (0–1)
|
|
40
|
+
- `setPlaybackRate` (0 pauses, 1 = normal speed)
|
|
28
41
|
|
|
29
|
-
|
|
42
|
+
### Native platform integration
|
|
30
43
|
|
|
31
|
-
|
|
44
|
+
| Platform | Engine | OS controls |
|
|
45
|
+
|----------|--------|-------------|
|
|
46
|
+
| Android | [ExoMedia](https://github.com/brianwernick/ExoMedia) + [PlaylistCore](https://github.com/brianwernick/PlaylistCore) | MediaStyle notification, MediaSession, foreground `mediaPlayback` service |
|
|
47
|
+
| iOS | Custom `AVBidirectionalQueuePlayer` | Lock screen + Control Center via `MPNowPlayingInfoCenter` / `MPRemoteCommandCenter` |
|
|
48
|
+
| Web | HTMLAudioElement + optional HLS.js | Browser media controls only |
|
|
32
49
|
|
|
33
|
-
|
|
50
|
+
### Background audio
|
|
34
51
|
|
|
35
|
-
|
|
52
|
+
- Android: foreground media service with `WAKE_LOCK` and `FOREGROUND_SERVICE_MEDIA_PLAYBACK` (Android 14+)
|
|
53
|
+
- iOS: `UIBackgroundModes` → `audio`
|
|
54
|
+
- Position events throttled while WebView is backgrounded; one live snapshot emitted on foreground resume (0.9.1+)
|
|
55
|
+
|
|
56
|
+
### Tracks and sources
|
|
57
|
+
|
|
58
|
+
- Remote URLs, local files (`file://` or app-resolved paths), and streams
|
|
59
|
+
- Set `isStream: true` on streaming URLs so pause/resume buffering behaves correctly
|
|
60
|
+
- `albumArt` shown in notification / lock screen (Glide on Android)
|
|
61
|
+
- No built-in download manager — resolve offline paths in your app and pass them as `assetUrl`
|
|
62
|
+
|
|
63
|
+
### Status event stream
|
|
64
|
+
|
|
65
|
+
Single `status` listener with `RmxAudioStatusMessage` events (see [Events](#events)).
|
|
66
|
+
|
|
67
|
+
### Video handoff
|
|
68
|
+
|
|
69
|
+
When switching from background audio to native fullscreen video:
|
|
70
|
+
|
|
71
|
+
- `prepareForVideoHandoff()` — release audio focus / session
|
|
72
|
+
- `getLastKnownPosition()` — saved head position (seconds)
|
|
73
|
+
- `resumeAfterVideoHandoff({ position, prewarm? })` — re-arm audio after video
|
|
74
|
+
|
|
75
|
+
See [Video handoff](#video-handoff).
|
|
76
|
+
|
|
77
|
+
### Cordova-compatible wrapper
|
|
78
|
+
|
|
79
|
+
`RmxAudioPlayer` (`src/RmxAudioPlayer.ts`) is a drop-in replacement for cordova-plugin-playlist with `on('status')` / `off('status')` and state getters (`isPlaying`, `currentTrack`, etc.).
|
|
80
|
+
|
|
81
|
+
**Not exposed on `RmxAudioPlayer`:** `getPlaylist`, video handoff methods — call `Playlist` directly for those.
|
|
82
|
+
|
|
83
|
+
### Not supported
|
|
84
|
+
|
|
85
|
+
- Shuffle
|
|
86
|
+
- Reorder API
|
|
87
|
+
- Mixable / low-latency game audio (use [cordova-plugin-nativeaudio](https://github.com/floatinghotpot/cordova-plugin-nativeaudio) instead)
|
|
88
|
+
- Simultaneous audio mixing (lock-screen controls require exclusive audio focus)
|
|
89
|
+
|
|
90
|
+
## Background
|
|
91
|
+
|
|
92
|
+
Forked from [cordova-plugin-playlist](https://github.com/Rolamix/cordova-plugin-playlist) for Capacitor.
|
|
93
|
+
|
|
94
|
+
## Notes
|
|
95
|
+
|
|
96
|
+
### Android
|
|
97
|
+
|
|
98
|
+
Uses ExoMedia (ExoPlayer wrapper) with PlaylistCore for notification and MediaSession integration.
|
|
99
|
+
|
|
100
|
+
### iOS
|
|
101
|
+
|
|
102
|
+
Uses a customized AVQueuePlayer (`AVBidirectionalQueuePlayer`) for track-change feedback and continuous audio session between songs. Minimum iOS **18** (0.9.4+). Swift Package Manager supported (0.10.0+).
|
|
103
|
+
|
|
104
|
+
## Installation
|
|
36
105
|
|
|
37
106
|
```
|
|
38
107
|
npm i capacitor-plugin-playlist
|
|
39
108
|
npx cap sync
|
|
40
109
|
```
|
|
41
110
|
|
|
42
|
-
###
|
|
111
|
+
### Web
|
|
43
112
|
|
|
44
|
-
|
|
113
|
+
Include HLS.js in your build for HLS streams.
|
|
45
114
|
|
|
46
|
-
####
|
|
115
|
+
#### Angular example
|
|
47
116
|
|
|
48
117
|
```
|
|
49
118
|
npm i hls.js
|
|
50
119
|
```
|
|
51
120
|
|
|
52
|
-
|
|
53
|
-
architect => build => options:
|
|
121
|
+
Add to `angular.json` → architect → build → options → scripts:
|
|
54
122
|
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
123
|
+
```json
|
|
124
|
+
"scripts": [
|
|
125
|
+
{
|
|
126
|
+
"input": "node_modules/hls.js/dist/hls.min.js"
|
|
127
|
+
}
|
|
128
|
+
]
|
|
61
129
|
```
|
|
62
130
|
|
|
63
|
-
|
|
131
|
+
### Android
|
|
64
132
|
|
|
65
|
-
|
|
66
|
-
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
67
|
-
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
68
|
-
<application
|
|
69
|
-
android:name="org.dwbn.plugins.playlist.App"
|
|
70
|
-
>
|
|
71
|
-
<service android:enabled="true" android:exported="false"
|
|
72
|
-
android:name="org.dwbn.plugins.playlist.service.MediaService">
|
|
73
|
-
</service>
|
|
74
|
-
</application>
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
**Note**: Starting with Android 14, you now need to specify the `foregroundServiceType` and request the appropriate permission:
|
|
133
|
+
#### AndroidManifest.xml
|
|
78
134
|
|
|
135
|
+
```xml
|
|
136
|
+
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
137
|
+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
|
|
138
|
+
<application android:name="org.dwbn.plugins.playlist.App">
|
|
139
|
+
<service android:enabled="true" android:exported="false"
|
|
140
|
+
android:foregroundServiceType="mediaPlayback"
|
|
141
|
+
android:name="org.dwbn.plugins.playlist.service.MediaService">
|
|
142
|
+
</service>
|
|
143
|
+
</application>
|
|
79
144
|
```
|
|
80
|
-
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
81
|
-
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
|
|
82
|
-
<application
|
|
83
|
-
android:name="org.dwbn.plugins.playlist.App"
|
|
84
|
-
>
|
|
85
|
-
<service android:enabled="true" android:exported="false"
|
|
86
|
-
android:foregroundServiceType="mediaPlayback"
|
|
87
|
-
android:name="org.dwbn.plugins.playlist.service.MediaService">
|
|
88
|
-
</service>
|
|
89
|
-
</application>
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
##### Gradle Configuration (Gradle 9+)
|
|
93
145
|
|
|
94
|
-
|
|
146
|
+
#### Gradle 9+
|
|
95
147
|
|
|
96
|
-
|
|
148
|
+
Ensure the Kotlin plugin is declared in your root `android/build.gradle` (this plugin no longer ships its own `buildscript` block):
|
|
97
149
|
|
|
98
150
|
```gradle
|
|
99
151
|
buildscript {
|
|
100
|
-
ext.kotlin_version = '2.3.0'
|
|
101
|
-
|
|
152
|
+
ext.kotlin_version = '2.3.0'
|
|
102
153
|
repositories {
|
|
103
154
|
google()
|
|
104
155
|
mavenCentral()
|
|
@@ -106,22 +157,18 @@ buildscript {
|
|
|
106
157
|
dependencies {
|
|
107
158
|
classpath 'com.android.tools.build:gradle:8.13.2'
|
|
108
159
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
109
|
-
// ... other dependencies
|
|
110
160
|
}
|
|
111
161
|
}
|
|
112
|
-
|
|
113
162
|
ext {
|
|
114
|
-
kotlin_version = '2.3.0'
|
|
163
|
+
kotlin_version = '2.3.0'
|
|
115
164
|
}
|
|
116
165
|
```
|
|
117
166
|
|
|
118
|
-
|
|
167
|
+
#### Glide (notification album art)
|
|
119
168
|
|
|
120
|
-
|
|
169
|
+
Create `MyAppGlideModule.java`:
|
|
121
170
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
```
|
|
171
|
+
```java
|
|
125
172
|
package org.your.package.namespace;
|
|
126
173
|
|
|
127
174
|
import com.bumptech.glide.annotation.GlideModule;
|
|
@@ -131,113 +178,1062 @@ import com.bumptech.glide.module.AppGlideModule;
|
|
|
131
178
|
public final class MyAppGlideModule extends AppGlideModule {}
|
|
132
179
|
```
|
|
133
180
|
|
|
134
|
-
|
|
181
|
+
See https://guides.codepath.com/android/Displaying-Images-with-the-Glide-Library
|
|
182
|
+
|
|
183
|
+
#### Notification icon
|
|
184
|
+
|
|
185
|
+
Create a transparent silhouette icon (e.g. `ic_notification.png`) and pass it via `setOptions`:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
await Playlist.setOptions({
|
|
189
|
+
verbose: !environment.production,
|
|
190
|
+
options: { icon: 'ic_notification' },
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
In Android Studio: right-click `res` → New → Image Asset → Notification Icons.
|
|
195
|
+
|
|
196
|
+

|
|
197
|
+
|
|
198
|
+

|
|
135
199
|
|
|
136
200
|
### iOS
|
|
137
201
|
|
|
138
|
-
|
|
202
|
+
Add to `Info.plist`:
|
|
203
|
+
|
|
204
|
+
```xml
|
|
205
|
+
<key>UIBackgroundModes</key>
|
|
206
|
+
<array>
|
|
207
|
+
<string>audio</string>
|
|
208
|
+
<string>fetch</string>
|
|
209
|
+
</array>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Without `audio` background mode, iOS stops playback when the app backgrounds.
|
|
213
|
+
|
|
214
|
+
## Usage
|
|
215
|
+
|
|
216
|
+
See also `examples/audio-provider.ts` for an Angular/Ionic integration.
|
|
217
|
+
|
|
218
|
+
### Basic flow (`Playlist` API)
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { Playlist, AudioTrack, RmxAudioStatusMessage } from 'capacitor-plugin-playlist';
|
|
222
|
+
|
|
223
|
+
await Playlist.setOptions({
|
|
224
|
+
verbose: true,
|
|
225
|
+
resetStreamOnPause: true,
|
|
226
|
+
options: { icon: 'ic_notification' },
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
await Playlist.initialize();
|
|
139
230
|
|
|
231
|
+
const handle = await Playlist.addListener('status', ({ status }) => {
|
|
232
|
+
if (status.msgType === RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION) {
|
|
233
|
+
// update UI progress
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const track: AudioTrack = {
|
|
238
|
+
trackId: 'track-1',
|
|
239
|
+
assetUrl: 'https://example.com/audio.mp3',
|
|
240
|
+
title: 'Track title',
|
|
241
|
+
artist: 'Artist name',
|
|
242
|
+
album: 'Album name',
|
|
243
|
+
albumArt: 'https://example.com/cover.jpg',
|
|
244
|
+
isStream: false,
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
await Playlist.setPlaylistItems({
|
|
248
|
+
items: [track],
|
|
249
|
+
options: { startPaused: false },
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
await Playlist.play();
|
|
253
|
+
// later: handle.remove();
|
|
140
254
|
```
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
255
|
+
|
|
256
|
+
### `RmxAudioPlayer` wrapper (Cordova migration)
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import { RmxAudioPlayer, AudioTrack } from 'capacitor-plugin-playlist';
|
|
260
|
+
|
|
261
|
+
const player = new RmxAudioPlayer();
|
|
262
|
+
await player.initialize();
|
|
263
|
+
|
|
264
|
+
player.on('status', (data) => {
|
|
265
|
+
console.log('status', data.msgType, data);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
await player.setLoop(true);
|
|
269
|
+
await player.setPlaylistItems([track], { retainPosition: true, playFromId: track.trackId });
|
|
270
|
+
await player.play();
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Events
|
|
274
|
+
|
|
275
|
+
Subscribe via `Playlist.addListener('status', …)` or `RmxAudioPlayer.on('status', …)`.
|
|
276
|
+
|
|
277
|
+
Each callback receives `{ action: 'status', status: OnStatusCallbackData }` where:
|
|
278
|
+
|
|
279
|
+
- `status.trackId` — current track id, `"NONE"` when idle, `"INVALID"` when playlist completed
|
|
280
|
+
- `status.msgType` — `RmxAudioStatusMessage` enum value
|
|
281
|
+
- `status.value` — payload (shape depends on `msgType`)
|
|
282
|
+
|
|
283
|
+
| msgType | Name | When | Payload |
|
|
284
|
+
|---------|------|------|---------|
|
|
285
|
+
| 5 | ERROR | Playback or network failure | `OnStatusErrorCallbackData` (`code`, `message`) |
|
|
286
|
+
| 10 | LOADING | Track loading started | `OnStatusCallbackUpdateData` |
|
|
287
|
+
| 11 | CANPLAY | Track ready to play | `OnStatusCallbackUpdateData` |
|
|
288
|
+
| 15 | LOADED | Track fully loaded | `OnStatusCallbackUpdateData` |
|
|
289
|
+
| 20 | STALLED | iOS: network stall | `OnStatusCallbackUpdateData` |
|
|
290
|
+
| 25 | BUFFERING | Buffer progress update | `OnStatusCallbackUpdateData` |
|
|
291
|
+
| 30 | PLAYING | Playback started/resumed | `OnStatusCallbackUpdateData` |
|
|
292
|
+
| 35 | PAUSE | Playback paused | `OnStatusCallbackUpdateData` |
|
|
293
|
+
| 40 | PLAYBACK_POSITION | Periodic position tick | `OnStatusCallbackUpdateData` (suppressed while WebView backgrounded) |
|
|
294
|
+
| 45 | SEEK | User or app seeked | `OnStatusCallbackUpdateData` |
|
|
295
|
+
| 50 | COMPLETED | Current track finished | `OnStatusCallbackUpdateData` |
|
|
296
|
+
| 55 | DURATION | Duration first known | `OnStatusCallbackUpdateData` |
|
|
297
|
+
| 60 | STOPPED | All playback stopped | `OnStatusCallbackUpdateData` |
|
|
298
|
+
| 90 | SKIP_FORWARD | Skipped to next track | `OnStatusCallbackUpdateData` |
|
|
299
|
+
| 95 | SKIP_BACK | Skipped to previous track | `OnStatusCallbackUpdateData` |
|
|
300
|
+
| 100 | TRACK_CHANGED | Active track changed | `OnStatusTrackChangedData` |
|
|
301
|
+
| 105 | PLAYLIST_COMPLETED | Entire playlist finished | `OnStatusCallbackUpdateData` |
|
|
302
|
+
| 110 | ITEM_ADDED | Track added | `OnStatusCallbackUpdateData` |
|
|
303
|
+
| 115 | ITEM_REMOVED | Track removed | `OnStatusCallbackUpdateData` |
|
|
304
|
+
| 120 | PLAYLIST_CLEARED | All tracks removed | `OnStatusCallbackUpdateData` |
|
|
305
|
+
|
|
306
|
+
For track changes, prefer handling `TRACK_CHANGED` over `SKIP_FORWARD` / `SKIP_BACK`.
|
|
307
|
+
|
|
308
|
+
## Video handoff
|
|
309
|
+
|
|
310
|
+
Native audio and native fullscreen video cannot share audio focus. These three methods coordinate a clean handoff when the user opens video while audio was playing (or when switching back to audio after video).
|
|
311
|
+
|
|
312
|
+
Works with any native Capacitor video plugin (or other player) that needs exclusive audio focus.
|
|
313
|
+
|
|
314
|
+
### Methods
|
|
315
|
+
|
|
316
|
+
| Method | Purpose |
|
|
317
|
+
|--------|---------|
|
|
318
|
+
| `prepareForVideoHandoff()` | Pause audio, capture head position, release audio focus / session |
|
|
319
|
+
| `getLastKnownPosition()` | Read captured position (seconds) after prepare |
|
|
320
|
+
| `resumeAfterVideoHandoff({ position, prewarm? })` | Re-arm audio after video, or prewarm Android FGS before video |
|
|
321
|
+
|
|
322
|
+
Call these on the `Playlist` plugin directly — they are **not** exposed on `RmxAudioPlayer`.
|
|
323
|
+
|
|
324
|
+
### Lifecycle
|
|
325
|
+
|
|
326
|
+
```mermaid
|
|
327
|
+
sequenceDiagram
|
|
328
|
+
participant App
|
|
329
|
+
participant Playlist
|
|
330
|
+
participant VideoPlayer
|
|
331
|
+
|
|
332
|
+
Note over App,VideoPlayer: Entering video
|
|
333
|
+
App->>Playlist: prepareForVideoHandoff()
|
|
334
|
+
Playlist-->>App: audio paused, focus released
|
|
335
|
+
App->>Playlist: getLastKnownPosition() optional
|
|
336
|
+
App->>Playlist: resumeAfterVideoHandoff position prewarm true
|
|
337
|
+
Note over Playlist: Android only silent FGS prewarm
|
|
338
|
+
App->>VideoPlayer: initPlayer
|
|
339
|
+
VideoPlayer-->>App: video playing
|
|
340
|
+
|
|
341
|
+
Note over App,VideoPlayer: Exiting video
|
|
342
|
+
App->>Playlist: resumeAfterVideoHandoff position
|
|
343
|
+
Note over Playlist: re-arm session no prewarm
|
|
344
|
+
App->>Playlist: play optional
|
|
345
|
+
Playlist-->>App: audio resumes
|
|
146
346
|
```
|
|
147
347
|
|
|
148
|
-
|
|
348
|
+
### Basic sequence
|
|
149
349
|
|
|
150
|
-
|
|
350
|
+
```typescript
|
|
351
|
+
import { Playlist } from 'capacitor-plugin-playlist';
|
|
151
352
|
|
|
152
|
-
|
|
353
|
+
// --- Entering native video ---
|
|
354
|
+
await Playlist.prepareForVideoHandoff();
|
|
355
|
+
const { position: audioPosition } = await Playlist.getLastKnownPosition();
|
|
153
356
|
|
|
154
|
-
|
|
155
|
-
Then you can use the options like:
|
|
357
|
+
await nativeVideoPlayer.init({ /* url, fullscreen, … */ });
|
|
156
358
|
|
|
359
|
+
// --- Exiting native video (use video head, not audioPosition) ---
|
|
360
|
+
const videoPosition = 120; // from your video player's position events
|
|
361
|
+
await Playlist.resumeAfterVideoHandoff({ position: videoPosition });
|
|
362
|
+
await Playlist.play(); // if user should resume audible playback
|
|
157
363
|
```
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
364
|
+
|
|
365
|
+
### Recommended Android sequence (with prewarm)
|
|
366
|
+
|
|
367
|
+
On Android 14+ (especially Android 17), starting or re-promoting the media foreground service from the background can fail or mute playback. **Prewarm while the app is still visible** before video starts:
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
// 1. Release audio focus
|
|
371
|
+
await Playlist.prepareForVideoHandoff();
|
|
372
|
+
|
|
373
|
+
// 2. Prewarm FGS silently at the video start position (Android)
|
|
374
|
+
await Playlist.resumeAfterVideoHandoff({
|
|
375
|
+
position: Math.floor(videoStartSec),
|
|
376
|
+
prewarm: true,
|
|
163
377
|
});
|
|
378
|
+
|
|
379
|
+
// 3. Start native video
|
|
380
|
+
await nativeVideoPlayer.init({ /* … */ });
|
|
381
|
+
|
|
382
|
+
// … user watches video; track video position via player events …
|
|
383
|
+
|
|
384
|
+
// 4. After video closes — re-arm without prewarm
|
|
385
|
+
await Playlist.resumeAfterVideoHandoff({ position: Math.floor(videoExitSec) });
|
|
386
|
+
await Playlist.play(); // when ready
|
|
164
387
|
```
|
|
165
388
|
|
|
166
|
-
|
|
389
|
+
**What `prewarm: true` does on Android:**
|
|
390
|
+
|
|
391
|
+
- Promotes `MediaService` to foreground (`mediaPlayback` FGS) while the app is foregrounded
|
|
392
|
+
- Prepares the playlist item at `position` but stays **silent** — no audio focus request, no audible playback
|
|
393
|
+
- Prevents video sound from dropping when audio would otherwise re-request focus
|
|
394
|
+
- During prewarm, `Playlist.play()` is a no-op for audible playback (only keeps FGS notification updated)
|
|
395
|
+
|
|
396
|
+
**iOS:** `prewarm` is accepted but ignored. Use `prepareForVideoHandoff()` → video → `resumeAfterVideoHandoff({ position })` → `play()`.
|
|
397
|
+
|
|
398
|
+
**Web:** Both methods are stubs (pause + store position). No native session handoff.
|
|
399
|
+
|
|
400
|
+
### Platform behaviour
|
|
401
|
+
|
|
402
|
+
| Step | Android | iOS | Web |
|
|
403
|
+
|------|---------|-----|-----|
|
|
404
|
+
| `prepareForVideoHandoff` | Pause, abandon audio focus, store position via `MediaProgress` | Pause, store track time, `AVAudioSession.setActive(false)` | Pause HTMLAudioElement, store `currentTime` |
|
|
405
|
+
| `getLastKnownPosition` | Returns stored handoff position (seconds) | Same | Same |
|
|
406
|
+
| `resumeAfterVideoHandoff` (no prewarm) | Re-request focus; in-place resume if FGS still foreground from prewarm, else `beginPlayback` | Reactivate audio session; reset track-id guard for PLAYING events | Store position only |
|
|
407
|
+
| `resumeAfterVideoHandoff` (prewarm) | Silent FGS + prepare at position, no focus/play | No-op | N/A |
|
|
408
|
+
| After resume | Call `play()` to start audible playback | Call `play()` to start audible playback | Call `play()` on web player |
|
|
409
|
+
|
|
410
|
+
### Position: audio vs video head
|
|
411
|
+
|
|
412
|
+
- **`getLastKnownPosition()`** after `prepareForVideoHandoff` — last **audio** head before video opened. Useful if video never started or for debugging.
|
|
413
|
+
- **On video exit** — pass the **video** playback position (from your video player's position events), not the stale audio position, so audio resumes where the user left off in the video timeline.
|
|
414
|
+
- Track video head while video plays and persist it if the app may cold-start (e.g. after PiP dismiss on Android).
|
|
415
|
+
|
|
416
|
+
### Integration checklist
|
|
417
|
+
|
|
418
|
+
1. Call `prepareForVideoHandoff()` **immediately before** your native video player starts — never after.
|
|
419
|
+
2. On Android, call `resumeAfterVideoHandoff({ position, prewarm: true })` **after prepare and before video init**, while the WebView is still foregrounded.
|
|
420
|
+
3. On video exit, call `resumeAfterVideoHandoff({ position })` **without** `prewarm`, then `play()` if playback should resume.
|
|
421
|
+
4. `resumeAfterVideoHandoff` must complete before `seekTo()` / `play()` on the audio side.
|
|
422
|
+
5. Do not call `Playlist.release()` between prepare and resume unless you intend to tear down the native player entirely.
|
|
423
|
+
6. Idempotent exit handling: guard against duplicate `resumeAfterVideoHandoff` calls from concurrent native exit events (merge to a single call with `max(position)`).
|
|
424
|
+
|
|
425
|
+
### Common pitfalls
|
|
426
|
+
|
|
427
|
+
| Symptom | Likely cause |
|
|
428
|
+
|---------|----------------|
|
|
429
|
+
| Video has no sound shortly after start | Audio re-requested focus after prepare; use Android `prewarm: true` before video starts |
|
|
430
|
+
| Audio silent after long video session | FGS stopped while backgrounded; prewarm before video + in-place resume on exit (0.8.10+) |
|
|
431
|
+
| JS stuck in PAUSED after video (iOS, index > 0) | Missing `play()` after resume, or PLAYING event suppressed — fixed in 0.8.11 |
|
|
432
|
+
| `PLAYBACK_POSITION` flood after background | Expected — position events suppressed while WebView backgrounded (0.9.1+) |
|
|
433
|
+
|
|
434
|
+
See [CHANGELOG.md](./CHANGELOG.md) for version-specific fixes (0.8.8–0.10.3).
|
|
435
|
+
|
|
436
|
+
## API
|
|
437
|
+
|
|
438
|
+
<docgen-index>
|
|
439
|
+
|
|
440
|
+
* [`addListener('status', ...)`](#addlistenerstatus-)
|
|
441
|
+
* [`setOptions(...)`](#setoptions)
|
|
442
|
+
* [`initialize()`](#initialize)
|
|
443
|
+
* [`release()`](#release)
|
|
444
|
+
* [`setPlaylistItems(...)`](#setplaylistitems)
|
|
445
|
+
* [`addItem(...)`](#additem)
|
|
446
|
+
* [`addAllItems(...)`](#addallitems)
|
|
447
|
+
* [`removeItem(...)`](#removeitem)
|
|
448
|
+
* [`removeItems(...)`](#removeitems)
|
|
449
|
+
* [`clearAllItems()`](#clearallitems)
|
|
450
|
+
* [`getPlaylist()`](#getplaylist)
|
|
451
|
+
* [`play()`](#play)
|
|
452
|
+
* [`pause()`](#pause)
|
|
453
|
+
* [`skipForward()`](#skipforward)
|
|
454
|
+
* [`skipBack()`](#skipback)
|
|
455
|
+
* [`seekTo(...)`](#seekto)
|
|
456
|
+
* [`playTrackByIndex(...)`](#playtrackbyindex)
|
|
457
|
+
* [`playTrackById(...)`](#playtrackbyid)
|
|
458
|
+
* [`selectTrackByIndex(...)`](#selecttrackbyindex)
|
|
459
|
+
* [`selectTrackById(...)`](#selecttrackbyid)
|
|
460
|
+
* [`setPlaybackVolume(...)`](#setplaybackvolume)
|
|
461
|
+
* [`setLoop(...)`](#setloop)
|
|
462
|
+
* [`setPlaybackRate(...)`](#setplaybackrate)
|
|
463
|
+
* [`prepareForVideoHandoff()`](#prepareforvideohandoff)
|
|
464
|
+
* [`resumeAfterVideoHandoff(...)`](#resumeaftervideohandoff)
|
|
465
|
+
* [`getLastKnownPosition()`](#getlastknownposition)
|
|
466
|
+
* [Interfaces](#interfaces)
|
|
467
|
+
* [Type Aliases](#type-aliases)
|
|
468
|
+
* [Enums](#enums)
|
|
469
|
+
|
|
470
|
+
</docgen-index>
|
|
471
|
+
|
|
472
|
+
<docgen-api>
|
|
473
|
+
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
|
|
474
|
+
|
|
475
|
+
### addListener('status', ...)
|
|
476
|
+
|
|
477
|
+
```typescript
|
|
478
|
+
addListener(eventName: 'status', listenerFunc: PlaylistStatusChangeCallback) => Promise<PluginListenerHandle>
|
|
479
|
+
```
|
|
167
480
|
|
|
168
|
-
|
|
481
|
+
Subscribe to native playback status events (track changes, position, errors, etc.).
|
|
169
482
|
|
|
170
|
-
|
|
483
|
+
| Param | Type | Description |
|
|
484
|
+
| ------------------ | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
485
|
+
| **`eventName`** | <code>'status'</code> | Must be `'status'`. |
|
|
486
|
+
| **`listenerFunc`** | <code><a href="#playliststatuschangecallback">PlaylistStatusChangeCallback</a></code> | Callback receiving `{ action, status }` where `status.msgType` is a <a href="#rmxaudiostatusmessage">`RmxAudioStatusMessage`</a>. |
|
|
171
487
|
|
|
172
|
-
|
|
488
|
+
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
|
|
489
|
+
|
|
490
|
+
--------------------
|
|
173
491
|
|
|
174
492
|
|
|
175
|
-
|
|
493
|
+
### setOptions(...)
|
|
176
494
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
495
|
+
```typescript
|
|
496
|
+
setOptions(options: AudioPlayerOptions) => Promise<void>
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
Configure plugin behaviour (verbose logging, stream pause handling, notification icon).
|
|
500
|
+
Can be called at any time; not required before playback.
|
|
501
|
+
|
|
502
|
+
| Param | Type |
|
|
503
|
+
| ------------- | ----------------------------------------------------------------- |
|
|
504
|
+
| **`options`** | <code><a href="#audioplayeroptions">AudioPlayerOptions</a></code> |
|
|
180
505
|
|
|
181
|
-
|
|
506
|
+
--------------------
|
|
182
507
|
|
|
183
|
-
Example:
|
|
184
|
-
@see definition.ts
|
|
185
508
|
|
|
509
|
+
### initialize()
|
|
510
|
+
|
|
511
|
+
```typescript
|
|
512
|
+
initialize() => Promise<void>
|
|
186
513
|
```
|
|
187
|
-
import {Playlist, AudioTrack} from 'capacitor-plugin-playlist'
|
|
188
514
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
515
|
+
Initialise the native player, register status callbacks, and arm lock-screen / notification controls.
|
|
516
|
+
Call once before playback (e.g. on app start).
|
|
517
|
+
|
|
518
|
+
--------------------
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
### release()
|
|
522
|
+
|
|
523
|
+
```typescript
|
|
524
|
+
release() => Promise<void>
|
|
195
525
|
```
|
|
196
526
|
|
|
197
|
-
|
|
527
|
+
Tear down native resources (audio session, media service, observers).
|
|
528
|
+
Call when the app no longer needs background audio (e.g. on logout).
|
|
198
529
|
|
|
199
|
-
|
|
530
|
+
--------------------
|
|
200
531
|
|
|
201
|
-
See the use the shipped RmxAudioPlayer.ts
|
|
202
532
|
|
|
203
|
-
|
|
533
|
+
### setPlaylistItems(...)
|
|
534
|
+
|
|
535
|
+
```typescript
|
|
536
|
+
setPlaylistItems(options: PlaylistOptions) => Promise<void>
|
|
537
|
+
```
|
|
204
538
|
|
|
205
|
-
|
|
539
|
+
Replace the entire playlist. Clears all previous items.
|
|
540
|
+
Use `options.retainPosition` to keep the current track and playback position.
|
|
206
541
|
|
|
207
|
-
|
|
542
|
+
| Param | Type |
|
|
543
|
+
| ------------- | ----------------------------------------------------------- |
|
|
544
|
+
| **`options`** | <code><a href="#playlistoptions">PlaylistOptions</a></code> |
|
|
208
545
|
|
|
209
|
-
|
|
210
|
-
- [iOS, Android] Add a full example
|
|
546
|
+
--------------------
|
|
211
547
|
|
|
212
|
-
## 6. Credits
|
|
213
548
|
|
|
214
|
-
|
|
549
|
+
### addItem(...)
|
|
550
|
+
|
|
551
|
+
```typescript
|
|
552
|
+
addItem(options: AddItemOptions) => Promise<void>
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
Append a single track to the end of the playlist.
|
|
556
|
+
|
|
557
|
+
| Param | Type |
|
|
558
|
+
| ------------- | --------------------------------------------------------- |
|
|
559
|
+
| **`options`** | <code><a href="#additemoptions">AddItemOptions</a></code> |
|
|
560
|
+
|
|
561
|
+
--------------------
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
### addAllItems(...)
|
|
565
|
+
|
|
566
|
+
```typescript
|
|
567
|
+
addAllItems(options: AddAllItemOptions) => Promise<void>
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
Append multiple tracks to the end of the playlist.
|
|
571
|
+
Raises one `RMXSTATUS_ITEM_ADDED` event per track.
|
|
572
|
+
|
|
573
|
+
| Param | Type |
|
|
574
|
+
| ------------- | --------------------------------------------------------------- |
|
|
575
|
+
| **`options`** | <code><a href="#addallitemoptions">AddAllItemOptions</a></code> |
|
|
576
|
+
|
|
577
|
+
--------------------
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
### removeItem(...)
|
|
581
|
+
|
|
582
|
+
```typescript
|
|
583
|
+
removeItem(options: RemoveItemOptions) => Promise<void>
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
Remove a track by index (preferred) or id.
|
|
587
|
+
If the removed track is currently playing, the next track starts automatically.
|
|
588
|
+
|
|
589
|
+
| Param | Type |
|
|
590
|
+
| ------------- | --------------------------------------------------------------- |
|
|
591
|
+
| **`options`** | <code><a href="#removeitemoptions">RemoveItemOptions</a></code> |
|
|
592
|
+
|
|
593
|
+
--------------------
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
### removeItems(...)
|
|
597
|
+
|
|
598
|
+
```typescript
|
|
599
|
+
removeItems(options: RemoveItemsOptions) => Promise<void>
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
Remove multiple tracks in a single batch.
|
|
603
|
+
If the currently playing track is removed, the next available track starts automatically.
|
|
604
|
+
|
|
605
|
+
| Param | Type |
|
|
606
|
+
| ------------- | ----------------------------------------------------------------- |
|
|
607
|
+
| **`options`** | <code><a href="#removeitemsoptions">RemoveItemsOptions</a></code> |
|
|
608
|
+
|
|
609
|
+
--------------------
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
### clearAllItems()
|
|
613
|
+
|
|
614
|
+
```typescript
|
|
615
|
+
clearAllItems() => Promise<void>
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
Remove all tracks from the playlist. Raises `RMXSTATUS_PLAYLIST_CLEARED` and `RMXSTATUS_STOPPED`.
|
|
619
|
+
|
|
620
|
+
--------------------
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
### getPlaylist()
|
|
624
|
+
|
|
625
|
+
```typescript
|
|
626
|
+
getPlaylist() => Promise<GetPlaylistResult>
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
Return a snapshot of the current playlist items.
|
|
630
|
+
|
|
631
|
+
**Returns:** <code>Promise<<a href="#getplaylistresult">GetPlaylistResult</a>></code>
|
|
632
|
+
|
|
633
|
+
--------------------
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
### play()
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
play() => Promise<void>
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
Start or resume playback of the current track.
|
|
643
|
+
No-op if the playlist is empty.
|
|
644
|
+
|
|
645
|
+
--------------------
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
### pause()
|
|
649
|
+
|
|
650
|
+
```typescript
|
|
651
|
+
pause() => Promise<void>
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
Pause playback of the current track.
|
|
655
|
+
|
|
656
|
+
--------------------
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
### skipForward()
|
|
660
|
+
|
|
661
|
+
```typescript
|
|
662
|
+
skipForward() => Promise<void>
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
Skip to the next track. At the end of the playlist, wraps to the beginning when loop is enabled.
|
|
666
|
+
|
|
667
|
+
--------------------
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
### skipBack()
|
|
671
|
+
|
|
672
|
+
```typescript
|
|
673
|
+
skipBack() => Promise<void>
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
Skip to the previous track. No-op when already at the first track.
|
|
677
|
+
|
|
678
|
+
--------------------
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
### seekTo(...)
|
|
682
|
+
|
|
683
|
+
```typescript
|
|
684
|
+
seekTo(options: SeekToOptions) => Promise<void>
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
Seek to a position (seconds) in the currently playing track.
|
|
688
|
+
If the position exceeds track length, playback advances to the next track.
|
|
689
|
+
|
|
690
|
+
| Param | Type |
|
|
691
|
+
| ------------- | ------------------------------------------------------- |
|
|
692
|
+
| **`options`** | <code><a href="#seektooptions">SeekToOptions</a></code> |
|
|
693
|
+
|
|
694
|
+
--------------------
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
### playTrackByIndex(...)
|
|
698
|
+
|
|
699
|
+
```typescript
|
|
700
|
+
playTrackByIndex(options: PlayByIndexOptions) => Promise<void>
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
Jump to the track at the given 0-based index and start playback.
|
|
704
|
+
|
|
705
|
+
| Param | Type |
|
|
706
|
+
| ------------- | ----------------------------------------------------------------- |
|
|
707
|
+
| **`options`** | <code><a href="#playbyindexoptions">PlayByIndexOptions</a></code> |
|
|
708
|
+
|
|
709
|
+
--------------------
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
### playTrackById(...)
|
|
713
|
+
|
|
714
|
+
```typescript
|
|
715
|
+
playTrackById(options: PlayByIdOptions) => Promise<void>
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
Jump to the track with the given id and start playback.
|
|
719
|
+
|
|
720
|
+
| Param | Type |
|
|
721
|
+
| ------------- | ----------------------------------------------------------- |
|
|
722
|
+
| **`options`** | <code><a href="#playbyidoptions">PlayByIdOptions</a></code> |
|
|
723
|
+
|
|
724
|
+
--------------------
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
### selectTrackByIndex(...)
|
|
728
|
+
|
|
729
|
+
```typescript
|
|
730
|
+
selectTrackByIndex(options: SelectByIndexOptions) => Promise<void>
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
Select the track at the given index without necessarily starting playback.
|
|
734
|
+
|
|
735
|
+
| Param | Type |
|
|
736
|
+
| ------------- | --------------------------------------------------------------------- |
|
|
737
|
+
| **`options`** | <code><a href="#selectbyindexoptions">SelectByIndexOptions</a></code> |
|
|
738
|
+
|
|
739
|
+
--------------------
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
### selectTrackById(...)
|
|
743
|
+
|
|
744
|
+
```typescript
|
|
745
|
+
selectTrackById(options: SelectByIdOptions) => Promise<void>
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
Select the track with the given id without necessarily starting playback.
|
|
749
|
+
|
|
750
|
+
| Param | Type |
|
|
751
|
+
| ------------- | --------------------------------------------------------------- |
|
|
752
|
+
| **`options`** | <code><a href="#selectbyidoptions">SelectByIdOptions</a></code> |
|
|
753
|
+
|
|
754
|
+
--------------------
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
### setPlaybackVolume(...)
|
|
758
|
+
|
|
759
|
+
```typescript
|
|
760
|
+
setPlaybackVolume(options: SetPlaybackVolumeOptions) => Promise<void>
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
Set media stream volume. Float in range [0, 1].
|
|
764
|
+
Hardware volume controls still apply on top of this value.
|
|
765
|
+
|
|
766
|
+
| Param | Type |
|
|
767
|
+
| ------------- | ----------------------------------------------------------------------------- |
|
|
768
|
+
| **`options`** | <code><a href="#setplaybackvolumeoptions">SetPlaybackVolumeOptions</a></code> |
|
|
769
|
+
|
|
770
|
+
--------------------
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
### setLoop(...)
|
|
774
|
+
|
|
775
|
+
```typescript
|
|
776
|
+
setLoop(options: SetLoopOptions) => Promise<void>
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
When true, the playlist loops back to the first track after the last track completes.
|
|
780
|
+
|
|
781
|
+
| Param | Type |
|
|
782
|
+
| ------------- | --------------------------------------------------------- |
|
|
783
|
+
| **`options`** | <code><a href="#setloopoptions">SetLoopOptions</a></code> |
|
|
784
|
+
|
|
785
|
+
--------------------
|
|
786
|
+
|
|
787
|
+
|
|
788
|
+
### setPlaybackRate(...)
|
|
789
|
+
|
|
790
|
+
```typescript
|
|
791
|
+
setPlaybackRate(options: SetPlaybackRateOptions) => Promise<void>
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
Set playback speed. Float value; 0 pauses, 1 is normal speed.
|
|
795
|
+
|
|
796
|
+
| Param | Type |
|
|
797
|
+
| ------------- | ------------------------------------------------------------------------- |
|
|
798
|
+
| **`options`** | <code><a href="#setplaybackrateoptions">SetPlaybackRateOptions</a></code> |
|
|
799
|
+
|
|
800
|
+
--------------------
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
### prepareForVideoHandoff()
|
|
804
|
+
|
|
805
|
+
```typescript
|
|
806
|
+
prepareForVideoHandoff() => Promise<void>
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
Release native audio session / focus so a video player can own playback.
|
|
810
|
+
|
|
811
|
+
**Android:** pauses current track, abandons audio focus, stores head position. Does not stop the foreground media service.
|
|
812
|
+
**iOS:** pauses, captures head position, deactivates `AVAudioSession` with `notifyOthersOnDeactivation`.
|
|
813
|
+
**Web:** pauses HTMLAudioElement and stores `currentTime`.
|
|
814
|
+
|
|
815
|
+
Call immediately before native video starts (e.g. your video plugin's init method).
|
|
816
|
+
|
|
817
|
+
--------------------
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
### resumeAfterVideoHandoff(...)
|
|
821
|
+
|
|
822
|
+
```typescript
|
|
823
|
+
resumeAfterVideoHandoff(options: ResumeAfterVideoHandoffOptions) => Promise<ResumeAfterVideoHandoffResult>
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
Re-arm native audio after video ends or, on Android, prewarm the media service before video starts.
|
|
827
|
+
|
|
828
|
+
**Without `prewarm` (typical exit path):**
|
|
829
|
+
- Android: when `play` is true (default), re-acquires focus and resumes at `position`. When `resumed` is `true`, JS should skip redundant `seekTo`/`play`. When `play` is false, clears handoff retain and returns `{ resumed: false }` so JS can seek without playing.
|
|
830
|
+
- iOS: restores pinned track, reactivates `AVAudioSession`, seeks to `position`, and when `play` is true starts playback (seek-then-play). Returns `{ resumed: true }` when native handled the handoff.
|
|
831
|
+
- Web: stores position only (no native session); returns `{ resumed: false }`.
|
|
832
|
+
|
|
833
|
+
**With `prewarm: true` (Android, before video):** starts `MediaService` in foreground at `position` but stays silent — no audio focus, no audible playback. Always returns `{ resumed: false }`.
|
|
834
|
+
|
|
835
|
+
| Param | Type |
|
|
836
|
+
| ------------- | ----------------------------------------------------------------------------------------- |
|
|
837
|
+
| **`options`** | <code><a href="#resumeaftervideohandoffoptions">ResumeAfterVideoHandoffOptions</a></code> |
|
|
838
|
+
|
|
839
|
+
**Returns:** <code>Promise<<a href="#resumeaftervideohandoffresult">ResumeAfterVideoHandoffResult</a>></code>
|
|
840
|
+
|
|
841
|
+
--------------------
|
|
842
|
+
|
|
843
|
+
|
|
844
|
+
### getLastKnownPosition()
|
|
845
|
+
|
|
846
|
+
```typescript
|
|
847
|
+
getLastKnownPosition() => Promise<GetLastKnownPositionResult>
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
Return the audio head position (seconds) captured during the most recent `prepareForVideoHandoff`
|
|
851
|
+
or passed to `resumeAfterVideoHandoff`.
|
|
852
|
+
|
|
853
|
+
**Returns:** <code>Promise<<a href="#getlastknownpositionresult">GetLastKnownPositionResult</a>></code>
|
|
854
|
+
|
|
855
|
+
--------------------
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
### Interfaces
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
#### PluginListenerHandle
|
|
862
|
+
|
|
863
|
+
| Prop | Type |
|
|
864
|
+
| ------------ | ----------------------------------------- |
|
|
865
|
+
| **`remove`** | <code>() => Promise<void></code> |
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
#### PlaylistStatusChangeCallbackArg
|
|
869
|
+
|
|
870
|
+
| Prop | Type |
|
|
871
|
+
| ------------ | --------------------------------------------------------------------- |
|
|
872
|
+
| **`action`** | <code>string</code> |
|
|
873
|
+
| **`status`** | <code><a href="#onstatuscallbackdata">OnStatusCallbackData</a></code> |
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
#### OnStatusCallbackData
|
|
877
|
+
|
|
878
|
+
Encapsulates the data received by an onStatus callback
|
|
879
|
+
|
|
880
|
+
| Prop | Type | Description |
|
|
881
|
+
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
882
|
+
| **`trackId`** | <code>string</code> | The ID of this track. If the track is null or has completed, this value is "NONE" If the playlist is completed, this value is "INVALID" |
|
|
883
|
+
| **`msgType`** | <code><a href="#rmxaudiostatusmessage">RmxAudioStatusMessage</a></code> | The type of status update |
|
|
884
|
+
| **`value`** | <code><a href="#onstatuscallbackupdatedata">OnStatusCallbackUpdateData</a> \| <a href="#onstatustrackchangeddata">OnStatusTrackChangedData</a> \| <a href="#onstatuserrorcallbackdata">OnStatusErrorCallbackData</a></code> | The status payload. For all updates except ERROR, the data package is described by <a href="#onstatuscallbackupdatedata">OnStatusCallbackUpdateData</a>. For Errors, the data is shaped as <a href="#onstatuserrorcallbackdata">OnStatusErrorCallbackData</a> |
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
#### OnStatusCallbackUpdateData
|
|
888
|
+
|
|
889
|
+
Contains the current track status as of the moment an onStatus update event is emitted.
|
|
890
|
+
|
|
891
|
+
| Prop | Type | Description |
|
|
892
|
+
| --------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
893
|
+
| **`trackId`** | <code>string</code> | The ID of this track corresponding to this event. If the track is null or has completed, this value is "NONE". This will happen when skipping to the beginning or end of the playlist. If the playlist is completed, this value is "INVALID" |
|
|
894
|
+
| **`isStream`** | <code>boolean</code> | Boolean indicating whether this is a streaming track. |
|
|
895
|
+
| **`currentIndex`** | <code>number</code> | The current index of the track in the playlist. |
|
|
896
|
+
| **`status`** | <code>'error' \| 'unknown' \| 'ready' \| 'playing' \| 'loading' \| 'paused'</code> | The current status of the track, as a string. This is used to summarize the various event states that a track can be in; e.g. "playing" is true for any number of track statuses. The Javascript interface takes care of this for you; this field is here only for reference. |
|
|
897
|
+
| **`currentPosition`** | <code>number</code> | Current playback position of the reported track. |
|
|
898
|
+
| **`duration`** | <code>number</code> | The known duration of the reported track. For streams or malformed MP3's, this value will be 0. |
|
|
899
|
+
| **`playbackPercent`** | <code>number</code> | Progress of track playback, as a percent, in the range 0 - 100 |
|
|
900
|
+
| **`bufferPercent`** | <code>number</code> | Buffering progress of the track, as a percent, in the range 0 - 100 |
|
|
901
|
+
| **`bufferStart`** | <code>number</code> | The starting position of the buffering progress. For now, this is always reported as 0. |
|
|
902
|
+
| **`bufferEnd`** | <code>number</code> | The maximum position, in seconds, of the track buffer. For now, only the buffer with the maximum playback position is reported, even if there are other segments (due to seeking, for example). Practically speaking you don't need to worry about that, as in both implementations the minor gaps are automatically filled in by the underlying players. |
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
#### OnStatusTrackChangedData
|
|
906
|
+
|
|
907
|
+
Reports information about the playlist state when a track changes.
|
|
908
|
+
Includes the new track, its index, and the state of the playlist.
|
|
909
|
+
|
|
910
|
+
| Prop | Type | Description |
|
|
911
|
+
| ------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
912
|
+
| **`currentItem`** | <code><a href="#audiotrack">AudioTrack</a></code> | The new track that has been selected. May be null if you are at the end of the playlist, or the playlist has been emptied. |
|
|
913
|
+
| **`currentIndex`** | <code>number</code> | The 0-based index of the new track. If the playlist has ended or been cleared, this will be -1. |
|
|
914
|
+
| **`isAtEnd`** | <code>boolean</code> | Indicates whether the playlist is now currently at the last item in the list. |
|
|
915
|
+
| **`isAtBeginning`** | <code>boolean</code> | Indicates whether the playlist is now at the first item in the list |
|
|
916
|
+
| **`hasNext`** | <code>boolean</code> | Indicates if there are additional playlist items after the current item. |
|
|
917
|
+
| **`hasPrevious`** | <code>boolean</code> | Indicates if there are any items before this one in the playlist. |
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
#### AudioTrack
|
|
921
|
+
|
|
922
|
+
An audio track for playback by the playlist.
|
|
923
|
+
|
|
924
|
+
| Prop | Type | Description |
|
|
925
|
+
| -------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
926
|
+
| **`isStream`** | <code>boolean</code> | This item is a streaming asset. Make sure this is set to true for stream URLs, otherwise you will get odd behavior when the asset is paused. |
|
|
927
|
+
| **`trackId`** | <code>string</code> | trackId is optional and if not passed in, an auto-generated UUID will be used. |
|
|
928
|
+
| **`assetUrl`** | <code>string</code> | URL of the asset; can be local, a URL, or a streaming URL. If the asset is a stream, make sure that isStream is set to true, otherwise the plugin can't properly handle the item's buffer. |
|
|
929
|
+
| **`albumArt`** | <code>string</code> | The local or remote URL to an image asset to be shown for this track. If this is null, the plugin's default image is used. |
|
|
930
|
+
| **`artist`** | <code>string</code> | The track's artist |
|
|
931
|
+
| **`album`** | <code>string</code> | Album the track belongs to |
|
|
932
|
+
| **`title`** | <code>string</code> | Title of the track |
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
#### OnStatusErrorCallbackData
|
|
936
|
+
|
|
937
|
+
Represents an error reported by the onStatus callback.
|
|
938
|
+
|
|
939
|
+
| Prop | Type | Description |
|
|
940
|
+
| ------------- | --------------------------------------------------------------- | ----------------------- |
|
|
941
|
+
| **`code`** | <code><a href="#rmxaudioerrortype">RmxAudioErrorType</a></code> | Error code |
|
|
942
|
+
| **`message`** | <code>string</code> | The error, as a message |
|
|
943
|
+
|
|
944
|
+
|
|
945
|
+
#### AudioPlayerOptions
|
|
946
|
+
|
|
947
|
+
Options governing the overall behavior of the audio player plugin
|
|
948
|
+
|
|
949
|
+
| Prop | Type | Description |
|
|
950
|
+
| ------------------------ | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
951
|
+
| **`verbose`** | <code>boolean</code> | Should the plugin's javascript dump the status message stream to the javascript console? |
|
|
952
|
+
| **`resetStreamOnPause`** | <code>boolean</code> | If true, when pausing a live stream, play will continue from the LIVE POSITION (e.g. the stream jumps forward to the current point in time, rather than picking up where it left off when you paused). If false, the stream will continue where you paused. The drawback of doing this is that when the audio buffer fills, it will jump forward to the current point in time, cause a disjoint in playback. Default is true. |
|
|
953
|
+
| **`options`** | <code><a href="#notificationoptions">NotificationOptions</a></code> | Further options for notifications |
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
#### NotificationOptions
|
|
957
|
+
|
|
958
|
+
| Prop | Type |
|
|
959
|
+
| ---------- | ------------------- |
|
|
960
|
+
| **`icon`** | <code>string</code> |
|
|
961
|
+
|
|
962
|
+
|
|
963
|
+
#### PlaylistOptions
|
|
964
|
+
|
|
965
|
+
| Prop | Type |
|
|
966
|
+
| ------------- | ----------------------------------------------------------------------------------- |
|
|
967
|
+
| **`items`** | <code><a href="#array">Array</a><<a href="#audiotrack">AudioTrack</a>></code> |
|
|
968
|
+
| **`options`** | <code><a href="#playlistitemoptions">PlaylistItemOptions</a></code> |
|
|
969
|
+
|
|
970
|
+
|
|
971
|
+
#### Array
|
|
972
|
+
|
|
973
|
+
| Prop | Type | Description |
|
|
974
|
+
| ------------ | ------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
975
|
+
| **`length`** | <code>number</code> | Gets or sets the length of the array. This is a number one higher than the highest index in the array. |
|
|
976
|
+
|
|
977
|
+
| Method | Signature | Description |
|
|
978
|
+
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
979
|
+
| **toString** | () => string | Returns a string representation of an array. |
|
|
980
|
+
| **toLocaleString** | () => string | Returns a string representation of an array. The elements are converted to string using their toLocalString methods. |
|
|
981
|
+
| **pop** | () => T \| undefined | Removes the last element from an array and returns it. If the array is empty, undefined is returned and the array is not modified. |
|
|
982
|
+
| **push** | (...items: T[]) => number | Appends new elements to the end of an array, and returns the new length of the array. |
|
|
983
|
+
| **concat** | (...items: <a href="#concatarray">ConcatArray</a><T>[]) => T[] | Combines two or more arrays. This method returns a new array without modifying any existing arrays. |
|
|
984
|
+
| **concat** | (...items: (T \| <a href="#concatarray">ConcatArray</a><T>)[]) => T[] | Combines two or more arrays. This method returns a new array without modifying any existing arrays. |
|
|
985
|
+
| **join** | (separator?: string \| undefined) => string | Adds all the elements of an array into a string, separated by the specified separator string. |
|
|
986
|
+
| **reverse** | () => T[] | Reverses the elements in an array in place. This method mutates the array and returns a reference to the same array. |
|
|
987
|
+
| **shift** | () => T \| undefined | Removes the first element from an array and returns it. If the array is empty, undefined is returned and the array is not modified. |
|
|
988
|
+
| **slice** | (start?: number \| undefined, end?: number \| undefined) => T[] | Returns a copy of a section of an array. For both start and end, a negative index can be used to indicate an offset from the end of the array. For example, -2 refers to the second to last element of the array. |
|
|
989
|
+
| **sort** | (compareFn?: ((a: T, b: T) => number) \| undefined) => this | Sorts an array in place. This method mutates the array and returns a reference to the same array. |
|
|
990
|
+
| **splice** | (start: number, deleteCount?: number \| undefined) => T[] | Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements. |
|
|
991
|
+
| **splice** | (start: number, deleteCount: number, ...items: T[]) => T[] | Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements. |
|
|
992
|
+
| **unshift** | (...items: T[]) => number | Inserts new elements at the start of an array, and returns the new length of the array. |
|
|
993
|
+
| **indexOf** | (searchElement: T, fromIndex?: number \| undefined) => number | Returns the index of the first occurrence of a value in an array, or -1 if it is not present. |
|
|
994
|
+
| **lastIndexOf** | (searchElement: T, fromIndex?: number \| undefined) => number | Returns the index of the last occurrence of a specified value in an array, or -1 if it is not present. |
|
|
995
|
+
| **every** | <S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any) => this is S[] | Determines whether all the members of an array satisfy the specified test. |
|
|
996
|
+
| **every** | (predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any) => boolean | Determines whether all the members of an array satisfy the specified test. |
|
|
997
|
+
| **some** | (predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any) => boolean | Determines whether the specified callback function returns true for any element of an array. |
|
|
998
|
+
| **forEach** | (callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any) => void | Performs the specified action for each element in an array. |
|
|
999
|
+
| **map** | <U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] | Calls a defined callback function on each element of an array, and returns an array that contains the results. |
|
|
1000
|
+
| **filter** | <S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any) => S[] | Returns the elements of an array that meet the condition specified in a callback function. |
|
|
1001
|
+
| **filter** | (predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any) => T[] | Returns the elements of an array that meet the condition specified in a callback function. |
|
|
1002
|
+
| **reduce** | (callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T) => T | Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
|
|
1003
|
+
| **reduce** | (callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T) => T | |
|
|
1004
|
+
| **reduce** | <U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U) => U | Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
|
|
1005
|
+
| **reduceRight** | (callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T) => T | Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
|
|
1006
|
+
| **reduceRight** | (callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T) => T | |
|
|
1007
|
+
| **reduceRight** | <U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U) => U | Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
#### ConcatArray
|
|
1011
|
+
|
|
1012
|
+
| Prop | Type |
|
|
1013
|
+
| ------------ | ------------------- |
|
|
1014
|
+
| **`length`** | <code>number</code> |
|
|
1015
|
+
|
|
1016
|
+
| Method | Signature |
|
|
1017
|
+
| --------- | ------------------------------------------------------------------ |
|
|
1018
|
+
| **join** | (separator?: string \| undefined) => string |
|
|
1019
|
+
| **slice** | (start?: number \| undefined, end?: number \| undefined) => T[] |
|
|
1020
|
+
|
|
1021
|
+
|
|
1022
|
+
#### PlaylistItemOptions
|
|
1023
|
+
|
|
1024
|
+
Options governing how the items are managed when using setPlaylistItems
|
|
1025
|
+
to update the playlist. This is typically useful if you are retaining items
|
|
1026
|
+
that were in the previous list.
|
|
1027
|
+
|
|
1028
|
+
| Prop | Type | Description |
|
|
1029
|
+
| ---------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
1030
|
+
| **`retainPosition`** | <code>boolean</code> | If true, the plugin will continue playback from the current playback position after setting the items to the playlist. |
|
|
1031
|
+
| **`playFromPosition`** | <code>number</code> | If retainPosition is true, this value will tell the plugin the exact time to start from, rather than letting the plugin decide based on current playback. |
|
|
1032
|
+
| **`playFromId`** | <code>string</code> | If retainPosition is true, this value will tell the plugin the uid of the "current" item to start from, rather than letting the plugin decide based on current playback. |
|
|
1033
|
+
| **`startPaused`** | <code>boolean</code> | If playback should immediately begin when calling setPlaylistItems on the plugin. Default is false; |
|
|
1034
|
+
|
|
1035
|
+
|
|
1036
|
+
#### AddItemOptions
|
|
1037
|
+
|
|
1038
|
+
| Prop | Type |
|
|
1039
|
+
| ---------- | ------------------------------------------------- |
|
|
1040
|
+
| **`item`** | <code><a href="#audiotrack">AudioTrack</a></code> |
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
#### AddAllItemOptions
|
|
1044
|
+
|
|
1045
|
+
| Prop | Type |
|
|
1046
|
+
| ----------- | ----------------------------------------------------------------------------------- |
|
|
1047
|
+
| **`items`** | <code><a href="#array">Array</a><<a href="#audiotrack">AudioTrack</a>></code> |
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
#### RemoveItemOptions
|
|
1051
|
+
|
|
1052
|
+
| Prop | Type |
|
|
1053
|
+
| ----------- | ------------------- |
|
|
1054
|
+
| **`id`** | <code>string</code> |
|
|
1055
|
+
| **`index`** | <code>number</code> |
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
#### RemoveItemsOptions
|
|
1059
|
+
|
|
1060
|
+
| Prop | Type |
|
|
1061
|
+
| ----------- | ------------------------------------------------------------------------------------------------- |
|
|
1062
|
+
| **`items`** | <code><a href="#array">Array</a><<a href="#removeitemoptions">RemoveItemOptions</a>></code> |
|
|
1063
|
+
|
|
1064
|
+
|
|
1065
|
+
#### GetPlaylistResult
|
|
1066
|
+
|
|
1067
|
+
| Prop | Type |
|
|
1068
|
+
| ----------- | ----------------------------------------------------------------------------------- |
|
|
1069
|
+
| **`items`** | <code><a href="#array">Array</a><<a href="#audiotrack">AudioTrack</a>></code> |
|
|
1070
|
+
|
|
1071
|
+
|
|
1072
|
+
#### SeekToOptions
|
|
1073
|
+
|
|
1074
|
+
| Prop | Type |
|
|
1075
|
+
| -------------- | ------------------- |
|
|
1076
|
+
| **`position`** | <code>number</code> |
|
|
1077
|
+
|
|
1078
|
+
|
|
1079
|
+
#### PlayByIndexOptions
|
|
1080
|
+
|
|
1081
|
+
| Prop | Type |
|
|
1082
|
+
| -------------- | ------------------- |
|
|
1083
|
+
| **`index`** | <code>number</code> |
|
|
1084
|
+
| **`position`** | <code>number</code> |
|
|
1085
|
+
|
|
1086
|
+
|
|
1087
|
+
#### PlayByIdOptions
|
|
1088
|
+
|
|
1089
|
+
| Prop | Type |
|
|
1090
|
+
| -------------- | ------------------- |
|
|
1091
|
+
| **`id`** | <code>string</code> |
|
|
1092
|
+
| **`position`** | <code>number</code> |
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
#### SelectByIndexOptions
|
|
1096
|
+
|
|
1097
|
+
| Prop | Type |
|
|
1098
|
+
| -------------- | ------------------- |
|
|
1099
|
+
| **`index`** | <code>number</code> |
|
|
1100
|
+
| **`position`** | <code>number</code> |
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
#### SelectByIdOptions
|
|
1104
|
+
|
|
1105
|
+
| Prop | Type |
|
|
1106
|
+
| -------------- | ------------------- |
|
|
1107
|
+
| **`id`** | <code>string</code> |
|
|
1108
|
+
| **`position`** | <code>number</code> |
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
#### SetPlaybackVolumeOptions
|
|
1112
|
+
|
|
1113
|
+
| Prop | Type |
|
|
1114
|
+
| ------------ | ------------------- |
|
|
1115
|
+
| **`volume`** | <code>number</code> |
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
#### SetLoopOptions
|
|
1119
|
+
|
|
1120
|
+
| Prop | Type |
|
|
1121
|
+
| ---------- | -------------------- |
|
|
1122
|
+
| **`loop`** | <code>boolean</code> |
|
|
1123
|
+
|
|
1124
|
+
|
|
1125
|
+
#### SetPlaybackRateOptions
|
|
1126
|
+
|
|
1127
|
+
| Prop | Type |
|
|
1128
|
+
| ---------- | ------------------- |
|
|
1129
|
+
| **`rate`** | <code>number</code> |
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
#### ResumeAfterVideoHandoffResult
|
|
1133
|
+
|
|
1134
|
+
| Prop | Type | Description |
|
|
1135
|
+
| ------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1136
|
+
| **`resumed`** | <code>boolean</code> | `true` when native already handled seek (and play when requested) in place. When `true`, JS should skip redundant `seekTo` / `play` to avoid a stutter. `false` on web, prewarm, paused Android handoff, and Android last-resort `beginPlayback`. |
|
|
1137
|
+
|
|
1138
|
+
|
|
1139
|
+
#### ResumeAfterVideoHandoffOptions
|
|
1140
|
+
|
|
1141
|
+
| Prop | Type | Description |
|
|
1142
|
+
| -------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1143
|
+
| **`position`** | <code>number</code> | Resume position in seconds (video exit head or saved audio position). |
|
|
1144
|
+
| **`prewarm`** | <code>boolean</code> | **Android only.** When `true`, promote `MediaService` to foreground and prepare at `position` without requesting audio focus or playing audio. Use immediately after `prepareForVideoHandoff` and before native video starts, while the app is still foregrounded. Ignored on iOS (no-op). Not applicable on web. |
|
|
1145
|
+
| **`play`** | <code>boolean</code> | When `true`, native starts audible playback after seeking to `position`. When `false` (paused video exit), native must not start playback. iOS defaults to `false` when omitted; Android defaults to `true` for legacy callers. |
|
|
1146
|
+
|
|
1147
|
+
|
|
1148
|
+
#### GetLastKnownPositionResult
|
|
1149
|
+
|
|
1150
|
+
| Prop | Type |
|
|
1151
|
+
| -------------- | ------------------- |
|
|
1152
|
+
| **`position`** | <code>number</code> |
|
|
1153
|
+
|
|
1154
|
+
|
|
1155
|
+
### Type Aliases
|
|
1156
|
+
|
|
1157
|
+
|
|
1158
|
+
#### PlaylistStatusChangeCallback
|
|
1159
|
+
|
|
1160
|
+
<code>(data: <a href="#playliststatuschangecallbackarg">PlaylistStatusChangeCallbackArg</a>): void</code>
|
|
1161
|
+
|
|
1162
|
+
|
|
1163
|
+
### Enums
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
#### RmxAudioStatusMessage
|
|
1167
|
+
|
|
1168
|
+
| Members | Value | Description |
|
|
1169
|
+
| ---------------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1170
|
+
| **`RMXSTATUS_NONE`** | <code>0</code> | The starting state of the plugin. You will never see this value; it changes before the callbacks are even registered to report changes to this value. |
|
|
1171
|
+
| **`RMXSTATUS_REGISTER`** | <code>1</code> | Raised when the plugin registers the callback handler for onStatus callbacks. You will probably not be able to see this (nor do you need to). |
|
|
1172
|
+
| **`RMXSTATUS_INIT`** | <code>2</code> | Reserved for future use |
|
|
1173
|
+
| **`RMXSTATUS_ERROR`** | <code>5</code> | Indicates an error is reported in the 'value' field. |
|
|
1174
|
+
| **`RMXSTATUS_LOADING`** | <code>10</code> | The reported track is being loaded by the player |
|
|
1175
|
+
| **`RMXSTATUS_CANPLAY`** | <code>11</code> | The reported track is able to begin playback |
|
|
1176
|
+
| **`RMXSTATUS_LOADED`** | <code>15</code> | The reported track has loaded 100% of the file (either from disc or network) |
|
|
1177
|
+
| **`RMXSTATUS_STALLED`** | <code>20</code> | (iOS only): Playback has stalled due to insufficient network |
|
|
1178
|
+
| **`RMXSTATUS_BUFFERING`** | <code>25</code> | Reports an update in the reported track's buffering status |
|
|
1179
|
+
| **`RMXSTATUS_PLAYING`** | <code>30</code> | The reported track has started (or resumed) playing |
|
|
1180
|
+
| **`RMXSTATUS_PAUSE`** | <code>35</code> | The reported track has been paused, either by the user or by the system. (iOS only): This value is raised when MP3's are malformed (but still playable). These require the user to explicitly press play again. This can be worked around and is on the TODO list. |
|
|
1181
|
+
| **`RMXSTATUS_PLAYBACK_POSITION`** | <code>40</code> | Reports a change in the reported track's playback position. |
|
|
1182
|
+
| **`RMXSTATUS_SEEK`** | <code>45</code> | The reported track has seeked. On Android, only the plugin consumer can generate this (Notification controls on Android do not include a seek bar). On iOS, the Command Center includes a seek bar so this will be reported when the user has seeked via Command Center. |
|
|
1183
|
+
| **`RMXSTATUS_COMPLETED`** | <code>50</code> | The reported track has completed playback. |
|
|
1184
|
+
| **`RMXSTATUS_DURATION`** | <code>55</code> | The reported track's duration has changed. This is raised once, when duration is updated for the first time. For streams, this value is never reported. |
|
|
1185
|
+
| **`RMXSTATUS_STOPPED`** | <code>60</code> | All playback has stopped, probably because the plugin is shutting down. |
|
|
1186
|
+
| **`RMX_STATUS_SKIP_FORWARD`** | <code>90</code> | The playlist has skipped forward to the next track. On both Android and iOS, this will be raised if the notification controls/Command Center were used to skip. It is unlikely you need to consume this event: RMXSTATUS_TRACK_CHANGED is also reported when this occurs, so you can generalize your track change handling in one place. |
|
|
1187
|
+
| **`RMX_STATUS_SKIP_BACK`** | <code>95</code> | The playlist has skipped back to the previous track. On both Android and iOS, this will be raised if the notification controls/Command Center were used to skip. It is unlikely you need to consume this event: RMXSTATUS_TRACK_CHANGED is also reported when this occurs, so you can generalize your track change handling in one place. |
|
|
1188
|
+
| **`RMXSTATUS_TRACK_CHANGED`** | <code>100</code> | Reported when the current track has changed in the native player. This event contains full data about the new track, including the index and the actual track itself. The type of the 'value' field in this case is <a href="#onstatustrackchangeddata">OnStatusTrackChangedData</a>. |
|
|
1189
|
+
| **`RMXSTATUS_PLAYLIST_COMPLETED`** | <code>105</code> | The entire playlist has completed playback. After this event has been raised, the current item is set to null and the current index to -1. |
|
|
1190
|
+
| **`RMXSTATUS_ITEM_ADDED`** | <code>110</code> | An item has been added to the playlist. For the setPlaylistItems and addAllItems methods, this status is raised once for every track in the collection. |
|
|
1191
|
+
| **`RMXSTATUS_ITEM_REMOVED`** | <code>115</code> | An item has been removed from the playlist. For the removeItems and clearAllItems methods, this status is raised once for every track that was removed. |
|
|
1192
|
+
| **`RMXSTATUS_PLAYLIST_CLEARED`** | <code>120</code> | All items have been removed from the playlist |
|
|
1193
|
+
| **`RMXSTATUS_VIEWDISAPPEAR`** | <code>200</code> | Just for testing.. you don't need this and in fact can never receive it, the plugin is destroyed before it can be raised. |
|
|
1194
|
+
|
|
1195
|
+
|
|
1196
|
+
#### RmxAudioErrorType
|
|
1197
|
+
|
|
1198
|
+
| Members | Value |
|
|
1199
|
+
| --------------------------- | -------------- |
|
|
1200
|
+
| **`RMXERR_NONE_ACTIVE`** | <code>0</code> |
|
|
1201
|
+
| **`RMXERR_ABORTED`** | <code>1</code> |
|
|
1202
|
+
| **`RMXERR_NETWORK`** | <code>2</code> |
|
|
1203
|
+
| **`RMXERR_DECODE`** | <code>3</code> |
|
|
1204
|
+
| **`RMXERR_NONE_SUPPORTED`** | <code>4</code> |
|
|
1205
|
+
|
|
1206
|
+
</docgen-api>
|
|
1207
|
+
|
|
1208
|
+
## Migrating from cordova-plugin-playlist
|
|
1209
|
+
|
|
1210
|
+
Use the shipped `RmxAudioPlayer` class — in the best case you only change your import:
|
|
1211
|
+
|
|
1212
|
+
```typescript
|
|
1213
|
+
// before
|
|
1214
|
+
import { RmxAudioPlayer } from 'cordova-plugin-playlist';
|
|
1215
|
+
|
|
1216
|
+
// after
|
|
1217
|
+
import { RmxAudioPlayer } from 'capacitor-plugin-playlist';
|
|
1218
|
+
```
|
|
1219
|
+
|
|
1220
|
+
For new code or video handoff, prefer the `Playlist` plugin object directly.
|
|
1221
|
+
|
|
1222
|
+
## Changes
|
|
1223
|
+
|
|
1224
|
+
See [CHANGELOG.md](./CHANGELOG.md) for version history.
|
|
1225
|
+
|
|
1226
|
+
## Credits
|
|
1227
|
+
|
|
1228
|
+
Inspired by:
|
|
215
1229
|
|
|
216
1230
|
- [cordova-plugin-playlist](https://github.com/Rolamix/cordova-plugin-playlist)
|
|
217
1231
|
- [cordova-plugin-media](https://github.com/apache/cordova-plugin-media)
|
|
218
1232
|
- [ExoMedia](https://github.com/brianwernick/ExoMedia)
|
|
219
|
-
- [PlaylistCore](https://github.com/brianwernick/PlaylistCore)
|
|
220
|
-
- [Bi-Directional AVQueuePlayer
|
|
1233
|
+
- [PlaylistCore](https://github.com/brianwernick/PlaylistCore)
|
|
1234
|
+
- [Bi-Directional AVQueuePlayer](https://github.com/jrtaal/AVBidirectionalQueuePlayer)
|
|
221
1235
|
- [cordova-music-controls-plugin](https://github.com/homerours/cordova-music-controls-plugin)
|
|
222
1236
|
|
|
223
|
-
##
|
|
1237
|
+
## License
|
|
224
1238
|
|
|
225
1239
|
[The MIT License (MIT)](http://www.opensource.org/licenses/mit-license.html)
|
|
226
|
-
|
|
227
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
228
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
229
|
-
in the Software without restriction, including without limitation the rights
|
|
230
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
231
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
232
|
-
furnished to do so, subject to the following conditions:
|
|
233
|
-
|
|
234
|
-
The above copyright notice and this permission notice shall be included in
|
|
235
|
-
all copies or substantial portions of the Software.
|
|
236
|
-
|
|
237
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
238
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
239
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
240
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
241
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
242
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
243
|
-
THE SOFTWARE.
|