Skip to content

Commit de8db71

Browse files
Merge pull request #104 from SimformSolutionsPvtLtd/develop
Release v2.1.1
2 parents d4e5346 + c836c68 commit de8db71

File tree

12 files changed

+215
-123
lines changed

12 files changed

+215
-123
lines changed

android/build.gradle

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,6 @@ android {
6969
lintOptions {
7070
disable "GradleCompatible"
7171
}
72-
73-
compileOptions {
74-
sourceCompatibility JavaVersion.VERSION_11
75-
targetCompatibility JavaVersion.VERSION_11
76-
}
77-
78-
kotlinOptions {
79-
jvmTarget = "11"
80-
}
8172
}
8273

8374
repositories {

android/src/main/java/com/audiowaveform/AudioPlayer.kt

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ class AudioPlayer(
2424
private val key = playerKey
2525
private var updateFrequency = UpdateFrequency.Low
2626
private lateinit var audioPlaybackListener: CountDownTimer
27+
private var isComponentMounted = true // Flag to track mounting status
28+
29+
fun markPlayerAsUnmounted() {
30+
isComponentMounted = false
31+
}
2732

2833
fun preparePlayer(
2934
path: String?,
@@ -34,6 +39,7 @@ class AudioPlayer(
3439
) {
3540
if (path != null) {
3641
isPlayerPrepared = false
42+
isComponentMounted = true
3743
updateFrequency = frequency
3844
val uri = Uri.parse(path)
3945
val mediaItem = MediaItem.fromUri(uri)
@@ -76,7 +82,9 @@ class AudioPlayer(
7682
}
7783
}
7884
args.putString(Constants.playerKey, key)
79-
appContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("onDidFinishPlayingAudio", args)
85+
if (isComponentMounted) {
86+
appContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("onDidFinishPlayingAudio", args)
87+
}
8088
}
8189
}
8290
}
@@ -137,15 +145,14 @@ class AudioPlayer(
137145
}
138146
}
139147

