Skip to content

Commit

Permalink
Merge pull request #104 from SimformSolutionsPvtLtd/develop
Browse files Browse the repository at this point in the history
Release v2.1.1
  • Loading branch information
mukesh-simform authored Oct 9, 2024
2 parents d4e5346 + c836c68 commit de8db71
Show file tree
Hide file tree
Showing 12 changed files with 215 additions and 123 deletions.
9 changes: 0 additions & 9 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,6 @@ android {
lintOptions {
disable "GradleCompatible"
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}

kotlinOptions {
jvmTarget = "11"
}
}

repositories {
Expand Down
29 changes: 15 additions & 14 deletions android/src/main/java/com/audiowaveform/AudioPlayer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ class AudioPlayer(
private val key = playerKey
private var updateFrequency = UpdateFrequency.Low
private lateinit var audioPlaybackListener: CountDownTimer
private var isComponentMounted = true // Flag to track mounting status

fun markPlayerAsUnmounted() {
isComponentMounted = false
}

fun preparePlayer(
path: String?,
Expand All @@ -34,6 +39,7 @@ class AudioPlayer(
) {
if (path != null) {
isPlayerPrepared = false
isComponentMounted = true
updateFrequency = frequency
val uri = Uri.parse(path)
val mediaItem = MediaItem.fromUri(uri)
Expand Down Expand Up @@ -76,7 +82,9 @@ class AudioPlayer(
}
}
args.putString(Constants.playerKey, key)
appContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("onDidFinishPlayingAudio", args)
if (isComponentMounted) {
appContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("onDidFinishPlayingAudio", args)
}
}
}
}
Expand Down Expand Up @@ -137,15 +145,14 @@ class AudioPlayer(
}
}

fun stop(promise: Promise) {
fun stop() {
stopListening()
if (playerListener != null) {
player.removeListener(playerListener!!)
}
isPlayerPrepared = false
player.stop()
player.release()
promise.resolve(true)
}

fun pause(promise: Promise) {
Expand All @@ -172,16 +179,8 @@ class AudioPlayer(
}
}

fun setPlaybackSpeed(speed: Float?, promise: Promise) {
try {
// Call the custom function to validate and set the playback speed
val success = validateAndSetPlaybackSpeed(player, speed)
promise.resolve(success) // Resolve the promise with success

} catch (e: Exception) {
// Handle any exceptions and reject the promise
promise.reject("setPlaybackSpeed Error", e.toString())
}
fun setPlaybackSpeed(speed: Float?): Boolean {
return validateAndSetPlaybackSpeed(player, speed)
}

private fun startListening(promise: Promise) {
Expand All @@ -192,7 +191,9 @@ class AudioPlayer(
val args: WritableMap = Arguments.createMap()
args.putString(Constants.currentDuration, currentPosition)
args.putString(Constants.playerKey, key)
appContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("onCurrentDuration", args)
if (isComponentMounted) {
appContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("onCurrentDuration", args)
}
}
override fun onFinish() {}
}.start()
Expand Down
29 changes: 20 additions & 9 deletions android/src/main/java/com/audiowaveform/AudioRecorder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ private const val RECORD_AUDIO_REQUEST_CODE = 1001
class AudioRecorder {
private var permissions = arrayOf(Manifest.permission.RECORD_AUDIO)
private var useLegacyNormalization = false
private var isRecording = false

private fun isPermissionGranted(activity: Activity?): Int? {
return activity?.let { ActivityCompat.checkSelfPermission(it, permissions[0]) }
Expand Down Expand Up @@ -122,18 +123,26 @@ class AudioRecorder {

fun stopRecording(recorder: MediaRecorder?, path: String, promise: Promise) {
try {
recorder?.apply {
stop()
reset()
release()
if (isRecording) {
recorder?.apply {
stop()
reset()
release()
}
isRecording = false
val tempArrayForCommunication : MutableList<String> = mutableListOf()
val duration = getDuration(path)
tempArrayForCommunication.add(path)
tempArrayForCommunication.add(duration.toString())
promise.resolve(Arguments.fromList(tempArrayForCommunication))
} else {
promise.reject("Error", "Recorder is not recording or has already been stopped")
}
val tempArrayForCommunication : MutableList<String> = mutableListOf()
val duration = getDuration(path)
tempArrayForCommunication.add(path)
tempArrayForCommunication.add(duration.toString())
promise.resolve(Arguments.fromList(tempArrayForCommunication))
} catch (e: IllegalStateException) {
Log.e(Constants.LOG_TAG, "Failed to stop recording",e)
} catch (e: RuntimeException) {
Log.e(Constants.LOG_TAG, "Runtime exception when stopping recording", e)
promise.reject("Error", "Runtime exception: ${e.message}")
}
}

Expand All @@ -156,10 +165,12 @@ class AudioRecorder {
useLegacyNormalization = useLegacy
recorder?.apply {
start()
isRecording = true
}
promise.resolve(true)
} catch (e: IllegalStateException) {
Log.e(Constants.LOG_TAG, "Failed to start recording")
isRecording = false
}
}

Expand Down
107 changes: 75 additions & 32 deletions android/src/main/java/com/audiowaveform/AudioWaveformModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
private var sampleRate: Int = 44100
private var bitRate: Int = 128000
private val handler = Handler(Looper.getMainLooper())
private var startTime: Long = 0

companion object {
const val NAME = "AudioWaveform"
Expand All @@ -41,6 +42,20 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
return NAME
}

@ReactMethod
fun markPlayerAsUnmounted() {
if (audioPlayers.isEmpty()) {
return
}

audioPlayers.values.forEach { player ->
if (player != null) {
player.markPlayerAsUnmounted()
}
}
}


@ReactMethod
fun checkHasAudioRecorderPermission(promise: Promise) {
audioRecorder.checkPermission(currentActivity, promise)
Expand All @@ -66,6 +81,7 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
initRecorder(obj, promise)
val useLegacyNormalization = true
audioRecorder.startRecorder(recorder, useLegacyNormalization, promise)
startTime = System.currentTimeMillis() // Initialize startTime
startEmittingRecorderValue()
}

Expand All @@ -90,10 +106,21 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
return
}

audioRecorder.stopRecording(recorder, path!!, promise)
stopEmittingRecorderValue()
recorder = null
path = null
try {
val currentTime = System.currentTimeMillis()
if (currentTime - startTime < 500) {
promise.reject("SHORT_RECORDING", "Recording is too short")
return
}

stopEmittingRecorderValue()
audioRecorder.stopRecording(recorder, path!!, promise)
recorder = null
path = null
} catch (e: Exception) {
Log.e(Constants.LOG_TAG, "Failed to stop recording", e)
promise.reject("Error", "Failed to stop recording: ${e.message}")
}
}

@ReactMethod
Expand Down Expand Up @@ -145,8 +172,9 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
fun stopPlayer(obj: ReadableMap, promise: Promise) {
val key = obj.getString(Constants.playerKey)
if (key != null) {
audioPlayers[key]?.stop(promise)
audioPlayers[key]?.stop()
audioPlayers[key] = null // Release the player after stopping it
promise.resolve(true)
} else {
promise.reject("stopPlayer Error", "Player key can't be null")
}
Expand All @@ -164,19 +192,24 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav

@ReactMethod
fun seekToPlayer(obj: ReadableMap, promise: Promise) {
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)
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")
}
} else {
promise.reject("seekTo Error", "Player key can't be null")
Log.e(
Constants.LOG_TAG,
"Minimum android O is required for seekTo function to works"
)
promise.resolve(false)
}
} else {
Log.e(
Constants.LOG_TAG,
"Minimum android O is required for seekTo function to works"
)
} catch(e: Exception) {
promise.reject("seekTo Error", e.toString())
}
}

