@siteed/expo-audio-stream 2.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -27
- package/build/index.d.ts +11 -12
- package/build/index.js +44 -10
- package/package.json +49 -110
- package/src/index.ts +18 -33
- package/CHANGELOG.md +0 -195
- package/android/build.gradle +0 -105
- package/android/src/main/AndroidManifest.xml +0 -27
- package/android/src/main/java/net/siteed/audiostream/AudioAnalysisData.kt +0 -166
- package/android/src/main/java/net/siteed/audiostream/AudioDataEncoder.kt +0 -9
- package/android/src/main/java/net/siteed/audiostream/AudioFileHandler.kt +0 -131
- package/android/src/main/java/net/siteed/audiostream/AudioFormatUtils.kt +0 -103
- package/android/src/main/java/net/siteed/audiostream/AudioNotificationsManager.kt +0 -435
- package/android/src/main/java/net/siteed/audiostream/AudioProcessor.kt +0 -1936
- package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +0 -1437
- package/android/src/main/java/net/siteed/audiostream/AudioRecordingService.kt +0 -138
- package/android/src/main/java/net/siteed/audiostream/Constants.kt +0 -20
- package/android/src/main/java/net/siteed/audiostream/EventSender.kt +0 -7
- package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +0 -509
- package/android/src/main/java/net/siteed/audiostream/FFT.kt +0 -99
- package/android/src/main/java/net/siteed/audiostream/Features.kt +0 -98
- package/android/src/main/java/net/siteed/audiostream/NotificationConfig.kt +0 -70
- package/android/src/main/java/net/siteed/audiostream/PermissionUtils.kt +0 -59
- package/android/src/main/java/net/siteed/audiostream/RecordingActionReceiver.kt +0 -59
- package/android/src/main/java/net/siteed/audiostream/RecordingConfig.kt +0 -205
- package/android/src/main/java/net/siteed/audiostream/WaveformConfig.kt +0 -19
- package/android/src/main/java/net/siteed/audiostream/WaveformRenderer.kt +0 -159
- package/android/src/main/res/drawable/ic_default_action_icon.xml +0 -16
- package/android/src/main/res/drawable/ic_microphone.xml +0 -13
- package/android/src/main/res/drawable/ic_pause.xml +0 -10
- package/android/src/main/res/drawable/ic_play.xml +0 -10
- package/android/src/main/res/drawable/ic_stop.xml +0 -10
- package/android/src/main/res/layout/notification_recording.xml +0 -37
- package/android/src/main/test/java/net/siteed/audiostream/AudioProcessorTest.kt +0 -56
- package/app.plugin.js +0 -1
- package/build/AudioAnalysis/AudioAnalysis.types.d.ts +0 -144
- package/build/AudioAnalysis/AudioAnalysis.types.d.ts.map +0 -1
- package/build/AudioAnalysis/AudioAnalysis.types.js +0 -3
- package/build/AudioAnalysis/AudioAnalysis.types.js.map +0 -1
- package/build/AudioAnalysis/extractAudioAnalysis.d.ts +0 -78
- package/build/AudioAnalysis/extractAudioAnalysis.d.ts.map +0 -1
- package/build/AudioAnalysis/extractAudioAnalysis.js +0 -229
- package/build/AudioAnalysis/extractAudioAnalysis.js.map +0 -1
- package/build/AudioAnalysis/extractWaveform.d.ts +0 -8
- package/build/AudioAnalysis/extractWaveform.d.ts.map +0 -1
- package/build/AudioAnalysis/extractWaveform.js +0 -11
- package/build/AudioAnalysis/extractWaveform.js.map +0 -1
- package/build/AudioRecorder.provider.d.ts +0 -11
- package/build/AudioRecorder.provider.d.ts.map +0 -1
- package/build/AudioRecorder.provider.js +0 -37
- package/build/AudioRecorder.provider.js.map +0 -1
- package/build/ExpoAudioStream.native.d.ts +0 -3
- package/build/ExpoAudioStream.native.d.ts.map +0 -1
- package/build/ExpoAudioStream.native.js +0 -6
- package/build/ExpoAudioStream.native.js.map +0 -1
- package/build/ExpoAudioStream.types.d.ts +0 -206
- package/build/ExpoAudioStream.types.d.ts.map +0 -1
- package/build/ExpoAudioStream.types.js +0 -2
- package/build/ExpoAudioStream.types.js.map +0 -1
- package/build/ExpoAudioStream.web.d.ts +0 -59
- package/build/ExpoAudioStream.web.d.ts.map +0 -1
- package/build/ExpoAudioStream.web.js +0 -285
- package/build/ExpoAudioStream.web.js.map +0 -1
- package/build/ExpoAudioStreamModule.d.ts +0 -3
- package/build/ExpoAudioStreamModule.d.ts.map +0 -1
- package/build/ExpoAudioStreamModule.js +0 -239
- package/build/ExpoAudioStreamModule.js.map +0 -1
- package/build/WebRecorder.web.d.ts +0 -119
- package/build/WebRecorder.web.d.ts.map +0 -1
- package/build/WebRecorder.web.js +0 -436
- package/build/WebRecorder.web.js.map +0 -1
- package/build/constants.d.ts +0 -11
- package/build/constants.d.ts.map +0 -1
- package/build/constants.js +0 -14
- package/build/constants.js.map +0 -1
- package/build/events.d.ts +0 -26
- package/build/events.d.ts.map +0 -1
- package/build/events.js +0 -21
- package/build/events.js.map +0 -1
- package/build/index.d.ts.map +0 -1
- package/build/index.js.map +0 -1
- package/build/useAudioRecorder.d.ts +0 -21
- package/build/useAudioRecorder.d.ts.map +0 -1
- package/build/useAudioRecorder.js +0 -427
- package/build/useAudioRecorder.js.map +0 -1
- package/build/utils/BlobFix.d.ts +0 -9
- package/build/utils/BlobFix.d.ts.map +0 -1
- package/build/utils/BlobFix.js +0 -498
- package/build/utils/BlobFix.js.map +0 -1
- package/build/utils/audioProcessing.d.ts +0 -24
- package/build/utils/audioProcessing.d.ts.map +0 -1
- package/build/utils/audioProcessing.js +0 -133
- package/build/utils/audioProcessing.js.map +0 -1
- package/build/utils/concatenateBuffers.d.ts +0 -8
- package/build/utils/concatenateBuffers.d.ts.map +0 -1
- package/build/utils/concatenateBuffers.js +0 -21
- package/build/utils/concatenateBuffers.js.map +0 -1
- package/build/utils/convertPCMToFloat32.d.ts +0 -13
- package/build/utils/convertPCMToFloat32.d.ts.map +0 -1
- package/build/utils/convertPCMToFloat32.js +0 -120
- package/build/utils/convertPCMToFloat32.js.map +0 -1
- package/build/utils/encodingToBitDepth.d.ts +0 -5
- package/build/utils/encodingToBitDepth.d.ts.map +0 -1
- package/build/utils/encodingToBitDepth.js +0 -13
- package/build/utils/encodingToBitDepth.js.map +0 -1
- package/build/utils/getWavFileInfo.d.ts +0 -26
- package/build/utils/getWavFileInfo.d.ts.map +0 -1
- package/build/utils/getWavFileInfo.js +0 -92
- package/build/utils/getWavFileInfo.js.map +0 -1
- package/build/utils/writeWavHeader.d.ts +0 -49
- package/build/utils/writeWavHeader.d.ts.map +0 -1
- package/build/utils/writeWavHeader.js +0 -91
- package/build/utils/writeWavHeader.js.map +0 -1
- package/build/workers/InlineFeaturesExtractor.web.d.ts +0 -2
- package/build/workers/InlineFeaturesExtractor.web.d.ts.map +0 -1
- package/build/workers/InlineFeaturesExtractor.web.js +0 -828
- package/build/workers/InlineFeaturesExtractor.web.js.map +0 -1
- package/build/workers/inlineAudioWebWorker.web.d.ts +0 -2
- package/build/workers/inlineAudioWebWorker.web.d.ts.map +0 -1
- package/build/workers/inlineAudioWebWorker.web.js +0 -157
- package/build/workers/inlineAudioWebWorker.web.js.map +0 -1
- package/expo-module.config.json +0 -9
- package/ios/AudioAnalysisData.swift +0 -74
- package/ios/AudioNotificationManager.swift +0 -135
- package/ios/AudioProcessingHelpers.swift +0 -743
- package/ios/AudioProcessor.swift +0 -858
- package/ios/AudioStreamError.swift +0 -7
- package/ios/AudioStreamManager.swift +0 -1708
- package/ios/AudioStreamManagerDelegate.swift +0 -16
- package/ios/DataPoint.swift +0 -54
- package/ios/DecodingConfig.swift +0 -47
- package/ios/ExpoAudioStream.podspec +0 -27
- package/ios/ExpoAudioStreamModule.swift +0 -698
- package/ios/FFT.swift +0 -62
- package/ios/Features.swift +0 -95
- package/ios/Logger.swift +0 -7
- package/ios/NotificationExtension.swift +0 -15
- package/ios/RecordingResult.swift +0 -22
- package/ios/RecordingSettings.swift +0 -265
- package/ios/WaveformExtractor.swift +0 -105
- package/plugin/build/index.d.ts +0 -21
- package/plugin/build/index.js +0 -191
- package/plugin/src/index.ts +0 -278
- package/plugin/tsconfig.json +0 -10
- package/plugin/tsconfig.tsbuildinfo +0 -1
- package/src/AudioAnalysis/AudioAnalysis.types.ts +0 -165
- package/src/AudioAnalysis/extractAudioAnalysis.ts +0 -370
- package/src/AudioAnalysis/extractWaveform.ts +0 -22
- package/src/AudioRecorder.provider.tsx +0 -54
- package/src/ExpoAudioStream.native.ts +0 -6
- package/src/ExpoAudioStream.types.ts +0 -329
- package/src/ExpoAudioStream.web.ts +0 -359
- package/src/ExpoAudioStreamModule.ts +0 -286
- package/src/WebRecorder.web.ts +0 -580
- package/src/constants.ts +0 -18
- package/src/events.ts +0 -60
- package/src/useAudioRecorder.tsx +0 -620
- package/src/utils/BlobFix.ts +0 -559
- package/src/utils/audioProcessing.ts +0 -205
- package/src/utils/concatenateBuffers.ts +0 -24
- package/src/utils/convertPCMToFloat32.ts +0 -170
- package/src/utils/encodingToBitDepth.ts +0 -18
- package/src/utils/getWavFileInfo.ts +0 -132
- package/src/utils/writeWavHeader.ts +0 -114
- package/src/workers/InlineFeaturesExtractor.web.tsx +0 -827
- package/src/workers/inlineAudioWebWorker.web.tsx +0 -156
package/plugin/build/index.js
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const config_plugins_1 = require("@expo/config-plugins");
|
|
4
|
-
const MICROPHONE_USAGE = 'Allow $(PRODUCT_NAME) to access your microphone';
|
|
5
|
-
const NOTIFICATION_USAGE = 'Show recording notifications and controls';
|
|
6
|
-
const LOG_PREFIX = '[@siteed/expo-audio-stream]';
|
|
7
|
-
function debugLog(message, ...args) {
|
|
8
|
-
if (process.env.EXPO_DEBUG) {
|
|
9
|
-
console.log(`${LOG_PREFIX} ${message}`, ...args);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
const withRecordingPermission = (config, props) => {
|
|
13
|
-
const options = {
|
|
14
|
-
enablePhoneStateHandling: true, // Default to true for backward compatibility
|
|
15
|
-
enableNotifications: true,
|
|
16
|
-
enableBackgroundAudio: true,
|
|
17
|
-
iosBackgroundModes: {
|
|
18
|
-
useVoIP: false,
|
|
19
|
-
useAudio: false,
|
|
20
|
-
useProcessing: false,
|
|
21
|
-
useLocation: false,
|
|
22
|
-
useExternalAccessory: false,
|
|
23
|
-
},
|
|
24
|
-
iosConfig: {
|
|
25
|
-
microphoneUsageDescription: MICROPHONE_USAGE,
|
|
26
|
-
notificationUsageDescription: NOTIFICATION_USAGE,
|
|
27
|
-
},
|
|
28
|
-
...(props || {}),
|
|
29
|
-
};
|
|
30
|
-
const { enablePhoneStateHandling, enableNotifications, enableBackgroundAudio, } = options;
|
|
31
|
-
debugLog('📱 Configuring Recording Permissions Plugin...', options);
|
|
32
|
-
// iOS Configuration
|
|
33
|
-
config = (0, config_plugins_1.withInfoPlist)(config, (config) => {
|
|
34
|
-
// Always set the microphone usage description from options first
|
|
35
|
-
config.modResults['NSMicrophoneUsageDescription'] =
|
|
36
|
-
options.iosConfig?.microphoneUsageDescription ||
|
|
37
|
-
config.modResults['NSMicrophoneUsageDescription'] ||
|
|
38
|
-
MICROPHONE_USAGE;
|
|
39
|
-
if (enableNotifications) {
|
|
40
|
-
config.modResults['NSUserNotificationsUsageDescription'] =
|
|
41
|
-
options.iosConfig?.notificationUsageDescription ||
|
|
42
|
-
config.modResults['NSUserNotificationsUsageDescription'] ||
|
|
43
|
-
NOTIFICATION_USAGE;
|
|
44
|
-
config.modResults['NSUserNotificationAlertStyle'] = 'alert';
|
|
45
|
-
}
|
|
46
|
-
const existingBackgroundModes = config.modResults.UIBackgroundModes || [];
|
|
47
|
-
// Only add background modes if explicitly enabled and set to true
|
|
48
|
-
if (options.iosBackgroundModes?.useAudio === true &&
|
|
49
|
-
enableBackgroundAudio === true &&
|
|
50
|
-
!existingBackgroundModes.includes('audio')) {
|
|
51
|
-
// Don't automatically add 'audio' background mode as it's only for playback
|
|
52
|
-
// existingBackgroundModes.push('audio')
|
|
53
|
-
// Instead, ensure processing mode is used for background recording
|
|
54
|
-
if (options.iosBackgroundModes?.useProcessing !== true) {
|
|
55
|
-
console.warn(`${LOG_PREFIX} Warning: Background audio recording requires 'processing' background mode. Please enable 'useProcessing' in iosBackgroundModes.`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (options.iosBackgroundModes?.useVoIP === true &&
|
|
59
|
-
enablePhoneStateHandling === true) {
|
|
60
|
-
if (!existingBackgroundModes.includes('voip')) {
|
|
61
|
-
existingBackgroundModes.push('voip');
|
|
62
|
-
}
|
|
63
|
-
const existingCapabilities = (config.modResults
|
|
64
|
-
.UIRequiredDeviceCapabilities || []);
|
|
65
|
-
if (!existingCapabilities.includes('telephony')) {
|
|
66
|
-
existingCapabilities.push('telephony');
|
|
67
|
-
}
|
|
68
|
-
config.modResults.UIRequiredDeviceCapabilities =
|
|
69
|
-
existingCapabilities;
|
|
70
|
-
}
|
|
71
|
-
// Add additional background modes only if explicitly set to true
|
|
72
|
-
if (options.iosBackgroundModes?.useProcessing === true) {
|
|
73
|
-
if (!existingBackgroundModes.includes('processing')) {
|
|
74
|
-
existingBackgroundModes.push('processing');
|
|
75
|
-
}
|
|
76
|
-
// Add processing info if enabled
|
|
77
|
-
config.modResults.BGTaskSchedulerPermittedIdentifiers = [
|
|
78
|
-
'com.siteed.audiostream.processing',
|
|
79
|
-
];
|
|
80
|
-
}
|
|
81
|
-
if (options.iosBackgroundModes?.useLocation === true) {
|
|
82
|
-
if (!existingBackgroundModes.includes('location')) {
|
|
83
|
-
existingBackgroundModes.push('location');
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (options.iosBackgroundModes?.useExternalAccessory === true) {
|
|
87
|
-
if (!existingBackgroundModes.includes('external-accessory')) {
|
|
88
|
-
existingBackgroundModes.push('external-accessory');
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
// Configure background processing info if enabled
|
|
92
|
-
if (options.iosConfig?.backgroundProcessingTitle) {
|
|
93
|
-
config.modResults.BGProcessingTaskTitle =
|
|
94
|
-
options.iosConfig.backgroundProcessingTitle;
|
|
95
|
-
}
|
|
96
|
-
// Configure audio session behavior
|
|
97
|
-
if (options.iosConfig?.allowBackgroundAudioControls) {
|
|
98
|
-
config.modResults.UIBackgroundModes = [
|
|
99
|
-
...existingBackgroundModes,
|
|
100
|
-
'remote-notification',
|
|
101
|
-
];
|
|
102
|
-
config.modResults.MPNowPlayingInfoPropertyPlaybackRate = true;
|
|
103
|
-
}
|
|
104
|
-
config.modResults.UIBackgroundModes = existingBackgroundModes;
|
|
105
|
-
return config;
|
|
106
|
-
});
|
|
107
|
-
// Android Configuration
|
|
108
|
-
config = (0, config_plugins_1.withAndroidManifest)(config, (config) => {
|
|
109
|
-
const basePermissions = [
|
|
110
|
-
'android.permission.RECORD_AUDIO',
|
|
111
|
-
'android.permission.WAKE_LOCK',
|
|
112
|
-
];
|
|
113
|
-
const optionalPermissions = [
|
|
114
|
-
enableNotifications && 'android.permission.POST_NOTIFICATIONS',
|
|
115
|
-
enablePhoneStateHandling && 'android.permission.READ_PHONE_STATE',
|
|
116
|
-
enableBackgroundAudio && 'android.permission.FOREGROUND_SERVICE',
|
|
117
|
-
enableBackgroundAudio &&
|
|
118
|
-
'android.permission.FOREGROUND_SERVICE_MICROPHONE',
|
|
119
|
-
].filter(Boolean);
|
|
120
|
-
const permissionsToAdd = [...basePermissions, ...optionalPermissions];
|
|
121
|
-
debugLog('📋 Existing Android permissions:', config.modResults.manifest['uses-permission']?.map((p) => p.$?.['android:name']) || []);
|
|
122
|
-
debugLog('➕ Adding Android permissions:', permissionsToAdd);
|
|
123
|
-
const { addPermission } = config_plugins_1.AndroidConfig.Permissions;
|
|
124
|
-
// Add each permission only if it doesn't exist
|
|
125
|
-
permissionsToAdd.forEach((permission) => {
|
|
126
|
-
const existingPermission = config.modResults.manifest['uses-permission']?.find((p) => p.$?.['android:name'] === permission);
|
|
127
|
-
if (!existingPermission) {
|
|
128
|
-
addPermission(config.modResults, permission);
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
// Get the main application node
|
|
132
|
-
const mainApplication = config.modResults.manifest.application?.[0];
|
|
133
|
-
if (mainApplication) {
|
|
134
|
-
debugLog('📱 Configuring Android application components...');
|
|
135
|
-
// Add RecordingActionReceiver
|
|
136
|
-
if (!mainApplication.receiver) {
|
|
137
|
-
mainApplication.receiver = [];
|
|
138
|
-
}
|
|
139
|
-
const receiverConfig = {
|
|
140
|
-
$: {
|
|
141
|
-
'android:name': '.RecordingActionReceiver',
|
|
142
|
-
'android:exported': 'false',
|
|
143
|
-
},
|
|
144
|
-
'intent-filter': [
|
|
145
|
-
{
|
|
146
|
-
action: [
|
|
147
|
-
{ $: { 'android:name': 'PAUSE_RECORDING' } },
|
|
148
|
-
{ $: { 'android:name': 'RESUME_RECORDING' } },
|
|
149
|
-
{ $: { 'android:name': 'STOP_RECORDING' } },
|
|
150
|
-
],
|
|
151
|
-
},
|
|
152
|
-
],
|
|
153
|
-
};
|
|
154
|
-
const receiverIndex = mainApplication.receiver.findIndex((receiver) => receiver.$?.['android:name'] === '.RecordingActionReceiver');
|
|
155
|
-
if (receiverIndex >= 0) {
|
|
156
|
-
mainApplication.receiver[receiverIndex] = receiverConfig;
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
mainApplication.receiver.push(receiverConfig);
|
|
160
|
-
}
|
|
161
|
-
debugLog('✅ RecordingActionReceiver configured');
|
|
162
|
-
// Add AudioRecordingService
|
|
163
|
-
if (!mainApplication.service) {
|
|
164
|
-
mainApplication.service = [];
|
|
165
|
-
}
|
|
166
|
-
const serviceConfig = {
|
|
167
|
-
$: {
|
|
168
|
-
'android:name': '.AudioRecordingService',
|
|
169
|
-
'android:enabled': 'true',
|
|
170
|
-
'android:exported': 'false',
|
|
171
|
-
'android:foregroundServiceType': 'microphone',
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
const serviceIndex = mainApplication.service.findIndex((service) => service.$?.['android:name'] === '.AudioRecordingService');
|
|
175
|
-
if (serviceIndex >= 0) {
|
|
176
|
-
mainApplication.service[serviceIndex] = serviceConfig;
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
mainApplication.service.push(serviceConfig);
|
|
180
|
-
}
|
|
181
|
-
debugLog('✅ AudioRecordingService configured');
|
|
182
|
-
}
|
|
183
|
-
else {
|
|
184
|
-
console.error(`${LOG_PREFIX} ❌ Main application node not found in Android Manifest`);
|
|
185
|
-
}
|
|
186
|
-
return config;
|
|
187
|
-
});
|
|
188
|
-
debugLog('✨ Recording Permissions Plugin configuration completed');
|
|
189
|
-
return config;
|
|
190
|
-
};
|
|
191
|
-
exports.default = withRecordingPermission;
|
package/plugin/src/index.ts
DELETED
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ConfigPlugin,
|
|
3
|
-
withAndroidManifest,
|
|
4
|
-
withInfoPlist,
|
|
5
|
-
AndroidConfig,
|
|
6
|
-
} from '@expo/config-plugins'
|
|
7
|
-
import { ExpoConfig } from '@expo/config-types'
|
|
8
|
-
|
|
9
|
-
const MICROPHONE_USAGE = 'Allow $(PRODUCT_NAME) to access your microphone'
|
|
10
|
-
const NOTIFICATION_USAGE = 'Show recording notifications and controls'
|
|
11
|
-
const LOG_PREFIX = '[@siteed/expo-audio-stream]'
|
|
12
|
-
|
|
13
|
-
function debugLog(message: string, ...args: unknown[]): void {
|
|
14
|
-
if (process.env.EXPO_DEBUG) {
|
|
15
|
-
console.log(`${LOG_PREFIX} ${message}`, ...args)
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
interface AudioStreamPluginOptions {
|
|
20
|
-
enablePhoneStateHandling?: boolean // Controls READ_PHONE_STATE permission
|
|
21
|
-
enableNotifications?: boolean
|
|
22
|
-
enableBackgroundAudio?: boolean
|
|
23
|
-
iosBackgroundModes?: {
|
|
24
|
-
useVoIP?: boolean
|
|
25
|
-
useAudio?: boolean
|
|
26
|
-
useProcessing?: boolean
|
|
27
|
-
useLocation?: boolean
|
|
28
|
-
useExternalAccessory?: boolean
|
|
29
|
-
}
|
|
30
|
-
iosConfig?: {
|
|
31
|
-
allowBackgroundAudioControls?: boolean
|
|
32
|
-
backgroundProcessingTitle?: string
|
|
33
|
-
microphoneUsageDescription?: string
|
|
34
|
-
notificationUsageDescription?: string
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const withRecordingPermission: ConfigPlugin<AudioStreamPluginOptions> = (
|
|
39
|
-
config: ExpoConfig,
|
|
40
|
-
props: AudioStreamPluginOptions | void
|
|
41
|
-
) => {
|
|
42
|
-
const options: AudioStreamPluginOptions = {
|
|
43
|
-
enablePhoneStateHandling: true, // Default to true for backward compatibility
|
|
44
|
-
enableNotifications: true,
|
|
45
|
-
enableBackgroundAudio: true,
|
|
46
|
-
iosBackgroundModes: {
|
|
47
|
-
useVoIP: false,
|
|
48
|
-
useAudio: false,
|
|
49
|
-
useProcessing: false,
|
|
50
|
-
useLocation: false,
|
|
51
|
-
useExternalAccessory: false,
|
|
52
|
-
},
|
|
53
|
-
iosConfig: {
|
|
54
|
-
microphoneUsageDescription: MICROPHONE_USAGE,
|
|
55
|
-
notificationUsageDescription: NOTIFICATION_USAGE,
|
|
56
|
-
},
|
|
57
|
-
...(props || {}),
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const {
|
|
61
|
-
enablePhoneStateHandling,
|
|
62
|
-
enableNotifications,
|
|
63
|
-
enableBackgroundAudio,
|
|
64
|
-
} = options
|
|
65
|
-
|
|
66
|
-
debugLog('📱 Configuring Recording Permissions Plugin...', options)
|
|
67
|
-
|
|
68
|
-
// iOS Configuration
|
|
69
|
-
config = withInfoPlist(config as any, (config) => {
|
|
70
|
-
// Always set the microphone usage description from options first
|
|
71
|
-
config.modResults['NSMicrophoneUsageDescription'] =
|
|
72
|
-
options.iosConfig?.microphoneUsageDescription ||
|
|
73
|
-
config.modResults['NSMicrophoneUsageDescription'] ||
|
|
74
|
-
MICROPHONE_USAGE
|
|
75
|
-
|
|
76
|
-
if (enableNotifications) {
|
|
77
|
-
config.modResults['NSUserNotificationsUsageDescription'] =
|
|
78
|
-
options.iosConfig?.notificationUsageDescription ||
|
|
79
|
-
config.modResults['NSUserNotificationsUsageDescription'] ||
|
|
80
|
-
NOTIFICATION_USAGE
|
|
81
|
-
config.modResults['NSUserNotificationAlertStyle'] = 'alert'
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const existingBackgroundModes =
|
|
85
|
-
config.modResults.UIBackgroundModes || []
|
|
86
|
-
|
|
87
|
-
// Only add background modes if explicitly enabled and set to true
|
|
88
|
-
if (
|
|
89
|
-
options.iosBackgroundModes?.useAudio === true &&
|
|
90
|
-
enableBackgroundAudio === true &&
|
|
91
|
-
!existingBackgroundModes.includes('audio')
|
|
92
|
-
) {
|
|
93
|
-
// Don't automatically add 'audio' background mode as it's only for playback
|
|
94
|
-
// existingBackgroundModes.push('audio')
|
|
95
|
-
|
|
96
|
-
// Instead, ensure processing mode is used for background recording
|
|
97
|
-
if (options.iosBackgroundModes?.useProcessing !== true) {
|
|
98
|
-
console.warn(
|
|
99
|
-
`${LOG_PREFIX} Warning: Background audio recording requires 'processing' background mode. Please enable 'useProcessing' in iosBackgroundModes.`
|
|
100
|
-
)
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (
|
|
105
|
-
options.iosBackgroundModes?.useVoIP === true &&
|
|
106
|
-
enablePhoneStateHandling === true
|
|
107
|
-
) {
|
|
108
|
-
if (!existingBackgroundModes.includes('voip')) {
|
|
109
|
-
existingBackgroundModes.push('voip')
|
|
110
|
-
}
|
|
111
|
-
const existingCapabilities = (config.modResults
|
|
112
|
-
.UIRequiredDeviceCapabilities || []) as string[]
|
|
113
|
-
if (!existingCapabilities.includes('telephony')) {
|
|
114
|
-
existingCapabilities.push('telephony')
|
|
115
|
-
}
|
|
116
|
-
config.modResults.UIRequiredDeviceCapabilities =
|
|
117
|
-
existingCapabilities
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Add additional background modes only if explicitly set to true
|
|
121
|
-
if (options.iosBackgroundModes?.useProcessing === true) {
|
|
122
|
-
if (!existingBackgroundModes.includes('processing')) {
|
|
123
|
-
existingBackgroundModes.push('processing')
|
|
124
|
-
}
|
|
125
|
-
// Add processing info if enabled
|
|
126
|
-
config.modResults.BGTaskSchedulerPermittedIdentifiers = [
|
|
127
|
-
'com.siteed.audiostream.processing',
|
|
128
|
-
]
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (options.iosBackgroundModes?.useLocation === true) {
|
|
132
|
-
if (!existingBackgroundModes.includes('location')) {
|
|
133
|
-
existingBackgroundModes.push('location')
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (options.iosBackgroundModes?.useExternalAccessory === true) {
|
|
138
|
-
if (!existingBackgroundModes.includes('external-accessory')) {
|
|
139
|
-
existingBackgroundModes.push('external-accessory')
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Configure background processing info if enabled
|
|
144
|
-
if (options.iosConfig?.backgroundProcessingTitle) {
|
|
145
|
-
config.modResults.BGProcessingTaskTitle =
|
|
146
|
-
options.iosConfig.backgroundProcessingTitle
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Configure audio session behavior
|
|
150
|
-
if (options.iosConfig?.allowBackgroundAudioControls) {
|
|
151
|
-
config.modResults.UIBackgroundModes = [
|
|
152
|
-
...existingBackgroundModes,
|
|
153
|
-
'remote-notification',
|
|
154
|
-
]
|
|
155
|
-
config.modResults.MPNowPlayingInfoPropertyPlaybackRate = true
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
config.modResults.UIBackgroundModes = existingBackgroundModes
|
|
159
|
-
return config
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
// Android Configuration
|
|
163
|
-
config = withAndroidManifest(config as any, (config) => {
|
|
164
|
-
const basePermissions = [
|
|
165
|
-
'android.permission.RECORD_AUDIO',
|
|
166
|
-
'android.permission.WAKE_LOCK',
|
|
167
|
-
]
|
|
168
|
-
|
|
169
|
-
const optionalPermissions = [
|
|
170
|
-
enableNotifications && 'android.permission.POST_NOTIFICATIONS',
|
|
171
|
-
enablePhoneStateHandling && 'android.permission.READ_PHONE_STATE',
|
|
172
|
-
enableBackgroundAudio && 'android.permission.FOREGROUND_SERVICE',
|
|
173
|
-
enableBackgroundAudio &&
|
|
174
|
-
'android.permission.FOREGROUND_SERVICE_MICROPHONE',
|
|
175
|
-
].filter(Boolean) as string[]
|
|
176
|
-
|
|
177
|
-
const permissionsToAdd = [...basePermissions, ...optionalPermissions]
|
|
178
|
-
|
|
179
|
-
debugLog(
|
|
180
|
-
'📋 Existing Android permissions:',
|
|
181
|
-
config.modResults.manifest['uses-permission']?.map(
|
|
182
|
-
(p) => p.$?.['android:name']
|
|
183
|
-
) || []
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
debugLog('➕ Adding Android permissions:', permissionsToAdd)
|
|
187
|
-
|
|
188
|
-
const { addPermission } = AndroidConfig.Permissions
|
|
189
|
-
|
|
190
|
-
// Add each permission only if it doesn't exist
|
|
191
|
-
permissionsToAdd.forEach((permission) => {
|
|
192
|
-
const existingPermission = config.modResults.manifest[
|
|
193
|
-
'uses-permission'
|
|
194
|
-
]?.find((p) => p.$?.['android:name'] === permission)
|
|
195
|
-
if (!existingPermission) {
|
|
196
|
-
addPermission(config.modResults, permission)
|
|
197
|
-
}
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
// Get the main application node
|
|
201
|
-
const mainApplication = config.modResults.manifest.application?.[0]
|
|
202
|
-
if (mainApplication) {
|
|
203
|
-
debugLog('📱 Configuring Android application components...')
|
|
204
|
-
|
|
205
|
-
// Add RecordingActionReceiver
|
|
206
|
-
if (!mainApplication.receiver) {
|
|
207
|
-
mainApplication.receiver = []
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const receiverConfig = {
|
|
211
|
-
$: {
|
|
212
|
-
'android:name': '.RecordingActionReceiver',
|
|
213
|
-
'android:exported': 'false' as const,
|
|
214
|
-
},
|
|
215
|
-
'intent-filter': [
|
|
216
|
-
{
|
|
217
|
-
action: [
|
|
218
|
-
{ $: { 'android:name': 'PAUSE_RECORDING' } },
|
|
219
|
-
{ $: { 'android:name': 'RESUME_RECORDING' } },
|
|
220
|
-
{ $: { 'android:name': 'STOP_RECORDING' } },
|
|
221
|
-
],
|
|
222
|
-
},
|
|
223
|
-
],
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const receiverIndex = mainApplication.receiver.findIndex(
|
|
227
|
-
(receiver: any) =>
|
|
228
|
-
receiver.$?.['android:name'] === '.RecordingActionReceiver'
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
if (receiverIndex >= 0) {
|
|
232
|
-
mainApplication.receiver[receiverIndex] = receiverConfig
|
|
233
|
-
} else {
|
|
234
|
-
mainApplication.receiver.push(receiverConfig)
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
debugLog('✅ RecordingActionReceiver configured')
|
|
238
|
-
|
|
239
|
-
// Add AudioRecordingService
|
|
240
|
-
if (!mainApplication.service) {
|
|
241
|
-
mainApplication.service = []
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const serviceConfig = {
|
|
245
|
-
$: {
|
|
246
|
-
'android:name': '.AudioRecordingService',
|
|
247
|
-
'android:enabled': 'true' as const,
|
|
248
|
-
'android:exported': 'false' as const,
|
|
249
|
-
'android:foregroundServiceType': 'microphone',
|
|
250
|
-
},
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const serviceIndex = mainApplication.service.findIndex(
|
|
254
|
-
(service: any) =>
|
|
255
|
-
service.$?.['android:name'] === '.AudioRecordingService'
|
|
256
|
-
)
|
|
257
|
-
|
|
258
|
-
if (serviceIndex >= 0) {
|
|
259
|
-
mainApplication.service[serviceIndex] = serviceConfig
|
|
260
|
-
} else {
|
|
261
|
-
mainApplication.service.push(serviceConfig)
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
debugLog('✅ AudioRecordingService configured')
|
|
265
|
-
} else {
|
|
266
|
-
console.error(
|
|
267
|
-
`${LOG_PREFIX} ❌ Main application node not found in Android Manifest`
|
|
268
|
-
)
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
return config
|
|
272
|
-
})
|
|
273
|
-
|
|
274
|
-
debugLog('✨ Recording Permissions Plugin configuration completed')
|
|
275
|
-
return config as any
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
export default withRecordingPermission
|
package/plugin/tsconfig.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"root":["./src/index.ts"],"version":"5.7.2"}
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
// packages/expo-audio-stream/src/AudioAnalysis/AudioAnalysis.types.ts
|
|
2
|
-
|
|
3
|
-
import { BitDepth, ConsoleLike } from '../ExpoAudioStream.types'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Represents the configuration for decoding audio data.
|
|
7
|
-
*/
|
|
8
|
-
export interface DecodingConfig {
|
|
9
|
-
/** Target sample rate for decoded audio (Android and Web) */
|
|
10
|
-
targetSampleRate?: number
|
|
11
|
-
/** Target number of channels (Android and Web) */
|
|
12
|
-
targetChannels?: number
|
|
13
|
-
/** Target bit depth (Android and Web) */
|
|
14
|
-
targetBitDepth?: BitDepth
|
|
15
|
-
/** Whether to normalize audio levels (Android and Web) */
|
|
16
|
-
normalizeAudio?: boolean
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Represents speech-related features extracted from audio.
|
|
21
|
-
*/
|
|
22
|
-
export interface SpeechFeatures {
|
|
23
|
-
isActive: boolean // Whether speech is detected in this segment
|
|
24
|
-
speakerId?: number // Optional speaker identification
|
|
25
|
-
// Could add more speech-related features here like:
|
|
26
|
-
// confidence: number
|
|
27
|
-
// language?: string
|
|
28
|
-
// sentiment?: number
|
|
29
|
-
// etc.
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Represents various audio features extracted from an audio signal.
|
|
34
|
-
*/
|
|
35
|
-
export interface AudioFeatures {
|
|
36
|
-
energy?: number // The infinite integral of the squared signal, representing the overall energy of the audio.
|
|
37
|
-
mfcc?: number[] // Mel-frequency cepstral coefficients, describing the short-term power spectrum of a sound.
|
|
38
|
-
rms?: number // Root mean square value, indicating the amplitude of the audio signal.
|
|
39
|
-
minAmplitude?: number // Minimum amplitude value in the audio signal.
|
|
40
|
-
maxAmplitude?: number // Maximum amplitude value in the audio signal.
|
|
41
|
-
zcr?: number // Zero-crossing rate, indicating the rate at which the signal changes sign.
|
|
42
|
-
spectralCentroid?: number // The center of mass of the spectrum, indicating the brightness of the sound.
|
|
43
|
-
spectralFlatness?: number // Measure of the flatness of the spectrum, indicating how noise-like the signal is.
|
|
44
|
-
spectralRolloff?: number // The frequency below which a specified percentage (usually 85%) of the total spectral energy lies.
|
|
45
|
-
spectralBandwidth?: number // The width of the spectrum, indicating the range of frequencies present.
|
|
46
|
-
chromagram?: number[] // Chromagram, representing the 12 different pitch classes of the audio.
|
|
47
|
-
tempo?: number // Estimated tempo of the audio signal, measured in beats per minute (BPM).
|
|
48
|
-
hnr?: number // Harmonics-to-noise ratio, indicating the proportion of harmonics to noise in the audio signal.
|
|
49
|
-
melSpectrogram?: number[] // Mel-scaled spectrogram representation of the audio.
|
|
50
|
-
spectralContrast?: number[] // Spectral contrast features representing the difference between peaks and valleys.
|
|
51
|
-
tonnetz?: number[] // Tonal network features representing harmonic relationships.
|
|
52
|
-
pitch?: number // Pitch of the audio signal, measured in Hertz (Hz).
|
|
53
|
-
crc32?: number // crc32 checksum of the audio signal, used to verify the integrity of the audio.
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Options to specify which audio features to extract.
|
|
58
|
-
*/
|
|
59
|
-
export interface AudioFeaturesOptions {
|
|
60
|
-
energy?: boolean
|
|
61
|
-
mfcc?: boolean
|
|
62
|
-
rms?: boolean
|
|
63
|
-
zcr?: boolean
|
|
64
|
-
spectralCentroid?: boolean
|
|
65
|
-
spectralFlatness?: boolean
|
|
66
|
-
spectralRolloff?: boolean
|
|
67
|
-
spectralBandwidth?: boolean
|
|
68
|
-
chromagram?: boolean
|
|
69
|
-
tempo?: boolean
|
|
70
|
-
hnr?: boolean
|
|
71
|
-
melSpectrogram?: boolean
|
|
72
|
-
spectralContrast?: boolean
|
|
73
|
-
tonnetz?: boolean
|
|
74
|
-
pitch?: boolean
|
|
75
|
-
crc32?: boolean
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Represents a single data point in the audio analysis.
|
|
80
|
-
*/
|
|
81
|
-
export interface DataPoint {
|
|
82
|
-
id: number
|
|
83
|
-
amplitude: number // Peak amplitude for the segment
|
|
84
|
-
rms: number // Root mean square value
|
|
85
|
-
dB: number // Always computed
|
|
86
|
-
silent: boolean // Always computed
|
|
87
|
-
features?: AudioFeatures
|
|
88
|
-
speech?: SpeechFeatures
|
|
89
|
-
startTime?: number
|
|
90
|
-
endTime?: number
|
|
91
|
-
// start / end position in bytes
|
|
92
|
-
startPosition?: number
|
|
93
|
-
endPosition?: number
|
|
94
|
-
// number of audio samples for this point (samples size depends on bit depth)
|
|
95
|
-
samples?: number
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Represents the complete data from the audio analysis.
|
|
100
|
-
*/
|
|
101
|
-
export interface AudioAnalysis {
|
|
102
|
-
segmentDurationMs: number // Duration of each segment in milliseconds
|
|
103
|
-
durationMs: number // Duration of the audio in milliseconds
|
|
104
|
-
bitDepth: number // Bit depth of the audio
|
|
105
|
-
samples: number // Size of the audio in bytes
|
|
106
|
-
numberOfChannels: number // Number of audio channels
|
|
107
|
-
sampleRate: number // Sample rate of the audio
|
|
108
|
-
dataPoints: DataPoint[] // Array of data points from the analysis.
|
|
109
|
-
amplitudeRange: {
|
|
110
|
-
min: number
|
|
111
|
-
max: number
|
|
112
|
-
}
|
|
113
|
-
rmsRange: {
|
|
114
|
-
min: number
|
|
115
|
-
max: number
|
|
116
|
-
}
|
|
117
|
-
// TODO: speaker changes into a broader speech analysis section
|
|
118
|
-
speechAnalysis?: {
|
|
119
|
-
speakerChanges: {
|
|
120
|
-
timestamp: number
|
|
121
|
-
speakerId: number
|
|
122
|
-
}[]
|
|
123
|
-
// Could add more speech analysis data here like:
|
|
124
|
-
// dominantSpeaker?: number
|
|
125
|
-
// totalSpeechDuration?: number
|
|
126
|
-
// speakerStats?: { [speakerId: number]: { duration: number, segments: number } }
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Options for specifying a time range within an audio file.
|
|
132
|
-
*/
|
|
133
|
-
export interface AudioRangeOptions {
|
|
134
|
-
/** Start time in milliseconds */
|
|
135
|
-
startTimeMs?: number
|
|
136
|
-
/** End time in milliseconds */
|
|
137
|
-
endTimeMs?: number
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Options for generating a quick preview of audio waveform.
|
|
142
|
-
* This is optimized for UI rendering with a specified number of points.
|
|
143
|
-
*/
|
|
144
|
-
export interface PreviewOptions extends AudioRangeOptions {
|
|
145
|
-
/** URI of the audio file to analyze */
|
|
146
|
-
fileUri: string
|
|
147
|
-
/**
|
|
148
|
-
* Total number of points to generate for the preview.
|
|
149
|
-
* @default 100
|
|
150
|
-
*/
|
|
151
|
-
numberOfPoints?: number
|
|
152
|
-
/**
|
|
153
|
-
* Optional logger for debugging.
|
|
154
|
-
*/
|
|
155
|
-
logger?: ConsoleLike
|
|
156
|
-
/**
|
|
157
|
-
* Optional configuration for decoding the audio file.
|
|
158
|
-
* Defaults to:
|
|
159
|
-
* - targetSampleRate: undefined (keep original)
|
|
160
|
-
* - targetChannels: undefined (keep original)
|
|
161
|
-
* - targetBitDepth: 16
|
|
162
|
-
* - normalizeAudio: false
|
|
163
|
-
*/
|
|
164
|
-
decodingOptions?: DecodingConfig
|
|
165
|
-
}
|