@siteed/expo-audio-stream 1.0.0 → 1.0.2

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 (85) hide show
  1. package/README.md +7 -18
  2. package/android/build.gradle +5 -0
  3. package/android/src/main/java/net/siteed/audiostream/AudioAnalysisData.kt +120 -0
  4. package/android/src/main/java/net/siteed/audiostream/AudioFileHandler.kt +34 -4
  5. package/android/src/main/java/net/siteed/audiostream/AudioProcessor.kt +635 -0
  6. package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +194 -79
  7. package/android/src/main/java/net/siteed/audiostream/Constants.kt +1 -0
  8. package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +48 -2
  9. package/android/src/main/java/net/siteed/audiostream/FFT.kt +44 -0
  10. package/android/src/main/java/net/siteed/audiostream/Features.kt +56 -0
  11. package/android/src/main/java/net/siteed/audiostream/RecordingConfig.kt +12 -0
  12. package/android/src/main/test/java/net/siteed/audiostream/AudioProcessorTest.kt +56 -0
  13. package/app.plugin.js +1 -1
  14. package/build/AudioRecorder.provider.js +1 -1
  15. package/build/AudioRecorder.provider.js.map +1 -1
  16. package/build/ExpoAudioStream.native.d.ts +3 -0
  17. package/build/ExpoAudioStream.native.d.ts.map +1 -0
  18. package/build/ExpoAudioStream.native.js +6 -0
  19. package/build/ExpoAudioStream.native.js.map +1 -0
  20. package/build/ExpoAudioStream.types.d.ts +79 -6
  21. package/build/ExpoAudioStream.types.d.ts.map +1 -1
  22. package/build/ExpoAudioStream.types.js.map +1 -1
  23. package/build/ExpoAudioStream.web.d.ts +41 -0
  24. package/build/ExpoAudioStream.web.d.ts.map +1 -0
  25. package/build/ExpoAudioStream.web.js +184 -0
  26. package/build/ExpoAudioStream.web.js.map +1 -0
  27. package/build/ExpoAudioStreamModule.d.ts +2 -2
  28. package/build/ExpoAudioStreamModule.d.ts.map +1 -1
  29. package/build/ExpoAudioStreamModule.js +12 -3
  30. package/build/ExpoAudioStreamModule.js.map +1 -1
  31. package/build/WebRecorder.d.ts +47 -0
  32. package/build/WebRecorder.d.ts.map +1 -0
  33. package/build/WebRecorder.js +243 -0
  34. package/build/WebRecorder.js.map +1 -0
  35. package/build/index.d.ts +14 -5
  36. package/build/index.d.ts.map +1 -1
  37. package/build/index.js +106 -7
  38. package/build/index.js.map +1 -1
  39. package/build/inlineAudioWebWorker.d.ts +3 -0
  40. package/build/inlineAudioWebWorker.d.ts.map +1 -0
  41. package/build/inlineAudioWebWorker.js +340 -0
  42. package/build/inlineAudioWebWorker.js.map +1 -0
  43. package/build/useAudioRecording.d.ts +24 -9
  44. package/build/useAudioRecording.d.ts.map +1 -1
  45. package/build/useAudioRecording.js +107 -29
  46. package/build/useAudioRecording.js.map +1 -1
  47. package/build/utils.d.ts +31 -0
  48. package/build/utils.d.ts.map +1 -0
  49. package/build/utils.js +143 -0
  50. package/build/utils.js.map +1 -0
  51. package/expo-module.config.json +13 -4
  52. package/ios/AudioAnalysisData.swift +39 -0
  53. package/ios/AudioProcessingHelpers.swift +59 -0
  54. package/ios/AudioProcessor.swift +317 -0
  55. package/ios/AudioStreamError.swift +7 -0
  56. package/ios/AudioStreamManager.swift +204 -52
  57. package/ios/AudioStreamManagerDelegate.swift +4 -0
  58. package/ios/DataPoint.swift +41 -0
  59. package/ios/ExpoAudioStreamModule.swift +188 -6
  60. package/ios/Features.swift +44 -0
  61. package/ios/RecordingResult.swift +19 -0
  62. package/ios/RecordingSettings.swift +13 -0
  63. package/ios/WaveformExtractor.swift +105 -0
  64. package/package.json +9 -9
  65. package/plugin/tsconfig.json +13 -8
  66. package/publish.sh +8 -0
  67. package/src/AudioRecorder.provider.tsx +1 -1
  68. package/src/ExpoAudioStream.native.ts +6 -0
  69. package/src/ExpoAudioStream.types.ts +97 -11
  70. package/src/ExpoAudioStream.web.ts +228 -0
  71. package/src/ExpoAudioStreamModule.ts +17 -3
  72. package/src/WebRecorder.ts +364 -0
  73. package/src/index.ts +166 -20
  74. package/src/inlineAudioWebWorker.tsx +340 -0
  75. package/src/useAudioRecording.tsx +410 -0
  76. package/src/utils.ts +189 -0
  77. package/build/ExpoAudioStreamModule.web.d.ts +0 -37
  78. package/build/ExpoAudioStreamModule.web.d.ts.map +0 -1
  79. package/build/ExpoAudioStreamModule.web.js +0 -156
  80. package/build/ExpoAudioStreamModule.web.js.map +0 -1
  81. package/docs/demo.gif +0 -0
  82. package/release-it.js +0 -18
  83. package/src/ExpoAudioStreamModule.web.ts +0 -181
  84. package/src/useAudioRecording.ts +0 -268
  85. package/yarn-error.log +0 -7793
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @siteed/expo-audio-stream
2
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.
3
+ `@siteed/expo-audio-stream` is a comprehensive library designed to facilitate real-time audio processing and streaming across iOS, Android, and web platforms.
4
4
 