Expand Down Expand Up @@ -218,25 +251,31 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
@ReactMethod
fun stopAllPlayers(promise: Promise) {
for ((key, _) in audioPlayers) {
audioPlayers[key]?.stop(promise)
audioPlayers[key]?.stop()
audioPlayers[key] = null
}
promise.resolve(true)
}

@ReactMethod
fun setPlaybackSpeed(obj: ReadableMap, promise: Promise) {
// If the key doesn't exist or if the value is null or undefined, set default speed to 1.0
val speed = if (!obj.hasKey(Constants.speed) || obj.isNull(Constants.speed)) {
1.0f // Set default speed to 1.0 if null, undefined, or missing
} else {
obj.getDouble(Constants.speed).toFloat()
}
try {
// If the key doesn't exist or if the value is null or undefined, set default speed to 1.0
val speed = if (!obj.hasKey(Constants.speed) || obj.isNull(Constants.speed)) {
1.0f // Set default speed to 1.0 if null, undefined, or missing
} else {
obj.getDouble(Constants.speed).toFloat()
}

val key = obj.getString(Constants.playerKey)
if (key != null) {
audioPlayers[key]?.setPlaybackSpeed(speed, promise)
} else {
promise.reject("setPlaybackSpeed Error", "Player key can't be null")
val key = obj.getString(Constants.playerKey)
if (key != null) {
val status = audioPlayers[key]?.setPlaybackSpeed(speed)
promise.resolve(status ?: false)
} else {
promise.reject("setPlaybackSpeed Error", "Player key can't be null")
}
} catch(e: Exception) {
promise.reject("setPlaybackSpeed Error", e.toString())
}
}

Expand Down Expand Up @@ -276,11 +315,15 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
}
}
}
},
promise
override fun onReject(error: String?, message: String?) {
promise.reject(error, message)
}
override fun onResolve(value: MutableList<MutableList<Float>>) {
promise.resolve(Arguments.fromList(value))
}
}
)
extractors[playerKey]?.startDecode()
extractors[playerKey]?.stop()
extractors[playerKey]?.startDecode();
}

private fun normalizeWaveformData(data: MutableList<Float>, scale: Float = 0.25f, threshold: Float = 0.01f): MutableList<Float> {
Expand Down
Loading

0 comments on commit de8db71

Please sign in to comment.