@siteed/expo-audio-stream 0.1.0 → 0.2.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAudioStreamModule.web.js","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.web.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from \"expo-modules-core\";\nimport { AudioEventPayload, RecordingOptions } from \"./ExpoAudioStream.types\";\n\nclass ExpoAudioStreamWeb extends EventEmitter {\n mediaRecorder: MediaRecorder | null;\n audioChunks: Blob[];\n isRecording: boolean;\n isPaused: boolean;\n recordingStartTime: number;\n pausedTime: number;\n currentDuration: number;\n currentSize: number;\n currentInterval: number;\n lastEmittedSize: number;\n streamUuid: string | null;\n\n constructor() {\n const mockNativeModule = {\n addListener: (eventName: string) => {\n console.log(`Web addListener called for ${eventName}`);\n },\n removeListeners: (count: number) => {\n console.log(`Web removeListeners called, count: ${count}`);\n }\n };\n super(mockNativeModule); // Pass the mock native module to the parent class\n\n\n this.mediaRecorder = null;\n this.audioChunks = [];\n this.isRecording = false;\n this.isPaused = false;\n this.recordingStartTime = 0;\n this.pausedTime = 0;\n this.currentDuration = 0;\n this.currentSize = 0;\n this.currentInterval = 1000; // Default interval in ms\n this.lastEmittedSize = 0;\n this.streamUuid = null; // Initialize UUID on first recording start\n }\n\n // Utility to handle user media stream\n async getMediaStream() {\n try {\n return await navigator.mediaDevices.getUserMedia({ audio: true });\n } catch (error) {\n console.error(\"Failed to get media stream:\", error);\n throw error;\n }\n }\n\n // Start recording with options\n async startRecording(options: RecordingOptions = {}) {\n if (this.isRecording) {\n throw new Error('Recording is already in progress');\n }\n\n const stream = await this.getMediaStream();\n this.mediaRecorder = new MediaRecorder(stream);\n this.setupRecordingListeners();\n this.mediaRecorder.start(options.interval || this.currentInterval);\n this.isRecording = true;\n this.recordingStartTime = Date.now();\n this.pausedTime = 0;\n this.lastEmittedSize = 0;\n this.streamUuid = this.generateUUID(); // Generate a UUID for the new recording session\n }\n\n // Setup listeners for the MediaRecorder\n setupRecordingListeners() {\n if (!this.mediaRecorder) {\n throw new Error('No active media recorder');\n }\n this.mediaRecorder.ondataavailable = (event) => {\n this.audioChunks.push(event.data);\n this.currentSize += event.data.size; // Update the size of the recording\n this.emitAudioEvent(event.data); // Emit the event with the correct payload\n this.lastEmittedSize = this.currentSize;\n };\n\n this.mediaRecorder.onstop = () => {\n this.isRecording = false;\n console.log('Recording stopped', this.audioChunks);\n };\n\n this.mediaRecorder.onpause = () => {\n this.isPaused = true;\n };\n\n this.mediaRecorder.onresume = () => {\n this.isPaused = false;\n this.recordingStartTime += (Date.now() - this.pausedTime); // Adjust start time after resuming\n };\n }\n\n emitAudioEvent(data: Blob) {\n const fileUri = `${this.streamUuid}.pcm`;\n const audioEventPayload: AudioEventPayload = {\n fileUri: fileUri,\n from: this.lastEmittedSize, // Since this might be continuously streaming, adjust accordingly\n deltaSize: data.size,\n totalSize: this.currentSize,\n buffer: data,\n streamUuid: this.streamUuid ?? '', // Generate or manage UUID for stream identification\n };\n\n this.emit('AudioData', audioEventPayload);\n }\n\n // Helper method to generate a UUID\n generateUUID() {\n // Implementation of UUID generation (use a library or custom method)\n return 'xxxx-xxxx-xxxx-xxxx'.replace(/[x]/g, (c) => {\n const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n }\n\n // Stop recording\n async stopRecording() {\n console.debug('Stopping recording', this);\n this.mediaRecorder?.stop();\n this.isRecording = false;\n this.currentDuration = (Date.now() - this.recordingStartTime) / 1000;\n return this.currentDuration;\n }\n\n // Pause recording\n async pauseRecording() {\n if (!this.mediaRecorder) {\n throw new Error('No active media recorder');\n }\n\n if (this.isRecording && !this.isPaused) {\n this.mediaRecorder.pause();\n this.pausedTime = Date.now();\n } else {\n throw new Error('Recording is not active or already paused');\n }\n }\n\n // Get current status\n status() {\n return {\n isRecording: this.isRecording,\n isPaused: this.isPaused,\n duration: Date.now() - this.recordingStartTime,\n size: this.currentSize,\n interval: this.currentInterval,\n };\n }\n\n listAudioFiles() {\n // Not applicable on web\n }\n\n clearAudioFiles() {\n // Not applicable on web\n }\n}\n\nexport default new ExpoAudioStreamWeb();"]}
1
+ {"version":3,"file":"ExpoAudioStreamModule.web.js","sourceRoot":"","sources":["../src/ExpoAudioStreamModule.web.ts"],"names":[],"mappings":"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","sourcesContent":["import debug from \"debug\";\nimport { EventEmitter } from \"expo-modules-core\";\n\nimport {\n AudioEventPayload,\n AudioStreamResult,\n RecordingOptions,\n} from \"./ExpoAudioStream.types\";\n\nconst log = debug(\"expo-audio-stream:useAudioRecording\");\nclass ExpoAudioStreamWeb extends EventEmitter {\n mediaRecorder: MediaRecorder | null;\n audioChunks: Blob[];\n isRecording: boolean;\n isPaused: boolean;\n recordingStartTime: number;\n pausedTime: number;\n currentDuration: number;\n currentSize: number;\n currentInterval: number;\n lastEmittedSize: number;\n streamUuid: string | null;\n\n constructor() {\n const mockNativeModule = {\n addListener: (eventName: string) => {\n // Not used on web\n },\n removeListeners: (count: number) => {\n // Not used on web\n },\n };\n super(mockNativeModule); // Pass the mock native module to the parent class\n\n this.mediaRecorder = null;\n this.audioChunks = [];\n this.isRecording = false;\n this.isPaused = false;\n this.recordingStartTime = 0;\n this.pausedTime = 0;\n this.currentDuration = 0;\n this.currentSize = 0;\n this.currentInterval = 1000; // Default interval in ms\n this.lastEmittedSize = 0;\n this.streamUuid = null; // Initialize UUID on first recording start\n }\n\n // Utility to handle user media stream\n async getMediaStream() {\n try {\n return await navigator.mediaDevices.getUserMedia({ audio: true });\n } catch (error) {\n console.error(\"Failed to get media stream:\", error);\n throw error;\n }\n }\n\n // Start recording with options\n async startRecording(options: RecordingOptions = {}) {\n if (this.isRecording) {\n throw new Error(\"Recording is already in progress\");\n }\n\n const stream = await this.getMediaStream();\n this.mediaRecorder = new MediaRecorder(stream);\n this.setupRecordingListeners();\n this.mediaRecorder.start(options.interval || this.currentInterval);\n this.isRecording = true;\n this.recordingStartTime = Date.now();\n this.pausedTime = 0;\n this.lastEmittedSize = 0;\n this.streamUuid = this.generateUUID(); // Generate a UUID for the new recording session\n const fileUri = `${this.streamUuid}.webm`;\n return fileUri;\n }\n\n // Setup listeners for the MediaRecorder\n setupRecordingListeners() {\n if (!this.mediaRecorder) {\n throw new Error(\"No active media recorder\");\n }\n this.mediaRecorder.ondataavailable = (event) => {\n this.audioChunks.push(event.data);\n this.currentSize += event.data.size; // Update the size of the recording\n this.emitAudioEvent(event.data); // Emit the event with the correct payload\n this.lastEmittedSize = this.currentSize;\n };\n\n this.mediaRecorder.onstop = () => {\n this.isRecording = false;\n log(\"Recording stopped\", this.audioChunks);\n };\n\n this.mediaRecorder.onpause = () => {\n this.isPaused = true;\n };\n\n this.mediaRecorder.onresume = () => {\n this.isPaused = false;\n this.recordingStartTime += Date.now() - this.pausedTime; // Adjust start time after resuming\n };\n }\n\n emitAudioEvent(data: Blob) {\n const fileUri = `${this.streamUuid}.webm`;\n const audioEventPayload: AudioEventPayload = {\n fileUri,\n mimeType: \"audio/webm\",\n from: this.lastEmittedSize, // Since this might be continuously streaming, adjust accordingly\n deltaSize: data.size,\n totalSize: this.currentSize,\n buffer: data,\n streamUuid: this.streamUuid ?? \"\", // Generate or manage UUID for stream identification\n };\n\n this.emit(\"AudioData\", audioEventPayload);\n }\n\n // Helper method to generate a UUID\n generateUUID() {\n // Implementation of UUID generation (use a library or custom method)\n return \"xxxx-xxxx-xxxx-xxxx\".replace(/[x]/g, (c) => {\n const r = (Math.random() * 16) | 0,\n v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n\n // Stop recording\n async stopRecording(): Promise<AudioStreamResult | null> {\n this.mediaRecorder?.stop();\n this.isRecording = false;\n this.currentDuration = (Date.now() - this.recordingStartTime) / 1000;\n const result: AudioStreamResult = {\n fileUri: `${this.streamUuid}.webm`,\n duration: this.currentDuration,\n size: this.currentSize,\n mimeType: \"audio/webm\",\n };\n\n return result;\n }\n\n // Pause recording\n async pauseRecording() {\n if (!this.mediaRecorder) {\n throw new Error(\"No active media recorder\");\n }\n\n if (this.isRecording && !this.isPaused) {\n this.mediaRecorder.pause();\n this.pausedTime = Date.now();\n } else {\n throw new Error(\"Recording is not active or already paused\");\n }\n }\n\n // Get current status\n status() {\n return {\n isRecording: this.isRecording,\n isPaused: this.isPaused,\n duration: Date.now() - this.recordingStartTime,\n size: this.currentSize,\n interval: this.currentInterval,\n };\n }\n\n listAudioFiles() {\n // Not applicable on web\n }\n\n clearAudioFiles() {\n // Not applicable on web\n }\n}\n\nexport default new ExpoAudioStreamWeb();\n"]}
package/build/index.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- import { type Subscription } from 'expo-modules-core';
2
- import { AudioEventPayload } from './ExpoAudioStream.types';
3
- import { useAudioRecorder } from './useAudioRecording';
4
- export declare function getRecordingDuration(): Promise<number>;
1
+ import { type Subscription } from "expo-modules-core";
2
+ import { AudioEventPayload } from "./ExpoAudioStream.types";
3
+ import { useAudioRecorder } from "./useAudioRecording";
5
4
  export declare function listAudioFiles(): Promise<string[]>;
