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,689 @@
1
+ @file: OptIn(UnstableApi::class) package com.lovegaoshi.kotlinaudio.player
2
+
3
+ import android.content.Context
4
+ import android.media.AudioManager
5
+ import androidx.annotation.CallSuper
6
+ import androidx.annotation.OptIn
7
+ import androidx.media3.common.AudioAttributes
8
+ import androidx.media3.common.C
9
+ import androidx.media3.common.MediaItem
10
+ import androidx.media3.common.MediaMetadata
11
+ import androidx.media3.common.Metadata
12
+ import androidx.media3.common.PlaybackException
13
+ import androidx.media3.common.PlaybackParameters
14
+ import androidx.media3.common.Player
15
+ import androidx.media3.common.Player.Listener
16
+ import androidx.media3.common.TrackSelectionParameters
17
+ import androidx.media3.common.util.UnstableApi
18
+ import androidx.media3.datasource.cache.SimpleCache
19
+ import androidx.media3.exoplayer.DefaultRenderersFactory
20
+ import androidx.media3.exoplayer.ExoPlayer
21
+ import com.lovegaoshi.kotlinaudio.event.PlayerEventHolder
22
+ import com.lovegaoshi.kotlinaudio.models.AudioItem
23
+ import com.lovegaoshi.kotlinaudio.models.audioItem2MediaItem
24
+ import com.lovegaoshi.kotlinaudio.models.AudioItemTransitionReason
25
+ import com.lovegaoshi.kotlinaudio.models.AudioPlayerState
26
+ import com.lovegaoshi.kotlinaudio.models.mediaItem2AudioItem
27
+ import com.lovegaoshi.kotlinaudio.models.MediaSessionCallback
28
+ import com.lovegaoshi.kotlinaudio.models.PlayWhenReadyChangeData
29
+ import com.lovegaoshi.kotlinaudio.models.PlaybackError
30
+ import com.lovegaoshi.kotlinaudio.models.PlayerOptions
31
+ import com.lovegaoshi.kotlinaudio.models.PositionChangedReason
32
+ import com.lovegaoshi.kotlinaudio.models.setWakeMode
33
+ import com.lovegaoshi.kotlinaudio.player.components.Cache
34
+ import com.lovegaoshi.kotlinaudio.player.components.FocusManager
35
+ import com.lovegaoshi.kotlinaudio.player.components.MediaFactory
36
+ import com.lovegaoshi.kotlinaudio.player.components.setupBuffer
37
+ import kotlinx.coroutines.Deferred
38
+ import kotlinx.coroutines.MainScope
39
+ import kotlinx.coroutines.async
40
+ import kotlinx.coroutines.delay
41
+ import kotlinx.coroutines.launch
42
+ import timber.log.Timber
43
+ import java.util.Locale
44
+ import java.util.concurrent.TimeUnit
45
+ import kotlin.math.min
46
+
47
+ abstract class AudioPlayer internal constructor(
48
+ private val context: Context,
49
+ val options: PlayerOptions = PlayerOptions()
50
+ ) {
51
+
52
+ // for crossfading
53
+ private var exoPlayer1: ExoPlayer
54
+ private var exoPlayer2: ExoPlayer? = null
55
+ private var currentExoPlayer = true
56
+
57
+ var exoPlayer: ExoPlayer
58
+ var player: ForwardingPlayer
59
+ private var playerListener = PlayerListener()
60
+ private val scope = MainScope()
61
+ private var cache: SimpleCache? = null
62
+ val playerEventHolder = PlayerEventHolder()
63
+ private val focusListener = APMFocusListener()
64
+ private val focusManager = FocusManager(context, listener=focusListener, options=options)
65
+
66
+ var alwaysPauseOnInterruption: Boolean
67
+ get() = focusManager.alwaysPauseOnInterruption
68
+ set(v) { focusManager.alwaysPauseOnInterruption = v }
69
+
70
+ open val currentItem: AudioItem?
71
+ get() = mediaItem2AudioItem(exoPlayer.currentMediaItem)
72
+
73
+ var playbackError: PlaybackError? = null
74
+ var playerState: AudioPlayerState = AudioPlayerState.IDLE
75
+ private set(value) {
76
+ if (value != field) {
77
+ field = value
78
+ playerEventHolder.updateAudioPlayerState(value)
79
+ if (!options.handleAudioFocus) {
80
+ when (value) {
81
+ AudioPlayerState.IDLE,
82
+ AudioPlayerState.ERROR -> focusManager.abandonAudioFocusIfHeld()
83
+ AudioPlayerState.READY -> focusManager.requestAudioFocus()
84
+ else -> {}
85
+ }
86
+ }
87
+ }
88
+ }
89
+
90
+ var playWhenReady: Boolean
91
+ get() = exoPlayer.playWhenReady
92
+ set(value) {
93
+ exoPlayer.playWhenReady = value
94
+ }
95
+
96
+ val duration: Long
97
+ get() {
98
+ return if (exoPlayer.duration == C.TIME_UNSET) 0
99
+ else exoPlayer.duration
100
+ }
101
+
102
+ val isCurrentMediaItemLive: Boolean
103
+ get() = exoPlayer.isCurrentMediaItemLive
104
+
105
+ private var oldPosition = 0L
106
+
107
+ val position: Long
108
+ get() {
109
+ return if (exoPlayer.currentPosition == C.INDEX_UNSET.toLong()) 0
110
+ else exoPlayer.currentPosition
111
+ }
112
+
113
+ val bufferedPosition: Long
114
+ get() {
115
+ return if (exoPlayer.bufferedPosition == C.INDEX_UNSET.toLong()) 0
116
+ else exoPlayer.bufferedPosition
117
+ }
118
+
119
+ private var volumeMultiplier = 1f
120
+ set(value) {
121
+ field = value
122
+ volume = volume
123
+ }
124
+
125
+ var volume: Float
126
+ get() = exoPlayer.volume
127
+ set(value) {
128
+ exoPlayer.volume = value * volumeMultiplier
129
+ }
130
+
131
+ /**
132
+ * fade volume of the current exoPlayer by a simple linear function.
133
+ */
134
+ fun fadeVolume(volume: Float = 1f, duration: Long = 500, interval: Long = 20L, callback: () -> Unit = { }): Deferred<Unit> {
135
+ return scope.async {
136
+ val volumeDiff = (volume - exoPlayer.volume) * interval / duration
137
+ var fadeInDuration = duration
138
+ while (fadeInDuration > 0) {
139
+ fadeInDuration -= interval
140
+ exoPlayer.volume += volumeDiff
141
+ delay(interval)
142
+ }
143
+ exoPlayer.volume = volume
144
+ callback()
145
+ return@async
146
+ }
147
+ }
148
+
149
+ var playbackSpeed: Float
150
+ get() = exoPlayer.playbackParameters.speed
151
+ set(value) {
152
+ exoPlayer.setPlaybackSpeed(value)
153
+ }
154
+
155
+ var playbackPitch: Float
156
+ get() = exoPlayer.playbackParameters.pitch
157
+ set(v) {
158
+ exoPlayer.playbackParameters = PlaybackParameters(playbackSpeed, v)
159
+ }
160
+
161
+ val isPlaying
162
+ get() = exoPlayer.isPlaying
163
+
164
+ private var wasDucking = false
165
+
166
+ fun players (): List<ExoPlayer> {
167
+ if (options.crossfade) {
168
+ return listOf(exoPlayer1, exoPlayer2!!)
169
+ }
170
+ return listOf(exoPlayer)
171
+ }
172
+
173
+ fun setAudioOffload(offload: Boolean = true) {
174
+ val audioOffloadPreferences =
175
+ TrackSelectionParameters.AudioOffloadPreferences.Builder()
176
+ .setAudioOffloadMode(
177
+ if (offload) TrackSelectionParameters.AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_ENABLED
178
+ else TrackSelectionParameters.AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_DISABLED)
179
+ // Add additional options as needed
180
+ .setIsGaplessSupportRequired(true)
181
+ .setIsSpeedChangeSupportRequired(true)
182
+ .build()
183
+ exoPlayer.trackSelectionParameters =
184
+ exoPlayer.trackSelectionParameters
185
+ .buildUpon()
186
+ .setAudioOffloadPreferences(audioOffloadPreferences)
187
+ .build()
188
+ }
189
+
190
+ private fun initExoPlayer(name: String): ExoPlayer {
191
+ val renderer = DefaultRenderersFactory(context)
192
+ renderer.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER)
193
+ val mPlayer = ExoPlayer
194
+ .Builder(context)
195
+ .setRenderersFactory(renderer)
196
+ .setHandleAudioBecomingNoisy(options.handleAudioBecomingNoisy)
197
+ .setMediaSourceFactory(MediaFactory(context, cache))
198
+ .setWakeMode(setWakeMode(options.wakeMode))
199
+ .apply {
200
+ setLoadControl(setupBuffer(options.bufferOptions))
201
+ }
202
+ .setSkipSilenceEnabled(options.skipSilence)
203
+ .setName(name)
204
+ .build()
205
+ val audioAttributes = AudioAttributes.Builder()
206
+ .setUsage(C.USAGE_MEDIA)
207
+ .setContentType(options.audioContentType)
208
+ .build()
209
+ mPlayer.setAudioAttributes(audioAttributes, options.handleAudioFocus)
210
+ return mPlayer
211
+ }
212
+
213
+ init {
214
+ if (options.cacheSize > 0) {
215
+ try {
216
+ Timber.tag("RNTP").d("Initializing cache with size: ${options.cacheSize}")
217
+ cache = Cache.initCache(context, options.cacheSize)
218
+ Timber.tag("RNTP").d("Cache initialized successfully: ${cache}")
219
+ } catch (e: Exception) {
220
+ Timber.tag("RNTP").e(e, "Failed to initialize cache, proceeding without cache")
221
+ cache = null
222
+ }
223
+ } else {
224
+ Timber.tag("RNTP").d("Cache disabled (size <= 0): ${options.cacheSize}")
225
+ }
226
+ playerEventHolder.updateAudioPlayerState(AudioPlayerState.IDLE)
227
+ exoPlayer1 = initExoPlayer("APM-Player1")
228
+ if (options.crossfade) { exoPlayer2 = initExoPlayer("APM-Player2") }
229
+ exoPlayer = exoPlayer1
230
+ player = if (options.nativeExample) ExampleForwardingPlayer(exoPlayer1, exoPlayer2) else APMForwardingPlayer(exoPlayer1, exoPlayer2)
231
+ player.addListener(playerListener)
232
+
233
+ }
234
+
235
+ /**
236
+ * Will replace the current item with a new one and load it into the player.
237
+ * @param item The [AudioItem] to replace the current one.
238
+ * @param playWhenReady Whether playback starts automatically.
239
+ */
240
+ open fun load(item: AudioItem, playWhenReady: Boolean = true) {
241
+ exoPlayer.playWhenReady = playWhenReady
242
+ load(item)
243
+ }
244
+
245
+ /**
246
+ * Will replace the current item with a new one and load it into the player.
247
+ * @param item The [AudioItem] to replace the current one.
248
+ */
249
+ open fun load(item: AudioItem) {
250
+ players().forEach { p -> p.addMediaItem(audioItem2MediaItem(item)) }
251
+ exoPlayer.prepare()
252
+ }
253
+
254
+ fun togglePlaying() {
255
+ if (exoPlayer.isPlaying) {
256
+ pause()
257
+ } else {
258
+ play()
259
+ }
260
+ }
261
+
262
+ var skipSilence: Boolean
263
+ get() = exoPlayer.skipSilenceEnabled
264
+ set(value) {
265
+ players().forEach { p -> p.skipSilenceEnabled = value }
266
+ }
267
+
268
+ fun play() {
269
+ exoPlayer.play()
270
+ if (currentItem != null) {
271
+ exoPlayer.prepare()
272
+ }
273
+ }
274
+
275
+ fun prepare() {
276
+ if (currentItem != null) {
277
+ exoPlayer.prepare()
278
+ }
279
+ }
280
+
281
+ fun pause() {
282
+ exoPlayer.pause()
283
+ }
284
+
285
+ /**
286
+ * Stops playback, without clearing the active item. Calling this method will cause the playback
287
+ * state to transition to AudioPlayerState.IDLE and the player will release the loaded media and
288
+ * resources required for playback.
289
+ */
290
+ @CallSuper
291
+ open fun stop() {
292
+ playerState = AudioPlayerState.STOPPED
293
+ exoPlayer.playWhenReady = false
294
+ exoPlayer.stop()
295
+ }
296
+
297
+ @CallSuper
298
+ open fun clear() {
299
+ players().forEach { p -> p.clearMediaItems() }
300
+ }
301
+
302
+ /**
303
+ * Pause playback whenever an item plays to its end.
304
+ */
305
+ fun setPauseAtEndOfItem(pause: Boolean) {
306
+ exoPlayer.pauseAtEndOfMediaItems = pause
307
+ }
308
+
309
+ /**
310
+ * Stops and destroys the player. Only call this when you are finished using the player, otherwise use [pause].
311
+ */
312
+ @CallSuper
313
+ open fun destroy() {
314
+ focusManager.abandonAudioFocusIfHeld()
315
+ stop()
316
+
317
+ players().forEach { p ->
318
+ p.removeListener(playerListener)
319
+ p.release()
320
+ }
321
+ cache?.release()
322
+ cache = null
323
+ }
324
+
325
+ open fun seek(duration: Long, unit: TimeUnit) {
326
+ val positionMs = TimeUnit.MILLISECONDS.convert(duration, unit)
327
+ exoPlayer.seekTo(positionMs)
328
+ }
329
+
330
+ open fun seekBy(offset: Long, unit: TimeUnit) {
331
+ val positionMs = exoPlayer.currentPosition + TimeUnit.MILLISECONDS.convert(offset, unit)
332
+ exoPlayer.seekTo(positionMs)
333
+ }
334
+
335
+ fun crossFadePrepare(previous: Boolean = false, seekTo: Double = 0.0) {
336
+ if (!options.crossfade) { return }
337
+ val mPlayer = if (currentExoPlayer) exoPlayer2!! else exoPlayer1
338
+ // align playing index
339
+ mPlayer.seekTo(exoPlayer.currentMediaItemIndex, C.TIME_UNSET)
340
+ if (previous) { mPlayer.seekToPreviousMediaItem() }
341
+ else { mPlayer.seekToNextMediaItem() }
342
+ mPlayer.prepare()
343
+ if (seekTo > 0) {
344
+ mPlayer.seekTo((seekTo * 1000).toLong())
345
+ }
346
+ }
347
+
348
+ /**
349
+ * switches rotating exoplayers to achieve crossfade.
350
+ * playerOperation:
351
+ */
352
+ fun switchExoPlayer(
353
+ playerOperation: () -> Unit = ::play,
354
+ fadeDuration: Long = 2500,
355
+ fadeInterval: Long = 20,
356
+ fadeToVolume: Float = 1f,
357
+ waitUntil: Long = 0,
358
+ ){
359
+ if (!options.crossfade) {
360
+ playerOperation()
361
+ return
362
+ }
363
+ scope.launch {
364
+ val delayAmount = if (waitUntil == 0L) 0 else {
365
+ 0L.coerceAtLeast(waitUntil - player.currentPosition)
366
+ }
367
+ delay(delayAmount)
368
+
369
+ val prevPlayer: Player
370
+ if (currentExoPlayer) {
371
+ currentExoPlayer = false
372
+ exoPlayer = exoPlayer2!!
373
+ prevPlayer = exoPlayer1
374
+ } else {
375
+ currentExoPlayer = true
376
+ exoPlayer = exoPlayer1
377
+ prevPlayer = exoPlayer2!!
378
+ }
379
+ prevPlayer.setAudioAttributes(prevPlayer.audioAttributes, false)
380
+ player.switchCrossFadePlayer()
381
+ scope.launch {
382
+ var fadeOutDuration = fadeDuration
383
+ val startFadeOutTime = System.currentTimeMillis()
384
+ val fadeFromVolume = prevPlayer.volume
385
+ while (fadeOutDuration > 0) {
386
+ fadeOutDuration -= fadeInterval
387
+ prevPlayer.volume = fadeFromVolume * (1 - min((System.currentTimeMillis() - startFadeOutTime), fadeDuration).toFloat() / fadeDuration)
388
+ delay(fadeInterval)
389
+ }
390
+ prevPlayer.volume = 0f
391
+ prevPlayer.pause()
392
+ }
393
+ scope.launch {
394
+ exoPlayer.volume = 0f
395
+ playerOperation()
396
+ exoPlayer.setAudioAttributes(exoPlayer.audioAttributes, options.handleAudioFocus)
397
+ if (fadeToVolume > 0) {
398
+ var fadeInDuration = fadeDuration
399
+ val startTime = System.currentTimeMillis()
400
+ while (fadeInDuration > 0) {
401
+ fadeInDuration -= fadeInterval
402
+ exoPlayer.volume = fadeToVolume * min((System.currentTimeMillis() - startTime), fadeDuration) / fadeDuration
403
+ delay(fadeInterval)
404
+ }
405
+ }
406
+ // player.broadcastMediaItem()
407
+ }
408
+ }
409
+ }
410
+
411
+ inner class PlayerListener : Listener {
412
+
413
+ /**
414
+ * Called when there is metadata associated with the current playback time.
415
+ */
416
+ override fun onMetadata(metadata: Metadata) {
417
+ playerEventHolder.updateOnTimedMetadata(metadata)
418
+ }
419
+
420
+ override fun onMediaMetadataChanged(mediaMetadata: MediaMetadata) {
421
+ playerEventHolder.updateOnCommonMetadata(mediaMetadata)
422
+ }
423
+
424
+ /**
425
+ * A position discontinuity occurs when the playing period changes, the playback position
426
+ * jumps within the period currently being played, or when the playing period has been
427
+ * skipped or removed.
428
+ */
429
+ override fun onPositionDiscontinuity(
430
+ oldPosition: Player.PositionInfo,
431
+ newPosition: Player.PositionInfo,
432
+ reason: Int
433
+ ) {
434
+ this@AudioPlayer.oldPosition = oldPosition.positionMs
435
+
436
+ when (reason) {
437
+ Player.DISCONTINUITY_REASON_AUTO_TRANSITION -> playerEventHolder.updatePositionChangedReason(
438
+ PositionChangedReason.AUTO(oldPosition.positionMs, newPosition.positionMs)
439
+ )
440
+ Player.DISCONTINUITY_REASON_SEEK -> playerEventHolder.updatePositionChangedReason(
441
+ PositionChangedReason.SEEK(oldPosition.positionMs, newPosition.positionMs)
442
+ )
443
+ Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT -> playerEventHolder.updatePositionChangedReason(
444
+ PositionChangedReason.SEEK_FAILED(
445
+ oldPosition.positionMs,
446
+ newPosition.positionMs
447
+ )
448
+ )
449
+ Player.DISCONTINUITY_REASON_REMOVE -> playerEventHolder.updatePositionChangedReason(
450
+ PositionChangedReason.QUEUE_CHANGED(
451
+ oldPosition.positionMs,
452
+ newPosition.positionMs
453
+ )
454
+ )
455
+ Player.DISCONTINUITY_REASON_SKIP -> playerEventHolder.updatePositionChangedReason(
456
+ PositionChangedReason.SKIPPED_PERIOD(
457
+ oldPosition.positionMs,
458
+ newPosition.positionMs
459
+ )
460
+ )
461
+ Player.DISCONTINUITY_REASON_INTERNAL -> playerEventHolder.updatePositionChangedReason(
462
+ PositionChangedReason.UNKNOWN(oldPosition.positionMs, newPosition.positionMs)
463
+ )
464
+
465
+ Player.DISCONTINUITY_REASON_SILENCE_SKIP -> playerEventHolder.updatePositionChangedReason(
466
+ PositionChangedReason.UNKNOWN(oldPosition.positionMs, newPosition.positionMs)
467
+ )
468
+ }
469
+ }
470
+
471
+ /**
472
+ * Called when playback transitions to a media item or starts repeating a media item
473
+ * according to the current repeat mode. Note that this callback is also called when the
474
+ * playlist becomes non-empty or empty as a consequence of a playlist change.
475
+ */
476
+ override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
477
+ when (reason) {
478
+ Player.MEDIA_ITEM_TRANSITION_REASON_AUTO -> playerEventHolder.updateAudioItemTransition(
479
+ AudioItemTransitionReason.AUTO(oldPosition)
480
+ )
481
+ Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED -> playerEventHolder.updateAudioItemTransition(
482
+ AudioItemTransitionReason.QUEUE_CHANGED(oldPosition)
483
+ )
484
+ Player.MEDIA_ITEM_TRANSITION_REASON_REPEAT -> playerEventHolder.updateAudioItemTransition(
485
+ AudioItemTransitionReason.REPEAT(oldPosition)
486
+ )
487
+ Player.MEDIA_ITEM_TRANSITION_REASON_SEEK -> playerEventHolder.updateAudioItemTransition(
488
+ AudioItemTransitionReason.SEEK_TO_ANOTHER_AUDIO_ITEM(oldPosition)
489
+ )
490
+ }
491
+ }
492
+
493
+ /**
494
+ * Called when the value returned from Player.getPlayWhenReady() changes.
495
+ */
496
+ override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) {
497
+ val pausedBecauseReachedEnd = reason == Player.PLAY_WHEN_READY_CHANGE_REASON_END_OF_MEDIA_ITEM
498
+ playerEventHolder.updatePlayWhenReadyChange(PlayWhenReadyChangeData(playWhenReady, pausedBecauseReachedEnd))
499
+ }
500
+
501
+ /**
502
+ * The generic onEvents callback provides access to the Player object and specifies the set
503
+ * of events that occurred together. It's always called after the callbacks that correspond
504
+ * to the individual events.
505
+ */
506
+ override fun onEvents(player: Player, events: Player.Events) {
507
+ // Note that it is necessary to set `playerState` in order, since each mutation fires an
508
+ // event.
509
+ for (i in 0 until events.size()) {
510
+ when (events[i]) {
511
+ Player.EVENT_PLAYBACK_STATE_CHANGED -> {
512
+ val state = when (player.playbackState) {
513
+ Player.STATE_BUFFERING -> AudioPlayerState.BUFFERING
514
+ Player.STATE_READY -> AudioPlayerState.READY
515
+ Player.STATE_IDLE ->
516
+ // Avoid transitioning to idle from error or stopped
517
+ if (
518
+ playerState == AudioPlayerState.ERROR ||
519
+ playerState == AudioPlayerState.STOPPED
520
+ )
521
+ null
522
+ else
523
+ AudioPlayerState.IDLE
524
+ Player.STATE_ENDED ->
525
+ if (player.mediaItemCount > 0) AudioPlayerState.ENDED
526
+ else AudioPlayerState.IDLE
527
+ else -> null // noop
528
+ }
529
+ if (state != null && state != playerState) {
530
+ playerState = state
531
+ }
532
+ }
533
+ Player.EVENT_MEDIA_ITEM_TRANSITION -> {
534
+ playbackError = null
535
+ if (currentItem != null) {
536
+ playerState = AudioPlayerState.LOADING
537
+ if (isPlaying) {
538
+ playerState = AudioPlayerState.READY
539
+ playerState = AudioPlayerState.PLAYING
540
+ }
541
+ }
542
+ }
543
+ Player.EVENT_PLAY_WHEN_READY_CHANGED -> {
544
+ if (!player.playWhenReady && playerState != AudioPlayerState.STOPPED) {
545
+ playerState = AudioPlayerState.PAUSED
546
+ }
547
+ }
548
+ Player.EVENT_IS_PLAYING_CHANGED -> {
549
+ if (player.isPlaying) {
550
+ playerState = AudioPlayerState.PLAYING
551
+ }
552
+ }
553
+ }
554
+ }
555
+ }
556
+
557
+ override fun onPlayerError(error: PlaybackException) {
558
+ val _playbackError = PlaybackError(
559
+ error.errorCodeName
560
+ .replace("ERROR_CODE_", "")
561
+ .lowercase(Locale.getDefault())
562
+ .replace("_", "-"),
563
+ error.message
564
+ )
565
+ playerEventHolder.updatePlaybackError(_playbackError)
566
+ playbackError = _playbackError
567
+ playerState = AudioPlayerState.ERROR
568
+ }
569
+ }
570
+
571
+
572
+ private open inner class ExampleForwardingPlayer
573
+ (val mPlayer1: ExoPlayer, val mPlayer2: ExoPlayer?): ForwardingPlayer(mPlayer1, mPlayer2) {
574
+ override fun setMediaItems(mediaItems: MutableList<MediaItem>, resetPosition: Boolean) {
575
+ mPlayer1.setMediaItems(mediaItems, resetPosition)
576
+ mPlayer2?.setMediaItems(mediaItems, resetPosition)
577
+ }
578
+ override fun isCommandAvailable(command: Int): Boolean {
579
+ if (options.alwaysShowNext) {
580
+ return when (command) {
581
+ COMMAND_SEEK_TO_NEXT_MEDIA_ITEM -> true
582
+ COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM -> true
583
+ else -> super.isCommandAvailable(command)
584
+ }
585
+ }
586
+ return super.isCommandAvailable(command)
587
+ }
588
+
589
+ override fun getAvailableCommands(): Player.Commands {
590
+ if (options.alwaysShowNext) {
591
+ return super.getAvailableCommands().buildUpon()
592
+ .add(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)
593
+ .add(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)
594
+ .build()
595
+ }
596
+ return super.getAvailableCommands()
597
+ }
598
+ }
599
+
600
+ private inner class APMForwardingPlayer
601
+ (mPlayer1: ExoPlayer, mPlayer2: ExoPlayer?): ExampleForwardingPlayer(mPlayer1, mPlayer2) {
602
+ override fun setMediaItems(mediaItems: MutableList<MediaItem>, resetPosition: Boolean) {
603
+ // override setMediaItem handling to RNTP
604
+ return
605
+ }
606
+
607
+ override fun addMediaItems(mediaItems: MutableList<MediaItem>) {
608
+ // override setMediaItem handling to RNTP
609
+ return
610
+ }
611
+
612
+ override fun addMediaItems(index: Int, mediaItems: MutableList<MediaItem>) {
613
+ // override setMediaItem handling to RNTP
614
+ return
615
+ }
616
+
617
+ override fun setMediaItems(
618
+ mediaItems: MutableList<MediaItem>,
619
+ startIndex: Int,
620
+ startPositionMs: Long
621
+ ) {
622
+ // override setMediaItem handling to RNTP
623
+ return
624
+ }
625
+
626
+ override fun setMediaItems(mediaItems: MutableList<MediaItem>) {
627
+ // override setMediaItem handling to RNTP
628
+ return
629
+ }
630
+
631
+ override fun play() {
632
+ playerEventHolder.updateOnPlayerActionTriggeredExternally(MediaSessionCallback.PLAY)
633
+ }
634
+
635
+ override fun pause() {
636
+ playerEventHolder.updateOnPlayerActionTriggeredExternally(MediaSessionCallback.PAUSE)
637
+ }
638
+
639
+ override fun seekToNext() {
640
+ playerEventHolder.updateOnPlayerActionTriggeredExternally(MediaSessionCallback.NEXT)
641
+ }
642
+
643
+ override fun seekToNextMediaItem() {
644
+ playerEventHolder.updateOnPlayerActionTriggeredExternally(MediaSessionCallback.NEXT)
645
+ }
646
+
647
+ override fun seekToPrevious() {
648
+ playerEventHolder.updateOnPlayerActionTriggeredExternally(MediaSessionCallback.PREVIOUS)
649
+ }
650
+
651
+ override fun seekToPreviousMediaItem() {
652
+ playerEventHolder.updateOnPlayerActionTriggeredExternally(MediaSessionCallback.PREVIOUS)
653
+ }
654
+
655
+ override fun seekForward() {
656
+ playerEventHolder.updateOnPlayerActionTriggeredExternally(MediaSessionCallback.FORWARD)
657
+ }
658
+
659
+ override fun seekBack() {
660
+ playerEventHolder.updateOnPlayerActionTriggeredExternally(MediaSessionCallback.REWIND)
661
+ }
662
+
663
+ override fun stop() {
664
+ playerEventHolder.updateOnPlayerActionTriggeredExternally(MediaSessionCallback.STOP)
665
+ }
666
+
667
+ override fun seekTo(mediaItemIndex: Int, positionMs: Long) {
668
+ playerEventHolder.updateOnPlayerActionTriggeredExternally(
669
+ MediaSessionCallback.SEEK(
670
+ positionMs
671
+ )
672
+ )
673
+ }
674
+
675
+ override fun seekTo(positionMs: Long) {
676
+ playerEventHolder.updateOnPlayerActionTriggeredExternally(
677
+ MediaSessionCallback.SEEK(
678
+ positionMs
679
+ )
680
+ )
681
+ }
682
+ }
683
+
684
+ private inner class APMFocusListener: AudioManager.OnAudioFocusChangeListener {
685
+ override fun onAudioFocusChange(focusChange: Int) {
686
+ // TODO: complete focusManager logic here
687
+ }
688
+ }
689
+ }