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.
Files changed (328) hide show
  1. package/LICENSE +205 -0
  2. package/README.md +88 -0
  3. package/android/build.gradle +114 -0
  4. package/android/proguard-rules.txt +0 -0
  5. package/android/src/main/AndroidManifest.xml +27 -0
  6. package/android/src/main/java/com/doublesymmetry/trackplayer/HeadlessJsMediaService.kt +199 -0
  7. package/android/src/main/java/com/doublesymmetry/trackplayer/TrackPlayer.kt +30 -0
  8. package/android/src/main/java/com/doublesymmetry/trackplayer/extensions/AudioPlayerStateExt.kt +19 -0
  9. package/android/src/main/java/com/doublesymmetry/trackplayer/extensions/EnumExtensions.kt +5 -0
  10. package/android/src/main/java/com/doublesymmetry/trackplayer/extensions/NumberExt.kt +13 -0
  11. package/android/src/main/java/com/doublesymmetry/trackplayer/model/MetadataAdapter.kt +227 -0
  12. package/android/src/main/java/com/doublesymmetry/trackplayer/model/NowPlayingMetadata.kt +16 -0
  13. package/android/src/main/java/com/doublesymmetry/trackplayer/model/PlaybackMetadata.kt +203 -0
  14. package/android/src/main/java/com/doublesymmetry/trackplayer/model/State.kt +13 -0
  15. package/android/src/main/java/com/doublesymmetry/trackplayer/model/Track.kt +67 -0
  16. package/android/src/main/java/com/doublesymmetry/trackplayer/model/TrackAudioItem.kt +18 -0
  17. package/android/src/main/java/com/doublesymmetry/trackplayer/model/TrackMetadata.kt +38 -0
  18. package/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicEvents.kt +65 -0
  19. package/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt +775 -0
  20. package/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt +1251 -0
  21. package/android/src/main/java/com/doublesymmetry/trackplayer/utils/AppForegroundTracker.kt +35 -0
  22. package/android/src/main/java/com/doublesymmetry/trackplayer/utils/BundleUtils.kt +147 -0
  23. package/android/src/main/java/com/doublesymmetry/trackplayer/utils/CoilBitmapLoader.kt +64 -0
  24. package/android/src/main/java/com/doublesymmetry/trackplayer/utils/MediaItemBuilder.kt +41 -0
  25. package/android/src/main/java/com/doublesymmetry/trackplayer/utils/RejectionException.kt +11 -0
  26. package/android/src/main/java/com/lovegaoshi/kotlinaudio/event/EventHolder.kt +30 -0
  27. package/android/src/main/java/com/lovegaoshi/kotlinaudio/event/PlayerEventHolder.kt +124 -0
  28. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/AudioContentType.kt +10 -0
  29. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/AudioItem.kt +133 -0
  30. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/AudioItemTransitionReason.kt +33 -0
  31. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/AudioPlayerState.kt +30 -0
  32. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/BufferConfig.kt +8 -0
  33. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/CacheConfig.kt +17 -0
  34. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/Capability.kt +19 -0
  35. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/CustomButton.kt +19 -0
  36. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/FocusChangeData.kt +3 -0
  37. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/MediaSessionCallback.kt +17 -0
  38. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/PlayWhenReadyChangeData.kt +3 -0
  39. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/PlaybackEndedReason.kt +5 -0
  40. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/PlaybackError.kt +6 -0
  41. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/PlayerConfig.kt +36 -0
  42. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/PlayerOptions.kt +39 -0
  43. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/PositionChangedReason.kt +39 -0
  44. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/RepeatMode.kt +16 -0
  45. package/android/src/main/java/com/lovegaoshi/kotlinaudio/models/WakeMode.kt +7 -0
  46. package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/AudioPlayer.kt +689 -0
  47. package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/ForwardingPlayer.java +1124 -0
  48. package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/QueuedAudioPlayer.kt +295 -0
  49. package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/components/Buffer.kt +34 -0
  50. package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/components/Cache.kt +47 -0
  51. package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/components/FocusManager.kt +59 -0
  52. package/android/src/main/java/com/lovegaoshi/kotlinaudio/player/components/MediaFactory.kt +165 -0
  53. package/android/src/main/java/com/lovegaoshi/kotlinaudio/service/MusicService.kt +127 -0
  54. package/android/src/main/java/com/lovegaoshi/kotlinaudio/utils/Utils.kt +113 -0
  55. package/android/src/main/res/drawable/baseline_repeat_24.xml +5 -0
  56. package/android/src/main/res/drawable/baseline_repeat_one_24.xml +5 -0
  57. package/android/src/main/res/drawable/forward.xml +5 -0
  58. package/android/src/main/res/drawable/heart_24px.xml +5 -0
  59. package/android/src/main/res/drawable/hearte_24px.xml +5 -0
  60. package/android/src/main/res/drawable/ifl_24px.xml +5 -0
  61. package/android/src/main/res/drawable/rewind.xml +5 -0
  62. package/android/src/main/res/drawable/shuffle_24px.xml +5 -0
  63. package/android/src/main/res/values/strings.xml +5 -0
  64. package/android/src/main/res/xml/automotive_app_desc.xml +3 -0
  65. package/ios/Example/SwiftAudio/Assets.xcassets/22AMI.imageset/22AMillion.jpg +0 -0
  66. package/ios/Example/SwiftAudio/Assets.xcassets/22AMI.imageset/Contents.json +21 -0
  67. package/ios/Example/SwiftAudio/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  68. package/ios/Example/SwiftAudio/Assets.xcassets/AppIcon.appiconset/Contents.json +58 -0
  69. package/ios/Example/SwiftAudio/Assets.xcassets/Contents.json +6 -0
  70. package/ios/Example/SwiftAudio/Assets.xcassets/cover.imageset/Contents.json +21 -0
  71. package/ios/Example/SwiftAudio/Assets.xcassets/cover.imageset/cover.jpg +0 -0
  72. package/ios/Example/SwiftAudio/AudioController.swift +46 -0
  73. package/ios/Example/SwiftAudio/Extensions.swift +22 -0
  74. package/ios/Example/SwiftAudio/PlayerView.swift +172 -0
  75. package/ios/Example/SwiftAudio/PlayerViewModel.swift +120 -0
  76. package/ios/Example/SwiftAudio/Preview Content/Preview Assets.xcassets/Contents.json +6 -0
  77. package/ios/Example/SwiftAudio/QueueView.swift +65 -0
  78. package/ios/Example/SwiftAudio/SwiftAudio.entitlements +12 -0
  79. package/ios/Example/SwiftAudio/SwiftAudioApp.swift +17 -0
  80. package/ios/Example/SwiftAudio.xcodeproj/project.pbxproj +412 -0
  81. package/ios/Example/SwiftAudio.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  82. package/ios/Example/SwiftAudio.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  83. package/ios/RNTrackPlayer/Models/Capabilities.swift +52 -0
  84. package/ios/RNTrackPlayer/Models/MediaURL.swift +38 -0
  85. package/ios/RNTrackPlayer/Models/MetadataAdapter.swift +147 -0
  86. package/ios/RNTrackPlayer/Models/PitchAlgorithms.swift +13 -0
  87. package/ios/RNTrackPlayer/Models/SessionCategories.swift +106 -0
  88. package/ios/RNTrackPlayer/Models/State.swift +26 -0
  89. package/ios/RNTrackPlayer/Models/Track.swift +140 -0
  90. package/ios/RNTrackPlayer/RNTrackPlayer.swift +941 -0
  91. package/ios/RNTrackPlayer/Support/RNTrackPlayer-Bridging-Header.h +7 -0
  92. package/ios/RNTrackPlayer/TrackPlayer.h +14 -0
  93. package/ios/RNTrackPlayer/TrackPlayer.mm +246 -0
  94. package/ios/RNTrackPlayer/Utils/EventType.swift +44 -0
  95. package/ios/RNTrackPlayer/Utils/Metadata.swift +60 -0
  96. package/ios/SwiftAudioEx/Package.swift +20 -0
  97. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AVPlayerWrapper/AVPlayerWrapper.swift +521 -0
  98. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AVPlayerWrapper/AVPlayerWrapperDelegate.swift +27 -0
  99. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AVPlayerWrapper/AVPlayerWrapperProtocol.swift +69 -0
  100. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AVPlayerWrapper/AVPlayerWrapperState.swift +43 -0
  101. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AudioItem.swift +158 -0
  102. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AudioPlayer.swift +459 -0
  103. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AudioPlayerError.swift +26 -0
  104. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AudioSessionController/AudioSession.swift +33 -0
  105. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AudioSessionController/AudioSessionController.swift +135 -0
  106. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/AudioTap.swift +99 -0
  107. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/Event.swift +155 -0
  108. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/NowPlayingInfoController/MediaItemProperty.swift +95 -0
  109. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/NowPlayingInfoController/NowPlayingInfoCenter.swift +17 -0
  110. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/NowPlayingInfoController/NowPlayingInfoController.swift +73 -0
  111. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/NowPlayingInfoController/NowPlayingInfoControllerProtocol.swift +26 -0
  112. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/NowPlayingInfoController/NowPlayingInfoKeyValue.swift +14 -0
  113. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/NowPlayingInfoController/NowPlayingInfoProperty.swift +234 -0
  114. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/Observer/AVPlayerItemNotificationObserver.swift +102 -0
  115. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/Observer/AVPlayerItemObserver.swift +136 -0
  116. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/Observer/AVPlayerObserver.swift +120 -0
  117. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/Observer/AVPlayerTimeObserver.swift +112 -0
  118. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/QueueManager.swift +356 -0
  119. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/QueuedAudioPlayer.swift +236 -0
  120. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/RemoteCommandController/RemoteCommand.swift +170 -0
  121. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/RemoteCommandController/RemoteCommandController.swift +206 -0
  122. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/RepeatMode.swift +15 -0
  123. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/TimeEventFrequency.swift +26 -0
  124. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/Utils/DispatchQueueType.swift +18 -0
  125. package/ios/SwiftAudioEx/Sources/SwiftAudioEx/WaveformAudioTap.swift +159 -0
  126. package/lib/specs/NativeTrackPlayer.d.ts +129 -0
  127. package/lib/specs/NativeTrackPlayer.js +4 -0
  128. package/lib/src/constants/AndroidAudioContentType.d.ts +35 -0
  129. package/lib/src/constants/AndroidAudioContentType.js +36 -0
  130. package/lib/src/constants/AndroidAutoContentStyle.d.ts +10 -0
  131. package/lib/src/constants/AndroidAutoContentStyle.js +11 -0
  132. package/lib/src/constants/AppKilledPlaybackBehavior.d.ts +17 -0
  133. package/lib/src/constants/AppKilledPlaybackBehavior.js +18 -0
  134. package/lib/src/constants/Capability.d.ts +17 -0
  135. package/lib/src/constants/Capability.js +19 -0
  136. package/lib/src/constants/Event.d.ts +163 -0
  137. package/lib/src/constants/Event.js +164 -0
  138. package/lib/src/constants/IOSCategory.d.ts +36 -0
  139. package/lib/src/constants/IOSCategory.js +37 -0
  140. package/lib/src/constants/IOSCategoryMode.d.ts +47 -0
  141. package/lib/src/constants/IOSCategoryMode.js +48 -0
  142. package/lib/src/constants/IOSCategoryOptions.d.ts +44 -0
  143. package/lib/src/constants/IOSCategoryOptions.js +45 -0
  144. package/lib/src/constants/MediaItemPlayable.d.ts +4 -0
  145. package/lib/src/constants/MediaItemPlayable.js +5 -0
  146. package/lib/src/constants/PitchAlgorithm.d.ts +14 -0
  147. package/lib/src/constants/PitchAlgorithm.js +16 -0
  148. package/lib/src/constants/RatingType.d.ts +8 -0
  149. package/lib/src/constants/RatingType.js +10 -0
  150. package/lib/src/constants/RepeatMode.d.ts +8 -0
  151. package/lib/src/constants/RepeatMode.js +10 -0
  152. package/lib/src/constants/State.d.ts +34 -0
  153. package/lib/src/constants/State.js +35 -0
  154. package/lib/src/constants/TrackType.d.ts +6 -0
  155. package/lib/src/constants/TrackType.js +7 -0
  156. package/lib/src/constants/index.d.ts +14 -0
  157. package/lib/src/constants/index.js +14 -0
  158. package/lib/src/hooks/index.d.ts +6 -0
  159. package/lib/src/hooks/index.js +6 -0
  160. package/lib/src/hooks/useActiveTrack.d.ts +2 -0
  161. package/lib/src/hooks/useActiveTrack.js +28 -0
  162. package/lib/src/hooks/useAppIsInBackground.d.ts +1 -0
  163. package/lib/src/hooks/useAppIsInBackground.js +16 -0
  164. package/lib/src/hooks/useIsPlaying.d.ts +35 -0
  165. package/lib/src/hooks/useIsPlaying.js +50 -0
  166. package/lib/src/hooks/usePlayWhenReady.d.ts +1 -0
  167. package/lib/src/hooks/usePlayWhenReady.js +27 -0
  168. package/lib/src/hooks/usePlaybackState.d.ts +10 -0
  169. package/lib/src/hooks/usePlaybackState.js +35 -0
  170. package/lib/src/hooks/useProgress.d.ts +7 -0
  171. package/lib/src/hooks/useProgress.js +55 -0
  172. package/lib/src/hooks/useTrackPlayerEvents.d.ts +8 -0
  173. package/lib/src/hooks/useTrackPlayerEvents.js +30 -0
  174. package/lib/src/index.d.ts +5 -0
  175. package/lib/src/index.js +5 -0
  176. package/lib/src/interfaces/AndroidAutoBrowseTree.d.ts +5 -0
  177. package/lib/src/interfaces/AndroidAutoBrowseTree.js +1 -0
  178. package/lib/src/interfaces/AndroidOptions.d.ts +41 -0
  179. package/lib/src/interfaces/AndroidOptions.js +1 -0
  180. package/lib/src/interfaces/CustomButtons.d.ts +5 -0
  181. package/lib/src/interfaces/CustomButtons.js +1 -0
  182. package/lib/src/interfaces/FeedbackOptions.d.ts +6 -0
  183. package/lib/src/interfaces/FeedbackOptions.js +1 -0
  184. package/lib/src/interfaces/MediaItem.d.ts +18 -0
  185. package/lib/src/interfaces/MediaItem.js +1 -0
  186. package/lib/src/interfaces/MetadataOptions.d.ts +3 -0
  187. package/lib/src/interfaces/MetadataOptions.js +1 -0
  188. package/lib/src/interfaces/NowPlayingMetadata.d.ts +4 -0
  189. package/lib/src/interfaces/NowPlayingMetadata.js +1 -0
  190. package/lib/src/interfaces/PlaybackState.d.ts +8 -0
  191. package/lib/src/interfaces/PlaybackState.js +1 -0
  192. package/lib/src/interfaces/PlayerOptions.d.ts +127 -0
  193. package/lib/src/interfaces/PlayerOptions.js +1 -0
  194. package/lib/src/interfaces/Progress.d.ts +15 -0
  195. package/lib/src/interfaces/Progress.js +1 -0
  196. package/lib/src/interfaces/ResourceObject.d.ts +1 -0
  197. package/lib/src/interfaces/ResourceObject.js +1 -0
  198. package/lib/src/interfaces/ServiceHandler.d.ts +1 -0
  199. package/lib/src/interfaces/ServiceHandler.js +1 -0
  200. package/lib/src/interfaces/Track.d.ts +21 -0
  201. package/lib/src/interfaces/Track.js +1 -0
  202. package/lib/src/interfaces/TrackMetadataBase.d.ts +28 -0
  203. package/lib/src/interfaces/TrackMetadataBase.js +1 -0
  204. package/lib/src/interfaces/UpdateOptions.d.ts +52 -0
  205. package/lib/src/interfaces/UpdateOptions.js +1 -0
  206. package/lib/src/interfaces/events/AudioMetadataReceivedEvent.d.ts +33 -0
  207. package/lib/src/interfaces/events/AudioMetadataReceivedEvent.js +1 -0
  208. package/lib/src/interfaces/events/ControllerConnectedEvent.d.ts +8 -0
  209. package/lib/src/interfaces/events/ControllerConnectedEvent.js +1 -0
  210. package/lib/src/interfaces/events/EventPayloadByEvent.d.ts +73 -0
  211. package/lib/src/interfaces/events/EventPayloadByEvent.js +1 -0
  212. package/lib/src/interfaces/events/PlaybackActiveTrackChangedEvent.d.ts +24 -0
  213. package/lib/src/interfaces/events/PlaybackActiveTrackChangedEvent.js +1 -0
  214. package/lib/src/interfaces/events/PlaybackAnimatedVolumeChangedEvent.d.ts +4 -0
  215. package/lib/src/interfaces/events/PlaybackAnimatedVolumeChangedEvent.js +1 -0
  216. package/lib/src/interfaces/events/PlaybackErrorEvent.d.ts +6 -0
  217. package/lib/src/interfaces/events/PlaybackErrorEvent.js +1 -0
  218. package/lib/src/interfaces/events/PlaybackMetadataReceivedEvent.d.ts +16 -0
  219. package/lib/src/interfaces/events/PlaybackMetadataReceivedEvent.js +1 -0
  220. package/lib/src/interfaces/events/PlaybackPlayWhenReadyChangedEvent.d.ts +4 -0
  221. package/lib/src/interfaces/events/PlaybackPlayWhenReadyChangedEvent.js +1 -0
  222. package/lib/src/interfaces/events/PlaybackProgressUpdatedEvent.d.ts +4 -0
  223. package/lib/src/interfaces/events/PlaybackProgressUpdatedEvent.js +1 -0
  224. package/lib/src/interfaces/events/PlaybackQueueEndedEvent.d.ts +9 -0
  225. package/lib/src/interfaces/events/PlaybackQueueEndedEvent.js +1 -0
  226. package/lib/src/interfaces/events/PlaybackResumeEvent.d.ts +3 -0
  227. package/lib/src/interfaces/events/PlaybackResumeEvent.js +1 -0
  228. package/lib/src/interfaces/events/PlaybackTrackChangedEvent.d.ts +11 -0
  229. package/lib/src/interfaces/events/PlaybackTrackChangedEvent.js +1 -0
  230. package/lib/src/interfaces/events/PlayerErrorEvent.d.ts +6 -0
  231. package/lib/src/interfaces/events/PlayerErrorEvent.js +1 -0
  232. package/lib/src/interfaces/events/RemoteBrowseEvent.d.ts +4 -0
  233. package/lib/src/interfaces/events/RemoteBrowseEvent.js +1 -0
  234. package/lib/src/interfaces/events/RemoteCustomActionEvent.d.ts +7 -0
  235. package/lib/src/interfaces/events/RemoteCustomActionEvent.js +1 -0
  236. package/lib/src/interfaces/events/RemoteDuckEvent.d.ts +13 -0
  237. package/lib/src/interfaces/events/RemoteDuckEvent.js +1 -0
  238. package/lib/src/interfaces/events/RemoteJumpBackwardEvent.d.ts +8 -0
  239. package/lib/src/interfaces/events/RemoteJumpBackwardEvent.js +1 -0
  240. package/lib/src/interfaces/events/RemoteJumpForwardEvent.d.ts +8 -0
  241. package/lib/src/interfaces/events/RemoteJumpForwardEvent.js +1 -0
  242. package/lib/src/interfaces/events/RemotePlayIdEvent.d.ts +4 -0
  243. package/lib/src/interfaces/events/RemotePlayIdEvent.js +1 -0
  244. package/lib/src/interfaces/events/RemotePlaySearchEvent.d.ts +9 -0
  245. package/lib/src/interfaces/events/RemotePlaySearchEvent.js +1 -0
  246. package/lib/src/interfaces/events/RemoteSeekEvent.d.ts +4 -0
  247. package/lib/src/interfaces/events/RemoteSeekEvent.js +1 -0
  248. package/lib/src/interfaces/events/RemoteSetRatingEvent.d.ts +4 -0
  249. package/lib/src/interfaces/events/RemoteSetRatingEvent.js +1 -0
  250. package/lib/src/interfaces/events/RemoteSkipEvent.d.ts +3 -0
  251. package/lib/src/interfaces/events/RemoteSkipEvent.js +1 -0
  252. package/lib/src/interfaces/events/index.d.ts +18 -0
  253. package/lib/src/interfaces/events/index.js +18 -0
  254. package/lib/src/interfaces/index.d.ts +15 -0
  255. package/lib/src/interfaces/index.js +15 -0
  256. package/lib/src/resolveAssetSource.d.ts +2 -0
  257. package/lib/src/resolveAssetSource.js +3 -0
  258. package/lib/src/trackPlayer.d.ts +347 -0
  259. package/lib/src/trackPlayer.js +592 -0
  260. package/package.json +94 -0
  261. package/react-native-mp3-player.podspec +22 -0
  262. package/specs/NativeTrackPlayer.ts +148 -0
  263. package/src/constants/AndroidAudioContentType.ts +35 -0
  264. package/src/constants/AndroidAutoContentStyle.ts +10 -0
  265. package/src/constants/AppKilledPlaybackBehavior.ts +19 -0
  266. package/src/constants/Capability.ts +19 -0
  267. package/src/constants/Event.ts +164 -0
  268. package/src/constants/IOSCategory.ts +36 -0
  269. package/src/constants/IOSCategoryMode.ts +47 -0
  270. package/src/constants/IOSCategoryOptions.ts +44 -0
  271. package/src/constants/MediaItemPlayable.ts +4 -0
  272. package/src/constants/PitchAlgorithm.ts +16 -0
  273. package/src/constants/RatingType.ts +10 -0
  274. package/src/constants/RepeatMode.ts +10 -0
  275. package/src/constants/State.ts +34 -0
  276. package/src/constants/TrackType.ts +6 -0
  277. package/src/constants/index.ts +14 -0
  278. package/src/hooks/index.ts +6 -0
  279. package/src/hooks/useActiveTrack.ts +36 -0
  280. package/src/hooks/useAppIsInBackground.ts +20 -0
  281. package/src/hooks/useIsPlaying.ts +56 -0
  282. package/src/hooks/usePlayWhenReady.ts +37 -0
  283. package/src/hooks/usePlaybackState.ts +45 -0
  284. package/src/hooks/useProgress.ts +64 -0
  285. package/src/hooks/useTrackPlayerEvents.ts +48 -0
  286. package/src/index.ts +7 -0
  287. package/src/interfaces/AndroidAutoBrowseTree.ts +6 -0
  288. package/src/interfaces/AndroidOptions.ts +48 -0
  289. package/src/interfaces/CustomButtons.ts +6 -0
  290. package/src/interfaces/FeedbackOptions.ts +7 -0
  291. package/src/interfaces/MediaItem.ts +19 -0
  292. package/src/interfaces/MetadataOptions.ts +4 -0
  293. package/src/interfaces/NowPlayingMetadata.ts +5 -0
  294. package/src/interfaces/PlaybackState.ts +11 -0
  295. package/src/interfaces/PlayerOptions.ts +133 -0
  296. package/src/interfaces/Progress.ts +15 -0
  297. package/src/interfaces/ResourceObject.ts +1 -0
  298. package/src/interfaces/ServiceHandler.ts +1 -0
  299. package/src/interfaces/Track.ts +23 -0
  300. package/src/interfaces/TrackMetadataBase.ts +29 -0
  301. package/src/interfaces/UpdateOptions.ts +59 -0
  302. package/src/interfaces/events/AudioMetadataReceivedEvent.ts +37 -0
  303. package/src/interfaces/events/ControllerConnectedEvent.ts +9 -0
  304. package/src/interfaces/events/EventPayloadByEvent.ts +76 -0
  305. package/src/interfaces/events/PlaybackActiveTrackChangedEvent.ts +29 -0
  306. package/src/interfaces/events/PlaybackAnimatedVolumeChangedEvent.ts +4 -0
  307. package/src/interfaces/events/PlaybackErrorEvent.ts +6 -0
  308. package/src/interfaces/events/PlaybackMetadataReceivedEvent.ts +16 -0
  309. package/src/interfaces/events/PlaybackPlayWhenReadyChangedEvent.ts +4 -0
  310. package/src/interfaces/events/PlaybackProgressUpdatedEvent.ts +5 -0
  311. package/src/interfaces/events/PlaybackQueueEndedEvent.ts +9 -0
  312. package/src/interfaces/events/PlaybackResumeEvent.ts +5 -0
  313. package/src/interfaces/events/PlaybackTrackChangedEvent.ts +11 -0
  314. package/src/interfaces/events/PlayerErrorEvent.ts +6 -0
  315. package/src/interfaces/events/RemoteBrowseEvent.ts +4 -0
  316. package/src/interfaces/events/RemoteCustomActionEvent.ts +7 -0
  317. package/src/interfaces/events/RemoteDuckEvent.ts +13 -0
  318. package/src/interfaces/events/RemoteJumpBackwardEvent.ts +8 -0
  319. package/src/interfaces/events/RemoteJumpForwardEvent.ts +8 -0
  320. package/src/interfaces/events/RemotePlayIdEvent.ts +4 -0
  321. package/src/interfaces/events/RemotePlaySearchEvent.ts +21 -0
  322. package/src/interfaces/events/RemoteSeekEvent.ts +4 -0
  323. package/src/interfaces/events/RemoteSetRatingEvent.ts +5 -0
  324. package/src/interfaces/events/RemoteSkipEvent.ts +3 -0
  325. package/src/interfaces/events/index.ts +18 -0
  326. package/src/interfaces/index.ts +15 -0
  327. package/src/resolveAssetSource.ts +3 -0
  328. 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
+ }