@siteed/expo-audio-stream 0.5.2 → 0.7.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 (29) 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 +39 -430
  8. package/android/src/main/java/net/siteed/audiostream/PermissionUtils.kt +16 -0
  9. package/build/ExpoAudioStream.types.d.ts +5 -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.map +1 -1
  15. package/build/index.d.ts +1 -0
  16. package/build/index.d.ts.map +1 -1
  17. package/build/index.js +3 -0
  18. package/build/index.js.map +1 -1
  19. package/build/useAudioRecording.d.ts +4 -2
  20. package/build/useAudioRecording.d.ts.map +1 -1
  21. package/build/useAudioRecording.js +18 -13
  22. package/build/useAudioRecording.js.map +1 -1
  23. package/ios/AudioStreamManager.swift +26 -21
  24. package/ios/ExpoAudioStreamModule.swift +12 -6
  25. package/package.json +1 -1
  26. package/src/ExpoAudioStream.types.ts +6 -5
  27. package/src/ExpoAudioStreamModule.web.ts +2 -2
  28. package/src/index.ts +4 -0
  29. package/src/useAudioRecording.ts +25 -18
@@ -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"]}
@@ -1,14 +1,16 @@
1
- import { AudioStreamResult, RecordingOptions, StartAudioStreamResult } from "./ExpoAudioStream.types";
1
+ import { AudioStreamResult, RecordingConfig, StartAudioStreamResult } from "./ExpoAudioStream.types";
2
2
  export interface AudioDataEvent {
3
3
  data: string | Blob;
4
4
  position: number;
5
+ fileUri: string;
5
6
  eventDataSize: number;
6
7
  totalSize: number;
7
8
  }