5
5
  ## Features
6
6
 
@@ -11,7 +11,7 @@
11
11
  - Listeners for audio data events with detailed event payloads.
12
12
  - Utility functions for recording control and file management.
13
13
 
14
- ## Example Application
14
+ ## Playground Example Application
15
15
 
16
16
  The project comes with a fully functional example application that demonstrates how to use the library in a real-world scenario.
17
17
 
@@ -23,9 +23,9 @@ To try it:
23
23
  git clone https://github.com/deeeed/expo-audio-stream.git
24
24
  cd expo-audio-stream
25
25
  yarn
26
- yarn example ios
27
- yarn example android
28
- yarn example web
26
+ yarn playground ios
27
+ yarn playground android
28
+ yarn playground web
29
29
  ```
30
30
 
31
31
  ## Installation
@@ -38,13 +38,10 @@ npm install @siteed/expo-audio-stream
38
38
  yarn add @siteed/expo-audio-stream
39
39
  ```
40
40
 
41
- Make sure that you have Expo set up in your project. For details on setting up Expo, refer to the Expo documentation.
42
41
 
43
42
  ### Configuring with app.json
44
43
 
45
- 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.
46
-
47
- Add the plugin to your app.json like so:
44
+ To ensure expo-audio-stream works correctly with Expo, you must add it as a plugin in your app.json configuration file.
48
45
 
49
46
  ```json
50
47
  {
@@ -63,7 +60,7 @@ This library provides two hooks: `useAudioRecorder` for standalone use and `useS
63
60
 
64
61
  ### Standalone Recording
65
62
 
66
- The `example/` folder contains a fully functional React Native application demonstrating how to integrate and use `useAudioRecorder` from `@siteed/expo-audio-stream`. This includes starting and stopping recordings, handling permissions, and processing live audio data.
63
+ The `playground/` folder contains a fully functional React Native application demonstrating how to integrate and use `useAudioRecorder` from `@siteed/expo-audio-stream`. This includes starting and stopping recordings, handling permissions, and processing live audio data.
67
64
 
68
65
 
69
66
  #### Standalone Usage
