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,295 @@
1
+ @file: OptIn(UnstableApi::class) package com.lovegaoshi.kotlinaudio.player
2
+
3
+ import android.content.Context
4
+ import androidx.annotation.OptIn
5
+ import androidx.media3.common.C
6
+ import androidx.media3.common.IllegalSeekPositionException
7
+ import androidx.media3.common.MediaItem
8
+ import androidx.media3.common.Player
9
+ import androidx.media3.common.util.UnstableApi
10
+ import com.lovegaoshi.kotlinaudio.models.*
11
+ import java.util.*
12
+ import kotlin.math.max
13
+ import kotlin.math.min
14
+ import timber.log.Timber
15
+
16
+ class QueuedAudioPlayer(
17
+ private val context: Context,
18
+ options: PlayerOptions = PlayerOptions()
19
+ ) : AudioPlayer(context, options) {
20
+
21
+ var parseEmbeddedArtwork: Boolean = false
22
+
23
+ private val queue = LinkedList<MediaItem>()
24
+
25
+ private fun parseAudioItem(audioItem: AudioItem, skipSavingEmbeddedArtwork: Boolean = false): MediaItem {
26
+ return audioItem2MediaItem(audioItem, if (parseEmbeddedArtwork && !skipSavingEmbeddedArtwork) context else null, skipSavingEmbeddedArtwork)
27
+ }
28
+
29
+ var repeatMode: RepeatMode
30
+ get() {
31
+ return when (exoPlayer.repeatMode) {
32
+ Player.REPEAT_MODE_ALL -> RepeatMode.ALL
33
+ Player.REPEAT_MODE_ONE -> RepeatMode.ONE
34
+ else -> RepeatMode.OFF
35
+ }
36
+ }
37
+ set(value) {
38
+ when (value) {
39
+ RepeatMode.ALL -> players().forEach { p -> p.repeatMode = Player.REPEAT_MODE_ALL }
40
+ RepeatMode.ONE -> players().forEach { p -> p.repeatMode = Player.REPEAT_MODE_ONE }
41
+ RepeatMode.OFF -> players().forEach { p -> p.repeatMode = Player.REPEAT_MODE_OFF }
42
+ }
43
+ }
44
+
45
+ val currentIndex
46
+ get() = exoPlayer.currentMediaItemIndex
47
+
48
+ var shuffleMode
49
+ get() = exoPlayer.shuffleModeEnabled
50
+ set(v) {
51
+ players().forEach{ p -> p.shuffleModeEnabled = v }
52
+ }
53
+
54
+ override val currentItem: AudioItem?
55
+ get() = mediaItem2AudioItem(queue.getOrNull(currentIndex))
56
+
57
+ val nextIndex: Int?
58
+ get() {
59
+ return if (exoPlayer.nextMediaItemIndex == C.INDEX_UNSET) null
60
+ else exoPlayer.nextMediaItemIndex
61
+ }
62
+
63
+ val previousIndex: Int?
64
+ get() {
65
+ return if (exoPlayer.previousMediaItemIndex == C.INDEX_UNSET) null
66
+ else exoPlayer.previousMediaItemIndex
67
+ }
68
+
69
+ val items: List<AudioItem>
70
+ get() = queue.map { mediaItem2AudioItem(it)!! }
71
+
72
+ val previousItems: List<AudioItem>
73
+ get() {
74
+ return if (queue.isEmpty()) emptyList()
75
+ else queue
76
+ .subList(0, exoPlayer.currentMediaItemIndex)
77
+ .map { mediaItem2AudioItem(it)!! }
78
+ }
79
+
80
+ val nextItems: List<AudioItem>
81
+ get() {
82
+ return if (queue.isEmpty()) emptyList()
83
+ else queue
84
+ .subList(exoPlayer.currentMediaItemIndex, queue.lastIndex)
85
+ .map { mediaItem2AudioItem(it)!! }
86
+ }
87
+
88
+ val nextItem: AudioItem?
89
+ get() = items.getOrNull(currentIndex + 1)
90
+
91
+ val previousItem: AudioItem?
92
+ get() = items.getOrNull(currentIndex - 1)
93
+
94
+ override fun load(item: AudioItem, playWhenReady: Boolean) {
95
+ load(item)
96
+ exoPlayer.playWhenReady = playWhenReady
97
+ }
98
+
99
+ override fun load(item: AudioItem) {
100
+ if (queue.isEmpty()) {
101
+ add(item)
102
+ } else {
103
+ players().forEach { p ->
104
+ p.replaceMediaItem(currentIndex, parseAudioItem(item))
105
+ p.seekTo(currentIndex, C.TIME_UNSET)
106
+ }
107
+ exoPlayer.prepare()
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Add a single item to the queue. If the AudioPlayer has no item loaded, it will load the `item`.
113
+ * @param item The [AudioItem] to add.
114
+ */
115
+ fun add(item: AudioItem, playWhenReady: Boolean) {
116
+ exoPlayer.playWhenReady = playWhenReady
117
+ add(item)
118
+ }
119
+
120
+ /**
121
+ * Add a single item to the queue. If the AudioPlayer has no item loaded, it will load the `item`.
122
+ * @param item The [AudioItem] to add.
123
+ */
124
+ fun add(item: AudioItem) {
125
+ val mediaSource = parseAudioItem(item)
126
+ queue.add(mediaSource)
127
+ players().forEach { p -> p.addMediaItem(mediaSource) }
128
+ exoPlayer.prepare()
129
+ }
130
+
131
+ /**
132
+ * Add multiple items to the queue. If the AudioPlayer has no item loaded, it will load the first item in the list.
133
+ * @param items The [AudioItem]s to add.
134
+ * @param playWhenReady Whether playback starts automatically.
135
+ */
136
+ fun add(items: List<AudioItem>, playWhenReady: Boolean) {
137
+ exoPlayer.playWhenReady = playWhenReady
138
+ add(items)
139
+ }
140
+
141
+ /**
142
+ * Add multiple items to the queue. If the AudioPlayer has no item loaded, it will load the first item in the list.
143
+ * @param items The [AudioItem]s to add.
144
+ */
145
+ fun add(items: List<AudioItem>) {
146
+ try {
147
+ // disable embedded artwork extraction for multiple items to prevent blocking I/O operations
148
+ timber.log.Timber.tag("RNTP").d("QueuedAudioPlayer.add: Parsing ${items.size} items with skipSavingEmbeddedArtwork=true")
149
+ val mediaSources = items.map { parseAudioItem(it, skipSavingEmbeddedArtwork = true) }
150
+
151
+ timber.log.Timber.tag("RNTP").d("QueuedAudioPlayer.add: Adding ${mediaSources.size} media sources to queue")
152
+ queue.addAll(mediaSources)
153
+
154
+ timber.log.Timber.tag("RNTP").d("QueuedAudioPlayer.add: Adding media items to all players")
155
+ players().forEach { p -> p.addMediaItems(mediaSources) }
156
+
157
+ timber.log.Timber.tag("RNTP").d("QueuedAudioPlayer.add: Calling exoPlayer.prepare()")
158
+ exoPlayer.prepare()
159
+
160
+ timber.log.Timber.tag("RNTP").d("QueuedAudioPlayer.add: Successfully completed")
161
+ } catch (exception: Exception) {
162
+ timber.log.Timber.tag("RNTP").e(exception, "QueuedAudioPlayer.add: Error adding items")
163
+ throw exception
164
+ }
165
+ }
166
+
167
+
168
+ /**
169
+ * Add multiple items to the queue.
170
+ * @param items The [AudioItem]s to add.
171
+ * @param atIndex Index to insert items at, if no items loaded this will not automatically start playback.
172
+ */
173
+ fun add(items: List<AudioItem>, atIndex: Int) {
174
+ // disable embedded artwork extraction for multiple items to prevent blocking I/O operations
175
+ val mediaSources = items.map { parseAudioItem(it, skipSavingEmbeddedArtwork = true) }
176
+ queue.addAll(atIndex, mediaSources)
177
+ players().forEach { p -> p.addMediaItems(atIndex, mediaSources) }
178
+ exoPlayer.prepare()
179
+ }
180
+
181
+ /**
182
+ * Remove an item from the queue.
183
+ * @param index The index of the item to remove.
184
+ */
185
+ fun remove(index: Int) {
186
+ queue.removeAt(index)
187
+ players().forEach { p -> p.removeMediaItem(index) }
188
+ }
189
+
190
+ /**
191
+ * Remove items from the queue.
192
+ * @param indexes The indexes of the items to remove.
193
+ */
194
+ fun remove(indexes: List<Int>) {
195
+ val sorted = indexes.toMutableList()
196
+ // Sort the indexes in descending order so we can safely remove them one by one
197
+ // without having the next index possibly newly pointing to another item than intended:
198
+ sorted.sortDescending()
199
+ sorted.forEach {
200
+ remove(it)
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Skip to the next item in the queue, which may depend on the current repeat mode.
206
+ * Does nothing if there is no next item to skip to.
207
+ */
208
+ fun next() {
209
+ exoPlayer.seekToNextMediaItem()
210
+ exoPlayer.prepare()
211
+ }
212
+
213
+ /**
214
+ * Skip to the previous item in the queue, which may depend on the current repeat mode.
215
+ * Does nothing if there is no previous item to skip to.
216
+ */
217
+ fun previous() {
218
+ exoPlayer.seekToPreviousMediaItem()
219
+ exoPlayer.prepare()
220
+ }
221
+
222
+ /**
223
+ * Move an item in the queue from one position to another.
224
+ * @param fromIndex The index of the item ot move.
225
+ * @param toIndex The index to move the item to. If the index is larger than the size of the queue, the item is moved to the end of the queue instead.
226
+ */
227
+ fun move(fromIndex: Int, toIndex: Int) {
228
+ players().forEach { p -> p.moveMediaItem(fromIndex, toIndex) }
229
+ val item = queue[fromIndex]
230
+ queue.removeAt(fromIndex)
231
+ queue.add(max(0, min(items.size, if (toIndex > fromIndex) toIndex else toIndex - 1)), item)
232
+ }
233
+
234
+ /**
235
+ * Jump to an item in the queue.
236
+ * @param index the index to jump to
237
+ * @param playWhenReady Whether playback starts automatically.
238
+ */
239
+ fun jumpToItem(index: Int, playWhenReady: Boolean) {
240
+ exoPlayer.playWhenReady = playWhenReady
241
+ jumpToItem(index)
242
+ }
243
+
244
+ /**
245
+ * Jump to an item in the queue.
246
+ * @param index the index to jump to
247
+ */
248
+ fun jumpToItem(index: Int) {
249
+ try {
250
+ exoPlayer.seekTo(index, C.TIME_UNSET)
251
+ exoPlayer.prepare()
252
+ } catch (e: IllegalSeekPositionException) {
253
+ throw Error("This item index $index does not exist. The size of the queue is ${queue.size} items.")
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Replaces item at index in queue.
259
+ */
260
+ fun replaceItem(index: Int, item: AudioItem) {
261
+ val mediaSource = parseAudioItem(item)
262
+ queue[index] = mediaSource
263
+ players().forEach { p -> p.replaceMediaItem(index, mediaSource) }
264
+ }
265
+
266
+ /**
267
+ * Removes all the upcoming items, if any (the ones returned by [next]).
268
+ */
269
+ fun removeUpcomingItems() {
270
+ if (queue.lastIndex == -1 || currentIndex == -1) return
271
+ val lastIndex = queue.lastIndex + 1
272
+ val fromIndex = currentIndex + 1
273
+
274
+ players().forEach { p -> p.removeMediaItems(fromIndex, lastIndex) }
275
+ queue.subList(fromIndex, lastIndex).clear()
276
+ }
277
+
278
+ /**
279
+ * Removes all the previous items, if any (the ones returned by [previous]).
280
+ */
281
+ fun removePreviousItems() {
282
+ players().forEach { p -> p.removeMediaItems(0, currentIndex) }
283
+ queue.subList(0, currentIndex).clear()
284
+ }
285
+
286
+ override fun destroy() {
287
+ queue.clear()
288
+ super.destroy()
289
+ }
290
+
291
+ override fun clear() {
292
+ queue.clear()
293
+ super.clear()
294
+ }
295
+ }
@@ -0,0 +1,34 @@
1
+ package com.lovegaoshi.kotlinaudio.player.components
2
+
3
+ import androidx.annotation.OptIn
4
+ import androidx.media3.common.util.UnstableApi
5
+ import androidx.media3.exoplayer.DefaultLoadControl
6
+ import androidx.media3.exoplayer.DefaultLoadControl.Builder
7
+ import androidx.media3.exoplayer.DefaultLoadControl.DEFAULT_BACK_BUFFER_DURATION_MS
8
+ import androidx.media3.exoplayer.DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS
9
+ import androidx.media3.exoplayer.DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS
10
+ import androidx.media3.exoplayer.DefaultLoadControl.DEFAULT_MAX_BUFFER_MS
11
+ import androidx.media3.exoplayer.DefaultLoadControl.DEFAULT_MIN_BUFFER_MS
12
+ import com.lovegaoshi.kotlinaudio.models.BufferOptions
13
+
14
+
15
+ @OptIn(UnstableApi::class) fun setupBuffer(bufferConfig: BufferOptions): DefaultLoadControl {
16
+ bufferConfig.apply {
17
+ val multiplier =
18
+ DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS / DEFAULT_BUFFER_FOR_PLAYBACK_MS
19
+ val minBuffer =
20
+ if (minBuffer != null && minBuffer != 0) minBuffer else DEFAULT_MIN_BUFFER_MS
21
+ val maxBuffer =
22
+ if (maxBuffer != null && maxBuffer != 0) maxBuffer else DEFAULT_MAX_BUFFER_MS
23
+ val playBuffer =
24
+ if (playBuffer != null && playBuffer != 0) playBuffer else DEFAULT_BUFFER_FOR_PLAYBACK_MS
25
+ val backBuffer =
26
+ if (backBuffer != null && backBuffer != 0) backBuffer else DEFAULT_BACK_BUFFER_DURATION_MS
27
+
28
+ return Builder()
29
+ .setBufferDurationsMs(minBuffer, maxBuffer, playBuffer, playBuffer * multiplier)
30
+ .setBackBuffer(backBuffer, false)
31
+ .build()
32
+ }
33
+ }
34
+
@@ -0,0 +1,47 @@
1
+ package com.lovegaoshi.kotlinaudio.player.components
2
+
3
+ import android.content.Context
4
+ import androidx.media3.common.util.UnstableApi
5
+ import androidx.media3.database.DatabaseProvider
6
+ import androidx.media3.database.StandaloneDatabaseProvider
7
+ import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor
8
+ import androidx.media3.datasource.cache.SimpleCache
9
+ import timber.log.Timber
10
+ import java.io.File
11
+
12
+ @UnstableApi
13
+ object Cache {
14
+ @Volatile
15
+ private var instance: SimpleCache? = null
16
+
17
+ fun initCache(context: Context, size: Long): SimpleCache {
18
+ Timber.tag("RNTP").d("initCache called with size: $size")
19
+
20
+ return instance ?: synchronized(this) {
21
+ instance ?: try {
22
+ val cacheDir = File(context.cacheDir, "APM")
23
+ Timber.tag("RNTP").d("Creating cache directory: ${cacheDir.absolutePath}")
24
+
25
+ if (!cacheDir.exists()) {
26
+ val created = cacheDir.mkdirs()
27
+ Timber.tag("RNTP").d("Cache directory created: $created")
28
+ }
29
+
30
+ val db: DatabaseProvider = StandaloneDatabaseProvider(context)
31
+ Timber.tag("RNTP").d("Created database provider")
32
+
33
+ val evictor = LeastRecentlyUsedCacheEvictor(size)
34
+ Timber.tag("RNTP").d("Created cache evictor with size: $size")
35
+
36
+ val cache = SimpleCache(cacheDir, evictor, db)
37
+ Timber.tag("RNTP").d("Created SimpleCache successfully")
38
+
39
+ instance = cache
40
+ cache
41
+ } catch (e: Exception) {
42
+ Timber.tag("RNTP").e(e, "Failed to create cache")
43
+ throw e
44
+ }
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,59 @@
1
+ package com.lovegaoshi.kotlinaudio.player.components
2
+
3
+ import android.content.Context
4
+ import android.media.AudioManager
5
+ import androidx.core.content.ContextCompat
6
+ import androidx.media.AudioAttributesCompat
7
+ import androidx.media.AudioFocusRequestCompat
8
+ import androidx.media.AudioManagerCompat
9
+ import com.lovegaoshi.kotlinaudio.models.PlayerOptions
10
+
11
+ class FocusManager (
12
+ private val context: Context,
13
+ private val listener: AudioManager.OnAudioFocusChangeListener,
14
+ options: PlayerOptions
15
+ ) {
16
+ var hasAudioFocus = false
17
+ var alwaysPauseOnInterruption = options.alwaysPauseOnInterruption
18
+ private var focus: AudioFocusRequestCompat? = null
19
+
20
+ fun requestAudioFocus() {
21
+ if (hasAudioFocus) return
22
+
23
+ val manager = ContextCompat.getSystemService(context, AudioManager::class.java)
24
+
25
+ focus = AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN)
26
+ .setOnAudioFocusChangeListener(listener)
27
+ .setAudioAttributes(
28
+ AudioAttributesCompat.Builder()
29
+ .setUsage(AudioAttributesCompat.USAGE_MEDIA)
30
+ .setContentType(AudioAttributesCompat.CONTENT_TYPE_MUSIC)
31
+ .build()
32
+ )
33
+ .setWillPauseWhenDucked(alwaysPauseOnInterruption)
34
+ .build()
35
+
36
+ val result: Int = if (manager != null && focus != null) {
37
+ AudioManagerCompat.requestAudioFocus(manager, focus!!)
38
+ } else {
39
+ AudioManager.AUDIOFOCUS_REQUEST_FAILED
40
+ }
41
+
42
+ hasAudioFocus = (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED)
43
+ }
44
+
45
+ fun abandonAudioFocusIfHeld() {
46
+ if (!hasAudioFocus) return
47
+
48
+ val manager = ContextCompat.getSystemService(context, AudioManager::class.java)
49
+
50
+ val result: Int = if (manager != null && focus != null) {
51
+ AudioManagerCompat.abandonAudioFocusRequest(manager, focus!!)
52
+ } else {
53
+ AudioManager.AUDIOFOCUS_REQUEST_FAILED
54
+ }
55
+
56
+ hasAudioFocus = (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED)
57
+ }
58
+
59
+ }
@@ -0,0 +1,165 @@
1
+ package com.lovegaoshi.kotlinaudio.player.components
2
+
3
+ import android.content.Context
4
+ import android.os.Build
5
+ import androidx.annotation.OptIn
6
+ import androidx.media3.common.MediaItem
7
+ import androidx.media3.common.util.UnstableApi
8
+ import androidx.media3.datasource.DataSource
9
+ import androidx.media3.datasource.DataSpec
10
+ import androidx.media3.datasource.DefaultDataSource
11
+ import androidx.media3.datasource.DefaultHttpDataSource
12
+ import androidx.media3.datasource.RawResourceDataSource
13
+ import androidx.media3.datasource.cache.CacheDataSource
14
+ import androidx.media3.datasource.cache.SimpleCache
15
+ import androidx.media3.exoplayer.dash.DashMediaSource
16
+ import androidx.media3.exoplayer.dash.DefaultDashChunkSource
17
+ import androidx.media3.exoplayer.drm.DrmSessionManagerProvider
18
+ import androidx.media3.exoplayer.hls.HlsMediaSource
19
+ import androidx.media3.exoplayer.smoothstreaming.DefaultSsChunkSource
20
+ import androidx.media3.exoplayer.smoothstreaming.SsMediaSource
21
+ import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
22
+ import androidx.media3.exoplayer.source.MediaSource
23
+ import androidx.media3.exoplayer.source.ProgressiveMediaSource
24
+ import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy
25
+ import androidx.media3.extractor.DefaultExtractorsFactory
26
+ import com.lovegaoshi.kotlinaudio.utils.isUriLocalFile
27
+ import androidx.core.net.toUri
28
+ import timber.log.Timber
29
+
30
+
31
+ @OptIn(UnstableApi::class)
32
+ class MediaFactory (
33
+ private val context: Context,
34
+ private val cache: SimpleCache?
35
+ ) : MediaSource.Factory{
36
+
37
+ private val mediaFactory = DefaultMediaSourceFactory(context)
38
+
39
+ override fun setDrmSessionManagerProvider(drmSessionManagerProvider: DrmSessionManagerProvider): MediaSource.Factory {
40
+ return mediaFactory.setDrmSessionManagerProvider(drmSessionManagerProvider)
41
+ }
42
+
43
+ override fun setLoadErrorHandlingPolicy(loadErrorHandlingPolicy: LoadErrorHandlingPolicy): MediaSource.Factory {
44
+ return mediaFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)
45
+ }
46
+
47
+ override fun getSupportedTypes(): IntArray {
48
+ return mediaFactory.supportedTypes
49
+ }
50
+
51
+ override fun createMediaSource(mediaItem: MediaItem): MediaSource {
52
+
53
+ val userAgent = mediaItem.mediaMetadata.extras?.getString("user-agent")
54
+ val headers = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
55
+ mediaItem.mediaMetadata.extras?.getSerializable("headers", HashMap::class.java)
56
+ } else {
57
+ mediaItem.mediaMetadata.extras?.getSerializable("headers")
58
+ }
59
+ val resourceId = mediaItem.mediaMetadata.extras?.getInt("resource-id")
60
+ // HACK: why are these capitalized?
61
+ val resourceType = mediaItem.mediaMetadata.extras?.getString("type")?.lowercase()
62
+ val uri = mediaItem.mediaMetadata.extras?.getString("uri")!!.toUri()
63
+ val factory: DataSource.Factory = when {
64
+ resourceId != 0 && resourceId != null -> {
65
+ val raw = RawResourceDataSource(context)
66
+ raw.open(DataSpec(uri))
67
+ DataSource.Factory { raw }
68
+ }
69
+ isUriLocalFile(uri) -> {
70
+ DefaultDataSource.Factory(context)
71
+ }
72
+ else -> {
73
+ val tempFactory = DefaultHttpDataSource.Factory().apply {
74
+ setUserAgent(userAgent)
75
+ setAllowCrossProtocolRedirects(true)
76
+
77
+ headers?.let {
78
+ setDefaultRequestProperties(it as HashMap<String, String>)
79
+ }
80
+ }
81
+
82
+ // Only enable caching if cache is actually available
83
+ if (cache != null) {
84
+ enableCaching(tempFactory)
85
+ } else {
86
+ tempFactory
87
+ }
88
+ }
89
+ }
90
+
91
+ return when (resourceType) {
92
+ "dash" -> createDashSource(mediaItem, factory)
93
+ "hls" -> createHlsSource(mediaItem, factory)
94
+ "smoothstreaming" -> createSsSource(mediaItem, factory)
95
+ else -> createProgressiveSource(mediaItem, factory)
96
+ }
97
+ }
98
+
99
+ private fun createDashSource(mediaItem: MediaItem, factory: DataSource.Factory?): MediaSource {
100
+ return DashMediaSource.Factory(DefaultDashChunkSource.Factory(factory!!), factory)
101
+ .createMediaSource(mediaItem)
102
+ }
103
+
104
+ private fun createHlsSource(mediaItem: MediaItem, factory: DataSource.Factory?): MediaSource {
105
+ return HlsMediaSource.Factory(factory!!)
106
+ .createMediaSource(mediaItem)
107
+ }
108
+
109
+ private fun createSsSource(mediaItem: MediaItem, factory: DataSource.Factory?): MediaSource {
110
+ return SsMediaSource.Factory(DefaultSsChunkSource.Factory(factory!!), factory)
111
+ .createMediaSource(mediaItem)
112
+ }
113
+
114
+ private fun createProgressiveSource(
115
+ mediaItem: MediaItem,
116
+ factory: DataSource.Factory
117
+ ): ProgressiveMediaSource {
118
+ return ProgressiveMediaSource.Factory(
119
+ factory, DefaultExtractorsFactory()
120
+ .setConstantBitrateSeekingEnabled(true)
121
+ )
122
+ .createMediaSource(mediaItem)
123
+ }
124
+
125
+ private fun enableCaching(factory: DataSource.Factory): DataSource.Factory {
126
+ // Add detailed debugging to understand the NPE
127
+ Timber.tag("RNTP").d("enableCaching called - cache is: ${cache}")
128
+
129
+ if (cache == null) {
130
+ Timber.tag("RNTP").d("Cache is null in enableCaching, returning original factory")
131
+ return factory
132
+ }
133
+
134
+ // Validate cache is properly initialized
135
+ try {
136
+ val cacheKeys = cache.keys
137
+ Timber.tag("RNTP").d("Cache appears valid - keys count: ${cacheKeys.size}")
138
+ } catch (e: Exception) {
139
+ Timber.tag("RNTP").e(e, "Cache validation failed, returning original factory")
140
+ return factory
141
+ }
142
+
143
+ Timber.tag("RNTP").d("Cache is not null, attempting to create CacheDataSource.Factory")
144
+
145
+ return try {
146
+ val cacheFactory = CacheDataSource.Factory()
147
+ Timber.tag("RNTP").d("Created CacheDataSource.Factory, setting cache")
148
+
149
+ cacheFactory.setCache(cache)
150
+ Timber.tag("RNTP").d("Set cache successfully, setting upstream factory")
151
+
152
+ cacheFactory.setUpstreamDataSourceFactory(factory)
153
+ Timber.tag("RNTP").d("Set upstream factory, setting flags")
154
+
155
+ cacheFactory.setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR)
156
+ Timber.tag("RNTP").d("Cache setup completed successfully")
157
+
158
+ cacheFactory
159
+ } catch (e: Exception) {
160
+ // If cache setup fails, fall back to original factory
161
+ Timber.tag("RNTP").e(e, "Failed to setup cache at step, using original factory")
162
+ factory
163
+ }
164
+ }
165
+ }