nosnia-audio-recorder 0.9.15 → 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.
@@ -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
+ }
@@ -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