Simplify audio input modes: keep Custom and Prioritized, remove System Default option

This commit is contained in:
Beingpax 2025-12-12 09:19:29 +05:45
parent 8f48c91642
commit a3226bb0fb
3 changed files with 62 additions and 23 deletions

View File

@ -10,7 +10,6 @@ struct PrioritizedDevice: Codable, Identifiable {
} }
enum AudioInputMode: String, CaseIterable { enum AudioInputMode: String, CaseIterable {
case systemDefault = "System Default"
case custom = "Custom Device" case custom = "Custom Device"
case prioritized = "Prioritized" case prioritized = "Prioritized"
} }
@ -19,12 +18,12 @@ class AudioDeviceManager: ObservableObject {
private let logger = Logger(subsystem: "com.prakashjoshipax.voiceink", category: "AudioDeviceManager") private let logger = Logger(subsystem: "com.prakashjoshipax.voiceink", category: "AudioDeviceManager")
@Published var availableDevices: [(id: AudioDeviceID, uid: String, name: String)] = [] @Published var availableDevices: [(id: AudioDeviceID, uid: String, name: String)] = []
@Published var selectedDeviceID: AudioDeviceID? @Published var selectedDeviceID: AudioDeviceID?
@Published var inputMode: AudioInputMode = .systemDefault @Published var inputMode: AudioInputMode = .custom
@Published var prioritizedDevices: [PrioritizedDevice] = [] @Published var prioritizedDevices: [PrioritizedDevice] = []
var fallbackDeviceID: AudioDeviceID? var fallbackDeviceID: AudioDeviceID?
var isRecordingActive: Bool = false var isRecordingActive: Bool = false
static let shared = AudioDeviceManager() static let shared = AudioDeviceManager()
init() { init() {
@ -33,14 +32,35 @@ class AudioDeviceManager: ObservableObject {
loadAvailableDevices { [weak self] in loadAvailableDevices { [weak self] in
self?.initializeSelectedDevice() self?.initializeSelectedDevice()
} }
migrateFromSystemDefaultIfNeeded()
if let savedMode = UserDefaults.standard.audioInputModeRawValue, if let savedMode = UserDefaults.standard.audioInputModeRawValue,
let mode = AudioInputMode(rawValue: savedMode) { let mode = AudioInputMode(rawValue: savedMode) {
inputMode = mode inputMode = mode
} else {
inputMode = .custom
} }
setupDeviceChangeNotifications() setupDeviceChangeNotifications()
} }
private func migrateFromSystemDefaultIfNeeded() {
if let savedModeRaw = UserDefaults.standard.audioInputModeRawValue,
savedModeRaw == "System Default" {
logger.info("Migrating from System Default mode to Custom mode")
if let fallbackID = fallbackDeviceID {
selectedDeviceID = fallbackID
if let device = availableDevices.first(where: { $0.id == fallbackID }) {
UserDefaults.standard.selectedAudioDeviceUID = device.uid
logger.info("Migrated to Custom mode with device: \(device.name)")
}
}
UserDefaults.standard.audioInputModeRawValue = AudioInputMode.custom.rawValue
}
}
func setupFallbackDevice() { func setupFallbackDevice() {
let deviceID: AudioDeviceID? = getDeviceProperty( let deviceID: AudioDeviceID? = getDeviceProperty(
@ -216,6 +236,14 @@ class AudioDeviceManager: ObservableObject {
self.selectedDeviceID = id self.selectedDeviceID = id
UserDefaults.standard.selectedAudioDeviceUID = uid UserDefaults.standard.selectedAudioDeviceUID = uid
self.logger.info("Device selection saved with UID: \(uid)") self.logger.info("Device selection saved with UID: \(uid)")
do {
try AudioDeviceConfiguration.setDefaultInputDevice(id)
self.logger.info("✅ Set device as system default immediately")
} catch {
self.logger.error("Failed to set device as system default: \(error.localizedDescription)")
}
self.notifyDeviceChange() self.notifyDeviceChange()
} }
} else { } else {
@ -232,6 +260,14 @@ class AudioDeviceManager: ObservableObject {
self.selectedDeviceID = id self.selectedDeviceID = id
UserDefaults.standard.audioInputModeRawValue = AudioInputMode.custom.rawValue UserDefaults.standard.audioInputModeRawValue = AudioInputMode.custom.rawValue
UserDefaults.standard.selectedAudioDeviceUID = uid UserDefaults.standard.selectedAudioDeviceUID = uid
do {
try AudioDeviceConfiguration.setDefaultInputDevice(id)
self.logger.info("✅ Set device as system default immediately")
} catch {
self.logger.error("Failed to set device as system default: \(error.localizedDescription)")
}
self.notifyDeviceChange() self.notifyDeviceChange()
} }
} else { } else {
@ -243,11 +279,8 @@ class AudioDeviceManager: ObservableObject {
func selectInputMode(_ mode: AudioInputMode) { func selectInputMode(_ mode: AudioInputMode) {
inputMode = mode inputMode = mode
UserDefaults.standard.audioInputModeRawValue = mode.rawValue UserDefaults.standard.audioInputModeRawValue = mode.rawValue
if mode == .systemDefault { if selectedDeviceID == nil {
selectedDeviceID = nil
UserDefaults.standard.removeObject(forKey: UserDefaults.Keys.selectedAudioDeviceUID)
} else if selectedDeviceID == nil {
if inputMode == .custom { if inputMode == .custom {
if let firstDevice = availableDevices.first { if let firstDevice = availableDevices.first {
selectDevice(id: firstDevice.id) selectDevice(id: firstDevice.id)
@ -255,15 +288,22 @@ class AudioDeviceManager: ObservableObject {
} else if inputMode == .prioritized { } else if inputMode == .prioritized {
selectHighestPriorityAvailableDevice() selectHighestPriorityAvailableDevice()
} }
} else {
if let currentDeviceID = selectedDeviceID {
do {
try AudioDeviceConfiguration.setDefaultInputDevice(currentDeviceID)
logger.info("✅ Set current device as system default when mode changed")
} catch {
logger.error("Failed to set device as system default: \(error.localizedDescription)")
}
}
} }
notifyDeviceChange() notifyDeviceChange()
} }
func getCurrentDevice() -> AudioDeviceID { func getCurrentDevice() -> AudioDeviceID {
switch inputMode { switch inputMode {
case .systemDefault:
return fallbackDeviceID ?? 0
case .custom: case .custom:
if let id = selectedDeviceID, isDeviceAvailable(id) { if let id = selectedDeviceID, isDeviceAvailable(id) {
return id return id
@ -333,14 +373,15 @@ class AudioDeviceManager: ObservableObject {
private func selectHighestPriorityAvailableDevice() { private func selectHighestPriorityAvailableDevice() {
let sortedDevices = prioritizedDevices.sorted { $0.priority < $1.priority } let sortedDevices = prioritizedDevices.sorted { $0.priority < $1.priority }
for device in sortedDevices { for device in sortedDevices {
if let availableDevice = availableDevices.first(where: { $0.uid == device.id }) { if let availableDevice = availableDevices.first(where: { $0.uid == device.id }) {
selectedDeviceID = availableDevice.id selectedDeviceID = availableDevice.id
logger.info("Selected prioritized device: \(device.name) (Priority: \(device.priority))") logger.info("Selected prioritized device: \(device.name) (Priority: \(device.priority))")
do { do {
try AudioDeviceConfiguration.setDefaultInputDevice(availableDevice.id) try AudioDeviceConfiguration.setDefaultInputDevice(availableDevice.id)
logger.info("✅ Set prioritized device as system default immediately")
} catch { } catch {
logger.error("Failed to set prioritized device: \(error.localizedDescription)") logger.error("Failed to set prioritized device: \(error.localizedDescription)")
continue continue
@ -349,7 +390,7 @@ class AudioDeviceManager: ObservableObject {
return return
} }
} }
fallbackToDefaultDevice() fallbackToDefaultDevice()
} }

View File

@ -278,8 +278,8 @@ struct OnboardingPermissionsView: View {
// Check microphone permission // Check microphone permission
permissionStates[0] = AVCaptureDevice.authorizationStatus(for: .audio) == .authorized permissionStates[0] = AVCaptureDevice.authorizationStatus(for: .audio) == .authorized
// Check if device is selected or system default mode is being used // Check if device is selected
permissionStates[1] = audioDeviceManager.selectedDeviceID != nil || audioDeviceManager.inputMode == .systemDefault permissionStates[1] = audioDeviceManager.selectedDeviceID != nil
// Check accessibility permission // Check accessibility permission
permissionStates[2] = AXIsProcessTrusted() permissionStates[2] = AXIsProcessTrusted()
@ -315,7 +315,7 @@ struct OnboardingPermissionsView: View {
audioDeviceManager.loadAvailableDevices() audioDeviceManager.loadAvailableDevices()
if audioDeviceManager.availableDevices.isEmpty { if audioDeviceManager.availableDevices.isEmpty {
audioDeviceManager.selectInputMode(.systemDefault) audioDeviceManager.selectInputMode(.custom)
withAnimation { withAnimation {
permissionStates[currentPermissionIndex] = true permissionStates[currentPermissionIndex] = true
showAnimation = true showAnimation = true

View File

@ -258,15 +258,13 @@ struct InputModeCard: View {
private var icon: String { private var icon: String {
switch mode { switch mode {
case .systemDefault: return "macbook.and.iphone"
case .custom: return "mic.circle.fill" case .custom: return "mic.circle.fill"
case .prioritized: return "list.number" case .prioritized: return "list.number"
} }
} }
private var description: String { private var description: String {
switch mode { switch mode {
case .systemDefault: return "Use system's default input device"
case .custom: return "Select a specific input device" case .custom: return "Select a specific input device"
case .prioritized: return "Set up device priority order" case .prioritized: return "Set up device priority order"
} }