6
5
  export declare function clearAudioFiles(): Promise<void>;
7
- export declare function addChangeListener(listener: (event: AudioEventPayload) => void): Subscription;
6
+ export declare function addAudioEventListener(listener: (event: AudioEventPayload) => void): Subscription;
8
7
  export { AudioEventPayload, useAudioRecorder };
9
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKxF,OAAO,EAAE,iBAAiB,EAAoB,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAKvD,wBAAgB,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC,CAEtD;AAED,wBAAgB,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAElD;AAED,wBAAgB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAAG,YAAY,CAE5F;AAGD,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAMvD,wBAAgB,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAElD;AAED,wBAAgB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,GAC3C,YAAY,CAEd;AAED,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC"}
package/build/index.js CHANGED
@@ -1,21 +1,15 @@
1
- import { NativeModulesProxy, EventEmitter } from 'expo-modules-core';
2
- // Import the native module. On web, it will be resolved to ExpoAudioStream.web.ts
3
- // and on native platforms to ExpoAudioStream.ts
4
- import ExpoAudioStreamModule from './ExpoAudioStreamModule';
5
- import { useAudioRecorder } from './useAudioRecording';
1
+ import { EventEmitter, NativeModulesProxy, } from "expo-modules-core";
2
+ import ExpoAudioStreamModule from "./ExpoAudioStreamModule";
3
+ import { useAudioRecorder } from "./useAudioRecording";
6
4
  const emitter = new EventEmitter(ExpoAudioStreamModule ?? NativeModulesProxy.ExpoAudioStream);
