@siteed/expo-audio-stream 1.5.2 → 1.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 (94) hide show
  1. package/CHANGELOG.md +19 -27
  2. package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +13 -2
  3. package/build/AudioAnalysis/AudioAnalysis.types.d.ts +74 -0
  4. package/build/AudioAnalysis/AudioAnalysis.types.d.ts.map +1 -0
  5. package/build/AudioAnalysis/AudioAnalysis.types.js +3 -0
  6. package/build/AudioAnalysis/AudioAnalysis.types.js.map +1 -0
  7. package/build/AudioAnalysis/extractAudioAnalysis.d.ts +22 -0
  8. package/build/AudioAnalysis/extractAudioAnalysis.d.ts.map +1 -0
  9. package/build/AudioAnalysis/extractAudioAnalysis.js +86 -0
  10. package/build/AudioAnalysis/extractAudioAnalysis.js.map +1 -0
  11. package/build/AudioAnalysis/extractWaveform.d.ts +8 -0
  12. package/build/AudioAnalysis/extractWaveform.d.ts.map +1 -0
  13. package/build/AudioAnalysis/extractWaveform.js +11 -0
  14. package/build/AudioAnalysis/extractWaveform.js.map +1 -0
  15. package/build/AudioRecorder.provider.d.ts +11 -0
  16. package/build/AudioRecorder.provider.d.ts.map +1 -0
  17. package/build/AudioRecorder.provider.js +36 -0
  18. package/build/AudioRecorder.provider.js.map +1 -0
  19. package/build/ExpoAudioStream.native.d.ts +3 -0
  20. package/build/ExpoAudioStream.native.d.ts.map +1 -0
  21. package/build/ExpoAudioStream.native.js +6 -0
  22. package/build/ExpoAudioStream.native.js.map +1 -0
  23. package/build/ExpoAudioStream.types.d.ts +127 -0
  24. package/build/ExpoAudioStream.types.d.ts.map +1 -0
  25. package/build/ExpoAudioStream.types.js +2 -0
  26. package/build/ExpoAudioStream.types.js.map +1 -0
  27. package/build/ExpoAudioStream.web.d.ts +44 -0
  28. package/build/ExpoAudioStream.web.d.ts.map +1 -0
  29. package/build/ExpoAudioStream.web.js +206 -0
  30. package/build/ExpoAudioStream.web.js.map +1 -0
  31. package/build/ExpoAudioStreamModule.d.ts +3 -0
  32. package/build/ExpoAudioStreamModule.d.ts.map +1 -0
  33. package/build/ExpoAudioStreamModule.js +35 -0
  34. package/build/ExpoAudioStreamModule.js.map +1 -0
  35. package/build/WebRecorder.web.d.ts +54 -0
  36. package/build/WebRecorder.web.d.ts.map +1 -0
  37. package/build/WebRecorder.web.js +336 -0
  38. package/build/WebRecorder.web.js.map +1 -0
  39. package/build/constants.d.ts +11 -0
  40. package/build/constants.d.ts.map +1 -0
  41. package/build/constants.js +14 -0
  42. package/build/constants.js.map +1 -0
  43. package/build/events.d.ts +18 -0
  44. package/build/events.d.ts.map +1 -0
  45. package/build/events.js +11 -0
  46. package/build/events.js.map +1 -0
  47. package/build/index.d.ts +11 -0
  48. package/build/index.d.ts.map +1 -0
  49. package/build/index.js.map +1 -0
  50. package/build/useAudioRecorder.d.ts +20 -0
  51. package/build/useAudioRecorder.d.ts.map +1 -0
  52. package/build/useAudioRecorder.js +311 -0
  53. package/build/useAudioRecorder.js.map +1 -0
  54. package/build/utils/BlobFix.d.ts +9 -0
  55. package/build/utils/BlobFix.d.ts.map +1 -0
  56. package/build/utils/BlobFix.js +498 -0
  57. package/build/utils/BlobFix.js.map +1 -0
  58. package/build/utils/concatenateBuffers.d.ts +8 -0
  59. package/build/utils/concatenateBuffers.d.ts.map +1 -0
  60. package/build/utils/concatenateBuffers.js +21 -0
  61. package/build/utils/concatenateBuffers.js.map +1 -0
  62. package/build/utils/convertPCMToFloat32.d.ts +13 -0
  63. package/build/utils/convertPCMToFloat32.d.ts.map +1 -0
  64. package/build/utils/convertPCMToFloat32.js +120 -0
  65. package/build/utils/convertPCMToFloat32.js.map +1 -0
  66. package/build/utils/encodingToBitDepth.d.ts +5 -0
  67. package/build/utils/encodingToBitDepth.d.ts.map +1 -0
  68. package/build/utils/encodingToBitDepth.js +13 -0
  69. package/build/utils/encodingToBitDepth.js.map +1 -0
  70. package/build/utils/getWavFileInfo.d.ts +26 -0
  71. package/build/utils/getWavFileInfo.d.ts.map +1 -0
  72. package/build/utils/getWavFileInfo.js +92 -0
  73. package/build/utils/getWavFileInfo.js.map +1 -0
  74. package/build/utils/writeWavHeader.d.ts +49 -0
  75. package/build/utils/writeWavHeader.d.ts.map +1 -0
  76. package/build/utils/writeWavHeader.js +91 -0
  77. package/build/utils/writeWavHeader.js.map +1 -0
  78. package/build/workers/InlineFeaturesExtractor.web.d.ts +2 -0
  79. package/build/workers/InlineFeaturesExtractor.web.d.ts.map +1 -0
  80. package/build/workers/InlineFeaturesExtractor.web.js +311 -0
  81. package/build/workers/InlineFeaturesExtractor.web.js.map +1 -0
  82. package/build/workers/inlineAudioWebWorker.web.d.ts +2 -0
  83. package/build/workers/inlineAudioWebWorker.web.d.ts.map +1 -0
  84. package/build/workers/inlineAudioWebWorker.web.js +251 -0
  85. package/build/workers/inlineAudioWebWorker.web.js.map +1 -0
  86. package/expo-module.config.json +9 -0
  87. package/ios/AudioStreamManager.swift +394 -184
  88. package/ios/ExpoAudioStreamModule.swift +2 -2
  89. package/package.json +8 -4
  90. package/plugin/build/index.d.ts +3 -0
  91. package/plugin/build/index.js +132 -0
  92. package/plugin/src/index.ts +176 -0
  93. package/plugin/tsconfig.json +10 -0
  94. package/plugin/tsconfig.tsbuildinfo +1 -0
