From 69597cd943c35dd1e83833e9d1d5f0e130715779 Mon Sep 17 00:00:00 2001 From: David Chavez Date: Sat, 21 Oct 2023 01:09:07 +0200 Subject: [PATCH] Release v4.0.0 (#2177) --- .github/workflows/nightly.yml | 4 +- CHANGELOG.md | 12 + android/build.gradle | 4 +- docs/docs/v4-migration.md | 71 +++--- .../version-4.0/api/_category_.json | 4 + .../version-4.0/api/constants/_category_.json | 4 + .../constants/app-killed-playback-behavior.md | 25 ++ .../version-4.0/api/constants/capability.md | 29 +++ .../api/constants/ios-category-mode.md | 67 ++++++ .../api/constants/ios-category-options.md | 60 +++++ .../version-4.0/api/constants/ios-category.md | 52 ++++ .../api/constants/pitch-algorithm.md | 17 ++ .../version-4.0/api/constants/rating.md | 20 ++ .../version-4.0/api/constants/repeat-mode.md | 17 ++ .../version-4.0/api/constants/state.md | 24 ++ docs/versioned_docs/version-4.0/api/events.md | 222 +++++++++++++++++ .../version-4.0/api/functions/_category_.json | 4 + .../version-4.0/api/functions/lifecycle.md | 46 ++++ .../version-4.0/api/functions/player.md | 152 ++++++++++++ .../version-4.0/api/functions/queue.md | 143 +++++++++++ docs/versioned_docs/version-4.0/api/hooks.md | 105 ++++++++ .../version-4.0/api/objects/_category_.json | 4 + .../api/objects/android-options.md | 9 + .../version-4.0/api/objects/feedback.md | 12 + .../api/objects/metadata-options.md | 3 + .../version-4.0/api/objects/metadata.md | 57 +++++ .../api/objects/playback-error-event.md | 9 + .../version-4.0/api/objects/playback-state.md | 8 + .../version-4.0/api/objects/player-options.md | 18 ++ .../version-4.0/api/objects/progress.md | 9 + .../version-4.0/api/objects/resource.md | 5 + .../version-4.0/api/objects/track.md | 29 +++ .../version-4.0/api/objects/update-options.md | 29 +++ .../version-4.0/basics/_category_.json | 4 + .../version-4.0/basics/background-mode.md | 69 ++++++ .../version-4.0/basics/getting-started.md | 226 ++++++++++++++++++ .../version-4.0/basics/installation.mdx | 74 ++++++ .../version-4.0/basics/platform-support.md | 99 ++++++++ .../version-4.0/basics/playback-service.md | 37 +++ .../version-4.0/guides/_category_.json | 4 + .../version-4.0/guides/amazon-fire-support.md | 63 +++++ .../version-4.0/guides/multitrack-progress.md | 130 ++++++++++ .../version-4.0/guides/offline-playback.md | 41 ++++ .../version-4.0/guides/play-button.md | 24 ++ .../version-4.0/guides/saving-progress.md | 35 +++ .../version-4.0/guides/sleeptimers.md | 20 ++ docs/versioned_docs/version-4.0/intro.md | 45 ++++ .../version-4.0/troubleshooting.md | 43 ++++ .../version-4.0/v2-migration.md | 60 +++++ .../version-4.0/v3-migration.md | 65 +++++ .../version-4.0/v3.1.0-migration.md | 26 ++ .../version-4.0/v4-migration.md | 77 ++++++ .../version-4.0-sidebars.json | 8 + docs/versions.json | 3 +- package.json | 2 +- react-native-track-player.podspec | 2 +- 56 files changed, 2390 insertions(+), 41 deletions(-) create mode 100644 docs/versioned_docs/version-4.0/api/_category_.json create mode 100644 docs/versioned_docs/version-4.0/api/constants/_category_.json create mode 100644 docs/versioned_docs/version-4.0/api/constants/app-killed-playback-behavior.md create mode 100644 docs/versioned_docs/version-4.0/api/constants/capability.md create mode 100644 docs/versioned_docs/version-4.0/api/constants/ios-category-mode.md create mode 100644 docs/versioned_docs/version-4.0/api/constants/ios-category-options.md create mode 100644 docs/versioned_docs/version-4.0/api/constants/ios-category.md create mode 100644 docs/versioned_docs/version-4.0/api/constants/pitch-algorithm.md create mode 100644 docs/versioned_docs/version-4.0/api/constants/rating.md create mode 100644 docs/versioned_docs/version-4.0/api/constants/repeat-mode.md create mode 100644 docs/versioned_docs/version-4.0/api/constants/state.md create mode 100644 docs/versioned_docs/version-4.0/api/events.md create mode 100644 docs/versioned_docs/version-4.0/api/functions/_category_.json create mode 100644 docs/versioned_docs/version-4.0/api/functions/lifecycle.md create mode 100644 docs/versioned_docs/version-4.0/api/functions/player.md create mode 100644 docs/versioned_docs/version-4.0/api/functions/queue.md create mode 100644 docs/versioned_docs/version-4.0/api/hooks.md create mode 100644 docs/versioned_docs/version-4.0/api/objects/_category_.json create mode 100644 docs/versioned_docs/version-4.0/api/objects/android-options.md create mode 100644 docs/versioned_docs/version-4.0/api/objects/feedback.md create mode 100644 docs/versioned_docs/version-4.0/api/objects/metadata-options.md create mode 100644 docs/versioned_docs/version-4.0/api/objects/metadata.md create mode 100644 docs/versioned_docs/version-4.0/api/objects/playback-error-event.md create mode 100644 docs/versioned_docs/version-4.0/api/objects/playback-state.md create mode 100644 docs/versioned_docs/version-4.0/api/objects/player-options.md create mode 100644 docs/versioned_docs/version-4.0/api/objects/progress.md create mode 100644 docs/versioned_docs/version-4.0/api/objects/resource.md create mode 100644 docs/versioned_docs/version-4.0/api/objects/track.md create mode 100644 docs/versioned_docs/version-4.0/api/objects/update-options.md create mode 100644 docs/versioned_docs/version-4.0/basics/_category_.json create mode 100644 docs/versioned_docs/version-4.0/basics/background-mode.md create mode 100644 docs/versioned_docs/version-4.0/basics/getting-started.md create mode 100644 docs/versioned_docs/version-4.0/basics/installation.mdx create mode 100644 docs/versioned_docs/version-4.0/basics/platform-support.md create mode 100644 docs/versioned_docs/version-4.0/basics/playback-service.md create mode 100644 docs/versioned_docs/version-4.0/guides/_category_.json create mode 100644 docs/versioned_docs/version-4.0/guides/amazon-fire-support.md create mode 100644 docs/versioned_docs/version-4.0/guides/multitrack-progress.md create mode 100644 docs/versioned_docs/version-4.0/guides/offline-playback.md create mode 100644 docs/versioned_docs/version-4.0/guides/play-button.md create mode 100644 docs/versioned_docs/version-4.0/guides/saving-progress.md create mode 100644 docs/versioned_docs/version-4.0/guides/sleeptimers.md create mode 100644 docs/versioned_docs/version-4.0/intro.md create mode 100644 docs/versioned_docs/version-4.0/troubleshooting.md create mode 100644 docs/versioned_docs/version-4.0/v2-migration.md create mode 100644 docs/versioned_docs/version-4.0/v3-migration.md create mode 100644 docs/versioned_docs/version-4.0/v3.1.0-migration.md create mode 100644 docs/versioned_docs/version-4.0/v4-migration.md create mode 100644 docs/versioned_sidebars/version-4.0-sidebars.json diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 105228f5d..3a01fc579 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -20,9 +20,9 @@ jobs: - name: Build Library run: yarn build - name: Extract Version - run: echo "LIB_VERSION=$(yarn info . version | head -2 | tail -1)" >> $GITHUB_ENV + run: echo "LIB_VERSION=$(cat package.json | jq -r .version)" >> $GITHUB_ENV - name: Set Nightly Version - run: yarn version --no-git-tag-version --no-commit-hooks --new-version ${{ env.LIB_VERSION }}-${{ github.sha }} + run: yarn version --no-git-tag-version --no-commit-hooks --new-version ${{ env.LIB_VERSION }}-nightly-${{ github.sha }} - uses: JS-DevTools/npm-publish@v1 with: token: ${{ secrets.NPM_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index a00e93922..012c1775c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# [4.0.0](https://github.com/doublesymmetry/react-native-track-player/compare/v4.0.0-rc09...v4.0.0) (2023-10-20) + +* **RN:** New metadata events have a new `metadata` property that contains the metadata that was received +* **android:** Fix: allow updating duration in notification metadata +* **ios:** Avoid prematurely activating audio session +* **android:** Fix: don't emit both PlaybackTrackChanged when queue ends (parity with iOS) +* **android:** Fix: allow progressUpdateEventInterval to be set to a decimal value (partial seconds) +* **android:** Support for setting grace period before stopForeground (defaults to 5 seconds) +* **ios:** Fix: updating rate will immediately reflect in control center +* **android** Fix: issue where loading a new track after end required seek to start +* **ios:** Fix: crash adding output when load is called too fast + # [4.0.0-rc09](https://github.com/doublesymmetry/react-native-track-player/compare/v4.0.0-rc08...v4.0.0-rc09) (2023-09-22) * **RN:** useIsPlaying hook now takes into account `none` state diff --git a/android/build.gradle b/android/build.gradle index 37b5e0962..046d09678 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -49,9 +49,9 @@ repositories { } dependencies { - implementation 'com.github.doublesymmetry:kotlinaudio:v2.0.0-rc17' + implementation 'com.github.doublesymmetry:kotlinaudio:v2.0.0' // used when building against local maven -// implementation "com.github.doublesymmetry:kotlin-audio:1.2.2" +// implementation "com.github.doublesymmetry:kotlin-audio:2.0.0" //noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" diff --git a/docs/docs/v4-migration.md b/docs/docs/v4-migration.md index b25b7cfb7..045675521 100644 --- a/docs/docs/v4-migration.md +++ b/docs/docs/v4-migration.md @@ -6,13 +6,18 @@ sidebar_position: 8 ### General Additions -1. [`getActiveTrackIndex()`](./api/functions/queue.md#getactivetrackindex) - Gets the index of the current track, or `undefined` if no track loaded. -1. [`getProgress()`](./api/functions/player.md#getprogress) - Returns progress, buffer and duration information. -1. [`getPlaybackState`](./api/functions/player.md#getplaybackstate) - Returns the current playback state. -1. [`Event.AudioChapterMetadataReceived`, `Event.AudioTimedMetadataReceived`, `Event.AudioCommonMetadataReceived`](./api/events.md#metadata): more detailed metadata events that are emitted when metadata is received from the native player. +1. **New Function:** [`getActiveTrackIndex()`](./api/functions/queue.md#getactivetrackindex) + - Description: Gets the index of the current track, or `undefined` if no track loaded. +2. **New Function:** [`getProgress()`](./api/functions/player.md#getprogress) + - Description: Returns progress, buffer and duration information. +3. **New Function:** [`getPlaybackState`](./api/functions/player.md#getplaybackstate) + - Description: Returns the current playback state. +4. New Events: [`Event.AudioChapterMetadataReceived`, `Event.AudioTimedMetadataReceived`, `Event.AudioCommonMetadataReceived`](./api/events.md#metadata) + - Description: More detailed metadata events that are emitted when metadata is received from the native player. +### General Changes -### `alwaysPauseOnInterruption` has been moved to [`AndroidOptions`](./api/objects/android-options.md) +- The configuration option `alwaysPauseOnInterruption` has been moved to the `android` section of options. ```diff await TrackPlayer.updateOptions({ @@ -23,47 +28,45 @@ await TrackPlayer.updateOptions({ } ``` -### `usePlaybackState` initially returns `undefined` +- On iOS, the pitch algorithm now defaults to `timeDomain` instead of `lowQualityZeroLatency`. The latter has been deprecated by Apple and has known issues on iOS 17. -Have the [`usePlaybackState()`](./api/hooks.md##useplaybackstate) hook will -return `{ state: undefined}` initially before it has finished retrieving the -current state. Before it was incorrectly returning -[`State.None`](./api/constants/state.md) which means no track is loaded. +### Hook Behavior Updates -### `remove()` supports removing current track -You can now remove the current track with `remove()`. This was not allowed before. -1. If the current track is removed, the next track will activated. -2. If the current track was the last track in the queue, the first track will be activated. +The [`usePlaybackState()`](./api/hooks.md##useplaybackstate) hook now initially returns `{ state: undefined }` before it has finished retrieving the current state. It previously returned [`State.None`](./api/constants/state.md), indicating no track loaded. -### `getTrack` return type +### Player Method Updates -[`getTrack()`](./api/functions/queue.md#gettrack) now returns `undefined` -instead of `null` +- The [`remove()`](./api/functions/queue.md#removeracks) function now supports removing the current track. If the current track is removed, the next track in the queue will be activated. If the current track was the last track in the queue, the first track will be activated. -### Player `State` Updates +The [`getTrack()`](./api/functions/queue.md#gettrack) function now returns `undefined` instead of `null`. -1. [`State.Error`](./api/constants/state.md) - Emitted when an error state is encountered. -1. [`State.Ended`](./api/constants/state.md) - State indicates playback stopped due to the end of the queue being reached. -1. [`State.Loading`](./api/constants/state.md) - State indicating the initial loading phase of a track. -1. [`State.Buffering`](./api/constants/state.md) - Now emitted no matter whether playback is paused or not. -1. [`State.Connecting`](./api/constants/state.md) - Deprecated. Please use `State.Loading` instead. +### Player State Updates +- New player states have been introduced and some updated +1. [`State.Error`](./api/constants/state.md) + - **New.** Emitted when an error state is encountered. +2. [`State.Ended`](./api/constants/state.md) + - **New.** State indicates playback stopped due to the end of the queue being reached. +3. [`State.Loading`](./api/constants/state.md) + - **New.** State indicating the initial loading phase of a track. +4. [`State.Buffering`](./api/constants/state.md) + - **Updated.** Now emitted no matter whether playback is paused or not. +5. [`State.Connecting`](./api/constants/state.md) + - **Deprecated.** Please use `State.Loading` instead. ### General Deprecations +- The following functions and events have been deprecated: 1. `getState()` - Please use the `state` property returned by [`getPlaybackState()`](./api/functions/player.md#getplaybackstate). -1. `getDuration()` - Please use the `duration` property returned by [`getProgress()`](./api/functions/player.md#getprogress). -1. `getPosition()` - Please use the `position` property returned by [`getProgress()`](./api/functions/player.md#getprogress). -1. `getBufferedPosition()` - Please use the `buffered` property returned by [`getProgress()`](./api/functions/player.md#getprogress). -1. `getCurrentTrack()` - Please use [`getActiveTrackIndex()`](./api/functions/queue.md#getactivetrackindex). -1. `Event.PlaybackTrackChanged` - Please use [`Event.PlaybackActiveTrackChanged`](./api/events.md#playbackactivetrackchanged). Also note that in 4.0 `Event.PlaybackTrackChanged` is no longer emitted when a track repeats. -1. `Event.PlaybackMetadataReceived` - Please use [`Event.AudioChapterMetadataReceived`, `Event.AudioTimedMetadataReceived`, `Event.AudioCommonMetadataReceived`](./api/events.md#metadata). - -### General Removals +2. `getDuration()` - Please use the `duration` property returned by [`getProgress()`](./api/functions/player.md#getprogress). +3. `getPosition()` - Please use the `position` property returned by [`getProgress()`](./api/functions/player.md#getprogress). +4. `getBufferedPosition()` - Please use the `buffered` property returned by [`getProgress()`](./api/functions/player.md#getprogress). +5. `getCurrentTrack()` - Please use [`getActiveTrackIndex()`](./api/functions/queue.md#getactivetrackindex). +6. `Event.PlaybackTrackChanged` - Please use [`Event.PlaybackActiveTrackChanged`](./api/events.md#playbackactivetrackchanged). Also note that in 4.0 `Event.PlaybackTrackChanged` is no longer emitted when a track repeats. +7. `Event.PlaybackMetadataReceived` - Please use [`Event.AudioChapterMetadataReceived`, `Event.AudioTimedMetadataReceived`, `Event.AudioCommonMetadataReceived`](./api/events.md#metadata). -1. `clearMetadata()` - Instead use [`reset()`](./api/functions/player.md#reset) - which stops playback, clears the queue and clears the notification. +### Removals -### General Changes -1. on iOS pitch algorithm defaults to `timeDomain` instead of `lowQualityZeroLatency`. It has been deprecated by Apple and has a few bugs on iOS 17. +- The clearMetadata() function has been removed. Instead, use [`reset()`](./api/functions/player.md#reset), which stops playback, clears the queue, and clears the notification. ### Typescript Imports diff --git a/docs/versioned_docs/version-4.0/api/_category_.json b/docs/versioned_docs/version-4.0/api/_category_.json new file mode 100644 index 000000000..7e1d1665e --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "API Reference", + "position": 3 +} diff --git a/docs/versioned_docs/version-4.0/api/constants/_category_.json b/docs/versioned_docs/version-4.0/api/constants/_category_.json new file mode 100644 index 000000000..ecb869734 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/constants/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Constants", + "position": 4 +} diff --git a/docs/versioned_docs/version-4.0/api/constants/app-killed-playback-behavior.md b/docs/versioned_docs/version-4.0/api/constants/app-killed-playback-behavior.md new file mode 100644 index 000000000..6819fc645 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/constants/app-killed-playback-behavior.md @@ -0,0 +1,25 @@ +--- +sidebar_position: 6 +--- + +# App Killed Playback Behavior (android-only) + +```ts +import { AppKilledPlaybackBehavior } from 'react-native-track-player'; +``` + +## `ContinuePlayback` (default) + +This option will continue playing audio in the background when the app is +removed from recents. The notification remains. This is the default. + +## `PausePlayback` + +This option will pause playing audio in the background when the app is removed +from recents. The notification remains and can be used to resume playback. + +## `StopPlaybackAndRemoveNotification` + +This option will stop playing audio in the background when the app is removed +from recents. The notification is removed and can't be used to resume playback. +Users would need to open the app again to start playing audio. diff --git a/docs/versioned_docs/version-4.0/api/constants/capability.md b/docs/versioned_docs/version-4.0/api/constants/capability.md new file mode 100644 index 000000000..0dca7188f --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/constants/capability.md @@ -0,0 +1,29 @@ +--- +sidebar_position: 2 +--- + +# Capability + +All Capability types are made available through the named export `Capability`: + +```ts +import { Capability } from 'react-native-track-player'; +``` + +| Name | Description | +|------|-------------| +| `Play` | Capability indicating the ability to play | +| `PlayFromId` | Capability indicating the ability to play from a track id (Required for Android Auto) | +| `PlayFromSearch` | Capability indicating the ability to play from a text/voice search (Required for Android Auto) | +| `Pause` | Capability indicating the ability to pause | +| `Stop` | Capability indicating the ability to stop (on iOS available only for tracks where `.isLiveStream` is `true`) | +| `SeekTo` | Capability indicating the ability to seek to a position in the timeline | +| `Skip` | Capability indicating the ability to skip to any song in the queue | +| `SkipToNext` | Capability indicating the ability to skip to the next track | +| `SkipToPrevious` | Capability indicating the ability to skip to the previous track | +| `SetRating` | Capability indicating the ability to set the rating value based on the rating type | +| `JumpForward` | Capability indicating the ability to jump forward by the amount of seconds specified in the options | +| `JumpBackward` | Capability indicating the ability to jump backward by the amount of seconds specified in the options | +| `Like` | (ios-only) Capability indicating the ability to like from control center | +| `Dislike` | (ios-only) Capability indicating the ability to dislike from control center | +| `Bookmark` | (ios-only) Capability indicating the ability to bookmark from control center | diff --git a/docs/versioned_docs/version-4.0/api/constants/ios-category-mode.md b/docs/versioned_docs/version-4.0/api/constants/ios-category-mode.md new file mode 100644 index 000000000..80c245323 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/constants/ios-category-mode.md @@ -0,0 +1,67 @@ +--- +sidebar_position: 7 +--- + +# iOS Category Mode (ios-only) + +All iOS Category Mode types are made available through the named export `IOSCategoryMode`: + +## `Default` + +The default audio session mode. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/mode/1616579-default) + +## `GameChat` + +A mode that the GameKit framework sets on behalf of an application that +uses GameKit’s voice chat service. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/mode/1616511-gamechat) + + +## `Measurement` + +A mode that indicates that your app is performing measurement of audio +input or output. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/mode/1616608-measurement) + +## `MoviePlayback` + +A mode that indicates that your app is playing back movie content. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/mode/1616623-movieplayback) + +## `SpokenAudio` + +A mode used for continuous spoken audio to pause the audio when another +app plays a short audio prompt. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/mode/1616510-spokenaudio) + +## `VideoChat` + +A mode that indicates that your app is engaging in online video conferencing. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/mode/1616590-videochat) + +## `VideoRecording` + +A mode that indicates that your app is recording a movie. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/mode/1616535-videorecording) + +## `VoiceChat` + +A mode that indicates that your app is performing two-way voice communication, +such as using Voice over Internet Protocol (VoIP). + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/mode/1616455-voicechat) + + +## `VoicePrompt` + +A mode that indicates that your app plays audio using text-to-speech. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/mode/2962803-voiceprompt) diff --git a/docs/versioned_docs/version-4.0/api/constants/ios-category-options.md b/docs/versioned_docs/version-4.0/api/constants/ios-category-options.md new file mode 100644 index 000000000..8b0c7df70 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/constants/ios-category-options.md @@ -0,0 +1,60 @@ +--- +sidebar_position: 8 +--- + +# iOS Category Options (ios-only) + +All iOS Category Options types are made available through the named export `IOSCategoryOptions`: + +```ts +import { IOSCategoryOptions } from 'react-native-track-player'; +``` + +## `MixWithOthers` + +An option that indicates whether audio from this session mixes with audio +from active sessions in other audio apps. + +[See the Apple Docs ](https://developer.apple.com/documentation/avfaudio/avaudiosession/categoryoptions/1616611-mixwithothers) + +## `DuckOthers` + +An option that reduces the volume of other audio sessions while audio from +this session plays. + +[See the Apple Docs ](https://developer.apple.com/documentation/avfaudio/avaudiosession/categoryoptions/1616618-duckothers) + +## `InterruptSpokenAudioAndMixWithOthers` + +An option that determines whether to pause spoken audio content from other +sessions when your app plays its audio. + +[See the Apple Docs ](https://developer.apple.com/documentation/avfaudio/avaudiosession/categoryoptions/1616534-interruptspokenaudioandmixwithot) + +## `AllowBluetooth` + +An option that determines whether Bluetooth hands-free devices appear as +available input routes. + +[See the Apple Docs ](https://developer.apple.com/documentation/avfaudio/avaudiosession/categoryoptions/1616518-allowbluetooth) + +## `AllowBluetoothA2DP` + +An option that determines whether you can stream audio from this session +to Bluetooth devices that support the Advanced Audio Distribution Profile (A2DP). + +[See the Apple Docs ](https://developer.apple.com/documentation/avfaudio/avaudiosession/categoryoptions/1771735-allowbluetootha2dp) + +## `AllowAirPlay` + +An option that determines whether you can stream audio from this session +to AirPlay devices. + +[See the Apple Docs ](https://developer.apple.com/documentation/avfaudio/avaudiosession/categoryoptions/1771736-allowairplay) + +## `DefaultToSpeaker` + +An option that determines whether audio from the session defaults to the +built-in speaker instead of the receiver. + +[See the Apple Docs ](https://developer.apple.com/documentation/avfaudio/avaudiosession/categoryoptions/1616462-defaulttospeaker) diff --git a/docs/versioned_docs/version-4.0/api/constants/ios-category.md b/docs/versioned_docs/version-4.0/api/constants/ios-category.md new file mode 100644 index 000000000..fc7ed6e20 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/constants/ios-category.md @@ -0,0 +1,52 @@ +--- +sidebar_position: 6 +--- + +# iOS Category (ios-only) + +All iOS Category types are made available through the named export `IOSCategory`: + +```ts +import { IOSCategory } from 'react-native-track-player'; +``` + +## `Playback` + +The category for playing recorded music or other sounds that are central to the +successful use of your app. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/category/1616509-playback) + + +## `PlayAndRecord` + +The category for recording (input) and playback (output) of audio, such as for a +Voice over Internet Protocol (VoIP) app. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/category/1616568-playandrecord) + +## `MultiRoute` + +The category for routing distinct streams of audio data to different output +devices at the same time. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/category/1616484-multiroute) + +## `Ambient` + +The category for an app in which sound playback is nonprimary — that is, your +app also works with the sound turned off. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/category/1616560-ambient) + +## `SoloAmbient` + +The default audio session category. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/category/1616488-soloambient) + +## `Record` + +The category for recording audio while also silencing playback audio. + +[See the Apple Docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/category/1616451-record) diff --git a/docs/versioned_docs/version-4.0/api/constants/pitch-algorithm.md b/docs/versioned_docs/version-4.0/api/constants/pitch-algorithm.md new file mode 100644 index 000000000..f4e5ee163 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/constants/pitch-algorithm.md @@ -0,0 +1,17 @@ +--- +sidebar_position: 5 +--- + +# Pitch Algorithm (ios-only) + +All PitchAlgorithm types are made available through the named export `PitchAlgorithm`: + +```ts +import { PitchAlgorithm } from 'react-native-track-player'; +``` + +| Name | Description | +|------|-------------| +| `Linear` | An algorithm suitable for general use. | +| `Music` | An algorithm suitable for music. | +| `Voice` | An algorithm suitable for voice. | diff --git a/docs/versioned_docs/version-4.0/api/constants/rating.md b/docs/versioned_docs/version-4.0/api/constants/rating.md new file mode 100644 index 000000000..b14b5a65a --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/constants/rating.md @@ -0,0 +1,20 @@ +--- +sidebar_position: 3 +--- + +# Rating + +All RatingType types are made available through the named export `RatingType`: + +```ts +import { RatingType } from 'react-native-track-player'; +``` + +| Name | Description | +|------|-------------| +| `Heart` | Rating type indicating "with heart" or "without heart", its value is a `boolean`. | +| `ThumbsUpDown` | Rating type indicating "thumbs up" or "thumbs down", its value is a `boolean`. | +| `ThreeStars` | Rating type indicating 0 to 3 stars, its value is a `number` of stars. | +| `FourStars` | Rating type indicating 0 to 4 stars, its value is a `number` of stars. | +| `FiveStars` | Rating type indicating 0 to 5 stars, its value is a `number` of stars. | +| `Percentage` | Rating type indicating percentage, its value is a `number`. | diff --git a/docs/versioned_docs/version-4.0/api/constants/repeat-mode.md b/docs/versioned_docs/version-4.0/api/constants/repeat-mode.md new file mode 100644 index 000000000..b3e0864a5 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/constants/repeat-mode.md @@ -0,0 +1,17 @@ +--- +sidebar_position: 4 +--- + +# Repeat Mode + +All RepeatMode types are made available through the named export `RepeatMode`: + +```ts +import { RepeatMode } from 'react-native-track-player'; +``` + +| Name | Description | +|------|-------------| +| `Off` | Doesn't repeat. | +| `Track` | Loops the current track. | +| `Queue` | Repeats the whole queue. | diff --git a/docs/versioned_docs/version-4.0/api/constants/state.md b/docs/versioned_docs/version-4.0/api/constants/state.md new file mode 100644 index 000000000..58d014fba --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/constants/state.md @@ -0,0 +1,24 @@ +--- +sidebar_position: 1 +--- + +# State + +All State types are made available through the named export `State`: + +```ts +import { State } from 'react-native-track-player'; +``` + +| Name | Description | +|------|-------------| +| `None` | State indicating that no media is currently loaded | +| `Ready` | State indicates that the player is paused, but ready to start playing | +| `Playing` | State indicating that the player is currently playing | +| `Paused` | State indicating that the player is currently paused | +| `Stopped` | State indicating that the player is currently stopped | +| `Ended` | State indicates playback stopped due to the end of the queue being reached | +| `Buffering` | State indicating that the player is currently buffering (no matter whether playback is paused or not) | +| `Loading` | State indicating the initial loading phase of a track | +| `Error` | State indicating that the player experienced a playback error causing the audio to stop playing (or not start playing). When in `State.Error`, calling `play()` reloads the current track and seeks to its last known time. | +| `Connecting` | **⚠️ Deprecated**. Please use `State.Loading` instead. State indicating that the player is currently buffering (in "pause" state) | diff --git a/docs/versioned_docs/version-4.0/api/events.md b/docs/versioned_docs/version-4.0/api/events.md new file mode 100644 index 000000000..dc04069d5 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/events.md @@ -0,0 +1,222 @@ +--- +sidebar_position: 1 +--- + +# Events + +All event types are made available through the named export `Event`: + +```ts +import { Event } from 'react-native-track-player'; +``` + +## Player + +### `PlaybackState` +Fired when the state of the player changes. + +| Param | Type | Description | +| ----- | -------- | ------------- | +| state | [State](./constants/state.md) | The new state | + +### `PlaybackActiveTrackChanged` + +The new event also includes the full track objects for the newly active and last tracks. + +| Param | Type | Description | +| -------- | -------- | ----------------------------------------- | +| lastIndex | `number` \| `undefined` | The index of previously active track. | +| lastTrack | `Track` \| `undefined` | The previously active track or `undefined` when there wasn't a previously active track. | +| lastPosition | `number` | The position of the previously active track in seconds.| +| index | `number` \| `undefined` | The newly active track index or `undefined` if there is no longer an active track.| +| track | `Track` \| `undefined` | The newly active track or `undefined` if there is no longer an active track.| + +### `PlaybackQueueEnded` +Fired when the queue reaches the end. + +| Param | Type | Description | +| -------- | -------- | ----------------------------------------- | +| track | `number` | The previous track index. Might be null | +| position | `number` | The previous track position in seconds | + +### `PlaybackMetadataReceived` + +**⚠️ Deprecated:** Please use `AudioChapterMetadataReceived`, `AudioTimedMetadataReceived`, `AudioCommonMetadataReceived`. + +Fired when the current track receives metadata encoded in. (e.g. ID3 tags, Icy Metadata, Vorbis Comments or QuickTime metadata). + +| Param | Type | Description | +| -------- | -------- | --------------------------------------------------- | +| source | `string` | The metadata source (`id3`, `icy`, `icy-headers`, `vorbis-comment`, `quicktime`) | +| title | `string` | The track title. Might be null | +| url | `string` | The track url. Might be null | +| artist | `string` | The track artist. Might be null | +| album | `string` | The track album. Might be null | +| date | `string` | The track date. Might be null | +| genre | `string` | The track genre. Might be null | + +### `PlaybackProgressUpdated` + +⚠️ Note: This event is only emitted if you specify a non-zero `progressUpdateEventInterval` value in your player options. + +Fired at the `progressUpdateEventInterval` if the player is playing _and_ if a `progressUpdateEventInterval` has been specified. + +| Param | Type | Description | +| ----------- | -------- | ----------------- | +| position | `number` | See [`getProgress`](./functions/player.md#getProgress) | +| duration | `number` | See [`getProgress`](./functions/player.md#getProgress) | +| buffered | `number` | See [`getProgress`](./functions/player.md#getProgress) | +| track | `number` | The current index in the queue of the track. | + +### `PlaybackError` +Fired when an error occurs. + +| Param | Type | Description | +| ------- | -------- | ----------------- | +| code | `string` | The error code | +| message | `string` | The error message | + +### `PlaybackPlayWhenReadyChanged` + +Fired when the `playWhenReady` property is changed. + +| Param | Type | Description | +| ------------- | -------- | ------------------------------------- | +| playWhenReady | `boolean` | The current value of `playWhenReady` | + +### ⚠️`PlaybackTrackChanged` + +**⚠️ Deprecated:** Please use `PlaybackActiveTrackChanged`. + +Fired when a track is changed. + +| Param | Type | Description | +| --------- | -------- | --------------------------------------- | +| track | `number` | The previous track index. Might be null | +| position | `number` | The previous track position in seconds | +| nextTrack | `number` | The next track index. Might be null | + +---- + +## Media Controls + +### `RemotePlay` +Fired when the user presses the play button. Only fired if the [`Capability.Play`](./constants/capability.md) is allowed. + +### `RemotePlayId` +Fired when the user selects a track from an external device. Required for Android Auto support. Only fired if the [`Capability.PlayFromId`](./constants/capability.md) is allowed. + +| Param | Type | Description | +| ----- | -------- | ------------- | +| id | `string` | The track id | + +### `RemotePlaySearch` +Fired when the user searches for a track (usually voice search). Required for Android Auto support. Only fired if the [`Capability.PlayFromSearch`](./constants/capability.md) is allowed. + +Every parameter except `query` is optional and may not be provided. +In the case where `query` is empty, feel free to select any track to play. + +| Param | Type | Description | +| -------- | -------- | ------------- | +| query | `string` | The search query | +| focus | `string` | The focus of the search. One of `artist`, `album`, `playlist` or `genre` | +| title | `string` | The track title | +| artist | `string` | The track artist | +| album | `string` | The track album | +| genre | `string` | The track genre | +| playlist | `string` | The track playlist | + +### `RemotePause` +Fired when the user presses the pause button. Only fired if the [`Capability.Pause`](./constants/capability.md) is allowed or if there's a change in outputs (e.g.: headphone disconnected). + +### `RemoteStop` +Fired when the user presses the stop button. Only fired if the [`Capability.Stop`](./constants/capability.md) is allowed. + +### `RemoteSkip` +Fired when the user skips to a track in the queue. Only fired if the [`Capability.Skip`](./constants/capability.md) is allowed. + +| Param | Type | Description | +| ----- | -------- | ------------- | +| index | `number` | The track index | + +### `RemoteNext` +Fired when the user presses the next track button. Only fired if the [`Capability.SkipToNext`](./constants/capability.md) is allowed. + +### `RemotePrevious` +Fired when the user presses the previous track button. Only fired if the [`Capability.SkipToPrevious`](./constants/capability.md) is allowed. + +### `RemoteSeek` +Fired when the user changes the position of the timeline. Only fired if the [`Capability.SeekTo`](./constants/capability.md) is allowed. + +| Param | Type | Description | +| -------- | -------- | ------------- | +| position | `number` | The position to seek to in seconds | + +### `RemoteSetRating` +Fired when the user changes the rating for the track. Only fired if the [`Capability.SetRating`](./constants/capability.md) is allowed. + +| Param | Type | Description | +| ------ | -------- | ------------- | +| rating | Depends on the [Rating Type](./constants/rating.md) | The rating that was set | + +### `RemoteJumpForward` +Fired when the user presses the jump forward button. Only fired if the [`Capability.JumpForward`](./constants/capability.md) is allowed. + +| Param | Type | Description | +| -------- | -------- | ------------- | +| interval | `number` | The number of seconds to jump forward. It's usually the `forwardJumpInterval` set in the options. | + +### `RemoteJumpBackward` +Fired when the user presses the jump backward button. Only fired if the [`Capability.JumpBackward`](./constants/capability.md) is allowed. + +| Param | Type | Description | +| -------- | -------- | ------------- | +| interval | `number` | The number of seconds to jump backward. It's usually the `backwardJumpInterval` set in the options. | + +### `RemoteLike` (iOS only) +Fired when the user presses the like button in the now playing center. Only fired if the `likeOptions` is set in `updateOptions`. + +### `RemoteDislike` (iOS only) +Fired when the user presses the dislike button in the now playing center. Only fired if the `dislikeOptions` is set in `updateOptions`. + +### `RemoteBookmark` (iOS only) +Fired when the user presses the bookmark button in the now playing center. Only fired if the `bookmarkOptions` is set in `updateOptions`. + +### `RemoteDuck` +Fired when the audio is interrupted. For example when a phone call arrives, +a clock or calender sounds, or another app starts playing audio. + +We recommend to set `autoHandleInterruptions: true` in +`TrackPlayer.setupPlayer`. This way toggling playback is handled automatically. + +By default `autoHandleInterruptions` is set to `false` (default) in +`TrackPlayer.setupPlayer`, which means your app is expected to respond to this +event in the following situations: +- When the event is triggered with `paused` set to `true`, on Android playback + should be paused. When `permanent` is also set to `true`, on Android the + player should stop playback. +- When the event is triggered and `paused` is set to `false`, the player may + resume playback. + +| Param | Type | Description | +| --------- | --------- | -------------------------------------------- | +| paused | `boolean` | On Android when `true` the player should pause playback, when `false` the player may resume playback. On iOS when `true` the playback was paused and when `false` the player may resume playback. | +| permanent | `boolean` | Whether the interruption is permanent. On Android the player should stop playback. | + + +## Metadata + +### `AudioCommonMetadataReceived` +Fired when the current track receives metadata encoded in - static metadata not tied to a time. Usually received at start. + +Received data will be [`AudioCommonMetadataReceivedEvent`](./api/objects/metadata.md). + +### `AudioTimedMetadataReceived` +Fired when the current track receives metadata encoded in - dynamic metadata tied to a time. Events may be emitted over time. + +Received data will be [`AudioMetadataReceivedEvent`](./api/objects/metadata.md). + +### `AudioChapterMetadataReceived` (iOS only) +Fired when the current track receives metadata encoded in - chapter overview data. Usually received at start. + +Received data will be [`AudioMetadataReceivedEvent`](./api/objects/metadata.md). diff --git a/docs/versioned_docs/version-4.0/api/functions/_category_.json b/docs/versioned_docs/version-4.0/api/functions/_category_.json new file mode 100644 index 000000000..997823791 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/functions/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Functions", + "position": 1 +} diff --git a/docs/versioned_docs/version-4.0/api/functions/lifecycle.md b/docs/versioned_docs/version-4.0/api/functions/lifecycle.md new file mode 100644 index 000000000..70419ed66 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/functions/lifecycle.md @@ -0,0 +1,46 @@ +# Lifecycle + +## `setupPlayer(options: PlayerOptions)` + +Initializes the player with the specified options. These options do not apply to all platforms, see chart below. + +These options are different than the ones set using `updateOptions()`. Options other than those listed below will not be applied. + +You should always call this function (even without any options set) before using the player to make sure everything is initialized. Do not call this more than once in the lifetime of your app. + +Note that on Android this method must only be called while the app is in the foreground, otherwise it will throw an error with code `'android_cannot_setup_player_in_background'`. In this case you can wait for the app to be in the foreground and try again. + +**Returns:** `Promise` + +| Param | Type | Description | Default | Android | iOS | Windows | +| -------------------- | -------- | ------------- | --------- | :-----: | :-: | :-----: | +| options | `PlayerOptions` | The options | +| options.minBuffer | `number` | Minimum time in seconds that needs to be buffered | 15 (android), automatic (ios) | ✅ | ✅ | ❌ | +| options.maxBuffer | `number` | Maximum time in seconds that needs to be buffered | 50 | ✅ | ❌ | ❌ | +| options.playBuffer | `number` | Minimum time in seconds that needs to be buffered to start playing | 2.5 | ✅ | ❌ | ❌ | +| options.backBuffer | `number` | Time in seconds that should be kept in the buffer behind the current playhead time. | 0 | ✅ | ❌ | ❌ | +| options.maxCacheSize | `number` | Maximum cache size in kilobytes | 0 | ✅ | ❌ | ❌ | +| options.androidAudioContentType | `AndroidAudioContentType` | The audio content type indicates to the android system how you intend to use audio in your app. | `AndroidAudioContentType.Music` | ✅ | ❌ | ❌ | +| options.iosCategory | `IOSCategory` | [AVAudioSession.Category](https://developer.apple.com/documentation/avfoundation/avaudiosession/1616615-category) for iOS. Sets on `play()` | `IOSCategory.Playback` | ❌ | ✅ | ❌ | +| options.iosCategoryOptions | `IOSCategoryOptions[]` | [AVAudioSession.CategoryOptions](https://developer.apple.com/documentation/avfoundation/avaudiosession/1616503-categoryoptions) for iOS. Sets on `play()` | `[]` | ❌ | ✅ | ❌ | +| options.iosCategoryMode | `IOSCategoryMode` | [AVAudioSession.Mode](https://developer.apple.com/documentation/avfoundation/avaudiosession/1616508-mode) for iOS. Sets on `play()` | `default` | ❌ | ✅ | ❌ | +| options.autoHandleInterruptions | `boolean` | Indicates whether the player should automatically handle audio interruptions. | false | ✅ | ✅ | ❌ | +| options.autoUpdateMetadata | `boolean` | Indicates whether the player should automatically update now playing metadata data in control center / notification. | true | ✅ | ✅ | ❌ | + +## `registerPlaybackService(serviceProvider)` + +Register the playback service. The service will run as long as the player runs. + +This function should only be called once, and should be registered right after registering your React application with `AppRegistry`. + +You should use the playback service to register the event handlers that must be directly tied to the player, as the playback service might keep running when the app is in background. + +| Param | Type | Description | +| ------- | -------- | ------------- | +| serviceProvider | `function` | The function that must return an async service function. | + +## `useTrackPlayerEvents(events: Event[], handler: Handler)` + +Hook that fires on the specified events. + +You can find a list of events in the [events section](../events.md#player). diff --git a/docs/versioned_docs/version-4.0/api/functions/player.md b/docs/versioned_docs/version-4.0/api/functions/player.md new file mode 100644 index 000000000..29684b6af --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/functions/player.md @@ -0,0 +1,152 @@ +# Player + +## `setupPlayer(options)` + +Accepts a [`PlayerOptions`](../objects/player-options.md) object. + +## `updateOptions(options)` + +Accepts a [`UpdateOptions`](../objects/update-options.md) object. Updates +the configuration for the components. + + +⚠️ These parameters are different than the ones set using `setupPlayer()`. +Parameters other than those listed below will not be applied. + +## `play()` + +Plays or resumes the current track. + +## `pause()` + +Pauses the current track. + +## `stop()` + +Stops playback. Behavior is the same as `TrackPlayer.pause()` where +`playWhenReady` becomes `false`, but instead of just pausing playback, the item +is unloaded. + +This function causes any further loading / buffering to stop. + +## `retry()` + +Retries the current track when it stopped playing due to a playback error. + +## `seekBy(offset)` + +Seeks by a relative time offset in the current track. + +| Param | Type | Description | +| ------- | -------- | ----------------------- | +| offset | `number` | The offset in seconds | + +**Returns:** `Promise` + +## `seekTo(seconds)` + +Seeks to a specified time position in the current track. + +| Param | Type | Description | +| ------- | -------- | ----------------------- | +| seconds | `number` | The position in seconds | + +**Returns:** `Promise` + +## `setVolume(volume)` + +Sets the volume of the player. + +| Param | Type | Description | +| ------ | -------- | --------------------------------- | +| volume | `number` | The volume in a range from 0 to 1 | + +**Returns:** `Promise` + +## `getVolume()` + +Gets the volume of the player (a number between 0 and 1). + +**Returns:** `Promise` + +## `setRate(rate)` +Sets the playback rate + +| Param | Type | Description | +| ------ | -------- | --------------------------------- | +| rate | `number` | The playback rate where 1 is the regular speed | + +**Note:** If your rate is high, e.g. above 2, you may want to set the track's `pitchAlgorithm` to something like `PitchAlgorithm.Voice`, or else the default pitch algorithm (which in `SwiftAudioEx` drops down to `AVAudioTimePitchAlgorithm.lowQualityZeroLatency`) will likely +drop words in your audio. + +## `getRate()` + +Gets the playback rate, where 1 is the regular speed. + +**Returns:** `Promise` + +## `getProgress()` + +Gets the playback [`Progress`](../objects/progress.md) of the active track. + +**Returns:** `Promise<`[Progress](../objects/progress.md)`>` + +## `getPlaybackState()` + +Gets the [`PlaybackState`](../objects/playback-state.md) of the player. + +**Returns:** `Promise<`[PlaybackState](../objects/playback-state.md)`>` + +## `getPlayWhenReady()` + +Gets the current state of `playWhenReady`. + +**Returns:** `Promise` + +## `setPlayWhenReady(playWhenReady)` + +`TrackPlayer.setPlayWhenReady(false)` is the equivalent of `TrackPlayer.pause()` +and `TrackPlayer.setPlayWhenReady(true)` is the equivalent of +`TrackPlayer.play()`. + +| Param | Type | Description | +| ------ | -------- | --------------------------------- | +| playWhenReady | `boolean` | A boolean representing if you want `playWhenReady` set or not. | + +## ⚠️ `getState()` + +**⚠️ Deprecated** + +Gets the playback [`State`](../constants/state.md) of the player. + +**Returns:** `Promise<`[State](../constants/state.md)`>` + + +## ⚠️ `getDuration()` + +**⚠️ Deprecated** + +Gets the duration of the current track in seconds. + +Note: `react-native-track-player` is a streaming library, which means it slowly buffers the track and doesn't know exactly when it ends. +The duration returned by this function is determined through various tricks and *may not be exact or may not be available at all*. + +You should only trust the result of this function if you included the `duration` property in the [Track Object](../objects/track.md). + +**Returns:** `Promise` + +## ⚠️ `getPosition()` + +**⚠️ Deprecated** + +Gets the position of the current track in seconds. + +**Returns:** `Promise` + +## ⚠️ `getBufferedPosition()` + +**⚠️ Deprecated** + +Gets the buffered position of the current track in seconds. + +**Returns:** `Promise` diff --git a/docs/versioned_docs/version-4.0/api/functions/queue.md b/docs/versioned_docs/version-4.0/api/functions/queue.md new file mode 100644 index 000000000..3eaac7bd6 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/functions/queue.md @@ -0,0 +1,143 @@ +# Queue + +## `add(tracks, insertBeforeIndex)` +Adds one or more tracks to the queue. + +**Returns:** `Promise` - The promise resolves with the first +added track index. If no tracks were added it returns `void`. + +| Param | Type | Description | +| -------------- | -------- | ------------- | +| tracks | `Track \| Track[]` | The [Track](../objects/track.md) objects that will be added | +| insertBeforeIndex | `number` | The index of the track that will be located immediately after the inserted tracks. Set it to `null` to add it at the end of the queue | + +## `remove(tracks)` +Removes one or more tracks from the queue. If the current track is removed, the next track will activated. If the current track was the last track in the queue, the first track will be activated. + +**Returns:** `Promise` + +| Param | Type | Description | +|--------|-------------------|-------------| +| tracks | `Track \| Track[]` | The [Track](../objects/track.md) objects that will be removed | + +## `setQueue(tracks)` + +Clears the current queue and adds the supplied tracks to the now empty queue. + +**Returns:** `Promise` + +| Param | Type | Description | +|--------|-------------------|-------------| +| tracks | `Track[]` | An array of [Track](../objects/track.md) to replace the current queue with. | + +## `load(track)` + +Replaces the current track with the supplied track or creates a track when the queue is empty. + +| Param | Type | Description | +|--------|-------------------|-------------| +| track | `Track` | The [Track](../objects/track.md) object that will be loaded | + +## `skip(index, initialPosition)` +Skips to a track in the queue. + +**Returns:** `Promise` + +| Param | Type | Description | +| ------ | -------- | --------------- | +| index | `number` | The track index | +| initialPosition | `number` | **Optional.** Sets the initial playback for the track you're skipping to. | + +## `skipToNext(initialPosition)` +Skips to the next track in the queue. + +**Returns:** `Promise` + +| Param | Type | Description | +| ------ | -------- | --------------- | +| initialPosition | `number` | **Optional.** Sets the initial playback for the track you're skipping to. | + +## `skipToPrevious(initialPosition)` +Skips to the previous track in the queue. + +**Returns:** `Promise` + +| Param | Type | Description | +| ------ | -------- | --------------- | +| initialPosition | `number` | **Optional.** Sets the initial playback for the track you're skipping to. | + +## `move(fromIndex, toIndex)` + +Moves a track from the specified index to another. + +| Param | Type | Description | +| ------ | -------- | --------------- | +| fromIndex | `number` | The index of the track you'd like to move. | +| toIndex | `number` | The position you'd like to move the track to. | + + +## `reset()` +Resets the player stopping the current track and clearing the queue. + +## `getTrack(index)` +Gets a track object from the queue. + +**Returns:** `Promise<`[Track](../objects/track.md)`>` + +| Param | Type | Description | +| -------- | ---------- | --------------- | +| index | `number` | The track index | + +## `getActiveTrack()` + +Gets the active track object. + +**Returns:** `Promise<`[Track](../objects/track.md)` | undefined>` + +## `getActiveTrackIndex()` + +Gets the index of the current track, or `undefined` if no track loaded + +**Returns:** `Promise` + +## `getQueue()` +Gets the whole queue + +**Returns:** `Promise<`[Track[]](../objects/track.md)`>` + +## `removeUpcomingTracks()` +Clears any upcoming tracks from the queue. + +## `updateMetadataForTrack(index, metadata)` +Updates the metadata of a track in the queue. +If the current track is updated, the notification and the Now Playing Center will be updated accordingly. + +**Returns:** `Promise` + +| Param | Type | Description | +| -------- | ---------- | ------------- | +| index | `number` | The track index | +| metadata | `object` | A subset of the [Track Object](../objects/track.md) with only the `artwork`, `title`, `artist`, `album`, `description`, `genre`, `date`, `rating` and `duration` properties. | + +## `setRepeatMode(mode)` +Sets the repeat mode. + +| Param | Type | Description | +| -------- | ---------- | --------------- | +| mode | [Repeat Mode](../constants/repeat-mode.md) | The repeat mode | + +## `getRepeatMode()` +Gets the repeat mode. + +**Returns:** [Repeat Mode](../constants/repeat-mode.md) + +## ⚠️ `getCurrentTrack()` + +**⚠️ Deprecated:** To get the active track index use +[`getActiveTrackIndex()`](#getactivetrackindex) instead or use +[`getActiveTrack()`](#getactivetrack) to get the active track object. + +Gets the index of the current track, or null if no track loaded + +**Returns:** `Promise` + diff --git a/docs/versioned_docs/version-4.0/api/hooks.md b/docs/versioned_docs/version-4.0/api/hooks.md new file mode 100644 index 000000000..4df247584 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/hooks.md @@ -0,0 +1,105 @@ +--- +sidebar_position: 3 +--- + +# Hooks + +React v16.8 introduced [hooks](https://reactjs.org/docs/hooks-intro.html). If you are using a version of React Native that is before [v0.59.0](https://reactnative.dev/blog/2019/03/12/releasing-react-native-059), your React Native version does not support hooks. + +## `useTrackPlayerEvents` + +Register an event listener for one or more of the [events](./events.md) emitted by the TrackPlayer. The subscription is removed when the component unmounts. + +Check out the [events section](./events.md) for a full list of supported events. + +```tsx +import React, { useState } from 'react'; +import { Text, View } from 'react-native'; +import { useTrackPlayerEvents, Event, State } from 'react-native-track-player'; + +// Subscribing to the following events inside MyComponent +const events = [ + Event.PlaybackState, + Event.PlaybackError, +]; + +const MyComponent = () => { + const [playerState, setPlayerState] = useState(null) + + useTrackPlayerEvents(events, (event) => { + if (event.type === Event.PlaybackError) { + console.warn('An error occured while playing the current track.'); + } + if (event.type === Event.PlaybackState) { + setPlayerState(event.state); + } + }); + + const isPlaying = playerState === State.Playing; + + return ( + + The TrackPlayer is {isPlaying ? 'playing' : 'not playing'} + + ); +}; +``` + +## `useProgress` + +| State | Type | Description | +| ---------------- | -------- | -------------------------------- | +| position | `number` | The current position in seconds | +| buffered | `number` | The buffered position in seconds | +| duration | `number` | The duration in seconds | + +`useProgress` accepts an interval to set the rate (in miliseconds) to poll the track player's progress. The default value is `1000` or every second. + +```tsx +import React from 'react'; +import { Text, View } from 'react-native'; +import { useProgress } from 'react-native-track-player'; + +const MyComponent = () => { + const { position, buffered, duration } = useProgress() + + return ( + + Track progress: {position} seconds out of {duration} total + Buffered progress: {buffered} seconds buffered out of {duration} total + + ) +} +``` + +## `usePlaybackState` + +A hook which returns the up to date state of [`getPlaybackState()`](./functions/player.md#getplaybackstate). +The hook will initially return `{ state: undefined }` while it is awaiting the +initial state of the player. + +```tsx +import React, { useState } from 'react'; +import { Text, View } from 'react-native'; +import { usePlaybackState, State } from 'react-native-track-player'; + +const MyComponent = () => { + const playerState = usePlaybackState(); + const isPlaying = playerState === State.Playing; + + return ( + + The TrackPlayer is {isPlaying ? 'playing' : 'not playing'} + + ); +}; +``` + +## `usePlayWhenReady` + +A hook which returns the up to date state of `TrackPlayer.getPlayWhenReady()`. + +## `useActiveTrack` + +A hook which keeps track of the currently active track using +`TrackPlayer.getActiveTrack()` and `Event.PlaybackActiveTrackChanged`. diff --git a/docs/versioned_docs/version-4.0/api/objects/_category_.json b/docs/versioned_docs/version-4.0/api/objects/_category_.json new file mode 100644 index 000000000..721c8f17e --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/objects/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Objects", + "position": 5 +} diff --git a/docs/versioned_docs/version-4.0/api/objects/android-options.md b/docs/versioned_docs/version-4.0/api/objects/android-options.md new file mode 100644 index 000000000..384e9a429 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/objects/android-options.md @@ -0,0 +1,9 @@ +# AndroidOptions + +Options available for the android player. All options are optional. + +| Param | Type | Default | Description | +|-------|-------|---------|-------------| +| `appKilledPlaybackBehavior` | [`AppKilledPlaybackBehavior`](../constants/app-killed-playback-behavior.md) | [`ContinuePlayback`](../constants/app-killed-playback-behavior.md#continueplayback-default) | Define how the audio playback should behave after removing the app from recents (killing it). | +| `alwaysPauseOnInterruption` | `boolean` | `false` | Whether the `remote-duck` event will be triggered on every interruption | +| `stopForegroundGracePeriod` | `number` | `5` | Time in seconds to wait once the player should transition to not considering the service as in the foreground. If playback resumes within this grace period, the service remains in the foreground state. | diff --git a/docs/versioned_docs/version-4.0/api/objects/feedback.md b/docs/versioned_docs/version-4.0/api/objects/feedback.md new file mode 100644 index 000000000..392662915 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/objects/feedback.md @@ -0,0 +1,12 @@ +--- +sidebar_position: 2 +--- + +# Feedback + +Controls the rendering of the control center item. + +| Param | Type | Description | +| -------------- | --------------------------- | ------------ | +| isActive | `boolean` | Marks wether the option should be marked as active or "done" | +| title | `boolean` | The title to give the action (relevant for iOS) | diff --git a/docs/versioned_docs/version-4.0/api/objects/metadata-options.md b/docs/versioned_docs/version-4.0/api/objects/metadata-options.md new file mode 100644 index 000000000..83f9a0e76 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/objects/metadata-options.md @@ -0,0 +1,3 @@ +# ⚠️ MetadataOptions + +**⚠️ Deprecated in favor of [`UpdateOptions`](./update-options.md)** diff --git a/docs/versioned_docs/version-4.0/api/objects/metadata.md b/docs/versioned_docs/version-4.0/api/objects/metadata.md new file mode 100644 index 000000000..e69945da5 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/objects/metadata.md @@ -0,0 +1,57 @@ +# AudioMetadataReceivedEvent + +An object representing the timed or chapter metadata received for a track. + +| Param | Type | Description | +| -------- | -------- | --------------------------------------------------- | +| metadata | `AudioMetadata[]` | The metadata received | + +# AudioCommonMetadataReceivedEvent + +An object representing the common metadata received for a track. + +| Param | Type | Description | +| -------- | -------- | --------------------------------------------------- | +| metadata | `AudioCommonMetadata` | The metadata received | + +# AudioCommonMetadata + +An object representing the common metadata received for a track. + +| Param | Type | Description | +| -------- | -------- | --------------------------------------------------- | +| title | `string` | The track title. Might be undefined | +| artist | `string` | The track artist. Might be undefined | +| albumTitle | `string` | The track album. Might be undefined | +| subtitle | `string` | The track subtitle. Might be undefined | +| description | `string` | The track description. Might be undefined | +| artworkUri | `string` | The track artwork uri. Might be undefined | +| trackNumber | `string` | The track number. Might be undefined | +| composer | `string` | The track composer. Might be undefined | +| conductor | `string` | The track conductor. Might be undefined | +| genre | `string` | The track genre. Might be undefined | +| compilation | `string` | The track compilation. Might be undefined | +| station | `string` | The track station. Might be undefined | +| mediaType | `string` | The track media type. Might be undefined | +| creationDate | `string` | The track creation date. Might be undefined | +| creationYear | `string` | The track creation year. Might be undefined | + +# AudioMetadata + +An extension of `AudioCommonMetadataReceivedEvent` that includes the raw metadata. + +| Param | Type | Description | +| -------- | -------- | --------------------------------------------------- | +| raw | `RawEntry[]` | The raw metadata that was used to populate. May contain other non common keys. May be empty | + +# RawEntry + +An object representing a raw metadata entry. + +| Param | Type | Description | +| -------- | -------- | --------------------------------------------------- | +| commonKey | `string` | The common key. Might be undefined | +| keySpace | `string` | The key space. Might be undefined | +| time | `number` | The time. Might be undefined | +| value | `unknown` | The value. Might be undefined | +| key | `string` | The key. Might be undefined | diff --git a/docs/versioned_docs/version-4.0/api/objects/playback-error-event.md b/docs/versioned_docs/version-4.0/api/objects/playback-error-event.md new file mode 100644 index 000000000..d5140ea39 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/objects/playback-error-event.md @@ -0,0 +1,9 @@ +# PlaybackErrorEvent + +An object denoting a playback error encountered during loading or playback of a +track. + +| Property | Type | Description | +|----------|----------|-------------| +| code | `string` | The code values are strings prefixed with `android_` on Android and `ios_` on iOS. | +| message | `string` | The error message emitted by the native player. | diff --git a/docs/versioned_docs/version-4.0/api/objects/playback-state.md b/docs/versioned_docs/version-4.0/api/objects/playback-state.md new file mode 100644 index 000000000..24d458e3d --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/objects/playback-state.md @@ -0,0 +1,8 @@ +# PlaybackState + +An object representing the playback state of the player. + +| Property | Type | Description | +| -------------- | --------------------------- | ------------ | +| state | [`State`](../constants/state.md) | The current state of the player. | +| error | [`PlaybackErrorEvent`](./playback-error-event.md) \| `undefined` | If the `state` is type `Error` a [`PlaybackErrorEvent`](./playback-error-event.md) will be present. Else `undefined`.| diff --git a/docs/versioned_docs/version-4.0/api/objects/player-options.md b/docs/versioned_docs/version-4.0/api/objects/player-options.md new file mode 100644 index 000000000..089a7125b --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/objects/player-options.md @@ -0,0 +1,18 @@ +# PlayerOptions + +All parameters are optional. You also only need to specify the ones you want to update. + +| Param | Type | Description | Android | iOS | +|-------|------|-------------|---------|-----| +| `minBuffer` | `number` | Minimum duration of media that the player will attempt to buffer in seconds. | ✅ | ✅ | +| `maxBuffer` | `number` | Maximum duration of media that the player will attempt to buffer in seconds. | ✅ | ❌ | +| `backBuffer` | `number` | Duration in seconds that should be kept in the buffer behind the current playhead time. | ✅ | ❌ | +| `playBuffer` | `number` | Duration of media in seconds that must be buffered for playback to start or resume following a user action such as a seek. | ✅ | ❌ | +| `maxCacheSize` | `number` | Maximum cache size in kilobytes. | ✅ | ❌ | +| `iosCategory` | [`IOSCategory`](../constants/ios-category.md) | An [`IOSCategory`](../constants/ios-category.md). Sets on `play()`. | ❌ | ✅ | +| `iosCategoryMode` | [`IOSCategoryMode`](../constants/ios-category-mode.md) | The audio session mode, together with the audio session category, indicates to the system how you intend to use audio in your app. You can use a mode to configure the audio system for specific use cases such as video recording, voice or video chat, or audio analysis. Sets on `play()`. | ❌ | ✅ | +| `iosCategoryOptions` | [`IOSCategoryOptions[]`](../constants/ios-category-options.md) | An array of [`IOSCategoryOptions`](../constants/ios-category-options.md). Sets on `play()`. | ❌ | ✅ | +| `waitForBuffer` | `boolean` | Indicates whether the player should automatically delay playback in order to minimize stalling. Defaults to `true`. @deprecated This option has been nominated for removal in a future version of RNTP. If you have this set to `true`, you can safely remove this from the options. If you are setting this to `false` and have a reason for that, please post a comment in the following discussion: https://github.com/doublesymmetry/react-native-track-player/pull/1695 and describe why you are doing so. | ✅ | ✅ | +| `autoUpdateMetadata` | `boolean` | Indicates whether the player should automatically update now playing metadata data in control center / notification. Defaults to `true`. | ✅ | ✅ | +| `autoHandleInterruptions` | `boolean` | Indicates whether the player should automatically handle audio interruptions. Defaults to `false`. | ✅ | ✅ | +| `androidAudioContentType` | `boolean` | The audio content type indicates to the android system how you intend to use audio in your app. With `autoHandleInterruptions: true` and `androidAudioContentType: AndroidAudioContentType.Speech`, the audio will be paused during short interruptions, such as when a message arrives. Otherwise the playback volume is reduced while the notification is playing. Defaults to `AndroidAudioContentType.Music` | ✅ | ❌ | diff --git a/docs/versioned_docs/version-4.0/api/objects/progress.md b/docs/versioned_docs/version-4.0/api/objects/progress.md new file mode 100644 index 000000000..e51e8bc16 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/objects/progress.md @@ -0,0 +1,9 @@ +# Progress + +An object representing the various aspects of the active track. + +| Property | Type | Description| +|----------|------|------------| +| position | `number` | The playback position of the active track in seconds. | +| duration | `number` | The duration of the active track in seconds. | +| buffered | `number` | The buffered position of the active track in seconds. | diff --git a/docs/versioned_docs/version-4.0/api/objects/resource.md b/docs/versioned_docs/version-4.0/api/objects/resource.md new file mode 100644 index 000000000..e60260fc4 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/objects/resource.md @@ -0,0 +1,5 @@ +# Resource + +Resource objects are the result of `require`/`import` for files. + +For more information about Resource Objects, read the [Images](https://reactnative.dev/docs/images) section of the React Native documentation diff --git a/docs/versioned_docs/version-4.0/api/objects/track.md b/docs/versioned_docs/version-4.0/api/objects/track.md new file mode 100644 index 000000000..139f65380 --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/objects/track.md @@ -0,0 +1,29 @@ +--- +sidebar_position: 1 +--- + +# Track + +Tracks in the player queue are plain javascript objects as described below. + +Only the `url`, `title` and `artist` properties are required for basic playback + +| Param | Type | Description | +| -------------- | --------------------------- | ------------ | +| id | `string` | The track id | +| url | `string` or [Resource Object](../objects/resource.md) | The media URL | +| type | `string` | Stream type. One of `dash`, `hls`, `smoothstreaming` or `default` | +| userAgent | `string` | The user agent HTTP header | +| contentType | `string` | Mime type of the media file | +| duration | `number` | The duration in seconds | +| title | `string` | The track title | +| artist | `string` | The track artist | +| album | `string` | The track album | +| description | `string` | The track description | +| genre | `string` | The track genre | +| date | `string` | The track release date in [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) | +| rating | Depends on the [rating type](../constants/rating.md) | The track rating value | +| artwork | `string` or [Resource Object](../objects/resource.md) | The artwork url | +| pitchAlgorithm | [Pitch Algorithm](../constants/pitch-algorithm.md) | The pitch algorithm | +| headers | `object` | An object containing all the headers to use in the HTTP request | +| isLiveStream | `boolean` | Used by iOS to present live stream option in control center | diff --git a/docs/versioned_docs/version-4.0/api/objects/update-options.md b/docs/versioned_docs/version-4.0/api/objects/update-options.md new file mode 100644 index 000000000..436417d2a --- /dev/null +++ b/docs/versioned_docs/version-4.0/api/objects/update-options.md @@ -0,0 +1,29 @@ +# UpdateOptions + +All parameters are optional. You also only need to specify the ones you want to update. + + +| Param | Type | Description | Android | iOS | Windows | +| --------- | ---------- | -------------------- | ------- | --- | ------- | +| `ratingType` | [RatingType](../constants/rating.md) | The rating type | ✅ | ❌ | ❌ | +| `forwardJumpInterval` | `number` | The interval in seconds for the jump forward buttons (if only one is given then we use that value for both) | ✅ | ✅ | ❌ | +| `backwardJumpInterval` | `number` | The interval in seconds for the jump backward buttons (if only one is given then we use that value for both) | ✅ | ✅ | ✅ | +| `android` | [`AndroidOptions`](./android-options.md) | Whether the player will pause playback when the app closes | ✅ | ❌ | ❌ | +| `likeOptions` | [FeedbackOptions](../objects/feedback.md) | The media controls that will be enabled | ❌ | ✅ | ❌ | +| `dislikeOptions` | [FeedbackOptions](../objects/feedback.md) | The media controls that will be enabled | ❌ | ✅ | ❌ | +| `bookmarkOptions` | [FeedbackOptions](../objects/feedback.md) | The media controls that will be enabled | ❌ | ✅ | ❌ | +| `capabilities` | [Capability[]](../constants/capability.md) | The media controls that will be enabled | ✅ | ✅ | ✅ | +| `notificationCapabilities` | [Capability[]](../constants/capability.md) | The buttons that it will show in the notification. Defaults to `data.capabilities` | ✅ | ❌ | ❌ | +| `compactCapabilities` | [Capability[]](../constants/capability.md) | The buttons that it will show in the compact notification | ✅ | ❌ | ❌ | +| `icon` | [Resource Object](../objects/resource.md) | The notification icon¹ | ✅ | ❌ | ❌ | +| `playIcon` | [Resource Object](../objects/resource.md) | The play icon¹ | ✅ | ❌ | ❌ | +| `pauseIcon` | [Resource Object](../objects/resource.md) | The pause icon¹ | ✅ | ❌ | ❌ | +| `stopIcon` | [Resource Object](../objects/resource.md) | The stop icon¹ | ✅ | ❌ | ❌ | +| `previousIcon` | [Resource Object](../objects/resource.md) | The previous icon¹ | ✅ | ❌ | ❌ | +| `nextIcon` | [Resource Object](../objects/resource.md) | The next icon¹ | ✅ | ❌ | ❌ | +| `rewindIcon` | [Resource Object](../objects/resource.md) | The jump backward icon¹ | ✅ | ❌ | ❌ | +| `forwardIcon` | [Resource Object](../objects/resource.md) | The jump forward icon¹ | ✅ | ❌ | ❌ | +| `color` | `number` | The notification color in an ARGB hex | ✅ | ❌ | ❌ | +| `progressUpdateEventInterval` | `number` | The interval (in seconds) that the [`Event.PlaybackProgressUpdated`](../events.md#playbackprogressupdated) will be fired. `undefined` by default. | ✅ | ✅ | ❌ | + +*¹ - The custom icons will only work in release builds* diff --git a/docs/versioned_docs/version-4.0/basics/_category_.json b/docs/versioned_docs/version-4.0/basics/_category_.json new file mode 100644 index 000000000..0493fed12 --- /dev/null +++ b/docs/versioned_docs/version-4.0/basics/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "The Basics", + "position": 2 +} diff --git a/docs/versioned_docs/version-4.0/basics/background-mode.md b/docs/versioned_docs/version-4.0/basics/background-mode.md new file mode 100644 index 000000000..62260ab74 --- /dev/null +++ b/docs/versioned_docs/version-4.0/basics/background-mode.md @@ -0,0 +1,69 @@ +--- +sidebar_position: 4 +--- + +# Background Mode + +React Native Track Player supports playing audio while your app is in the +background on all supported platforms. + +## Android +Background audio playback works right out of the box. By default, the audio will +continue to play, not only when the app is suspended in the background, but also +after the app is closed by the user. If that is not the desired behavior, you +can disable it with the `android.appKilledPlaybackBehavior` property in +`updateOptions`. + +In this case, the audio will still play while the app is open in the background.: + +```js +TrackPlayer.updateOptions({ + android: { + // This is the default behavior + appKilledPlaybackBehavior: AppKilledPlaybackBehavior.ContinuePlayback + }, + ... +}); +``` + +Please look at the [`AppKilledPlaybackBehavior`](../api/constants/app-killed-playback-behavior.md) +documentation for all the possible settings and how they behave. + +Please note that while your app is in background, your UI might be unmounted by +React Native. Event listeners added in the [playback service](./playback-service.md) +will continue to receive events. + +### Notification + +The notification will only be visible if the following are true: + +- `AppKilledPlaybackBehavior.ContinuePlayback` or `AppKilledPlaybackBehavior.PausePlayback` are selected. +- Android has not killed the playback service due to no memory, crash, or other issue. + +Your app will be opened when the notification is tapped. You can implement a +custom initialization (e.g.: opening directly the player UI) by using the +[Linking API](https://reactnative.dev/docs/linking) looking for the +`trackplayer://notification.click` URI. + +## iOS +To allow background audio playback on iOS, you need to activate the 'Audio, +Airplay and Picture in Picture' background mode in Xcode. Without activating it, +the audio will only play when the app is in the foreground. + +![Xcode Background Capability](https://developer.apple.com/library/content/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/Art/background_modes_2x.png) + +### iOS Simulator +As of iOS Simulator version 11, Apple has removed support for Control Center and +Now Playing Info from the simulator. You will not be able to test lock screen +controls on recent versions of iOS Simulator. You can either test on real +devices, or download older versions of the iOS Simulator. + +## Windows +To allow background audio playback on Windows, you need to add the background +capability in the app manifest, as [documented by Microsoft](https://docs.microsoft.com/windows/uwp/audio-video-camera/background-audio#background-media-playback-manifest-capability) + +```xml + + + +``` diff --git a/docs/versioned_docs/version-4.0/basics/getting-started.md b/docs/versioned_docs/version-4.0/basics/getting-started.md new file mode 100644 index 000000000..fbcfc775e --- /dev/null +++ b/docs/versioned_docs/version-4.0/basics/getting-started.md @@ -0,0 +1,226 @@ +--- +sidebar_position: 2 +--- + +# Getting Started + +## Starting off +First, you need to register a [playback service](./playback-service.md) right after registering the main component of your app (typically in your `index.js` file at the root of your project): +```ts +// AppRegistry.registerComponent(...); +TrackPlayer.registerPlaybackService(() => require('./service')); +``` + +```ts +// service.js +module.exports = async function() { + // This service needs to be registered for the module to work + // but it will be used later in the "Receiving Events" section +} +``` + +Then, you need to set up the player. This usually takes less than a second: +```ts +import TrackPlayer from 'react-native-track-player'; + +await TrackPlayer.setupPlayer() +// The player is ready to be used +``` + +Make sure the setup method has completed before interacting with any other functions in `TrackPlayer` in order to avoid instability. + +## Controlling the Player + +### Adding Tracks to the Playback Queue + +You can add a track to the player using a url or by requiring a file in the app +bundle or on the file system. + +First of all, you need to create a [track object](../api/objects/track.md), which +is a plain javascript object with a number of properties describing the track. +Then add the track to the queue: + +```ts +var track1 = { + url: 'http://example.com/avaritia.mp3', // Load media from the network + title: 'Avaritia', + artist: 'deadmau5', + album: 'while(1<2)', + genre: 'Progressive House, Electro House', + date: '2014-05-20T07:00:00+00:00', // RFC 3339 + artwork: 'http://example.com/cover.png', // Load artwork from the network + duration: 402 // Duration in seconds +}; + +const track2 = { + url: require('./coelacanth.ogg'), // Load media from the app bundle + title: 'Coelacanth I', + artist: 'deadmau5', + artwork: require('./cover.jpg'), // Load artwork from the app bundle + duration: 166 +}; + +const track3 = { + url: 'file:///storage/sdcard0/Downloads/artwork.png', // Load media from the file system + title: 'Ice Age', + artist: 'deadmau5', + // Load artwork from the file system: + artwork: 'file:///storage/sdcard0/Downloads/cover.png', + duration: 411 +}; + +// You can then [add](https://rntp.dev/docs/api/functions/queue#addtracks-insertbeforeindex) the items to the queue +await TrackPlayer.add([track1, track2, track3]); +``` + +### Player Information + +```ts + +import TrackPlayer, { State } from 'react-native-track-player'; + +const state = await TrackPlayer.getState(); +if (state === State.Playing) { + console.log('The player is playing'); +}; + +let trackIndex = await TrackPlayer.getCurrentTrack(); +let trackObject = await TrackPlayer.getTrack(trackIndex); +console.log(`Title: ${trackObject.title}`); + +const position = await TrackPlayer.getPosition(); +const duration = await TrackPlayer.getDuration(); +console.log(`${duration - position} seconds left.`); +``` + +### Changing Playback State + +```ts +TrackPlayer.play(); +TrackPlayer.pause(); +TrackPlayer.reset(); + +// Seek to 12.5 seconds: +TrackPlayer.seekTo(12.5); + +// Set volume to 50%: +TrackPlayer.setVolume(0.5); +``` + +### Controlling the Queue +```ts +// Skip to a specific track index: +await TrackPlayer.skip(trackIndex); + +// Skip to the next track in the queue: +await TrackPlayer.skipToNext(); + +// Skip to the previous track in the queue: +await TrackPlayer.skipToPrevious(); + +// Remove two tracks from the queue: +await TrackPlayer.remove([trackIndex1, trackIndex2]); + +// Retrieve the track objects in the queue: +const tracks = await TrackPlayer.getQueue(); +console.log(`First title: ${tracks[0].title}`); +``` +#### Playback Events + +You can subscribe to [player events](../api/events.md#player), which describe the +changing nature of the playback state. For example, subscribe to the +`Event.PlaybackTrackChanged` event to be notified when the track has changed or +subscribe to the `Event.PlaybackState` event to be notified when the player +buffers, plays, pauses and stops. + +#### Example +```tsx +import TrackPlayer, { Event } from 'react-native-track-player'; + +const PlayerInfo = () => { + const [trackTitle, setTrackTitle] = useState(); + + // do initial setup, set initial trackTitle.. + + useTrackPlayerEvents([Event.PlaybackTrackChanged], async event => { + if (event.type === Event.PlaybackTrackChanged && event.nextTrack != null) { + const track = await TrackPlayer.getTrack(event.nextTrack); + const {title} = track || {}; + setTrackTitle(title); + } + }); + + return ( + {trackTitle} + ); +} +``` + +## Progress Updates + +Music apps often need an automated way to show the progress of a playing track. +For this purpose, we created [the hook: `useProgress`](../api/hooks.md) which +updates itself automatically. + +#### Example + +```tsx +import TrackPlayer, { useProgress } from 'react-native-track-player'; + +const MyPlayerBar = () => { + const progress = useProgress(); + + return ( + // Note: formatTime and ProgressBar are just examples: + + {formatTime(progress.position)} + + + ); + +} +``` + +## Track Player Options + +Track Player can be configured using a number of options. Some of these options +pertain to the media controls available in the lockscreen / notification and how +they behave, others describe the availability of capabilities needed for +platform specific functionalities like Android Auto. + +You can change options multiple times. You do not need to specify all the +options, just the ones you want to change. + +For more information about the properties you can set, [check the +documentation](../api/functions/player.md#updateoptionsoptions). + +#### Example + +```ts +import TrackPlayer, { Capability } from 'react-native-track-player'; + +TrackPlayer.updateOptions({ + // Media controls capabilities + capabilities: [ + Capability.Play, + Capability.Pause, + Capability.SkipToNext, + Capability.SkipToPrevious, + Capability.Stop, + ], + + // Capabilities that will show up when the notification is in the compact form on Android + compactCapabilities: [Capability.Play, Capability.Pause], + + // Icons for the notification on Android (if you don't like the default ones) + playIcon: require('./play-icon.png'), + pauseIcon: require('./pause-icon.png'), + stopIcon: require('./stop-icon.png'), + previousIcon: require('./previous-icon.png'), + nextIcon: require('./next-icon.png'), + icon: require('./notification-icon.png') +}); +``` diff --git a/docs/versioned_docs/version-4.0/basics/installation.mdx b/docs/versioned_docs/version-4.0/basics/installation.mdx new file mode 100644 index 000000000..14edb767d --- /dev/null +++ b/docs/versioned_docs/version-4.0/basics/installation.mdx @@ -0,0 +1,74 @@ +--- +sidebar_position: 1 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Installation + + +## Stable + + + + + npm install --save react-native-track-player + + + + + yarn add react-native-track-player + + + + +## Unstable / Nightly + +If for some reason you require an update that has not yet been officially +released you can install the `nightly` version which is an automatic release of +`main` published to npm every 24hrs. + + + + + npm install --save react-native-track-player@nightly + + + + + yarn add react-native-track-player@nightly + + + + +## iOS Setup + +iOS requires a few extra steps that are _not_ required for Android/Windows. + +### Enable Swift Modules + +Because the iOS module uses Swift, if the user is using a standard react-native application they'll need to add support for Swift in the project. This can be easily by adding a swift file to the Xcode project -- could be called `dummy.swift` and saying yes when prompted if you'd like to generate a bridging header. + +![Importing Swift](https://i.imgur.com/CBqBcWs.png) + +### Pod Install + +You'll need to run a `pod install` in order to install the native iOS dependencies + +```sh +cd ios && pod install +``` + +## Expo + +You can now use React Native Track Player with Expo. + +Please be aware that while many people are using React Native Track Player with Expo successfully, the current maintainers of this project do not use Expo and their ability to resolve issues involving Expo is limited. + +To get started, create a [custom development client](https://docs.expo.dev/clients/getting-started/) for your Expo app and then install React Native Track Player. + +Here is the configuration required for audio playback in background: + +- [iOS: Enable audio playback in background via your app.json](https://docs.expo.dev/versions/latest/sdk/audio/#playing-or-recording-audio-in-background) +- [Android: Stop playback when the app is closed](./background-mode.md/#android) diff --git a/docs/versioned_docs/version-4.0/basics/platform-support.md b/docs/versioned_docs/version-4.0/basics/platform-support.md new file mode 100644 index 000000000..185e03888 --- /dev/null +++ b/docs/versioned_docs/version-4.0/basics/platform-support.md @@ -0,0 +1,99 @@ +--- +sidebar_position: 5 +--- + +# Platform Support + +## Audio Sources + +| Feature | Android | iOS | Windows | +| ------- | :-----: | :-: | :-----: | +| App bundle¹ | ✅ | ✅ | ✅ | +| Network | ✅ | ✅ | ✅ | +| File System² | ✅ | ✅ | ✅ | + +¹: Use `require` or `import` + +²: Prefix the file path with `file:///` + +## Stream Types + +| Feature | Android | iOS | Windows | +| ------- | :-----: | :-: | :-----: | +| Regular Streams | ✅ | ✅ | ✅ | +| DASH | ✅ | ❌ | ✅ | +| HLS | ✅ | ✅ | ✅ | +| SmoothStreaming | ✅ | ❌ | ❌ | + +## Casting + +| Feature | Android | iOS | Windows | +| ------- | :-----: | :-: | :-----: | +| Google Cast¹ | ✅ | ❌ | ❌ | +| Miracast/DLNA | ❌ | ❌ | ❌ | +| AirPlay | ❌ | ❌ | ❌ | + +¹: Google Cast support has been moved to [react-native-track-casting (WIP)](https://github.com/react-native-kit/react-native-track-casting) which can be used in combination with `react-native-track-player`. + +## Miscellaneous + +| Feature | Android | iOS | Windows | +| ------- | :-----: | :-: | :-----: | +| Media Controls | ✅ | ✅ | ✅ | +| Caching | ✅ | ❌ | ❌ | +| Background Mode¹ | ✅ | ✅ | ✅ | + +¹: Read more in [Background Mode](./background-mode.md) + +## Functions + +| Function | Android | iOS | Windows | +| ------- | :-----: | :-: | :-----: | +| `setupPlayer` | ✅ | ✅ | ✅ | +| `updateOptions` | ✅ | ✅ | ✅ | +| `registerPlaybackService` | ✅ | ✅ | ✅ | +| `addEventListener` | ✅ | ✅ | ✅ | +| `play` | ✅ | ✅ | ✅ | +| `pause` | ✅ | ✅ | ✅ | +| `reset` | ✅ | ✅ | ✅ | +| `setVolume` | ✅ | ✅ | ✅ | +| `getVolume` | ✅ | ✅ | ✅ | +| `setRate` | ✅ | ✅ | ✅ | +| `getRate` | ✅ | ✅ | ✅ | +| `seekTo` | ✅ | ✅ | ✅ | +| `getPosition` | ✅ | ✅ | ✅ | +| `getBufferedPosition` | ✅ | ✅ | ✅ | +| `getDuration` | ✅ | ✅ | ✅ | +| `getState` | ✅ | ✅ | ✅ | +| `getQueue` | ✅ | ✅ | ✅ | +| `getCurrentTrack` | ✅ | ✅ | ✅ | +| `getTrack` | ✅ | ✅ | ✅ | +| `add` | ✅ | ✅ | ✅ | +| `remove` | ✅ | ✅ | ✅ | +| `skip` | ✅ | ✅ | ✅ | +| `skipToPrevious` | ✅ | ✅ | ✅ | +| `skipToNext` | ✅ | ✅ | ✅ | +| `removeUpcomingTracks` | ✅ | ✅ | ✅ | + +## Events + +| Event | Android | iOS | Windows | +| ------- | :-----: | :-: | :-----: | +| `remote-play` | ✅ | ✅ | ✅ | +| `remote-play-id` | ✅ | ❌ | ❌ | +| `remote-play-search` | ✅ | ❌ | ❌ | +| `remote-pause` | ✅ | ✅ | ✅ | +| `remote-stop` | ✅ | ✅ | ✅ | +| `remote-skip` | ✅ | ❌ | ❌ | +| `remote-next` | ✅ | ✅ | ✅ | +| `remote-previous` | ✅ | ✅ | ✅ | +| `remote-seek` | ✅ | ✅ | ✅ | +| `remote-set-rating` | ✅ | ❌ | ❌ | +| `remote-jump-forward` | ✅ | ✅ | ✅ | +| `remote-jump-backward` | ✅ | ✅ | ✅ | +| `remote-duck` | ✅ | ✅ | ❌ | +| `playback-state` | ✅ | ✅ | ✅ | +| `playback-track-changed` | ✅ | ✅ | ✅ | +| `playback-queue-ended` | ✅ | ✅ | ✅ | +| `playback-error` | ✅ | ✅ | ✅ | +| `playback-metadata-received` | ✅ | ✅ | ❌ | diff --git a/docs/versioned_docs/version-4.0/basics/playback-service.md b/docs/versioned_docs/version-4.0/basics/playback-service.md new file mode 100644 index 000000000..3183cfbea --- /dev/null +++ b/docs/versioned_docs/version-4.0/basics/playback-service.md @@ -0,0 +1,37 @@ +--- +sidebar_position: 3 +--- + +# Playback Service + +The playback service keeps running even when the app is in the background. It will start when the player is set up and will only stop when the player is destroyed. It is a good idea to put any code in there that needs to be directly tied to the player state. For example, if you want to be able to track what is being played for analytics purposes, the playback service would be the place to do so. + +## Remote Events + +[Remote events](../api/events.md#media-controls) are sent from places outside of our user interface that we can react to. For example if the user presses the pause media control in the IOS lockscreen / Android notification or from their Bluetooth headset, we want to have TrackPlayer pause the audio. + +If you create a listener to a remote event like `Event.RemotePause` in the context of a React component, there is a chance the UI will be unmounted automatically when the app is in the background, causing it to be missed. For this reason it is best to place remote listeners in the playback service, since it will keep running even when the app is in the background. + +## Example +```js +import { PlaybackService } from './src/services'; + +// This needs to go right after you register the main component of your app +// AppRegistry.registerComponent(...) +TrackPlayer.registerPlaybackService(() => PlaybackService); +``` + +```ts +// src/services/PlaybackService.ts +import { Event } from 'react-native-track-player'; + +export const PlaybackService = async function() { + + TrackPlayer.addEventListener(Event.RemotePlay, () => TrackPlayer.play()); + + TrackPlayer.addEventListener(Event.RemotePause, () => TrackPlayer.pause()); + + // ... + +}; +``` diff --git a/docs/versioned_docs/version-4.0/guides/_category_.json b/docs/versioned_docs/version-4.0/guides/_category_.json new file mode 100644 index 000000000..b6d477248 --- /dev/null +++ b/docs/versioned_docs/version-4.0/guides/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Guides", + "position": 4 +} diff --git a/docs/versioned_docs/version-4.0/guides/amazon-fire-support.md b/docs/versioned_docs/version-4.0/guides/amazon-fire-support.md new file mode 100644 index 000000000..90bbb34d1 --- /dev/null +++ b/docs/versioned_docs/version-4.0/guides/amazon-fire-support.md @@ -0,0 +1,63 @@ +--- +sidebar_position: 99 +--- + +# Amazon FireOS Support + +Support for Android in `react-native-track-player` is built on top of the [ExoPlayer](https://github.com/google/ExoPlayer) media player library provided by Google. ExoPlayer does not officially support Amazon's FireOS fork of Android, because it does not pass [Android CTS](https://source.android.com/compatibility/cts). ExoPlayer seems to work decently on FireOS 5, but it hardly works at all on FireOS 4. + +Thankfully, [Amazon maintains](https://developer.amazon.com/docs/fire-tv/media-players.html#exoplayer) a [ported version of ExoPlayer](https://github.com/amzn/exoplayer-amazon-port) that can be used as a direct replacement as long as matching versions are used. + +## Setup + +In order to fully support FireOS, you will need to build separate APKs for Google and Amazon. This can be accomplised using gradle flavors. + +You will need to choose a ExoPlayer version that has been ported by Amazon, and that is close enough to the version that `react-native-track-player` currently uses, in order to compile. In this example we have chosen to use `2.9.0`. + +### Edit `app/build.gradle` + +Add `productFlavors` to your build file: + +``` +android { + flavorDimensions "store" + productFlavors { + google { + dimension "store" + } + amazon { + dimension "store" + } + } + ... +} +``` + +Override the exoplayer library, and version, by modifying the dependencies: + +``` +dependencies { + compile (project(':react-native-track-player')) { + exclude group: 'com.google.android.exoplayer' + } + googleImplementation 'com.google.android.exoplayer:exoplayer-core:2.10.1' + amazonImplementation 'com.amazon.android:exoplayer-core:2.10.1' + ... +} +``` + +### Build Using Variants + +To make builds using either Google or Amazon libraries, you will need to specify a build variant when you build. + +Here are some examples of `react-native` commands using the `--variant` parameter that can be added as scripts in `package.json`: + +``` +"scripts": { + "android-google": "react-native run-android --variant=googleDebug", + "android-amazon": "react-native run-android --variant=amazonDebug", + "android-release-google": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle && react-native run-android --variant=googleRelease", + "android-release-amazon": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle && react-native run-android --variant=amazonRelease", + ... +} +``` diff --git a/docs/versioned_docs/version-4.0/guides/multitrack-progress.md b/docs/versioned_docs/version-4.0/guides/multitrack-progress.md new file mode 100644 index 000000000..de8a9e3f3 --- /dev/null +++ b/docs/versioned_docs/version-4.0/guides/multitrack-progress.md @@ -0,0 +1,130 @@ +--- +sidebar_position: 4 +--- + +# Multitrack Progress + +If you're building an app that allows the playback of more than one Track you'll +probably also want to keep track of and display the users progress for each of +those tracks. **RNTP does not handle this for you**, but offers everything you +need in order to build it yourself. + +## The Wrong Way + +The most common misconception is that one could simply create a list of tracks +and then simply call `useProgress` in each of them to get their progress. +However, this doesn't work, as **`useProgress` is _only_ concerned with the +progress of the currently playing track!** If you attempt to do it this way +you'll quickly realize that all of your tracks are showing the exact same +progress, which given the understanding of `useProgress` above, should make +perfect sense. + +The other problem with this approach is that when a user listens headlessly ( +or when the player is in the background), you won't get any progress updates. + +## The Right Way + +You're responsible for storing your progress on each track outside of RNTP, and +then using that progress when displaying things to your users. At a high-level, +what you need to do is store a record somewhere that associates a progress with +a unique track. Let's say we want to store a record that has a `track.id` and a +`track.progress`. Then what we want to do is _periodically_ update this record +while a given track is playing. Finally, when you want to display or otherwise +use your progress you should _read_ from the stored record (not from RNTP). See +the example below where we're going to use +[zustand](https://www.npmjs.com/package/zustand). Zustand will allow us to store +(and with some additional configuration, persist) our track progress AND it +gives us a nice way to dynamically update our progress displays in +realtime/reactively. + +Please note, that the below solution assumes that you're adding an `id` property +to your `Track` object before you add it to RNTP, as RNTP does not add `id`'s +to your tracks by default, nor does it require them. + +#### 1. Setup Zustand + +First let's create a basic zustand store to store our progress in: + +```ts +// src/store.ts +import create from 'zustand'; +import type { SetState } from 'zustand/vanilla'; + +type ProgressStateStore = { + map: Record; + setProgress: (id: string, progress: number) => void; +}; + +export const useProgressStateStore = create( + (set: SetState) => ({ + map: {}, + setProgress: (id: string, progress: number) => set((state) => { + state.map[id] = progress; + }), + }) +); +``` + +Let's also set up a little helper hook to make it easier to read progress (we'll +use this later on): + +```ts +// src/hooks/useTrackProgress.ts +import { useCallback } from 'react'; +import { useProgressStateStore } from '../store'; + +export const useTrackProgress = (id: string | number): number => { + return useProgressStateStore(useCallback(state => { + return state.map[id.toString()] || 0; + }, [id])); +}; +``` + +#### 2. Listen To Progress Updates + +Next we need to set up a listener for progress updates in our +[playback service](../basics/playback-service.md) and update our zustand store: + +```ts +// src/services/PlaybackService.ts +import TrackPlayer, { Event } from 'react-native-track-player'; +import { useProgressStateStore } from '../store'; + +// create a local reference for the `setProgress` function +const setProgress = useProgressStateStore.getState().setProgress; + +export const PlaybackService = async function() { + TrackPlayer.addEventListener(Event.PlaybackProgressUpdated, async ({ position, track }) => { + // get the track to fetch your unique ID property (if applicable) + const track = await TrackPlayer.getTrack(track); + // write progress to the zustand store + setProgress(track.id, position); + }); +}; +``` + +⚠️ make sure you've configured your `progressUpdateEventInterval` +in the `TrackPlayer.updateOptions` call. + + +#### 3. Reactively Update Progress + +Finally, we just need to read from the store whenever we display our track list +item: + +```ts +// src/components/TrackListItem.tsx +import type { Track } from 'react-native-track-player'; +import { useTrackProgress } from '../hooks/useTrackProgress'; + +export interface TrackListItemProps {} + +export const TrackListItem: React.FC = (track: Track) => { + const progress = useTrackProgress(track.id); + return ( + Progress: {progress} + ); +}; +``` + +:confetti_ball: voilà diff --git a/docs/versioned_docs/version-4.0/guides/offline-playback.md b/docs/versioned_docs/version-4.0/guides/offline-playback.md new file mode 100644 index 000000000..64bd0cb5a --- /dev/null +++ b/docs/versioned_docs/version-4.0/guides/offline-playback.md @@ -0,0 +1,41 @@ +--- +sidebar_position: 1 +--- + +# Offline Playback + +There are two general use-cases for offline playback: + +1. An "Offline Only" case where all the audio is bundled with your App itself. +2. A "Hybrid Offline/Network" case where some of the time you're playing from a + network and sometime you're playing offline. + +Both of these can be achieved by with this project. The only practical +difference between the two is in the 2nd you'll need another package to +download your audio while your App is running instead of loading into the App's +source at build time. + +After that, you simply send a `Track` object to the player with a **local file +path** to your audio. + +## Offline Only + +This case is simple, just stick your audio files in your repository with your +source code and use the file paths to them when adding Tracks. + +⚠️ Please take into consideration that this approach will increase +the size of your App based on how much audio you want the user to be able to +play. If you're doing anything substantial, it's recommended that you use +the [Hybrid Offline/Network](#hybrid-offline-network) approach. + +## Hybrid Offline/Network + +To do this you'll first need to install a package like: + +- [react-native-fs](https://github.com/itinance/react-native-fs/) +- [rn-fetch-blob](https://github.com/joltup/rn-fetch-blob) +- [expo-file-system](https://www.npmjs.com/package/expo-file-system) + +The typical approach is to then create a download button in your app, which, +once clicked, uses one of the above packages to download your audio to a local +file. Then voila! Simply play the local file after download. diff --git a/docs/versioned_docs/version-4.0/guides/play-button.md b/docs/versioned_docs/version-4.0/guides/play-button.md new file mode 100644 index 000000000..844d1c567 --- /dev/null +++ b/docs/versioned_docs/version-4.0/guides/play-button.md @@ -0,0 +1,24 @@ +--- +sidebar_position: 4 +--- + +# Play Buttons + +UI often needs to display a Play button that changes between three states: + +1. Play +2. Pause +3. Spinner (e.g. if playback is being attempted, but sound is paused due to buffering) + +Implementing this correctly will take a bit of care. For instance, `usePlaybackState` can return `State.Buffering` even if playback is currently paused. `usePlayWhenReady` is one way to check if the player is attempting to play, but can return true even if `PlaybackState` is `State.Error` or `State.Ended`. + +To determine how to render a Play button in its three states correctly, do the following: + +* Render the button as a spinner if `playWhenReady` and `state === State.Loading || state === State.Buffering` +* Else render the button as being in the Playing state if `playWhenReady && !(state === State.Error || state === State.Buffering)` +* Otherwise render the button as being in the Paused state + +To help with this logic, the API has two utilities: + +1. The `useIsPlaying()` hook. This returns `{playing: boolean | undefined, bufferingDuringPlay: boolean | undefined}`, which you can consult to render your play button correctly. You should render a spinner if `bufferingDuringPlay === true`; otherwise render according to `playing`. Values are `undefined` if the player isn't yet in a state where they can be determined. +2. The `async isPlaying()` function, which returns the same result as `useIsPlaying()`, but can be used outside of React components (i.e. without hooks). Note that you can't easily just instead call `getPlaybackState()` to determine the same answer, unless you've accounted for the issues mentioned above. \ No newline at end of file diff --git a/docs/versioned_docs/version-4.0/guides/saving-progress.md b/docs/versioned_docs/version-4.0/guides/saving-progress.md new file mode 100644 index 000000000..7f5e2536c --- /dev/null +++ b/docs/versioned_docs/version-4.0/guides/saving-progress.md @@ -0,0 +1,35 @@ +--- +sidebar_position: 2 +--- + +# Saving Progress + +A common use-case is to store the users progress on a particular `Track` +somewhere so that when they leave and come back, they can pick up right where +they left off. To do this you need to listen for progress updates and then +store the progress somewhere. There are two high level ways of getting this +done. + +## Naive Approach + +One approach could be to use the progress events/updates that the `useProgress` +hook provides. This isn't a very good idea and here's why: + +Users can listen to audio both "in-App" and "Remotely". In-App would be defined +as playback while the user has the app opened on screen. However, whenever +audio is being played in the background/remotely. For example: playback on the +lockscreen, carplay, etc. In these situations **the UI is not mounted**, meaning +the `useProgress` hook, or really any event listeners that are registered +inside of your App UI tree (anything called as a result of +`AppRegistry.registerComponent(appName, () => App);` in your `index.js` file) +**WILL NOT EXECUTE**. + +In a nutshell, if you do this, you're progress **will not** update when the user +is playing back in Remote contexts and therefore your app will seem buggy. + +## Recommended Approach + +The correct way to handle this is to track progress in the +[Playback Service](../basics/playback-service.md), based on the +`Event.PlaybackProgressUpdated` event. These events fire all the time, including +when your app is playing back remotely. diff --git a/docs/versioned_docs/version-4.0/guides/sleeptimers.md b/docs/versioned_docs/version-4.0/guides/sleeptimers.md new file mode 100644 index 000000000..2ad29e190 --- /dev/null +++ b/docs/versioned_docs/version-4.0/guides/sleeptimers.md @@ -0,0 +1,20 @@ +--- +sidebar_position: 3 +--- + +# Sleeptimers + +This guide has very similar principles and implementation to +[Saving Progress](./saving-progress.md). First please read through that guide +to understand the concept of "remote" playback and why coupling playback events +to the UI is a bad idea. + +Once you've understood that concept, this concept is nearly identical. You would +leverage the same `Event.PlaybackProgressUpdated` event in this scenario too. + +Here's how you would use an event to implement a sleep timer: + +1. The user configures a sleep timer in the UI. +2. Persist the time they configure in a store as a timestamp. +3. Each time the progress event fires you check your persisted sleep timer timestamp. + - IF `sleeptime !== null && sleeptime <= now` THEN pause. diff --git a/docs/versioned_docs/version-4.0/intro.md b/docs/versioned_docs/version-4.0/intro.md new file mode 100644 index 000000000..fce50e04f --- /dev/null +++ b/docs/versioned_docs/version-4.0/intro.md @@ -0,0 +1,45 @@ +--- +sidebar_position: 1 +--- + +# Intro + +A fully fledged audio module created for music apps. Provides audio playback, external media controls, background mode and more! + +## Features + +* **Lightweight** - Optimized to use the least amount of resources according to your needs +* **Feels native** - As everything is built together, it follows the same design principles as real music apps do +* **Multi-platform** - Supports Android, iOS and Windows +* **Media Controls support** - Provides events for controlling the app from a bluetooth device, the lockscreen, a notification, a smartwatch or even a car +* **Local or network, files or streams** - It doesn't matter where the media belongs, we've got you covered +* **Adaptive bitrate streaming support** - Support for DASH, HLS or SmoothStreaming +* **Caching support** - Cache media files to play them again without an internet connection +* **Background support** - Keep playing audio even after the app is in background +* **Fully Customizable** - Even the notification icons are customizable! +* **Supports React Hooks 🎣** - Includes React Hooks for common use-cases so you don't have to write them +* **Casting support** - Use in combination with [react-native-track-casting (WIP)](https://github.com/react-native-kit/react-native-track-casting) to seamlessly switch to any Google Cast compatible device that supports custom media receivers + +## Example + +If you want to get started with this module, check the [Installation](./basics/installation.mdx) & [Getting Started](./basics/getting-started.md) page. +If you want detailed information about the API, check the [API Reference](./api/functions/lifecycle.md). +You can also look at our example project [here](https://github.com/doublesymmetry/react-native-track-player/tree/master/example). + +```javascript +import TrackPlayer, { RepeatMode } from 'react-native-track-player'; + +// Creates the player +const setup = async () => { + await TrackPlayer.setupPlayer({}); + + await TrackPlayer.add({ + url: require('track.mp3'), + title: 'Track Title', + artist: 'Track Artist', + artwork: require('track.png') + }); + + TrackPlayer.setRepeatMode(RepeatMode.Queue); +}; +``` diff --git a/docs/versioned_docs/version-4.0/troubleshooting.md b/docs/versioned_docs/version-4.0/troubleshooting.md new file mode 100644 index 000000000..f265c2067 --- /dev/null +++ b/docs/versioned_docs/version-4.0/troubleshooting.md @@ -0,0 +1,43 @@ +--- +sidebar_position: 10 +--- + +# Troubleshooting + +## iOS: (Enable Swift) `library not found for -lswiftCoreAudio for architecture x86_64` +Because the iOS module uses Swift, if the user is using a standard react-native application they'll need to add support for Swift in the project. This can easily be done by adding a swift file to the Xcode project -- could be called `dummy.swift` and saying yes when prompted if you'd like to generate a bridging header. + +![Importing Swift](https://i.imgur.com/CBqBcWs.png) + +## Android: `CIRCULAR REFERENCE:com.android.tools.r8.ApiLevelException: Default interface methods are only supported starting with Android N (--min-api 24)` +Since version 1.0.0, we began using a few Java 8 features in the project to reduce the code size. + +To fix the issue, add the following options to your `android/app/build.gradle` file: +```diff +android { + ... ++ compileOptions { ++ sourceCompatibility JavaVersion.VERSION_1_8 ++ targetCompatibility JavaVersion.VERSION_1_8 ++ } + ... +} +``` + +## Android: `com.facebook.react.common.JavascriptException: No task registered for key TrackPlayer` +The playback service requires a headless task to be registered. You have to register it with `registerPlaybackService`. + +## Android: `Error: Attribute XXX from [androidx.core:core:XXX] is also present at [com.android.support:support-compat:XXX]` +This error occurs when you're mixing both AndroidX and the Support Library in the same project. + +You have to either upgrade everything to AndroidX or downgrade everything to the support library. + + +* For react-native-track-player, the last version to run the support library is **1.1.4** and the first version to run AndroidX is **1.2.0**. +* For react-native, the last version to run the support library is **0.59** and the first version to run AndroidX is **0.60**. + +You can also use [jetifier](https://github.com/mikehardy/jetifier#usage-for-source-files) to convert all of the native code to use only one of them. + +## Android: Cleartext HTTP traffic not permitted + +Since API 28, Android disables traffic without TLS. To fix the issue you have to use `https` or [enable clear text traffic](https://stackoverflow.com/a/50834600). diff --git a/docs/versioned_docs/version-4.0/v2-migration.md b/docs/versioned_docs/version-4.0/v2-migration.md new file mode 100644 index 000000000..f39cfa153 --- /dev/null +++ b/docs/versioned_docs/version-4.0/v2-migration.md @@ -0,0 +1,60 @@ +--- +sidebar_position: 5 +--- + +# Migrating from v1 to v2 + +All queue methods have been updating to work on indexes instead of id's. We want this library to support all kinds of apps -- and moving to be index based will allow us to better support applications who have long/endless queues and in the future to allow us to build a performant API around queue management. + +We recommend using Typescript to have the system alert you of issues. + +When migrating from v1 to v2, the following has changed: + +```diff +// Methods + +- async function add(tracks: Track | Track[], insertBeforeId?: string): Promise { ++ async function add(tracks: Track | Track[], insertBeforeIndex?: number): Promise { + +- async function remove(tracks: string | string[]): Promise { ++ async function remove(tracks: number | number[]): Promise { + +- async function skip(trackId: string): Promise { ++ function skip(trackIndex: number): Promise { + +- async function updateMetadataForTrack(trackId: string, metadata: TrackMetadataBase): Promise { ++ async function updateMetadataForTrack(trackIndex: number, metadata: TrackMetadataBase): Promise { + +- async function getTrack(trackId: string): Promise { ++ async function getTrack(trackIndex: number): Promise { + +- async function getCurrentTrack(): Promise { ++ async function getCurrentTrack(): Promise { + +// Imports + +import TrackPlayer, { +- STATE_XXX, +- CAPABILITY_XXX, +- PITCH_ALGORITHM_XXX, +- RATING_XXX, ++ State, ++ Capability, ++ PitchAlgorithm, ++ RatingType, ++ Event, ++ RepeatMode +} from 'react-native-track-player' + +// Hooks + +- useTrackPlayerProgress ++ useProgress + +// Event Listeners +// Refrain from using: TrackPlayer.addEventListener() and instead use the provided hooks + ++ usePlaybackState ++ useTrackPlayerEvents ++ useProgress +``` diff --git a/docs/versioned_docs/version-4.0/v3-migration.md b/docs/versioned_docs/version-4.0/v3-migration.md new file mode 100644 index 000000000..e1659f49f --- /dev/null +++ b/docs/versioned_docs/version-4.0/v3-migration.md @@ -0,0 +1,65 @@ +--- +sidebar_position: 6 +--- + +# Migrating from v2 to v3 + +Due to how Android handles foreground services, it's not possible for us to stop the process manually, as it's waiting for the foreground service to come back. With v3 we are introducing the following changes related to this: + +- On Android, the audio service can't be manually stopped by the app anymore. + The OS itself decides when to stop it. +- An audio control notification will *always* be present (depending on phone + vendor, this would look and behave differently), which allows users to + quickly go back to the app by tapping on it. + +The full changelog of added features and bug fixes [can be found here](https://github.com/doublesymmetry/react-native-track-player/releases/tag/v3.0). + +When migrating from v2 to v3, the following has changed: + + +## API Changes + +### `stopWithApp` is now `android.appKilledPlaybackBehavior` + +```diff +// Methods +await TrackPlayer.updateOptions({ +- stopWithApp: true, ++ android: { ++ appKilledPlaybackBehavior: AppKilledPlaybackBehavior.ContinuePlayback ++ } +}); +``` + +### `destroy` and `stop` have been removed + +```diff +// remove all usages of `.destroy()` and `.stop()` +- TrackPlayer.destroy(); +- TrackPlayer.stop(); +``` + +## Configuration Changes + +### `track-player.json` / Build Preferences no longer needed + +HLS, Dash, & Smoothstreaming are now supported on Android out of the box. You +can remove your `track-player.json` file if you have one. You still need to +ensure that [the correct `type` is specified on your `Track` +object](./api/objects/track.md). + +```diff +- track-player.json +``` + +### Minimum Compile/Target SDK + +You also need to have a minimum compile & target SDK of 31 (Android 12) + +```groovy +// android/build.gradle +... + compileSdkVersion = 31 + targetSdkVersion = 31 +... +``` diff --git a/docs/versioned_docs/version-4.0/v3.1.0-migration.md b/docs/versioned_docs/version-4.0/v3.1.0-migration.md new file mode 100644 index 000000000..c5e210b46 --- /dev/null +++ b/docs/versioned_docs/version-4.0/v3.1.0-migration.md @@ -0,0 +1,26 @@ +--- +sidebar_position: 7 +--- + +# Migrating from v3.1.0 to v3.2.0 + +### `stoppingAppPausesPlayback` is deprecated + +```diff +await TrackPlayer.updateOptions({ ++ android: { ++ appKilledPlaybackBehavior: AppKilledPlaybackBehavior.ContinuePlayback ++ }, + // This flag is now deprecated. Please use the above to define playback mode. +- stoppingAppPausesPlayback: true, +} +``` + +### `compileSdkVersion` 33 + +The upgrade to `v3.2.0` [requires a minimum `compileSdkVersion` of `33`](https://github.com/doublesymmetry/react-native-track-player/issues/1767#issuecomment-1267156549): + +```diff +- compileSdkVersion = 31 ++ compileSdkVersion = 33 +``` diff --git a/docs/versioned_docs/version-4.0/v4-migration.md b/docs/versioned_docs/version-4.0/v4-migration.md new file mode 100644 index 000000000..045675521 --- /dev/null +++ b/docs/versioned_docs/version-4.0/v4-migration.md @@ -0,0 +1,77 @@ +--- +sidebar_position: 8 +--- + +# Migrating from v3.2 to v4 + +### General Additions + +1. **New Function:** [`getActiveTrackIndex()`](./api/functions/queue.md#getactivetrackindex) + - Description: Gets the index of the current track, or `undefined` if no track loaded. +2. **New Function:** [`getProgress()`](./api/functions/player.md#getprogress) + - Description: Returns progress, buffer and duration information. +3. **New Function:** [`getPlaybackState`](./api/functions/player.md#getplaybackstate) + - Description: Returns the current playback state. +4. New Events: [`Event.AudioChapterMetadataReceived`, `Event.AudioTimedMetadataReceived`, `Event.AudioCommonMetadataReceived`](./api/events.md#metadata) + - Description: More detailed metadata events that are emitted when metadata is received from the native player. + +### General Changes + +- The configuration option `alwaysPauseOnInterruption` has been moved to the `android` section of options. + +```diff +await TrackPlayer.updateOptions({ ++ android: { ++ alwaysPauseOnInterruption: true, ++ }, +- alwaysPauseOnInterruption: true, +} +``` + +- On iOS, the pitch algorithm now defaults to `timeDomain` instead of `lowQualityZeroLatency`. The latter has been deprecated by Apple and has known issues on iOS 17. + +### Hook Behavior Updates + +The [`usePlaybackState()`](./api/hooks.md##useplaybackstate) hook now initially returns `{ state: undefined }` before it has finished retrieving the current state. It previously returned [`State.None`](./api/constants/state.md), indicating no track loaded. + +### Player Method Updates + +- The [`remove()`](./api/functions/queue.md#removeracks) function now supports removing the current track. If the current track is removed, the next track in the queue will be activated. If the current track was the last track in the queue, the first track will be activated. + +The [`getTrack()`](./api/functions/queue.md#gettrack) function now returns `undefined` instead of `null`. + +### Player State Updates +- New player states have been introduced and some updated +1. [`State.Error`](./api/constants/state.md) + - **New.** Emitted when an error state is encountered. +2. [`State.Ended`](./api/constants/state.md) + - **New.** State indicates playback stopped due to the end of the queue being reached. +3. [`State.Loading`](./api/constants/state.md) + - **New.** State indicating the initial loading phase of a track. +4. [`State.Buffering`](./api/constants/state.md) + - **Updated.** Now emitted no matter whether playback is paused or not. +5. [`State.Connecting`](./api/constants/state.md) + - **Deprecated.** Please use `State.Loading` instead. + +### General Deprecations +- The following functions and events have been deprecated: + +1. `getState()` - Please use the `state` property returned by [`getPlaybackState()`](./api/functions/player.md#getplaybackstate). +2. `getDuration()` - Please use the `duration` property returned by [`getProgress()`](./api/functions/player.md#getprogress). +3. `getPosition()` - Please use the `position` property returned by [`getProgress()`](./api/functions/player.md#getprogress). +4. `getBufferedPosition()` - Please use the `buffered` property returned by [`getProgress()`](./api/functions/player.md#getprogress). +5. `getCurrentTrack()` - Please use [`getActiveTrackIndex()`](./api/functions/queue.md#getactivetrackindex). +6. `Event.PlaybackTrackChanged` - Please use [`Event.PlaybackActiveTrackChanged`](./api/events.md#playbackactivetrackchanged). Also note that in 4.0 `Event.PlaybackTrackChanged` is no longer emitted when a track repeats. +7. `Event.PlaybackMetadataReceived` - Please use [`Event.AudioChapterMetadataReceived`, `Event.AudioTimedMetadataReceived`, `Event.AudioCommonMetadataReceived`](./api/events.md#metadata). + +### Removals + +- The clearMetadata() function has been removed. Instead, use [`reset()`](./api/functions/player.md#reset), which stops playback, clears the queue, and clears the notification. + +### Typescript Imports + +1. If you were using deep imports from RNTP, the `src` has been completely +reorganized, and so you may need to adjust your imports accordingly. If you've +been importing everything directly (ex. `import ... from 'react-native-track-player';`) +then you don't need to do anything. +1. The `PlaybackStateEvent` interface has been renamed to `PlaybackState` diff --git a/docs/versioned_sidebars/version-4.0-sidebars.json b/docs/versioned_sidebars/version-4.0-sidebars.json new file mode 100644 index 000000000..3582563e1 --- /dev/null +++ b/docs/versioned_sidebars/version-4.0-sidebars.json @@ -0,0 +1,8 @@ +{ + "app": [ + { + "type": "autogenerated", + "dirName": "." + } + ] +} \ No newline at end of file diff --git a/docs/versions.json b/docs/versions.json index dabe1ec83..8e70d571e 100644 --- a/docs/versions.json +++ b/docs/versions.json @@ -1,5 +1,6 @@ [ + "4.0", "3.2", "3.1", "2.1" -] +] \ No newline at end of file diff --git a/package.json b/package.json index b8ced8fbb..bbbd4acec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-track-player", - "version": "4.0.0-rc09", + "version": "4.0.0", "description": "A fully fledged audio module created for music apps", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/react-native-track-player.podspec b/react-native-track-player.podspec index 812933294..86f5f821e 100644 --- a/react-native-track-player.podspec +++ b/react-native-track-player.podspec @@ -18,5 +18,5 @@ Pod::Spec.new do |s| s.swift_version = "4.2" s.dependency "React-Core" - s.dependency "SwiftAudioEx", "1.0.0-rc.11" + s.dependency "SwiftAudioEx", "1.0.0" end