nosnia-audio-recorder 0.9.14 → 0.9.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/nosniaaudiorecorder/NosniaAudioPlayerModule.kt +237 -237
- package/ios/NosniaAudioPlayer.h +6 -6
- package/ios/NosniaAudioPlayer.mm +254 -254
- package/ios/NosniaAudioRecorder.mm +28 -32
- package/ios/Pods/Pods.xcodeproj/xcuserdata/nosnia.xcuserdatad/xcschemes/xcschememanagement.plist +10 -0
- package/lib/module/AudioPlayer.js.map +1 -1
- package/lib/module/NativeNosniaAudioPlayer.js.map +1 -1
- package/lib/module/NativeNosniaAudioRecorder.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/package.json +174 -174
|
@@ -1,237 +1,237 @@
|
|
|
1
|
-
package com.nosniaaudiorecorder
|
|
2
|
-
|
|
3
|
-
import android.media.MediaPlayer
|
|
4
|
-
import android.os.Handler
|
|
5
|
-
import android.os.Looper
|
|
6
|
-
import com.facebook.react.bridge.*
|
|
7
|
-
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
8
|
-
import com.facebook.react.module.annotations.ReactModule
|
|
9
|
-
import java.io.File
|
|
10
|
-
|
|
11
|
-
@ReactModule(name = "NosniaAudioPlayer")
|
|
12
|
-
class NosniaAudioPlayerModule(private val reactContext: ReactApplicationContext) :
|
|
13
|
-
ReactContextBaseJavaModule(reactContext) {
|
|
14
|
-
|
|
15
|
-
companion object {
|
|
16
|
-
const val NAME = "NosniaAudioPlayer"
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
private var mediaPlayer: MediaPlayer? = null
|
|
20
|
-
private var currentFilePath: String? = null
|
|
21
|
-
private var isPlaying = false
|
|
22
|
-
|
|
23
|
-
private val progressHandler = Handler(Looper.getMainLooper())
|
|
24
|
-
private val progressRunnable = object : Runnable {
|
|
25
|
-
override fun run() {
|
|
26
|
-
mediaPlayer?.let { player ->
|
|
27
|
-
if (isPlaying && player.isPlaying) {
|
|
28
|
-
val currentTime = player.currentPosition.toLong()
|
|
29
|
-
val duration = player.duration.toLong()
|
|
30
|
-
|
|
31
|
-
sendEvent("onPlaybackProgress", Arguments.createMap().apply {
|
|
32
|
-
putDouble("currentTime", currentTime.toDouble())
|
|
33
|
-
putDouble("duration", duration.toDouble())
|
|
34
|
-
putBoolean("isPlaying", true)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
progressHandler.postDelayed(this, 100)
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
private fun sendEvent(eventName: String, params: WritableMap?) {
|
|
44
|
-
reactContext
|
|
45
|
-
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
46
|
-
.emit(eventName, params)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
private fun startProgressUpdates() {
|
|
50
|
-
progressHandler.post(progressRunnable)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
private fun stopProgressUpdates() {
|
|
54
|
-
progressHandler.removeCallbacks(progressRunnable)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
override fun getName(): String = NAME
|
|
58
|
-
|
|
59
|
-
@ReactMethod
|
|
60
|
-
fun startPlaying(options: ReadableMap, promise: Promise) {
|
|
61
|
-
try {
|
|
62
|
-
val filePath = options.getString("filePath")
|
|
63
|
-
if (filePath == null) {
|
|
64
|
-
promise.reject("INVALID_PATH", "File path is required")
|
|
65
|
-
return
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
val volume = if (options.hasKey("volume")) {
|
|
69
|
-
options.getDouble("volume").toFloat()
|
|
70
|
-
} else {
|
|
71
|
-
1.0f
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
val loop = if (options.hasKey("loop")) {
|
|
75
|
-
options.getBoolean("loop")
|
|
76
|
-
} else {
|
|
77
|
-
false
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
val file = File(filePath)
|
|
81
|
-
if (!file.exists()) {
|
|
82
|
-
promise.reject("FILE_NOT_FOUND", "Audio file not found: $filePath")
|
|
83
|
-
return
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
mediaPlayer?.release()
|
|
87
|
-
|
|
88
|
-
val module = this
|
|
89
|
-
mediaPlayer = MediaPlayer().apply {
|
|
90
|
-
setDataSource(filePath)
|
|
91
|
-
setVolume(volume, volume)
|
|
92
|
-
isLooping = loop
|
|
93
|
-
|
|
94
|
-
setOnCompletionListener {
|
|
95
|
-
module.isPlaying = false
|
|
96
|
-
stopProgressUpdates()
|
|
97
|
-
sendEvent("onPlaybackComplete", Arguments.createMap())
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
setOnErrorListener { _, _, _ ->
|
|
101
|
-
module.isPlaying = false
|
|
102
|
-
stopProgressUpdates()
|
|
103
|
-
true
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
prepare()
|
|
107
|
-
start()
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
this.isPlaying = true
|
|
111
|
-
this.currentFilePath = filePath
|
|
112
|
-
startProgressUpdates()
|
|
113
|
-
promise.resolve(null)
|
|
114
|
-
} catch (e: Exception) {
|
|
115
|
-
mediaPlayer?.release()
|
|
116
|
-
mediaPlayer = null
|
|
117
|
-
this.isPlaying = false
|
|
118
|
-
promise.reject("START_PLAYING_ERROR", e.message, e)
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
@ReactMethod
|
|
123
|
-
fun stopPlaying(promise: Promise) {
|
|
124
|
-
try {
|
|
125
|
-
stopProgressUpdates()
|
|
126
|
-
|
|
127
|
-
mediaPlayer?.apply {
|
|
128
|
-
if (isPlaying) {
|
|
129
|
-
stop()
|
|
130
|
-
}
|
|
131
|
-
release()
|
|
132
|
-
}
|
|
133
|
-
mediaPlayer = null
|
|
134
|
-
this.isPlaying = false
|
|
135
|
-
this.currentFilePath = null
|
|
136
|
-
|
|
137
|
-
promise.resolve(null)
|
|
138
|
-
} catch (e: Exception) {
|
|
139
|
-
promise.reject("STOP_PLAYING_ERROR", e.message, e)
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
@ReactMethod
|
|
144
|
-
fun pausePlaying(promise: Promise) {
|
|
145
|
-
try {
|
|
146
|
-
if (!this.isPlaying || mediaPlayer == null) {
|
|
147
|
-
promise.reject("NOT_PLAYING", "No playback in progress")
|
|
148
|
-
return
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
mediaPlayer?.pause()
|
|
152
|
-
this.isPlaying = false
|
|
153
|
-
promise.resolve(null)
|
|
154
|
-
} catch (e: Exception) {
|
|
155
|
-
promise.reject("PAUSE_ERROR", e.message, e)
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
@ReactMethod
|
|
160
|
-
fun resumePlaying(promise: Promise) {
|
|
161
|
-
try {
|
|
162
|
-
if (this.isPlaying || mediaPlayer == null) {
|
|
163
|
-
promise.reject("NOT_PAUSED", "Playback is not paused")
|
|
164
|
-
return
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
mediaPlayer?.start()
|
|
168
|
-
this.isPlaying = true
|
|
169
|
-
promise.resolve(null)
|
|
170
|
-
} catch (e: Exception) {
|
|
171
|
-
promise.reject("RESUME_ERROR", e.message, e)
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
@ReactMethod
|
|
176
|
-
fun seekToTime(time: Double, promise: Promise) {
|
|
177
|
-
try {
|
|
178
|
-
if (mediaPlayer == null) {
|
|
179
|
-
promise.reject("NO_PLAYER", "No audio player initialized")
|
|
180
|
-
return
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
val timeMs = (time * 1000).toInt()
|
|
184
|
-
mediaPlayer?.seekTo(timeMs)
|
|
185
|
-
promise.resolve(null)
|
|
186
|
-
} catch (e: Exception) {
|
|
187
|
-
promise.reject("SEEK_ERROR", e.message, e)
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
@ReactMethod
|
|
192
|
-
fun setVolume(volume: Double, promise: Promise) {
|
|
193
|
-
try {
|
|
194
|
-
if (mediaPlayer == null) {
|
|
195
|
-
promise.reject("NO_PLAYER", "No audio player initialized")
|
|
196
|
-
return
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
val volumeFloat = volume.toFloat()
|
|
200
|
-
mediaPlayer?.setVolume(volumeFloat, volumeFloat)
|
|
201
|
-
promise.resolve(null)
|
|
202
|
-
} catch (e: Exception) {
|
|
203
|
-
promise.reject("SET_VOLUME_ERROR", e.message, e)
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
@ReactMethod
|
|
208
|
-
fun getPlayerStatus(promise: Promise) {
|
|
209
|
-
try {
|
|
210
|
-
val status = WritableNativeMap().apply {
|
|
211
|
-
putBoolean("isPlaying", this@NosniaAudioPlayerModule.isPlaying)
|
|
212
|
-
|
|
213
|
-
if (mediaPlayer != null) {
|
|
214
|
-
putDouble("duration", mediaPlayer!!.duration.toDouble())
|
|
215
|
-
putDouble("currentTime", mediaPlayer!!.currentPosition.toDouble())
|
|
216
|
-
} else {
|
|
217
|
-
putDouble("duration", 0.0)
|
|
218
|
-
putDouble("currentTime", 0.0)
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (this@NosniaAudioPlayerModule.currentFilePath != null) {
|
|
222
|
-
putString("currentFilePath", this@NosniaAudioPlayerModule.currentFilePath)
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
promise.resolve(status)
|
|
226
|
-
} catch (e: Exception) {
|
|
227
|
-
promise.reject("STATUS_ERROR", e.message, e)
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
override fun onCatalystInstanceDestroy() {
|
|
232
|
-
super.onCatalystInstanceDestroy()
|
|
233
|
-
stopProgressUpdates()
|
|
234
|
-
mediaPlayer?.release()
|
|
235
|
-
mediaPlayer = null
|
|
236
|
-
}
|
|
237
|
-
}
|
|
1
|
+
package com.nosniaaudiorecorder
|
|
2
|
+
|
|
3
|
+
import android.media.MediaPlayer
|
|
4
|
+
import android.os.Handler
|
|
5
|
+
import android.os.Looper
|
|
6
|
+
import com.facebook.react.bridge.*
|
|
7
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
8
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
9
|
+
import java.io.File
|
|
10
|
+
|
|
11
|
+
@ReactModule(name = "NosniaAudioPlayer")
|
|
12
|
+
class NosniaAudioPlayerModule(private val reactContext: ReactApplicationContext) :
|
|
13
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
14
|
+
|
|
15
|
+
companion object {
|
|
16
|
+
const val NAME = "NosniaAudioPlayer"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private var mediaPlayer: MediaPlayer? = null
|
|
20
|
+
private var currentFilePath: String? = null
|
|
21
|
+
private var isPlaying = false
|
|
22
|
+
|
|
23
|
+
private val progressHandler = Handler(Looper.getMainLooper())
|
|
24
|
+
private val progressRunnable = object : Runnable {
|
|
25
|
+
override fun run() {
|
|
26
|
+
mediaPlayer?.let { player ->
|
|
27
|
+
if (isPlaying && player.isPlaying) {
|
|
28
|
+
val currentTime = player.currentPosition.toLong()
|
|
29
|
+
val duration = player.duration.toLong()
|
|
30
|
+
|
|
31
|
+
sendEvent("onPlaybackProgress", Arguments.createMap().apply {
|
|
32
|
+
putDouble("currentTime", currentTime.toDouble())
|
|
33
|
+
putDouble("duration", duration.toDouble())
|
|
34
|
+
putBoolean("isPlaying", true)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
progressHandler.postDelayed(this, 100)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private fun sendEvent(eventName: String, params: WritableMap?) {
|
|
44
|
+
reactContext
|
|
45
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
46
|
+
.emit(eventName, params)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private fun startProgressUpdates() {
|
|
50
|
+
progressHandler.post(progressRunnable)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private fun stopProgressUpdates() {
|
|
54
|
+
progressHandler.removeCallbacks(progressRunnable)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
override fun getName(): String = NAME
|
|
58
|
+
|
|
59
|
+
@ReactMethod
|
|
60
|
+
fun startPlaying(options: ReadableMap, promise: Promise) {
|
|
61
|
+
try {
|
|
62
|
+
val filePath = options.getString("filePath")
|
|
63
|
+
if (filePath == null) {
|
|
64
|
+
promise.reject("INVALID_PATH", "File path is required")
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
val volume = if (options.hasKey("volume")) {
|
|
69
|
+
options.getDouble("volume").toFloat()
|
|
70
|
+
} else {
|
|
71
|
+
1.0f
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
val loop = if (options.hasKey("loop")) {
|
|
75
|
+
options.getBoolean("loop")
|
|
76
|
+
} else {
|
|
77
|
+
false
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
val file = File(filePath)
|
|
81
|
+
if (!file.exists()) {
|
|
82
|
+
promise.reject("FILE_NOT_FOUND", "Audio file not found: $filePath")
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
mediaPlayer?.release()
|
|
87
|
+
|
|
88
|
+
val module = this
|
|
89
|
+
mediaPlayer = MediaPlayer().apply {
|
|
90
|
+
setDataSource(filePath)
|
|
91
|
+
setVolume(volume, volume)
|
|
92
|
+
isLooping = loop
|
|
93
|
+
|
|
94
|
+
setOnCompletionListener {
|
|
95
|
+
module.isPlaying = false
|
|
96
|
+
stopProgressUpdates()
|
|
97
|
+
sendEvent("onPlaybackComplete", Arguments.createMap())
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
setOnErrorListener { _, _, _ ->
|
|
101
|
+
module.isPlaying = false
|
|
102
|
+
stopProgressUpdates()
|
|
103
|
+
true
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
prepare()
|
|
107
|
+
start()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
this.isPlaying = true
|
|
111
|
+
this.currentFilePath = filePath
|
|
112
|
+
startProgressUpdates()
|
|
113
|
+
promise.resolve(null)
|
|
114
|
+
} catch (e: Exception) {
|
|
115
|
+
mediaPlayer?.release()
|
|
116
|
+
mediaPlayer = null
|
|
117
|
+
this.isPlaying = false
|
|
118
|
+
promise.reject("START_PLAYING_ERROR", e.message, e)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@ReactMethod
|
|
123
|
+
fun stopPlaying(promise: Promise) {
|
|
124
|
+
try {
|
|
125
|
+
stopProgressUpdates()
|
|
126
|
+
|
|
127
|
+
mediaPlayer?.apply {
|
|
128
|
+
if (isPlaying) {
|
|
129
|
+
stop()
|
|
130
|
+
}
|
|
131
|
+
release()
|
|
132
|
+
}
|
|
133
|
+
mediaPlayer = null
|
|
134
|
+
this.isPlaying = false
|
|
135
|
+
this.currentFilePath = null
|
|
136
|
+
|
|
137
|
+
promise.resolve(null)
|
|
138
|
+
} catch (e: Exception) {
|
|
139
|
+
promise.reject("STOP_PLAYING_ERROR", e.message, e)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@ReactMethod
|
|
144
|
+
fun pausePlaying(promise: Promise) {
|
|
145
|
+
try {
|
|
146
|
+
if (!this.isPlaying || mediaPlayer == null) {
|
|
147
|
+
promise.reject("NOT_PLAYING", "No playback in progress")
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
mediaPlayer?.pause()
|
|
152
|
+
this.isPlaying = false
|
|
153
|
+
promise.resolve(null)
|
|
154
|
+
} catch (e: Exception) {
|
|
155
|
+
promise.reject("PAUSE_ERROR", e.message, e)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@ReactMethod
|
|
160
|
+
fun resumePlaying(promise: Promise) {
|
|
161
|
+
try {
|
|
162
|
+
if (this.isPlaying || mediaPlayer == null) {
|
|
163
|
+
promise.reject("NOT_PAUSED", "Playback is not paused")
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
mediaPlayer?.start()
|
|
168
|
+
this.isPlaying = true
|
|
169
|
+
promise.resolve(null)
|
|
170
|
+
} catch (e: Exception) {
|
|
171
|
+
promise.reject("RESUME_ERROR", e.message, e)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@ReactMethod
|
|
176
|
+
fun seekToTime(time: Double, promise: Promise) {
|
|
177
|
+
try {
|
|
178
|
+
if (mediaPlayer == null) {
|
|
179
|
+
promise.reject("NO_PLAYER", "No audio player initialized")
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
val timeMs = (time * 1000).toInt()
|
|
184
|
+
mediaPlayer?.seekTo(timeMs)
|
|
185
|
+
promise.resolve(null)
|
|
186
|
+
} catch (e: Exception) {
|
|
187
|
+
promise.reject("SEEK_ERROR", e.message, e)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
@ReactMethod
|
|
192
|
+
fun setVolume(volume: Double, promise: Promise) {
|
|
193
|
+
try {
|
|
194
|
+
if (mediaPlayer == null) {
|
|
195
|
+
promise.reject("NO_PLAYER", "No audio player initialized")
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
val volumeFloat = volume.toFloat()
|
|
200
|
+
mediaPlayer?.setVolume(volumeFloat, volumeFloat)
|
|
201
|
+
promise.resolve(null)
|
|
202
|
+
} catch (e: Exception) {
|
|
203
|
+
promise.reject("SET_VOLUME_ERROR", e.message, e)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
@ReactMethod
|
|
208
|
+
fun getPlayerStatus(promise: Promise) {
|
|
209
|
+
try {
|
|
210
|
+
val status = WritableNativeMap().apply {
|
|
211
|
+
putBoolean("isPlaying", this@NosniaAudioPlayerModule.isPlaying)
|
|
212
|
+
|
|
213
|
+
if (mediaPlayer != null) {
|
|
214
|
+
putDouble("duration", mediaPlayer!!.duration.toDouble())
|
|
215
|
+
putDouble("currentTime", mediaPlayer!!.currentPosition.toDouble())
|
|
216
|
+
} else {
|
|
217
|
+
putDouble("duration", 0.0)
|
|
218
|
+
putDouble("currentTime", 0.0)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (this@NosniaAudioPlayerModule.currentFilePath != null) {
|
|
222
|
+
putString("currentFilePath", this@NosniaAudioPlayerModule.currentFilePath)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
promise.resolve(status)
|
|
226
|
+
} catch (e: Exception) {
|
|
227
|
+
promise.reject("STATUS_ERROR", e.message, e)
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
override fun onCatalystInstanceDestroy() {
|
|
232
|
+
super.onCatalystInstanceDestroy()
|
|
233
|
+
stopProgressUpdates()
|
|
234
|
+
mediaPlayer?.release()
|
|
235
|
+
mediaPlayer = null
|
|
236
|
+
}
|
|
237
|
+
}
|
package/ios/NosniaAudioPlayer.h
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#import <React/RCTBridgeModule.h>
|
|
2
|
-
#import <React/RCTEventEmitter.h>
|
|
3
|
-
|
|
4
|
-
@interface NosniaAudioPlayer : RCTEventEmitter
|
|
5
|
-
|
|
6
|
-
@end
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
#import <React/RCTEventEmitter.h>
|
|
3
|
+
|
|
4
|
+
@interface NosniaAudioPlayer : RCTEventEmitter
|
|
5
|
+
|
|
6
|
+
@end
|