Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,6 @@ buck-out/

# generated
lib

# Local history vs code plugin
.history/
109 changes: 46 additions & 63 deletions android/src/main/java/com/audiowaveform/AudioPlayer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,24 @@ package com.audiowaveform

import android.net.Uri
import android.os.CountDownTimer
import androidx.media3.common.MediaItem
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.WritableMap
import com.facebook.react.common.JavascriptException
import com.facebook.react.modules.core.DeviceEventManagerModule
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.common.MediaItem
import androidx.media3.common.Player

class AudioPlayer(
context: ReactApplicationContext,
playerKey: String,
) {
private val appContext = context
private lateinit var player: ExoPlayer
private var playerListener: Player.Listener? = null
private lateinit var playerListener: Player.Listener
private var isPlayerPrepared: Boolean = false
private var finishMode = FinishMode.Stop
private val key = playerKey
Expand Down Expand Up @@ -49,8 +50,7 @@ class AudioPlayer(
player.prepare()
playerListener = object : Player.Listener {

@Deprecated("Deprecated in Java")
override fun onPlayerStateChanged(isReady: Boolean, state: Int) {
override fun onPlaybackStateChanged(state: Int) {
if (!isPlayerPrepared) {
if (state == Player.STATE_READY) {
player.volume = (volume ?: 1).toFloat()
Expand All @@ -59,6 +59,10 @@ class AudioPlayer(
val duration = player.duration
promise.resolve(duration.toString())
}
else if (state == Player.STATE_IDLE) {
// Fix leaking promise when path is incorrect
promise.reject("preparePlayer-onPlayerStateChanged-error-idle", "Player stayed in idle state, unable to load $path")
}
}
if (state == Player.STATE_ENDED) {
val args: WritableMap = Arguments.createMap()
Expand Down Expand Up @@ -87,30 +91,27 @@ class AudioPlayer(
}
}
}
override fun onPlayerError(error: PlaybackException) {
promise.reject("preparePlayer onPlayerError", error.message)
}
}
player.addListener(playerListener!!)

player.addListener(playerListener)
} else {
promise.reject("preparePlayer Error", "path to audio file or unique key can't be null")
}
}

fun seekToPosition(progress: Long?, promise: Promise) {
fun seekToPosition(progress: Long?): Boolean {
if (progress != null) {
player.seekTo(progress)
promise.resolve(true)
} else {
promise.resolve(false)
return true;
}
return false;
}

fun getDuration(durationType: DurationType, promise: Promise) {
if (durationType == DurationType.Current) {
val duration = player.currentPosition
promise.resolve(duration.toString())
} else {
val duration = player.duration
promise.resolve(duration.toString())
}
fun getDuration(durationType: DurationType): Long {
return if (durationType == DurationType.Current) player.currentPosition else player.duration
}

private fun validateAndSetPlaybackSpeed(player: Player, speed: Float?): Boolean {
Expand All @@ -124,66 +125,48 @@ class AudioPlayer(
return true // Indicate success
}

fun start(finishMode: Int?, speed: Float?, promise: Promise) {
try {
if (finishMode != null && finishMode == 0) {
this.finishMode = FinishMode.Loop
} else if (finishMode != null && finishMode == 1) {
this.finishMode = FinishMode.Pause
} else {
this.finishMode = FinishMode.Stop
}
fun start(finishMode: Int, speed: Float): Boolean {
this.finishMode = when (finishMode) {
0 -> FinishMode.Loop
1 -> FinishMode.Pause
else -> FinishMode.Stop
}

validateAndSetPlaybackSpeed(player, speed)
validateAndSetPlaybackSpeed(player, speed)

player.playWhenReady = true
player.play()
promise.resolve(true)
startListening(promise)
} catch (e: Exception) {
promise.reject("Can not start the player", e.toString())
}
player.playWhenReady = true
player.play()
startListening()
return true
}

fun stop() {
stopListening()
if (playerListener != null) {
player.removeListener(playerListener!!)
}
player.removeListener(playerListener)
isPlayerPrepared = false
player.stop()
if(player.isPlaying) player.stop()
player.release()
}

fun pause(promise: Promise) {
try {
stopListening()
player.pause()
promise.resolve(true)
} catch (e: Exception) {
promise.reject("Failed to pause the player", e.toString())
}

fun pause(): Boolean {
stopListening()
player.pause()
return true
}

fun setVolume(volume: Float?, promise: Promise) {
fun setVolume(volume: Float): Boolean {
try {
if (volume != null) {
player.volume = volume
promise.resolve(true)
} else {
promise.resolve(false)
}
} catch (e: Exception) {
promise.resolve(false)
player.volume = volume
return true;
} catch (_: Exception) {
// Noop
}
return false
}

fun setPlaybackSpeed(speed: Float?): Boolean {
return validateAndSetPlaybackSpeed(player, speed)
}
fun setPlaybackSpeed(speed: Float?) = validateAndSetPlaybackSpeed(player, speed)

private fun startListening(promise: Promise) {
private fun startListening() {
try {
audioPlaybackListener = object : CountDownTimer(player.duration, UpdateFrequency.Low.value) {
override fun onTick(millisUntilFinished: Long) {
Expand All @@ -198,7 +181,7 @@ class AudioPlayer(
override fun onFinish() {}
}.start()
} catch(err: JavascriptException) {
promise.reject("startListening Error", err)
throw Exception("startListening Error", err)
}
}

Expand Down
36 changes: 8 additions & 28 deletions android/src/main/java/com/audiowaveform/AudioRecorder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,15 @@ class AudioRecorder {
private var useLegacyNormalization = false
private var isRecording = false

private fun isPermissionGranted(activity: Activity?): Int? {
return activity?.let { ActivityCompat.checkSelfPermission(it, permissions[0]) }
}
private fun isPermissionGranted(activity: Activity?): Int? = activity?.let { ActivityCompat.checkSelfPermission(it, permissions[0]) }

fun checkPermission(activity: Activity?, promise: Promise): String {
val permissionResponse = isPermissionGranted(activity)
if (permissionResponse === PackageManager.PERMISSION_GRANTED) {
promise.resolve("granted")
return "granted"
} else {
promise.resolve("denied")
return "denied"
}
}
fun checkPermission(activity: Activity?): String = if (isPermissionGranted(activity) == PackageManager.PERMISSION_GRANTED) "granted" else "denied"

fun getPermission(activity: Activity?, promise: Promise): String {
val permissionResponse = isPermissionGranted(activity)
if (permissionResponse === PackageManager.PERMISSION_GRANTED) {
promise.resolve("granted");
return "granted"
} else {
activity?.let {
ActivityCompat.requestPermissions(
it, permissions,
RECORD_AUDIO_REQUEST_CODE
)
}
return "denied"
}
fun getPermission(activity: Activity?): String {
if (isPermissionGranted(activity) == PackageManager.PERMISSION_GRANTED) return "granted"

activity?.let { ActivityCompat.requestPermissions(it, permissions, RECORD_AUDIO_REQUEST_CODE) }
return "denied"
}

fun getDecibel(recorder: MediaRecorder?): Double? {
Expand Down Expand Up @@ -133,7 +113,7 @@ class AudioRecorder {
val tempArrayForCommunication : MutableList<String> = mutableListOf()
val duration = getDuration(path)
tempArrayForCommunication.add(path)
tempArrayForCommunication.add(duration.toString())
tempArrayForCommunication.add(duration)
promise.resolve(Arguments.fromList(tempArrayForCommunication))
} else {
promise.reject("Error", "Recorder is not recording or has already been stopped")
Expand Down
Loading