@siteed/expo-audio-stream 2.0.1 → 2.2.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 (166) hide show
  1. package/README.md +46 -27
  2. package/build/index.d.ts +11 -12
  3. package/build/index.js +44 -10
  4. package/package.json +49 -110
  5. package/src/index.ts +18 -33
  6. package/CHANGELOG.md +0 -195
  7. package/android/build.gradle +0 -105
  8. package/android/src/main/AndroidManifest.xml +0 -27
  9. package/android/src/main/java/net/siteed/audiostream/AudioAnalysisData.kt +0 -166
  10. package/android/src/main/java/net/siteed/audiostream/AudioDataEncoder.kt +0 -9
  11. package/android/src/main/java/net/siteed/audiostream/AudioFileHandler.kt +0 -131
  12. package/android/src/main/java/net/siteed/audiostream/AudioFormatUtils.kt +0 -103
  13. package/android/src/main/java/net/siteed/audiostream/AudioNotificationsManager.kt +0 -435
  14. package/android/src/main/java/net/siteed/audiostream/AudioProcessor.kt +0 -1936
  15. package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +0 -1437
  16. package/android/src/main/java/net/siteed/audiostream/AudioRecordingService.kt +0 -138
  17. package/android/src/main/java/net/siteed/audiostream/Constants.kt +0 -20
  18. package/android/src/main/java/net/siteed/audiostream/EventSender.kt +0 -7
  19. package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +0 -509
  20. package/android/src/main/java/net/siteed/audiostream/FFT.kt +0 -99
  21. package/android/src/main/java/net/siteed/audiostream/Features.kt +0 -98
  22. package/android/src/main/java/net/siteed/audiostream/NotificationConfig.kt +0 -70
  23. package/android/src/main/java/net/siteed/audiostream/PermissionUtils.kt +0 -59
  24. package/android/src/main/java/net/siteed/audiostream/RecordingActionReceiver.kt +0 -59
  25. package/android/src/main/java/net/siteed/audiostream/RecordingConfig.kt +0 -205
  26. package/android/src/main/java/net/siteed/audiostream/WaveformConfig.kt +0 -19
  27. package/android/src/main/java/net/siteed/audiostream/WaveformRenderer.kt +0 -159
  28. package/android/src/main/res/drawable/ic_default_action_icon.xml +0 -16
  29. package/android/src/main/res/drawable/ic_microphone.xml +0 -13
  30. package/android/src/main/res/drawable/ic_pause.xml +0 -10
  31. package/android/src/main/res/drawable/ic_play.xml +0 -10
  32. package/android/src/main/res/drawable/ic_stop.xml +0 -10
  33. package/android/src/main/res/layout/notification_recording.xml +0 -37
  34. package/android/src/main/test/java/net/siteed/audiostream/AudioProcessorTest.kt +0 -56
  35. package/app.plugin.js +0 -1
  36. package/build/AudioAnalysis/AudioAnalysis.types.d.ts +0 -144
  37. package/build/AudioAnalysis/AudioAnalysis.types.d.ts.map +0 -1
  38. package/build/AudioAnalysis/AudioAnalysis.types.js +0 -3
  39. package/build/AudioAnalysis/AudioAnalysis.types.js.map +0 -1
  40. package/build/AudioAnalysis/extractAudioAnalysis.d.ts +0 -78
  41. package/build/AudioAnalysis/extractAudioAnalysis.d.ts.map +0 -1
  42. package/build/AudioAnalysis/extractAudioAnalysis.js +0 -229
  43. package/build/AudioAnalysis/extractAudioAnalysis.js.map +0 -1
  44. package/build/AudioAnalysis/extractWaveform.d.ts +0 -8
  45. package/build/AudioAnalysis/extractWaveform.d.ts.map +0 -1
  46. package/build/AudioAnalysis/extractWaveform.js +0 -11
  47. package/build/AudioAnalysis/extractWaveform.js.map +0 -1
  48. package/build/AudioRecorder.provider.d.ts +0 -11
  49. package/build/AudioRecorder.provider.d.ts.map +0 -1
  50. package/build/AudioRecorder.provider.js +0 -37
  51. package/build/AudioRecorder.provider.js.map +0 -1
  52. package/build/ExpoAudioStream.native.d.ts +0 -3
  53. package/build/ExpoAudioStream.native.d.ts.map +0 -1
  54. package/build/ExpoAudioStream.native.js +0 -6
  55. package/build/ExpoAudioStream.native.js.map +0 -1
  56. package/build/ExpoAudioStream.types.d.ts +0 -206
  57. package/build/ExpoAudioStream.types.d.ts.map +0 -1
  58. package/build/ExpoAudioStream.types.js +0 -2
  59. package/build/ExpoAudioStream.types.js.map +0 -1
  60. package/build/ExpoAudioStream.web.d.ts +0 -59
  61. package/build/ExpoAudioStream.web.d.ts.map +0 -1
  62. package/build/ExpoAudioStream.web.js +0 -285
  63. package/build/ExpoAudioStream.web.js.map +0 -1
  64. package/build/ExpoAudioStreamModule.d.ts +0 -3
  65. package/build/ExpoAudioStreamModule.d.ts.map +0 -1
  66. package/build/ExpoAudioStreamModule.js +0 -239
  67. package/build/ExpoAudioStreamModule.js.map +0 -1
  68. package/build/WebRecorder.web.d.ts +0 -119
  69. package/build/WebRecorder.web.d.ts.map +0 -1
  70. package/build/WebRecorder.web.js +0 -436
  71. package/build/WebRecorder.web.js.map +0 -1
  72. package/build/constants.d.ts +0 -11
  73. package/build/constants.d.ts.map +0 -1
  74. package/build/constants.js +0 -14
  75. package/build/constants.js.map +0 -1
  76. package/build/events.d.ts +0 -26
  77. package/build/events.d.ts.map +0 -1
  78. package/build/events.js +0 -21
  79. package/build/events.js.map +0 -1
  80. package/build/index.d.ts.map +0 -1
  81. package/build/index.js.map +0 -1
  82. package/build/useAudioRecorder.d.ts +0 -21
  83. package/build/useAudioRecorder.d.ts.map +0 -1
  84. package/build/useAudioRecorder.js +0 -427
  85. package/build/useAudioRecorder.js.map +0 -1
  86. package/build/utils/BlobFix.d.ts +0 -9
  87. package/build/utils/BlobFix.d.ts.map +0 -1
  88. package/build/utils/BlobFix.js +0 -498
  89. package/build/utils/BlobFix.js.map +0 -1
  90. package/build/utils/audioProcessing.d.ts +0 -24
  91. package/build/utils/audioProcessing.d.ts.map +0 -1
  92. package/build/utils/audioProcessing.js +0 -133
  93. package/build/utils/audioProcessing.js.map +0 -1
  94. package/build/utils/concatenateBuffers.d.ts +0 -8
  95. package/build/utils/concatenateBuffers.d.ts.map +0 -1
  96. package/build/utils/concatenateBuffers.js +0 -21
  97. package/build/utils/concatenateBuffers.js.map +0 -1
  98. package/build/utils/convertPCMToFloat32.d.ts +0 -13
  99. package/build/utils/convertPCMToFloat32.d.ts.map +0 -1
  100. package/build/utils/convertPCMToFloat32.js +0 -120
  101. package/build/utils/convertPCMToFloat32.js.map +0 -1
  102. package/build/utils/encodingToBitDepth.d.ts +0 -5
  103. package/build/utils/encodingToBitDepth.d.ts.map +0 -1
  104. package/build/utils/encodingToBitDepth.js +0 -13
  105. package/build/utils/encodingToBitDepth.js.map +0 -1
  106. package/build/utils/getWavFileInfo.d.ts +0 -26
  107. package/build/utils/getWavFileInfo.d.ts.map +0 -1
  108. package/build/utils/getWavFileInfo.js +0 -92
  109. package/build/utils/getWavFileInfo.js.map +0 -1
  110. package/build/utils/writeWavHeader.d.ts +0 -49
  111. package/build/utils/writeWavHeader.d.ts.map +0 -1
  112. package/build/utils/writeWavHeader.js +0 -91
  113. package/build/utils/writeWavHeader.js.map +0 -1
  114. package/build/workers/InlineFeaturesExtractor.web.d.ts +0 -2
  115. package/build/workers/InlineFeaturesExtractor.web.d.ts.map +0 -1
  116. package/build/workers/InlineFeaturesExtractor.web.js +0 -828
  117. package/build/workers/InlineFeaturesExtractor.web.js.map +0 -1
  118. package/build/workers/inlineAudioWebWorker.web.d.ts +0 -2
  119. package/build/workers/inlineAudioWebWorker.web.d.ts.map +0 -1
  120. package/build/workers/inlineAudioWebWorker.web.js +0 -157
  121. package/build/workers/inlineAudioWebWorker.web.js.map +0 -1
  122. package/expo-module.config.json +0 -9
  123. package/ios/AudioAnalysisData.swift +0 -74
  124. package/ios/AudioNotificationManager.swift +0 -135
  125. package/ios/AudioProcessingHelpers.swift +0 -743
  126. package/ios/AudioProcessor.swift +0 -858
  127. package/ios/AudioStreamError.swift +0 -7
  128. package/ios/AudioStreamManager.swift +0 -1708
  129. package/ios/AudioStreamManagerDelegate.swift +0 -16
  130. package/ios/DataPoint.swift +0 -54
  131. package/ios/DecodingConfig.swift +0 -47
  132. package/ios/ExpoAudioStream.podspec +0 -27
  133. package/ios/ExpoAudioStreamModule.swift +0 -698
  134. package/ios/FFT.swift +0 -62
  135. package/ios/Features.swift +0 -95
  136. package/ios/Logger.swift +0 -7
  137. package/ios/NotificationExtension.swift +0 -15
  138. package/ios/RecordingResult.swift +0 -22
  139. package/ios/RecordingSettings.swift +0 -265
  140. package/ios/WaveformExtractor.swift +0 -105
  141. package/plugin/build/index.d.ts +0 -21
  142. package/plugin/build/index.js +0 -191
  143. package/plugin/src/index.ts +0 -278
  144. package/plugin/tsconfig.json +0 -10
  145. package/plugin/tsconfig.tsbuildinfo +0 -1
  146. package/src/AudioAnalysis/AudioAnalysis.types.ts +0 -165
  147. package/src/AudioAnalysis/extractAudioAnalysis.ts +0 -370
  148. package/src/AudioAnalysis/extractWaveform.ts +0 -22
  149. package/src/AudioRecorder.provider.tsx +0 -54
  150. package/src/ExpoAudioStream.native.ts +0 -6
  151. package/src/ExpoAudioStream.types.ts +0 -329
  152. package/src/ExpoAudioStream.web.ts +0 -359
  153. package/src/ExpoAudioStreamModule.ts +0 -286
  154. package/src/WebRecorder.web.ts +0 -580
  155. package/src/constants.ts +0 -18
  156. package/src/events.ts +0 -60
  157. package/src/useAudioRecorder.tsx +0 -620
  158. package/src/utils/BlobFix.ts +0 -559
  159. package/src/utils/audioProcessing.ts +0 -205
  160. package/src/utils/concatenateBuffers.ts +0 -24
  161. package/src/utils/convertPCMToFloat32.ts +0 -170
  162. package/src/utils/encodingToBitDepth.ts +0 -18
  163. package/src/utils/getWavFileInfo.ts +0 -132
  164. package/src/utils/writeWavHeader.ts +0 -114
  165. package/src/workers/InlineFeaturesExtractor.web.tsx +0 -827
  166. package/src/workers/inlineAudioWebWorker.web.tsx +0 -156
