@javascriptcommon/react-native-track-player 1.2.23 → 4.1.5

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