@siteed/expo-audio-stream 0.1.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 (52) hide show
  1. package/.eslintrc.js +2 -0
  2. package/README.md +85 -0
  3. package/android/.gradle/8.1.1/checksums/checksums.lock +0 -0
  4. package/android/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock +0 -0
  5. package/android/.gradle/8.1.1/dependencies-accessors/gc.properties +0 -0
  6. package/android/.gradle/8.1.1/fileChanges/last-build.bin +0 -0
  7. package/android/.gradle/8.1.1/fileHashes/fileHashes.lock +0 -0
  8. package/android/.gradle/8.1.1/gc.properties +0 -0
  9. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  10. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  11. package/android/.gradle/vcs-1/gc.properties +0 -0
  12. package/android/build.gradle +92 -0
  13. package/android/src/main/AndroidManifest.xml +4 -0
  14. package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +318 -0
  15. package/app.plugin.js +1 -0
  16. package/build/ExpoAudioStream.types.d.ts +23 -0
  17. package/build/ExpoAudioStream.types.d.ts.map +1 -0
  18. package/build/ExpoAudioStream.types.js +3 -0
  19. package/build/ExpoAudioStream.types.js.map +1 -0
  20. package/build/ExpoAudioStreamModule.d.ts +3 -0
  21. package/build/ExpoAudioStreamModule.d.ts.map +1 -0
  22. package/build/ExpoAudioStreamModule.js +5 -0
  23. package/build/ExpoAudioStreamModule.js.map +1 -0
  24. package/build/ExpoAudioStreamModule.web.d.ts +35 -0
  25. package/build/ExpoAudioStreamModule.web.d.ts.map +1 -0
  26. package/build/ExpoAudioStreamModule.web.js +143 -0
  27. package/build/ExpoAudioStreamModule.web.js.map +1 -0
  28. package/build/index.d.ts +9 -0
  29. package/build/index.d.ts.map +1 -0
  30. package/build/index.js +21 -0
  31. package/build/index.js.map +1 -0
  32. package/build/useAudioRecording.d.ts +15 -0
  33. package/build/useAudioRecording.d.ts.map +1 -0
  34. package/build/useAudioRecording.js +118 -0
  35. package/build/useAudioRecording.js.map +1 -0
  36. package/expo-module.config.json +9 -0
  37. package/ios/AudioStreamManager.swift +168 -0
  38. package/ios/ExpoAudioStream.podspec +27 -0
  39. package/ios/ExpoAudioStreamModule.swift +133 -0
  40. package/package.json +61 -0
  41. package/plugin/build/index.d.ts +5 -0
  42. package/plugin/build/index.js +17 -0
  43. package/plugin/src/index.ts +27 -0
  44. package/plugin/tsconfig.json +9 -0
  45. package/release-it.js +18 -0
  46. package/src/ExpoAudioStream.types.ts +25 -0
  47. package/src/ExpoAudioStreamModule.ts +5 -0
  48. package/src/ExpoAudioStreamModule.web.ts +162 -0
  49. package/src/index.ts +29 -0
  50. package/src/useAudioRecording.ts +141 -0
  51. package/tsconfig.json +9 -0
  52. package/yarn-error.log +72 -0
