diff --git a/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt b/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt index b2409a099..5f434a693 100644 --- a/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt +++ b/android/src/main/java/com/doublesymmetry/trackplayer/module/MusicModule.kt @@ -251,8 +251,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun updateOptions(data: ReadableMap?, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun updateOptions(data: ReadableMap?, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope val options = Arguments.toBundle(data) @@ -264,14 +264,14 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun add(data: ReadableArray?, insertBeforeIndex: Int, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun add(data: ReadableArray?, insertBeforeIndex: Int, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope try { val tracks = readableArrayToTrackList(data); if (insertBeforeIndex < -1 || insertBeforeIndex > musicService.tracks.size) { callback.reject("index_out_of_bounds", "The track index is out of bounds") - return@launch + return@launchInScope } val index = if (insertBeforeIndex == -1) musicService.tracks.size else insertBeforeIndex musicService.add( @@ -285,11 +285,11 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun load(data: ReadableMap?, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun load(data: ReadableMap?, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope if (data == null) { callback.resolve(null) - return@launch + return@launchInScope } val bundle = Arguments.toBundle(data); if (bundle is Bundle) { @@ -301,15 +301,15 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun move(fromIndex: Int, toIndex: Int, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun move(fromIndex: Int, toIndex: Int, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.move(fromIndex, toIndex) callback.resolve(null) } @ReactMethod - fun remove(data: ReadableArray?, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun remove(data: ReadableArray?, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope val inputIndexes = Arguments.toList(data) if (inputIndexes != null) { val size = musicService.tracks.size @@ -321,7 +321,7 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM "index_out_of_bounds", "One or more indexes was out of bounds" ) - return@launch + return@launchInScope } indexes.add(index) } @@ -332,8 +332,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM @ReactMethod fun updateMetadataForTrack(index: Int, map: ReadableMap?, callback: Promise) = - scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope if (index < 0 || index >= musicService.tracks.size) { callback.reject("index_out_of_bounds", "The index is out of bounds") @@ -348,8 +348,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun updateNowPlayingMetadata(map: ReadableMap?, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun updateNowPlayingMetadata(map: ReadableMap?, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope if (musicService.tracks.isEmpty()) callback.reject("no_current_item", "There is no current item in the player") @@ -364,8 +364,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun clearNowPlayingMetadata(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun clearNowPlayingMetadata(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope if (musicService.tracks.isEmpty()) callback.reject("no_current_item", "There is no current item in the player") @@ -375,16 +375,16 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun removeUpcomingTracks(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun removeUpcomingTracks(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.removeUpcomingTracks() callback.resolve(null) } @ReactMethod - fun skip(index: Int, initialTime: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun skip(index: Int, initialTime: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.skip(index) @@ -396,8 +396,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun skipToNext(initialTime: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun skipToNext(initialTime: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.skipToNext() @@ -409,8 +409,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun skipToPrevious(initialTime: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun skipToPrevious(initialTime: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.skipToPrevious() @@ -422,8 +422,8 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun reset(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun reset(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.stop() delay(300) // Allow playback to stop @@ -433,116 +433,116 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun play(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun play(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.play() callback.resolve(null) } @ReactMethod - fun pause(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun pause(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.pause() callback.resolve(null) } @ReactMethod - fun stop(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun stop(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.stop() callback.resolve(null) } @ReactMethod - fun seekTo(seconds: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun seekTo(seconds: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.seekTo(seconds) callback.resolve(null) } @ReactMethod - fun seekBy(offset: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun seekBy(offset: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.seekBy(offset) callback.resolve(null) } @ReactMethod - fun retry(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun retry(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.retry() callback.resolve(null) } @ReactMethod - fun setVolume(volume: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun setVolume(volume: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.setVolume(volume) callback.resolve(null) } @ReactMethod - fun getVolume(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getVolume(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.getVolume()) } @ReactMethod - fun setRate(rate: Float, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun setRate(rate: Float, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.setRate(rate) callback.resolve(null) } @ReactMethod - fun getRate(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getRate(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.getRate()) } @ReactMethod - fun setRepeatMode(mode: Int, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun setRepeatMode(mode: Int, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.setRepeatMode(RepeatMode.fromOrdinal(mode)) callback.resolve(null) } @ReactMethod - fun getRepeatMode(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getRepeatMode(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.getRepeatMode().ordinal) } @ReactMethod - fun setPlayWhenReady(playWhenReady: Boolean, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun setPlayWhenReady(playWhenReady: Boolean, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope musicService.playWhenReady = playWhenReady callback.resolve(null) } @ReactMethod - fun getPlayWhenReady(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getPlayWhenReady(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.playWhenReady) } @ReactMethod - fun getTrack(index: Int, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getTrack(index: Int, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope if (index >= 0 && index < musicService.tracks.size) { callback.resolve(Arguments.fromBundle(musicService.tracks[index].originalItem)) @@ -552,15 +552,15 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun getQueue(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getQueue(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(Arguments.fromList(musicService.tracks.map { it.originalItem })) } @ReactMethod - fun setQueue(data: ReadableArray?, callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun setQueue(data: ReadableArray?, callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope try { musicService.clear() @@ -572,16 +572,16 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun getActiveTrackIndex(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getActiveTrackIndex(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve( if (musicService.tracks.isEmpty()) null else musicService.getCurrentTrackIndex() ) } @ReactMethod - fun getActiveTrack(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getActiveTrack(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve( if (musicService.tracks.isEmpty()) null else Arguments.fromBundle( @@ -591,29 +591,29 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun getDuration(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getDuration(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.getDurationInSeconds()) } @ReactMethod - fun getBufferedPosition(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getBufferedPosition(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.getBufferedPositionInSeconds()) } @ReactMethod - fun getPosition(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getPosition(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(musicService.getPositionInSeconds()) } @ReactMethod - fun getProgress(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getProgress(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope var bundle = Bundle() bundle.putDouble("duration", musicService.getDurationInSeconds()); bundle.putDouble("position", musicService.getPositionInSeconds()); @@ -622,8 +622,16 @@ class MusicModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaM } @ReactMethod - fun getPlaybackState(callback: Promise) = scope.launch { - if (verifyServiceBoundOrReject(callback)) return@launch + fun getPlaybackState(callback: Promise) = launchInScope { + if (verifyServiceBoundOrReject(callback)) return@launchInScope callback.resolve(Arguments.fromBundle(musicService.getPlayerStateBundle(musicService.state))) } + + // Bridgeless interop layer tries to pass the `Job` from `scope.launch` to the JS side + // which causes an exception. We can work around this using a wrapper. + private fun launchInScope(block: suspend () -> Unit) { + scope.launch { + block() + } + } } diff --git a/ios/RNTrackPlayer/RNTrackPlayerBridge.m b/ios/RNTrackPlayer/RNTrackPlayerBridge.m index 774199419..776c09ec0 100644 --- a/ios/RNTrackPlayer/RNTrackPlayerBridge.m +++ b/ios/RNTrackPlayer/RNTrackPlayerBridge.m @@ -151,17 +151,4 @@ @interface RCT_EXTERN_REMAP_MODULE(TrackPlayerModule, RNTrackPlayer, NSObject) resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject); -RCT_EXTERN_METHOD(getSleepTimerProgress:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject); - -RCT_EXTERN_METHOD(setSleepTimer:(double)time - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject); - -RCT_EXTERN_METHOD(sleepWhenActiveTrackReachesEnd:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject); - -RCT_EXTERN_METHOD(clearSleepTimer:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject); - @end