@siteed/expo-audio-stream 0.1.0 → 0.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.
- package/README.md +80 -6
- package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +129 -49
- package/build/ExpoAudioStream.types.d.ts +8 -3
- package/build/ExpoAudioStream.types.d.ts.map +1 -1
- package/build/ExpoAudioStream.types.js.map +1 -1
- package/build/ExpoAudioStreamModule.web.d.ts +3 -3
- package/build/ExpoAudioStreamModule.web.d.ts.map +1 -1
- package/build/ExpoAudioStreamModule.web.js +16 -6
- package/build/ExpoAudioStreamModule.web.js.map +1 -1
- package/build/index.d.ts +1 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -5
- package/build/index.js.map +1 -1
- package/build/useAudioRecording.d.ts +3 -3
- package/build/useAudioRecording.d.ts.map +1 -1
- package/build/useAudioRecording.js +49 -57
- package/build/useAudioRecording.js.map +1 -1
- package/ios/AudioStreamManager.swift +189 -37
- package/ios/ExpoAudioStreamModule.swift +21 -12
- package/package.json +9 -3
- package/src/ExpoAudioStream.types.ts +12 -3
- package/src/ExpoAudioStreamModule.web.ts +19 -8
- package/src/index.ts +1 -7
- package/src/useAudioRecording.ts +58 -65
- package/yarn-error.log +0 -72
package/package.json
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@siteed/expo-audio-stream",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "stream audio crossplatform",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "build/index.js",
|
|
7
7
|
"types": "build/index.d.ts",
|
|
8
8
|
"author": "Arthur Breton <abreton@siteed.net> (https://github.com/deeeed)",
|
|
9
9
|
"homepage": "https://github.com/deeeed/expo-audio-stream#readme",
|
|
10
|
-
"repository":
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/deeeed/expo-audio-stream.git"
|
|
13
|
+
},
|
|
11
14
|
"bugs": {
|
|
12
15
|
"url": "https://github.com/deeeed/expo-audio-stream/issues"
|
|
13
16
|
},
|
|
@@ -31,11 +34,13 @@
|
|
|
31
34
|
},
|
|
32
35
|
"dependencies": {
|
|
33
36
|
"base-64": "^1.0.0",
|
|
37
|
+
"debug": "^4.3.4",
|
|
34
38
|
"expo-file-system": "^16.0.9"
|
|
35
39
|
},
|
|
36
40
|
"devDependencies": {
|
|
37
41
|
"@expo/config-plugins": "^7.9.1",
|
|
38
42
|
"@release-it/conventional-changelog": "^8.0.1",
|
|
43
|
+
"@types/debug": "^4.1.12",
|
|
39
44
|
"@types/react": "^18.0.25",
|
|
40
45
|
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
|
41
46
|
"@typescript-eslint/parser": "^7.7.0",
|
|
@@ -56,6 +61,7 @@
|
|
|
56
61
|
"react-native": "*"
|
|
57
62
|
},
|
|
58
63
|
"publishConfig": {
|
|
59
|
-
"access": "public"
|
|
64
|
+
"access": "public",
|
|
65
|
+
"registry": "https://registry.npmjs.org"
|
|
60
66
|
}
|
|
61
67
|
}
|
|
@@ -5,21 +5,30 @@ export interface AudioEventPayload {
|
|
|
5
5
|
from: number,
|
|
6
6
|
deltaSize: number,
|
|
7
7
|
totalSize: number,
|
|
8
|
+
mimeType: string;
|
|
8
9
|
streamUuid: string,
|
|
9
10
|
};
|
|
10
11
|
|
|
12
|
+
export interface AudioStreamResult {
|
|
13
|
+
fileUri: string;
|
|
14
|
+
duration: number;
|
|
15
|
+
size: number;
|
|
16
|
+
mimeType: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
11
19
|
export interface AudioStreamStatus {
|
|
12
20
|
isRecording: boolean;
|
|
13
21
|
isPaused: boolean;
|
|
14
22
|
duration: number;
|
|
15
23
|
size: number;
|
|
16
24
|
interval: number;
|
|
25
|
+
mimeType: string;
|
|
17
26
|
}
|
|
18
27
|
|
|
19
28
|
export interface RecordingOptions {
|
|
20
29
|
// TODO align Android and IOS options
|
|
21
|
-
sampleRate?: number;
|
|
22
|
-
channelConfig?: number; // numberOfChannel
|
|
23
|
-
audioFormat?: number; // bitDepth (ENCODING_PCM_16BIT --> 2)
|
|
30
|
+
// sampleRate?: number;
|
|
31
|
+
// channelConfig?: number; // numberOfChannel
|
|
32
|
+
// audioFormat?: number; // bitDepth (ENCODING_PCM_16BIT --> 2)
|
|
24
33
|
interval?: number;
|
|
25
34
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { EventEmitter } from "expo-modules-core";
|
|
2
|
-
import { AudioEventPayload, RecordingOptions } from "./ExpoAudioStream.types";
|
|
2
|
+
import { AudioEventPayload, AudioStreamResult, RecordingOptions } from "./ExpoAudioStream.types";
|
|
3
|
+
import debug from 'debug';
|
|
3
4
|
|
|
5
|
+
const log = debug("expo-audio-stream:useAudioRecording");
|
|
4
6
|
class ExpoAudioStreamWeb extends EventEmitter {
|
|
5
7
|
mediaRecorder: MediaRecorder | null;
|
|
6
8
|
audioChunks: Blob[];
|
|
@@ -17,10 +19,10 @@ class ExpoAudioStreamWeb extends EventEmitter {
|
|
|
17
19
|
constructor() {
|
|
18
20
|
const mockNativeModule = {
|
|
19
21
|
addListener: (eventName: string) => {
|
|
20
|
-
|
|
22
|
+
// Not used on web
|
|
21
23
|
},
|
|
22
24
|
removeListeners: (count: number) => {
|
|
23
|
-
|
|
25
|
+
// Not used on web
|
|
24
26
|
}
|
|
25
27
|
};
|
|
26
28
|
super(mockNativeModule); // Pass the mock native module to the parent class
|
|
@@ -64,6 +66,8 @@ class ExpoAudioStreamWeb extends EventEmitter {
|
|
|
64
66
|
this.pausedTime = 0;
|
|
65
67
|
this.lastEmittedSize = 0;
|
|
66
68
|
this.streamUuid = this.generateUUID(); // Generate a UUID for the new recording session
|
|
69
|
+
const fileUri = `${this.streamUuid}.webm`;
|
|
70
|
+
return fileUri;
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
// Setup listeners for the MediaRecorder
|
|
@@ -80,7 +84,7 @@ class ExpoAudioStreamWeb extends EventEmitter {
|
|
|
80
84
|
|
|
81
85
|
this.mediaRecorder.onstop = () => {
|
|
82
86
|
this.isRecording = false;
|
|
83
|
-
|
|
87
|
+
log('Recording stopped', this.audioChunks);
|
|
84
88
|
};
|
|
85
89
|
|
|
86
90
|
this.mediaRecorder.onpause = () => {
|
|
@@ -94,9 +98,10 @@ class ExpoAudioStreamWeb extends EventEmitter {
|
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
emitAudioEvent(data: Blob) {
|
|
97
|
-
const fileUri = `${this.streamUuid}.
|
|
101
|
+
const fileUri = `${this.streamUuid}.webm`;
|
|
98
102
|
const audioEventPayload: AudioEventPayload = {
|
|
99
103
|
fileUri: fileUri,
|
|
104
|
+
mimeType: 'audio/webm',
|
|
100
105
|
from: this.lastEmittedSize, // Since this might be continuously streaming, adjust accordingly
|
|
101
106
|
deltaSize: data.size,
|
|
102
107
|
totalSize: this.currentSize,
|
|
@@ -117,12 +122,18 @@ class ExpoAudioStreamWeb extends EventEmitter {
|
|
|
117
122
|
}
|
|
118
123
|
|
|
119
124
|
// Stop recording
|
|
120
|
-
async stopRecording() {
|
|
121
|
-
console.debug('Stopping recording', this);
|
|
125
|
+
async stopRecording(): Promise<AudioStreamResult | null> {
|
|
122
126
|
this.mediaRecorder?.stop();
|
|
123
127
|
this.isRecording = false;
|
|
124
128
|
this.currentDuration = (Date.now() - this.recordingStartTime) / 1000;
|
|
125
|
-
|
|
129
|
+
const result: AudioStreamResult = {
|
|
130
|
+
fileUri: `${this.streamUuid}.webm`,
|
|
131
|
+
duration: this.currentDuration,
|
|
132
|
+
size: this.currentSize,
|
|
133
|
+
mimeType: 'audio/webm',
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return result;
|
|
126
137
|
}
|
|
127
138
|
|
|
128
139
|
// Pause recording
|
package/src/index.ts
CHANGED
|
@@ -8,11 +8,6 @@ import { useAudioRecorder } from './useAudioRecording';
|
|
|
8
8
|
|
|
9
9
|
const emitter = new EventEmitter(ExpoAudioStreamModule ?? NativeModulesProxy.ExpoAudioStream);
|
|
10
10
|
|
|
11
|
-
// Function to get the recording duration
|
|
12
|
-
export function getRecordingDuration(): Promise<number> {
|
|
13
|
-
return ExpoAudioStreamModule.getRecordingDuration();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
11
|
export function listAudioFiles(): Promise<string[]> {
|
|
17
12
|
return ExpoAudioStreamModule.listAudioFiles();
|
|
18
13
|
}
|
|
@@ -21,9 +16,8 @@ export function clearAudioFiles(): Promise<void> {
|
|
|
21
16
|
return ExpoAudioStreamModule.clearAudioFiles();
|
|
22
17
|
}
|
|
23
18
|
|
|
24
|
-
export function
|
|
19
|
+
export function addAudioEventListener(listener: (event: AudioEventPayload) => void): Subscription {
|
|
25
20
|
return emitter.addListener<AudioEventPayload>('AudioData', listener);
|
|
26
21
|
}
|
|
27
22
|
|
|
28
|
-
|
|
29
23
|
export { AudioEventPayload, useAudioRecorder };
|
package/src/useAudioRecording.ts
CHANGED
|
@@ -2,16 +2,19 @@ import { NativeModulesProxy, EventEmitter, type Subscription, Platform } from 'e
|
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useState } from "react";
|
|
4
4
|
import ExpoAudioStreamModule from './ExpoAudioStreamModule';
|
|
5
|
-
import { AudioEventPayload, AudioStreamStatus, RecordingOptions } from "./ExpoAudioStream.types";
|
|
6
|
-
import {
|
|
5
|
+
import { AudioEventPayload, AudioStreamResult, AudioStreamStatus, RecordingOptions } from "./ExpoAudioStream.types";
|
|
6
|
+
import { addAudioEventListener } from '.';
|
|
7
7
|
import * as FileSystem from 'expo-file-system';
|
|
8
8
|
import { decode as atob } from 'base-64';
|
|
9
|
+
import debug from 'debug';
|
|
9
10
|
|
|
10
11
|
const emitter = new EventEmitter(ExpoAudioStreamModule ?? NativeModulesProxy.ExpoAudioStream);
|
|
11
12
|
|
|
13
|
+
const log = debug("expo-audio-stream:useAudioRecording");
|
|
14
|
+
|
|
12
15
|
interface UseAudioRecorderState {
|
|
13
|
-
startRecording: (_: RecordingOptions) => Promise<
|
|
14
|
-
stopRecording: () => Promise<
|
|
16
|
+
startRecording: (_: RecordingOptions) => Promise<string | null>;
|
|
17
|
+
stopRecording: () => Promise<AudioStreamResult | null>;
|
|
15
18
|
pauseRecording: () => void;
|
|
16
19
|
isRecording: boolean;
|
|
17
20
|
isPaused: boolean;
|
|
@@ -19,6 +22,7 @@ interface UseAudioRecorderState {
|
|
|
19
22
|
size: number; // Size in bytes of the recorded audio
|
|
20
23
|
}
|
|
21
24
|
|
|
25
|
+
|
|
22
26
|
export function useAudioRecorder({onAudioStream}: {onAudioStream?: (buffer: Blob) => void}): UseAudioRecorderState {
|
|
23
27
|
const [isRecording, setIsRecording] = useState(false);
|
|
24
28
|
const [isPaused, setIsPaused] = useState(false);
|
|
@@ -40,34 +44,43 @@ export function useAudioRecorder({onAudioStream}: {onAudioStream?: (buffer: Blob
|
|
|
40
44
|
|
|
41
45
|
|
|
42
46
|
useEffect(() => {
|
|
43
|
-
const subscribe =
|
|
44
|
-
|
|
47
|
+
const subscribe = addAudioEventListener(async ({fileUri, deltaSize, totalSize, from, streamUuid, encoded, mimeType, buffer}) => {
|
|
48
|
+
log(`Received audio event:`, {fileUri, deltaSize, totalSize, mimeType, from, streamUuid, encodedLength: encoded?.length})
|
|
45
49
|
if(deltaSize > 0) {
|
|
46
|
-
//
|
|
47
|
-
const options = {
|
|
48
|
-
encoding: FileSystem.EncodingType.Base64,
|
|
49
|
-
position: from,
|
|
50
|
-
length: deltaSize,
|
|
51
|
-
};
|
|
52
|
-
|
|
50
|
+
// Coming from native ( ios / android ) otherwise buffer is set
|
|
53
51
|
if(Platform.OS !== 'web') {
|
|
54
52
|
// Read the audio file as a base64 string for comparison
|
|
55
53
|
try {
|
|
56
|
-
|
|
57
|
-
const binaryData = atob(
|
|
54
|
+
// convert encoded string to binary data
|
|
55
|
+
const binaryData = atob(encoded);
|
|
58
56
|
const content = new Uint8Array(binaryData.length);
|
|
59
57
|
for (let i = 0; i < binaryData.length; i++) {
|
|
60
|
-
|
|
58
|
+
content[i] = binaryData.charCodeAt(i);
|
|
61
59
|
}
|
|
60
|
+
const audioBlob = new Blob([content], { type: mimeType });
|
|
61
|
+
|
|
62
|
+
// Below code is optional, used to compare encoded data to audio on file system
|
|
63
|
+
// Fetch the audio data from the fileUri
|
|
64
|
+
// const options = {
|
|
65
|
+
// encoding: FileSystem.EncodingType.Base64,
|
|
66
|
+
// position: from,
|
|
67
|
+
// length: deltaSize,
|
|
68
|
+
// };
|
|
69
|
+
// const base64Content = await FileSystem.readAsStringAsync(fileUri, options);
|
|
70
|
+
// const binaryData = atob(base64Content);
|
|
71
|
+
// const content = new Uint8Array(binaryData.length);
|
|
72
|
+
// for (let i = 0; i < binaryData.length; i++) {
|
|
73
|
+
// content[i] = binaryData.charCodeAt(i);
|
|
74
|
+
// }
|
|
75
|
+
// const audioBlob = new Blob([content], { type: 'application/octet-stream' }); // Create a Blob from the byte array
|
|
76
|
+
// console.debug(`Read audio file (len: ${content.length}) vs ${deltaSize}`)
|
|
62
77
|
|
|
63
|
-
// TODO: get the filetype based on audio setting and encoding
|
|
64
|
-
const audioBlob = new Blob([content], { type: 'application/octet-stream' }); // Create a Blob from the byte array
|
|
65
|
-
console.debug(`Read audio file (len: ${content.length}) vs ${deltaSize}`)
|
|
66
78
|
onAudioStream?.(audioBlob);
|
|
67
79
|
} catch (error) {
|
|
68
80
|
console.error('Error reading audio file:', error);
|
|
69
81
|
}
|
|
70
82
|
} else if(buffer) {
|
|
83
|
+
// Coming from web
|
|
71
84
|
onAudioStream?.(buffer);
|
|
72
85
|
}
|
|
73
86
|
}
|
|
@@ -77,57 +90,37 @@ export function useAudioRecorder({onAudioStream}: {onAudioStream?: (buffer: Blob
|
|
|
77
90
|
|
|
78
91
|
|
|
79
92
|
const startRecording = useCallback(async (recordingOptions: RecordingOptions) => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
} catch (error) {
|
|
93
|
-
console.error('Error starting recording:', error);
|
|
94
|
-
setIsRecording(false);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}, [isRecording]);
|
|
98
|
-
|
|
99
|
-
const stopRecording = useCallback(async (): Promise<number> => {
|
|
100
|
-
if (isRecording) {
|
|
93
|
+
setIsRecording(true);
|
|
94
|
+
setIsPaused(false);
|
|
95
|
+
setSize(0);
|
|
96
|
+
setDuration(0);
|
|
97
|
+
try {
|
|
98
|
+
log(`start recoding`, recordingOptions)
|
|
99
|
+
const fileUrl = await ExpoAudioStreamModule.startRecording(recordingOptions);
|
|
100
|
+
|
|
101
|
+
return fileUrl;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error('Error starting recording:', error);
|
|
101
104
|
setIsRecording(false);
|
|
102
|
-
setIsPaused(false);
|
|
103
|
-
try {
|
|
104
|
-
const recordedDuration = await ExpoAudioStreamModule.stopRecording();
|
|
105
|
-
setDuration(recordedDuration);
|
|
106
|
-
return recordedDuration;
|
|
107
|
-
} catch (error) {
|
|
108
|
-
console.error('Error stopping recording:', error);
|
|
109
|
-
return 0;
|
|
110
|
-
}
|
|
111
105
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
106
|
+
}, []);
|
|
107
|
+
|
|
108
|
+
const stopRecording = useCallback(async () => {
|
|
109
|
+
setIsRecording(false);
|
|
110
|
+
setIsPaused(false);
|
|
111
|
+
const result: AudioStreamResult = await ExpoAudioStreamModule.stopRecording();
|
|
112
|
+
return result;
|
|
113
|
+
}, []);
|
|
114
|
+
|
|
115
|
+
const pauseRecording = useCallback(async () => {
|
|
116
|
+
try {
|
|
117
|
+
await ExpoAudioStreamModule.stopRecording()
|
|
118
118
|
setIsPaused(true);
|
|
119
119
|
setIsRecording(false);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error('Error pausing recording:', error);
|
|
120
122
|
}
|
|
121
|
-
}, [
|
|
122
|
-
|
|
123
|
-
// Cleanup listener on unmount to prevent memory leaks
|
|
124
|
-
useEffect(() => {
|
|
125
|
-
return () => {
|
|
126
|
-
if (isRecording) {
|
|
127
|
-
ExpoAudioStreamModule.stopRecording().catch(console.error);
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
}, [isRecording]);
|
|
123
|
+
}, []);
|
|
131
124
|
|
|
132
125
|
return {
|
|
133
126
|
startRecording,
|
package/yarn-error.log
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
Arguments:
|
|
2
|
-
/Users/arthurbreton/.asdf/installs/nodejs/18.19.1/bin/node /Users/arthurbreton/.cache/node/corepack/yarn/1.22.19/bin/yarn.js
|
|
3
|
-
|
|
4
|
-
PATH:
|
|
5
|
-
/Users/arthurbreton/.asdf/plugins/nodejs/shims:/Users/arthurbreton/.asdf/installs/nodejs/18.19.1/.npm/bin:/Users/arthurbreton/.asdf/installs/nodejs/18.19.1/bin:/Users/arthurbreton/.docker/bin:/Users/arthurbreton/.asdf/shims:/opt/homebrew/opt/asdf/libexec/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/X11/bin:/Library/Apple/usr/bin:/Applications/Wireshark.app/Contents/MacOS:/opt/homebrew/opt/libpq/bin:/Users/arthurbreton/Library/Android/sdk/platform-tools:/Users/arthurbreton/.docker/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/Users/arthurbreton/.cargo/bin:/anaconda3/bin:/Users/arthurbreton/.foundry/bin:/opt/homebrew/anaconda3/bin
|
|
6
|
-
|
|
7
|
-
Yarn version:
|
|
8
|
-
1.22.19
|
|
9
|
-
|
|
10
|
-
Node version:
|
|
11
|
-
18.19.1
|
|
12
|
-
|
|
13
|
-
Platform:
|
|
14
|
-
darwin arm64
|
|
15
|
-
|
|
16
|
-
Trace:
|
|
17
|
-
SyntaxError: /Users/arthurbreton/Library/Caches/Yarn/v6/npm-xcode-3.0.1-3efb62aac641ab2c702458f9a0302696146aa53c-integrity/node_modules/xcode/package.json: Unexpected end of JSON input
|
|
18
|
-
at JSON.parse (<anonymous>)
|
|
19
|
-
at /Users/arthurbreton/.cache/node/corepack/yarn/1.22.19/lib/cli.js:1629:59
|
|
20
|
-
at Generator.next (<anonymous>)
|
|
21
|
-
at step (/Users/arthurbreton/.cache/node/corepack/yarn/1.22.19/lib/cli.js:310:30)
|
|
22
|
-
at /Users/arthurbreton/.cache/node/corepack/yarn/1.22.19/lib/cli.js:321:13
|
|
23
|
-
|
|
24
|
-
npm manifest:
|
|
25
|
-
{
|
|
26
|
-
"name": "expo-audio-stream",
|
|
27
|
-
"version": "0.1.0",
|
|
28
|
-
"description": "stream audio crossplatform",
|
|
29
|
-
"main": "build/index.js",
|
|
30
|
-
"types": "build/index.d.ts",
|
|
31
|
-
"scripts": {
|
|
32
|
-
"build": "expo-module build",
|
|
33
|
-
"clean": "expo-module clean",
|
|
34
|
-
"lint": "expo-module lint",
|
|
35
|
-
"test": "expo-module test",
|
|
36
|
-
"prepare": "expo-module prepare",
|
|
37
|
-
"prepublishOnly": "expo-module prepublishOnly",
|
|
38
|
-
"expo-module": "expo-module",
|
|
39
|
-
"open:ios": "open -a \"Xcode\" example/ios",
|
|
40
|
-
"open:android": "open -a \"Android Studio\" example/android"
|
|
41
|
-
},
|
|
42
|
-
"keywords": [
|
|
43
|
-
"react-native",
|
|
44
|
-
"expo",
|
|
45
|
-
"expo-audio-stream",
|
|
46
|
-
"ExpoAudioStream"
|
|
47
|
-
],
|
|
48
|
-
"repository": "https://github.com/deeeed/expo-audio-stream",
|
|
49
|
-
"bugs": {
|
|
50
|
-
"url": "https://github.com/deeeed/expo-audio-stream/issues"
|
|
51
|
-
},
|
|
52
|
-
"author": "Arthur Breton <abreton@siteed.net> (https://github.com/deeeed)",
|
|
53
|
-
"license": "MIT",
|
|
54
|
-
"homepage": "https://github.com/deeeed/expo-audio-stream#readme",
|
|
55
|
-
"dependencies": {},
|
|
56
|
-
"devDependencies": {
|
|
57
|
-
"@types/react": "^18.0.25",
|
|
58
|
-
"expo-module-scripts": "^3.4.1",
|
|
59
|
-
"expo-modules-core": "^1.11.12"
|
|
60
|
-
},
|
|
61
|
-
"peerDependencies": {
|
|
62
|
-
"expo": "*",
|
|
63
|
-
"react": "*",
|
|
64
|
-
"react-native": "*"
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
yarn manifest:
|
|
69
|
-
No manifest
|
|
70
|
-
|
|
71
|
-
Lockfile:
|
|
72
|
-
No lockfile
|