react-native-nitro-player 0.5.6 → 0.5.7

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 (31) hide show
  1. package/README.md +2 -0
  2. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridTrackPlayer.kt +43 -0
  3. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerCore.kt +340 -0
  4. package/android/src/main/java/com/margelo/nitro/nitroplayer/playlist/PlaylistManager.kt +60 -0
  5. package/ios/HybridTrackPlayer.swift +54 -1
  6. package/ios/core/TrackPlayerCore.swift +254 -2
  7. package/ios/playlist/PlaylistManager.swift +68 -0
  8. package/lib/specs/TrackPlayer.nitro.d.ts +47 -0
  9. package/lib/types/PlayerQueue.d.ts +5 -0
  10. package/nitrogen/generated/android/NitroPlayerOnLoad.cpp +2 -0
  11. package/nitrogen/generated/android/c++/JFunc_void_std__vector_TrackItem__double.hpp +104 -0
  12. package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.cpp +160 -0
  13. package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.hpp +8 -0
  14. package/nitrogen/generated/android/c++/JPlayerConfig.hpp +7 -3
  15. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__vector_TrackItem__double.kt +80 -0
  16. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridTrackPlayerSpec.kt +37 -0
  17. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/PlayerConfig.kt +6 -3
  18. package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.cpp +16 -0
  19. package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.hpp +65 -0
  20. package/nitrogen/generated/ios/c++/HybridTrackPlayerSpecSwift.hpp +62 -0
  21. package/nitrogen/generated/ios/swift/Func_void_double.swift +47 -0
  22. package/nitrogen/generated/ios/swift/Func_void_std__vector_TrackItem__double.swift +47 -0
  23. package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec.swift +8 -0
  24. package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec_cxx.swift +173 -0
  25. package/nitrogen/generated/ios/swift/PlayerConfig.swift +24 -1
  26. package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.cpp +8 -0
  27. package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.hpp +8 -0
  28. package/nitrogen/generated/shared/c++/PlayerConfig.hpp +6 -2
  29. package/package.json +1 -1
  30. package/src/specs/TrackPlayer.nitro.ts +57 -0
  31. package/src/types/PlayerQueue.ts +5 -0
@@ -50,6 +50,7 @@ class TrackPlayerCore: NSObject {
50
50
  private var currentTracks: [TrackItem] = []
51
51
  private var isManuallySeeked = false
52
52
  private var currentRepeatMode: RepeatMode = .off
53
+ private var lookaheadCount: Int = 5 // Number of tracks to preload ahead
53
54
  private var boundaryTimeObserver: Any?
54
55
  private var currentItemObservers: [NSKeyValueObservation] = []
55
56
 
@@ -310,6 +311,9 @@ class TrackPlayerCore: NSObject {
310
311
  if let player = player {
311
312
  NitroPlayerLogger.log("TrackPlayerCore", "📋 Remaining items in queue: \(player.items().count)")
312
313
  }
314
+
315
+ // Check if upcoming tracks need URLs
316
+ checkUpcomingTracksForUrls(lookahead: lookaheadCount)
313
317
  }
314
318
 
315
319
  @objc private func playerItemFailedToPlayToEndTime(notification: Notification) {
@@ -571,6 +575,14 @@ class TrackPlayerCore: NSObject {
571
575
  }
572
576
  }
573
577
  }
578
+
579
+ func setPlaybackSpeed(_ speed: Double) {
580
+ player?.rate = Float(speed)
581
+ }
582
+
583
+ func getPlaybackSpeed() -> Double {
584
+ return Double(player?.rate ?? 1.0)
585
+ }
574
586
 
