@siteed/expo-audio-studio 2.6.3 → 2.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.
- package/CHANGELOG.md +6 -1
- package/app.plugin.cjs +2 -0
- package/ios/AudioProcessor.swift +11 -2
- package/ios/AudioStreamManager.swift +38 -3
- package/package.json +6 -6
- package/plugin/build/index.cjs +192 -0
- package/plugin/build/index.js +6 -5
- package/plugin/src/index.ts +8 -5
- package/app.plugin.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
## [2.7.0] - 2025-05-04
|
|
12
|
+
### Changed
|
|
13
|
+
- fix: Enhance iOS Background Audio Recording and Audio Format Conversion (#228) ([c17169b](https://github.com/deeeed/expo-audio-stream/commit/c17169bf9275706abf287712acc30df2f1814ed7))
|
|
14
|
+
- chore(expo-audio-studio): improve build script for cjs esm conversion ([767dfbe](https://github.com/deeeed/expo-audio-stream/commit/767dfbe5da0f1550b689f6859e2e5fccf7f8141c))
|
|
11
15
|
## [2.6.3] - 2025-05-03
|
|
12
16
|
### Changed
|
|
13
17
|
- chore: update readme with store download information (#224) ([c404d86](https://github.com/deeeed/expo-audio-stream/commit/c404d860cdb1c4c4bbc3767214f56bf547acec33))
|
|
@@ -213,7 +217,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
213
217
|
- Feature: Audio features extraction during recording.
|
|
214
218
|
- Feature: Consistent WAV PCM recording format across all platforms.
|
|
215
219
|
|
|
216
|
-
[unreleased]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.
|
|
220
|
+
[unreleased]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.7.0...HEAD
|
|
221
|
+
[2.7.0]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.6.3...@siteed/expo-audio-studio@2.7.0
|
|
217
222
|
[2.6.3]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.6.2...@siteed/expo-audio-studio@2.6.3
|
|
218
223
|
[2.6.2]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.6.1...@siteed/expo-audio-studio@2.6.2
|
|
219
224
|
[2.6.1]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.6.0...@siteed/expo-audio-studio@2.6.1
|
package/app.plugin.cjs
ADDED
package/ios/AudioProcessor.swift
CHANGED
|
@@ -801,7 +801,16 @@ public class AudioProcessor {
|
|
|
801
801
|
try audioFile.read(into: buffer, frameCount: frameCount)
|
|
802
802
|
let converter = AVAudioConverter(from: inputFormat, to: targetFormat)!
|
|
803
803
|
let convertedBuffer = AVAudioPCMBuffer(pcmFormat: targetFormat, frameCapacity: frameCount)!
|
|
804
|
-
|
|
804
|
+
var error: NSError?
|
|
805
|
+
_ = converter.convert(to: convertedBuffer, error: &error) { inNumPackets, outStatus in
|
|
806
|
+
outStatus.pointee = .haveData
|
|
807
|
+
return buffer
|
|
808
|
+
}
|
|
809
|
+
if let error = error {
|
|
810
|
+
Logger.debug("AudioProcessor", "Format conversion failed: \(error.localizedDescription)")
|
|
811
|
+
reject("CONVERSION_ERROR", "Failed to convert audio format: \(error.localizedDescription)")
|
|
812
|
+
return nil
|
|
813
|
+
}
|
|
805
814
|
try outputFile.write(from: convertedBuffer)
|
|
806
815
|
cumulativeFrames += Int64(frameCount)
|
|
807
816
|
let progress = Float(cumulativeFrames) / Float(totalFrames) * 100
|
|
@@ -933,7 +942,7 @@ public class AudioProcessor {
|
|
|
933
942
|
let convertedBuffer = AVAudioPCMBuffer(pcmFormat: targetFormat, frameCapacity: framesToRead)!
|
|
934
943
|
|
|
935
944
|
var error: NSError?
|
|
936
|
-
|
|
945
|
+
_ = converter.convert(to: convertedBuffer, error: &error) { inNumPackets, outStatus in
|
|
937
946
|
outStatus.pointee = .haveData
|
|
938
947
|
return buffer
|
|
939
948
|
}
|
|
@@ -363,9 +363,15 @@ class AudioStreamManager: NSObject, AudioDeviceManagerDelegate {
|
|
|
363
363
|
|
|
364
364
|
@objc private func handleAppDidEnterBackground(_ notification: Notification) {
|
|
365
365
|
if isRecording {
|
|
366
|
-
// If keepAwake is false, we should track this as a pause
|
|
366
|
+
// If keepAwake is false, we should track this as a pause and actually pause the engine
|
|
367
367
|
if let settings = recordingSettings, !settings.keepAwake {
|
|
368
|
+
Logger.debug("AudioStreamManager", "App entering background with keepAwake=false, pausing recording")
|
|
368
369
|
currentPauseStart = Date()
|
|
370
|
+
// Explicitly pause the engine but don't change isPaused state
|
|
371
|
+
// so we can automatically resume when returning to foreground
|
|
372
|
+
audioEngine.pause()
|
|
373
|
+
} else {
|
|
374
|
+
Logger.debug("AudioStreamManager", "App entering background with keepAwake=true, continuing recording")
|
|
369
375
|
}
|
|
370
376
|
|
|
371
377
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
|
@@ -382,6 +388,23 @@ class AudioStreamManager: NSObject, AudioDeviceManagerDelegate {
|
|
|
382
388
|
totalPausedDuration += pauseDuration
|
|
383
389
|
currentPauseStart = nil
|
|
384
390
|
Logger.debug("AudioStreamManager", "Added background pause duration: \(pauseDuration), total paused: \(totalPausedDuration)")
|
|
391
|
+
|
|
392
|
+
// Now restart the engine if it was paused due to background
|
|
393
|
+
do {
|
|
394
|
+
// Reinstall tap with hardware format to ensure we have good input
|
|
395
|
+
_ = installTapWithHardwareFormat()
|
|
396
|
+
// Restart the engine
|
|
397
|
+
try audioEngine.start()
|
|
398
|
+
Logger.debug("AudioStreamManager", "Successfully restarted audio engine after returning from background")
|
|
399
|
+
} catch {
|
|
400
|
+
Logger.debug("AudioStreamManager", "Failed to restart audio engine after returning from background: \(error)")
|
|
401
|
+
// If we can't restart, officially pause the recording
|
|
402
|
+
if !isPaused {
|
|
403
|
+
isPaused = true
|
|
404
|
+
// Notify delegate
|
|
405
|
+
delegate?.audioStreamManager(self, didPauseRecording: Date())
|
|
406
|
+
}
|
|
407
|
+
}
|
|
385
408
|
}
|
|
386
409
|
|
|
387
410
|
notificationManager?.stopUpdates()
|
|
@@ -768,9 +791,21 @@ class AudioStreamManager: NSObject, AudioDeviceManagerDelegate {
|
|
|
768
791
|
// Append necessary options for background recording if keepAwake is enabled
|
|
769
792
|
if settings.keepAwake {
|
|
770
793
|
Logger.debug("AudioStreamManager", "keepAwake enabled - configuring for background recording")
|
|
771
|
-
//
|
|
794
|
+
// Set the category to PlayAndRecord with proper background options
|
|
772
795
|
options.insert(.mixWithOthers)
|
|
773
|
-
|
|
796
|
+
// Add duckOthers to reduce volume of other apps instead of stopping them
|
|
797
|
+
options.insert(.duckOthers)
|
|
798
|
+
|
|
799
|
+
// Configure audio session for background audio
|
|
800
|
+
do {
|
|
801
|
+
try session.setCategory(.playAndRecord, mode: .default, options: options)
|
|
802
|
+
try session.setActive(true, options: .notifyOthersOnDeactivation)
|
|
803
|
+
// Ensure the app has appropriate Info.plist settings for background audio
|
|
804
|
+
Logger.debug("AudioStreamManager", "Audio session configured for background recording with options: \(options)")
|
|
805
|
+
} catch {
|
|
806
|
+
Logger.debug("AudioStreamManager", "Failed to configure audio session for background: \(error)")
|
|
807
|
+
try session.setActive(true, options: .notifyOthersOnDeactivation)
|
|
808
|
+
}
|
|
774
809
|
} else {
|
|
775
810
|
Logger.debug("AudioStreamManager", "keepAwake disabled - using standard session configuration")
|
|
776
811
|
// If keepAwake is false, don't add background audio options
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@siteed/expo-audio-studio",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "Comprehensive audio processing library for React Native and Expo with recording, analysis, visualization, and streaming capabilities across iOS, Android, and web",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "build/index.js",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"ios",
|
|
45
45
|
"cpp",
|
|
46
46
|
"plugin",
|
|
47
|
-
"app.plugin.
|
|
47
|
+
"app.plugin.cjs",
|
|
48
48
|
"LICENSE",
|
|
49
49
|
"CHANGELOG.md",
|
|
50
50
|
"generated",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
],
|
|
67
67
|
"scripts": {
|
|
68
68
|
"build": "tsc",
|
|
69
|
-
"build:plugin": "tsc --build plugin/tsconfig.json",
|
|
69
|
+
"build:plugin": "tsc --build plugin/tsconfig.json && node scripts/convert-to-cjs.js",
|
|
70
70
|
"build:plugin:dev": "expo-module build plugin",
|
|
71
71
|
"build:dev": "expo-module build",
|
|
72
72
|
"clean": "expo-module clean && rimraf plugin/build",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"test": "expo-module test",
|
|
75
75
|
"typecheck": "tsc --noEmit",
|
|
76
76
|
"docgen": "typedoc src/index.ts --plugin typedoc-plugin-markdown --readme none --out ../../documentation_site/docs/api-reference/API",
|
|
77
|
-
"prepare": "yarn build && yarn build:plugin",
|
|
77
|
+
"prepare": "yarn build && yarn build:plugin && node -e \"require('fs').renameSync('./plugin/build/index.d.ts', './plugin/build/index.d.cts')\"",
|
|
78
78
|
"prepublishOnly": "expo-module prepublishOnly",
|
|
79
79
|
"expo-module": "expo-module",
|
|
80
80
|
"open:ios": "open -a \"Xcode\" ../../apps/playground/ios",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"eslint-plugin-prettier": "^5.1.3",
|
|
100
100
|
"eslint-plugin-promise": "^6.1.1",
|
|
101
101
|
"eslint-plugin-react": "^7.34.1",
|
|
102
|
-
"expo": "^
|
|
102
|
+
"expo": "^53.0.6",
|
|
103
103
|
"expo-module-scripts": "^4.0.2",
|
|
104
104
|
"jest": "^29.7.0",
|
|
105
105
|
"prettier": "^3.2.5",
|
|
@@ -121,6 +121,6 @@
|
|
|
121
121
|
"registry": "https://registry.npmjs.org"
|
|
122
122
|
},
|
|
123
123
|
"dependencies": {
|
|
124
|
-
"expo-modules-core": "~2.
|
|
124
|
+
"expo-modules-core": "~2.3.12"
|
|
125
125
|
}
|
|
126
126
|
}
|
|
@@ -0,0 +1,192 @@
|
|
|
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-studio]';
|
|
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
|
+
// If background audio is enabled with useAudio, add the audio background mode
|
|
48
|
+
if (options.iosBackgroundModes?.useAudio === true &&
|
|
49
|
+
enableBackgroundAudio === true &&
|
|
50
|
+
!existingBackgroundModes.includes('audio')) {
|
|
51
|
+
// Add 'audio' background mode - REQUIRED for background recording
|
|
52
|
+
existingBackgroundModes.push('audio');
|
|
53
|
+
debugLog('✅ Added audio background mode for iOS background recording');
|
|
54
|
+
// Also ensure processing mode is recommended
|
|
55
|
+
if (options.iosBackgroundModes?.useProcessing !== true) {
|
|
56
|
+
console.warn(`${LOG_PREFIX} Warning: Background audio recording works best with both 'audio' and 'processing' background modes. Consider enabling 'useProcessing' in iosBackgroundModes.`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (options.iosBackgroundModes?.useVoIP === true &&
|
|
60
|
+
enablePhoneStateHandling === true) {
|
|
61
|
+
if (!existingBackgroundModes.includes('voip')) {
|
|
62
|
+
existingBackgroundModes.push('voip');
|
|
63
|
+
}
|
|
64
|
+
const existingCapabilities = (config.modResults
|
|
65
|
+
.UIRequiredDeviceCapabilities || []);
|
|
66
|
+
if (!existingCapabilities.includes('telephony')) {
|
|
67
|
+
existingCapabilities.push('telephony');
|
|
68
|
+
}
|
|
69
|
+
config.modResults.UIRequiredDeviceCapabilities =
|
|
70
|
+
existingCapabilities;
|
|
71
|
+
}
|
|
72
|
+
// Add additional background modes only if explicitly set to true
|
|
73
|
+
if (options.iosBackgroundModes?.useProcessing === true) {
|
|
74
|
+
if (!existingBackgroundModes.includes('processing')) {
|
|
75
|
+
existingBackgroundModes.push('processing');
|
|
76
|
+
}
|
|
77
|
+
// Add processing info if enabled
|
|
78
|
+
// Note: We keep the 'audiostream' namespace for native modules to maintain compatibility
|
|
79
|
+
config.modResults.BGTaskSchedulerPermittedIdentifiers = [
|
|
80
|
+
'com.siteed.audiostream.processing',
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
if (options.iosBackgroundModes?.useLocation === true) {
|
|
84
|
+
if (!existingBackgroundModes.includes('location')) {
|
|
85
|
+
existingBackgroundModes.push('location');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (options.iosBackgroundModes?.useExternalAccessory === true) {
|
|
89
|
+
if (!existingBackgroundModes.includes('external-accessory')) {
|
|
90
|
+
existingBackgroundModes.push('external-accessory');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Configure background processing info if enabled
|
|
94
|
+
if (options.iosConfig?.backgroundProcessingTitle) {
|
|
95
|
+
config.modResults.BGProcessingTaskTitle =
|
|
96
|
+
options.iosConfig.backgroundProcessingTitle;
|
|
97
|
+
}
|
|
98
|
+
// Configure audio session behavior
|
|
99
|
+
if (options.iosConfig?.allowBackgroundAudioControls) {
|
|
100
|
+
config.modResults.UIBackgroundModes = [
|
|
101
|
+
...existingBackgroundModes,
|
|
102
|
+
'remote-notification',
|
|
103
|
+
];
|
|
104
|
+
config.modResults.MPNowPlayingInfoPropertyPlaybackRate = true;
|
|
105
|
+
}
|
|
106
|
+
config.modResults.UIBackgroundModes = existingBackgroundModes;
|
|
107
|
+
return config;
|
|
108
|
+
});
|
|
109
|
+
// Android Configuration
|
|
110
|
+
config = (0, config_plugins_1.withAndroidManifest)(config, (config) => {
|
|
111
|
+
const basePermissions = [
|
|
112
|
+
'android.permission.RECORD_AUDIO',
|
|
113
|
+
'android.permission.WAKE_LOCK',
|
|
114
|
+
];
|
|
115
|
+
const optionalPermissions = [
|
|
116
|
+
enableNotifications && 'android.permission.POST_NOTIFICATIONS',
|
|
117
|
+
enablePhoneStateHandling && 'android.permission.READ_PHONE_STATE', // Only add if enabled
|
|
118
|
+
enableBackgroundAudio && 'android.permission.FOREGROUND_SERVICE',
|
|
119
|
+
enableBackgroundAudio && 'android.permission.FOREGROUND_SERVICE_MICROPHONE',
|
|
120
|
+
].filter(Boolean);
|
|
121
|
+
const permissionsToAdd = [...basePermissions, ...optionalPermissions];
|
|
122
|
+
debugLog('📋 Existing Android permissions:', config.modResults.manifest['uses-permission']?.map((p) => p.$?.['android:name']) || []);
|
|
123
|
+
debugLog('➕ Adding Android permissions:', permissionsToAdd);
|
|
124
|
+
const { addPermission } = config_plugins_1.AndroidConfig.Permissions;
|
|
125
|
+
// Add each permission only if it doesn't exist
|
|
126
|
+
permissionsToAdd.forEach((permission) => {
|
|
127
|
+
const existingPermission = config.modResults.manifest['uses-permission']?.find((p) => p.$?.['android:name'] === permission);
|
|
128
|
+
if (!existingPermission) {
|
|
129
|
+
addPermission(config.modResults, permission);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
// Get the main application node
|
|
133
|
+
const mainApplication = config.modResults.manifest.application?.[0];
|
|
134
|
+
if (mainApplication) {
|
|
135
|
+
debugLog('📱 Configuring Android application components...');
|
|
136
|
+
// Add RecordingActionReceiver
|
|
137
|
+
if (!mainApplication.receiver) {
|
|
138
|
+
mainApplication.receiver = [];
|
|
139
|
+
}
|
|
140
|
+
const receiverConfig = {
|
|
141
|
+
$: {
|
|
142
|
+
'android:name': '.RecordingActionReceiver',
|
|
143
|
+
'android:exported': 'false',
|
|
144
|
+
},
|
|
145
|
+
'intent-filter': [
|
|
146
|
+
{
|
|
147
|
+
action: [
|
|
148
|
+
{ $: { 'android:name': 'PAUSE_RECORDING' } },
|
|
149
|
+
{ $: { 'android:name': 'RESUME_RECORDING' } },
|
|
150
|
+
{ $: { 'android:name': 'STOP_RECORDING' } },
|
|
151
|
+
],
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
};
|
|
155
|
+
const receiverIndex = mainApplication.receiver.findIndex((receiver) => receiver.$?.['android:name'] === '.RecordingActionReceiver');
|
|
156
|
+
if (receiverIndex >= 0) {
|
|
157
|
+
mainApplication.receiver[receiverIndex] = receiverConfig;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
mainApplication.receiver.push(receiverConfig);
|
|
161
|
+
}
|
|
162
|
+
debugLog('✅ RecordingActionReceiver configured');
|
|
163
|
+
// Add AudioRecordingService
|
|
164
|
+
if (!mainApplication.service) {
|
|
165
|
+
mainApplication.service = [];
|
|
166
|
+
}
|
|
167
|
+
const serviceConfig = {
|
|
168
|
+
$: {
|
|
169
|
+
'android:name': '.AudioRecordingService',
|
|
170
|
+
'android:enabled': 'true',
|
|
171
|
+
'android:exported': 'false',
|
|
172
|
+
'android:foregroundServiceType': 'microphone',
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
const serviceIndex = mainApplication.service.findIndex((service) => service.$?.['android:name'] === '.AudioRecordingService');
|
|
176
|
+
if (serviceIndex >= 0) {
|
|
177
|
+
mainApplication.service[serviceIndex] = serviceConfig;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
mainApplication.service.push(serviceConfig);
|
|
181
|
+
}
|
|
182
|
+
debugLog('✅ AudioRecordingService configured');
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
console.error(`${LOG_PREFIX} ❌ Main application node not found in Android Manifest`);
|
|
186
|
+
}
|
|
187
|
+
return config;
|
|
188
|
+
});
|
|
189
|
+
debugLog('✨ Recording Permissions Plugin configuration completed');
|
|
190
|
+
return config;
|
|
191
|
+
};
|
|
192
|
+
exports.default = withRecordingPermission;
|
package/plugin/build/index.js
CHANGED
|
@@ -44,15 +44,16 @@ const withRecordingPermission = (config, props) => {
|
|
|
44
44
|
config.modResults['NSUserNotificationAlertStyle'] = 'alert';
|
|
45
45
|
}
|
|
46
46
|
const existingBackgroundModes = config.modResults.UIBackgroundModes || [];
|
|
47
|
-
//
|
|
47
|
+
// If background audio is enabled with useAudio, add the audio background mode
|
|
48
48
|
if (options.iosBackgroundModes?.useAudio === true &&
|
|
49
49
|
enableBackgroundAudio === true &&
|
|
50
50
|
!existingBackgroundModes.includes('audio')) {
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
// Add 'audio' background mode - REQUIRED for background recording
|
|
52
|
+
existingBackgroundModes.push('audio');
|
|
53
|
+
debugLog('✅ Added audio background mode for iOS background recording');
|
|
54
|
+
// Also ensure processing mode is recommended
|
|
54
55
|
if (options.iosBackgroundModes?.useProcessing !== true) {
|
|
55
|
-
console.warn(`${LOG_PREFIX} Warning: Background audio recording
|
|
56
|
+
console.warn(`${LOG_PREFIX} Warning: Background audio recording works best with both 'audio' and 'processing' background modes. Consider enabling 'useProcessing' in iosBackgroundModes.`);
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
if (options.iosBackgroundModes?.useVoIP === true &&
|
package/plugin/src/index.ts
CHANGED
|
@@ -84,19 +84,22 @@ const withRecordingPermission: ConfigPlugin<AudioStreamPluginOptions> = (
|
|
|
84
84
|
const existingBackgroundModes =
|
|
85
85
|
config.modResults.UIBackgroundModes || []
|
|
86
86
|
|
|
87
|
-
//
|
|
87
|
+
// If background audio is enabled with useAudio, add the audio background mode
|
|
88
88
|
if (
|
|
89
89
|
options.iosBackgroundModes?.useAudio === true &&
|
|
90
90
|
enableBackgroundAudio === true &&
|
|
91
91
|
!existingBackgroundModes.includes('audio')
|
|
92
92
|
) {
|
|
93
|
-
//
|
|
94
|
-
|
|
93
|
+
// Add 'audio' background mode - REQUIRED for background recording
|
|
94
|
+
existingBackgroundModes.push('audio')
|
|
95
|
+
debugLog(
|
|
96
|
+
'✅ Added audio background mode for iOS background recording'
|
|
97
|
+
)
|
|
95
98
|
|
|
96
|
-
//
|
|
99
|
+
// Also ensure processing mode is recommended
|
|
97
100
|
if (options.iosBackgroundModes?.useProcessing !== true) {
|
|
98
101
|
console.warn(
|
|
99
|
-
`${LOG_PREFIX} Warning: Background audio recording
|
|
102
|
+
`${LOG_PREFIX} Warning: Background audio recording works best with both 'audio' and 'processing' background modes. Consider enabling 'useProcessing' in iosBackgroundModes.`
|
|
100
103
|
)
|
|
101
104
|
}
|
|
102
105
|
}
|
package/app.plugin.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = require('./plugin/build')
|