@siteed/expo-audio-stream 0.5.1 → 0.6.0

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.
Files changed (30) hide show
  1. package/android/src/main/java/net/siteed/audiostream/AudioDataEncoder.kt +9 -0
  2. package/android/src/main/java/net/siteed/audiostream/AudioFileHandler.kt +62 -0
  3. package/android/src/main/java/net/siteed/audiostream/AudioFormatUtils.kt +4 -0
  4. package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +445 -0
  5. package/android/src/main/java/net/siteed/audiostream/Constants.kt +12 -0
  6. package/android/src/main/java/net/siteed/audiostream/EventSender.kt +7 -0
  7. package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +43 -392
  8. package/android/src/main/java/net/siteed/audiostream/PermissionUtils.kt +16 -0
  9. package/build/ExpoAudioStream.types.d.ts +12 -1
  10. package/build/ExpoAudioStream.types.d.ts.map +1 -1
  11. package/build/ExpoAudioStream.types.js.map +1 -1
  12. package/build/ExpoAudioStreamModule.web.d.ts +2 -2
  13. package/build/ExpoAudioStreamModule.web.d.ts.map +1 -1
  14. package/build/ExpoAudioStreamModule.web.js +5 -1
  15. package/build/ExpoAudioStreamModule.web.js.map +1 -1
  16. package/build/index.d.ts +1 -0
  17. package/build/index.d.ts.map +1 -1
  18. package/build/index.js +3 -0
  19. package/build/index.js.map +1 -1
  20. package/build/useAudioRecording.d.ts +5 -4
  21. package/build/useAudioRecording.d.ts.map +1 -1
  22. package/build/useAudioRecording.js +38 -27
  23. package/build/useAudioRecording.js.map +1 -1
  24. package/ios/AudioStreamManager.swift +46 -16
  25. package/ios/ExpoAudioStreamModule.swift +2 -2
  26. package/package.json +1 -1
  27. package/src/ExpoAudioStream.types.ts +14 -5
  28. package/src/ExpoAudioStreamModule.web.ts +8 -3
  29. package/src/index.ts +4 -0
  30. package/src/useAudioRecording.ts +48 -34
@@ -1,417 +1,68 @@
1
1
  package net.siteed.audiostream
2
2
 
3
- import android.Manifest
4
- import android.annotation.SuppressLint
5
- import android.content.pm.PackageManager
6
- import android.media.AudioFormat
7
- import android.media.AudioRecord
8
- import android.media.MediaRecorder
3
+ import android.os.Build
4
+ import android.os.Bundle
9
5
  import android.util.Log
10
- import androidx.core.content.ContextCompat
11
- import androidx.core.os.bundleOf
6
+ import androidx.annotation.RequiresApi
7
+ import expo.modules.kotlin.Promise
12
8
  import expo.modules.kotlin.modules.Module
13
9
  import expo.modules.kotlin.modules.ModuleDefinition
