react-native-mp3-player 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +205 -0
- package/README.md +88 -0
- package/android/build.gradle +114 -0
- package/android/proguard-rules.txt +0 -0
- package/android/src/main/AndroidManifest.xml +27 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/HeadlessJsMediaService.kt +199 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/TrackPlayer.kt +30 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/extensions/AudioPlayerStateExt.kt +19 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/extensions/EnumExtensions.kt +5 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/extensions/NumberExt.kt +13 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/model/MetadataAdapter.kt +227 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/model/NowPlayingMetadata.kt +16 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/model/PlaybackMetadata.kt +203 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/model/State.kt +13 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/model/Track.kt +67 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/model/TrackAudioItem.kt +18 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/model/TrackMetadata.kt +38 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicEvents.kt +65 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt +775 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt +1251 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/utils/AppForegroundTracker.kt +35 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/utils/BundleUtils.kt +147 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/utils/CoilBitmapLoader.kt +64 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/utils/MediaItemBuilder.kt +41 -0
- package/android/src/main/java/com/doublesymmetry/trackplayer/utils/RejectionException.kt +11 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/event/EventHolder.kt +30 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/event/PlayerEventHolder.kt +124 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/AudioContentType.kt +10 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/AudioItem.kt +133 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/AudioItemTransitionReason.kt +33 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/AudioPlayerState.kt +30 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/BufferConfig.kt +8 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/CacheConfig.kt +17 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/Capability.kt +19 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/CustomButton.kt +19 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/FocusChangeData.kt +3 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/MediaSessionCallback.kt +17 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/PlayWhenReadyChangeData.kt +3 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/PlaybackEndedReason.kt +5 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/PlaybackError.kt +6 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/PlayerConfig.kt +36 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/PlayerOptions.kt +39 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/PositionChangedReason.kt +39 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/RepeatMode.kt +16 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/WakeMode.kt +7 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/AudioPlayer.kt +689 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/ForwardingPlayer.java +1124 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/QueuedAudioPlayer.kt +295 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/components/Buffer.kt +34 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/components/Cache.kt +47 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/components/FocusManager.kt +59 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/components/MediaFactory.kt +165 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/service/MusicService.kt +127 -0
- package/android/src/main/java/com/lovegaoshi/kotlinaudio/utils/Utils.kt +113 -0
- package/android/src/main/res/drawable/baseline_repeat_24.xml +5 -0
- package/android/src/main/res/drawable/baseline_repeat_one_24.xml +5 -0
- package/android/src/main/res/drawable/forward.xml +5 -0
- package/android/src/main/res/drawable/heart_24px.xml +5 -0
- package/android/src/main/res/drawable/hearte_24px.xml +5 -0
- package/android/src/main/res/drawable/ifl_24px.xml +5 -0
- package/android/src/main/res/drawable/rewind.xml +5 -0
- package/android/src/main/res/drawable/shuffle_24px.xml +5 -0
- package/android/src/main/res/values/strings.xml +5 -0
- package/android/src/main/res/xml/automotive_app_desc.xml +3 -0
- package/ios/Example/SwiftAudio/Assets.xcassets/22AMI.imageset/22AMillion.jpg +0 -0
- package/ios/Example/SwiftAudio/Assets.xcassets/22AMI.imageset/Contents.json +21 -0
- package/ios/Example/SwiftAudio/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
- package/ios/Example/SwiftAudio/Assets.xcassets/AppIcon.appiconset/Contents.json +58 -0
- package/ios/Example/SwiftAudio/Assets.xcassets/Contents.json +6 -0
- package/ios/Example/SwiftAudio/Assets.xcassets/cover.imageset/Contents.json +21 -0
- package/ios/Example/SwiftAudio/Assets.xcassets/cover.imageset/cover.jpg +0 -0
- package/ios/Example/SwiftAudio/AudioController.swift +46 -0
- package/ios/Example/SwiftAudio/Extensions.swift +22 -0
- package/ios/Example/SwiftAudio/PlayerView.swift +172 -0
- package/ios/Example/SwiftAudio/PlayerViewModel.swift +120 -0
- package/ios/Example/SwiftAudio/Preview Content/Preview Assets.xcassets/Contents.json +6 -0
- package/ios/Example/SwiftAudio/QueueView.swift +65 -0
- package/ios/Example/SwiftAudio/SwiftAudio.entitlements +12 -0
- package/ios/Example/SwiftAudio/SwiftAudioApp.swift +17 -0
- package/ios/Example/SwiftAudio.xcodeproj/project.pbxproj +412 -0
- package/ios/Example/SwiftAudio.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/ios/Example/SwiftAudio.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/ios/RNTrackPlayer/Models/Capabilities.swift +52 -0
- package/ios/RNTrackPlayer/Models/MediaURL.swift +38 -0
- package/ios/RNTrackPlayer/Models/MetadataAdapter.swift +147 -0
- package/ios/RNTrackPlayer/Models/PitchAlgorithms.swift +13 -0
- package/ios/RNTrackPlayer/Models/SessionCategories.swift +106 -0
- package/ios/RNTrackPlayer/Models/State.swift +26 -0
- package/ios/RNTrackPlayer/Models/Track.swift +140 -0
- package/ios/RNTrackPlayer/RNTrackPlayer.swift +941 -0
- package/ios/RNTrackPlayer/Support/RNTrackPlayer-Bridging-Header.h +7 -0
- package/ios/RNTrackPlayer/TrackPlayer.h +14 -0
- package/ios/RNTrackPlayer/TrackPlayer.mm +246 -0
- package/ios/RNTrackPlayer/Utils/EventType.swift +44 -0
- package/ios/RNTrackPlayer/Utils/Metadata.swift +60 -0
- package/ios/SwiftAudioEx/Package.swift +20 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AVPlayerWrapper/AVPlayerWrapper.swift +521 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AVPlayerWrapper/AVPlayerWrapperDelegate.swift +27 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AVPlayerWrapper/AVPlayerWrapperProtocol.swift +69 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AVPlayerWrapper/AVPlayerWrapperState.swift +43 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AudioItem.swift +158 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AudioPlayer.swift +459 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AudioPlayerError.swift +26 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AudioSessionController/AudioSession.swift +33 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AudioSessionController/AudioSessionController.swift +135 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AudioTap.swift +99 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/Event.swift +155 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/NowPlayingInfoController/MediaItemProperty.swift +95 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/NowPlayingInfoController/NowPlayingInfoCenter.swift +17 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/NowPlayingInfoController/NowPlayingInfoController.swift +73 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/NowPlayingInfoController/NowPlayingInfoControllerProtocol.swift +26 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/NowPlayingInfoController/NowPlayingInfoKeyValue.swift +14 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/NowPlayingInfoController/NowPlayingInfoProperty.swift +234 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/Observer/AVPlayerItemNotificationObserver.swift +102 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/Observer/AVPlayerItemObserver.swift +136 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/Observer/AVPlayerObserver.swift +120 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/Observer/AVPlayerTimeObserver.swift +112 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/QueueManager.swift +356 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/QueuedAudioPlayer.swift +236 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/RemoteCommandController/RemoteCommand.swift +170 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/RemoteCommandController/RemoteCommandController.swift +206 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/RepeatMode.swift +15 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/TimeEventFrequency.swift +26 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/Utils/DispatchQueueType.swift +18 -0
- package/ios/SwiftAudioEx/Sources/SwiftAudioEx/WaveformAudioTap.swift +159 -0
- package/lib/specs/NativeTrackPlayer.d.ts +129 -0
- package/lib/specs/NativeTrackPlayer.js +4 -0
- package/lib/src/constants/AndroidAudioContentType.d.ts +35 -0
- package/lib/src/constants/AndroidAudioContentType.js +36 -0
- package/lib/src/constants/AndroidAutoContentStyle.d.ts +10 -0
- package/lib/src/constants/AndroidAutoContentStyle.js +11 -0
- package/lib/src/constants/AppKilledPlaybackBehavior.d.ts +17 -0
- package/lib/src/constants/AppKilledPlaybackBehavior.js +18 -0
- package/lib/src/constants/Capability.d.ts +17 -0
- package/lib/src/constants/Capability.js +19 -0
- package/lib/src/constants/Event.d.ts +163 -0
- package/lib/src/constants/Event.js +164 -0
- package/lib/src/constants/IOSCategory.d.ts +36 -0
- package/lib/src/constants/IOSCategory.js +37 -0
- package/lib/src/constants/IOSCategoryMode.d.ts +47 -0
- package/lib/src/constants/IOSCategoryMode.js +48 -0
- package/lib/src/constants/IOSCategoryOptions.d.ts +44 -0
- package/lib/src/constants/IOSCategoryOptions.js +45 -0
- package/lib/src/constants/MediaItemPlayable.d.ts +4 -0
- package/lib/src/constants/MediaItemPlayable.js +5 -0
- package/lib/src/constants/PitchAlgorithm.d.ts +14 -0
- package/lib/src/constants/PitchAlgorithm.js +16 -0
- package/lib/src/constants/RatingType.d.ts +8 -0
- package/lib/src/constants/RatingType.js +10 -0
- package/lib/src/constants/RepeatMode.d.ts +8 -0
- package/lib/src/constants/RepeatMode.js +10 -0
- package/lib/src/constants/State.d.ts +34 -0
- package/lib/src/constants/State.js +35 -0
- package/lib/src/constants/TrackType.d.ts +6 -0
- package/lib/src/constants/TrackType.js +7 -0
- package/lib/src/constants/index.d.ts +14 -0
- package/lib/src/constants/index.js +14 -0
- package/lib/src/hooks/index.d.ts +6 -0
- package/lib/src/hooks/index.js +6 -0
- package/lib/src/hooks/useActiveTrack.d.ts +2 -0
- package/lib/src/hooks/useActiveTrack.js +28 -0
- package/lib/src/hooks/useAppIsInBackground.d.ts +1 -0
- package/lib/src/hooks/useAppIsInBackground.js +16 -0
- package/lib/src/hooks/useIsPlaying.d.ts +35 -0
- package/lib/src/hooks/useIsPlaying.js +50 -0
- package/lib/src/hooks/usePlayWhenReady.d.ts +1 -0
- package/lib/src/hooks/usePlayWhenReady.js +27 -0
- package/lib/src/hooks/usePlaybackState.d.ts +10 -0
- package/lib/src/hooks/usePlaybackState.js +35 -0
- package/lib/src/hooks/useProgress.d.ts +7 -0
- package/lib/src/hooks/useProgress.js +55 -0
- package/lib/src/hooks/useTrackPlayerEvents.d.ts +8 -0
- package/lib/src/hooks/useTrackPlayerEvents.js +30 -0
- package/lib/src/index.d.ts +5 -0
- package/lib/src/index.js +5 -0
- package/lib/src/interfaces/AndroidAutoBrowseTree.d.ts +5 -0
- package/lib/src/interfaces/AndroidAutoBrowseTree.js +1 -0
- package/lib/src/interfaces/AndroidOptions.d.ts +41 -0
- package/lib/src/interfaces/AndroidOptions.js +1 -0
- package/lib/src/interfaces/CustomButtons.d.ts +5 -0
- package/lib/src/interfaces/CustomButtons.js +1 -0
- package/lib/src/interfaces/FeedbackOptions.d.ts +6 -0
- package/lib/src/interfaces/FeedbackOptions.js +1 -0
- package/lib/src/interfaces/MediaItem.d.ts +18 -0
- package/lib/src/interfaces/MediaItem.js +1 -0
- package/lib/src/interfaces/MetadataOptions.d.ts +3 -0
- package/lib/src/interfaces/MetadataOptions.js +1 -0
- package/lib/src/interfaces/NowPlayingMetadata.d.ts +4 -0
- package/lib/src/interfaces/NowPlayingMetadata.js +1 -0
- package/lib/src/interfaces/PlaybackState.d.ts +8 -0
- package/lib/src/interfaces/PlaybackState.js +1 -0
- package/lib/src/interfaces/PlayerOptions.d.ts +127 -0
- package/lib/src/interfaces/PlayerOptions.js +1 -0
- package/lib/src/interfaces/Progress.d.ts +15 -0
- package/lib/src/interfaces/Progress.js +1 -0
- package/lib/src/interfaces/ResourceObject.d.ts +1 -0
- package/lib/src/interfaces/ResourceObject.js +1 -0
- package/lib/src/interfaces/ServiceHandler.d.ts +1 -0
- package/lib/src/interfaces/ServiceHandler.js +1 -0
- package/lib/src/interfaces/Track.d.ts +21 -0
- package/lib/src/interfaces/Track.js +1 -0
- package/lib/src/interfaces/TrackMetadataBase.d.ts +28 -0
- package/lib/src/interfaces/TrackMetadataBase.js +1 -0
- package/lib/src/interfaces/UpdateOptions.d.ts +52 -0
- package/lib/src/interfaces/UpdateOptions.js +1 -0
- package/lib/src/interfaces/events/AudioMetadataReceivedEvent.d.ts +33 -0
- package/lib/src/interfaces/events/AudioMetadataReceivedEvent.js +1 -0
- package/lib/src/interfaces/events/ControllerConnectedEvent.d.ts +8 -0
- package/lib/src/interfaces/events/ControllerConnectedEvent.js +1 -0
- package/lib/src/interfaces/events/EventPayloadByEvent.d.ts +73 -0
- package/lib/src/interfaces/events/EventPayloadByEvent.js +1 -0
- package/lib/src/interfaces/events/PlaybackActiveTrackChangedEvent.d.ts +24 -0
- package/lib/src/interfaces/events/PlaybackActiveTrackChangedEvent.js +1 -0
- package/lib/src/interfaces/events/PlaybackAnimatedVolumeChangedEvent.d.ts +4 -0
- package/lib/src/interfaces/events/PlaybackAnimatedVolumeChangedEvent.js +1 -0
- package/lib/src/interfaces/events/PlaybackErrorEvent.d.ts +6 -0
- package/lib/src/interfaces/events/PlaybackErrorEvent.js +1 -0
- package/lib/src/interfaces/events/PlaybackMetadataReceivedEvent.d.ts +16 -0
- package/lib/src/interfaces/events/PlaybackMetadataReceivedEvent.js +1 -0
- package/lib/src/interfaces/events/PlaybackPlayWhenReadyChangedEvent.d.ts +4 -0
- package/lib/src/interfaces/events/PlaybackPlayWhenReadyChangedEvent.js +1 -0
- package/lib/src/interfaces/events/PlaybackProgressUpdatedEvent.d.ts +4 -0
- package/lib/src/interfaces/events/PlaybackProgressUpdatedEvent.js +1 -0
- package/lib/src/interfaces/events/PlaybackQueueEndedEvent.d.ts +9 -0
- package/lib/src/interfaces/events/PlaybackQueueEndedEvent.js +1 -0
- package/lib/src/interfaces/events/PlaybackResumeEvent.d.ts +3 -0
- package/lib/src/interfaces/events/PlaybackResumeEvent.js +1 -0
- package/lib/src/interfaces/events/PlaybackTrackChangedEvent.d.ts +11 -0
- package/lib/src/interfaces/events/PlaybackTrackChangedEvent.js +1 -0
- package/lib/src/interfaces/events/PlayerErrorEvent.d.ts +6 -0
- package/lib/src/interfaces/events/PlayerErrorEvent.js +1 -0
- package/lib/src/interfaces/events/RemoteBrowseEvent.d.ts +4 -0
- package/lib/src/interfaces/events/RemoteBrowseEvent.js +1 -0
- package/lib/src/interfaces/events/RemoteCustomActionEvent.d.ts +7 -0
- package/lib/src/interfaces/events/RemoteCustomActionEvent.js +1 -0
- package/lib/src/interfaces/events/RemoteDuckEvent.d.ts +13 -0
- package/lib/src/interfaces/events/RemoteDuckEvent.js +1 -0
- package/lib/src/interfaces/events/RemoteJumpBackwardEvent.d.ts +8 -0
- package/lib/src/interfaces/events/RemoteJumpBackwardEvent.js +1 -0
- package/lib/src/interfaces/events/RemoteJumpForwardEvent.d.ts +8 -0
- package/lib/src/interfaces/events/RemoteJumpForwardEvent.js +1 -0
- package/lib/src/interfaces/events/RemotePlayIdEvent.d.ts +4 -0
- package/lib/src/interfaces/events/RemotePlayIdEvent.js +1 -0
- package/lib/src/interfaces/events/RemotePlaySearchEvent.d.ts +9 -0
- package/lib/src/interfaces/events/RemotePlaySearchEvent.js +1 -0
- package/lib/src/interfaces/events/RemoteSeekEvent.d.ts +4 -0
- package/lib/src/interfaces/events/RemoteSeekEvent.js +1 -0
- package/lib/src/interfaces/events/RemoteSetRatingEvent.d.ts +4 -0
- package/lib/src/interfaces/events/RemoteSetRatingEvent.js +1 -0
- package/lib/src/interfaces/events/RemoteSkipEvent.d.ts +3 -0
- package/lib/src/interfaces/events/RemoteSkipEvent.js +1 -0
- package/lib/src/interfaces/events/index.d.ts +18 -0
- package/lib/src/interfaces/events/index.js +18 -0
- package/lib/src/interfaces/index.d.ts +15 -0
- package/lib/src/interfaces/index.js +15 -0
- package/lib/src/resolveAssetSource.d.ts +2 -0
- package/lib/src/resolveAssetSource.js +3 -0
- package/lib/src/trackPlayer.d.ts +347 -0
- package/lib/src/trackPlayer.js +592 -0
- package/package.json +94 -0
- package/react-native-mp3-player.podspec +22 -0
- package/specs/NativeTrackPlayer.ts +148 -0
- package/src/constants/AndroidAudioContentType.ts +35 -0
- package/src/constants/AndroidAutoContentStyle.ts +10 -0
- package/src/constants/AppKilledPlaybackBehavior.ts +19 -0
- package/src/constants/Capability.ts +19 -0
- package/src/constants/Event.ts +164 -0
- package/src/constants/IOSCategory.ts +36 -0
- package/src/constants/IOSCategoryMode.ts +47 -0
- package/src/constants/IOSCategoryOptions.ts +44 -0
- package/src/constants/MediaItemPlayable.ts +4 -0
- package/src/constants/PitchAlgorithm.ts +16 -0
- package/src/constants/RatingType.ts +10 -0
- package/src/constants/RepeatMode.ts +10 -0
- package/src/constants/State.ts +34 -0
- package/src/constants/TrackType.ts +6 -0
- package/src/constants/index.ts +14 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/useActiveTrack.ts +36 -0
- package/src/hooks/useAppIsInBackground.ts +20 -0
- package/src/hooks/useIsPlaying.ts +56 -0
- package/src/hooks/usePlayWhenReady.ts +37 -0
- package/src/hooks/usePlaybackState.ts +45 -0
- package/src/hooks/useProgress.ts +64 -0
- package/src/hooks/useTrackPlayerEvents.ts +48 -0
- package/src/index.ts +7 -0
- package/src/interfaces/AndroidAutoBrowseTree.ts +6 -0
- package/src/interfaces/AndroidOptions.ts +48 -0
- package/src/interfaces/CustomButtons.ts +6 -0
- package/src/interfaces/FeedbackOptions.ts +7 -0
- package/src/interfaces/MediaItem.ts +19 -0
- package/src/interfaces/MetadataOptions.ts +4 -0
- package/src/interfaces/NowPlayingMetadata.ts +5 -0
- package/src/interfaces/PlaybackState.ts +11 -0
- package/src/interfaces/PlayerOptions.ts +133 -0
- package/src/interfaces/Progress.ts +15 -0
- package/src/interfaces/ResourceObject.ts +1 -0
- package/src/interfaces/ServiceHandler.ts +1 -0
- package/src/interfaces/Track.ts +23 -0
- package/src/interfaces/TrackMetadataBase.ts +29 -0
- package/src/interfaces/UpdateOptions.ts +59 -0
- package/src/interfaces/events/AudioMetadataReceivedEvent.ts +37 -0
- package/src/interfaces/events/ControllerConnectedEvent.ts +9 -0
- package/src/interfaces/events/EventPayloadByEvent.ts +76 -0
- package/src/interfaces/events/PlaybackActiveTrackChangedEvent.ts +29 -0
- package/src/interfaces/events/PlaybackAnimatedVolumeChangedEvent.ts +4 -0
- package/src/interfaces/events/PlaybackErrorEvent.ts +6 -0
- package/src/interfaces/events/PlaybackMetadataReceivedEvent.ts +16 -0
- package/src/interfaces/events/PlaybackPlayWhenReadyChangedEvent.ts +4 -0
- package/src/interfaces/events/PlaybackProgressUpdatedEvent.ts +5 -0
- package/src/interfaces/events/PlaybackQueueEndedEvent.ts +9 -0
- package/src/interfaces/events/PlaybackResumeEvent.ts +5 -0
- package/src/interfaces/events/PlaybackTrackChangedEvent.ts +11 -0
- package/src/interfaces/events/PlayerErrorEvent.ts +6 -0
- package/src/interfaces/events/RemoteBrowseEvent.ts +4 -0
- package/src/interfaces/events/RemoteCustomActionEvent.ts +7 -0
- package/src/interfaces/events/RemoteDuckEvent.ts +13 -0
- package/src/interfaces/events/RemoteJumpBackwardEvent.ts +8 -0
- package/src/interfaces/events/RemoteJumpForwardEvent.ts +8 -0
- package/src/interfaces/events/RemotePlayIdEvent.ts +4 -0
- package/src/interfaces/events/RemotePlaySearchEvent.ts +21 -0
- package/src/interfaces/events/RemoteSeekEvent.ts +4 -0
- package/src/interfaces/events/RemoteSetRatingEvent.ts +5 -0
- package/src/interfaces/events/RemoteSkipEvent.ts +3 -0
- package/src/interfaces/events/index.ts +18 -0
- package/src/interfaces/index.ts +15 -0
- package/src/resolveAssetSource.ts +3 -0
- package/src/trackPlayer.ts +768 -0
|
@@ -0,0 +1,941 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RNTrackPlayer.swift
|
|
3
|
+
// RNTrackPlayer
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import Foundation
|
|
7
|
+
import AVFoundation
|
|
8
|
+
import MediaPlayer
|
|
9
|
+
import React
|
|
10
|
+
|
|
11
|
+
@objc public protocol RNTPDelegate {
|
|
12
|
+
func sendEvent(name: String, body: Any)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@objc(RNTrackPlayer)
|
|
16
|
+
public class RNTrackPlayer: NSObject, AudioSessionControllerDelegate {
|
|
17
|
+
|
|
18
|
+
// newarch swift event emitter
|
|
19
|
+
@objc public weak var delegate: RNTPDelegate? = nil
|
|
20
|
+
// MARK: - Attributes
|
|
21
|
+
private var hasInitialized = false
|
|
22
|
+
private let player = QueuedAudioPlayer()
|
|
23
|
+
private let audioSessionController = AudioSessionController.shared
|
|
24
|
+
private var shouldEmitProgressEvent: Bool = false
|
|
25
|
+
private var shouldResumePlaybackAfterInterruptionEnds: Bool = false
|
|
26
|
+
private var forwardJumpInterval: NSNumber? = nil;
|
|
27
|
+
private var backwardJumpInterval: NSNumber? = nil;
|
|
28
|
+
private var sessionCategory: AVAudioSession.Category = .playback
|
|
29
|
+
private var sessionCategoryMode: AVAudioSession.Mode = .default
|
|
30
|
+
private var sessionCategoryPolicy: AVAudioSession.RouteSharingPolicy = .longFormAudio
|
|
31
|
+
private var sessionCategoryOptions: AVAudioSession.CategoryOptions = []
|
|
32
|
+
|
|
33
|
+
// MARK: - Lifecycle Methods
|
|
34
|
+
|
|
35
|
+
public override init() {
|
|
36
|
+
super.init()
|
|
37
|
+
audioSessionController.delegate = self
|
|
38
|
+
player.playWhenReady = false;
|
|
39
|
+
player.event.receiveChapterMetadata.addListener(self, handleAudioPlayerChapterMetadataReceived)
|
|
40
|
+
player.event.receiveTimedMetadata.addListener(self, handleAudioPlayerTimedMetadataReceived)
|
|
41
|
+
player.event.receiveCommonMetadata.addListener(self, handleAudioPlayerCommonMetadataReceived)
|
|
42
|
+
player.event.stateChange.addListener(self, handleAudioPlayerStateChange)
|
|
43
|
+
player.event.fail.addListener(self, handleAudioPlayerFailed)
|
|
44
|
+
player.event.currentItem.addListener(self, handleAudioPlayerCurrentItemChange)
|
|
45
|
+
player.event.secondElapse.addListener(self, handleAudioPlayerSecondElapse)
|
|
46
|
+
player.event.playWhenReadyChange.addListener(self, handlePlayWhenReadyChange)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
deinit {
|
|
50
|
+
reset(resolve: { _ in }, reject: { _, _, _ in })
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private func emit(event: EventType, body: Any? = nil) {
|
|
54
|
+
delegate?.sendEvent(name: event.rawValue, body: body)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// MARK: - AudioSessionControllerDelegate
|
|
58
|
+
|
|
59
|
+
public func handleInterruption(type: InterruptionType) {
|
|
60
|
+
switch type {
|
|
61
|
+
case .began:
|
|
62
|
+
// Interruption began, take appropriate actions (save state, update user interface)
|
|
63
|
+
emit(event: EventType.RemoteDuck, body: [
|
|
64
|
+
"paused": true
|
|
65
|
+
])
|
|
66
|
+
case let .ended(shouldResume):
|
|
67
|
+
if shouldResume {
|
|
68
|
+
if (shouldResumePlaybackAfterInterruptionEnds) {
|
|
69
|
+
player.play()
|
|
70
|
+
}
|
|
71
|
+
// Interruption Ended - playback should resume
|
|
72
|
+
emit(event: EventType.RemoteDuck, body: [
|
|
73
|
+
"paused": false
|
|
74
|
+
])
|
|
75
|
+
} else {
|
|
76
|
+
// Interruption Ended - playback should NOT resume
|
|
77
|
+
emit(event: EventType.RemoteDuck, body: [
|
|
78
|
+
"paused": true,
|
|
79
|
+
"permanent": true
|
|
80
|
+
])
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// MARK: - Bridged Methods
|
|
86
|
+
|
|
87
|
+
private func rejectWhenNotInitialized(reject: RCTPromiseRejectBlock) -> Bool {
|
|
88
|
+
let rejected = !hasInitialized;
|
|
89
|
+
if (rejected) {
|
|
90
|
+
reject("player_not_initialized", "The player is not initialized. Call setupPlayer first.", nil)
|
|
91
|
+
}
|
|
92
|
+
return rejected;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private func rejectWhenTrackIndexOutOfBounds(
|
|
96
|
+
index: Int,
|
|
97
|
+
min: Int? = nil,
|
|
98
|
+
max : Int? = nil,
|
|
99
|
+
message : String? = "The track index is out of bounds",
|
|
100
|
+
reject: RCTPromiseRejectBlock
|
|
101
|
+
) -> Bool {
|
|
102
|
+
let rejected = index < (min ?? 0) || index > (max ?? player.items.count - 1);
|
|
103
|
+
if (rejected) {
|
|
104
|
+
reject("index_out_of_bounds", message, nil)
|
|
105
|
+
}
|
|
106
|
+
return rejected
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@objc(setupPlayer:resolver:rejecter:)
|
|
110
|
+
public func setupPlayer(config: [String: Any], resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
111
|
+
if hasInitialized {
|
|
112
|
+
reject("player_already_initialized", "The player has already been initialized via setupPlayer.", nil)
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// configure the FFT audio tap
|
|
117
|
+
if let fftLength = config["useFFTProcessor"] as? Int {
|
|
118
|
+
player.audioTap = WaveformAudioTap(mFFTLength: fftLength, mEmit: {data in
|
|
119
|
+
self.emit(event:EventType.FFTUpdated, body:data)})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// configure buffer size
|
|
123
|
+
if let bufferDuration = config["minBuffer"] as? TimeInterval {
|
|
124
|
+
player.bufferDuration = bufferDuration
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
self.shouldResumePlaybackAfterInterruptionEnds = config["autoHandleInterruptions"] as? Bool ?? true
|
|
128
|
+
|
|
129
|
+
// configure wether player waits to play (deprecated)
|
|
130
|
+
if let waitForBuffer = config["waitForBuffer"] as? Bool {
|
|
131
|
+
player.automaticallyWaitsToMinimizeStalling = waitForBuffer
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// configure wether control center metdata should auto update
|
|
135
|
+
player.automaticallyUpdateNowPlayingInfo = config["autoUpdateMetadata"] as? Bool ?? true
|
|
136
|
+
|
|
137
|
+
// configure audio session - category, options & mode
|
|
138
|
+
if
|
|
139
|
+
let sessionCategoryStr = config["iosCategory"] as? String,
|
|
140
|
+
let mappedCategory = SessionCategory(rawValue: sessionCategoryStr) {
|
|
141
|
+
sessionCategory = mappedCategory.mapConfigToAVAudioSessionCategory()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if
|
|
145
|
+
let sessionCategoryModeStr = config["iosCategoryMode"] as? String,
|
|
146
|
+
let mappedCategoryMode = SessionCategoryMode(rawValue: sessionCategoryModeStr) {
|
|
147
|
+
sessionCategoryMode = mappedCategoryMode.mapConfigToAVAudioSessionCategoryMode()
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if
|
|
151
|
+
let sessionCategoryPolicyStr = config["iosCategoryPolicy"] as? String,
|
|
152
|
+
let mappedCategoryPolicy = SessionCategoryPolicy(rawValue: sessionCategoryPolicyStr) {
|
|
153
|
+
sessionCategoryPolicy = mappedCategoryPolicy.mapConfigToAVAudioSessionCategoryPolicy()
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let sessionCategoryOptsStr = config["iosCategoryOptions"] as? [String]
|
|
157
|
+
let mappedCategoryOpts = sessionCategoryOptsStr?.compactMap { SessionCategoryOptions(rawValue: $0)?.mapConfigToAVAudioSessionCategoryOptions() } ?? []
|
|
158
|
+
sessionCategoryOptions = AVAudioSession.CategoryOptions(mappedCategoryOpts)
|
|
159
|
+
|
|
160
|
+
if config["iosCategoryPolicy"] == nil && sessionCategory == .playback {
|
|
161
|
+
sessionCategoryPolicy = .longFormAudio
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
configureAudioSessionForBackgroundPlayback()
|
|
165
|
+
configureAudioSession()
|
|
166
|
+
|
|
167
|
+
// setup event listeners
|
|
168
|
+
player.remoteCommandController.handleChangePlaybackPositionCommand = { [weak self] event in
|
|
169
|
+
if let event = event as? MPChangePlaybackPositionCommandEvent {
|
|
170
|
+
self?.emit(event: EventType.RemoteSeek, body: ["position": event.positionTime])
|
|
171
|
+
return MPRemoteCommandHandlerStatus.success
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return MPRemoteCommandHandlerStatus.commandFailed
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
player.remoteCommandController.handleNextTrackCommand = { [weak self] _ in
|
|
178
|
+
self?.emit(event: EventType.RemoteNext)
|
|
179
|
+
return MPRemoteCommandHandlerStatus.success
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
player.remoteCommandController.handlePauseCommand = { [weak self] _ in
|
|
183
|
+
self?.emit(event: EventType.RemotePause)
|
|
184
|
+
return MPRemoteCommandHandlerStatus.success
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
player.remoteCommandController.handlePlayCommand = { [weak self] _ in
|
|
188
|
+
self?.emit(event: EventType.RemotePlay)
|
|
189
|
+
return MPRemoteCommandHandlerStatus.success
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
player.remoteCommandController.handlePreviousTrackCommand = { [weak self] _ in
|
|
193
|
+
self?.emit(event: EventType.RemotePrevious)
|
|
194
|
+
return MPRemoteCommandHandlerStatus.success
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
player.remoteCommandController.handleSkipBackwardCommand = { [weak self] event in
|
|
198
|
+
if let command = event.command as? MPSkipIntervalCommand,
|
|
199
|
+
let interval = command.preferredIntervals.first {
|
|
200
|
+
self?.emit(event: EventType.RemoteJumpBackward, body: ["interval": interval])
|
|
201
|
+
return MPRemoteCommandHandlerStatus.success
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return MPRemoteCommandHandlerStatus.commandFailed
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
player.remoteCommandController.handleSkipForwardCommand = { [weak self] event in
|
|
208
|
+
if let command = event.command as? MPSkipIntervalCommand,
|
|
209
|
+
let interval = command.preferredIntervals.first {
|
|
210
|
+
self?.emit(event: EventType.RemoteJumpForward, body: ["interval": interval])
|
|
211
|
+
return MPRemoteCommandHandlerStatus.success
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return MPRemoteCommandHandlerStatus.commandFailed
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
player.remoteCommandController.handleStopCommand = { [weak self] _ in
|
|
218
|
+
self?.emit(event: EventType.RemoteStop)
|
|
219
|
+
return MPRemoteCommandHandlerStatus.success
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
player.remoteCommandController.handleTogglePlayPauseCommand = { [weak self] _ in
|
|
223
|
+
self?.emit(event: self?.player.playerState == .paused
|
|
224
|
+
? EventType.RemotePlay
|
|
225
|
+
: EventType.RemotePause
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
return MPRemoteCommandHandlerStatus.success
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
player.remoteCommandController.handleLikeCommand = { [weak self] _ in
|
|
232
|
+
self?.emit(event: EventType.RemoteLike)
|
|
233
|
+
return MPRemoteCommandHandlerStatus.success
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
player.remoteCommandController.handleDislikeCommand = { [weak self] _ in
|
|
237
|
+
self?.emit(event: EventType.RemoteDislike)
|
|
238
|
+
return MPRemoteCommandHandlerStatus.success
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
player.remoteCommandController.handleBookmarkCommand = { [weak self] _ in
|
|
242
|
+
self?.emit(event: EventType.RemoteBookmark)
|
|
243
|
+
return MPRemoteCommandHandlerStatus.success
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
hasInitialized = true
|
|
247
|
+
resolve(NSNull())
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
private func configureAudioSessionForBackgroundPlayback() {
|
|
252
|
+
let session = AVAudioSession.sharedInstance()
|
|
253
|
+
do {
|
|
254
|
+
if #available(iOS 11.0, *) {
|
|
255
|
+
try session.setCategory(sessionCategory, mode: sessionCategoryMode, policy: sessionCategoryPolicy, options: sessionCategoryOptions)
|
|
256
|
+
} else {
|
|
257
|
+
try session.setCategory(sessionCategory, mode: sessionCategoryMode, options: sessionCategoryOptions)
|
|
258
|
+
}
|
|
259
|
+
try session.setActive(true, options: [])
|
|
260
|
+
} catch {}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private func configureAudioSession() {
|
|
264
|
+
|
|
265
|
+
if (player.currentItem == nil) {
|
|
266
|
+
try? audioSessionController.deactivateSession()
|
|
267
|
+
return
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (player.playWhenReady) {
|
|
271
|
+
try? audioSessionController.activateSession()
|
|
272
|
+
if #available(iOS 11.0, *) {
|
|
273
|
+
try? AVAudioSession.sharedInstance().setCategory(sessionCategory, mode: sessionCategoryMode, policy: sessionCategoryPolicy, options: sessionCategoryOptions)
|
|
274
|
+
} else {
|
|
275
|
+
try? AVAudioSession.sharedInstance().setCategory(sessionCategory, mode: sessionCategoryMode, options: sessionCategoryOptions)
|
|
276
|
+
}
|
|
277
|
+
try? AVAudioSession.sharedInstance().setActive(true, options: [])
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
@objc(isServiceRunning:rejecter:)
|
|
282
|
+
public func isServiceRunning(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
283
|
+
// TODO That is probably always true
|
|
284
|
+
resolve(player != nil)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@objc(updateOptions:resolver:rejecter:)
|
|
288
|
+
public func update(options: [String: Any], resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
289
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
290
|
+
|
|
291
|
+
var capabilitiesStr = options["capabilities"] as? [String] ?? []
|
|
292
|
+
if (capabilitiesStr.contains("play") && capabilitiesStr.contains("pause")) {
|
|
293
|
+
capabilitiesStr.append("togglePlayPause");
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
forwardJumpInterval = options["forwardJumpInterval"] as? NSNumber ?? forwardJumpInterval
|
|
297
|
+
backwardJumpInterval = options["backwardJumpInterval"] as? NSNumber ?? backwardJumpInterval
|
|
298
|
+
|
|
299
|
+
player.remoteCommands = capabilitiesStr
|
|
300
|
+
.compactMap { Capability(rawValue: $0) }
|
|
301
|
+
.map { capability in
|
|
302
|
+
capability.mapToPlayerCommand(
|
|
303
|
+
forwardJumpInterval: forwardJumpInterval,
|
|
304
|
+
backwardJumpInterval: backwardJumpInterval,
|
|
305
|
+
likeOptions: options["likeOptions"] as? [String: Any],
|
|
306
|
+
dislikeOptions: options["dislikeOptions"] as? [String: Any],
|
|
307
|
+
bookmarkOptions: options["bookmarkOptions"] as? [String: Any]
|
|
308
|
+
)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
configureProgressUpdateEvent(
|
|
312
|
+
interval: ((options["progressUpdateEventInterval"] as? NSNumber) ?? 0).doubleValue
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
resolve(NSNull())
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
private func configureProgressUpdateEvent(interval: Double) {
|
|
319
|
+
shouldEmitProgressEvent = interval > 0
|
|
320
|
+
self.player.timeEventFrequency = shouldEmitProgressEvent
|
|
321
|
+
? .custom(time: CMTime(seconds: interval, preferredTimescale: 1000))
|
|
322
|
+
: .everySecond
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
@objc(add:before:resolver:rejecter:)
|
|
326
|
+
public func add(
|
|
327
|
+
trackDicts: [[String: Any]],
|
|
328
|
+
before trackIndex: Int,
|
|
329
|
+
resolve: RCTPromiseResolveBlock,
|
|
330
|
+
reject: RCTPromiseRejectBlock
|
|
331
|
+
) {
|
|
332
|
+
// -1 means no index was passed and therefore should be inserted at the end.
|
|
333
|
+
let index = trackIndex == -1 ? player.items.count : trackIndex;
|
|
334
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
335
|
+
if (rejectWhenTrackIndexOutOfBounds(
|
|
336
|
+
index: index,
|
|
337
|
+
max: player.items.count,
|
|
338
|
+
reject: reject
|
|
339
|
+
)) { return }
|
|
340
|
+
|
|
341
|
+
var tracks = [Track]()
|
|
342
|
+
for trackDict in trackDicts {
|
|
343
|
+
guard let track = Track(dictionary: trackDict) else {
|
|
344
|
+
reject("invalid_track_object", "Track is missing a required key", nil)
|
|
345
|
+
return
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
tracks.append(track)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
try? player.add(
|
|
352
|
+
items: tracks,
|
|
353
|
+
at: index
|
|
354
|
+
)
|
|
355
|
+
resolve(index)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
@objc(load:resolver:rejecter:)
|
|
359
|
+
public func load(
|
|
360
|
+
trackDict: [String: Any],
|
|
361
|
+
resolve: RCTPromiseResolveBlock,
|
|
362
|
+
reject: RCTPromiseRejectBlock
|
|
363
|
+
) {
|
|
364
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
365
|
+
|
|
366
|
+
guard let track = Track(dictionary: trackDict) else {
|
|
367
|
+
reject("invalid_track_object", "Track is missing a required key", nil)
|
|
368
|
+
return
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
player.load(item: track)
|
|
372
|
+
resolve(player.currentIndex)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@objc(remove:resolver:rejecter:)
|
|
376
|
+
public func remove(tracks indexes: [Int], resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
377
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
378
|
+
for index in indexes {
|
|
379
|
+
if (rejectWhenTrackIndexOutOfBounds(index: index, message: "One or more of the indexes were out of bounds.", reject: reject)) {
|
|
380
|
+
return
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Sort the indexes in descending order so we can safely remove them one by one
|
|
385
|
+
// without having the next index possibly newly pointing to another item than intended:
|
|
386
|
+
for index in indexes.sorted().reversed() {
|
|
387
|
+
try? player.removeItem(at: index)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
resolve(NSNull())
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
@objc(move:toIndex:resolver:rejecter:)
|
|
394
|
+
public func move(
|
|
395
|
+
fromIndex: Int,
|
|
396
|
+
toIndex: Int,
|
|
397
|
+
resolve: RCTPromiseResolveBlock,
|
|
398
|
+
reject: RCTPromiseRejectBlock
|
|
399
|
+
) {
|
|
400
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
401
|
+
if (rejectWhenTrackIndexOutOfBounds(
|
|
402
|
+
index: fromIndex,
|
|
403
|
+
message: "The fromIndex is out of bounds",
|
|
404
|
+
reject: reject)
|
|
405
|
+
) { return }
|
|
406
|
+
if (rejectWhenTrackIndexOutOfBounds(
|
|
407
|
+
index: toIndex,
|
|
408
|
+
max: Int.max,
|
|
409
|
+
message: "The toIndex is out of bounds",
|
|
410
|
+
reject: reject)
|
|
411
|
+
) { return }
|
|
412
|
+
try? player.moveItem(fromIndex: fromIndex, toIndex: toIndex)
|
|
413
|
+
resolve(NSNull())
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
@objc(removeUpcomingTracks:rejecter:)
|
|
418
|
+
public func removeUpcomingTracks(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
419
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
420
|
+
|
|
421
|
+
player.removeUpcomingItems()
|
|
422
|
+
resolve(NSNull())
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
@objc(skip:initialTime:resolver:rejecter:)
|
|
426
|
+
public func skip(
|
|
427
|
+
to trackIndex: Int,
|
|
428
|
+
initialTime: Double,
|
|
429
|
+
resolve: RCTPromiseResolveBlock,
|
|
430
|
+
reject: RCTPromiseRejectBlock
|
|
431
|
+
) {
|
|
432
|
+
let index = trackIndex;
|
|
433
|
+
if (rejectWhenTrackIndexOutOfBounds(index: index, reject: reject)) { return }
|
|
434
|
+
|
|
435
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
436
|
+
|
|
437
|
+
print("Skipping to track:", index)
|
|
438
|
+
try? player.jumpToItem(atIndex: index, playWhenReady: player.playerState == .playing)
|
|
439
|
+
|
|
440
|
+
// if an initialTime is passed the seek to it
|
|
441
|
+
if (initialTime >= 0) {
|
|
442
|
+
self.seekTo(time: initialTime, resolve: resolve, reject: reject)
|
|
443
|
+
} else {
|
|
444
|
+
resolve(NSNull())
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
@objc(skipToNext:resolver:rejecter:)
|
|
449
|
+
public func skipToNext(
|
|
450
|
+
initialTime: Double,
|
|
451
|
+
resolve: RCTPromiseResolveBlock,
|
|
452
|
+
reject: RCTPromiseRejectBlock
|
|
453
|
+
) {
|
|
454
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
455
|
+
|
|
456
|
+
player.next()
|
|
457
|
+
|
|
458
|
+
// if an initialTime is passed the seek to it
|
|
459
|
+
if (initialTime >= 0) {
|
|
460
|
+
self.seekTo(time: initialTime, resolve: resolve, reject: reject)
|
|
461
|
+
} else {
|
|
462
|
+
resolve(NSNull())
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
@objc(skipToPrevious:resolver:rejecter:)
|
|
467
|
+
public func skipToPrevious(
|
|
468
|
+
initialTime: Double,
|
|
469
|
+
resolve: RCTPromiseResolveBlock,
|
|
470
|
+
reject: RCTPromiseRejectBlock
|
|
471
|
+
) {
|
|
472
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
473
|
+
|
|
474
|
+
player.previous()
|
|
475
|
+
|
|
476
|
+
// if an initialTime is passed the seek to it
|
|
477
|
+
if (initialTime >= 0) {
|
|
478
|
+
self.seekTo(time: initialTime, resolve: resolve, reject: reject)
|
|
479
|
+
} else {
|
|
480
|
+
resolve(NSNull())
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
@objc(reset:rejecter:)
|
|
485
|
+
public func reset(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
486
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
487
|
+
|
|
488
|
+
player.stop()
|
|
489
|
+
player.clear()
|
|
490
|
+
resolve(NSNull())
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
@objc(play:rejecter:)
|
|
494
|
+
public func play(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
495
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
496
|
+
player.play()
|
|
497
|
+
resolve(NSNull())
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
@objc(pause:rejecter:)
|
|
501
|
+
public func pause(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
502
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
503
|
+
|
|
504
|
+
player.pause()
|
|
505
|
+
resolve(NSNull())
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
@objc(setPlayWhenReady:resolver:rejecter:)
|
|
509
|
+
public func setPlayWhenReady(playWhenReady: Bool, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
510
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
511
|
+
player.playWhenReady = playWhenReady
|
|
512
|
+
resolve(NSNull())
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
@objc(getPlayWhenReady:rejecter:)
|
|
516
|
+
public func getPlayWhenReady(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
517
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
518
|
+
resolve(player.playWhenReady)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
@objc(stop:rejecter:)
|
|
522
|
+
public func stop(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
523
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
524
|
+
|
|
525
|
+
player.stop()
|
|
526
|
+
resolve(NSNull())
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
@objc(seekTo:resolver:rejecter:)
|
|
530
|
+
public func seekTo(time: Double, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
531
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
532
|
+
|
|
533
|
+
player.seek(to: time)
|
|
534
|
+
resolve(NSNull())
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
@objc(seekBy:resolver:rejecter:)
|
|
538
|
+
public func seekBy(offset: Double, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
539
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
540
|
+
|
|
541
|
+
player.seek(by: offset)
|
|
542
|
+
resolve(NSNull())
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
@objc(retry:rejecter:)
|
|
546
|
+
public func retry(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
547
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
548
|
+
player.reload(startFromCurrentTime: true)
|
|
549
|
+
resolve(NSNull())
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
@objc(setRepeatMode:resolver:rejecter:)
|
|
553
|
+
public func setRepeatMode(repeatMode: Int, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
554
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
555
|
+
|
|
556
|
+
player.repeatMode = RepeatMode(rawValue: repeatMode) ?? .off
|
|
557
|
+
resolve(NSNull())
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
@objc(getRepeatMode:rejecter:)
|
|
561
|
+
public func getRepeatMode(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
562
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
563
|
+
|
|
564
|
+
resolve(player.repeatMode.rawValue)
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
@objc(setVolume:resolver:rejecter:)
|
|
568
|
+
public func setVolume(level: Float, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
569
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
570
|
+
|
|
571
|
+
player.volume = level
|
|
572
|
+
resolve(NSNull())
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
@objc(getVolume:rejecter:)
|
|
576
|
+
public func getVolume(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
577
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
578
|
+
|
|
579
|
+
resolve(player.volume)
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
@objc(setRate:resolver:rejecter:)
|
|
583
|
+
public func setRate(rate: Float, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
584
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
585
|
+
|
|
586
|
+
player.rate = rate
|
|
587
|
+
resolve(NSNull())
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
@objc(getRate:rejecter:)
|
|
591
|
+
public func getRate(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
592
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
593
|
+
|
|
594
|
+
resolve(player.rate)
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
@objc(getTrack:resolver:rejecter:)
|
|
598
|
+
public func getTrack(index: Int, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
599
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
600
|
+
|
|
601
|
+
if (index >= 0 && index < player.items.count) {
|
|
602
|
+
let track = player.items[index]
|
|
603
|
+
resolve((track as? Track)?.toObject())
|
|
604
|
+
} else {
|
|
605
|
+
resolve(NSNull())
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
@objc(getQueue:rejecter:)
|
|
610
|
+
public func getQueue(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
611
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
612
|
+
|
|
613
|
+
let serializedQueue = player.items.map { ($0 as! Track).toObject() }
|
|
614
|
+
resolve(serializedQueue)
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
@objc(setQueue:resolver:rejecter:)
|
|
618
|
+
public func setQueue(
|
|
619
|
+
trackDicts: [[String: Any]],
|
|
620
|
+
resolve: RCTPromiseResolveBlock,
|
|
621
|
+
reject: RCTPromiseRejectBlock
|
|
622
|
+
) {
|
|
623
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
624
|
+
|
|
625
|
+
var tracks = [Track]()
|
|
626
|
+
for trackDict in trackDicts {
|
|
627
|
+
guard let track = Track(dictionary: trackDict) else {
|
|
628
|
+
reject("invalid_track_object", "Track is missing a required key", nil)
|
|
629
|
+
return
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
tracks.append(track)
|
|
633
|
+
}
|
|
634
|
+
player.clear()
|
|
635
|
+
try? player.add(items: tracks)
|
|
636
|
+
resolve(index)
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
@objc(getActiveTrack:rejecter:)
|
|
640
|
+
public func getActiveTrack(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
641
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
642
|
+
|
|
643
|
+
let index = player.currentIndex
|
|
644
|
+
if (index >= 0 && index < player.items.count) {
|
|
645
|
+
let track = player.items[index]
|
|
646
|
+
resolve((track as? Track)?.toObject())
|
|
647
|
+
} else {
|
|
648
|
+
resolve(NSNull())
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
@objc(getActiveTrackIndex:rejecter:)
|
|
653
|
+
public func getActiveTrackIndex(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
654
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
655
|
+
|
|
656
|
+
let index = player.currentIndex
|
|
657
|
+
if index < 0 || index >= player.items.count {
|
|
658
|
+
resolve(NSNull())
|
|
659
|
+
} else {
|
|
660
|
+
resolve(index)
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
@objc(getDuration:rejecter:)
|
|
665
|
+
public func getDuration(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
666
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
667
|
+
|
|
668
|
+
resolve(player.duration)
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
@objc(getBufferedPosition:rejecter:)
|
|
672
|
+
public func getBufferedPosition(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
673
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
674
|
+
|
|
675
|
+
resolve(player.bufferedPosition)
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
@objc(getPosition:rejecter:)
|
|
679
|
+
public func getPosition(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
680
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
681
|
+
|
|
682
|
+
resolve(player.currentTime)
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
@objc(getProgress:rejecter:)
|
|
686
|
+
public func getProgress(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
687
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
688
|
+
resolve([
|
|
689
|
+
"position": player.currentTime,
|
|
690
|
+
"duration": player.duration,
|
|
691
|
+
"buffered": player.bufferedPosition
|
|
692
|
+
])
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
@objc(getPlaybackState:rejecter:)
|
|
696
|
+
public func getPlaybackState(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
697
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
698
|
+
resolve(getPlaybackStateBodyKeyValues(state: player.playerState))
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
@objc(updateMetadataForTrack:metadata:resolver:rejecter:)
|
|
702
|
+
public func updateMetadata(for trackIndex: Int, metadata: [String: Any], resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
703
|
+
let index = trackIndex;
|
|
704
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
705
|
+
if (rejectWhenTrackIndexOutOfBounds(index: index, reject: reject)) { return }
|
|
706
|
+
|
|
707
|
+
let track : Track = player.items[index] as! Track;
|
|
708
|
+
track.updateMetadata(dictionary: metadata)
|
|
709
|
+
|
|
710
|
+
if (player.currentIndex == index) {
|
|
711
|
+
Metadata.update(for: player, with: metadata)
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
resolve(NSNull())
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
@objc(clearNowPlayingMetadata:rejecter:)
|
|
718
|
+
public func clearNowPlayingMetadata(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
719
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
720
|
+
|
|
721
|
+
player.nowPlayingInfoController.clear()
|
|
722
|
+
resolve(NSNull())
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
@objc(updateNowPlayingMetadata:resolver:rejecter:)
|
|
726
|
+
public func updateNowPlayingMetadata(metadata: [String: Any], resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {
|
|
727
|
+
if (rejectWhenNotInitialized(reject: reject)) { return }
|
|
728
|
+
|
|
729
|
+
Metadata.update(for: player, with: metadata)
|
|
730
|
+
resolve(NSNull())
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
private func getPlaybackStateErrorKeyValues() -> Dictionary<String, Any> {
|
|
734
|
+
switch player.playbackError {
|
|
735
|
+
case .failedToLoadKeyValue: return [
|
|
736
|
+
"message": "Failed to load resource",
|
|
737
|
+
"code": "ios_failed_to_load_resource"
|
|
738
|
+
]
|
|
739
|
+
case .invalidSourceUrl: return [
|
|
740
|
+
"message": "The source url was invalid",
|
|
741
|
+
"code": "ios_invalid_source_url"
|
|
742
|
+
]
|
|
743
|
+
case .notConnectedToInternet: return [
|
|
744
|
+
"message": "A network resource was requested, but an internet connection has not been established and can’t be established automatically.",
|
|
745
|
+
"code": "ios_not_connected_to_internet"
|
|
746
|
+
]
|
|
747
|
+
case .playbackFailed: return [
|
|
748
|
+
"message": "Playback of the track failed",
|
|
749
|
+
"code": "ios_playback_failed"
|
|
750
|
+
]
|
|
751
|
+
case .itemWasUnplayable: return [
|
|
752
|
+
"message": "The track could not be played",
|
|
753
|
+
"code": "ios_track_unplayable"
|
|
754
|
+
]
|
|
755
|
+
default: return [
|
|
756
|
+
"message": "A playback error occurred",
|
|
757
|
+
"code": "ios_playback_error"
|
|
758
|
+
]
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
private func getPlaybackStateBodyKeyValues(state: AudioPlayerState) -> Dictionary<String, Any> {
|
|
763
|
+
var body: Dictionary<String, Any> = ["state": State.fromPlayerState(state: state).rawValue]
|
|
764
|
+
if (state == AudioPlayerState.failed) {
|
|
765
|
+
body["error"] = getPlaybackStateErrorKeyValues()
|
|
766
|
+
}
|
|
767
|
+
return body
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// MARK: - QueuedAudioPlayer Event Handlers
|
|
771
|
+
|
|
772
|
+
func handleAudioPlayerStateChange(state: AVPlayerWrapperState) {
|
|
773
|
+
emit(event: EventType.PlaybackState, body: getPlaybackStateBodyKeyValues(state: state))
|
|
774
|
+
if (state == .ended) {
|
|
775
|
+
emit(event: EventType.PlaybackQueueEnded, body: [
|
|
776
|
+
"track": player.currentIndex,
|
|
777
|
+
"position": player.currentTime,
|
|
778
|
+
] as [String : Any])
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
func handleAudioPlayerCommonMetadataReceived(metadata: [AVMetadataItem]) {
|
|
783
|
+
let commonMetadata = MetadataAdapter.convertToCommonMetadata(metadata: metadata, skipRaw: true)
|
|
784
|
+
emit(event: EventType.MetadataCommonReceived, body: ["metadata": commonMetadata])
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
func handleAudioPlayerChapterMetadataReceived(metadata: [AVTimedMetadataGroup]) {
|
|
788
|
+
let metadataItems = MetadataAdapter.convertToGroupedMetadata(metadataGroups: metadata);
|
|
789
|
+
emit(event: EventType.MetadataChapterReceived, body: ["metadata": metadataItems])
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
func handleAudioPlayerTimedMetadataReceived(metadata: [AVTimedMetadataGroup]) {
|
|
793
|
+
let metadataItems = MetadataAdapter.convertToGroupedMetadata(metadataGroups: metadata);
|
|
794
|
+
emit(event: EventType.MetadataTimedReceived, body: ["metadata": metadataItems])
|
|
795
|
+
|
|
796
|
+
// SwiftAudioEx was updated to return the array of timed metadata
|
|
797
|
+
// Until we have support for that in RNTP, we take the first item to keep existing behaviour.
|
|
798
|
+
let metadata = metadata.first?.items ?? []
|
|
799
|
+
let metadataItem = MetadataAdapter.legacyConversion(metadata: metadata)
|
|
800
|
+
emit(event: EventType.PlaybackMetadataReceived, body: metadataItem)
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
func handleAudioPlayerFailed(error: Error?) {
|
|
804
|
+
emit(event: EventType.PlaybackError, body: ["error": error?.localizedDescription])
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
func handleAudioPlayerCurrentItemChange(
|
|
808
|
+
item: AudioItem?,
|
|
809
|
+
index: Int?,
|
|
810
|
+
lastItem: AudioItem?,
|
|
811
|
+
lastIndex: Int?,
|
|
812
|
+
lastPosition: Double?
|
|
813
|
+
) {
|
|
814
|
+
|
|
815
|
+
if let item = item {
|
|
816
|
+
DispatchQueue.main.async {
|
|
817
|
+
UIApplication.shared.beginReceivingRemoteControlEvents();
|
|
818
|
+
}
|
|
819
|
+
// Update now playing controller with isLiveStream option from track
|
|
820
|
+
if self.player.automaticallyUpdateNowPlayingInfo {
|
|
821
|
+
let isTrackLiveStream = (item as? Track)?.isLiveStream ?? false
|
|
822
|
+
self.player.nowPlayingInfoController.set(keyValue: NowPlayingInfoProperty.isLiveStream(isTrackLiveStream))
|
|
823
|
+
}
|
|
824
|
+
} else {
|
|
825
|
+
DispatchQueue.main.async {
|
|
826
|
+
UIApplication.shared.endReceivingRemoteControlEvents();
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
if ((item != nil && lastItem == nil) || item == nil) {
|
|
831
|
+
configureAudioSession();
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
var a: Dictionary<String, Any> = ["lastPosition": lastPosition ?? 0]
|
|
835
|
+
if let lastIndex = lastIndex {
|
|
836
|
+
a["lastIndex"] = lastIndex
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
if let lastTrack = (lastItem as? Track)?.toObject() {
|
|
840
|
+
a["lastTrack"] = lastTrack
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
if let index = index {
|
|
844
|
+
a["index"] = index
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
if let track = (item as? Track)?.toObject() {
|
|
848
|
+
a["track"] = track
|
|
849
|
+
}
|
|
850
|
+
emit(event: EventType.PlaybackActiveTrackChanged, body: a)
|
|
851
|
+
|
|
852
|
+
// deprecated:
|
|
853
|
+
var b: Dictionary<String, Any> = ["position": lastPosition ?? 0]
|
|
854
|
+
if let lastIndex = lastIndex {
|
|
855
|
+
b["lastIndex"] = lastIndex
|
|
856
|
+
}
|
|
857
|
+
if let index = index {
|
|
858
|
+
b["nextTrack"] = index
|
|
859
|
+
}
|
|
860
|
+
emit(event: EventType.PlaybackTrackChanged, body: b)
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
func handleAudioPlayerSecondElapse(seconds: Double) {
|
|
864
|
+
// because you cannot prevent the `event.secondElapse` from firing
|
|
865
|
+
// do not emit an event if `progressUpdateEventInterval` is nil
|
|
866
|
+
// additionally, there are certain instances in which this event is emitted
|
|
867
|
+
// _after_ a manipulation to the queu causing no currentItem to exist (see reset)
|
|
868
|
+
// in which case we shouldn't emit anything or we'll get an exception.
|
|
869
|
+
if !shouldEmitProgressEvent || player.currentItem == nil { return }
|
|
870
|
+
emit(
|
|
871
|
+
event: EventType.PlaybackProgressUpdated,
|
|
872
|
+
body: [
|
|
873
|
+
"position": player.currentTime,
|
|
874
|
+
"duration": player.duration,
|
|
875
|
+
"buffered": player.bufferedPosition,
|
|
876
|
+
"track": player.currentIndex,
|
|
877
|
+
]
|
|
878
|
+
)
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
func handlePlayWhenReadyChange(playWhenReady: Bool) {
|
|
882
|
+
configureAudioSession();
|
|
883
|
+
emit(
|
|
884
|
+
event: EventType.PlaybackPlayWhenReadyChanged,
|
|
885
|
+
body: [
|
|
886
|
+
"playWhenReady": playWhenReady
|
|
887
|
+
]
|
|
888
|
+
)
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
extension RNTrackPlayer {
|
|
893
|
+
@objc
|
|
894
|
+
public static var constantsToExport: [AnyHashable: Any] {
|
|
895
|
+
return [
|
|
896
|
+
"STATE_NONE": State.none.rawValue,
|
|
897
|
+
"STATE_READY": State.ready.rawValue,
|
|
898
|
+
"STATE_PLAYING": State.playing.rawValue,
|
|
899
|
+
"STATE_PAUSED": State.paused.rawValue,
|
|
900
|
+
"STATE_STOPPED": State.stopped.rawValue,
|
|
901
|
+
"STATE_BUFFERING": State.buffering.rawValue,
|
|
902
|
+
"STATE_LOADING": State.loading.rawValue,
|
|
903
|
+
"STATE_ERROR": State.error.rawValue,
|
|
904
|
+
|
|
905
|
+
"TRACK_PLAYBACK_ENDED_REASON_END": PlaybackEndedReason.playedUntilEnd.rawValue,
|
|
906
|
+
"TRACK_PLAYBACK_ENDED_REASON_JUMPED": PlaybackEndedReason.jumpedToIndex.rawValue,
|
|
907
|
+
"TRACK_PLAYBACK_ENDED_REASON_NEXT": PlaybackEndedReason.skippedToNext.rawValue,
|
|
908
|
+
"TRACK_PLAYBACK_ENDED_REASON_PREVIOUS": PlaybackEndedReason.skippedToPrevious.rawValue,
|
|
909
|
+
"TRACK_PLAYBACK_ENDED_REASON_STOPPED": PlaybackEndedReason.playerStopped.rawValue,
|
|
910
|
+
|
|
911
|
+
"PITCH_ALGORITHM_LINEAR": PitchAlgorithm.linear.rawValue,
|
|
912
|
+
"PITCH_ALGORITHM_MUSIC": PitchAlgorithm.music.rawValue,
|
|
913
|
+
"PITCH_ALGORITHM_VOICE": PitchAlgorithm.voice.rawValue,
|
|
914
|
+
|
|
915
|
+
"CAPABILITY_PLAY": Capability.play.rawValue,
|
|
916
|
+
"CAPABILITY_PLAY_FROM_ID": "NOOP",
|
|
917
|
+
"CAPABILITY_PLAY_FROM_SEARCH": "NOOP",
|
|
918
|
+
"CAPABILITY_PAUSE": Capability.pause.rawValue,
|
|
919
|
+
"CAPABILITY_STOP": Capability.stop.rawValue,
|
|
920
|
+
"CAPABILITY_SEEK_TO": Capability.seek.rawValue,
|
|
921
|
+
"CAPABILITY_SKIP": "NOOP",
|
|
922
|
+
"CAPABILITY_SKIP_TO_NEXT": Capability.next.rawValue,
|
|
923
|
+
"CAPABILITY_SKIP_TO_PREVIOUS": Capability.previous.rawValue,
|
|
924
|
+
"CAPABILITY_SET_RATING": "NOOP",
|
|
925
|
+
"CAPABILITY_JUMP_FORWARD": Capability.jumpForward.rawValue,
|
|
926
|
+
"CAPABILITY_JUMP_BACKWARD": Capability.jumpBackward.rawValue,
|
|
927
|
+
"CAPABILITY_LIKE": Capability.like.rawValue,
|
|
928
|
+
"CAPABILITY_DISLIKE": Capability.dislike.rawValue,
|
|
929
|
+
"CAPABILITY_BOOKMARK": Capability.bookmark.rawValue,
|
|
930
|
+
|
|
931
|
+
"REPEAT_OFF": RepeatMode.off.rawValue,
|
|
932
|
+
"REPEAT_TRACK": RepeatMode.track.rawValue,
|
|
933
|
+
"REPEAT_QUEUE": RepeatMode.queue.rawValue,
|
|
934
|
+
]
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
@objc
|
|
938
|
+
public static var supportedEvents: [String] {
|
|
939
|
+
return EventType.allRawValues()
|
|
940
|
+
}
|
|
941
|
+
}
|