7
- // Function to get the recording duration
8
- export function getRecordingDuration() {
9
- return ExpoAudioStreamModule.getRecordingDuration();
10
- }
11
5
  export function listAudioFiles() {
12
6
  return ExpoAudioStreamModule.listAudioFiles();
13
7
  }
14
8
  export function clearAudioFiles() {
15
9
  return ExpoAudioStreamModule.clearAudioFiles();
16
10
  }
17
- export function addChangeListener(listener) {
18
- return emitter.addListener('AudioData', listener);
11
+ export function addAudioEventListener(listener) {
12
+ return emitter.addListener("AudioData", listener);
19
13
  }
20
14
  export { useAudioRecorder };
21
15
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAqB,MAAM,mBAAmB,CAAC;AAExF,kFAAkF;AAClF,gDAAgD;AAChD,OAAO,qBAAqB,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,qBAAqB,IAAI,kBAAkB,CAAC,eAAe,CAAC,CAAC;AAE9F,yCAAyC;AACzC,MAAM,UAAU,oBAAoB;IAClC,OAAO,qBAAqB,CAAC,oBAAoB,EAAE,CAAC;AACtD,CAAC;AAED,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,iBAAiB,CAAC,QAA4C;IAC5E,OAAO,OAAO,CAAC,WAAW,CAAoB,WAAW,EAAE,QAAQ,CAAC,CAAC;AACvE,CAAC;AAGD,OAAO,EAAqB,gBAAgB,EAAE,CAAC","sourcesContent":["import { NativeModulesProxy, EventEmitter, type Subscription } 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 ExpoAudioStreamModule from './ExpoAudioStreamModule';\nimport { AudioEventPayload, RecordingOptions } from './ExpoAudioStream.types';\nimport { useAudioRecorder } from './useAudioRecording';\n\nconst emitter = new EventEmitter(ExpoAudioStreamModule ?? NativeModulesProxy.ExpoAudioStream);\n\n// Function to get the recording duration\nexport function getRecordingDuration(): Promise<number> {\n return ExpoAudioStreamModule.getRecordingDuration();\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 addChangeListener(listener: (event: AudioEventPayload) => void): Subscription {\n return emitter.addListener<AudioEventPayload>('AudioData', listener);\n}\n\n\nexport { AudioEventPayload, 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,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,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,QAA4C;IAE5C,OAAO,OAAO,CAAC,WAAW,CAAoB,WAAW,EAAE,QAAQ,CAAC,CAAC;AACvE,CAAC;AAED,OAAO,EAAqB,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 { useAudioRecorder } 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) => void,\n): Subscription {\n return emitter.addListener<AudioEventPayload>(\"AudioData\", listener);\n}\n\nexport { AudioEventPayload, useAudioRecorder };\n"]}
@@ -1,14 +1,14 @@
1
- import { RecordingOptions } from "./ExpoAudioStream.types";
1
+ import { AudioStreamResult, RecordingOptions } from "./ExpoAudioStream.types";
2
2
  interface UseAudioRecorderState {
3
- startRecording: (_: RecordingOptions) => Promise<void>;
4
- stopRecording: () => Promise<number>;
3
+ startRecording: (_: RecordingOptions) => Promise<string | null>;
4
+ stopRecording: () => Promise<AudioStreamResult | null>;
5
5
  pauseRecording: () => void;
6
6
  isRecording: boolean;
7
7
  isPaused: boolean;
8
8
  duration: number;
9
9
  size: number;
10
10
  }
11
- export declare function useAudioRecorder({ onAudioStream }: {
11
+ export declare function useAudioRecorder({ onAudioStream, }: {
12
12
  onAudioStream?: (buffer: Blob) => void;
13
13
  }): UseAudioRecorderState;
14
14
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"useAudioRecording.d.ts","sourceRoot":"","sources":["../src/useAudioRecording.ts"],"names":[],"mappings":"AAIA,OAAO,EAAwC,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAOjG,UAAU,qBAAqB;IAC3B,cAAc,EAAE,CAAC,CAAC,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,aAAa,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,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;CAChB;AAED,wBAAgB,gBAAgB,CAAC,EAAC,aAAa,EAAC,EAAE;IAAC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,KAAK,IAAI,CAAA;CAAC,GAAG,qBAAqB,CAuHjH"}
1
+ {"version":3,"file":"useAudioRecording.d.ts","sourceRoot":"","sources":["../src/useAudioRecording.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,iBAAiB,EAEjB,gBAAgB,EACjB,MAAM,yBAAyB,CAAC;AAKjC,UAAU,qBAAqB;IAC7B,cAAc,EAAE,CAAC,CAAC,EAAE,gBAAgB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAChE,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,GACd,EAAE;IACD,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,KAAK,IAAI,CAAC;CACxC,GAAG,qBAAqB,CAkIxB"}
@@ -1,11 +1,11 @@
1
- import { NativeModulesProxy, EventEmitter, Platform } from 'expo-modules-core';
1
+ import { decode as atob } from "base-64";
2
+ import debug from "debug";
3
+ import { Platform } from "expo-modules-core";
2
4
  import { useCallback, useEffect, useState } from "react";
3
- import ExpoAudioStreamModule from './ExpoAudioStreamModule';
4
- import { addChangeListener } from '.';
5
- import * as FileSystem from 'expo-file-system';
6
- import { decode as atob } from 'base-64';
7
- const emitter = new EventEmitter(ExpoAudioStreamModule ?? NativeModulesProxy.ExpoAudioStream);
8
- export function useAudioRecorder({ onAudioStream }) {
5
+ import { addAudioEventListener } from ".";
6
+ import ExpoAudioStreamModule from "./ExpoAudioStreamModule";
7
+ const log = debug("expo-audio-stream:useAudioRecording");
8
+ export function useAudioRecorder({ onAudioStream, }) {
9
9
  const [isRecording, setIsRecording] = useState(false);
10
10
  const [isPaused, setIsPaused] = useState(false);
11
11
  const [duration, setDuration] = useState(0);
@@ -22,34 +22,51 @@ export function useAudioRecorder({ onAudioStream }) {
22
22
  return () => null;
23
23
  }, [isRecording, isPaused]);
24
24
  useEffect(() => {
25
- const subscribe = addChangeListener(async ({ fileUri, deltaSize, totalSize, from, streamUuid, encoded, buffer }) => {
26
- console.debug(`Received audio event:`, { fileUri, deltaSize, totalSize, from, streamUuid, encodedLength: encoded?.length });
25
+ const subscribe = addAudioEventListener(async ({ fileUri, deltaSize, totalSize, from, streamUuid, encoded, mimeType, buffer, }) => {
26
+ log(`Received audio event:`, {
27
+ fileUri,
28
+ deltaSize,
29
+ totalSize,
30
+ mimeType,
31
+ from,
32
+ streamUuid,
33
+ encodedLength: encoded?.length,
34
+ });
27
35
  if (deltaSize > 0) {
28
- // Fetch the audio data from the fileUri
29
- const options = {
30
- encoding: FileSystem.EncodingType.Base64,
31
- position: from,
32
- length: deltaSize,
33
- };
34
- if (Platform.OS !== 'web') {
36
+ // Coming from native ( ios / android ) otherwise buffer is set
37
+ if (Platform.OS !== "web") {
35
38
  // Read the audio file as a base64 string for comparison
36
39
  try {
37
- const base64Content = await FileSystem.readAsStringAsync(fileUri, options);
38
- const binaryData = atob(base64Content);
40
+ // convert encoded string to binary data
41
+ const binaryData = atob(encoded);
39
42
  const content = new Uint8Array(binaryData.length);
40
43
  for (let i = 0; i < binaryData.length; i++) {
41
44
  content[i] = binaryData.charCodeAt(i);
42
45
  }
43
- // TODO: get the filetype based on audio setting and encoding
44
- const audioBlob = new Blob([content], { type: 'application/octet-stream' }); // Create a Blob from the byte array
45
- console.debug(`Read audio file (len: ${content.length}) vs ${deltaSize}`);
46
+ const audioBlob = new Blob([content], { type: mimeType });
47
+ // Below code is optional, used to compare encoded data to audio on file system
48
+ // Fetch the audio data from the fileUri
49
+ // const options = {
50
+ // encoding: FileSystem.EncodingType.Base64,
51
+ // position: from,
52
+ // length: deltaSize,
53
+ // };
54
+ // const base64Content = await FileSystem.readAsStringAsync(fileUri, options);
55
+ // const binaryData = atob(base64Content);
56
+ // const content = new Uint8Array(binaryData.length);
57
+ // for (let i = 0; i < binaryData.length; i++) {
58
+ // content[i] = binaryData.charCodeAt(i);
59
+ // }
60
+ // const audioBlob = new Blob([content], { type: 'application/octet-stream' }); // Create a Blob from the byte array
61
+ // console.debug(`Read audio file (len: ${content.length}) vs ${deltaSize}`)
46
62
  onAudioStream?.(audioBlob);
47
63
  }
48
64
  catch (error) {
49
- console.error('Error reading audio file:', error);
65
+ console.error("Error reading audio file:", error);
50
66
  }
51
67
  }
52
68
  else if (buffer) {
69
+ // Coming from web
53
70
  onAudioStream?.(buffer);
54
71
  }
55
72
  }
@@ -57,54 +74,36 @@ export function useAudioRecorder({ onAudioStream }) {
57
74
  return () => subscribe.remove();
58
75
  }, [isRecording, onAudioStream]);
59
76
  const startRecording = useCallback(async (recordingOptions) => {
60
- if (!isRecording) {
61
- setIsRecording(true);
62
- setIsPaused(false);
63
- setSize(0);
64
- setDuration(0);
65
- const startTime = Date.now();
66
- console.log(`module shims`, ExpoAudioStreamModule);
67
- try {
68
- console.log(`start recoding`, recordingOptions);
69
- await ExpoAudioStreamModule.startRecording(recordingOptions);
70
- }
71
- catch (error) {
72
- console.error('Error starting recording:', error);
73
- setIsRecording(false);
74
- }
77
+ setIsRecording(true);
78
+ setIsPaused(false);
79
+ setSize(0);
80
+ setDuration(0);
81
+ try {
82
+ log(`start recoding`, recordingOptions);
83
+ const fileUrl = await ExpoAudioStreamModule.startRecording(recordingOptions);
84
+ return fileUrl;
75
85
  }
76
- }, [isRecording]);
77
- const stopRecording = useCallback(async () => {
78
- if (isRecording) {
86
+ catch (error) {
87
+ console.error("Error starting recording:", error);
79
88
  setIsRecording(false);
80
- setIsPaused(false);
81
- try {
82
- const recordedDuration = await ExpoAudioStreamModule.stopRecording();
83
- setDuration(recordedDuration);
84
- return recordedDuration;
85
- }
86
- catch (error) {
87
- console.error('Error stopping recording:', error);
88
- return 0;
89
- }
90
89
  }
91
- return 0;
92
- }, [isRecording]);
93
- const pauseRecording = useCallback(() => {
94
- if (isRecording) {
95
- ExpoAudioStreamModule.stopRecording().catch(console.error);
90
+ }, []);
91
+ const stopRecording = useCallback(async () => {
92
+ setIsRecording(false);
93
+ setIsPaused(false);
94
+ const result = await ExpoAudioStreamModule.stopRecording();
95
+ return result;
96
+ }, []);
97
+ const pauseRecording = useCallback(async () => {
98
+ try {
99
+ await ExpoAudioStreamModule.stopRecording();
96
100
  setIsPaused(true);
97
101
  setIsRecording(false);
98
102
  }
99
- }, [isRecording]);
100
- // Cleanup listener on unmount to prevent memory leaks
101
- useEffect(() => {
102
- return () => {
103
- if (isRecording) {
104
- ExpoAudioStreamModule.stopRecording().catch(console.error);
105
- }
106
- };
107
- }, [isRecording]);
103
+ catch (error) {
104
+ console.error("Error pausing recording:", error);
105
+ }
106
+ }, []);
108
107
  return {
109
108
  startRecording,
110
109
  stopRecording,
@@ -112,7 +111,7 @@ export function useAudioRecorder({ onAudioStream }) {
112
111
  isPaused,
113
112
  isRecording,
114
113
  duration,
115
- size
114
+ size,
116
115
  };
117
116
  }
118
117
  //# sourceMappingURL=useAudioRecording.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAudioRecording.js","sourceRoot":"","sources":["../src/useAudioRecording.ts"],"names":[],"mappings":"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","sourcesContent":["import { NativeModulesProxy, EventEmitter, type Subscription, Platform } from 'expo-modules-core';\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport ExpoAudioStreamModule from './ExpoAudioStreamModule';\nimport { AudioEventPayload, AudioStreamStatus, RecordingOptions } from \"./ExpoAudioStream.types\";\nimport { addChangeListener } from '.';\nimport * as FileSystem from 'expo-file-system';\nimport { decode as atob } from 'base-64';\n\nconst emitter = new EventEmitter(ExpoAudioStreamModule ?? NativeModulesProxy.ExpoAudioStream);\n\ninterface UseAudioRecorderState {\n startRecording: (_: RecordingOptions) => Promise<void>;\n stopRecording: () => Promise<number>;\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({onAudioStream}: {onAudioStream?: (buffer: Blob) => void}): 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 useEffect( () => {\n if(isRecording || isPaused) {\n const interval = setInterval(() => {\n const status: AudioStreamStatus = ExpoAudioStreamModule.status()\n setDuration(status.duration);\n setSize(status.size);\n }, 1000);\n return () => clearInterval(interval);\n }\n\n return () => null;\n }, [isRecording, isPaused])\n\n\n useEffect(() => {\n const subscribe = addChangeListener(async ({fileUri, deltaSize, totalSize, from, streamUuid, encoded, buffer}) => {\n console.debug(`Received audio event:`, {fileUri, deltaSize, totalSize, from, streamUuid, encodedLength: encoded?.length})\n if(deltaSize > 0) {\n // Fetch the audio data from the fileUri\n const options = {\n encoding: FileSystem.EncodingType.Base64,\n position: from,\n length: deltaSize,\n };\n\n if(Platform.OS !== 'web') {\n // Read the audio file as a base64 string for comparison\n try {\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\n // TODO: get the filetype based on audio setting and encoding\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 onAudioStream?.(audioBlob);\n } catch (error) {\n console.error('Error reading audio file:', error);\n }\n } else if(buffer) {\n onAudioStream?.(buffer);\n }\n }\n });\n return () => subscribe.remove();\n }, [isRecording, onAudioStream]);\n\n\n const startRecording = useCallback(async (recordingOptions: RecordingOptions) => {\n if (!isRecording) {\n setIsRecording(true);\n setIsPaused(false);\n setSize(0);\n setDuration(0);\n const startTime = Date.now();\n\n console.log(`module shims`, ExpoAudioStreamModule)\n try {\n console.log(`start recoding`, recordingOptions)\n await ExpoAudioStreamModule.startRecording(recordingOptions);\n\n } catch (error) {\n console.error('Error starting recording:', error);\n setIsRecording(false);\n }\n }\n }, [isRecording]);\n\n const stopRecording = useCallback(async (): Promise<number> => {\n if (isRecording) {\n setIsRecording(false);\n setIsPaused(false);\n try {\n const recordedDuration = await ExpoAudioStreamModule.stopRecording();\n setDuration(recordedDuration);\n return recordedDuration;\n } catch (error) {\n console.error('Error stopping recording:', error);\n return 0;\n }\n }\n return 0;\n }, [isRecording]);\n\n const pauseRecording = useCallback(() => {\n if (isRecording) {\n ExpoAudioStreamModule.stopRecording().catch(console.error);\n setIsPaused(true);\n setIsRecording(false);\n }\n }, [isRecording]);\n\n // Cleanup listener on unmount to prevent memory leaks\n useEffect(() => {\n return () => {\n if (isRecording) {\n ExpoAudioStreamModule.stopRecording().catch(console.error);\n }\n };\n }, [isRecording]);\n\n return {\n startRecording,\n stopRecording,\n pauseRecording,\n isPaused,\n isRecording,\n duration,\n size\n };\n}"]}
1
+ {"version":3,"file":"useAudioRecording.js","sourceRoot":"","sources":["../src/useAudioRecording.ts"],"names":[],"mappings":"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","sourcesContent":["import { decode as atob } from \"base-64\";\nimport debug from \"debug\";\nimport { Platform } from \"expo-modules-core\";\nimport { useCallback, useEffect, useState } from \"react\";\n\nimport { addAudioEventListener } from \".\";\nimport {\n AudioStreamResult,\n AudioStreamStatus,\n RecordingOptions,\n} from \"./ExpoAudioStream.types\";\nimport ExpoAudioStreamModule from \"./ExpoAudioStreamModule\";\n\nconst log = debug(\"expo-audio-stream:useAudioRecording\");\n\ninterface UseAudioRecorderState {\n startRecording: (_: RecordingOptions) => Promise<string | null>;\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}: {\n onAudioStream?: (buffer: Blob) => void;\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 useEffect(() => {\n if (isRecording || isPaused) {\n const interval = setInterval(() => {\n const status: AudioStreamStatus = ExpoAudioStreamModule.status();\n setDuration(status.duration);\n setSize(status.size);\n }, 1000);\n return () => clearInterval(interval);\n }\n\n return () => null;\n }, [isRecording, isPaused]);\n\n useEffect(() => {\n const subscribe = addAudioEventListener(\n async ({\n fileUri,\n deltaSize,\n totalSize,\n from,\n streamUuid,\n encoded,\n mimeType,\n buffer,\n }) => {\n log(`Received audio event:`, {\n fileUri,\n deltaSize,\n totalSize,\n mimeType,\n from,\n streamUuid,\n encodedLength: encoded?.length,\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 // convert encoded string to binary data\n const binaryData = atob(encoded);\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: mimeType });\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: from,\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\n onAudioStream?.(audioBlob);\n } catch (error) {\n console.error(\"Error reading audio file:\", error);\n }\n } else if (buffer) {\n // Coming from web\n onAudioStream?.(buffer);\n }\n }\n },\n );\n return () => subscribe.remove();\n }, [isRecording, onAudioStream]);\n\n const startRecording = useCallback(\n async (recordingOptions: RecordingOptions) => {\n setIsRecording(true);\n setIsPaused(false);\n setSize(0);\n setDuration(0);\n try {\n log(`start recoding`, recordingOptions);\n const fileUrl =\n await ExpoAudioStreamModule.startRecording(recordingOptions);\n\n return fileUrl;\n } catch (error) {\n console.error(\"Error starting recording:\", error);\n setIsRecording(false);\n }\n },\n [],\n );\n\n const stopRecording = useCallback(async () => {\n setIsRecording(false);\n setIsPaused(false);\n const result: AudioStreamResult =\n await ExpoAudioStreamModule.stopRecording();\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(\"Error pausing recording:\", error);\n }\n }, []);\n\n return {\n startRecording,\n stopRecording,\n pauseRecording,\n isPaused,\n isRecording,\n duration,\n size,\n };\n}\n"]}