@@ -187,11 +184,3 @@ function App() {
187
184
  - on web, it usually records in opus but it depends on the browser configuration.
188
185
 
189
186
  If you want to process the audio livestream directly, I recommend having another encoding step to align the audio format across platforms.
190
-
191
- ## TODO
192
- this package is still in development, and there are a few things that need to be done:
193
- - Add resume (vs currently use start) support and implement pause on iOS.
194
- - Multi format support: Extend support to other audio formats beyond WAV, such as MP3 or AAC
195
- - Integrate an audio processing library for optional audio analysis, such as equalization, noise reduction, or volume normalization.
196
- - Implement a more robust error handling system to provide detailed error messages and recovery options.
197
-
@@ -89,4 +89,9 @@ repositories {
89
89
  dependencies {
90
90
  implementation project(':expo-modules-core')
91
91
  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
92
+
93
+ // Add testing dependencies
94
+ testImplementation 'junit:junit:4.13.2'
95
+ testImplementation 'org.jetbrains.kotlin:kotlin-test:1.8.10'
96
+ testImplementation 'org.jetbrains.kotlin:kotlin-test-junit:1.8.10'
92
97
  }
@@ -0,0 +1,120 @@
1
+ // net/siteed/audiostream/AudioAnalysisData.kt
2
+ package net.siteed.audiostream
3
+
4
+ import android.os.Bundle
5
+ import androidx.core.os.bundleOf
6
+
7
+ data class DataPoint(
8
+ val id: Long,
9
+ val amplitude: Float,
10
+ val activeSpeech: Boolean? = null,
11
+ val dB: Float? = null,
12
+ val silent: Boolean? = null,
13
+ val features: Features? = null,
14
+ val startTime: Float? = null,
15
+ val endTime: Float? = null,
16
+ val startPosition: Int? = null,
17
+ val endPosition: Int? = null,
18
+ val samples: Int = 0,
19
+ val speaker: Int? = null
20
+ ) {
21
+ fun toDictionary(): Map<String, Any?> {
22
+ return mapOf(
23
+ "id" to id,
24
+ "amplitude" to amplitude,
25
+ "activeSpeech" to activeSpeech,
26
+ "dB" to dB,
27
+ "silent" to silent,
28
+ "features" to features?.toDictionary(),
29
+ "startTime" to startTime,
30
+ "endTime" to endTime,
31
+ "startPosition" to startPosition,
32
+ "endPosition" to endPosition,
33
+ "samples" to samples,
34
+ "speaker" to speaker
35
+ )
36
+ }
37
+
38
+ fun toBundle(): Bundle {
39
+ return bundleOf(
40
+ "id" to id,
41
+ "amplitude" to amplitude,
42
+ "activeSpeech" to activeSpeech,
43
+ "dB" to dB,
44
+ "silent" to silent,
45
+ "features" to features?.toBundle(),
46
+ "startTime" to startTime,
47
+ "endTime" to endTime,
48
+ "startPosition" to startPosition,
49
+ "endPosition" to endPosition,
50
+ "samples" to samples,
51
+ "speaker" to speaker
52
+ )
53
+ }
54
+ }
55
+
56
+ data class AudioAnalysisData(
57
+ val pointsPerSecond: Double,
58
+ val durationMs: Int,
59
+ val bitDepth: Int,
60
+ val numberOfChannels: Int,
61
+ val sampleRate: Int,
62
+ val samples: Int,
63
+ val dataPoints: List<DataPoint>,
64
+ val amplitudeRange: AmplitudeRange,
65
+ val speakerChanges: List<SpeakerChange>,
66
+ val extractionTimeMs: Float
67
+ ) {
68
+ data class AmplitudeRange(val min: Float, val max: Float) {
69
+ fun toDictionary(): Map<String, Float> {
70
+ return mapOf("min" to min, "max" to max)
71
+ }
72
+
73
+ fun toBundle(): Bundle {
74
+ return bundleOf("min" to min, "max" to max)
75
+ }
76
+ }
77
+
78
+ data class SpeakerChange(val timestamp: Float, val speaker: Int) {
79
+ fun toDictionary(): Map<String, Any> {
80
+ return mapOf("timestamp" to timestamp, "speaker" to speaker)
81
+ }
82
+
83
+ fun toBundle(): Bundle {
84
+ return bundleOf("timestamp" to timestamp, "speaker" to speaker)
85
+ }
86
+ }
87
+
88
+ fun toDictionary(): Map<String, Any> {
89
+ return mapOf(
90
+ "pointsPerSecond" to pointsPerSecond,
91
+ "durationMs" to durationMs,
92
+ "bitDepth" to bitDepth,
93
+ "numberOfChannels" to numberOfChannels,
94
+ "sampleRate" to sampleRate,
95
+ "samples" to samples,
96
+ "dataPoints" to dataPoints.map { it.toDictionary() },
97
+ "amplitudeRange" to amplitudeRange.toDictionary(),
98
+ "speakerChanges" to speakerChanges.map { it.toDictionary() },
99
+ "extractionTimeMs" to extractionTimeMs
100
+ )
101
+ }
102
+
103
+ fun toBundle(): Bundle {
104
+ val dataPointsBundleArray = dataPoints.map { it.toBundle() }.toTypedArray()
105
+ val speakerChangesBundleArray = speakerChanges.map { it.toBundle() }.toTypedArray()
106
+
107
+ return bundleOf(
108
+ "pointsPerSecond" to pointsPerSecond,
109
+ "durationMs" to durationMs,
110
+ "bitDepth" to bitDepth,
111
+ "numberOfChannels" to numberOfChannels,
112
+ "sampleRate" to sampleRate,
113
+ "samples" to samples,
114
+ "dataPoints" to dataPointsBundleArray,
115
+ "amplitudeRange" to amplitudeRange.toBundle(),
116
+ "speakerChanges" to speakerChangesBundleArray,
117
+ "extractionTimeMs" to extractionTimeMs
118
+ )
119
+ }
120
+ }
@@ -14,25 +14,55 @@ class AudioFileHandler(private val filesDir: File) {
14
14
 
15
15
  // RIFF/WAVE header
16
16
  "RIFF".toByteArray().copyInto(header, 0)
17
- header[4] = 0 // Size will be updated later
17
+ // (file size - 8) to be updated later
18
+ header[4] = 0 // Placeholder
19
+ header[5] = 0 // Placeholder
20
+ header[6] = 0 // Placeholder
21
+ header[7] = 0 // Placeholder
18
22
  "WAVE".toByteArray().copyInto(header, 8)
19
23
  "fmt ".toByteArray().copyInto(header, 12)
20
24
 
21
25
  // 16 for PCM
22
26
  header[16] = 16
27
+ header[17] = 0
28
+ header[18] = 0
29
+ header[19] = 0
30
+
31
+ // PCM format ID
23
32
  header[20] = 1 // Audio format 1 for PCM (not compressed)
24
- header[22] = channels.toByte()
33
+ header[21] = 0
34
+
35
+ // Number of channels
36
+ header[22] = (channels and 0xff).toByte()
37
+ header[23] = (channels shr 8 and 0xff).toByte()
38
+
39
+ // Sample rate
25
40
  header[24] = (sampleRateInHz and 0xff).toByte()
26
41
  header[25] = (sampleRateInHz shr 8 and 0xff).toByte()
27
42
  header[26] = (sampleRateInHz shr 16 and 0xff).toByte()
28
43
  header[27] = (sampleRateInHz shr 24 and 0xff).toByte()
44
+
45
+ // Byte rate
29
46
  header[28] = (byteRate and 0xff).toByte()
30
47
  header[29] = (byteRate shr 8 and 0xff).toByte()
31
48
  header[30] = (byteRate shr 16 and 0xff).toByte()
32
49
  header[31] = (byteRate shr 24 and 0xff).toByte()
33
- header[32] = blockAlign.toByte()
34
- header[34] = bitDepth.toByte()
50
+
51
+ // Block align
52
+ header[32] = (blockAlign and 0xff).toByte()
53
+ header[33] = (blockAlign shr 8 and 0xff).toByte()
54
+
55
+ // Bits per sample
56
+ header[34] = (bitDepth and 0xff).toByte()
57
+ header[35] = (bitDepth shr 8 and 0xff).toByte()
58
+
59
+ // Data chunk
35
60
  "data".toByteArray().copyInto(header, 36)
61
+ // Data size to be updated later
62
+ header[40] = 0 // Placeholder
63
+ header[41] = 0 // Placeholder
64
+ header[42] = 0 // Placeholder
65
+ header[43] = 0 // Placeholder
36
66
 
37
67
  out.write(header, 0, 44)
38
68
  }