140-
fun stop(promise: Promise) {
148+
fun stop() {
141149
stopListening()
142150
if (playerListener != null) {
143151
player.removeListener(playerListener!!)
144152
}
145153
isPlayerPrepared = false
146154
player.stop()
147155
player.release()
148-
promise.resolve(true)
149156
}
150157

151158
fun pause(promise: Promise) {
@@ -172,16 +179,8 @@ class AudioPlayer(
172179
}
173180
}
174181

175-
fun setPlaybackSpeed(speed: Float?, promise: Promise) {
176-
try {
177-
// Call the custom function to validate and set the playback speed
178-
val success = validateAndSetPlaybackSpeed(player, speed)
179-
promise.resolve(success) // Resolve the promise with success
180-
181-
} catch (e: Exception) {
182-
// Handle any exceptions and reject the promise
183-
promise.reject("setPlaybackSpeed Error", e.toString())
184-
}
182+
fun setPlaybackSpeed(speed: Float?): Boolean {
183+
return validateAndSetPlaybackSpeed(player, speed)
185184
}
186185

187186
private fun startListening(promise: Promise) {
@@ -192,7 +191,9 @@ class AudioPlayer(
192191
val args: WritableMap = Arguments.createMap()
193192
args.putString(Constants.currentDuration, currentPosition)
194193
args.putString(Constants.playerKey, key)
195-
appContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("onCurrentDuration", args)
194+
if (isComponentMounted) {
195+
appContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)?.emit("onCurrentDuration", args)
196+
}
196197
}
197198
override fun onFinish() {}
198199
}.start()

android/src/main/java/com/audiowaveform/AudioRecorder.kt

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ private const val RECORD_AUDIO_REQUEST_CODE = 1001
2020
class AudioRecorder {
2121
private var permissions = arrayOf(Manifest.permission.RECORD_AUDIO)
2222
private var useLegacyNormalization = false
23+
private var isRecording = false
2324

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

123124
fun stopRecording(recorder: MediaRecorder?, path: String, promise: Promise) {
124125
try {
125-
recorder?.apply {
126-
stop()
127-
reset()
128-
release()
126+
if (isRecording) {
127+
recorder?.apply {
128+
stop()
129+
reset()
130+
release()
131+
}
132+
isRecording = false
133+
val tempArrayForCommunication : MutableList<String> = mutableListOf()
134+
val duration = getDuration(path)
135+
tempArrayForCommunication.add(path)
136+
tempArrayForCommunication.add(duration.toString())
137+
promise.resolve(Arguments.fromList(tempArrayForCommunication))
138+
} else {
139+
promise.reject("Error", "Recorder is not recording or has already been stopped")
129140
}
130-
val tempArrayForCommunication : MutableList<String> = mutableListOf()
131-
val duration = getDuration(path)
132-
tempArrayForCommunication.add(path)
133-
tempArrayForCommunication.add(duration.toString())
134-
promise.resolve(Arguments.fromList(tempArrayForCommunication))
135141
} catch (e: IllegalStateException) {
136142
Log.e(Constants.LOG_TAG, "Failed to stop recording",e)
143+
} catch (e: RuntimeException) {
144+
Log.e(Constants.LOG_TAG, "Runtime exception when stopping recording", e)
145+
promise.reject("Error", "Runtime exception: ${e.message}")
137146
}
138147
}
139148

@@ -156,10 +165,12 @@ class AudioRecorder {
156165
useLegacyNormalization = useLegacy
157166
recorder?.apply {
158167
start()
168+
isRecording = true
159169
}
160170
promise.resolve(true)
161171
} catch (e: IllegalStateException) {
162172
Log.e(Constants.LOG_TAG, "Failed to start recording")
173+
isRecording = false
163174
}
164175
}
165176

android/src/main/java/com/audiowaveform/AudioWaveformModule.kt

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
3131
private var sampleRate: Int = 44100
3232
private var bitRate: Int = 128000
3333
private val handler = Handler(Looper.getMainLooper())
34+
private var startTime: Long = 0
3435

3536
companion object {
3637
const val NAME = "AudioWaveform"
@@ -41,6 +42,20 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
4142
return NAME
4243
}
4344

45+
@ReactMethod
46+
fun markPlayerAsUnmounted() {
47+
if (audioPlayers.isEmpty()) {
48+
return
49+
}
50+
51+
audioPlayers.values.forEach { player ->
52+
if (player != null) {
53+
player.markPlayerAsUnmounted()
54+
}
55+
}
56+
}
57+
58+
4459
@ReactMethod
4560
fun checkHasAudioRecorderPermission(promise: Promise) {
4661
audioRecorder.checkPermission(currentActivity, promise)
@@ -66,6 +81,7 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
6681
initRecorder(obj, promise)
6782
val useLegacyNormalization = true
6883
audioRecorder.startRecorder(recorder, useLegacyNormalization, promise)
84+
startTime = System.currentTimeMillis() // Initialize startTime
6985
startEmittingRecorderValue()
7086
}
7187

@@ -90,10 +106,21 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
90106
return
91107
}
92108

93-
audioRecorder.stopRecording(recorder, path!!, promise)
94-
stopEmittingRecorderValue()
95-
recorder = null
96-
path = null
109+
try {
110+
val currentTime = System.currentTimeMillis()
111+
if (currentTime - startTime < 500) {
112+
promise.reject("SHORT_RECORDING", "Recording is too short")
113+
return
114+
}
115+
116+
stopEmittingRecorderValue()
117+
audioRecorder.stopRecording(recorder, path!!, promise)
118+
recorder = null
119+
path = null
120+
} catch (e: Exception) {
121+
Log.e(Constants.LOG_TAG, "Failed to stop recording", e)
122+
promise.reject("Error", "Failed to stop recording: ${e.message}")
123+
}
97124
}
98125