package/.eslintrc.js ADDED
@@ -0,0 +1,2 @@
1
+ // @generated by expo-module-scripts
2
+ module.exports = require('expo-module-scripts/eslintrc.base.js');
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # expo-audio-stream
2
+
3
+ `@siteed/expo-audio-stream` is a comprehensive library designed to facilitate real-time audio processing and streaming across iOS, Android, and web platforms. This library leverages Expo's robust ecosystem to simplify the implementation of audio recording and streaming functionalities within React Native applications. Key features include audio streaming with configurable buffer intervals and automatic handling of microphone permissions in managed Expo projects.
4
+
5
+ ## Features
6
+
7
+ - Real-time audio streaming across iOS, Android, and web.
8
+ - Configurable intervals for audio buffer receipt.
9
+ - Automated microphone permissions setup in managed Expo projects.
10
+ - Listeners for audio data events with detailed event payloads.
11
+ - Utility functions for recording control and file management.
12
+
13
+
14
+ ## Installation
15
+
16
+ To install `@siteed/expo-audio-stream`, add it to your project using npm or Yarn:
17
+
18
+ ```bash
19
+ npm install @siteed/expo-audio-stream
20
+ # or
21
+ yarn add @siteed/expo-audio-stream
22
+ ```
23
+
24
+ Make sure that you have Expo set up in your project. For details on setting up Expo, refer to the Expo documentation.
25
+
26
+ ### Configuring with app.json
27
+
28
+ To ensure expo-audio-stream works correctly with Expo, you must add it as a plugin in your app.json configuration file. This step is crucial as it allows Expo to load any necessary configurations or permissions required by the library.
29
+
30
+ Add the plugin to your app.json like so:
31
+
32
+ ```json
33
+ {
34
+ "expo": {
35
+ "plugins": ["@siteed/expo-audio-stream"]
36
+ }
37
+ }
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ ### Importing the module
43
+
44
+ ```tsx
45
+ import {
46
+ useAudioRecorder,
47
+ } from 'expo-audio-stream';
48
+
49
+ export default function App() {
50
+ const { startRecording, stopRecording, duration, size, isRecording } = useAudioRecorder({
51
+ onAudioStream: (base64Data) => {
52
+ console.log(`audio event ${typeof base64Data}`, base64Data);
53
+ }
54
+ });
55
+
56
+ const handleStart = async () => {
57
+ const { granted } = await Audio.requestPermissionsAsync();
58
+ if (granted) {
59
+ startRecording({interval: 500});
60
+ }
61
+ };
62
+
63
+ const renderRecording = () => (
64
+ <View>
65
+ <Text>Duration: {duration} ms</Text>
66
+ <Text>Size: {size} bytes</Text>
67
+ <Button title="Stop Recording" onPress={stopRecording} />
68
+ </View>
69
+ );
70
+
71
+ const renderStopped = () => (
72
+ <View>
73
+ <Button title="Start Recording" onPress={handleStart} />
74
+ </View>
75
+ );
76
+
77
+ return (
78
+ <View>
79
+ <Button title="Request Permission" onPress={() => Audio.requestPermissionsAsync()} />
80
+ {isRecording ? renderRecording() : renderStopped()}
81
+ </View>
82
+ );
83
+ }
84
+ ```
85
+
File without changes
@@ -0,0 +1,2 @@
1
+ #Sat Apr 20 14:30:49 HKT 2024
2
+ gradle.version=8.1.1
File without changes
@@ -0,0 +1,92 @@
1
+ apply plugin: 'com.android.library'
2
+ apply plugin: 'kotlin-android'
3
+ apply plugin: 'maven-publish'
4
+
5
+ group = 'net.siteed.audiostream'
6
+ version = '0.1.0'
7
+
8
+ buildscript {
9
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
10
+ if (expoModulesCorePlugin.exists()) {
11
+ apply from: expoModulesCorePlugin
12
+ applyKotlinExpoModulesCorePlugin()
13
+ }
14
+
15
+ // Simple helper that allows the root project to override versions declared by this library.
16
+ ext.safeExtGet = { prop, fallback ->
17
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
18
+ }
19
+
20
+ // Ensures backward compatibility
21
+ ext.getKotlinVersion = {
22
+ if (ext.has("kotlinVersion")) {
23
+ ext.kotlinVersion()
24
+ } else {
25
+ ext.safeExtGet("kotlinVersion", "1.8.10")
26
+ }
27
+ }
28
+
29
+ repositories {
30
+ mavenCentral()
31
+ }
32
+
33
+ dependencies {
34
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
35
+ }
36
+ }
37
+
38
+ afterEvaluate {
39
+ publishing {
40
+ publications {
41
+ release(MavenPublication) {
42
+ from components.release
43
+ }
44
+ }
45
+ repositories {
46
+ maven {
47
+ url = mavenLocal().url
48
+ }
49
+ }
50
+ }
51
+ }
52
+
53
+ android {
54
+ compileSdkVersion safeExtGet("compileSdkVersion", 33)
55
+
56
+ def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
57
+ if (agpVersion.tokenize('.')[0].toInteger() < 8) {
58
+ compileOptions {
59
+ sourceCompatibility JavaVersion.VERSION_11
60
+ targetCompatibility JavaVersion.VERSION_11
61
+ }
62
+
63
+ kotlinOptions {
64
+ jvmTarget = JavaVersion.VERSION_11.majorVersion
65
+ }
66
+ }
67
+
68
+ namespace "net.siteed.audiostream"
69
+ defaultConfig {
70
+ minSdkVersion safeExtGet("minSdkVersion", 21)
71
+ targetSdkVersion safeExtGet("targetSdkVersion", 34)
72
+ versionCode 1
73
+ versionName "0.1.0"
74
+ }
75
+ lintOptions {
76
+ abortOnError false
77
+ }
78
+ publishing {
79
+ singleVariant("release") {
80
+ withSourcesJar()
81
+ }
82
+ }
83
+ }
84
+
85
+ repositories {
86
+ mavenCentral()
87
+ }
88
+
89
+ dependencies {
90
+ implementation project(':expo-modules-core')
91
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
92
+ }
@@ -0,0 +1,4 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
3
+ <uses-permission android:name="android.permission.INTERNET"/>
4
+ </manifest>
@@ -0,0 +1,318 @@
1
+ package net.siteed.audiostream
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
9
+ import android.util.Log
10
+ import androidx.core.content.ContextCompat
11
+ import androidx.core.os.bundleOf
12
+ import expo.modules.kotlin.modules.Module
13
+ 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
+ const val AUDIO_EVENT_NAME = "AudioData"
26
+
27
+ class ExpoAudioStreamModule() : Module() {
28
+ private var audioRecord: AudioRecord? = null
29
+ private var sampleRateInHz = 44100 // Default sample rate
30
+ private var channelConfig = AudioFormat.CHANNEL_IN_MONO
31
+ private var audioFormat = AudioFormat.ENCODING_PCM_16BIT
32
+ private var bufferSizeInBytes: Int = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)
33
+ private var isRecording = AtomicBoolean(false)
34
+ private val isPaused = AtomicBoolean(false)
35
+ private var streamUuid: String? = null
36
+ private var audioFile: File? = null
37
+ private var recordingThread: Thread? = null
38
+ private var recordingStartTime: Long = 0
39
+ private var totalRecordedTime: Long = 0
40
+ private var totalDataSize = 0
41
+ private val audioDataBuffer = ByteArrayOutputStream()
42
+ private var interval = 1000L // Emit data every 1000 milliseconds (1 second)
43
+ private var lastEmitTime = SystemClock.elapsedRealtime()
44
+ private var lastPauseTime = 0L
45
+ private var pausedDuration = 0L
46
+ private var lastEmittedSize = 0L
47
+ private val mainHandler = Handler(Looper.getMainLooper())
48
+
49
+ @SuppressLint("MissingPermission")
50
+ override fun definition() = ModuleDefinition {
51
+ // Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
52
+ // Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
53
+ // The module will be accessible from `requireNativeModule('ExpoAudioStream')` in JavaScript.
54
+ Name("ExpoAudioStream")
55
+
56
+ Events(AUDIO_EVENT_NAME)
57
+
58
+ AsyncFunction("startRecording") { options: Map<String, Any?>, promise: Promise ->
59
+ configureRecording(options)
60
+ startRecording(options, promise)
61
+ }
62
+
63
+ Function("clearAudioFiles") {
64
+ clearAudioStorage()
65
+ }
66
+
67
+ Function("status") {
68
+ val currentTime = System.currentTimeMillis()
69
+ totalRecordedTime = (currentTime - recordingStartTime - pausedDuration) // Adjust the total recording time
70
+
71
+ bundleOf(
72
+ "duration" to totalRecordedTime,
73
+ "isRecording" to isRecording.get(),
74
+ "isPaused" to isPaused.get(),
75
+ "size" to totalDataSize,
76
+ "interval" to interval,
77
+ )
78
+ }
79
+
80
+ AsyncFunction("listAudioFiles") { promise: Promise ->
81
+ try {
82
+ val fileList = listAudioFiles()
83
+ promise.resolve(fileList)
84
+ } catch (e: Exception) {
85
+ promise.reject("ERROR_LIST_FILES", "Failed to list audio files", e)
86
+ }
87
+ }
88
+
89
+ AsyncFunction("pauseRecording") { promise: Promise ->
90
+ pauseRecording(promise)
91
+ }
92
+
93
+ AsyncFunction("stopRecording") { promise: Promise ->
94
+ stopRecording(promise)
95
+ }
96
+ }
97
+
98
+ private fun configureRecording(params: Map<String, Any?>) {
99
+ sampleRateInHz = (params["sampleRate"] as? Int) ?: 44100
100
+ channelConfig = (params["channelConfig"] as? Int) ?: AudioFormat.CHANNEL_IN_MONO
101
+ audioFormat = (params["audioFormat"] as? Int) ?: AudioFormat.ENCODING_PCM_16BIT
102
+ bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)
103
+ }
104
+
105
+ private fun listAudioFiles(): List<String> {
106
+ val filesDir = appContext.reactContext?.filesDir
107
+ // Filter to include only .pcm files
108
+ val files = filesDir?.listFiles { file ->
109
+ file.isFile && file.name.endsWith(".pcm")
110
+ }?.map { it.absolutePath } ?: listOf() // Use `listOf()` to return an empty list if null
111
+ return files
112
+ }
113
+
114
+
115
+ private fun startRecording(options: Map<String, Any?>, promise: Promise) {
116
+ if (!checkPermission()) {
117
+ promise.reject("PERMISSION_DENIED", "Recording permission has not been granted", null)
118
+ return
119
+ }
120
+
121
+ if (isRecording.get() && !isPaused.get()) {
122
+ promise.reject("ALREADY_RECORDING", "Recording is already in progress", null)
123
+ return
124
+ }
125
+
126
+ val intervalOption = options["interval"]
127
+ if (intervalOption != null) {
128
+ Log.d("AudioRecorderModule", "Setting interval to $intervalOption")
129
+ if (intervalOption is Number) {
130
+ val intervalValue = intervalOption.toLong()
131
+ if (intervalValue < 100) {
132
+ promise.reject("INVALID_INTERVAL", "Interval must be at least 100 ms", null)
133
+ return
134
+ } else {
135
+ this.interval = intervalValue
136
+ }
137
+ } else {
138
+ promise.reject("INVALID_INTERVAL", "Interval must be a number", null)
139
+ return
140
+ }
141
+ }
142
+
143
+ // Log for new recording or resuming
144
+ if (!isPaused.get()) {
145
+ streamUuid = java.util.UUID.randomUUID().toString()
146
+ audioFile = File(appContext.reactContext?.filesDir, "audio_${streamUuid}.pcm")
147
+ Log.i("AudioRecorderModule", "Starting new recording $streamUuid with sample rate: $sampleRateInHz, channel config: $channelConfig, audio format: $audioFormat, buffer size: $bufferSizeInBytes, interval: $interval")
148
+
149
+ } else {
150
+ Log.i("AudioRecorderModule", "Resuming recording")
151
+ }
152
+
153
+ // Initialize the recorder if it's a new recording
154
+ if (!isPaused.get() && !initializeRecorder()) {
155
+ promise.reject("INITIALIZATION_FAILED", "AudioRecord initialization failed", null)
156
+ return
157
+ }
158
+
159
+ audioRecord?.startRecording()
160
+ isPaused.set(false)
161
+ isRecording.set(true)
162
+
163
+
164
+ if (!isPaused.get()) {
165
+ recordingStartTime = System.currentTimeMillis() // Only reset start time if it's not a resume
166
+ }
167
+
168
+ recordingThread = Thread { recordingProcess() }.apply { start() }
169
+ promise.resolve(null)
170
+ }
171
+
172
+ private fun stopRecording(promise: Promise) {
173
+ if (!isRecording.get()) {
174
+ promise.reject("NOT_RECORDING", "Recording is not active", null)
175
+ return
176
+ }
177
+
178
+ try {
179
+ audioRecord?.stop()
180
+ audioRecord?.release()
181
+ val endTime = System.currentTimeMillis()
182
+ totalRecordedTime += (endTime - recordingStartTime - pausedDuration) // Adjust the total recording time
183
+ isRecording.set(false)
184
+ isPaused.set(false)
185
+ promise.resolve(totalRecordedTime)
186
+ // Reset the timing variables
187
+ totalRecordedTime = 0
188
+ pausedDuration = 0
189
+ } catch (e: Exception) {
190
+ promise.reject("STOP_FAILED", "Failed to stop recording", e)
191
+ } finally {
192
+ audioRecord = null
193
+ }
194
+ }
195
+
196
+ private fun recordingProcess() {
197
+
198
+ val audioData = ByteArray(bufferSizeInBytes)
199
+ while (isRecording.get()) {
200
+ if (!isPaused.get()) {
201
+ val bytesRead = audioRecord?.read(audioData, 0, bufferSizeInBytes) ?: -1
202
+ if (bytesRead < 0) {
203
+ Log.e("AudioRecorderModule", "Read error: $bytesRead")
204
+ break
205
+ }
206
+ if (bytesRead > 0) {
207
+ audioDataBuffer.write(audioData, 0, bytesRead)
208
+ totalDataSize += bytesRead
209
+ if (SystemClock.elapsedRealtime() - lastEmitTime >= interval) {
210
+ emitAudioData()
211
+ lastEmitTime = SystemClock.elapsedRealtime() // Reset the timer
212
+ }
213
+ }
214
+ }
215
+ }
216
+ if (audioDataBuffer.size() > 0) {
217
+ emitAudioData() // Emit any remaining data
218
+ }
219
+ }
220
+
221
+
222
+ private fun clearAudioStorage() {
223
+ // Clear all files in the app's internal storage
224
+ val filesDir = appContext.reactContext?.filesDir
225
+ filesDir?.listFiles()?.forEach {
226
+ Log.d("AudioRecorderModule", "Deleting file: ${it.absolutePath}")
227
+ it.delete()
228
+ }
229
+ }
230
+
231
+ private fun emitAudioData() {
232
+ val rawData = audioDataBuffer.toByteArray()
233
+ if (!saveAudioToFile(rawData)) {
234
+ Log.e("AudioRecorderModule", "Failed to save audio data")
235
+ return
236
+ }
237
+ val encodedBuffer = encodeAudioData(rawData)
238
+ val fileSize = audioFile?.length() ?: 0
239
+ val from = lastEmittedSize
240
+ val deltaSize = fileSize - lastEmittedSize
241
+ lastEmittedSize = fileSize
242
+ mainHandler.post {
243
+ try {
244
+ this@ExpoAudioStreamModule.sendEvent(AUDIO_EVENT_NAME,
245
+ bundleOf(
246
+ "fileUri" to audioFile?.toURI().toString(),
247
+ "from" to from,
248
+ "encoded" to encodedBuffer,
249
+ "deltaSize" to deltaSize,
250
+ "totalSize" to fileSize,
251
+ "streamUuid" to streamUuid
252
+ )
253
+ )
254
+ } catch (e: Exception) {
255
+ Log.e("AudioRecorderModule", "Failed to send event", e)
256
+ }
257
+ }
258
+ audioDataBuffer.reset() // Clear the buffer after emitting
259
+ }
260
+
261
+ private fun encodeAudioData(rawData: ByteArray): String {
262
+ return Base64.encodeToString(rawData, Base64.DEFAULT)
263
+ }
264
+
265
+ private fun saveAudioToFile(rawData: ByteArray): Boolean {
266
+ return try {
267
+ // Open a FileOutputStream in append mode.
268
+ FileOutputStream(audioFile, true).use { output ->
269
+ // Write rawData to the file.
270
+ output.write(rawData)
271
+ }
272
+ true
273
+ } catch (e: IOException) {
274
+ // Handle exceptions here
275
+ Log.e("AudioRecorderModule", "Could not write to file: ${audioFile?.absolutePath}", e)
276
+ false
277
+ }
278
+ }
279
+
280
+ private fun checkPermission(): Boolean {
281
+ val reactContext = appContext.reactContext ?: return false // If reactContext is null, permissions cannot be checked
282
+ return ContextCompat.checkSelfPermission(reactContext, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED
283
+ }
284
+
285
+ private fun pauseRecording(promise: Promise) {
286
+ if (isRecording.get() && !isPaused.get()) {
287
+ audioRecord?.stop()
288
+ lastPauseTime = System.currentTimeMillis() // Record the time when the recording was paused
289
+ isPaused.set(true)
290
+ promise.resolve("Recording paused")
291
+ } else {
292
+ promise.reject("NOT_RECORDING_OR_ALREADY_PAUSED", "Recording is either not active or already paused", null)
293
+ }
294
+ }
295
+
296
+ @SuppressLint("MissingPermission")
297
+ private fun initializeRecorder(): Boolean {
298
+ Log.d("AudioRecorderModule", "Initializing recorder")
299
+ bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)
300
+ Log.d("AudioRecorderModule", "Buffer size: $bufferSizeInBytes")
301
+
302
+ if (bufferSizeInBytes == AudioRecord.ERROR_BAD_VALUE) {
303
+ Log.e("AudioRecorderModule", "Invalid buffer size")
304
+ return false
305
+ }
306
+
307
+ val recorder = AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes)
308
+ if (recorder.state != AudioRecord.STATE_INITIALIZED) {
309
+ Log.e("AudioRecorderModule", "AudioRecord initialization failed")
310
+ recorder.release() // Clean up resources if initialization fails
311
+ return false
312
+ }
313
+
314
+ this.audioRecord = recorder // Properly assign the recorder to the class member
315
+ return true
316
+ }
317
+
318
+ }
package/app.plugin.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require('./plugin/build');
@@ -0,0 +1,23 @@
1
+ export interface AudioEventPayload {
2
+ encoded?: string;
3
+ buffer?: Blob;
4
+ fileUri: string;
5
+ from: number;
6
+ deltaSize: number;
7
+ totalSize: number;
8
+ streamUuid: string;
9
+ }
10
+ export interface AudioStreamStatus {
11
+ isRecording: boolean;
12
+ isPaused: boolean;
13
+ duration: number;
14
+ size: number;
15
+ interval: number;
16
+ }
17
+ export interface RecordingOptions {
18
+ sampleRate?: number;
19
+ channelConfig?: number;
20
+ audioFormat?: number;
21
+ interval?: number;
22
+ }
23
+ //# sourceMappingURL=ExpoAudioStream.types.d.ts.map
@@ -0,0 +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,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;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;CAClB;AAED,MAAM,WAAW,gBAAgB;IAE/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1,3 @@
1
+ ;
2
+ export {};
3
+ //# sourceMappingURL=ExpoAudioStream.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoAudioStream.types.js","sourceRoot":"","sources":["../src/ExpoAudioStream.types.ts"],"names":[],"mappings":"AAQC,CAAC","sourcesContent":["export interface AudioEventPayload {\n encoded?: string, \n buffer?: Blob,\n fileUri: string,\n from: number,\n deltaSize: number,\n totalSize: number,\n streamUuid: string,\n};\n\nexport interface AudioStreamStatus {\n isRecording: boolean;\n isPaused: boolean;\n duration: number;\n size: number;\n interval: number;\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"]}
@@ -0,0 +1,3 @@
1
+ declare const _default: any;
2
+ export default _default;
3
+ //# sourceMappingURL=ExpoAudioStreamModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoAudioStreamModule.d.ts","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.ts"],"names":[],"mappings":";AAIA,wBAAsD"}
@@ -0,0 +1,5 @@
1
+ import { requireNativeModule } from 'expo-modules-core';
2
+ // It loads the native module object from the JSI or falls back to
3
+ // the bridge module (from NativeModulesProxy) if the remote debugger is on.
4
+ export default requireNativeModule('ExpoAudioStream');
5
+ //# sourceMappingURL=ExpoAudioStreamModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoAudioStreamModule.js","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,kEAAkE;AAClE,4EAA4E;AAC5E,eAAe,mBAAmB,CAAC,iBAAiB,CAAC,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\n\n// It loads the native module object from the JSI or falls back to\n// the bridge module (from NativeModulesProxy) if the remote debugger is on.\nexport default requireNativeModule('ExpoAudioStream');\n"]}
@@ -0,0 +1,35 @@
1
+ import { EventEmitter } from "expo-modules-core";
2
+ import { RecordingOptions } from "./ExpoAudioStream.types";
3
+ declare class ExpoAudioStreamWeb extends EventEmitter {
4
+ mediaRecorder: MediaRecorder | null;
5
+ audioChunks: Blob[];
6
+ isRecording: boolean;
7
+ isPaused: boolean;
8
+ recordingStartTime: number;
9
+ pausedTime: number;
10
+ currentDuration: number;
11
+ currentSize: number;
12
+ currentInterval: number;
13
+ lastEmittedSize: number;
14
+ streamUuid: string | null;
15
+ constructor();
16
+ getMediaStream(): Promise<MediaStream>;
17
+ startRecording(options?: RecordingOptions): Promise<void>;
18
+ setupRecordingListeners(): void;
19
+ emitAudioEvent(data: Blob): void;
20
+ generateUUID(): string;
21
+ stopRecording(): Promise<number>;
22
+ pauseRecording(): Promise<void>;
23
+ status(): {
24
+ isRecording: boolean;
25
+ isPaused: boolean;
26
+ duration: number;
27
+ size: number;
28
+ interval: number;
29
+ };
30
+ listAudioFiles(): void;
31
+ clearAudioFiles(): void;
32
+ }
33
+ declare const _default: ExpoAudioStreamWeb;
34
+ export default _default;
35
+ //# sourceMappingURL=ExpoAudioStreamModule.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoAudioStreamModule.web.d.ts","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAqB,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE9E,cAAM,kBAAmB,SAAQ,YAAY;IACzC,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,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;;IA4BpB,cAAc;IAUd,cAAc,CAAC,OAAO,GAAE,gBAAqB;IAiBnD,uBAAuB;IA0BvB,cAAc,CAAC,IAAI,EAAE,IAAI;IAexB,YAAY;IASP,aAAa;IASb,cAAc;IAcpB,MAAM;;;;;;;IAUN,cAAc;IAId,eAAe;CAGlB;;AAED,wBAAwC"}