@@ -1,59 +0,0 @@
1
- import { LegacyEventEmitter } from 'expo-modules-core';
2
- import { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types';
3
- import { AudioRecording, AudioStreamStatus, BitDepth, ConsoleLike, RecordingConfig, StartRecordingResult } from './ExpoAudioStream.types';
4
- import { WebRecorder } from './WebRecorder.web';
5
- export interface EmitAudioEventProps {
6
- data: Float32Array;
7
- position: number;
8
- compression?: {
9
- data: Blob;
10
- size: number;
11
- totalSize: number;
12
- mimeType: string;
13
- format: string;
14
- bitrate: number;
15
- };
16
- }
17
- export type EmitAudioEventFunction = (_: EmitAudioEventProps) => void;
18
- export type EmitAudioAnalysisFunction = (_: AudioAnalysis) => void;
19
- export interface ExpoAudioStreamWebProps {
20
- logger?: ConsoleLike;
21
- audioWorkletUrl: string;
22
- featuresExtratorUrl: string;
23
- maxBufferSize?: number;
24
- }
25
- export declare class ExpoAudioStreamWeb extends LegacyEventEmitter {
26
- customRecorder: WebRecorder | null;
27
- audioChunks: Float32Array[];
28
- isRecording: boolean;
29
- isPaused: boolean;
30
- recordingStartTime: number;
31
- pausedTime: number;
32
- currentDurationMs: number;
33
- currentSize: number;
34
- currentInterval: number;
35
- currentIntervalAnalysis: number;
36
- lastEmittedSize: number;
37
- lastEmittedTime: number;
38
- lastEmittedCompressionSize: number;
39
- lastEmittedAnalysisTime: number;
40
- streamUuid: string | null;
41
- extension: 'webm' | 'wav';
42
- recordingConfig?: RecordingConfig;
43
- bitDepth: BitDepth;
44
- audioWorkletUrl: string;
45
- featuresExtratorUrl: string;
46
- logger?: ConsoleLike;
47
- latestPosition: number;
48
- totalCompressedSize: number;
49
- private readonly maxBufferSize;
50
- constructor({ audioWorkletUrl, featuresExtratorUrl, logger, maxBufferSize, }: ExpoAudioStreamWebProps);
51
- getMediaStream(): Promise<MediaStream>;
52
- startRecording(recordingConfig?: RecordingConfig): Promise<StartRecordingResult>;
53
- emitAudioEvent({ data, position, compression }: EmitAudioEventProps): void;
54
- stopRecording(): Promise<AudioRecording>;
55
- pauseRecording(): Promise<void>;
56
- resumeRecording(): Promise<void>;
57
- status(): AudioStreamStatus;
58
- }
59
- //# sourceMappingURL=ExpoAudioStream.web.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ExpoAudioStream.web.d.ts","sourceRoot":"","sources":["../src/ExpoAudioStream.web.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAEtD,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAA;AACnE,OAAO,EACH,cAAc,EACd,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,eAAe,EACf,oBAAoB,EACvB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAI/C,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,YAAY,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE;QACV,IAAI,EAAE,IAAI,CAAA;QACV,IAAI,EAAE,MAAM,CAAA;QACZ,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;QACd,OAAO,EAAE,MAAM,CAAA;KAClB,CAAA;CACJ;AACD,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,EAAE,mBAAmB,KAAK,IAAI,CAAA;AACrE,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,CAAA;AAElE,MAAM,WAAW,uBAAuB;IACpC,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;IACvB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,qBAAa,kBAAmB,SAAQ,kBAAkB;IACtD,cAAc,EAAE,WAAW,GAAG,IAAI,CAAA;IAClC,WAAW,EAAE,YAAY,EAAE,CAAA;IAC3B,WAAW,EAAE,OAAO,CAAA;IACpB,QAAQ,EAAE,OAAO,CAAA;IACjB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,iBAAiB,EAAE,MAAM,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,uBAAuB,EAAE,MAAM,CAAA;IAC/B,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,0BAA0B,EAAE,MAAM,CAAA;IAClC,uBAAuB,EAAE,MAAM,CAAA;IAC/B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,EAAE,MAAM,GAAG,KAAK,CAAQ;IACjC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,QAAQ,EAAE,QAAQ,CAAA;IAClB,eAAe,EAAE,MAAM,CAAA;IACvB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,cAAc,EAAE,MAAM,CAAI;IAC1B,mBAAmB,EAAE,MAAM,CAAI;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAQ;gBAE1B,EACR,eAAe,EACf,mBAAmB,EACnB,MAAM,EACN,aAAmB,GACtB,EAAE,uBAAuB;IAmCpB,cAAc;IAUd,cAAc,CAChB,eAAe,GAAE,eAAoB,GACtC,OAAO,CAAC,oBAAoB,CAAC;IA8FhC,cAAc,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,mBAAmB;IAgC7D,aAAa,IAAI,OAAO,CAAC,cAAc,CAAC;IAoExC,cAAc;IAad,eAAe;IAarB,MAAM;CAsBT"}
@@ -1,285 +0,0 @@
1
- // src/ExpoAudioStreamModule.web.ts
2
- import { LegacyEventEmitter } from 'expo-modules-core';
3
- import { WebRecorder } from './WebRecorder.web';
4
- import { encodingToBitDepth } from './utils/encodingToBitDepth';
5
- export class ExpoAudioStreamWeb extends LegacyEventEmitter {
6
- customRecorder;
7
- audioChunks;
8
- isRecording;
9
- isPaused;
10
- recordingStartTime;
11
- pausedTime;
12
- currentDurationMs;
13
- currentSize;
14
- currentInterval;
15
- currentIntervalAnalysis;
16
- lastEmittedSize;
17
- lastEmittedTime;
18
- lastEmittedCompressionSize;
19
- lastEmittedAnalysisTime;
20
- streamUuid;
21
- extension = 'wav'; // Default extension is 'wav'
22
- recordingConfig;
23
- bitDepth; // Bit depth of the audio
24
- audioWorkletUrl;
25
- featuresExtratorUrl;
26
- logger;
27
- latestPosition = 0;
28
- totalCompressedSize = 0;
29
- maxBufferSize;
30
- constructor({ audioWorkletUrl, featuresExtratorUrl, logger, maxBufferSize = 100, // Default to storing last 100 chunks (1 chunk = 0.5 seconds)
31
- }) {
32
- const mockNativeModule = {
33
- addListener: () => {
34
- // Not used on web
35
- },
36
- removeListeners: () => {
37
- // Not used on web
38
- },
39
- };
40
- super(mockNativeModule); // Pass the mock native module to the parent class
41
- this.logger = logger;
42
- this.customRecorder = null;
43
- this.audioChunks = [];
44
- this.isRecording = false;
45
- this.isPaused = false;
46
- this.recordingStartTime = 0;
47
- this.pausedTime = 0;
48
- this.currentDurationMs = 0;
49
- this.currentSize = 0;
50
- this.bitDepth = 32; // Default
51
- this.currentInterval = 1000; // Default interval in ms
52
- this.currentIntervalAnalysis = 500; // Default analysis interval in ms
53
- this.lastEmittedSize = 0;
54
- this.lastEmittedTime = 0;
55
- this.latestPosition = 0;
56
- this.lastEmittedCompressionSize = 0;
57
- this.lastEmittedAnalysisTime = 0;
58
- this.streamUuid = null; // Initialize UUID on first recording start
59
- this.audioWorkletUrl = audioWorkletUrl;
60
- this.featuresExtratorUrl = featuresExtratorUrl;
61
- this.maxBufferSize = maxBufferSize;
62
- }
63
- // Utility to handle user media stream
64
- async getMediaStream() {
65
- try {
66
- return await navigator.mediaDevices.getUserMedia({ audio: true });
67
- }
68
- catch (error) {
69
- this.logger?.error('Failed to get media stream:', error);
70
- throw error;
71
- }
72
- }
73
- // Start recording with options
74
- async startRecording(recordingConfig = {}) {
75
- if (this.isRecording) {
76
- throw new Error('Recording is already in progress');
77
- }
78
- this.bitDepth = encodingToBitDepth({
79
- encoding: recordingConfig.encoding ?? 'pcm_32bit',
80
- });
81
- const audioContext = new (window.AudioContext ||
82
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
83
- // @ts-ignore - Allow webkitAudioContext for Safari
84
- window.webkitAudioContext)();
85
- const stream = await this.getMediaStream();
86
- const source = audioContext.createMediaStreamSource(stream);
87
- this.customRecorder = new WebRecorder({
88
- logger: this.logger,
89
- audioContext,
90
- source,
91
- recordingConfig,
92
- emitAudioEventCallback: ({ data, position, compression, }) => {
93
- // Keep only the latest chunks based on maxBufferSize
94
- this.audioChunks.push(new Float32Array(data));
95
- if (this.audioChunks.length > this.maxBufferSize) {
96
- this.audioChunks.shift(); // Remove oldest chunk
97
- }
98
- this.currentSize += data.byteLength;
99
- this.emitAudioEvent({ data, position, compression });
100
- this.lastEmittedTime = Date.now();
101
- this.lastEmittedSize = this.currentSize;
102
- this.lastEmittedCompressionSize = compression?.size ?? 0;
103
- },
104
- emitAudioAnalysisCallback: (audioAnalysisData) => {
105
- this.logger?.log(`Emitted AudioAnalysis:`, audioAnalysisData);
106
- this.emit('AudioAnalysis', audioAnalysisData);
107
- },
108
- });
109
- await this.customRecorder.init();
110
- this.customRecorder.start();
111
- // // Set a timer to stop recording after 5 seconds
112
- // setTimeout(() => {
113
- // logger.log("AUTO Stopping recording");
114
- // this.customRecorder?.stopAndPlay();
115
- // this.isRecording = false;
116
- // }, 3000);
117
- this.isRecording = true;
118
- this.recordingConfig = recordingConfig;
119
- this.recordingStartTime = Date.now();
120
- this.pausedTime = 0;
121
- this.isPaused = false;
122
- this.lastEmittedSize = 0;
123
- this.lastEmittedTime = 0;
124
- this.lastEmittedCompressionSize = 0;
125
- this.currentInterval = recordingConfig.interval ?? 1000;
126
- this.currentIntervalAnalysis = recordingConfig.intervalAnalysis ?? 500;
127
- this.lastEmittedAnalysisTime = Date.now();
128
- // Use custom filename if provided, otherwise fallback to timestamp
129
- if (recordingConfig.filename) {
130
- // Remove any existing extension from the filename
131
- this.streamUuid = recordingConfig.filename.replace(/\.[^/.]+$/, '');
132
- }
133
- else {
134
- this.streamUuid = Date.now().toString();
135
- }
136
- const fileUri = `${this.streamUuid}.${this.extension}`;
137
- const streamConfig = {
138
- fileUri,
139
- mimeType: `audio/${this.extension}`,
140
- bitDepth: this.bitDepth,
141
- channels: recordingConfig.channels ?? 1,
142
- sampleRate: recordingConfig.sampleRate ?? 44100,
143
- compression: recordingConfig.compression
144
- ? {
145
- ...recordingConfig.compression,
146
- bitrate: recordingConfig.compression?.bitrate ?? 128000,
147
- size: 0,
148
- mimeType: 'audio/webm',
149
- format: recordingConfig.compression?.format ?? 'opus',
150
- compressedFileUri: '',
151
- }
152
- : undefined,
153
- };
154
- return streamConfig;
155
- }
156
- emitAudioEvent({ data, position, compression }) {
157
- const fileUri = `${this.streamUuid}.${this.extension}`;
158
- if (compression?.size) {
159
- this.lastEmittedCompressionSize = compression.size;
160
- this.totalCompressedSize = compression.totalSize;
161
- }
162
- this.latestPosition = position;
163
- this.currentDurationMs = position * 1000; // Convert position (in seconds) to ms
164
- const audioEventPayload = {
165
- fileUri,
166
- mimeType: `audio/${this.extension}`,
167
- lastEmittedSize: this.lastEmittedSize,
168
- deltaSize: data.byteLength,
169
- position,
170
- totalSize: this.currentSize,
171
- buffer: data,
172
- streamUuid: this.streamUuid ?? '',
173
- compression: compression
174
- ? {
175
- data: compression?.data,
176
- totalSize: this.totalCompressedSize,
177
- eventDataSize: compression?.size ?? 0,
178
- position,
179
- }
180
- : undefined,
181
- };
182
- this.emit('AudioData', audioEventPayload);
183
- }
184
- // Stop recording
185
- async stopRecording() {
186
- if (!this.customRecorder) {
187
- throw new Error('Recorder is not initialized');
188
- }
189
- this.logger?.debug('[Stop] Starting stop process');
190
- const startTime = performance.now();
191
- try {
192
- this.logger?.debug('[Stop] Stopping recorder');
193
- const { compressedBlob } = await this.customRecorder.stop();
194
- this.isRecording = false;
195
- this.isPaused = false;
196
- this.currentDurationMs = Date.now() - this.recordingStartTime;
197
- let compression;
198
- let fileUri = `${this.streamUuid}.${this.extension}`;
199
- let mimeType = `audio/${this.extension}`;
200
- if (compressedBlob && this.recordingConfig?.compression?.enabled) {
201
- const compressedUri = URL.createObjectURL(compressedBlob);
202
- compression = {
203
- compressedFileUri: compressedUri,
204
- size: compressedBlob.size,
205
- mimeType: 'audio/webm',
206
- format: 'opus',
207
- bitrate: this.recordingConfig.compression.bitrate ?? 128000,
208
- };
209
- // Use compressed values when compression is enabled
210
- fileUri = compressedUri;
211
- mimeType = 'audio/webm';
212
- }
213
- this.logger?.debug(`[Stop] Completed stop process in ${performance.now() - startTime}ms`, {
214
- durationMs: this.currentDurationMs,
215
- compressedSize: compression?.size,
216
- });
217
- // Use the stored streamUuid (which contains our custom filename) for the final filename
218
- const filename = `${this.streamUuid}.${this.extension}`;
219
- const result = {
220
- fileUri,
221
- filename, // This will now use our custom filename
222
- bitDepth: this.bitDepth,
223
- createdAt: this.recordingStartTime,
224
- channels: this.recordingConfig?.channels ?? 1,
225
- sampleRate: this.recordingConfig?.sampleRate ?? 44100,
226
- durationMs: this.currentDurationMs,
227
- size: this.currentSize,
228
- mimeType,
229
- compression,
230
- };
231
- // Reset after creating the result
232
- this.streamUuid = null;
233
- return result;
234
- }
235
- catch (error) {
236
- this.logger?.error('[Stop] Error stopping recording:', error);
237
- throw error;
238
- }
239
- }
240
- // Pause recording
241
- async pauseRecording() {
242
- if (!this.isRecording || this.isPaused) {
243
- throw new Error('Recording is not active or already paused');
244
- }
245
- if (this.customRecorder) {
246
- this.customRecorder.pause();
247
- }
248
- this.isPaused = true;
249
- this.pausedTime = Date.now();
250
- }
251
- // Resume recording
252
- async resumeRecording() {
253
- if (!this.isPaused) {
254
- throw new Error('Recording is not paused');
255
- }
256
- if (this.customRecorder) {
257
- this.customRecorder.resume();
258
- }
259
- this.isPaused = false;
260
- this.recordingStartTime += Date.now() - this.pausedTime;
261
- }
262
- // Get current status
263
- status() {
264
- const status = {
265
- isRecording: this.isRecording,
266
- isPaused: this.isPaused,
267
- durationMs: this.currentDurationMs,
268
- size: this.currentSize,
269
- interval: this.currentInterval,
270
- intervalAnalysis: this.currentIntervalAnalysis,
271
- mimeType: `audio/${this.extension}`,
272
- compression: this.recordingConfig?.compression?.enabled
273
- ? {
274
- size: this.totalCompressedSize,
275
- mimeType: 'audio/webm',
276
- format: this.recordingConfig.compression.format ?? 'opus',
277
- bitrate: this.recordingConfig.compression.bitrate ?? 128000,
278
- compressedFileUri: `${this.streamUuid}.webm`,
279
- }
280
- : undefined,
281
- };
282
- return status;
283
- }
284
- }
285
- //# sourceMappingURL=ExpoAudioStream.web.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ExpoAudioStream.web.js","sourceRoot":"","sources":["../src/ExpoAudioStream.web.ts"],"names":[],"mappings":"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","sourcesContent":["// src/ExpoAudioStreamModule.web.ts\nimport { LegacyEventEmitter } from 'expo-modules-core'\n\nimport { AudioAnalysis } from './AudioAnalysis/AudioAnalysis.types'\nimport {\n AudioRecording,\n AudioStreamStatus,\n BitDepth,\n ConsoleLike,\n RecordingConfig,\n StartRecordingResult,\n} from './ExpoAudioStream.types'\nimport { WebRecorder } from './WebRecorder.web'\nimport { AudioEventPayload } from './events'\nimport { encodingToBitDepth } from './utils/encodingToBitDepth'\n\nexport interface EmitAudioEventProps {\n data: Float32Array\n position: number\n compression?: {\n data: Blob\n size: number\n totalSize: number\n mimeType: string\n format: string\n bitrate: number\n }\n}\nexport type EmitAudioEventFunction = (_: EmitAudioEventProps) => void\nexport type EmitAudioAnalysisFunction = (_: AudioAnalysis) => void\n\nexport interface ExpoAudioStreamWebProps {\n logger?: ConsoleLike\n audioWorkletUrl: string\n featuresExtratorUrl: string\n maxBufferSize?: number // Maximum number of chunks to keep in memory\n}\n\nexport class ExpoAudioStreamWeb extends LegacyEventEmitter {\n customRecorder: WebRecorder | null\n audioChunks: Float32Array[]\n isRecording: boolean\n isPaused: boolean\n recordingStartTime: number\n pausedTime: number\n currentDurationMs: number\n currentSize: number\n currentInterval: number\n currentIntervalAnalysis: number\n lastEmittedSize: number\n lastEmittedTime: number\n lastEmittedCompressionSize: number\n lastEmittedAnalysisTime: number\n streamUuid: string | null\n extension: 'webm' | 'wav' = 'wav' // Default extension is 'wav'\n recordingConfig?: RecordingConfig\n bitDepth: BitDepth // Bit depth of the audio\n audioWorkletUrl: string\n featuresExtratorUrl: string\n logger?: ConsoleLike\n latestPosition: number = 0\n totalCompressedSize: number = 0\n private readonly maxBufferSize: number\n\n constructor({\n audioWorkletUrl,\n featuresExtratorUrl,\n logger,\n maxBufferSize = 100, // Default to storing last 100 chunks (1 chunk = 0.5 seconds)\n }: ExpoAudioStreamWebProps) {\n const mockNativeModule = {\n addListener: () => {\n // Not used on web\n },\n removeListeners: () => {\n // Not used on web\n },\n }\n super(mockNativeModule) // Pass the mock native module to the parent class\n\n this.logger = logger\n this.customRecorder = 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.bitDepth = 32 // Default\n this.currentInterval = 1000 // Default interval in ms\n this.currentIntervalAnalysis = 500 // Default analysis interval in ms\n this.lastEmittedSize = 0\n this.lastEmittedTime = 0\n this.latestPosition = 0\n this.lastEmittedCompressionSize = 0\n this.lastEmittedAnalysisTime = 0\n this.streamUuid = null // Initialize UUID on first recording start\n this.audioWorkletUrl = audioWorkletUrl\n this.featuresExtratorUrl = featuresExtratorUrl\n this.maxBufferSize = maxBufferSize\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 this.logger?.error('Failed to get media stream:', error)\n throw error\n }\n }\n\n // Start recording with options\n async startRecording(\n recordingConfig: RecordingConfig = {}\n ): Promise<StartRecordingResult> {\n if (this.isRecording) {\n throw new Error('Recording is already in progress')\n }\n\n this.bitDepth = encodingToBitDepth({\n encoding: recordingConfig.encoding ?? 'pcm_32bit',\n })\n\n const audioContext = new (window.AudioContext ||\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore - Allow webkitAudioContext for Safari\n window.webkitAudioContext)()\n const stream = await this.getMediaStream()\n\n const source = audioContext.createMediaStreamSource(stream)\n\n this.customRecorder = new WebRecorder({\n logger: this.logger,\n audioContext,\n source,\n recordingConfig,\n emitAudioEventCallback: ({\n data,\n position,\n compression,\n }: EmitAudioEventProps) => {\n // Keep only the latest chunks based on maxBufferSize\n this.audioChunks.push(new Float32Array(data))\n if (this.audioChunks.length > this.maxBufferSize) {\n this.audioChunks.shift() // Remove oldest chunk\n }\n this.currentSize += data.byteLength\n this.emitAudioEvent({ data, position, compression })\n this.lastEmittedTime = Date.now()\n this.lastEmittedSize = this.currentSize\n this.lastEmittedCompressionSize = compression?.size ?? 0\n },\n emitAudioAnalysisCallback: (audioAnalysisData: AudioAnalysis) => {\n this.logger?.log(`Emitted AudioAnalysis:`, audioAnalysisData)\n this.emit('AudioAnalysis', audioAnalysisData)\n },\n })\n await this.customRecorder.init()\n this.customRecorder.start()\n\n // // Set a timer to stop recording after 5 seconds\n // setTimeout(() => {\n // logger.log(\"AUTO Stopping recording\");\n // this.customRecorder?.stopAndPlay();\n // this.isRecording = false;\n // }, 3000);\n\n this.isRecording = true\n this.recordingConfig = recordingConfig\n this.recordingStartTime = Date.now()\n this.pausedTime = 0\n this.isPaused = false\n this.lastEmittedSize = 0\n this.lastEmittedTime = 0\n this.lastEmittedCompressionSize = 0\n this.currentInterval = recordingConfig.interval ?? 1000\n this.currentIntervalAnalysis = recordingConfig.intervalAnalysis ?? 500\n this.lastEmittedAnalysisTime = Date.now()\n\n // Use custom filename if provided, otherwise fallback to timestamp\n if (recordingConfig.filename) {\n // Remove any existing extension from the filename\n this.streamUuid = recordingConfig.filename.replace(/\\.[^/.]+$/, '')\n } else {\n this.streamUuid = Date.now().toString()\n }\n\n const fileUri = `${this.streamUuid}.${this.extension}`\n const streamConfig: StartRecordingResult = {\n fileUri,\n mimeType: `audio/${this.extension}`,\n bitDepth: this.bitDepth,\n channels: recordingConfig.channels ?? 1,\n sampleRate: recordingConfig.sampleRate ?? 44100,\n compression: recordingConfig.compression\n ? {\n ...recordingConfig.compression,\n bitrate: recordingConfig.compression?.bitrate ?? 128000,\n size: 0,\n mimeType: 'audio/webm',\n format: recordingConfig.compression?.format ?? 'opus',\n compressedFileUri: '',\n }\n : undefined,\n }\n return streamConfig\n }\n\n emitAudioEvent({ data, position, compression }: EmitAudioEventProps) {\n const fileUri = `${this.streamUuid}.${this.extension}`\n if (compression?.size) {\n this.lastEmittedCompressionSize = compression.size\n this.totalCompressedSize = compression.totalSize\n }\n this.latestPosition = position\n this.currentDurationMs = position * 1000 // Convert position (in seconds) to ms\n\n const audioEventPayload: AudioEventPayload = {\n fileUri,\n mimeType: `audio/${this.extension}`,\n lastEmittedSize: this.lastEmittedSize,\n deltaSize: data.byteLength,\n position,\n totalSize: this.currentSize,\n buffer: data,\n streamUuid: this.streamUuid ?? '',\n compression: compression\n ? {\n data: compression?.data,\n totalSize: this.totalCompressedSize,\n eventDataSize: compression?.size ?? 0,\n position,\n }\n : undefined,\n }\n\n this.emit('AudioData', audioEventPayload)\n }\n\n // Stop recording\n async stopRecording(): Promise<AudioRecording> {\n if (!this.customRecorder) {\n throw new Error('Recorder is not initialized')\n }\n\n this.logger?.debug('[Stop] Starting stop process')\n const startTime = performance.now()\n\n try {\n this.logger?.debug('[Stop] Stopping recorder')\n const { compressedBlob } = await this.customRecorder.stop()\n\n this.isRecording = false\n this.isPaused = false\n this.currentDurationMs = Date.now() - this.recordingStartTime\n\n let compression: AudioRecording['compression']\n let fileUri = `${this.streamUuid}.${this.extension}`\n let mimeType = `audio/${this.extension}`\n\n if (compressedBlob && this.recordingConfig?.compression?.enabled) {\n const compressedUri = URL.createObjectURL(compressedBlob)\n compression = {\n compressedFileUri: compressedUri,\n size: compressedBlob.size,\n mimeType: 'audio/webm',\n format: 'opus',\n bitrate: this.recordingConfig.compression.bitrate ?? 128000,\n }\n // Use compressed values when compression is enabled\n fileUri = compressedUri\n mimeType = 'audio/webm'\n }\n\n this.logger?.debug(\n `[Stop] Completed stop process in ${performance.now() - startTime}ms`,\n {\n durationMs: this.currentDurationMs,\n compressedSize: compression?.size,\n }\n )\n\n // Use the stored streamUuid (which contains our custom filename) for the final filename\n const filename = `${this.streamUuid}.${this.extension}`\n const result: AudioRecording = {\n fileUri,\n filename, // This will now use our custom filename\n bitDepth: this.bitDepth,\n createdAt: this.recordingStartTime,\n channels: this.recordingConfig?.channels ?? 1,\n sampleRate: this.recordingConfig?.sampleRate ?? 44100,\n durationMs: this.currentDurationMs,\n size: this.currentSize,\n mimeType,\n compression,\n }\n\n // Reset after creating the result\n this.streamUuid = null\n\n return result\n } catch (error) {\n this.logger?.error('[Stop] Error stopping recording:', error)\n throw error\n }\n }\n\n // Pause recording\n async pauseRecording() {\n if (!this.isRecording || this.isPaused) {\n throw new Error('Recording is not active or already paused')\n }\n\n if (this.customRecorder) {\n this.customRecorder.pause()\n }\n this.isPaused = true\n this.pausedTime = Date.now()\n }\n\n // Resume recording\n async resumeRecording() {\n if (!this.isPaused) {\n throw new Error('Recording is not paused')\n }\n\n if (this.customRecorder) {\n this.customRecorder.resume()\n }\n this.isPaused = false\n this.recordingStartTime += Date.now() - this.pausedTime\n }\n\n // Get current status\n status() {\n const status: AudioStreamStatus = {\n isRecording: this.isRecording,\n isPaused: this.isPaused,\n durationMs: this.currentDurationMs,\n size: this.currentSize,\n interval: this.currentInterval,\n intervalAnalysis: this.currentIntervalAnalysis,\n mimeType: `audio/${this.extension}`,\n compression: this.recordingConfig?.compression?.enabled\n ? {\n size: this.totalCompressedSize,\n mimeType: 'audio/webm',\n format: this.recordingConfig.compression.format ?? 'opus',\n bitrate:\n this.recordingConfig.compression.bitrate ?? 128000,\n compressedFileUri: `${this.streamUuid}.webm`,\n }\n : undefined,\n }\n return status\n }\n}\n"]}
@@ -1,3 +0,0 @@
1
- declare let ExpoAudioStreamModule: any;
2
- export default ExpoAudioStreamModule;
3
- //# sourceMappingURL=ExpoAudioStreamModule.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ExpoAudioStreamModule.d.ts","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.ts"],"names":[],"mappings":"AAiBA,QAAA,IAAI,qBAAqB,EAAE,GAAG,CAAA;AA4Q9B,eAAe,qBAAqB,CAAA"}
@@ -1,239 +0,0 @@
1
- import crc32 from 'crc-32';
2
- import { requireNativeModule } from 'expo-modules-core';
3
- import { Platform } from 'react-native';
4
- import { ExpoAudioStreamWeb, } from './ExpoAudioStream.web';
5
- import { processAudioBuffer } from './utils/audioProcessing';
6
- import { writeWavHeader } from './utils/writeWavHeader';
7
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
- let ExpoAudioStreamModule;
9
- if (Platform.OS === 'web') {
10
- let instance = null;
11
- ExpoAudioStreamModule = (webProps) => {
12
- if (!instance) {
13
- instance = new ExpoAudioStreamWeb(webProps);
14
- }
15
- return instance;
16
- };
17
- ExpoAudioStreamModule.requestPermissionsAsync = async () => {
18
- try {
19
- const stream = await navigator.mediaDevices.getUserMedia({
20
- audio: true,
21
- });
22
- stream.getTracks().forEach((track) => track.stop());
23
- return {
24
- status: 'granted',
25
- expires: 'never',
26
- canAskAgain: true,
27
- granted: true,
28
- };
29
- }
30
- catch {
31
- return {
32
- status: 'denied',
33
- expires: 'never',
34
- canAskAgain: true,
35
- granted: false,
36
- };
37
- }
38
- };
39
- ExpoAudioStreamModule.getPermissionsAsync = async () => {
40
- let maybeStatus = null;
41
- if (navigator?.permissions?.query) {
42
- try {
43
- const { state } = await navigator.permissions.query({
44
- name: 'microphone',
45
- });
46
- maybeStatus = state;
47
- }
48
- catch {
49
- maybeStatus = null;
50
- }
51
- }
52
- switch (maybeStatus) {
53
- case 'granted':
54
- return {
55
- status: 'granted',
56
- expires: 'never',
57
- canAskAgain: true,
58
- granted: true,
59
- };
60
- case 'denied':
61
- return {
62
- status: 'denied',
63
- expires: 'never',
64
- canAskAgain: true,
65
- granted: false,
66
- };
67
- default:
68
- return await ExpoAudioStreamModule.requestPermissionsAsync();
69
- }
70
- };
71
- ExpoAudioStreamModule.extractAudioData = async (options) => {
72
- try {
73
- const { fileUri, position, length, startTimeMs, endTimeMs, decodingOptions, includeNormalizedData, includeBase64Data, includeWavHeader = false, logger, } = options;
74
- logger?.debug('EXTRACT AUDIO - Step 1: Initial request', {
75
- fileUri,
76
- extractionParams: {
77
- position,
78
- length,
79
- startTimeMs,
80
- endTimeMs,
81
- },
82
- decodingOptions: {
83
- targetSampleRate: decodingOptions?.targetSampleRate ?? 16000,
84
- targetChannels: decodingOptions?.targetChannels ?? 1,
85
- targetBitDepth: decodingOptions?.targetBitDepth ?? 16,
86
- normalizeAudio: decodingOptions?.normalizeAudio ?? false,
87
- },
88
- outputOptions: {
89
- includeNormalizedData,
90
- includeBase64Data,
91
- includeWavHeader,
92
- },
93
- });
94
- // Process the audio using shared helper function
95
- const processedBuffer = await processAudioBuffer({
96
- fileUri,
97
- targetSampleRate: decodingOptions?.targetSampleRate ?? 16000,
98
- targetChannels: decodingOptions?.targetChannels ?? 1,
99
- normalizeAudio: decodingOptions?.normalizeAudio ?? false,
100
- position,
101
- length,
102
- startTimeMs,
103
- endTimeMs,
104
- logger,
105
- });
106
- logger?.debug('EXTRACT AUDIO - Step 2: Audio processing complete', {
107
- processedData: {
108
- samples: processedBuffer.samples,
109
- sampleRate: processedBuffer.sampleRate,
110
- channels: processedBuffer.channels,
111
- durationMs: processedBuffer.durationMs,
112
- },
113
- });
114
- const channelData = processedBuffer.channelData;
115
- const bitDepth = (decodingOptions?.targetBitDepth ?? 16);
116
- const bytesPerSample = bitDepth / 8;
117
- const numSamples = processedBuffer.samples;
118
- logger?.debug('EXTRACT AUDIO - Step 3: PCM conversion setup', {
119
- channelData: {
120
- length: channelData.length,
121
- first: channelData[0],
122
- last: channelData[channelData.length - 1],
123
- },
124
- calculation: {
125
- bitDepth,
126
- bytesPerSample,
127
- numSamples,
128
- expectedBytes: numSamples * bytesPerSample,
129
- },
130
- });
131
- // Create PCM data with correct length based on original byte length
132
- const pcmData = new Uint8Array(numSamples * bytesPerSample);
133
- let offset = 0;
134
- // Convert Float32 samples to PCM format
135
- for (let i = 0; i < numSamples; i++) {
136
- const sample = channelData[i];
137
- const value = Math.max(-1, Math.min(1, sample));
138
- // Convert to 16-bit signed integer
139
- let intValue = Math.round(value * 32767);
140
- // Handle negative values correctly
141
- if (intValue < 0) {
142
- intValue = 65536 + intValue;
143
- }
144
- // Write as little-endian
145
- pcmData[offset++] = intValue & 255; // Low byte
146
- pcmData[offset++] = (intValue >> 8) & 255; // High byte
147
- }
148
- const durationMs = Math.round((numSamples / processedBuffer.sampleRate) * 1000);
149
- logger?.debug('EXTRACT AUDIO - Step 4: Final output', {
150
- pcmData: {
151
- length: pcmData.length,
152
- first: pcmData[0],
153
- last: pcmData[pcmData.length - 1],
154
- },
155
- timing: {
156
- numSamples,
157
- sampleRate: processedBuffer.sampleRate,
158
- durationMs,
159
- shouldBe3000ms: endTimeMs
160
- ? endTimeMs - (startTimeMs ?? 0) === 3000
161
- : undefined,
162
- },
163
- });
164
- const result = {
165
- pcmData: new Uint8Array(pcmData.buffer),
166
- sampleRate: processedBuffer.sampleRate,
167
- channels: processedBuffer.channels,
168
- bitDepth,
169
- durationMs,
170
- format: `pcm_${bitDepth}bit`,
171
- samples: numSamples,
172
- };
173
- // Add WAV header if requested
174
- if (includeWavHeader) {
175
- logger?.debug('EXTRACT AUDIO - Step 4: Adding WAV header', {
176
- originalLength: pcmData.length,
177
- newLength: result.pcmData.length,
178
- firstBytes: Array.from(result.pcmData.slice(0, 44)), // WAV header is 44 bytes
179
- });
180
- const wavBuffer = writeWavHeader({
181
- buffer: pcmData.buffer.slice(0, pcmData.length),
182
- sampleRate: processedBuffer.sampleRate,
183
- numChannels: processedBuffer.channels,
184
- bitDepth,
185
- });
186
- result.pcmData = new Uint8Array(wavBuffer);
187
- result.hasWavHeader = true;
188
- }
189
- if (includeNormalizedData) {
190
- // // Simple approach: Create normalized data directly from the PCM data
191
- // // Just convert to -1 to 1 range without any amplification
192
- // const normalizedData = new Float32Array(numSamples)
193
- // // Convert the PCM data to float values
194
- // for (let i = 0; i < numSamples; i++) {
195
- // // Get the 16-bit PCM value (little endian)
196
- // const lowByte = pcmData[i * 2]
197
- // const highByte = pcmData[i * 2 + 1]
198
- // const pcmValue = (highByte << 8) | lowByte
199
- // // Convert to signed 16-bit value
200
- // const signedValue =
201
- // pcmValue > 32767 ? pcmValue - 65536 : pcmValue
202
- // // Normalize to float between -1 and 1
203
- // normalizedData[i] = signedValue / 32768.0
204
- // }
205
- // Store the normalized data in the result
206
- result.normalizedData = channelData;
207
- }
208
- if (includeBase64Data) {
209
- // Convert the PCM data to a base64 string
210
- const binary = Array.from(new Uint8Array(pcmData.buffer))
211
- .map((b) => String.fromCharCode(b))
212
- .join('');
213
- result.base64Data = btoa(binary);
214
- }
215
- if (options.computeChecksum) {
216
- result.checksum = crc32.buf(pcmData);
217
- }
218
- logger?.debug('EXTRACT AUDIO - Step 3: PCM conversion complete', {
219
- pcmStats: {
220
- length: pcmData.length,
221
- bytesPerSample,
222
- totalSamples: numSamples,
223
- firstBytes: Array.from(pcmData.slice(0, 16)),
224
- lastBytes: Array.from(pcmData.slice(-16)),
225
- },
226
- });
227
- return result;
228
- }
229
- catch (error) {
230
- options.logger?.error('EXTRACT AUDIO - Error:', error);
231
- throw error;
232
- }
233
- };
234
- }
235
- else {
236
- ExpoAudioStreamModule = requireNativeModule('ExpoAudioStream');
237
- }
238
- export default ExpoAudioStreamModule;
239
- //# sourceMappingURL=ExpoAudioStreamModule.js.map