diff --git a/android/src/main/java/com/audiowaveform/AudioWaveformModule.kt b/android/src/main/java/com/audiowaveform/AudioWaveformModule.kt index 698ca5c..47a0036 100644 --- a/android/src/main/java/com/audiowaveform/AudioWaveformModule.kt +++ b/android/src/main/java/com/audiowaveform/AudioWaveformModule.kt @@ -159,13 +159,10 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav @ReactMethod fun startPlayer(obj: ReadableMap, promise: Promise) { val finishMode = obj.getInt(Constants.finishMode) - val key = obj.getString(Constants.playerKey) val speed = obj.getDouble(Constants.speed) - if (key != null) { - audioPlayers[key]?.start(finishMode ?: 2, speed.toFloat(),promise) - } else { - promise.reject("startPlayer Error", "Player key can't be null") - } + + val player = getPlayerOrReject(obj, promise, "startPlayer Error"); + player?.start(finishMode ?: 2, speed.toFloat(),promise) } @ReactMethod @@ -182,12 +179,8 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav @ReactMethod fun pausePlayer(obj: ReadableMap, promise: Promise) { - val key = obj.getString(Constants.playerKey) - if (key != null) { - audioPlayers[key]?.pause(promise) - } else { - promise.reject("pausePlayer Error", "Player key can't be null") - } + val player = getPlayerOrReject(obj, promise, "pausePlayer Error"); + player?.pause(promise); } @ReactMethod @@ -195,12 +188,9 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val progress = obj.getInt(Constants.progress) - val key = obj.getString(Constants.playerKey) - if (key != null) { - audioPlayers[key]?.seekToPosition(progress.toLong(), promise) - } else { - promise.reject("seekTo Error", "Player key can't be null") - } + + val player = getPlayerOrReject(obj, promise, "seekTo Error"); + player?.seekToPosition(progress.toLong(), promise) } else { Log.e( Constants.LOG_TAG, @@ -216,24 +206,18 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav @ReactMethod fun setVolume(obj: ReadableMap, promise: Promise) { val volume = obj.getInt(Constants.volume) - val key = obj.getString(Constants.playerKey) - if (key != null) { - audioPlayers[key]?.setVolume(volume.toFloat(), promise) - } else { - promise.reject("setVolume error", "Player key can't be null") - } + + val player = getPlayerOrReject(obj, promise, "setVolume Error"); + player?.setVolume(volume.toFloat(), promise) } @ReactMethod fun getDuration(obj: ReadableMap, promise: Promise) { - val key = obj.getString(Constants.playerKey) val duration = obj.getInt(Constants.durationType) val type = if (duration == 0) DurationType.Current else DurationType.Max - if (key != null) { - audioPlayers[key]?.getDuration(type, promise) - } else { - promise.reject("getDuration Error", "Player key can't be null") - } + + val player = getPlayerOrReject(obj, promise, "getDuration Error"); + player?.getDuration(type, promise) } @ReactMethod @@ -429,4 +413,18 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav handler.removeCallbacks(emitLiveRecordValue) } + private fun getPlayerOrReject(arguments: ReadableMap, promise: Promise, errorCode: String): AudioPlayer? { + val key = getPlayerKeyOrReject(arguments, promise, errorCode) + return audioPlayers[key] ?: run { + promise.reject(errorCode, "$errorCode: Player not in the list") + null + } + } + + private fun getPlayerKeyOrReject(arguments: ReadableMap, promise: Promise, errorCode: String): String? { + return arguments.getString(Constants.playerKey) ?: run { + promise.reject(errorCode, "$errorCode: Player key can't be null") + null + } + } } \ No newline at end of file diff --git a/src/components/Waveform/Waveform.tsx b/src/components/Waveform/Waveform.tsx index d62154f..0961a15 100644 --- a/src/components/Waveform/Waveform.tsx +++ b/src/components/Waveform/Waveform.tsx @@ -209,14 +209,17 @@ export const Waveform = forwardRef((props, ref) => { } }; - const stopPlayerAction = async () => { + const stopPlayerAction = async (resetProgress = true) => { if (mode === 'static') { try { const result = await stopPlayer({ playerKey: `PlayerFor${path}`, }); if (!isNil(result) && result) { - setCurrentProgress(0); + if (resetProgress) { + setCurrentProgress(0); + } + setPlayerState(PlayerState.stopped); return Promise.resolve(result); } else { @@ -258,6 +261,11 @@ export const Waveform = forwardRef((props, ref) => { ); } } catch (error) { + if (playerState === PlayerState.paused) { + // If the player is not prepared, triggering the stop will reset the player for next click. Fix blocked paused player after a call to `stopAllPlayers` + await stopPlayerAction(); + } + return Promise.reject(error); } } else { @@ -267,14 +275,17 @@ export const Waveform = forwardRef((props, ref) => { } }; - const pausePlayerAction = async () => { + const pausePlayerAction = async (changePlayerState = true) => { if (mode === 'static') { try { const pause = await pausePlayer({ playerKey: `PlayerFor${path}`, }); if (pause) { - setPlayerState(PlayerState.paused); + if (changePlayerState) { + setPlayerState(PlayerState.paused); + } + return Promise.resolve(true); } else { return Promise.reject( @@ -423,7 +434,7 @@ export const Waveform = forwardRef((props, ref) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [viewLayout?.width, mode, candleWidth, candleSpace]); - useEffect(() => { + const seekToPlayerAction = async () => { if (!isNil(seekPosition)) { if (mode === 'static') { const seekAmount = @@ -432,10 +443,18 @@ export const Waveform = forwardRef((props, ref) => { const clampedSeekAmount = clamp(seekAmount, 0, 1); if (!panMoving) { - seekToPlayer({ - playerKey: `PlayerFor${path}`, - progress: clampedSeekAmount * songDuration, - }); + try { + await seekToPlayer({ + playerKey: `PlayerFor${path}`, + progress: clampedSeekAmount * songDuration, + }); + } catch (e) { + if (playerState === PlayerState.paused) { + // If the player is not prepared, triggering the stop will reset the player for next click. Fix blocked paused player after a call to `stopAllPlayers` + await stopPlayerAction(false); + } + } + if (playerState === PlayerState.playing) { startPlayerAction(); } @@ -444,6 +463,10 @@ export const Waveform = forwardRef((props, ref) => { setCurrentProgress(clampedSeekAmount * songDuration); } } + }; + + useEffect(() => { + seekToPlayerAction(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [seekPosition, panMoving, mode, songDuration]); @@ -518,7 +541,7 @@ export const Waveform = forwardRef((props, ref) => { useEffect(() => { if (panMoving) { if (playerState === PlayerState.playing) { - pausePlayerAction(); + pausePlayerAction(false); isAutoPaused.current = true; } } else {