From bd6973e5599e585c0c7c089db265dd9fdbc80efc Mon Sep 17 00:00:00 2001 From: Beingpax Date: Fri, 12 Dec 2025 11:39:25 +0545 Subject: [PATCH] Better device fallback logic --- VoiceInk/Services/AudioDeviceManager.swift | 38 ++++++++++++++++--- .../OnboardingPermissionsView.swift | 38 ++++++------------- 2 files changed, 44 insertions(+), 32 deletions(-) diff --git a/VoiceInk/Services/AudioDeviceManager.swift b/VoiceInk/Services/AudioDeviceManager.swift index c5f684d..d31007b 100644 --- a/VoiceInk/Services/AudioDeviceManager.swift +++ b/VoiceInk/Services/AudioDeviceManager.swift @@ -106,13 +106,39 @@ class AudioDeviceManager: ObservableObject { } private func fallbackToDefaultDevice() { - logger.info("Temporarily falling back to system default input device – user preference remains intact.") + logger.info("Current device unavailable, selecting new device...") - if let currentID = selectedDeviceID, !isDeviceAvailable(currentID) { + guard let newDeviceID = findBestAvailableDevice() else { + logger.error("No input devices available!") selectedDeviceID = nil + notifyDeviceChange() + return } - notifyDeviceChange() + let newDeviceName = getDeviceName(deviceID: newDeviceID) ?? "Unknown Device" + logger.info("Auto-selecting new device: \(newDeviceName)") + selectDevice(id: newDeviceID) + } + + func findBestAvailableDevice() -> AudioDeviceID? { + if let device = availableDevices.first(where: { isBuiltInDevice($0.id) }) { + logger.info("Found built-in device: \(device.name)") + return device.id + } + + if let device = availableDevices.first { + logger.warning("No built-in device found, using first available: \(device.name)") + return device.id + } + + return nil + } + + private func isBuiltInDevice(_ deviceID: AudioDeviceID) -> Bool { + guard let uid = getDeviceUID(deviceID: deviceID) else { + return false + } + return uid.contains("BuiltIn") } func loadAvailableDevices(completion: (() -> Void)? = nil) { @@ -308,7 +334,8 @@ class AudioDeviceManager: ObservableObject { if let id = selectedDeviceID, isDeviceAvailable(id) { return id } else { - return fallbackDeviceID ?? 0 + // Use smart device finding instead of stale fallback + return findBestAvailableDevice() ?? 0 } case .prioritized: let sortedDevices = prioritizedDevices.sorted { $0.priority < $1.priority } @@ -317,7 +344,8 @@ class AudioDeviceManager: ObservableObject { return available.id } } - return fallbackDeviceID ?? 0 + // Use smart device finding instead of stale fallback + return findBestAvailableDevice() ?? 0 } } diff --git a/VoiceInk/Views/Onboarding/OnboardingPermissionsView.swift b/VoiceInk/Views/Onboarding/OnboardingPermissionsView.swift index f753e3c..b5be453 100644 --- a/VoiceInk/Views/Onboarding/OnboardingPermissionsView.swift +++ b/VoiceInk/Views/Onboarding/OnboardingPermissionsView.swift @@ -175,15 +175,9 @@ struct OnboardingPermissionsView: View { } ) .onAppear { - // Auto-select built-in microphone if no device is selected - if audioDeviceManager.selectedDeviceID == nil && !audioDeviceManager.availableDevices.isEmpty { - let builtInDevice = audioDeviceManager.availableDevices.first { device in - device.name.lowercased().contains("built-in") || - device.name.lowercased().contains("internal") - } - let deviceToSelect = builtInDevice ?? audioDeviceManager.availableDevices.first - if let device = deviceToSelect { - audioDeviceManager.selectDevice(id: device.id) + if !audioDeviceManager.availableDevices.isEmpty { + if let deviceID = audioDeviceManager.findBestAvailableDevice() { + audioDeviceManager.selectDevice(id: deviceID) audioDeviceManager.selectInputMode(.custom) withAnimation { permissionStates[currentPermissionIndex] = true @@ -313,7 +307,7 @@ struct OnboardingPermissionsView: View { case .audioDeviceSelection: audioDeviceManager.loadAvailableDevices() - + if audioDeviceManager.availableDevices.isEmpty { audioDeviceManager.selectInputMode(.custom) withAnimation { @@ -323,23 +317,13 @@ struct OnboardingPermissionsView: View { moveToNext() return } - - // If no device is selected yet, auto-select the built-in microphone or first available device - if audioDeviceManager.selectedDeviceID == nil { - let builtInDevice = audioDeviceManager.availableDevices.first { device in - device.name.lowercased().contains("built-in") || - device.name.lowercased().contains("internal") - } - - let deviceToSelect = builtInDevice ?? audioDeviceManager.availableDevices.first - - if let device = deviceToSelect { - audioDeviceManager.selectDevice(id: device.id) - audioDeviceManager.selectInputMode(.custom) - withAnimation { - permissionStates[currentPermissionIndex] = true - showAnimation = true - } + + if let deviceID = audioDeviceManager.findBestAvailableDevice() { + audioDeviceManager.selectDevice(id: deviceID) + audioDeviceManager.selectInputMode(.custom) + withAnimation { + permissionStates[currentPermissionIndex] = true + showAnimation = true } } moveToNext()