8
9
  export interface UseAudioRecorderState {
9
- startRecording: (_: RecordingOptions) => Promise<StartAudioStreamResult>;
10
+ startRecording: (_: RecordingConfig) => Promise<StartAudioStreamResult>;
10
11
  stopRecording: () => Promise<AudioStreamResult | null>;
11
12
  pauseRecording: () => void;
13
+ resumeRecording: () => void;
12
14
  isRecording: boolean;
13
15
  isPaused: boolean;
14
16
  duration: number;
@@ -1 +1 @@
1
- {"version":3,"file":"useAudioRecording.d.ts","sourceRoot":"","sources":["../src/useAudioRecording.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,iBAAiB,EAEjB,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,yBAAyB,CAAC;AAGjC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,CAAC,CAAC,EAAE,gBAAgB,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACzE,aAAa,EAAE,MAAM,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACvD,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,aAAa,EACb,KAAa,GACd,EAAE;IACD,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,qBAAqB,CA0MxB"}
1
+ {"version":3,"file":"useAudioRecording.d.ts","sourceRoot":"","sources":["../src/useAudioRecording.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,iBAAiB,EAEjB,eAAe,EACf,sBAAsB,EACvB,MAAM,yBAAyB,CAAC;AAGjC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,CAAC,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACxE,aAAa,EAAE,MAAM,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACvD,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,aAAa,EACb,KAAa,GACd,EAAE;IACD,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,qBAAqB,CA+MxB"}
@@ -73,6 +73,7 @@ export function useAudioRecorder({ onAudioStream, debug = false, }) {
73
73
  onAudioStream?.({
74
74
  data: encoded,
75
75
  position,
76
+ fileUri,
76
77
  eventDataSize: deltaSize,
77
78
  totalSize,
78
79
  });
@@ -101,6 +102,7 @@ export function useAudioRecorder({ onAudioStream, debug = false, }) {
101
102
  onAudioStream?.({
102
103
  data: buffer,
103
104
  position,
105
+ fileUri,
104
106
  eventDataSize: deltaSize,
105
107
  totalSize,
106
108
  });
@@ -126,29 +128,31 @@ export function useAudioRecorder({ onAudioStream, debug = false, }) {
126
128
  setIsPaused(false);
127
129
  setSize(0);
128
130
  setDuration(0);
129
- try {
130
- if (debug) {
131
- console.log(`[useAudioRecorder] start recoding`, recordingOptions);
132
- }
133
- const fileUrl = await ExpoAudioStreamModule.startRecording(recordingOptions);
134
- return fileUrl;
135
- }
136
- catch (error) {
137
- console.error("[useAudioRecorder] Error starting recording:", error);
138
- setIsRecording(false);
131
+ if (debug) {
132
+ console.log(`[useAudioRecorder] start recoding`, recordingOptions);
139
133
  }
134
+ const result = await ExpoAudioStreamModule.startRecording(recordingOptions);
135
+ return result;
140
136
  }, [debug]);
141
137
  const stopRecording = useCallback(async () => {
142
- console.log(`STOOOOOP NOW`);
143
138
  const result = await ExpoAudioStreamModule.stopRecording();
144
- console.log(`STOOOOOP NOW 2`);
145
139
  setIsRecording(false);
146
140
  setIsPaused(false);
147
141
  return result;
148
142
  }, []);
149
143
  const pauseRecording = useCallback(async () => {
150
144
  try {
151
- await ExpoAudioStreamModule.stopRecording();
145
+ await ExpoAudioStreamModule.pauseRecording();
146
+ setIsPaused(true);
147
+ setIsRecording(false);
148
+ }
149
+ catch (error) {
150
+ console.error("[useAudioRecorder] Error pausing recording:", error);
151
+ }
152
+ }, [debug]);
153
+ const resumeRecording = useCallback(async () => {
154
+ try {
155
+ await ExpoAudioStreamModule.resumeRecording();
152
156
  setIsPaused(true);
153
157
  setIsRecording(false);
154
158
  }
@@ -160,6 +164,7 @@ export function useAudioRecorder({ onAudioStream, debug = false, }) {
160
164
  startRecording,
161
165
  stopRecording,
162
166
  pauseRecording,
167
+ resumeRecording,
163
168
  isPaused,
164
169
  isRecording,
165
170
  duration,
@@ -1 +1 @@
1
- {"version":3,"file":"useAudioRecording.js","sourceRoot":"","sources":["../src/useAudioRecording.ts"],"names":[],"mappings":"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","sourcesContent":["import { Platform } from \"expo-modules-core\";\nimport { useCallback, useEffect, useState } from \"react\";\n\nimport { addAudioEventListener } from \".\";\nimport {\n AudioStreamResult,\n AudioStreamStatus,\n RecordingOptions,\n StartAudioStreamResult,\n} from \"./ExpoAudioStream.types\";\nimport ExpoAudioStreamModule from \"./ExpoAudioStreamModule\";\n\nexport interface AudioDataEvent {\n data: string | Blob;\n position: number;\n eventDataSize: number;\n totalSize: number;\n}\nexport interface UseAudioRecorderState {\n startRecording: (_: RecordingOptions) => Promise<StartAudioStreamResult>;\n stopRecording: () => Promise<AudioStreamResult | null>;\n pauseRecording: () => void;\n isRecording: boolean;\n isPaused: boolean;\n duration: number; // Duration of the recording\n size: number; // Size in bytes of the recorded audio\n}\n\nexport function useAudioRecorder({\n onAudioStream,\n debug = false,\n}: {\n onAudioStream?: (_: AudioDataEvent) => Promise<void>;\n debug?: boolean;\n}): UseAudioRecorderState {\n const [isRecording, setIsRecording] = useState(false);\n const [isPaused, setIsPaused] = useState(false);\n const [duration, setDuration] = useState(0);\n const [size, setSize] = useState(0);\n\n const checkStatus = useCallback(async () => {\n try {\n if (!isRecording) {\n return;\n }\n\n const status: AudioStreamStatus = ExpoAudioStreamModule.status();\n if (debug) {\n console.log(`[useAudioRecorder] Status:`, status);\n }\n\n if (!status.isRecording) {\n // Don't update if recording stopped.\n return;\n }\n // Extract matching file from filesystem\n setDuration(status.duration);\n setSize(status.size);\n } catch (error) {\n console.error(`[useAudioRecorder] Error getting status:`, error);\n }\n }, [isRecording]);\n\n useEffect(() => {\n const interval = setInterval(checkStatus, 1000);\n return () => clearInterval(interval);\n }, [checkStatus]);\n\n useEffect(() => {\n if (debug) {\n console.log(\n `[useAudioRecorder] Registering audio event listener`,\n onAudioStream,\n );\n }\n const subscribe = addAudioEventListener(\n async ({\n fileUri,\n deltaSize,\n totalSize,\n lastEmittedSize,\n position,\n streamUuid,\n encoded,\n mimeType,\n buffer,\n }) => {\n try {\n if (debug) {\n console.log(`[useAudioRecorder] Received audio event:`, {\n fileUri,\n deltaSize,\n totalSize,\n position,\n mimeType,\n lastEmittedSize,\n streamUuid,\n encodedLength: encoded?.length,\n });\n }\n if (deltaSize > 0) {\n // Coming from native ( ios / android ) otherwise buffer is set\n if (Platform.OS !== \"web\") {\n // Read the audio file as a base64 string for comparison\n try {\n if (!encoded) {\n console.error(\n \"[useAudioRecorder] Encoded audio data is missing\",\n );\n throw new Error(\"Encoded audio data is missing\");\n }\n // const binaryData = atob(encoded);\n // const bytes = new Uint8Array(binaryData.length);\n // for (let i = 0; i < binaryData.length; i++) {\n // bytes[i] = binaryData.charCodeAt(i) & 0xff; // Mask to 8 bits\n // }\n // const arrayBuffer = bytes.buffer;\n\n // if (debug) {\n // console.log(\n // `[useAudioRecorder] Read audio file position=${position} deltaSize: ${deltaSize} vs encoded.length: ${encoded.length}`,\n // );\n // }\n\n onAudioStream?.({\n data: encoded,\n position,\n eventDataSize: deltaSize,\n totalSize,\n });\n\n // Below code is optional, used to compare encoded data to audio on file system\n // Fetch the audio data from the fileUri\n // const options = {\n // encoding: FileSystem.EncodingType.Base64,\n // position: lastEmittedSize,\n // length: deltaSize,\n // };\n // const base64Content = await FileSystem.readAsStringAsync(fileUri, options);\n // const binaryData = atob(base64Content);\n // const content = new Uint8Array(binaryData.length);\n // for (let i = 0; i < binaryData.length; i++) {\n // content[i] = binaryData.charCodeAt(i);\n // }\n // const audioBlob = new Blob([content], { type: 'application/octet-stream' }); // Create a Blob from the byte array\n // console.debug(`Read audio file (len: ${content.length}) vs ${deltaSize}`)\n } catch (error) {\n console.error(\n \"[useAudioRecorder] Error reading audio file:\",\n error,\n );\n }\n } else if (buffer) {\n // Coming from web\n onAudioStream?.({\n data: buffer,\n position,\n eventDataSize: deltaSize,\n totalSize,\n });\n }\n }\n } catch (error) {\n console.error(\n \"[useAudioRecorder] Error processing audio event:\",\n error,\n );\n }\n },\n );\n if (debug) {\n console.log(\n `[useAudioRecorder] Subscribed to audio event listener`,\n subscribe,\n );\n }\n return () => {\n if (debug) {\n console.log(`[useAudioRecorder] Removing audio event listener`);\n }\n subscribe.remove();\n };\n }, []);\n\n const startRecording = useCallback(\n async (recordingOptions: RecordingOptions) => {\n setIsRecording(true);\n setIsPaused(false);\n setSize(0);\n setDuration(0);\n try {\n if (debug) {\n console.log(`[useAudioRecorder] start recoding`, recordingOptions);\n }\n\n const fileUrl =\n await ExpoAudioStreamModule.startRecording(recordingOptions);\n\n return fileUrl;\n } catch (error) {\n console.error(\"[useAudioRecorder] Error starting recording:\", error);\n setIsRecording(false);\n }\n },\n [debug],\n );\n\n const stopRecording = useCallback(async () => {\n console.log(`STOOOOOP NOW`);\n const result: AudioStreamResult =\n await ExpoAudioStreamModule.stopRecording();\n console.log(`STOOOOOP NOW 2`);\n setIsRecording(false);\n setIsPaused(false);\n return result;\n }, []);\n\n const pauseRecording = useCallback(async () => {\n try {\n await ExpoAudioStreamModule.stopRecording();\n setIsPaused(true);\n setIsRecording(false);\n } catch (error) {\n console.error(\"[useAudioRecorder] Error pausing recording:\", error);\n }\n }, [debug]);\n\n return {\n startRecording,\n stopRecording,\n pauseRecording,\n isPaused,\n isRecording,\n duration,\n size,\n };\n}\n"]}
1
+ {"version":3,"file":"useAudioRecording.js","sourceRoot":"","sources":["../src/useAudioRecording.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,GAAG,CAAC;AAO1C,OAAO,qBAAqB,MAAM,yBAAyB,CAAC;AAoB5D,MAAM,UAAU,gBAAgB,CAAC,EAC/B,aAAa,EACb,KAAK,GAAG,KAAK,GAId;IACC,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEpC,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACzC,IAAI,CAAC;YACH,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAsB,qBAAqB,CAAC,MAAM,EAAE,CAAC;YACjE,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,CAAC,GAAG,CAAC,4BAA4B,EAAE,MAAM,CAAC,CAAC;YACpD,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;gBACxB,qCAAqC;gBACrC,OAAO;YACT,CAAC;YACD,wCAAwC;YACxC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC7B,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAC;QACnE,CAAC;IACH,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAChD,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CACT,qDAAqD,EACrD,aAAa,CACd,CAAC;QACJ,CAAC;QACD,MAAM,SAAS,GAAG,qBAAqB,CACrC,KAAK,EAAE,EACL,OAAO,EACP,SAAS,EACT,SAAS,EACT,eAAe,EACf,QAAQ,EACR,UAAU,EACV,OAAO,EACP,QAAQ,EACR,MAAM,GACP,EAAE,EAAE;YACH,IAAI,CAAC;gBACH,IAAI,KAAK,EAAE,CAAC;oBACV,OAAO,CAAC,GAAG,CAAC,0CAA0C,EAAE;wBACtD,OAAO;wBACP,SAAS;wBACT,SAAS;wBACT,QAAQ;wBACR,QAAQ;wBACR,eAAe;wBACf,UAAU;wBACV,aAAa,EAAE,OAAO,EAAE,MAAM;qBAC/B,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;oBAClB,+DAA+D;oBAC/D,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;wBAC1B,wDAAwD;wBACxD,IAAI,CAAC;4BACH,IAAI,CAAC,OAAO,EAAE,CAAC;gCACb,OAAO,CAAC,KAAK,CACX,kDAAkD,CACnD,CAAC;gCACF,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;4BACnD,CAAC;4BACD,oCAAoC;4BACpC,mDAAmD;4BACnD,gDAAgD;4BAChD,kEAAkE;4BAClE,IAAI;4BACJ,oCAAoC;4BAEpC,eAAe;4BACf,iBAAiB;4BACjB,8HAA8H;4BAC9H,OAAO;4BACP,IAAI;4BAEJ,aAAa,EAAE,CAAC;gCACd,IAAI,EAAE,OAAO;gCACb,QAAQ;gCACR,OAAO;gCACP,aAAa,EAAE,SAAS;gCACxB,SAAS;6BACV,CAAC,CAAC;4BAEH,+EAA+E;4BAC/E,wCAAwC;4BACxC,oBAAoB;4BACpB,gDAAgD;4BAChD,iCAAiC;4BACjC,yBAAyB;4BACzB,KAAK;4BACL,8EAA8E;4BAC9E,0CAA0C;4BAC1C,qDAAqD;4BACrD,gDAAgD;4BAChD,yCAAyC;4BACzC,IAAI;4BACJ,oHAAoH;4BACpH,4EAA4E;wBAC9E,CAAC;wBAAC,OAAO,KAAK,EAAE,CAAC;4BACf,OAAO,CAAC,KAAK,CACX,8CAA8C,EAC9C,KAAK,CACN,CAAC;wBACJ,CAAC;oBACH,CAAC;yBAAM,IAAI,MAAM,EAAE,CAAC;wBAClB,kBAAkB;wBAClB,aAAa,EAAE,CAAC;4BACd,IAAI,EAAE,MAAM;4BACZ,QAAQ;4BACR,OAAO;4BACP,aAAa,EAAE,SAAS;4BACxB,SAAS;yBACV,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CACX,kDAAkD,EAClD,KAAK,CACN,CAAC;YACJ,CAAC;QACH,CAAC,CACF,CAAC;QACF,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CACT,uDAAuD,EACvD,SAAS,CACV,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,EAAE;YACV,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;YAClE,CAAC;YACD,SAAS,CAAC,MAAM,EAAE,CAAC;QACrB,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,cAAc,GAAG,WAAW,CAChC,KAAK,EAAE,gBAAiC,EAAE,EAAE;QAC1C,cAAc,CAAC,IAAI,CAAC,CAAC;QACrB,WAAW,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO,CAAC,CAAC,CAAC,CAAC;QACX,WAAW,CAAC,CAAC,CAAC,CAAC;QACf,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,mCAAmC,EAAE,gBAAgB,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,MAAM,GACV,MAAM,qBAAqB,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;QAC/D,OAAO,MAAM,CAAC;IAChB,CAAC,EACD,CAAC,KAAK,CAAC,CACR,CAAC;IAEF,MAAM,aAAa,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC3C,MAAM,MAAM,GACV,MAAM,qBAAqB,CAAC,aAAa,EAAE,CAAC;QAC9C,cAAc,CAAC,KAAK,CAAC,CAAC;QACtB,WAAW,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO,MAAM,CAAC;IAChB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC5C,IAAI,CAAC;YACH,MAAM,qBAAqB,CAAC,cAAc,EAAE,CAAC;YAC7C,WAAW,CAAC,IAAI,CAAC,CAAC;YAClB,cAAc,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6CAA6C,EAAE,KAAK,CAAC,CAAC;QACtE,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,MAAM,eAAe,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC7C,IAAI,CAAC;YACH,MAAM,qBAAqB,CAAC,eAAe,EAAE,CAAC;YAC9C,WAAW,CAAC,IAAI,CAAC,CAAC;YAClB,cAAc,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6CAA6C,EAAE,KAAK,CAAC,CAAC;QACtE,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,OAAO;QACL,cAAc;QACd,aAAa;QACb,cAAc;QACd,eAAe;QACf,QAAQ;QACR,WAAW;QACX,QAAQ;QACR,IAAI;KACL,CAAC;AACJ,CAAC","sourcesContent":["import { Platform } from \"expo-modules-core\";\nimport { useCallback, useEffect, useState } from \"react\";\n\nimport { addAudioEventListener } from \".\";\nimport {\n AudioStreamResult,\n AudioStreamStatus,\n RecordingConfig,\n StartAudioStreamResult,\n} from \"./ExpoAudioStream.types\";\nimport ExpoAudioStreamModule from \"./ExpoAudioStreamModule\";\n\nexport interface AudioDataEvent {\n data: string | Blob;\n position: number;\n fileUri: string;\n eventDataSize: number;\n totalSize: number;\n}\nexport interface UseAudioRecorderState {\n startRecording: (_: RecordingConfig) => Promise<StartAudioStreamResult>;\n stopRecording: () => Promise<AudioStreamResult | null>;\n pauseRecording: () => void;\n resumeRecording: () => void;\n isRecording: boolean;\n isPaused: boolean;\n duration: number; // Duration of the recording\n size: number; // Size in bytes of the recorded audio\n}\n\nexport function useAudioRecorder({\n onAudioStream,\n debug = false,\n}: {\n onAudioStream?: (_: AudioDataEvent) => Promise<void>;\n debug?: boolean;\n}): UseAudioRecorderState {\n const [isRecording, setIsRecording] = useState(false);\n const [isPaused, setIsPaused] = useState(false);\n const [duration, setDuration] = useState(0);\n const [size, setSize] = useState(0);\n\n const checkStatus = useCallback(async () => {\n try {\n if (!isRecording) {\n return;\n }\n\n const status: AudioStreamStatus = ExpoAudioStreamModule.status();\n if (debug) {\n console.log(`[useAudioRecorder] Status:`, status);\n }\n\n if (!status.isRecording) {\n // Don't update if recording stopped.\n return;\n }\n // Extract matching file from filesystem\n setDuration(status.duration);\n setSize(status.size);\n } catch (error) {\n console.error(`[useAudioRecorder] Error getting status:`, error);\n }\n }, [isRecording]);\n\n useEffect(() => {\n const interval = setInterval(checkStatus, 1000);\n return () => clearInterval(interval);\n }, [checkStatus]);\n\n useEffect(() => {\n if (debug) {\n console.log(\n `[useAudioRecorder] Registering audio event listener`,\n onAudioStream,\n );\n }\n const subscribe = addAudioEventListener(\n async ({\n fileUri,\n deltaSize,\n totalSize,\n lastEmittedSize,\n position,\n streamUuid,\n encoded,\n mimeType,\n buffer,\n }) => {\n try {\n if (debug) {\n console.log(`[useAudioRecorder] Received audio event:`, {\n fileUri,\n deltaSize,\n totalSize,\n position,\n mimeType,\n lastEmittedSize,\n streamUuid,\n encodedLength: encoded?.length,\n });\n }\n if (deltaSize > 0) {\n // Coming from native ( ios / android ) otherwise buffer is set\n if (Platform.OS !== \"web\") {\n // Read the audio file as a base64 string for comparison\n try {\n if (!encoded) {\n console.error(\n \"[useAudioRecorder] Encoded audio data is missing\",\n );\n throw new Error(\"Encoded audio data is missing\");\n }\n // const binaryData = atob(encoded);\n // const bytes = new Uint8Array(binaryData.length);\n // for (let i = 0; i < binaryData.length; i++) {\n // bytes[i] = binaryData.charCodeAt(i) & 0xff; // Mask to 8 bits\n // }\n // const arrayBuffer = bytes.buffer;\n\n // if (debug) {\n // console.log(\n // `[useAudioRecorder] Read audio file position=${position} deltaSize: ${deltaSize} vs encoded.length: ${encoded.length}`,\n // );\n // }\n\n onAudioStream?.({\n data: encoded,\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n });\n\n // Below code is optional, used to compare encoded data to audio on file system\n // Fetch the audio data from the fileUri\n // const options = {\n // encoding: FileSystem.EncodingType.Base64,\n // position: lastEmittedSize,\n // length: deltaSize,\n // };\n // const base64Content = await FileSystem.readAsStringAsync(fileUri, options);\n // const binaryData = atob(base64Content);\n // const content = new Uint8Array(binaryData.length);\n // for (let i = 0; i < binaryData.length; i++) {\n // content[i] = binaryData.charCodeAt(i);\n // }\n // const audioBlob = new Blob([content], { type: 'application/octet-stream' }); // Create a Blob from the byte array\n // console.debug(`Read audio file (len: ${content.length}) vs ${deltaSize}`)\n } catch (error) {\n console.error(\n \"[useAudioRecorder] Error reading audio file:\",\n error,\n );\n }\n } else if (buffer) {\n // Coming from web\n onAudioStream?.({\n data: buffer,\n position,\n fileUri,\n eventDataSize: deltaSize,\n totalSize,\n });\n }\n }\n } catch (error) {\n console.error(\n \"[useAudioRecorder] Error processing audio event:\",\n error,\n );\n }\n },\n );\n if (debug) {\n console.log(\n `[useAudioRecorder] Subscribed to audio event listener`,\n subscribe,\n );\n }\n return () => {\n if (debug) {\n console.log(`[useAudioRecorder] Removing audio event listener`);\n }\n subscribe.remove();\n };\n }, []);\n\n const startRecording = useCallback(\n async (recordingOptions: RecordingConfig) => {\n setIsRecording(true);\n setIsPaused(false);\n setSize(0);\n setDuration(0);\n if (debug) {\n console.log(`[useAudioRecorder] start recoding`, recordingOptions);\n }\n\n const result: StartAudioStreamResult =\n await ExpoAudioStreamModule.startRecording(recordingOptions);\n return result;\n },\n [debug],\n );\n\n const stopRecording = useCallback(async () => {\n const result: AudioStreamResult =\n await ExpoAudioStreamModule.stopRecording();\n setIsRecording(false);\n setIsPaused(false);\n return result;\n }, []);\n\n const pauseRecording = useCallback(async () => {\n try {\n await ExpoAudioStreamModule.pauseRecording();\n setIsPaused(true);\n setIsRecording(false);\n } catch (error) {\n console.error(\"[useAudioRecorder] Error pausing recording:\", error);\n }\n }, [debug]);\n\n const resumeRecording = useCallback(async () => {\n try {\n await ExpoAudioStreamModule.resumeRecording();\n setIsPaused(true);\n setIsRecording(false);\n } catch (error) {\n console.error(\"[useAudioRecorder] Error pausing recording:\", error);\n }\n }, [debug]);\n\n return {\n startRecording,\n stopRecording,\n pauseRecording,\n resumeRecording,\n isPaused,\n isRecording,\n duration,\n size,\n };\n}\n"]}
@@ -76,9 +76,9 @@ class AudioStreamManager: NSObject {
76
76
  internal var recordingSettings: RecordingSettings?
77
77
  internal var recordingUUID: UUID?
78
78
  internal var mimeType: String = "audio/wav"
79
- private var lastBuffer: AVAudioPCMBuffer?
80
79
  private var lastBufferTime: AVAudioTime?
81
-
80
+ private var accumulatedData = Data()
81
+
82
82
  weak var delegate: AudioStreamManagerDelegate? // Define the delegate here
83
83
 
84
84
  override init() {
@@ -113,16 +113,9 @@ class AudioStreamManager: NSObject {
113
113
  let fileName = "\(recordingUUID!.uuidString).wav"
114
114
  let fileURL = documentsDirectory.appendingPathComponent(fileName)
115
115
 
116
- if fileManager.createFile(atPath: fileURL.path, contents: nil, attributes: nil) {
117
- do {
118
- let fileHandle = try FileHandle(forWritingTo: fileURL)
119
- let wavHeader = createWavHeader(dataSize: 0) // Initially set data size to 0
120
- fileHandle.write(wavHeader)
121
- fileHandle.closeFile()
122
- } catch {
123
- Logger.debug("Failed to write WAV header: \(error.localizedDescription)")
124
- return nil
125
- }
116
+ if !fileManager.createFile(atPath: fileURL.path, contents: nil, attributes: nil) {
117
+ Logger.debug("Failed to create file at: \(fileURL.path)")
118
+ return nil
126
119
  }
127
120
  return fileURL
128
121
  }
@@ -215,6 +208,8 @@ class AudioStreamManager: NSObject {
215
208
 
216
209
  emissionInterval = max(100.0, Double(intervalMilliseconds)) / 1000.0
217
210
  lastEmissionTime = Date()
211
+ accumulatedData.removeAll()
212
+ totalDataSize = 0
218
213
 
219
214
  let session = AVAudioSession.sharedInstance()
220
215
  do {
@@ -247,9 +242,6 @@ class AudioStreamManager: NSObject {
247
242
 
248
243
  // Processing the current buffer
249
244
  self.processAudioBuffer(buffer, fileURL: self.recordingFileURL!)
250
-
251
- // Store the buffer and time as the last buffer and time
252
- self.lastBuffer = buffer
253
245
  self.lastBufferTime = time
254
246
  }
255
247
 
@@ -309,9 +301,12 @@ class AudioStreamManager: NSObject {
309
301
  return nil
310
302
  }
311
303
 
312
- // Ensure all remaining audio data is sent
313
- if let lastBuffer = lastBuffer, let lastBufferTime = lastBufferTime {
314
- self.processAudioBuffer(lastBuffer, fileURL: fileURL)
304
+ // Emit any remaining accumulated data
305
+ if !accumulatedData.isEmpty {
306
+ let currentTime = Date()
307
+ let recordingTime = currentTime.timeIntervalSince(startTime)
308
+ delegate?.audioStreamManager(self, didReceiveAudioData: accumulatedData, recordingTime: recordingTime, totalDataSize: totalDataSize)
309
+ accumulatedData.removeAll()
315
310
  }
316
311
 
317
312
  let endTime = Date()
@@ -336,7 +331,6 @@ class AudioStreamManager: NSObject {
336
331
  sampleRate: settings.sampleRate
337
332
  )
338
333
  recordingFileURL = nil // Reset for next recording
339
- lastBuffer = nil // Reset last buffer
340
334
  lastBufferTime = nil // Reset last buffer time
341
335
 
342
336
  return result
@@ -381,7 +375,17 @@ class AudioStreamManager: NSObject {
381
375
  print("Buffer data is nil.")
382
376
  return
383
377
  }
384
- let data = Data(bytes: bufferData, count: Int(audioData.mDataByteSize))
378
+ var data = Data(bytes: bufferData, count: Int(audioData.mDataByteSize))
379
+
380
+ // Check if this is the first buffer to process and totalDataSize is 0
381
+ if totalDataSize == 0 {
382
+ // Since it's the first buffer, prepend the WAV header
383
+ let header = createWavHeader(dataSize: 0) // Set initial dataSize to 0, update later
384
+ data.insert(contentsOf: header, at: 0)
385
+ }
386
+
387
+ // Accumulate new data
388
+ accumulatedData.append(data)
385
389
 
386
390
  // print("Writing data size: \(data.count) bytes") // Debug: Check the size of data being written
387
391
  fileHandle.seekToEndOfFile()
@@ -396,9 +400,10 @@ class AudioStreamManager: NSObject {
396
400
  if let startTime = startTime {
397
401
  let recordingTime = currentTime.timeIntervalSince(startTime)
398
402
  // print("Emitting data: Recording time \(recordingTime) seconds, Data size \(totalDataSize) bytes")
399
- self.delegate?.audioStreamManager(self, didReceiveAudioData: data, recordingTime: recordingTime, totalDataSize: totalDataSize)
403
+ self.delegate?.audioStreamManager(self, didReceiveAudioData: accumulatedData, recordingTime: recordingTime, totalDataSize: totalDataSize)
400
404
  self.lastEmissionTime = currentTime // Update last emission time
401
405
  self.lastEmittedSize = totalDataSize
406
+ accumulatedData.removeAll() // Reset accumulated data after emission
402
407
  }
403
408
  }
404
409
  }
@@ -31,9 +31,18 @@ public class ExpoAudioStreamModule: Module, AudioStreamManagerDelegate {
31
31
  let interval = options["interval"] as? Int ?? 1000
32
32
 
33
33
  let settings = RecordingSettings(sampleRate: sampleRate, numberOfChannels: numberOfChannels, bitDepth: bitDepth)
34
- let result = self.streamManager.startRecording(settings: settings, intervalMilliseconds: interval)
35
-
36
- promise.resolve(result)
34
+ if let result = self.streamManager.startRecording(settings: settings, intervalMilliseconds: interval) {
35
+ let resultDict: [String: Any] = [
36
+ "fileUri": result.fileUri,
37
+ "channels": result.channels,
38
+ "bitDepth": result.bitDepth,
39
+ "sampleRate": result.sampleRate,
40
+ "mimeType": result.mimeType,
41
+ ]
42
+ promise.resolve(resultDict)
43
+ } else {
44
+ promise.reject("ERROR", "Failed to start recording.")
45
+ }
37
46
  }
38
47
  }
39
48
 
@@ -97,9 +106,6 @@ public class ExpoAudioStreamModule: Module, AudioStreamManagerDelegate {
97
106
  "streamUuid": manager.recordingUUID?.uuidString ?? UUID().uuidString
98
107
  ]
99
108
 
100
- // Update the last emitted size for the next calculation
101
- manager.lastEmittedSize += Int64(deltaSize)
102
-
103
109
  // Emit the event to JavaScript
104
110
  sendEvent(audioDataEvent, eventBody)
105
111
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siteed/expo-audio-stream",
3
- "version": "0.5.2",
3
+ "version": "0.7.0",
4
4
  "description": "stream audio crossplatform",
5
5
  "license": "MIT",
6
6
  "main": "build/index.js",
@@ -37,10 +37,11 @@ export interface AudioStreamStatus {
37
37
  mimeType: string;
38
38
  }
39
39
 
40
- export interface RecordingOptions {
41
- // TODO align Android and IOS options
42
- // sampleRate?: number;
43
- // channelConfig?: number; // numberOfChannel
44
- // audioFormat?: number; // bitDepth (ENCODING_PCM_16BIT --> 2)
40
+ export type EncodingType = "pcm_16bit" | "pcm_8bit";
41
+
42
+ export interface RecordingConfig {
43
+ sampleRate?: 16000 | 44100 | 48000;
44
+ channels?: 1 | 2; // 1 or 2 MONO or STEREO
45
+ encoding?: EncodingType;
45
46
  interval?: number;
46
47
  }
@@ -4,7 +4,7 @@ import { EventEmitter } from "expo-modules-core";
4
4
  import {
5
5
  AudioEventPayload,
6
6
  AudioStreamResult,
7
- RecordingOptions,
7
+ RecordingConfig,
8
8
  StartAudioStreamResult,
9
9
  } from "./ExpoAudioStream.types";
10
10
 
@@ -59,7 +59,7 @@ class ExpoAudioStreamWeb extends EventEmitter {
59
59
  }
60
60
 
61
61
  // Start recording with options
62
- async startRecording(options: RecordingOptions = {}) {
62
+ async startRecording(options: RecordingConfig = {}) {
63
63
  if (this.isRecording) {
64
64
  throw new Error("Recording is already in progress");
65
65
  }
package/src/index.ts CHANGED
@@ -26,6 +26,10 @@ export function clearAudioFiles(): Promise<void> {
26
26
  return ExpoAudioStreamModule.clearAudioFiles();
27
27
  }
28
28
 
29
+ export function test(): void {
30
+ return ExpoAudioStreamModule.test();
31
+ }
32
+
29
33
  export function addAudioEventListener(
30
34
  listener: (event: AudioEventPayload) => Promise<void>,
31
35
  ): Subscription {
@@ -5,7 +5,7 @@ import { addAudioEventListener } from ".";
5
5
  import {
6
6
  AudioStreamResult,
7
7
  AudioStreamStatus,
8
- RecordingOptions,
8
+ RecordingConfig,
9
9
  StartAudioStreamResult,
10
10
  } from "./ExpoAudioStream.types";
11
11
  import ExpoAudioStreamModule from "./ExpoAudioStreamModule";
@@ -13,13 +13,15 @@ import ExpoAudioStreamModule from "./ExpoAudioStreamModule";
13
13
  export interface AudioDataEvent {
14
14
  data: string | Blob;
15
15
  position: number;
16
+ fileUri: string;
16
17
  eventDataSize: number;
17
18
  totalSize: number;
18
19
  }
19
20
  export interface UseAudioRecorderState {
20
- startRecording: (_: RecordingOptions) => Promise<StartAudioStreamResult>;
21
+ startRecording: (_: RecordingConfig) => Promise<StartAudioStreamResult>;
21
22
  stopRecording: () => Promise<AudioStreamResult | null>;
22
23
  pauseRecording: () => void;
24
+ resumeRecording: () => void;
23
25
  isRecording: boolean;
24
26
  isPaused: boolean;
25
27
  duration: number; // Duration of the recording
@@ -125,6 +127,7 @@ export function useAudioRecorder({
125
127
  onAudioStream?.({
126
128
  data: encoded,
127
129
  position,
130
+ fileUri,
128
131
  eventDataSize: deltaSize,
129
132
  totalSize,
130
133
  });
@@ -155,6 +158,7 @@ export function useAudioRecorder({
155
158
  onAudioStream?.({
156
159
  data: buffer,
157
160
  position,
161
+ fileUri,
158
162
  eventDataSize: deltaSize,
159
163
  totalSize,
160
164
  });
@@ -183,33 +187,25 @@ export function useAudioRecorder({
183
187
  }, []);
184
188
 
185
189
  const startRecording = useCallback(
186
- async (recordingOptions: RecordingOptions) => {
190
+ async (recordingOptions: RecordingConfig) => {
187
191
  setIsRecording(true);
188
192
  setIsPaused(false);
189
193
  setSize(0);
190
194
  setDuration(0);
191
- try {
192
- if (debug) {
193
- console.log(`[useAudioRecorder] start recoding`, recordingOptions);
194
- }
195
-
196
- const fileUrl =
197
- await ExpoAudioStreamModule.startRecording(recordingOptions);
198
-
199
- return fileUrl;
200
- } catch (error) {
201
- console.error("[useAudioRecorder] Error starting recording:", error);
202
- setIsRecording(false);
195
+ if (debug) {
196
+ console.log(`[useAudioRecorder] start recoding`, recordingOptions);
203
197
  }
198
+
199
+ const result: StartAudioStreamResult =
200
+ await ExpoAudioStreamModule.startRecording(recordingOptions);
201
+ return result;
204
202
  },
205
203
  [debug],
206
204
  );
207
205
 
208
206
  const stopRecording = useCallback(async () => {
209
- console.log(`STOOOOOP NOW`);
210
207
  const result: AudioStreamResult =
211
208
  await ExpoAudioStreamModule.stopRecording();
212
- console.log(`STOOOOOP NOW 2`);
213
209
  setIsRecording(false);
214
210
  setIsPaused(false);
215
211
  return result;
@@ -217,7 +213,17 @@ export function useAudioRecorder({
217
213
 
218
214
  const pauseRecording = useCallback(async () => {
219
215
  try {
220
- await ExpoAudioStreamModule.stopRecording();
216
+ await ExpoAudioStreamModule.pauseRecording();
217
+ setIsPaused(true);
218
+ setIsRecording(false);
219
+ } catch (error) {
220
+ console.error("[useAudioRecorder] Error pausing recording:", error);
221
+ }
222
+ }, [debug]);
223
+
224
+ const resumeRecording = useCallback(async () => {
225
+ try {
226
+ await ExpoAudioStreamModule.resumeRecording();
221
227
  setIsPaused(true);
222
228
  setIsRecording(false);
223
229
  } catch (error) {
@@ -229,6 +235,7 @@ export function useAudioRecorder({
229
235
  startRecording,
230
236
  stopRecording,
231
237
  pauseRecording,
238
+ resumeRecording,
232
239
  isPaused,
233
240
  isRecording,
234
241
  duration,