575
587
  private func loadPlaylistInternal(playlistId: String) {
576
588
  NitroPlayerLogger.log("TrackPlayerCore", "\n" + String(repeating: "🎼", count: Constants.playlistSeparatorLength))
@@ -596,6 +608,9 @@ class TrackPlayerCore: NSObject {
596
608
  self.updatePlayerQueue(tracks: playlist.tracks)
597
609
  // Emit initial state (paused/stopped before play)
598
610
  self.emitStateChange()
611
+
612
+ // Check if upcoming tracks need URLs
613
+ self.checkUpcomingTracksForUrls(lookahead: lookaheadCount)
599
614
  } else {
600
615
  NitroPlayerLogger.log("TrackPlayerCore", " ❌ Playlist NOT FOUND")
601
616
  NitroPlayerLogger.log("TrackPlayerCore", String(repeating: "🎼", count: Constants.playlistSeparatorLength) + "\n")
@@ -1301,6 +1316,9 @@ class TrackPlayerCore: NSObject {
1301
1316
  queuePlayer.pause()
1302
1317
  self.notifyPlaybackStateChange(.stopped, .end)
1303
1318
  }
1319
+
1320
+ // Check if upcoming tracks need URLs
1321
+ checkUpcomingTracksForUrls(lookahead: lookaheadCount)
1304
1322
  }
1305
1323
 
1306
1324
  func skipToPrevious() {
@@ -1343,6 +1361,9 @@ class TrackPlayerCore: NSObject {
1343
1361
  // Already at first track, restart it
1344
1362
  queuePlayer.seek(to: .zero)
1345
1363
  }
1364
+
1365
+ // Check if upcoming tracks need URLs
1366
+ checkUpcomingTracksForUrls(lookahead: lookaheadCount)
1346
1367
  }
1347
1368
 
1348
1369
  func seek(position: Double) {
@@ -1469,9 +1490,14 @@ class TrackPlayerCore: NSObject {
1469
1490
  func configure(
1470
1491
  androidAutoEnabled: Bool?,
1471
1492
  carPlayEnabled: Bool?,
1472
- showInNotification: Bool?
1493
+ showInNotification: Bool?,
1494
+ lookaheadCount: Int? = nil
1473
1495
  ) {
1474
1496
  DispatchQueue.main.async { [weak self] in
1497
+ if let lookahead = lookaheadCount {
1498
+ self?.lookaheadCount = lookahead
1499
+ NitroPlayerLogger.log("TrackPlayerCore", "🔄 Lookahead count set to: \(lookahead)")
1500
+ }
1475
1501
  self?.mediaSessionManager?.configure(
1476
1502
  androidAutoEnabled: androidAutoEnabled,
1477
1503
  carPlayEnabled: carPlayEnabled,
@@ -1619,9 +1645,17 @@ class TrackPlayerCore: NSObject {
1619
1645
  upNextQueue.removeAll()
1620
1646
  currentTemporaryType = .none
1621
1647
 
1622
- return playFromIndexInternalWithResult(index: originalIndex)
1648
+ let result = playFromIndexInternalWithResult(index: originalIndex)
1649
+
1650
+ // Check if upcoming tracks need URLs
1651
+ checkUpcomingTracksForUrls(lookahead: lookaheadCount)
1652
+
1653
+ return result
1623
1654
  }
1624
1655
 
1656
+ // Check if upcoming tracks need URLs after any successful skip
1657
+ checkUpcomingTracksForUrls(lookahead: lookaheadCount)
1658
+
1625
1659
  return false
1626
1660
  }
1627
1661
 
@@ -1857,6 +1891,224 @@ class TrackPlayerCore: NSObject {
1857
1891
  return .none
1858
1892
  }
1859
1893
 
1894
+ // MARK: - Lazy URL Loading Support
1895
+
1896
+ /**
1897
+ * Update entire track objects and rebuild queue if needed
1898
+ * Skips currently playing track to preserve gapless playback
1899
+ * CRITICAL: Invalidates preloaded assets and re-preloads for gapless
1900
+ */
1901
+ func updateTracks(tracks: [TrackItem]) {
1902
+ DispatchQueue.main.async { [weak self] in
1903
+ guard let self = self else { return }
1904
+
1905
+ NitroPlayerLogger.log("TrackPlayerCore", "🔄 updateTracks: \(tracks.count) updates")
1906
+
1907
+ // Get current track ID to avoid updating it (preserves gapless playback)
1908
+ let currentTrackId = self.getCurrentTrack()?.id
1909
+
1910
+ // Filter out current track and validate
1911
+ let safeTracks = tracks.filter { track in
1912
+ switch true {
1913
+ case track.id == currentTrackId:
1914
+ NitroPlayerLogger.log(
1915
+ "TrackPlayerCore",
1916
+ "⚠️ Skipping update for currently playing track: \(track.id) (preserves gapless)")
1917
+ return false
1918
+ case track.url.isEmpty:
1919
+ NitroPlayerLogger.log(
1920
+ "TrackPlayerCore", "⚠️ Skipping track with empty URL: \(track.id)")
1921
+ return false
1922
+ default:
1923
+ return true
1924
+ }
1925
+ }
1926
+
1927
+ guard !safeTracks.isEmpty else {
1928
+ NitroPlayerLogger.log("TrackPlayerCore", "✅ No valid updates to apply")
1929
+ return
1930
+ }
1931
+
1932
+ // Invalidate preloaded assets for tracks with updated data
1933
+ // This is CRITICAL for gapless playback - old assets might use old URLs
1934
+ let updatedTrackIds = Set(safeTracks.map { $0.id })
1935
+ for trackId in updatedTrackIds {
1936
+ if self.preloadedAssets[trackId] != nil {
1937
+ NitroPlayerLogger.log(
1938
+ "TrackPlayerCore", "🗑️ Invalidating preloaded asset for track: \(trackId)")
1939
+ self.preloadedAssets.removeValue(forKey: trackId)
1940
+ }
1941
+ }
1942
+
1943
+ // Update in PlaylistManager
1944
+ let affectedPlaylists = self.playlistManager.updateTracks(tracks: safeTracks)
1945
+
1946
+ // Rebuild queue if current playlist was affected
1947
+ if let currentId = self.currentPlaylistId,
1948
+ let updateCount = affectedPlaylists[currentId]
1949
+ {
1950
+ NitroPlayerLogger.log(
1951
+ "TrackPlayerCore",
1952
+ "🔄 Rebuilding queue - \(updateCount) tracks updated in current playlist")
1953
+
1954
+ // This method preserves current item
1955
+ self.rebuildAVQueueFromCurrentPosition()
1956
+
1957
+ // Re-preload upcoming tracks for gapless playback
1958
+ // CRITICAL: This restores gapless buffering after queue rebuild
1959
+ self.preloadUpcomingTracks(from: self.currentTrackIndex + 1)
1960
+
1961
+ NitroPlayerLogger.log("TrackPlayerCore", "✅ Queue rebuilt, gapless playback preserved")
1962
+ }
1963
+
1964
+ NitroPlayerLogger.log(
1965
+ "TrackPlayerCore",
1966
+ "✅ Track updates complete - \(affectedPlaylists.count) playlists affected")
1967
+ }
1968
+ }
1969
+
1970
+ /**
1971
+ * Get tracks by IDs from all playlists
1972
+ */
1973
+ func getTracksById(trackIds: [String]) -> [TrackItem] {
1974
+ if Thread.isMainThread {
1975
+ return playlistManager.getTracksById(trackIds: trackIds)
1976
+ } else {
1977
+ var tracks: [TrackItem] = []
1978
+ DispatchQueue.main.sync { [weak self] in
1979
+ tracks = self?.playlistManager.getTracksById(trackIds: trackIds) ?? []
1980
+ }
1981
+ return tracks
1982
+ }
1983
+ }
1984
+
1985
+ /**
1986
+ * Get tracks needing URLs from current playlist
1987
+ */
1988
+ func getTracksNeedingUrls() -> [TrackItem] {
1989
+ if Thread.isMainThread {
1990
+ return getTracksNeedingUrlsInternal()
1991
+ } else {
1992
+ var tracks: [TrackItem] = []
1993
+ DispatchQueue.main.sync { [weak self] in
1994
+ tracks = self?.getTracksNeedingUrlsInternal() ?? []
1995
+ }
1996
+ return tracks
1997
+ }
1998
+ }
1999
+
2000
+ private func getTracksNeedingUrlsInternal() -> [TrackItem] {
2001
+ guard let currentId = currentPlaylistId,
2002
+ let playlist = playlistManager.getPlaylist(playlistId: currentId)
2003
+ else {
2004
+ return []
2005
+ }
2006
+
2007
+ return playlist.tracks.filter { $0.url.isEmpty }
2008
+ }
2009
+
2010
+ /**
2011
+ * Get next N tracks from current position
2012
+ */
2013
+ func getNextTracks(count: Int) -> [TrackItem] {
2014
+ if Thread.isMainThread {
2015
+ return getNextTracksInternal(count: count)
2016
+ } else {
2017
+ var tracks: [TrackItem] = []
2018
+ DispatchQueue.main.sync { [weak self] in
2019
+ tracks = self?.getNextTracksInternal(count: count) ?? []
2020
+ }
2021
+ return tracks
2022
+ }
2023
+ }
2024
+
2025
+ private func getNextTracksInternal(count: Int) -> [TrackItem] {
2026
+ let actualQueue = getActualQueueInternal()
2027
+ guard !actualQueue.isEmpty else { return [] }
2028
+
2029
+ guard let currentTrack = getCurrentTrack(),
2030
+ let currentIndex = actualQueue.firstIndex(where: { $0.id == currentTrack.id })
2031
+ else {
2032
+ return []
2033
+ }
2034
+
2035
+ let startIndex = currentIndex + 1
2036
+ let endIndex = min(startIndex + count, actualQueue.count)
2037
+
2038
+ return startIndex < actualQueue.count ? Array(actualQueue[startIndex..<endIndex]) : []
2039
+ }
2040
+
2041
+ /**
2042
+ * Get current track index in playlist
2043
+ */
2044
+ func getCurrentTrackIndex() -> Int {
2045
+ if Thread.isMainThread {
2046
+ return currentTrackIndex
2047
+ } else {
2048
+ var index = -1
2049
+ DispatchQueue.main.sync { [weak self] in
2050
+ index = self?.currentTrackIndex ?? -1
2051
+ }
2052
+ return index
2053
+ }
2054
+ }
2055
+
2056
+ /**
2057
+ * Callback for tracks needing update
2058
+ */
2059
+ typealias OnTracksNeedUpdateCallback = ([TrackItem], Int) -> Void
2060
+
2061
+ // Add to class properties
2062
+ private var onTracksNeedUpdateListeners: [(callback: OnTracksNeedUpdateCallback, isAlive: Bool)] =
2063
+ []
2064
+ private let tracksNeedUpdateQueue = DispatchQueue(
2065
+ label: "com.nitroplayer.tracksneedupdate", attributes: .concurrent)
2066
+
2067
+ /**
2068
+ * Register listener for when tracks need update
2069
+ */
2070
+ func addOnTracksNeedUpdateListener(callback: @escaping OnTracksNeedUpdateCallback) {
2071
+ tracksNeedUpdateQueue.async(flags: .barrier) { [weak self] in
2072
+ self?.onTracksNeedUpdateListeners.append((callback: callback, isAlive: true))
2073
+ }
2074
+ }
2075
+
2076
+ /**
2077
+ * Notify listeners that tracks need updating
2078
+ */
2079
+ private func notifyTracksNeedUpdate(tracks: [TrackItem], lookahead: Int) {
2080
+ tracksNeedUpdateQueue.async(flags: .barrier) { [weak self] in
2081
+ guard let self = self else { return }
2082
+
2083
+ // Clean up dead listeners
2084
+ self.onTracksNeedUpdateListeners.removeAll { !$0.isAlive }
2085
+ let liveCallbacks = self.onTracksNeedUpdateListeners.map { $0.callback }
2086
+
2087
+ if !liveCallbacks.isEmpty {
2088
+ DispatchQueue.main.async {
2089
+ for callback in liveCallbacks {
2090
+ callback(tracks, lookahead)
2091
+ }
2092
+ }
2093
+ }
2094
+ }
2095
+ }
2096
+
2097
+ /**
2098
+ * Check if upcoming tracks need URLs and notify listeners
2099
+ * Call this in playerItemDidPlayToEndTime or after skip operations
2100
+ */
2101
+ private func checkUpcomingTracksForUrls(lookahead: Int = 5) {
2102
+ let nextTracks = getNextTracksInternal(count: lookahead)
2103
+ let tracksNeedingUrls = nextTracks.filter { $0.url.isEmpty }
2104
+
2105
+ if !tracksNeedingUrls.isEmpty {
2106
+ NitroPlayerLogger.log(
2107
+ "TrackPlayerCore", "⚠️ \(tracksNeedingUrls.count) upcoming tracks need URLs")
2108
+ notifyTracksNeedUpdate(tracks: tracksNeedingUrls, lookahead: lookahead)
2109
+ }
2110
+ }
2111
+
1860
2112
  // MARK: - Cleanup
1861
2113
 
1862
2114
  deinit {
@@ -274,6 +274,74 @@ class PlaylistManager {
274
274
  return true
275
275
  }
276
276
 
277
+ /**
278
+ * Update entire track objects across all playlists
279
+ * Matches by track.id and replaces the entire track object
280
+ * @param tracks Array of full TrackItem objects to update
281
+ * @return Dictionary of playlistId -> count of tracks updated
282
+ */
283
+ func updateTracks(tracks: [TrackItem]) -> [String: Int] {
284
+ let tracksMap = Dictionary(uniqueKeysWithValues: tracks.map { ($0.id, $0) })
285
+ var affectedPlaylists: [String: Int] = [:]
286
+
287
+ queue.sync {
288
+ for (playlistId, playlist) in playlists {
289
+ var updateCount = 0
290
+ let newTracks = playlist.tracks.map { track -> TrackItem in
291
+ if let updatedTrack = tracksMap[track.id] {
292
+ updateCount += 1
293
+ return updatedTrack
294
+ }
295
+ return track
296
+ }
297
+
298
+ if updateCount > 0 {
299
+ affectedPlaylists[playlistId] = updateCount
300
+ playlists[playlistId] = PlaylistModel(
301
+ id: playlist.id,
302
+ name: playlist.name,
303
+ description: playlist.description,
304
+ artwork: playlist.artwork,
305
+ tracks: newTracks
306
+ )
307
+ }
308
+ }
309
+ }
310
+
311
+ if !affectedPlaylists.isEmpty {
312
+ scheduleSave()
313
+ affectedPlaylists.keys.forEach { playlistId in
314
+ notifyPlaylistChanged(playlistId, .update)
315
+ }
316
+ notifyPlaylistsChanged(.update)
317
+ }
318
+
319
+ return affectedPlaylists
320
+ }
321
+
322
+ /**
323
+ * Get tracks by IDs from all playlists
324
+ * @param trackIds Array of track IDs to fetch
325
+ * @return Array of matching TrackItem objects
326
+ */
327
+ func getTracksById(trackIds: [String]) -> [TrackItem] {
328
+ let trackIdSet = Set(trackIds)
329
+ var foundTracks: [String: TrackItem] = [:]
330
+
331
+ queue.sync {
332
+ for playlist in playlists.values {
333
+ for track in playlist.tracks {
334
+ if trackIdSet.contains(track.id) && foundTracks[track.id] == nil {
335
+ foundTracks[track.id] = track
336
+ }
337
+ }
338
+ }
339
+ }
340
+
341
+ // Return in same order as requested
342
+ return trackIds.compactMap { foundTracks[$0] }
343
+ }
344
+
277
345
  /**
278
346
  * Get the current playlist ID
279
347
  */
@@ -44,4 +44,51 @@ export interface TrackPlayer extends HybridObject<{
44
44
  onAndroidAutoConnectionChange(callback: (connected: boolean) => void): void;
45
45
  isAndroidAutoConnected(): boolean;
46
46
  setVolume(volume: number): boolean;
47
+ /**
48
+ * Update entire track objects across all playlists
49
+ * Matches by track.id and updates all properties (url, artwork, title, etc.)
50
+ * Note: Empty string "" is valid for TrackItem.url to support lazy loading
51
+ * @param tracks Array of full TrackItem objects to update
52
+ * @returns Promise that resolves when updates complete
53
+ */
54
+ updateTracks(tracks: TrackItem[]): Promise<void>;
55
+ /**
56
+ * Get tracks by IDs from all playlists
57
+ * @param trackIds Array of track IDs to fetch
58
+ * @returns Promise resolving to array of matching tracks
59
+ */
60
+ getTracksById(trackIds: string[]): Promise<TrackItem[]>;
61
+ /**
62
+ * Get tracks with missing/empty URLs from current playlist
63
+ * @returns Promise resolving to array of tracks needing URLs
64
+ */
65
+ getTracksNeedingUrls(): Promise<TrackItem[]>;
66
+ /**
67
+ * Get next N tracks from current position in playlist
68
+ * Useful for preloading URLs before they're needed
69
+ * @param count Number of upcoming tracks to return
70
+ * @returns Promise resolving to array of next tracks
71
+ */
72
+ getNextTracks(count: number): Promise<TrackItem[]>;
73
+ /**
74
+ * Get current track index in the active playlist
75
+ * @returns Promise resolving to 0-based index, or -1 if no track playing
76
+ */
77
+ getCurrentTrackIndex(): Promise<number>;
78
+ /**
79
+ * Register callback that fires when tracks will be needed soon
80
+ * Useful for proactive URL resolution in Android Auto/CarPlay
81
+ * @param callback Function called with tracks needing URLs and lookahead count
82
+ */
83
+ onTracksNeedUpdate(callback: (tracks: TrackItem[], lookahead: number) => void): void;
84
+ /**
85
+ * Get the current track index in the active playlist
86
+ * @returns Promise resolving to 0-based index, or -1 if no track playing
87
+ */
88
+ setPlaybackSpeed(speed: number): Promise<void>;
89
+ /**
90
+ * Get the current playback speed
91
+ * @returns Promise resolving to playback speed
92
+ */
93
+ getPlaybackSpeed(): Promise<number>;
47
94
  }
@@ -33,4 +33,9 @@ export interface PlayerConfig {
33
33
  androidAutoEnabled?: boolean;
34
34
  carPlayEnabled?: boolean;
35
35
  showInNotification?: boolean;
36
+ /**
37
+ * Number of upcoming tracks to preload URLs for (default: 5)
38
+ * Higher values = more proactive loading, but more network requests
39
+ */
40
+ lookaheadCount?: number;
36
41
  }
@@ -33,6 +33,7 @@
33
33
  #include "JFunc_void_TrackPlayerState_std__optional_Reason_.hpp"
34
34
  #include "JFunc_void_double_double.hpp"
35
35
  #include "JFunc_void_double_double_std__optional_bool_.hpp"
36
+ #include "JFunc_void_std__vector_TrackItem__double.hpp"
36
37
  #include <NitroModules/DefaultConstructableObject.hpp>
37
38
 
38
39
  namespace margelo::nitro::nitroplayer {
@@ -62,6 +63,7 @@ int initialize(JavaVM* vm) {
62
63
  margelo::nitro::nitroplayer::JFunc_void_TrackPlayerState_std__optional_Reason__cxx::registerNatives();
63
64
  margelo::nitro::nitroplayer::JFunc_void_double_double_cxx::registerNatives();
64
65
  margelo::nitro::nitroplayer::JFunc_void_double_double_std__optional_bool__cxx::registerNatives();
66
+ margelo::nitro::nitroplayer::JFunc_void_std__vector_TrackItem__double_cxx::registerNatives();
65
67
 
66
68
  // Register Nitro Hybrid Objects
67
69
  HybridObjectRegistry::registerHybridObjectConstructor(
@@ -0,0 +1,104 @@
1
+ ///
2
+ /// JFunc_void_std__vector_TrackItem__double.hpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © 2026 Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #pragma once
9
+
10
+ #include <fbjni/fbjni.h>
11
+ #include <functional>
12
+
13
+ #include "TrackItem.hpp"
14
+ #include <vector>
15
+ #include <functional>
16
+ #include <NitroModules/JNICallable.hpp>
17
+ #include "JTrackItem.hpp"
18
+ #include <string>
19
+ #include <NitroModules/Null.hpp>
20
+ #include <variant>
21
+ #include <optional>
22
+ #include "JVariant_NullType_String.hpp"
23
+ #include <NitroModules/JNull.hpp>
24
+ #include <NitroModules/AnyMap.hpp>
25
+ #include <NitroModules/JAnyMap.hpp>
26
+
27
+ namespace margelo::nitro::nitroplayer {
28
+
29
+ using namespace facebook;
30
+
31
+ /**
32
+ * Represents the Java/Kotlin callback `(tracks: Array<TrackItem>, lookahead: Double) -> Unit`.
33
+ * This can be passed around between C++ and Java/Kotlin.
34
+ */
35
+ struct JFunc_void_std__vector_TrackItem__double: public jni::JavaClass<JFunc_void_std__vector_TrackItem__double> {
36
+ public:
37
+ static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/nitroplayer/Func_void_std__vector_TrackItem__double;";
38
+
39
+ public:
40
+ /**
41
+ * Invokes the function this `JFunc_void_std__vector_TrackItem__double` instance holds through JNI.
42
+ */
43
+ void invoke(const std::vector<TrackItem>& tracks, double lookahead) const {
44
+ static const auto method = javaClassStatic()->getMethod<void(jni::alias_ref<jni::JArrayClass<JTrackItem>> /* tracks */, double /* lookahead */)>("invoke");
45
+ method(self(), [&]() {
46
+ size_t __size = tracks.size();
47
+ jni::local_ref<jni::JArrayClass<JTrackItem>> __array = jni::JArrayClass<JTrackItem>::newArray(__size);
48
+ for (size_t __i = 0; __i < __size; __i++) {
49
+ const auto& __element = tracks[__i];
50
+ auto __elementJni = JTrackItem::fromCpp(__element);
51
+ __array->setElement(__i, *__elementJni);
52
+ }
53
+ return __array;
54
+ }(), lookahead);
55
+ }
56
+ };
57
+
58
+ /**
59
+ * An implementation of Func_void_std__vector_TrackItem__double that is backed by a C++ implementation (using `std::function<...>`)
60
+ */
61
+ class JFunc_void_std__vector_TrackItem__double_cxx final: public jni::HybridClass<JFunc_void_std__vector_TrackItem__double_cxx, JFunc_void_std__vector_TrackItem__double> {
62
+ public:
63
+ static jni::local_ref<JFunc_void_std__vector_TrackItem__double::javaobject> fromCpp(const std::function<void(const std::vector<TrackItem>& /* tracks */, double /* lookahead */)>& func) {
64
+ return JFunc_void_std__vector_TrackItem__double_cxx::newObjectCxxArgs(func);
65
+ }
66
+
67
+ public:
68
+ /**
69
+ * Invokes the C++ `std::function<...>` this `JFunc_void_std__vector_TrackItem__double_cxx` instance holds.
70
+ */
71
+ void invoke_cxx(jni::alias_ref<jni::JArrayClass<JTrackItem>> tracks, double lookahead) {
72
+ _func([&]() {
73
+ size_t __size = tracks->size();
74
+ std::vector<TrackItem> __vector;
75
+ __vector.reserve(__size);
76
+ for (size_t __i = 0; __i < __size; __i++) {
77
+ auto __element = tracks->getElement(__i);
78
+ __vector.push_back(__element->toCpp());
79
+ }
80
+ return __vector;
81
+ }(), lookahead);
82
+ }
83
+
84
+ public:
85
+ [[nodiscard]]
86
+ inline const std::function<void(const std::vector<TrackItem>& /* tracks */, double /* lookahead */)>& getFunction() const {
87
+ return _func;
88
+ }
89
+
90
+ public:
91
+ static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/nitroplayer/Func_void_std__vector_TrackItem__double_cxx;";
92
+ static void registerNatives() {
93
+ registerHybrid({makeNativeMethod("invoke_cxx", JFunc_void_std__vector_TrackItem__double_cxx::invoke_cxx)});
94
+ }
95
+
96
+ private:
97
+ explicit JFunc_void_std__vector_TrackItem__double_cxx(const std::function<void(const std::vector<TrackItem>& /* tracks */, double /* lookahead */)>& func): _func(func) { }
98
+
99
+ private:
100
+ friend HybridBase;
101
+ std::function<void(const std::vector<TrackItem>& /* tracks */, double /* lookahead */)> _func;
102
+ };
103
+
104
+ } // namespace margelo::nitro::nitroplayer