99126
@ReactMethod
@@ -145,8 +172,9 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
145172
fun stopPlayer(obj: ReadableMap, promise: Promise) {
146173
val key = obj.getString(Constants.playerKey)
147174
if (key != null) {
148-
audioPlayers[key]?.stop(promise)
175+
audioPlayers[key]?.stop()
149176
audioPlayers[key] = null // Release the player after stopping it
177+
promise.resolve(true)
150178
} else {
151179
promise.reject("stopPlayer Error", "Player key can't be null")
152180
}
@@ -164,19 +192,24 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
164192

165193
@ReactMethod
166194
fun seekToPlayer(obj: ReadableMap, promise: Promise) {
167-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
168-
val progress = obj.getInt(Constants.progress)
169-
val key = obj.getString(Constants.playerKey)
170-
if (key != null) {
171-
audioPlayers[key]?.seekToPosition(progress.toLong(), promise)
195+
try {
196+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
197+
val progress = obj.getInt(Constants.progress)
198+
val key = obj.getString(Constants.playerKey)
199+
if (key != null) {
200+
audioPlayers[key]?.seekToPosition(progress.toLong(), promise)
201+
} else {
202+
promise.reject("seekTo Error", "Player key can't be null")
203+
}
172204
} else {
173-
promise.reject("seekTo Error", "Player key can't be null")
205+
Log.e(
206+
Constants.LOG_TAG,
207+
"Minimum android O is required for seekTo function to works"
208+
)
209+
promise.resolve(false)
174210
}
175-
} else {
176-
Log.e(
177-
Constants.LOG_TAG,
178-
"Minimum android O is required for seekTo function to works"
179-
)
211+
} catch(e: Exception) {
212+
promise.reject("seekTo Error", e.toString())
180213
}
181214
}
182215

@@ -218,25 +251,31 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
218251
@ReactMethod
219252
fun stopAllPlayers(promise: Promise) {
220253
for ((key, _) in audioPlayers) {
221-
audioPlayers[key]?.stop(promise)
254+
audioPlayers[key]?.stop()
222255
audioPlayers[key] = null
223256
}
257+
promise.resolve(true)
224258
}
225259

226260
@ReactMethod
227261
fun setPlaybackSpeed(obj: ReadableMap, promise: Promise) {
228-
// If the key doesn't exist or if the value is null or undefined, set default speed to 1.0
229-
val speed = if (!obj.hasKey(Constants.speed) || obj.isNull(Constants.speed)) {
230-
1.0f // Set default speed to 1.0 if null, undefined, or missing
231-
} else {
232-
obj.getDouble(Constants.speed).toFloat()
233-
}
262+
try {
263+
// If the key doesn't exist or if the value is null or undefined, set default speed to 1.0
264+
val speed = if (!obj.hasKey(Constants.speed) || obj.isNull(Constants.speed)) {
265+
1.0f // Set default speed to 1.0 if null, undefined, or missing
266+
} else {
267+
obj.getDouble(Constants.speed).toFloat()
268+
}
234269

235-
val key = obj.getString(Constants.playerKey)
236-
if (key != null) {
237-
audioPlayers[key]?.setPlaybackSpeed(speed, promise)
238-
} else {
239-
promise.reject("setPlaybackSpeed Error", "Player key can't be null")
270+
val key = obj.getString(Constants.playerKey)
271+
if (key != null) {
272+
val status = audioPlayers[key]?.setPlaybackSpeed(speed)
273+
promise.resolve(status ?: false)
274+
} else {
275+
promise.reject("setPlaybackSpeed Error", "Player key can't be null")
276+
}
277+
} catch(e: Exception) {
278+
promise.reject("setPlaybackSpeed Error", e.toString())
240279
}
241280
}
242281

@@ -276,11 +315,15 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
276315
}
277316
}
278317
}
279-
},
280-
promise
318+
override fun onReject(error: String?, message: String?) {
319+
promise.reject(error, message)
320+
}
321+
override fun onResolve(value: MutableList<MutableList<Float>>) {
322+
promise.resolve(Arguments.fromList(value))
323+
}
324+
}
281325
)
282-
extractors[playerKey]?.startDecode()
283-
extractors[playerKey]?.stop()
326+
extractors[playerKey]?.startDecode();
284327
}
285328

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

0 commit comments

Comments
 (0)