14
- import expo.modules.kotlin.Promise
15
- import android.util.Base64
16
- import android.os.Handler
17
- import android.os.SystemClock
18
- import java.io.ByteArrayOutputStream
19
- import android.os.Looper
20
- import expo.modules.core.interfaces.Function
21
- import java.util.concurrent.atomic.AtomicBoolean
22
- import java.io.File
23
- import java.io.FileOutputStream
24
- import java.io.IOException
25
- import java.io.RandomAccessFile
26
-
27
- const val AUDIO_EVENT_NAME = "AudioData"
28
- const val DEFAULT_SAMPLE_RATE = 16000 // Default sample rate for audio recording
29
- const val DEFAULT_CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO
30
- const val DEFAULT_AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT
31
-
32
- class ExpoAudioStreamModule() : Module() {
33
- private var audioRecord: AudioRecord? = null
34
- private var sampleRateInHz = DEFAULT_SAMPLE_RATE
35
- private var channelConfig = DEFAULT_CHANNEL_CONFIG
36
- private var audioFormat = DEFAULT_AUDIO_FORMAT
37
- private var bufferSizeInBytes: Int = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)
38
- private var isRecording = AtomicBoolean(false)
39
- private val isPaused = AtomicBoolean(false)
40
- private var streamUuid: String? = null
41
- private var audioFile: File? = null
42
- private var recordingThread: Thread? = null
43
- private var recordingStartTime: Long = 0
44
- private var totalRecordedTime: Long = 0
45
- private var totalDataSize = 0
46
- private val audioDataBuffer = ByteArrayOutputStream()
47
- private var interval = 1000L // Emit data every 1000 milliseconds (1 second)
48
- private var lastEmitTime = SystemClock.elapsedRealtime()
49
- private var lastPauseTime = 0L
50
- private var pausedDuration = 0L
51
- private var lastEmittedSize = 0L
52
- private var mimeType = "audio/wav"
53
- private val mainHandler = Handler(Looper.getMainLooper())
54
- private var bitDepth = 16
55
- private var channels = 1
56
-
57
- @SuppressLint("MissingPermission")
58
- override fun definition() = ModuleDefinition {
59
- // Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
60
- // Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
61
- // The module will be accessible from `requireNativeModule('ExpoAudioStream')` in JavaScript.
62
- Name("ExpoAudioStream")
63
-
64
- Events(AUDIO_EVENT_NAME)
65
-
66
- AsyncFunction("startRecording") { options: Map<String, Any?>, promise: Promise ->
67
- configureRecording(options)
68
- startRecording(options, promise)
69
- }
70
-
71
- Function("clearAudioFiles") {
72
- clearAudioStorage()
73
- }
74
-
75
- Function("status") {
76
- // Ensure you update this to check if audioFile is null or not
77
- val fileSize = audioFile?.length() ?: 0
78
- val dataFileSize = fileSize - 44 // Assuming header is always 44 bytes
79
-
80
- val byteRate = sampleRateInHz * channels * (bitDepth / 8)
81
- val duration = if (byteRate > 0) (dataFileSize * 1000 / byteRate) else 0 // Duration in milliseconds
82
-
83
- bundleOf(
84
- "duration" to duration,
85
- "isRecording" to isRecording.get(),
86
- "isPaused" to isPaused.get(),
87
- "mime" to mimeType,
88
- "size" to totalDataSize,
89
- "interval" to interval,
90
- )
91
- }
92
-
93
- AsyncFunction("listAudioFiles") { promise: Promise ->
94
- try {
95
- val fileList = listAudioFiles()
96
- promise.resolve(fileList)
97
- } catch (e: Exception) {
98
- promise.reject("ERROR_LIST_FILES", "Failed to list audio files", e)
99
- }
100
- }
101
-
102
- AsyncFunction("pauseRecording") { promise: Promise ->
103
- Log.d("AudioRecorderModule", "Pausing recording")
104
- pauseRecording(promise)
105
- }
106
-
107
- AsyncFunction("stopRecording") { promise: Promise ->
108
- Log.d("AudioRecorderModule", "Stopping recording")
109
- stopRecording(promise)
110
- }
111
- }
112
-
113
- // Method to write WAV file header
114
- private fun writeWavHeader(out: FileOutputStream) {
115
- val header = ByteArray(44)
116
- val byteRate = sampleRateInHz * channels * bitDepth / 8
117
- val blockAlign = channels * bitDepth / 8
118
-
119
- // RIFF/WAVE header
120
- "RIFF".toByteArray().copyInto(header, 0)
121
- header[4] = 0 // Size will be updated later
122
- "WAVE".toByteArray().copyInto(header, 8)
123
- "fmt ".toByteArray().copyInto(header, 12)
124
10
 
125
- // 16 for PCM
126
- header[16] = 16
127
- header[20] = 1 // Audio format 1 for PCM (not compressed)
128
- header[22] = channels.toByte()
129
- header[24] = (sampleRateInHz and 0xff).toByte()
130
- header[25] = (sampleRateInHz shr 8 and 0xff).toByte()
131
- header[26] = (sampleRateInHz shr 16 and 0xff).toByte()
132
- header[27] = (sampleRateInHz shr 24 and 0xff).toByte()
133
- header[28] = (byteRate and 0xff).toByte()
134
- header[29] = (byteRate shr 8 and 0xff).toByte()
135
- header[30] = (byteRate shr 16 and 0xff).toByte()
136
- header[31] = (byteRate shr 24 and 0xff).toByte()
137
- header[32] = blockAlign.toByte()
138
- header[34] = bitDepth.toByte()
139
- "data".toByteArray().copyInto(header, 36)
11
+ class ExpoAudioStreamModule() : Module(), EventSender {
12
+ private lateinit var audioRecorderManager: AudioRecorderManager
140
13
 
141
- out.write(header, 0, 44)
142
- }
14
+ @RequiresApi(Build.VERSION_CODES.R)
15
+ override fun definition() = ModuleDefinition {
16
+ // Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
17
+ // Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
18
+ // The module will be accessible from `requireNativeModule('ExpoAudioStream')` in JavaScript.
19
+ Name("ExpoAudioStream")
143
20
 
144
- private fun configureRecording(params: Map<String, Any?>) {
145
- sampleRateInHz = (params["sampleRate"] as? Int) ?: DEFAULT_SAMPLE_RATE
146
- channelConfig = (params["channelConfig"] as? Int) ?: DEFAULT_CHANNEL_CONFIG
147
- audioFormat = (params["audioFormat"] as? Int) ?: DEFAULT_AUDIO_FORMAT
148
- bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)
149
- channels = if (channelConfig == AudioFormat.CHANNEL_IN_MONO) 1 else 2
150
- bitDepth = if (audioFormat == AudioFormat.ENCODING_PCM_16BIT) 16 else 8
151
- }
21
+ Events(Constants.AUDIO_EVENT_NAME)
152
22
 
153
- private fun listAudioFiles(): List<String> {
154
- val filesDir = appContext.reactContext?.filesDir
155
- // Filter to include only .wav files
156
- val files = filesDir?.listFiles { file ->
157
- file.isFile && file.name.endsWith(".wav")
158
- }?.map { it.absolutePath } ?: listOf() // Use `listOf()` to return an empty list if null
159
- return files
160
- }
23
+ // Initialize AudioRecorderManager
24
+ initializeManager()
161
25
 
162
-
163
- private fun startRecording(options: Map<String, Any?>, promise: Promise) {
164
- if (!checkPermission()) {
165
- promise.reject("PERMISSION_DENIED", "Recording permission has not been granted", null)
166
- return
167
- }
168
-
169
- if (isRecording.get() && !isPaused.get()) {
170
- promise.reject("ALREADY_RECORDING", "Recording is already in progress", null)
171
- return
172
- }
173
-
174
- val intervalOption = options["interval"]
175
- if (intervalOption != null) {
176
- Log.d("AudioRecorderModule", "Setting interval to $intervalOption")
177
- if (intervalOption is Number) {
178
- val intervalValue = intervalOption.toLong()
179
- if (intervalValue < 100) {
180
- promise.reject("INVALID_INTERVAL", "Interval must be at least 100 ms", null)
181
- return
182
- } else {
183
- this.interval = intervalValue
26
+ AsyncFunction("startRecording") { options: Map<String, Any?>, promise: Promise ->
27
+ audioRecorderManager.startRecording(options, promise)
184
28
  }
185
- } else {
186
- promise.reject("INVALID_INTERVAL", "Interval must be a number", null)
187
- return
188
- }
189
- }
190
-
191
- // Log for new recording or resuming
192
- if (!isPaused.get()) {
193
- streamUuid = java.util.UUID.randomUUID().toString()
194
- audioFile = File(appContext.reactContext?.filesDir, "audio_${streamUuid}.wav")
195
- Log.i("AudioRecorderModule", "Starting new recording $streamUuid with sample rate: $sampleRateInHz, channel config: $channelConfig, audio format: $audioFormat, buffer size: $bufferSizeInBytes, interval: $interval")
196
-
197
- } else {
198
- Log.i("AudioRecorderModule", "Resuming recording")
199
- }
200
-
201
- // Initialize the recorder if it's a new recording
202
- if (!isPaused.get() && !initializeRecorder()) {
203
- promise.reject("INITIALIZATION_FAILED", "AudioRecord initialization failed", null)
204
- return
205
- }
206
-
207
- try {
208
- FileOutputStream(audioFile, true).use { fos ->
209
- writeWavHeader(fos)
210
- }
211
- } catch (e: IOException) {
212
- promise.reject("FILE_CREATION_FAILED", "Failed to create audio file with WAV header", null)
213
- return
214
- }
215
-
216
- audioRecord?.startRecording()
217
- isPaused.set(false)
218
- isRecording.set(true)
219
-
220
-
221
- if (!isPaused.get()) {
222
- recordingStartTime = System.currentTimeMillis() // Only reset start time if it's not a resume
223
- }
224
-
225
- recordingThread = Thread { recordingProcess() }.apply { start() }
226
- promise.resolve(audioFile?.toURI().toString())
227
- }
228
-
229
- private fun stopRecording(promise: Promise) {
230
- if (!isRecording.get()) {
231
- promise.reject("NOT_RECORDING", "Recording is not active", null)
232
- return
233
- }
234
-
235
- try {
236
- audioRecord?.stop()
237
- audioRecord?.release()
238
29
 
239
- val fileSize = audioFile?.length() ?: 0
240
- val dataFileSize = fileSize - 44 // Subtract header size
241
- val byteRate = sampleRateInHz * channels * (bitDepth / 8)
242
-
243
- // Calculate duration based on the data size and byte rate
244
- val duration = if (byteRate > 0) (dataFileSize * 1000 / byteRate) else 0
245
-
246
- // Create result bundle
247
- val result = bundleOf(
248
- "fileUri" to audioFile?.toURI().toString(),
249
- "duration" to duration,
250
- "channels" to channels,
251
- "bitDepth" to bitDepth,
252
- "sampleRate" to sampleRateInHz,
253
- "size" to fileSize,
254
- "mimeType" to mimeType
255
- )
256
- promise.resolve(result)
257
-
258
- // Reset the timing variables
259
- isRecording.set(false)
260
- isPaused.set(false)
261
- totalRecordedTime = 0
262
- pausedDuration = 0
263
- } catch (e: Exception) {
264
- promise.reject("STOP_FAILED", "Failed to stop recording", e)
265
- } finally {
266
- audioRecord = null
267
- }
268
- }
269
-
270
- private fun recordingProcess() {
271
- FileOutputStream(audioFile, true).use { fos ->
272
- // Buffer to accumulate data
273
- val accumulatedAudioData = ByteArrayOutputStream()
274
-
275
- // Write audio data directly to the file
276
- val audioData = ByteArray(bufferSizeInBytes)
277
- while (isRecording.get()) {
278
- if (!isPaused.get()) {
279
- val bytesRead = audioRecord?.read(audioData, 0, bufferSizeInBytes) ?: -1
280
- if (bytesRead < 0) {
281
- Log.e("AudioRecorderModule", "Read error: $bytesRead")
282
- break
283
- }
284
- if (bytesRead > 0) {
285
- fos.write(audioData, 0, bytesRead)
286
- totalDataSize += bytesRead
287
- accumulatedAudioData.write(audioData, 0, bytesRead)
288
-
289
- // Emit audio data at defined intervals
290
- if (SystemClock.elapsedRealtime() - lastEmitTime >= interval) {
291
- emitAudioData(accumulatedAudioData.toByteArray(), accumulatedAudioData.size())
292
- lastEmitTime = SystemClock.elapsedRealtime() // Reset the timer
293
- accumulatedAudioData.reset() // Clear the accumulator
294
- }
295
- }
30
+ Function("clearAudioFiles") {
31
+ audioRecorderManager.clearAudioStorage()
296
32
  }
297
- }
298
- }
299
- updateWavHeader() // Update the header with the correct file size after recording stops
300
- }
301
33
 
302
- private fun updateWavHeader() {
303
- try {
304
- RandomAccessFile(audioFile, "rw").use { raf ->
305
- val fileSize = raf.length()
306
- val dataSize = fileSize - 44 // Subtract the header size
307
- raf.seek(4) // Skip 'RIFF' label
308
-
309
- // Write correct file size, excluding the first 8 bytes of the RIFF header
310
- raf.writeInt(Integer.reverseBytes((dataSize + 36).toInt()))
311
-
312
- raf.seek(40) // Go to the data size position
313
- raf.writeInt(Integer.reverseBytes(dataSize.toInt())) // Write the size of the data segment
314
- }
315
- } catch (e: IOException) {
316
- Log.e("AudioRecorderModule", "Could not update WAV header", e)
317
- }
318
- }
319
-
320
- private fun clearAudioStorage() {
321
- // Clear all files in the app's internal storage
322
- val filesDir = appContext.reactContext?.filesDir
323
- filesDir?.listFiles()?.forEach {
324
- Log.d("AudioRecorderModule", "Deleting file: ${it.absolutePath}")
325
- it.delete()
326
- }
327
- }
328
-
329
- private fun emitAudioData(audioData: ByteArray, length: Int) {
330
- // Since audioData now contains the actual bytes read, you do not need to read from audioDataBuffer.
331
- // Encode the part of the buffer that contains new audio data.
332
- val encodedBuffer = encodeAudioData(audioData)
333
- val fileSize = audioFile?.length() ?: 0 // Update file size information
334
- val from = lastEmittedSize
335
- val deltaSize = fileSize - lastEmittedSize
336
- lastEmittedSize = fileSize // Update last emitted size
337
-
338
- // Calculate position in milliseconds
339
- val positionInMs = (from * 1000) / (sampleRateInHz * channels * (bitDepth / 8))
340
-
341
- mainHandler.post {
342
- try {
343
- this@ExpoAudioStreamModule.sendEvent(AUDIO_EVENT_NAME, bundleOf(
344
- "fileUri" to audioFile?.toURI().toString(),
345
- "lastEmittedSize" to from,
346
- "encoded" to encodedBuffer,
347
- "deltaSize" to length,
348
- "position" to positionInMs,
349
- "mimeType" to mimeType,
350
- "totalSize" to fileSize,
351
- "streamUuid" to streamUuid
352
- ))
353
- } catch (e: Exception) {
354
- Log.e("AudioRecorderModule", "Failed to send event", e)
355
- }
356
- }
357
- // audioDataBuffer.reset() is no longer needed here as we do not use the buffer to store ongoing data
358
- }
34
+ Function("status") {
35
+ return@Function audioRecorderManager.getStatus()
36
+ }
359
37
 
360
- private fun encodeAudioData(rawData: ByteArray): String {
361
- return Base64.encodeToString(rawData, Base64.NO_WRAP)
362
- }
38
+ AsyncFunction("listAudioFiles") { promise: Promise ->
39
+ audioRecorderManager.listAudioFiles(promise)
40
+ }
363
41
 
364
- private fun saveAudioToFile(rawData: ByteArray): Boolean {
365
- return try {
366
- // Open a FileOutputStream in append mode.
367
- FileOutputStream(audioFile, true).use { output ->
368
- // Write rawData to the file.
369
- output.write(rawData)
370
- }
371
- true
372
- } catch (e: IOException) {
373
- // Handle exceptions here
374
- Log.e("AudioRecorderModule", "Could not write to file: ${audioFile?.absolutePath}", e)
375
- false
376
- }
377
- }
42
+ AsyncFunction("pauseRecording") { promise: Promise ->
43
+ audioRecorderManager.pauseRecording(promise)
44
+ }
378
45
 
379
- private fun checkPermission(): Boolean {
380
- val reactContext = appContext.reactContext ?: return false // If reactContext is null, permissions cannot be checked
381
- return ContextCompat.checkSelfPermission(reactContext, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED
382
- }
46
+ AsyncFunction("resumeRecording") { promise: Promise ->
47
+ audioRecorderManager.resumeRecording(promise)
48
+ }
383
49
 
384
- private fun pauseRecording(promise: Promise) {
385
- if (isRecording.get() && !isPaused.get()) {
386
- audioRecord?.stop()
387
- lastPauseTime = System.currentTimeMillis() // Record the time when the recording was paused
388
- isPaused.set(true)
389
- promise.resolve("Recording paused")
390
- } else {
391
- promise.reject("NOT_RECORDING_OR_ALREADY_PAUSED", "Recording is either not active or already paused", null)
50
+ AsyncFunction("stopRecording") { promise: Promise ->
51
+ audioRecorderManager.stopRecording(promise)
52
+ }
392
53
  }
393
- }
394
54
 
395
- @SuppressLint("MissingPermission")
396
- private fun initializeRecorder(): Boolean {
397
- Log.d("AudioRecorderModule", "Initializing recorder")
398
- bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)
399
- Log.d("AudioRecorderModule", "Buffer size: $bufferSizeInBytes")
400
-
401
- if (bufferSizeInBytes == AudioRecord.ERROR_BAD_VALUE) {
402
- Log.e("AudioRecorderModule", "Invalid buffer size")
403
- return false
55
+ private fun initializeManager() {
56
+ val androidContext =
57
+ appContext.reactContext ?: throw IllegalStateException("Android context not available")
58
+ val permissionUtils = PermissionUtils(androidContext)
59
+ val audioEncoder = AudioDataEncoder()
60
+ audioRecorderManager =
61
+ AudioRecorderManager(androidContext.filesDir, permissionUtils, audioEncoder, this)
404
62
  }
405
63
 
406
- val recorder = AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes)
407
- if (recorder.state != AudioRecord.STATE_INITIALIZED) {
408
- Log.e("AudioRecorderModule", "AudioRecord initialization failed")
409
- recorder.release() // Clean up resources if initialization fails
410
- return false
64
+ override fun sendExpoEvent(eventName: String, params: Bundle) {
65
+ this@ExpoAudioStreamModule.sendEvent(Constants.AUDIO_EVENT_NAME, params)
411
66
  }
412
67
 
413
- this.audioRecord = recorder // Properly assign the recorder to the class member
414
- return true
415
- }
416
-
417
68
  }
@@ -0,0 +1,16 @@
1
+ package net.siteed.audiostream
2
+
3
+ import android.content.Context
4
+ import android.content.pm.PackageManager
5
+ import androidx.core.content.ContextCompat
6
+
7
+ class PermissionUtils(private val context: Context) {
8
+
9
+ /**
10
+ * Checks if the recording permission has been granted.
11
+ * @return Boolean indicating whether the RECORD_AUDIO permission is granted.
12
+ */
13
+ fun checkRecordingPermission(): Boolean {
14
+ return ContextCompat.checkSelfPermission(context, android.Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED
15
+ }
16
+ }
@@ -18,6 +18,13 @@ export interface AudioStreamResult {
18
18
  bitDepth?: number;
19
19
  sampleRate?: number;
20
20
  }
21
+ export interface StartAudioStreamResult {
22
+ fileUri: string;
23
+ mimeType: string;
24
+ channels?: number;
25
+ bitDepth?: number;
26
+ sampleRate?: number;
27
+ }
21
28
  export interface AudioStreamStatus {
22
29
  isRecording: boolean;
23
30
  isPaused: boolean;
@@ -26,7 +33,11 @@ export interface AudioStreamStatus {
26
33
  interval: number;
27
34
  mimeType: string;
28
35
  }
29
- export interface RecordingOptions {
36
+ export type EncodingType = "pcm_16bit" | "pcm_8bit";
37
+ export interface RecordingConfig {
38
+ sampleRate?: 16000 | 44100 | 48000;
39
+ channels?: 1 | 2;
40
+ encoding?: EncodingType;
30
41
  interval?: number;
31
42
  }
32
43
  //# sourceMappingURL=ExpoAudioStream.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAudioStream.types.d.ts","sourceRoot":"","sources":["../src/ExpoAudioStream.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAK/B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
1
+ {"version":3,"file":"ExpoAudioStream.types.d.ts","sourceRoot":"","sources":["../src/ExpoAudioStream.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,UAAU,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACjB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAudioStream.types.js","sourceRoot":"","sources":["../src/ExpoAudioStream.types.ts"],"names":[],"mappings":"","sourcesContent":["export interface AudioEventPayload {\n encoded?: string;\n buffer?: Blob;\n fileUri: string;\n lastEmittedSize: number;\n position: number;\n deltaSize: number;\n totalSize: number;\n mimeType: string;\n streamUuid: string;\n}\n\nexport interface AudioStreamResult {\n fileUri: string;\n duration: number;\n size: number;\n mimeType: string;\n channels?: number;\n bitDepth?: number;\n sampleRate?: number;\n}\n\nexport interface AudioStreamStatus {\n isRecording: boolean;\n isPaused: boolean;\n duration: number;\n size: number;\n interval: number;\n mimeType: string;\n}\n\nexport interface RecordingOptions {\n // TODO align Android and IOS options\n // sampleRate?: number;\n // channelConfig?: number; // numberOfChannel\n // audioFormat?: number; // bitDepth (ENCODING_PCM_16BIT --> 2)\n interval?: number;\n}\n"]}
1
+ {"version":3,"file":"ExpoAudioStream.types.js","sourceRoot":"","sources":["../src/ExpoAudioStream.types.ts"],"names":[],"mappings":"","sourcesContent":["export interface AudioEventPayload {\n encoded?: string;\n buffer?: Blob;\n fileUri: string;\n lastEmittedSize: number;\n position: number;\n deltaSize: number;\n totalSize: number;\n mimeType: string;\n streamUuid: string;\n}\n\nexport interface AudioStreamResult {\n fileUri: string;\n duration: number;\n size: number;\n mimeType: string;\n channels?: number;\n bitDepth?: number;\n sampleRate?: number;\n}\n\nexport interface StartAudioStreamResult {\n fileUri: string;\n mimeType: string;\n channels?: number;\n bitDepth?: number;\n sampleRate?: number;\n}\n\nexport interface AudioStreamStatus {\n isRecording: boolean;\n isPaused: boolean;\n duration: number;\n size: number;\n interval: number;\n mimeType: string;\n}\n\nexport type EncodingType = \"pcm_16bit\" | \"pcm_8bit\";\n\nexport interface RecordingConfig {\n sampleRate?: 16000 | 44100 | 48000;\n channels?: 1 | 2; // 1 or 2 MONO or STEREO\n encoding?: EncodingType;\n interval?: number;\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { EventEmitter } from "expo-modules-core";
2
- import { AudioStreamResult, RecordingOptions } from "./ExpoAudioStream.types";
2
+ import { AudioStreamResult, RecordingConfig, StartAudioStreamResult } from "./ExpoAudioStream.types";
3
3
  declare class ExpoAudioStreamWeb extends EventEmitter {
4
4
  mediaRecorder: MediaRecorder | null;
5
5
  audioChunks: Blob[];
@@ -15,7 +15,7 @@ declare class ExpoAudioStreamWeb extends EventEmitter {
15
15
  streamUuid: string | null;
16
16
  constructor();
17
17
  getMediaStream(): Promise<MediaStream>;
18
- startRecording(options?: RecordingOptions): Promise<string>;
18
+ startRecording(options?: RecordingConfig): Promise<StartAudioStreamResult>;
19
19
  setupRecordingListeners(): void;
20
20
  emitAudioEvent({ data, position }: {
21
21
  data: Blob;
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAudioStreamModule.web.d.ts","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.web.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAEL,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,yBAAyB,CAAC;AAGjC,cAAM,kBAAmB,SAAQ,YAAY;IAC3C,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IACpC,WAAW,EAAE,IAAI,EAAE,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;;IA4BpB,cAAc;IAUd,cAAc,CAAC,OAAO,GAAE,gBAAqB;IAoBnD,uBAAuB;IA4BvB,cAAc,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAiBnE,YAAY;IAUN,aAAa,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAelD,cAAc;IAcpB,MAAM;;;;;;;IAUN,cAAc;IAId,eAAe;CAGhB;;AAED,wBAAwC"}
1
+ {"version":3,"file":"ExpoAudioStreamModule.web.d.ts","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.web.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAEL,iBAAiB,EACjB,eAAe,EACf,sBAAsB,EACvB,MAAM,yBAAyB,CAAC;AAGjC,cAAM,kBAAmB,SAAQ,YAAY;IAC3C,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IACpC,WAAW,EAAE,IAAI,EAAE,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;;IA4BpB,cAAc;IAUd,cAAc,CAAC,OAAO,GAAE,eAAoB;IAwBlD,uBAAuB;IA4BvB,cAAc,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAiBnE,YAAY;IAUN,aAAa,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAelD,cAAc;IAcpB,MAAM;;;;;;;IAUN,cAAc;IAId,eAAe;CAGhB;;AAED,wBAAwC"}
@@ -63,7 +63,11 @@ class ExpoAudioStreamWeb extends EventEmitter {
63
63
  this.lastEmittedTime = 0;
64
64
  this.streamUuid = this.generateUUID(); // Generate a UUID for the new recording session
65
65
  const fileUri = `${this.streamUuid}.webm`;
66
- return fileUri;
66
+ const streamConfig = {
67
+ fileUri,
68
+ mimeType: "audio/webm",
69
+ };
70
+ return streamConfig;
67
71
  }
68
72
  // Setup listeners for the MediaRecorder
69
73
  setupRecordingListeners() {
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAudioStreamModule.web.js","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAQjD,MAAM,GAAG,GAAG,KAAK,CAAC,qCAAqC,CAAC,CAAC;AACzD,MAAM,kBAAmB,SAAQ,YAAY;IAC3C,aAAa,CAAuB;IACpC,WAAW,CAAS;IACpB,WAAW,CAAU;IACrB,QAAQ,CAAU;IAClB,kBAAkB,CAAS;IAC3B,UAAU,CAAS;IACnB,iBAAiB,CAAS;IAC1B,WAAW,CAAS;IACpB,eAAe,CAAS;IACxB,eAAe,CAAS;IACxB,eAAe,CAAS;IACxB,UAAU,CAAgB;IAE1B;QACE,MAAM,gBAAgB,GAAG;YACvB,WAAW,EAAE,CAAC,SAAiB,EAAE,EAAE;gBACjC,kBAAkB;YACpB,CAAC;YACD,eAAe,EAAE,CAAC,KAAa,EAAE,EAAE;gBACjC,kBAAkB;YACpB,CAAC;SACF,CAAC;QACF,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,kDAAkD;QAE3E,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,yBAAyB;QACtD,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,2CAA2C;IACrE,CAAC;IAED,sCAAsC;IACtC,KAAK,CAAC,cAAc;QAClB,IAAI,CAAC;YACH,OAAO,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YACpD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,+BAA+B;IAC/B,KAAK,CAAC,cAAc,CAAC,UAA4B,EAAE;QACjD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC3C,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;QAC/C,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAC/B,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC;QACnE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACrC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,gDAAgD;QACvF,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,UAAU,OAAO,CAAC;QAC1C,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,wCAAwC;IACxC,uBAAuB;QACrB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,CAAC,aAAa,CAAC,eAAe,GAAG,CAAC,KAAK,EAAE,EAAE;YAC7C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,mCAAmC;YAExE,IAAI,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;YAC1E,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC,SAAS,CAAC;YACvC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC;QAC1C,CAAC,CAAC;QAEF,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,GAAG,EAAE;YAC/B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;YACzB,GAAG,CAAC,mBAAmB,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7C,CAAC,CAAC;QAEF,IAAI,CAAC,aAAa,CAAC,OAAO,GAAG,GAAG,EAAE;YAChC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,CAAC,CAAC;QAEF,IAAI,CAAC,aAAa,CAAC,QAAQ,GAAG,GAAG,EAAE;YACjC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;YACtB,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,mCAAmC;QAC9F,CAAC,CAAC;IACJ,CAAC;IAED,cAAc,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAoC;QACjE,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,UAAU,OAAO,CAAC;QAC1C,MAAM,iBAAiB,GAAsB;YAC3C,OAAO;YACP,QAAQ,EAAE,YAAY;YACtB,eAAe,EAAE,IAAI,CAAC,eAAe,EAAE,iEAAiE;YACxG,SAAS,EAAE,IAAI,CAAC,IAAI;YACpB,QAAQ;YACR,SAAS,EAAE,IAAI,CAAC,WAAW;YAC3B,MAAM,EAAE,IAAI;YACZ,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,oDAAoD;SACxF,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;IAC5C,CAAC;IAED,mCAAmC;IACnC,YAAY;QACV,qEAAqE;QACrE,OAAO,qBAAqB,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;YACjD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,EAChC,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;YACtC,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,iBAAiB;IACjB,KAAK,CAAC,aAAa;QACjB,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB,CAAC;QAC9D,MAAM,MAAM,GAAsB;YAChC,OAAO,EAAE,GAAG,IAAI,CAAC,UAAU,OAAO;YAClC,QAAQ,EAAE,IAAI,CAAC,iBAAiB;YAChC,IAAI,EAAE,IAAI,CAAC,WAAW;YACtB,QAAQ,EAAE,YAAY;SACvB,CAAC;QAEF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,kBAAkB;IAClB,KAAK,CAAC,cAAc;QAClB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC9C,CAAC;QAED,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACvC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;YAC3B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,qBAAqB;IACrB,MAAM;QACJ,OAAO;YACL,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB;YAC9C,IAAI,EAAE,IAAI,CAAC,WAAW;YACtB,QAAQ,EAAE,IAAI,CAAC,eAAe;SAC/B,CAAC;IACJ,CAAC;IAED,cAAc;QACZ,wBAAwB;IAC1B,CAAC;IAED,eAAe;QACb,wBAAwB;IAC1B,CAAC;CACF;AAED,eAAe,IAAI,kBAAkB,EAAE,CAAC","sourcesContent":["import debug from \"debug\";\nimport { EventEmitter } from \"expo-modules-core\";\n\nimport {\n AudioEventPayload,\n AudioStreamResult,\n RecordingOptions,\n} from \"./ExpoAudioStream.types\";\n\nconst log = debug(\"expo-audio-stream:useAudioRecording\");\nclass ExpoAudioStreamWeb extends EventEmitter {\n mediaRecorder: MediaRecorder | null;\n audioChunks: Blob[];\n isRecording: boolean;\n isPaused: boolean;\n recordingStartTime: number;\n pausedTime: number;\n currentDurationMs: number;\n currentSize: number;\n currentInterval: number;\n lastEmittedSize: number;\n lastEmittedTime: number;\n streamUuid: string | null;\n\n constructor() {\n const mockNativeModule = {\n addListener: (eventName: string) => {\n // Not used on web\n },\n removeListeners: (count: number) => {\n // Not used on web\n },\n };\n super(mockNativeModule); // Pass the mock native module to the parent class\n\n this.mediaRecorder = null;\n this.audioChunks = [];\n this.isRecording = false;\n this.isPaused = false;\n this.recordingStartTime = 0;\n this.pausedTime = 0;\n this.currentDurationMs = 0;\n this.currentSize = 0;\n this.currentInterval = 1000; // Default interval in ms\n this.lastEmittedSize = 0;\n this.lastEmittedTime = 0;\n this.streamUuid = null; // Initialize UUID on first recording start\n }\n\n // Utility to handle user media stream\n async getMediaStream() {\n try {\n return await navigator.mediaDevices.getUserMedia({ audio: true });\n } catch (error) {\n console.error(\"Failed to get media stream:\", error);\n throw error;\n }\n }\n\n // Start recording with options\n async startRecording(options: RecordingOptions = {}) {\n if (this.isRecording) {\n throw new Error(\"Recording is already in progress\");\n }\n\n const stream = await this.getMediaStream();\n this.mediaRecorder = new MediaRecorder(stream);\n this.setupRecordingListeners();\n this.mediaRecorder.start(options.interval || this.currentInterval);\n this.isRecording = true;\n this.recordingStartTime = Date.now();\n this.pausedTime = 0;\n this.lastEmittedSize = 0;\n this.lastEmittedTime = 0;\n this.streamUuid = this.generateUUID(); // Generate a UUID for the new recording session\n const fileUri = `${this.streamUuid}.webm`;\n return fileUri;\n }\n\n // Setup listeners for the MediaRecorder\n setupRecordingListeners() {\n if (!this.mediaRecorder) {\n throw new Error(\"No active media recorder\");\n }\n this.mediaRecorder.ondataavailable = (event) => {\n this.audioChunks.push(event.data);\n this.currentSize += event.data.size; // Update the size of the recording\n\n this.emitAudioEvent({ data: event.data, position: this.lastEmittedTime });\n this.lastEmittedTime = event.timeStamp;\n this.lastEmittedSize = this.currentSize;\n };\n\n this.mediaRecorder.onstop = () => {\n this.isRecording = false;\n log(\"Recording stopped\", this.audioChunks);\n };\n\n this.mediaRecorder.onpause = () => {\n this.isPaused = true;\n };\n\n this.mediaRecorder.onresume = () => {\n this.isPaused = false;\n this.recordingStartTime += Date.now() - this.pausedTime; // Adjust start time after resuming\n };\n }\n\n emitAudioEvent({ data, position }: { data: Blob; position: number }) {\n const fileUri = `${this.streamUuid}.webm`;\n const audioEventPayload: AudioEventPayload = {\n fileUri,\n mimeType: \"audio/webm\",\n lastEmittedSize: this.lastEmittedSize, // Since this might be continuously streaming, adjust accordingly\n deltaSize: data.size,\n position,\n totalSize: this.currentSize,\n buffer: data,\n streamUuid: this.streamUuid ?? \"\", // Generate or manage UUID for stream identification\n };\n\n this.emit(\"AudioData\", audioEventPayload);\n }\n\n // Helper method to generate a UUID\n generateUUID() {\n // Implementation of UUID generation (use a library or custom method)\n return \"xxxx-xxxx-xxxx-xxxx\".replace(/[x]/g, (c) => {\n const r = (Math.random() * 16) | 0,\n v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n\n // Stop recording\n async stopRecording(): Promise<AudioStreamResult | null> {\n this.mediaRecorder?.stop();\n this.isRecording = false;\n this.currentDurationMs = Date.now() - this.recordingStartTime;\n const result: AudioStreamResult = {\n fileUri: `${this.streamUuid}.webm`,\n duration: this.currentDurationMs,\n size: this.currentSize,\n mimeType: \"audio/webm\",\n };\n\n return result;\n }\n\n // Pause recording\n async pauseRecording() {\n if (!this.mediaRecorder) {\n throw new Error(\"No active media recorder\");\n }\n\n if (this.isRecording && !this.isPaused) {\n this.mediaRecorder.pause();\n this.pausedTime = Date.now();\n } else {\n throw new Error(\"Recording is not active or already paused\");\n }\n }\n\n // Get current status\n status() {\n return {\n isRecording: this.isRecording,\n isPaused: this.isPaused,\n duration: Date.now() - this.recordingStartTime,\n size: this.currentSize,\n interval: this.currentInterval,\n };\n }\n\n listAudioFiles() {\n // Not applicable on web\n }\n\n clearAudioFiles() {\n // Not applicable on web\n }\n}\n\nexport default new ExpoAudioStreamWeb();\n"]}
1
+ {"version":3,"file":"ExpoAudioStreamModule.web.js","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AASjD,MAAM,GAAG,GAAG,KAAK,CAAC,qCAAqC,CAAC,CAAC;AACzD,MAAM,kBAAmB,SAAQ,YAAY;IAC3C,aAAa,CAAuB;IACpC,WAAW,CAAS;IACpB,WAAW,CAAU;IACrB,QAAQ,CAAU;IAClB,kBAAkB,CAAS;IAC3B,UAAU,CAAS;IACnB,iBAAiB,CAAS;IAC1B,WAAW,CAAS;IACpB,eAAe,CAAS;IACxB,eAAe,CAAS;IACxB,eAAe,CAAS;IACxB,UAAU,CAAgB;IAE1B;QACE,MAAM,gBAAgB,GAAG;YACvB,WAAW,EAAE,CAAC,SAAiB,EAAE,EAAE;gBACjC,kBAAkB;YACpB,CAAC;YACD,eAAe,EAAE,CAAC,KAAa,EAAE,EAAE;gBACjC,kBAAkB;YACpB,CAAC;SACF,CAAC;QACF,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,kDAAkD;QAE3E,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,yBAAyB;QACtD,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,2CAA2C;IACrE,CAAC;IAED,sCAAsC;IACtC,KAAK,CAAC,cAAc;QAClB,IAAI,CAAC;YACH,OAAO,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YACpD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,+BAA+B;IAC/B,KAAK,CAAC,cAAc,CAAC,UAA2B,EAAE;QAChD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC3C,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;QAC/C,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAC/B,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC;QACnE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACrC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,gDAAgD;QACvF,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,UAAU,OAAO,CAAC;QAC1C,MAAM,YAAY,GAA2B;YAC3C,OAAO;YACP,QAAQ,EAAE,YAAY;SACvB,CAAC;QACF,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,wCAAwC;IACxC,uBAAuB;QACrB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,CAAC,aAAa,CAAC,eAAe,GAAG,CAAC,KAAK,EAAE,EAAE;YAC7C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,mCAAmC;YAExE,IAAI,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;YAC1E,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC,SAAS,CAAC;YACvC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC;QAC1C,CAAC,CAAC;QAEF,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,GAAG,EAAE;YAC/B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;YACzB,GAAG,CAAC,mBAAmB,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7C,CAAC,CAAC;QAEF,IAAI,CAAC,aAAa,CAAC,OAAO,GAAG,GAAG,EAAE;YAChC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,CAAC,CAAC;QAEF,IAAI,CAAC,aAAa,CAAC,QAAQ,GAAG,GAAG,EAAE;YACjC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;YACtB,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,mCAAmC;QAC9F,CAAC,CAAC;IACJ,CAAC;IAED,cAAc,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAoC;QACjE,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,UAAU,OAAO,CAAC;QAC1C,MAAM,iBAAiB,GAAsB;YAC3C,OAAO;YACP,QAAQ,EAAE,YAAY;YACtB,eAAe,EAAE,IAAI,CAAC,eAAe,EAAE,iEAAiE;YACxG,SAAS,EAAE,IAAI,CAAC,IAAI;YACpB,QAAQ;YACR,SAAS,EAAE,IAAI,CAAC,WAAW;YAC3B,MAAM,EAAE,IAAI;YACZ,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,oDAAoD;SACxF,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;IAC5C,CAAC;IAED,mCAAmC;IACnC,YAAY;QACV,qEAAqE;QACrE,OAAO,qBAAqB,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;YACjD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,EAChC,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;YACtC,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,iBAAiB;IACjB,KAAK,CAAC,aAAa;QACjB,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB,CAAC;QAC9D,MAAM,MAAM,GAAsB;YAChC,OAAO,EAAE,GAAG,IAAI,CAAC,UAAU,OAAO;YAClC,QAAQ,EAAE,IAAI,CAAC,iBAAiB;YAChC,IAAI,EAAE,IAAI,CAAC,WAAW;YACtB,QAAQ,EAAE,YAAY;SACvB,CAAC;QAEF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,kBAAkB;IAClB,KAAK,CAAC,cAAc;QAClB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC9C,CAAC;QAED,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACvC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;YAC3B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,qBAAqB;IACrB,MAAM;QACJ,OAAO;YACL,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB;YAC9C,IAAI,EAAE,IAAI,CAAC,WAAW;YACtB,QAAQ,EAAE,IAAI,CAAC,eAAe;SAC/B,CAAC;IACJ,CAAC;IAED,cAAc;QACZ,wBAAwB;IAC1B,CAAC;IAED,eAAe;QACb,wBAAwB;IAC1B,CAAC;CACF;AAED,eAAe,IAAI,kBAAkB,EAAE,CAAC","sourcesContent":["import debug from \"debug\";\nimport { EventEmitter } from \"expo-modules-core\";\n\nimport {\n AudioEventPayload,\n AudioStreamResult,\n RecordingConfig,\n StartAudioStreamResult,\n} from \"./ExpoAudioStream.types\";\n\nconst log = debug(\"expo-audio-stream:useAudioRecording\");\nclass ExpoAudioStreamWeb extends EventEmitter {\n mediaRecorder: MediaRecorder | null;\n audioChunks: Blob[];\n isRecording: boolean;\n isPaused: boolean;\n recordingStartTime: number;\n pausedTime: number;\n currentDurationMs: number;\n currentSize: number;\n currentInterval: number;\n lastEmittedSize: number;\n lastEmittedTime: number;\n streamUuid: string | null;\n\n constructor() {\n const mockNativeModule = {\n addListener: (eventName: string) => {\n // Not used on web\n },\n removeListeners: (count: number) => {\n // Not used on web\n },\n };\n super(mockNativeModule); // Pass the mock native module to the parent class\n\n this.mediaRecorder = null;\n this.audioChunks = [];\n this.isRecording = false;\n this.isPaused = false;\n this.recordingStartTime = 0;\n this.pausedTime = 0;\n this.currentDurationMs = 0;\n this.currentSize = 0;\n this.currentInterval = 1000; // Default interval in ms\n this.lastEmittedSize = 0;\n this.lastEmittedTime = 0;\n this.streamUuid = null; // Initialize UUID on first recording start\n }\n\n // Utility to handle user media stream\n async getMediaStream() {\n try {\n return await navigator.mediaDevices.getUserMedia({ audio: true });\n } catch (error) {\n console.error(\"Failed to get media stream:\", error);\n throw error;\n }\n }\n\n // Start recording with options\n async startRecording(options: RecordingConfig = {}) {\n if (this.isRecording) {\n throw new Error(\"Recording is already in progress\");\n }\n\n const stream = await this.getMediaStream();\n this.mediaRecorder = new MediaRecorder(stream);\n this.setupRecordingListeners();\n this.mediaRecorder.start(options.interval || this.currentInterval);\n this.isRecording = true;\n this.recordingStartTime = Date.now();\n this.pausedTime = 0;\n this.lastEmittedSize = 0;\n this.lastEmittedTime = 0;\n this.streamUuid = this.generateUUID(); // Generate a UUID for the new recording session\n const fileUri = `${this.streamUuid}.webm`;\n const streamConfig: StartAudioStreamResult = {\n fileUri,\n mimeType: \"audio/webm\",\n };\n return streamConfig;\n }\n\n // Setup listeners for the MediaRecorder\n setupRecordingListeners() {\n if (!this.mediaRecorder) {\n throw new Error(\"No active media recorder\");\n }\n this.mediaRecorder.ondataavailable = (event) => {\n this.audioChunks.push(event.data);\n this.currentSize += event.data.size; // Update the size of the recording\n\n this.emitAudioEvent({ data: event.data, position: this.lastEmittedTime });\n this.lastEmittedTime = event.timeStamp;\n this.lastEmittedSize = this.currentSize;\n };\n\n this.mediaRecorder.onstop = () => {\n this.isRecording = false;\n log(\"Recording stopped\", this.audioChunks);\n };\n\n this.mediaRecorder.onpause = () => {\n this.isPaused = true;\n };\n\n this.mediaRecorder.onresume = () => {\n this.isPaused = false;\n this.recordingStartTime += Date.now() - this.pausedTime; // Adjust start time after resuming\n };\n }\n\n emitAudioEvent({ data, position }: { data: Blob; position: number }) {\n const fileUri = `${this.streamUuid}.webm`;\n const audioEventPayload: AudioEventPayload = {\n fileUri,\n mimeType: \"audio/webm\",\n lastEmittedSize: this.lastEmittedSize, // Since this might be continuously streaming, adjust accordingly\n deltaSize: data.size,\n position,\n totalSize: this.currentSize,\n buffer: data,\n streamUuid: this.streamUuid ?? \"\", // Generate or manage UUID for stream identification\n };\n\n this.emit(\"AudioData\", audioEventPayload);\n }\n\n // Helper method to generate a UUID\n generateUUID() {\n // Implementation of UUID generation (use a library or custom method)\n return \"xxxx-xxxx-xxxx-xxxx\".replace(/[x]/g, (c) => {\n const r = (Math.random() * 16) | 0,\n v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n\n // Stop recording\n async stopRecording(): Promise<AudioStreamResult | null> {\n this.mediaRecorder?.stop();\n this.isRecording = false;\n this.currentDurationMs = Date.now() - this.recordingStartTime;\n const result: AudioStreamResult = {\n fileUri: `${this.streamUuid}.webm`,\n duration: this.currentDurationMs,\n size: this.currentSize,\n mimeType: \"audio/webm\",\n };\n\n return result;\n }\n\n // Pause recording\n async pauseRecording() {\n if (!this.mediaRecorder) {\n throw new Error(\"No active media recorder\");\n }\n\n if (this.isRecording && !this.isPaused) {\n this.mediaRecorder.pause();\n this.pausedTime = Date.now();\n } else {\n throw new Error(\"Recording is not active or already paused\");\n }\n }\n\n // Get current status\n status() {\n return {\n isRecording: this.isRecording,\n isPaused: this.isPaused,\n duration: Date.now() - this.recordingStartTime,\n size: this.currentSize,\n interval: this.currentInterval,\n };\n }\n\n listAudioFiles() {\n // Not applicable on web\n }\n\n clearAudioFiles() {\n // Not applicable on web\n }\n}\n\nexport default new ExpoAudioStreamWeb();\n"]}
package/build/index.d.ts CHANGED
@@ -3,6 +3,7 @@ import { AudioEventPayload } from "./ExpoAudioStream.types";
3
3
  import { useAudioRecorder, UseAudioRecorderState, AudioDataEvent } from "./useAudioRecording";
4
4
  export declare function listAudioFiles(): Promise<string[]>;
5
5
  export declare function clearAudioFiles(): Promise<void>;
6
+ export declare function test(): void;
6
7
  export declare function addAudioEventListener(listener: (event: AudioEventPayload) => Promise<void>): Subscription;
7
8
  export type { AudioEventPayload, UseAudioRecorderState, AudioDataEvent };
8
9
  export { useAudioRecorder };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACf,MAAM,qBAAqB,CAAC;AAM7B,wBAAgB,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAElD;AAED,wBAAgB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GACpD,YAAY,CAGd;AAED,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,cAAc,EAAE,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACf,MAAM,qBAAqB,CAAC;AAM7B,wBAAgB,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAElD;AAED,wBAAgB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED,wBAAgB,IAAI,IAAI,IAAI,CAE3B;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,GACpD,YAAY,CAGd;AAED,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,cAAc,EAAE,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
package/build/index.js CHANGED
@@ -8,6 +8,9 @@ export function listAudioFiles() {
8
8
  export function clearAudioFiles() {
9
9
  return ExpoAudioStreamModule.clearAudioFiles();
10
10
  }
11
+ export function test() {
12
+ return ExpoAudioStreamModule.test();
13
+ }
11
14
  export function addAudioEventListener(listener) {
12
15
  console.log(`addAudioEventListener`, listener);
13
16
  return emitter.addListener("AudioData", listener);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,kBAAkB,GAEnB,MAAM,mBAAmB,CAAC;AAK3B,OAAO,qBAAqB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACL,gBAAgB,GAGjB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,OAAO,GAAG,IAAI,YAAY,CAC9B,qBAAqB,IAAI,kBAAkB,CAAC,eAAe,CAC5D,CAAC;AAEF,MAAM,UAAU,cAAc;IAC5B,OAAO,qBAAqB,CAAC,cAAc,EAAE,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,qBAAqB,CAAC,eAAe,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,QAAqD;IAErD,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CAAC;IAC/C,OAAO,OAAO,CAAC,WAAW,CAAoB,WAAW,EAAE,QAAQ,CAAC,CAAC;AACvE,CAAC;AAGD,OAAO,EAAE,gBAAgB,EAAE,CAAC","sourcesContent":["import {\n EventEmitter,\n NativeModulesProxy,\n type Subscription,\n} from \"expo-modules-core\";\n\n// Import the native module. On web, it will be resolved to ExpoAudioStream.web.ts\n// and on native platforms to ExpoAudioStream.ts\nimport { AudioEventPayload } from \"./ExpoAudioStream.types\";\nimport ExpoAudioStreamModule from \"./ExpoAudioStreamModule\";\nimport {\n useAudioRecorder,\n UseAudioRecorderState,\n AudioDataEvent,\n} from \"./useAudioRecording\";\n\nconst emitter = new EventEmitter(\n ExpoAudioStreamModule ?? NativeModulesProxy.ExpoAudioStream,\n);\n\nexport function listAudioFiles(): Promise<string[]> {\n return ExpoAudioStreamModule.listAudioFiles();\n}\n\nexport function clearAudioFiles(): Promise<void> {\n return ExpoAudioStreamModule.clearAudioFiles();\n}\n\nexport function addAudioEventListener(\n listener: (event: AudioEventPayload) => Promise<void>,\n): Subscription {\n console.log(`addAudioEventListener`, listener);\n return emitter.addListener<AudioEventPayload>(\"AudioData\", listener);\n}\n\nexport type { AudioEventPayload, UseAudioRecorderState, AudioDataEvent };\nexport { useAudioRecorder };\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,kBAAkB,GAEnB,MAAM,mBAAmB,CAAC;AAK3B,OAAO,qBAAqB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACL,gBAAgB,GAGjB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,OAAO,GAAG,IAAI,YAAY,CAC9B,qBAAqB,IAAI,kBAAkB,CAAC,eAAe,CAC5D,CAAC;AAEF,MAAM,UAAU,cAAc;IAC5B,OAAO,qBAAqB,CAAC,cAAc,EAAE,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,qBAAqB,CAAC,eAAe,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,OAAO,qBAAqB,CAAC,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,QAAqD;IAErD,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CAAC;IAC/C,OAAO,OAAO,CAAC,WAAW,CAAoB,WAAW,EAAE,QAAQ,CAAC,CAAC;AACvE,CAAC;AAGD,OAAO,EAAE,gBAAgB,EAAE,CAAC","sourcesContent":["import {\n EventEmitter,\n NativeModulesProxy,\n type Subscription,\n} from \"expo-modules-core\";\n\n// Import the native module. On web, it will be resolved to ExpoAudioStream.web.ts\n// and on native platforms to ExpoAudioStream.ts\nimport { AudioEventPayload } from \"./ExpoAudioStream.types\";\nimport ExpoAudioStreamModule from \"./ExpoAudioStreamModule\";\nimport {\n useAudioRecorder,\n UseAudioRecorderState,\n AudioDataEvent,\n} from \"./useAudioRecording\";\n\nconst emitter = new EventEmitter(\n ExpoAudioStreamModule ?? NativeModulesProxy.ExpoAudioStream,\n);\n\nexport function listAudioFiles(): Promise<string[]> {\n return ExpoAudioStreamModule.listAudioFiles();\n}\n\nexport function clearAudioFiles(): Promise<void> {\n return ExpoAudioStreamModule.clearAudioFiles();\n}\n\nexport function test(): void {\n return ExpoAudioStreamModule.test();\n}\n\nexport function addAudioEventListener(\n listener: (event: AudioEventPayload) => Promise<void>,\n): Subscription {\n console.log(`addAudioEventListener`, listener);\n return emitter.addListener<AudioEventPayload>(\"AudioData\", listener);\n}\n\nexport type { AudioEventPayload, UseAudioRecorderState, AudioDataEvent };\nexport { useAudioRecorder };\n"]}