@siteed/expo-audio-studio 2.6.0 → 2.6.2
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 +10 -1
- package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +2 -2
- package/android/src/main/java/net/siteed/audiostream/LogUtils.kt +3 -3
- package/build/ExpoAudioStream.types.d.ts +5 -1
- package/build/ExpoAudioStream.types.d.ts.map +1 -1
- package/build/ExpoAudioStream.types.js.map +1 -1
- package/build/useAudioRecorder.d.ts.map +1 -1
- package/build/useAudioRecorder.js +1 -1
- package/build/useAudioRecorder.js.map +1 -1
- package/ios/AudioDeviceManager.swift +65 -65
- package/ios/AudioProcessor.swift +32 -32
- package/ios/AudioStreamManager.swift +323 -158
- package/ios/ExpoAudioStreamModule.swift +92 -75
- package/ios/ISSUE_IOS.md +26 -3
- package/ios/Logger.swift +27 -7
- package/package.json +1 -1
- package/src/ExpoAudioStream.types.ts +5 -1
- package/src/useAudioRecorder.tsx +1 -2
|
@@ -53,7 +53,7 @@ class AudioDeviceManager {
|
|
|
53
53
|
|
|
54
54
|
/// Maps AVAudioSession port types to standardized device types
|
|
55
55
|
func mapDeviceType(_ portType: AVAudioSession.Port) -> String {
|
|
56
|
-
Logger.debug("Mapping device type for port: \(portType.rawValue)")
|
|
56
|
+
Logger.debug("AudioDeviceManager", "Mapping device type for port: \(portType.rawValue)")
|
|
57
57
|
switch portType {
|
|
58
58
|
case .builtInMic:
|
|
59
59
|
return deviceTypeBuiltinMic
|
|
@@ -79,11 +79,11 @@ class AudioDeviceManager {
|
|
|
79
79
|
let timeSinceLastPreparation = now - AudioDeviceManager.lastPreparationTime
|
|
80
80
|
|
|
81
81
|
if AudioDeviceManager.isAudioSessionPrepared && !force && timeSinceLastPreparation < 5.0 {
|
|
82
|
-
Logger.debug("Audio session already prepared, skipping")
|
|
82
|
+
Logger.debug("AudioDeviceManager", "Audio session already prepared, skipping")
|
|
83
83
|
return true
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
Logger.debug("Preparing audio session for device detection")
|
|
86
|
+
Logger.debug("AudioDeviceManager", "Preparing audio session for device detection")
|
|
87
87
|
do {
|
|
88
88
|
let session = AVAudioSession.sharedInstance()
|
|
89
89
|
|
|
@@ -101,10 +101,10 @@ class AudioDeviceManager {
|
|
|
101
101
|
AudioDeviceManager.isAudioSessionPrepared = true
|
|
102
102
|
AudioDeviceManager.lastPreparationTime = now
|
|
103
103
|
|
|
104
|
-
Logger.debug("Audio session prepared for device detection")
|
|
104
|
+
Logger.debug("AudioDeviceManager", "Audio session prepared for device detection")
|
|
105
105
|
return true
|
|
106
106
|
} catch {
|
|
107
|
-
Logger.debug("Failed to prepare audio session: \(error.localizedDescription)")
|
|
107
|
+
Logger.debug("AudioDeviceManager", "Failed to prepare audio session: \(error.localizedDescription)")
|
|
108
108
|
return false
|
|
109
109
|
}
|
|
110
110
|
}
|
|
@@ -116,7 +116,7 @@ class AudioDeviceManager {
|
|
|
116
116
|
let timeSinceLastPreparation = now - AudioDeviceManager.lastPreparationTime
|
|
117
117
|
|
|
118
118
|
if timeSinceLastPreparation < 1.0 {
|
|
119
|
-
Logger.debug("Skipping force refresh - too soon since last preparation (\(timeSinceLastPreparation) seconds)")
|
|
119
|
+
Logger.debug("AudioDeviceManager", "Skipping force refresh - too soon since last preparation (\(timeSinceLastPreparation) seconds)")
|
|
120
120
|
return false
|
|
121
121
|
}
|
|
122
122
|
|
|
@@ -125,7 +125,7 @@ class AudioDeviceManager {
|
|
|
125
125
|
|
|
126
126
|
/// Gets capabilities for an audio input device
|
|
127
127
|
func getDeviceCapabilities(_ port: AVAudioSessionPortDescription) -> [String: Any] {
|
|
128
|
-
Logger.debug("Getting capabilities for device: \(port.portName) (ID: \(port.uid))")
|
|
128
|
+
Logger.debug("AudioDeviceManager", "Getting capabilities for device: \(port.portName) (ID: \(port.uid))")
|
|
129
129
|
let session = AVAudioSession.sharedInstance()
|
|
130
130
|
|
|
131
131
|
// Test standard sample rates for support
|
|
@@ -146,12 +146,12 @@ class AudioDeviceManager {
|
|
|
146
146
|
|
|
147
147
|
/// Gets a list of available audio input devices
|
|
148
148
|
func getAvailableInputDevices(promise: Promise) {
|
|
149
|
-
Logger.debug("Getting available input devices")
|
|
149
|
+
Logger.debug("AudioDeviceManager", "Getting available input devices")
|
|
150
150
|
|
|
151
151
|
// Prepare audio session if needed
|
|
152
152
|
let prepared = prepareAudioSession()
|
|
153
153
|
if !prepared {
|
|
154
|
-
Logger.debug("Warning: Audio session preparation failed, device list may be incomplete")
|
|
154
|
+
Logger.debug("AudioDeviceManager", "Warning: Audio session preparation failed, device list may be incomplete")
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
do {
|
|
@@ -174,7 +174,7 @@ class AudioDeviceManager {
|
|
|
174
174
|
|
|
175
175
|
let deviceId = normalizeBluetoothDeviceId(input.uid)
|
|
176
176
|
|
|
177
|
-
Logger.debug("Current route device: \(input.portName) (type: \(deviceType), ID: \(deviceId))")
|
|
177
|
+
Logger.debug("AudioDeviceManager", "Current route device: \(input.portName) (type: \(deviceType), ID: \(deviceId))")
|
|
178
178
|
|
|
179
179
|
devices.append([
|
|
180
180
|
"id": deviceId,
|
|
@@ -199,7 +199,7 @@ class AudioDeviceManager {
|
|
|
199
199
|
|
|
200
200
|
// Skip if already in our list
|
|
201
201
|
if !devices.contains(where: { ($0["id"] as? String) == deviceId }) {
|
|
202
|
-
Logger.debug("Available input: \(port.portName) (type: \(deviceType), ID: \(deviceId))")
|
|
202
|
+
Logger.debug("AudioDeviceManager", "Available input: \(port.portName) (type: \(deviceType), ID: \(deviceId))")
|
|
203
203
|
|
|
204
204
|
devices.append([
|
|
205
205
|
"id": deviceId,
|
|
@@ -214,22 +214,22 @@ class AudioDeviceManager {
|
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
Logger.debug("Found \(devices.count) available input devices")
|
|
217
|
+
Logger.debug("AudioDeviceManager", "Found \(devices.count) available input devices")
|
|
218
218
|
promise.resolve(devices)
|
|
219
219
|
} catch {
|
|
220
|
-
Logger.debug("Error getting available input devices: \(error.localizedDescription)")
|
|
220
|
+
Logger.debug("AudioDeviceManager", "Error getting available input devices: \(error.localizedDescription)")
|
|
221
221
|
promise.reject("DEVICE_DETECTION_ERROR", "Failed to get available audio devices: \(error.localizedDescription)")
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
/// Gets the currently selected audio input device
|
|
226
226
|
func getCurrentInputDevice(promise: Promise) {
|
|
227
|
-
Logger.debug("Getting current input device")
|
|
227
|
+
Logger.debug("AudioDeviceManager", "Getting current input device")
|
|
228
228
|
|
|
229
229
|
// Prepare audio session if needed
|
|
230
230
|
let prepared = prepareAudioSession()
|
|
231
231
|
if !prepared {
|
|
232
|
-
Logger.debug("Warning: Audio session preparation failed, current device may not be correctly detected")
|
|
232
|
+
Logger.debug("AudioDeviceManager", "Warning: Audio session preparation failed, current device may not be correctly detected")
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
do {
|
|
@@ -245,7 +245,7 @@ class AudioDeviceManager {
|
|
|
245
245
|
let isDefault = session.preferredInput == nil || session.preferredInput?.portType == currentPort.portType
|
|
246
246
|
let deviceId = normalizeBluetoothDeviceId(currentPort.uid)
|
|
247
247
|
|
|
248
|
-
Logger.debug("Current input device: \(currentPort.portName) (ID: \(deviceId), type: \(deviceType))")
|
|
248
|
+
Logger.debug("AudioDeviceManager", "Current input device: \(currentPort.portName) (ID: \(deviceId), type: \(deviceType))")
|
|
249
249
|
|
|
250
250
|
let device: [String: Any] = [
|
|
251
251
|
"id": deviceId,
|
|
@@ -266,7 +266,7 @@ class AudioDeviceManager {
|
|
|
266
266
|
let deviceType = mapDeviceType(preferredInput.portType)
|
|
267
267
|
let deviceId = normalizeBluetoothDeviceId(preferredInput.uid)
|
|
268
268
|
|
|
269
|
-
Logger.debug("Current input from preferred: \(preferredInput.portName) (ID: \(deviceId), type: \(deviceType))")
|
|
269
|
+
Logger.debug("AudioDeviceManager", "Current input from preferred: \(preferredInput.portName) (ID: \(deviceId), type: \(deviceType))")
|
|
270
270
|
|
|
271
271
|
let device: [String: Any] = [
|
|
272
272
|
"id": deviceId,
|
|
@@ -283,10 +283,10 @@ class AudioDeviceManager {
|
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
// No input device is currently selected
|
|
286
|
-
Logger.debug("No current input device found")
|
|
286
|
+
Logger.debug("AudioDeviceManager", "No current input device found")
|
|
287
287
|
promise.resolve(nil)
|
|
288
288
|
} catch {
|
|
289
|
-
Logger.debug("Error getting current input device: \(error.localizedDescription)")
|
|
289
|
+
Logger.debug("AudioDeviceManager", "Error getting current input device: \(error.localizedDescription)")
|
|
290
290
|
promise.reject("DEVICE_DETECTION_ERROR", "Failed to get current audio device: \(error.localizedDescription)")
|
|
291
291
|
}
|
|
292
292
|
}
|
|
@@ -294,11 +294,11 @@ class AudioDeviceManager {
|
|
|
294
294
|
/// Gets the default audio input device (usually built-in mic)
|
|
295
295
|
/// This is an async version useful for fallback logic.
|
|
296
296
|
func getDefaultInputDevice() async -> AudioDevice? {
|
|
297
|
-
Logger.debug("Getting default input device")
|
|
297
|
+
Logger.debug("AudioDeviceManager", "Getting default input device")
|
|
298
298
|
|
|
299
299
|
let prepared = prepareAudioSession()
|
|
300
300
|
if !prepared {
|
|
301
|
-
Logger.debug("Warning: Audio session preparation failed, default device detection may be inaccurate")
|
|
301
|
+
Logger.debug("AudioDeviceManager", "Warning: Audio session preparation failed, default device detection may be inaccurate")
|
|
302
302
|
}
|
|
303
303
|
|
|
304
304
|
let session = AVAudioSession.sharedInstance()
|
|
@@ -311,7 +311,7 @@ class AudioDeviceManager {
|
|
|
311
311
|
let deviceId = normalizeBluetoothDeviceId(defaultPort.uid)
|
|
312
312
|
let capabilities = getDeviceCapabilities(defaultPort)
|
|
313
313
|
|
|
314
|
-
Logger.debug("Found default device: \(defaultPort.portName) (ID: \(deviceId), Type: \(deviceType))")
|
|
314
|
+
Logger.debug("AudioDeviceManager", "Found default device: \(defaultPort.portName) (ID: \(deviceId), Type: \(deviceType))")
|
|
315
315
|
|
|
316
316
|
// Convert capabilities dictionary to Capabilities struct/object if needed
|
|
317
317
|
let audioCapabilities = AudioDeviceCapabilities(
|
|
@@ -330,23 +330,23 @@ class AudioDeviceManager {
|
|
|
330
330
|
isAvailable: true // It's available if found here
|
|
331
331
|
)
|
|
332
332
|
} else {
|
|
333
|
-
Logger.debug("Could not find built-in mic as default device.")
|
|
333
|
+
Logger.debug("AudioDeviceManager", "Could not find built-in mic as default device.")
|
|
334
334
|
return nil
|
|
335
335
|
}
|
|
336
336
|
} catch {
|
|
337
|
-
Logger.debug("Error getting default input device: \(error)")
|
|
337
|
+
Logger.debug("AudioDeviceManager", "Error getting default input device: \(error)")
|
|
338
338
|
return nil
|
|
339
339
|
}
|
|
340
340
|
}
|
|
341
341
|
|
|
342
342
|
/// Selects a specific audio input device for recording
|
|
343
343
|
func selectInputDevice(_ deviceId: String, promise: Promise) {
|
|
344
|
-
Logger.debug("Attempting to select input device with ID: \(deviceId)")
|
|
344
|
+
Logger.debug("AudioDeviceManager", "Attempting to select input device with ID: \(deviceId)")
|
|
345
345
|
|
|
346
346
|
// Prepare audio session - use force: true for device selection to ensure we get the latest devices
|
|
347
347
|
let prepared = prepareAudioSession(force: true)
|
|
348
348
|
if !prepared {
|
|
349
|
-
Logger.debug("Warning: Audio session preparation failed, device selection may not work correctly")
|
|
349
|
+
Logger.debug("AudioDeviceManager", "Warning: Audio session preparation failed, device selection may not work correctly")
|
|
350
350
|
}
|
|
351
351
|
|
|
352
352
|
do {
|
|
@@ -359,7 +359,7 @@ class AudioDeviceManager {
|
|
|
359
359
|
let normalizedRequestedId = normalizeBluetoothDeviceId(deviceId)
|
|
360
360
|
let isBluetoothDevice = deviceId.contains(":")
|
|
361
361
|
|
|
362
|
-
Logger.debug("Selecting \(isBluetoothDevice ? "Bluetooth" : "non-Bluetooth") device with normalized ID: \(normalizedRequestedId)")
|
|
362
|
+
Logger.debug("AudioDeviceManager", "Selecting \(isBluetoothDevice ? "Bluetooth" : "non-Bluetooth") device with normalized ID: \(normalizedRequestedId)")
|
|
363
363
|
|
|
364
364
|
// Find the device with the specified ID
|
|
365
365
|
let selectedPort: AVAudioSessionPortDescription?
|
|
@@ -369,29 +369,29 @@ class AudioDeviceManager {
|
|
|
369
369
|
selectedPort = session.availableInputs?.first { port in
|
|
370
370
|
let portNormalizedId = normalizeBluetoothDeviceId(port.uid)
|
|
371
371
|
let matches = portNormalizedId == normalizedRequestedId
|
|
372
|
-
Logger.debug("Checking device \(port.portName) (ID: \(port.uid), Normalized: \(portNormalizedId)) - Matches: \(matches)")
|
|
372
|
+
Logger.debug("AudioDeviceManager", "Checking device \(port.portName) (ID: \(port.uid), Normalized: \(portNormalizedId)) - Matches: \(matches)")
|
|
373
373
|
return matches
|
|
374
374
|
}
|
|
375
375
|
} else {
|
|
376
376
|
// For non-Bluetooth devices, direct match
|
|
377
377
|
selectedPort = session.availableInputs?.first { port in
|
|
378
378
|
let matches = port.uid == deviceId
|
|
379
|
-
Logger.debug("Checking device \(port.portName) (ID: \(port.uid)) - Matches: \(matches)")
|
|
379
|
+
Logger.debug("AudioDeviceManager", "Checking device \(port.portName) (ID: \(port.uid)) - Matches: \(matches)")
|
|
380
380
|
return matches
|
|
381
381
|
}
|
|
382
382
|
}
|
|
383
383
|
|
|
384
384
|
guard let selectedPort = selectedPort else {
|
|
385
|
-
Logger.debug("Device not found with ID \(deviceId)")
|
|
385
|
+
Logger.debug("AudioDeviceManager", "Device not found with ID \(deviceId)")
|
|
386
386
|
|
|
387
387
|
// Log all available devices to help debugging
|
|
388
388
|
if let availableInputs = session.availableInputs {
|
|
389
|
-
Logger.debug("Available devices:")
|
|
389
|
+
Logger.debug("AudioDeviceManager", "Available devices:")
|
|
390
390
|
for (index, device) in availableInputs.enumerated() {
|
|
391
|
-
Logger.debug("\(index+1). \(device.portName) (ID: \(device.uid), Normalized: \(normalizeBluetoothDeviceId(device.uid)))")
|
|
391
|
+
Logger.debug("AudioDeviceManager", "\(index+1). \(device.portName) (ID: \(device.uid), Normalized: \(normalizeBluetoothDeviceId(device.uid)))")
|
|
392
392
|
}
|
|
393
393
|
} else {
|
|
394
|
-
Logger.debug("No available devices found")
|
|
394
|
+
Logger.debug("AudioDeviceManager", "No available devices found")
|
|
395
395
|
}
|
|
396
396
|
|
|
397
397
|
promise.reject("DEVICE_NOT_FOUND", "The selected audio device is not available")
|
|
@@ -399,31 +399,31 @@ class AudioDeviceManager {
|
|
|
399
399
|
}
|
|
400
400
|
|
|
401
401
|
// Set the preferred input device
|
|
402
|
-
Logger.debug("Setting preferred input to: \(selectedPort.portName) (ID: \(selectedPort.uid))")
|
|
402
|
+
Logger.debug("AudioDeviceManager", "Setting preferred input to: \(selectedPort.portName) (ID: \(selectedPort.uid))")
|
|
403
403
|
try session.setPreferredInput(selectedPort)
|
|
404
404
|
|
|
405
405
|
// Verify selection
|
|
406
406
|
if let currentInput = session.currentRoute.inputs.first {
|
|
407
407
|
let succeeded = (currentInput.uid == selectedPort.uid ||
|
|
408
408
|
normalizeBluetoothDeviceId(currentInput.uid) == normalizeBluetoothDeviceId(selectedPort.uid))
|
|
409
|
-
Logger.debug("Device selection \(succeeded ? "succeeded" : "failed") - Current device: \(currentInput.portName) (ID: \(currentInput.uid))")
|
|
409
|
+
Logger.debug("AudioDeviceManager", "Device selection \(succeeded ? "succeeded" : "failed") - Current device: \(currentInput.portName) (ID: \(currentInput.uid))")
|
|
410
410
|
}
|
|
411
411
|
|
|
412
|
-
Logger.debug("Device selected successfully")
|
|
412
|
+
Logger.debug("AudioDeviceManager", "Device selected successfully")
|
|
413
413
|
promise.resolve(true)
|
|
414
414
|
} catch {
|
|
415
|
-
Logger.debug("Failed to select device: \(error.localizedDescription)")
|
|
415
|
+
Logger.debug("AudioDeviceManager", "Failed to select device: \(error.localizedDescription)")
|
|
416
416
|
promise.reject("DEVICE_SELECTION_FAILED", "Failed to select audio device: \(error.localizedDescription)")
|
|
417
417
|
}
|
|
418
418
|
}
|
|
419
419
|
|
|
420
420
|
/// Selects a specific audio input device asynchronously (useful for internal calls)
|
|
421
421
|
func selectDevice(_ deviceId: String) async -> Bool {
|
|
422
|
-
Logger.debug("Attempting to select input device with ID: \(deviceId) (async)")
|
|
422
|
+
Logger.debug("AudioDeviceManager", "Attempting to select input device with ID: \(deviceId) (async)")
|
|
423
423
|
|
|
424
424
|
let prepared = prepareAudioSession(force: true)
|
|
425
425
|
if !prepared {
|
|
426
|
-
Logger.debug("Warning: Audio session preparation failed, device selection may not work correctly")
|
|
426
|
+
Logger.debug("AudioDeviceManager", "Warning: Audio session preparation failed, device selection may not work correctly")
|
|
427
427
|
return false
|
|
428
428
|
}
|
|
429
429
|
|
|
@@ -434,7 +434,7 @@ class AudioDeviceManager {
|
|
|
434
434
|
let normalizedRequestedId = normalizeBluetoothDeviceId(deviceId)
|
|
435
435
|
let isBluetoothDevice = deviceId.contains(":")
|
|
436
436
|
|
|
437
|
-
Logger.debug("Selecting \(isBluetoothDevice ? "Bluetooth" : "non-Bluetooth") device with normalized ID: \(normalizedRequestedId)")
|
|
437
|
+
Logger.debug("AudioDeviceManager", "Selecting \(isBluetoothDevice ? "Bluetooth" : "non-Bluetooth") device with normalized ID: \(normalizedRequestedId)")
|
|
438
438
|
|
|
439
439
|
let selectedPort: AVAudioSessionPortDescription?
|
|
440
440
|
if isBluetoothDevice {
|
|
@@ -446,11 +446,11 @@ class AudioDeviceManager {
|
|
|
446
446
|
}
|
|
447
447
|
|
|
448
448
|
guard let portToSet = selectedPort else {
|
|
449
|
-
Logger.debug("Device not found with ID \(deviceId) for async selection")
|
|
449
|
+
Logger.debug("AudioDeviceManager", "Device not found with ID \(deviceId) for async selection")
|
|
450
450
|
return false
|
|
451
451
|
}
|
|
452
452
|
|
|
453
|
-
Logger.debug("Setting preferred input to: \(portToSet.portName) (ID: \(portToSet.uid)) (async)")
|
|
453
|
+
Logger.debug("AudioDeviceManager", "Setting preferred input to: \(portToSet.portName) (ID: \(portToSet.uid)) (async)")
|
|
454
454
|
try session.setPreferredInput(portToSet)
|
|
455
455
|
// Add a small delay hoping the system applies the change before potential next operations
|
|
456
456
|
try await Task.sleep(nanoseconds: 100_000_000) // 0.1 seconds
|
|
@@ -458,7 +458,7 @@ class AudioDeviceManager {
|
|
|
458
458
|
// Optional: Verify selection succeeded (might be less reliable immediately after setting)
|
|
459
459
|
if let currentInput = session.currentRoute.inputs.first {
|
|
460
460
|
let succeeded = (currentInput.uid == portToSet.uid || normalizeBluetoothDeviceId(currentInput.uid) == normalizedRequestedId)
|
|
461
|
-
Logger.debug("Async selection verification: \(succeeded ? "succeeded" : "failed")")
|
|
461
|
+
Logger.debug("AudioDeviceManager", "Async selection verification: \(succeeded ? "succeeded" : "failed")")
|
|
462
462
|
return succeeded
|
|
463
463
|
} else {
|
|
464
464
|
// If no current input after setting, assume failure
|
|
@@ -466,19 +466,19 @@ class AudioDeviceManager {
|
|
|
466
466
|
}
|
|
467
467
|
|
|
468
468
|
} catch {
|
|
469
|
-
Logger.debug("Failed to select device asynchronously: \(error.localizedDescription)")
|
|
469
|
+
Logger.debug("AudioDeviceManager", "Failed to select device asynchronously: \(error.localizedDescription)")
|
|
470
470
|
return false
|
|
471
471
|
}
|
|
472
472
|
}
|
|
473
473
|
|
|
474
474
|
/// Determines if a device is still available
|
|
475
475
|
func isDeviceAvailable(_ deviceId: String) -> Bool {
|
|
476
|
-
Logger.debug("Checking availability for device ID: \(deviceId)")
|
|
476
|
+
Logger.debug("AudioDeviceManager", "Checking availability for device ID: \(deviceId)")
|
|
477
477
|
|
|
478
478
|
// Prepare audio session if needed
|
|
479
479
|
let prepared = prepareAudioSession()
|
|
480
480
|
if !prepared {
|
|
481
|
-
Logger.debug("Warning: Audio session preparation failed, device availability check may not be accurate")
|
|
481
|
+
Logger.debug("AudioDeviceManager", "Warning: Audio session preparation failed, device availability check may not be accurate")
|
|
482
482
|
}
|
|
483
483
|
|
|
484
484
|
let session = AVAudioSession.sharedInstance()
|
|
@@ -491,26 +491,26 @@ class AudioDeviceManager {
|
|
|
491
491
|
let baseDeviceId = deviceId.split(separator: "-").first ?? Substring(deviceId)
|
|
492
492
|
|
|
493
493
|
// Log all available inputs for debugging
|
|
494
|
-
Logger.debug("Available devices to check against:")
|
|
494
|
+
Logger.debug("AudioDeviceManager", "Available devices to check against:")
|
|
495
495
|
if let availableInputs = session.availableInputs {
|
|
496
496
|
for (index, device) in availableInputs.enumerated() {
|
|
497
497
|
let normalizedId = normalizeBluetoothDeviceId(device.uid)
|
|
498
498
|
let matches = device.uid.starts(with: String(baseDeviceId))
|
|
499
|
-
Logger.debug("\(index+1). \(device.portName) (ID: \(device.uid), Normalized: \(normalizedId)) - Matches: \(matches)")
|
|
499
|
+
Logger.debug("AudioDeviceManager", "\(index+1). \(device.portName) (ID: \(device.uid), Normalized: \(normalizedId)) - Matches: \(matches)")
|
|
500
500
|
}
|
|
501
501
|
} else {
|
|
502
|
-
Logger.debug("No available devices found")
|
|
502
|
+
Logger.debug("AudioDeviceManager", "No available devices found")
|
|
503
503
|
}
|
|
504
504
|
|
|
505
505
|
// Also check current route
|
|
506
506
|
for (index, input) in session.currentRoute.inputs.enumerated() {
|
|
507
507
|
let normalizedId = normalizeBluetoothDeviceId(input.uid)
|
|
508
508
|
let matches = input.uid.starts(with: String(baseDeviceId))
|
|
509
|
-
Logger.debug("Current route input \(index+1): \(input.portName) (ID: \(input.uid), Normalized: \(normalizedId)) - Matches: \(matches)")
|
|
509
|
+
Logger.debug("AudioDeviceManager", "Current route input \(index+1): \(input.portName) (ID: \(input.uid), Normalized: \(normalizedId)) - Matches: \(matches)")
|
|
510
510
|
}
|
|
511
511
|
|
|
512
512
|
let result = session.availableInputs?.contains { $0.uid.starts(with: String(baseDeviceId)) } ?? false
|
|
513
|
-
Logger.debug("Bluetooth device \(deviceId) with base ID \(baseDeviceId) available: \(result)")
|
|
513
|
+
Logger.debug("AudioDeviceManager", "Bluetooth device \(deviceId) with base ID \(baseDeviceId) available: \(result)")
|
|
514
514
|
return result
|
|
515
515
|
} else {
|
|
516
516
|
// Standard device ID check for non-Bluetooth devices
|
|
@@ -521,12 +521,12 @@ class AudioDeviceManager {
|
|
|
521
521
|
/// Resets the selected device to system default (usually built-in mic)
|
|
522
522
|
/// - Parameter completion: Callback with success (Bool) and optional error
|
|
523
523
|
func resetToDefaultDevice(completion: @escaping (Bool, Error?) -> Void) {
|
|
524
|
-
Logger.debug("Attempting to reset to default input device")
|
|
524
|
+
Logger.debug("AudioDeviceManager", "Attempting to reset to default input device")
|
|
525
525
|
|
|
526
526
|
// Prepare audio session if needed
|
|
527
527
|
let prepared = prepareAudioSession()
|
|
528
528
|
if !prepared {
|
|
529
|
-
Logger.debug("Warning: Audio session preparation failed, device reset may not work correctly")
|
|
529
|
+
Logger.debug("AudioDeviceManager", "Warning: Audio session preparation failed, device reset may not work correctly")
|
|
530
530
|
}
|
|
531
531
|
|
|
532
532
|
do {
|
|
@@ -534,9 +534,9 @@ class AudioDeviceManager {
|
|
|
534
534
|
|
|
535
535
|
// Log current device before reset
|
|
536
536
|
if let currentDevice = session.currentRoute.inputs.first {
|
|
537
|
-
Logger.debug("Current device before reset: \(currentDevice.portName) (ID: \(currentDevice.uid))")
|
|
537
|
+
Logger.debug("AudioDeviceManager", "Current device before reset: \(currentDevice.portName) (ID: \(currentDevice.uid))")
|
|
538
538
|
} else {
|
|
539
|
-
Logger.debug("No current device before reset")
|
|
539
|
+
Logger.debug("AudioDeviceManager", "No current device before reset")
|
|
540
540
|
}
|
|
541
541
|
|
|
542
542
|
// Setting preferred input to nil lets the system choose the default
|
|
@@ -544,18 +544,18 @@ class AudioDeviceManager {
|
|
|
544
544
|
|
|
545
545
|
// Log the device after reset
|
|
546
546
|
if let newDevice = session.currentRoute.inputs.first {
|
|
547
|
-
Logger.debug("Reset to default device: \(newDevice.portName) (ID: \(newDevice.uid))")
|
|
547
|
+
Logger.debug("AudioDeviceManager", "Reset to default device: \(newDevice.portName) (ID: \(newDevice.uid))")
|
|
548
548
|
|
|
549
549
|
// Check if it's actually the built-in mic (which is the typical default)
|
|
550
550
|
let isBuiltIn = newDevice.portType == .builtInMic
|
|
551
|
-
Logger.debug("Reset device is built-in mic: \(isBuiltIn)")
|
|
551
|
+
Logger.debug("AudioDeviceManager", "Reset device is built-in mic: \(isBuiltIn)")
|
|
552
552
|
} else {
|
|
553
|
-
Logger.debug("No device found after reset")
|
|
553
|
+
Logger.debug("AudioDeviceManager", "No device found after reset")
|
|
554
554
|
}
|
|
555
555
|
|
|
556
556
|
completion(true, nil)
|
|
557
557
|
} catch {
|
|
558
|
-
Logger.debug("Failed to reset to default device: \(error.localizedDescription)")
|
|
558
|
+
Logger.debug("AudioDeviceManager", "Failed to reset to default device: \(error.localizedDescription)")
|
|
559
559
|
completion(false, error)
|
|
560
560
|
}
|
|
561
561
|
}
|
|
@@ -565,7 +565,7 @@ class AudioDeviceManager {
|
|
|
565
565
|
// Ensure we don't add multiple observers
|
|
566
566
|
stopMonitoringDeviceChanges()
|
|
567
567
|
|
|
568
|
-
Logger.debug("Starting device change monitoring")
|
|
568
|
+
Logger.debug("AudioDeviceManager", "Starting device change monitoring")
|
|
569
569
|
routeChangeObserver = NotificationCenter.default.addObserver(
|
|
570
570
|
forName: AVAudioSession.routeChangeNotification,
|
|
571
571
|
object: nil,
|
|
@@ -578,7 +578,7 @@ class AudioDeviceManager {
|
|
|
578
578
|
/// Stops monitoring device changes
|
|
579
579
|
private func stopMonitoringDeviceChanges() {
|
|
580
580
|
if let observer = routeChangeObserver {
|
|
581
|
-
Logger.debug("Stopping device change monitoring")
|
|
581
|
+
Logger.debug("AudioDeviceManager", "Stopping device change monitoring")
|
|
582
582
|
NotificationCenter.default.removeObserver(observer)
|
|
583
583
|
routeChangeObserver = nil
|
|
584
584
|
}
|
|
@@ -592,17 +592,17 @@ class AudioDeviceManager {
|
|
|
592
592
|
return
|
|
593
593
|
}
|
|
594
594
|
|
|
595
|
-
Logger.debug("Route change detected, reason: \(reason.rawValue)")
|
|
595
|
+
Logger.debug("AudioDeviceManager", "Route change detected, reason: \(reason.rawValue)")
|
|
596
596
|
|
|
597
597
|
// Only proceed if a device was potentially removed or the route changed significantly
|
|
598
598
|
guard reason == .oldDeviceUnavailable || reason == .newDeviceAvailable || reason == .override || reason == .routeConfigurationChange else {
|
|
599
|
-
Logger.debug("Ignoring route change reason: \(reason.rawValue)")
|
|
599
|
+
Logger.debug("AudioDeviceManager", "Ignoring route change reason: \(reason.rawValue)")
|
|
600
600
|
return
|
|
601
601
|
}
|
|
602
602
|
|
|
603
603
|
// Get the *previous* route description
|
|
604
604
|
guard let previousRoute = userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription else {
|
|
605
|
-
Logger.debug("No previous route info found for disconnection check.")
|
|
605
|
+
Logger.debug("AudioDeviceManager", "No previous route info found for disconnection check.")
|
|
606
606
|
return
|
|
607
607
|
}
|
|
608
608
|
|
|
@@ -615,7 +615,7 @@ class AudioDeviceManager {
|
|
|
615
615
|
let normalizedPreviousId = normalizeBluetoothDeviceId(previousInputPort.uid)
|
|
616
616
|
// Check if the previously connected input is NOT in the set of currently available inputs
|
|
617
617
|
if !currentInputIds.contains(normalizedPreviousId) {
|
|
618
|
-
Logger.debug("Detected disconnection of device: \(previousInputPort.portName) (Normalized ID: \(normalizedPreviousId))")
|
|
618
|
+
Logger.debug("AudioDeviceManager", "Detected disconnection of device: \(previousInputPort.portName) (Normalized ID: \(normalizedPreviousId))")
|
|
619
619
|
// Notify the delegate (AudioStreamManager) about the specific disconnected device
|
|
620
620
|
delegate?.audioDeviceManager(self, didDetectDisconnectionOfDevice: normalizedPreviousId)
|
|
621
621
|
// Found a disconnected device, can stop checking previous inputs for this event
|