@@ -317,13 +317,13 @@ public class ExpoAudioStreamModule: Module, AudioStreamManagerDelegate {
317
317
  let sampleRate = settings.sampleRate
318
318
  let channels = Double(settings.numberOfChannels)
319
319
  let bitDepth = Double(settings.bitDepth)
320
- let position = Int((Double(manager.lastEmittedSize) / (sampleRate * channels * (bitDepth / 8))) * 1000)
320
+ let position = Int(manager.currentRecordingDuration() * 1000)
321
321
 
322
322
  // Construct the event payload similar to Android
323
323
  let eventBody: [String: Any] = [
324
324
  "fileUri": fileURL.absoluteString,
325
325
  "lastEmittedSize": manager.lastEmittedSize, // Needs to be maintained within AudioStreamManager
326
- "position": position, // Add position of the chunk in ms since
326
+ "position": position, // time in ms based on pause-aware duration
327
327
  "encoded": encodedData,
328
328
  "deltaSize": deltaSize,
329
329
  "totalSize": fileSize,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siteed/expo-audio-stream",
3
- "version": "1.5.2",
3
+ "version": "1.7.0",
4
4
  "description": "stream audio crossplatform",
5
5
  "license": "MIT",
6
6
  "main": "build/index.js",
@@ -26,12 +26,16 @@
26
26
  "android",
27
27
  "ios",
28
28
  "cpp",
29
- "plugin/build",
29
+ "plugin",
30
30
  "app.plugin.js",
31
+ "LICENSE",
32
+ "CHANGELOG.md",
31
33
  "generated",
34
+ "expo-module.config.json",
32
35
  "README.md",
33
36
  "package.json",
34
37
  "*.podspec",
38
+ "build",
35
39
  "!ios/build",
36
40
  "!android/build",
37
41
  "!android/gradle",
@@ -45,7 +49,7 @@
45
49
  ],
46
50
  "scripts": {
47
51
  "build": "tsc",
48
- "build:plugin": "yarn tsc --build plugin/tsconfig.json",
52
+ "build:plugin": "tsc --build plugin/tsconfig.json",
49
53
  "build:plugin:dev": "expo-module build plugin",
50
54
  "build:dev": "expo-module build",
51
55
  "clean": "expo-module clean && rimraf plugin/build",
@@ -53,7 +57,7 @@
53
57
  "test": "expo-module test",
54
58
  "typecheck": "tsc --noEmit",
55
59
  "docgen": "typedoc src/index.ts --plugin typedoc-plugin-markdown --readme none --out ../../documentation_site/docs/api-reference/API",
56
- "prepare": "expo-module prepare",
60
+ "prepare": "yarn build && yarn build:plugin",
57
61
  "prepublishOnly": "expo-module prepublishOnly",
58
62
  "expo-module": "expo-module",
59
63
  "open:ios": "open -a \"Xcode\" ../../apps/playground/ios",
@@ -0,0 +1,3 @@
1
+ import { ConfigPlugin } from '@expo/config-plugins';
2
+ declare const withRecordingPermission: ConfigPlugin;
3
+ export default withRecordingPermission;
@@ -0,0 +1,132 @@
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) => {
13
+ debugLog('📱 Configuring Recording Permissions Plugin...');
14
+ // iOS Configuration
15
+ config = (0, config_plugins_1.withInfoPlist)(config, (config) => {
16
+ debugLog('🍎 Configuring iOS permissions and capabilities...');
17
+ // Existing microphone permission
18
+ config.modResults['NSMicrophoneUsageDescription'] =
19
+ config.modResults['NSMicrophoneUsageDescription'] ||
20
+ MICROPHONE_USAGE;
21
+ // Add notification permissions
22
+ config.modResults['NSUserNotificationsUsageDescription'] =
23
+ NOTIFICATION_USAGE;
24
+ // Add notification style
25
+ config.modResults['NSUserNotificationAlertStyle'] = 'alert';
26
+ // Background modes
27
+ const existingBackgroundModes = config.modResults.UIBackgroundModes || [];
28
+ if (!existingBackgroundModes.includes('audio')) {
29
+ existingBackgroundModes.push('audio');
30
+ }
31
+ if (!existingBackgroundModes.includes('remote-notification')) {
32
+ existingBackgroundModes.push('remote-notification');
33
+ }
34
+ config.modResults.UIBackgroundModes = existingBackgroundModes;
35
+ debugLog('iOS Background Modes:', config.modResults.UIBackgroundModes);
36
+ return config;
37
+ });
38
+ // Android Configuration
39
+ config = (0, config_plugins_1.withAndroidManifest)(config, (config) => {
40
+ debugLog('🤖 Configuring Android Manifest...');
41
+ const androidManifest = config.modResults;
42
+ if (!androidManifest.manifest) {
43
+ console.error(`${LOG_PREFIX} ❌ Android Manifest is null - plugin cannot continue`);
44
+ return config;
45
+ }
46
+ // Add xmlns:android attribute to manifest
47
+ androidManifest.manifest.$ = {
48
+ ...androidManifest.manifest.$,
49
+ 'xmlns:android': 'http://schemas.android.com/apk/res/android',
50
+ };
51
+ // Ensure permissions array exists
52
+ if (!androidManifest.manifest['uses-permission']) {
53
+ androidManifest.manifest['uses-permission'] = [];
54
+ }
55
+ const { addPermission } = config_plugins_1.AndroidConfig.Permissions;
56
+ debugLog('📋 Existing Android permissions:', androidManifest.manifest['uses-permission']?.map(p => p.$?.['android:name']) || []);
57
+ const permissionsToAdd = [
58
+ 'android.permission.RECORD_AUDIO',
59
+ 'android.permission.FOREGROUND_SERVICE',
60
+ 'android.permission.FOREGROUND_SERVICE_MICROPHONE',
61
+ 'android.permission.WAKE_LOCK',
62
+ 'android.permission.POST_NOTIFICATIONS',
63
+ ];
64
+ debugLog('➕ Adding Android permissions:', permissionsToAdd);
65
+ // Add each permission only if it doesn't exist
66
+ permissionsToAdd.forEach((permission) => {
67
+ const existingPermission = androidManifest.manifest['uses-permission']?.find((p) => p.$?.['android:name'] === permission);
68
+ if (!existingPermission) {
69
+ addPermission(androidManifest, permission);
70
+ }
71
+ });
72
+ // Get the main application node
73
+ const mainApplication = androidManifest.manifest.application?.[0];
74
+ if (mainApplication) {
75
+ debugLog('📱 Configuring Android application components...');
76
+ // Add RecordingActionReceiver
77
+ if (!mainApplication.receiver) {
78
+ mainApplication.receiver = [];
79
+ }
80
+ const receiverConfig = {
81
+ $: {
82
+ 'android:name': '.RecordingActionReceiver',
83
+ 'android:exported': 'false',
84
+ },
85
+ 'intent-filter': [
86
+ {
87
+ action: [
88
+ { $: { 'android:name': 'PAUSE_RECORDING' } },
89
+ { $: { 'android:name': 'RESUME_RECORDING' } },
90
+ { $: { 'android:name': 'STOP_RECORDING' } },
91
+ ],
92
+ },
93
+ ],
94
+ };
95
+ const receiverIndex = mainApplication.receiver.findIndex((receiver) => receiver.$?.['android:name'] === '.RecordingActionReceiver');
96
+ if (receiverIndex >= 0) {
97
+ mainApplication.receiver[receiverIndex] = receiverConfig;
98
+ }
99
+ else {
100
+ mainApplication.receiver.push(receiverConfig);
101
+ }
102
+ debugLog('✅ RecordingActionReceiver configured');
103
+ // Add AudioRecordingService
104
+ if (!mainApplication.service) {
105
+ mainApplication.service = [];
106
+ }
107
+ const serviceConfig = {
108
+ $: {
109
+ 'android:name': '.AudioRecordingService',
110
+ 'android:enabled': 'true',
111
+ 'android:exported': 'false',
112
+ 'android:foregroundServiceType': 'microphone',
113
+ },
114
+ };
115
+ const serviceIndex = mainApplication.service.findIndex((service) => service.$?.['android:name'] === '.AudioRecordingService');
116
+ if (serviceIndex >= 0) {
117
+ mainApplication.service[serviceIndex] = serviceConfig;
118
+ }
119
+ else {
120
+ mainApplication.service.push(serviceConfig);
121
+ }
122
+ debugLog('✅ AudioRecordingService configured');
123
+ }
124
+ else {
125
+ console.error(`${LOG_PREFIX} ❌ Main application node not found in Android Manifest`);
126
+ }
127
+ return config;
128
+ });
129
+ debugLog('✨ Recording Permissions Plugin configuration completed');
130
+ return config;
131
+ };
132
+ exports.default = withRecordingPermission;
@@ -0,0 +1,176 @@
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
+ const withRecordingPermission: ConfigPlugin = (config: ExpoConfig) => {
20
+ debugLog('📱 Configuring Recording Permissions Plugin...')
21
+
22
+ // iOS Configuration
23
+ config = withInfoPlist(config as any, (config) => {
24
+ debugLog('🍎 Configuring iOS permissions and capabilities...')
25
+
26
+ // Existing microphone permission
27
+ config.modResults['NSMicrophoneUsageDescription'] =
28
+ config.modResults['NSMicrophoneUsageDescription'] ||
29
+ MICROPHONE_USAGE
30
+
31
+ // Add notification permissions
32
+ config.modResults['NSUserNotificationsUsageDescription'] =
33
+ NOTIFICATION_USAGE
34
+
35
+ // Add notification style
36
+ config.modResults['NSUserNotificationAlertStyle'] = 'alert'
37
+
38
+ // Background modes
39
+ const existingBackgroundModes =
40
+ config.modResults.UIBackgroundModes || []
41
+ if (!existingBackgroundModes.includes('audio')) {
42
+ existingBackgroundModes.push('audio')
43
+ }
44
+ if (!existingBackgroundModes.includes('remote-notification')) {
45
+ existingBackgroundModes.push('remote-notification')
46
+ }
47
+ config.modResults.UIBackgroundModes = existingBackgroundModes
48
+
49
+ debugLog('iOS Background Modes:', config.modResults.UIBackgroundModes)
50
+
51
+ return config
52
+ })
53
+
54
+ // Android Configuration
55
+ config = withAndroidManifest(config as any, (config) => {
56
+ debugLog('🤖 Configuring Android Manifest...')
57
+
58
+ const androidManifest = config.modResults
59
+ if (!androidManifest.manifest) {
60
+ console.error(`${LOG_PREFIX} ❌ Android Manifest is null - plugin cannot continue`)
61
+ return config
62
+ }
63
+
64
+ // Add xmlns:android attribute to manifest
65
+ androidManifest.manifest.$ = {
66
+ ...androidManifest.manifest.$,
67
+ 'xmlns:android': 'http://schemas.android.com/apk/res/android',
68
+ }
69
+
70
+ // Ensure permissions array exists
71
+ if (!androidManifest.manifest['uses-permission']) {
72
+ androidManifest.manifest['uses-permission'] = []
73
+ }
74
+
75
+ const { addPermission } = AndroidConfig.Permissions
76
+
77
+ debugLog('📋 Existing Android permissions:',
78
+ androidManifest.manifest['uses-permission']?.map(p => p.$?.['android:name']) || [])
79
+
80
+ const permissionsToAdd = [
81
+ 'android.permission.RECORD_AUDIO',
82
+ 'android.permission.FOREGROUND_SERVICE',
83
+ 'android.permission.FOREGROUND_SERVICE_MICROPHONE',
84
+ 'android.permission.WAKE_LOCK',
85
+ 'android.permission.POST_NOTIFICATIONS',
86
+ ]
87
+
88
+ debugLog('➕ Adding Android permissions:', permissionsToAdd)
89
+
90
+ // Add each permission only if it doesn't exist
91
+ permissionsToAdd.forEach((permission) => {
92
+ const existingPermission = androidManifest.manifest[
93
+ 'uses-permission'
94
+ ]?.find((p) => p.$?.['android:name'] === permission)
95
+ if (!existingPermission) {
96
+ addPermission(androidManifest, permission)
97
+ }
98
+ })
99
+
100
+ // Get the main application node
101
+ const mainApplication = androidManifest.manifest.application?.[0]
102
+ if (mainApplication) {
103
+ debugLog('📱 Configuring Android application components...')
104
+
105
+ // Add RecordingActionReceiver
106
+ if (!mainApplication.receiver) {
107
+ mainApplication.receiver = []
108
+ }
109
+
110
+ const receiverConfig = {
111
+ $: {
112
+ 'android:name': '.RecordingActionReceiver',
113
+ 'android:exported': 'false' as const,
114
+ },
115
+ 'intent-filter': [
116
+ {
117
+ action: [
118
+ { $: { 'android:name': 'PAUSE_RECORDING' } },
119
+ { $: { 'android:name': 'RESUME_RECORDING' } },
120
+ { $: { 'android:name': 'STOP_RECORDING' } },
121
+ ],
122
+ },
123
+ ],
124
+ }
125
+
126
+ const receiverIndex = mainApplication.receiver.findIndex(
127
+ (receiver: any) =>
128
+ receiver.$?.['android:name'] === '.RecordingActionReceiver'
129
+ )
130
+
131
+ if (receiverIndex >= 0) {
132
+ mainApplication.receiver[receiverIndex] = receiverConfig
133
+ } else {
134
+ mainApplication.receiver.push(receiverConfig)
135
+ }
136
+
137
+ debugLog('✅ RecordingActionReceiver configured')
138
+
139
+ // Add AudioRecordingService
140
+ if (!mainApplication.service) {
141
+ mainApplication.service = []
142
+ }
143
+
144
+ const serviceConfig = {
145
+ $: {
146
+ 'android:name': '.AudioRecordingService',
147
+ 'android:enabled': 'true' as const,
148
+ 'android:exported': 'false' as const,
149
+ 'android:foregroundServiceType': 'microphone',
150
+ },
151
+ }
152
+
153
+ const serviceIndex = mainApplication.service.findIndex(
154
+ (service: any) =>
155
+ service.$?.['android:name'] === '.AudioRecordingService'
156
+ )
157
+
158
+ if (serviceIndex >= 0) {
159
+ mainApplication.service[serviceIndex] = serviceConfig
160
+ } else {
161
+ mainApplication.service.push(serviceConfig)
162
+ }
163
+
164
+ debugLog('✅ AudioRecordingService configured')
165
+ } else {
166
+ console.error(`${LOG_PREFIX} ❌ Main application node not found in Android Manifest`)
167
+ }
168
+
169
+ return config
170
+ })
171
+
172
+ debugLog('✨ Recording Permissions Plugin configuration completed')
173
+ return config as any
174
+ }
175
+
176
+ export default withRecordingPermission
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "expo-module-scripts/tsconfig.plugin",
3
+ "compilerOptions": {
4
+ "outDir": "build",
5
+ "lib": ["es2023", "dom"],
6
+ "rootDir": "src"
7
+ },
8
+ "include": ["./src"],
9
+ "exclude": ["**/__mocks__/*", "**/__tests__/*"]
10
+ }
@@ -0,0 +1 @@
1
+ {"root":["./src/index.ts"],"version":"5.7.2"}