63 lines
1.9 KiB
Swift
63 lines
1.9 KiB
Swift
import AVFoundation
|
|
import Commander
|
|
import Foundation
|
|
import Swabble
|
|
|
|
@MainActor
|
|
struct MicCommand: ParsableCommand {
|
|
static var commandDescription: CommandDescription {
|
|
CommandDescription(
|
|
commandName: "mic",
|
|
abstract: "Microphone management",
|
|
subcommands: [MicList.self, MicSet.self])
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
struct MicList: ParsableCommand {
|
|
static var commandDescription: CommandDescription {
|
|
CommandDescription(commandName: "list", abstract: "List input devices")
|
|
}
|
|
|
|
init() {}
|
|
init(parsed: ParsedValues) {}
|
|
|
|
mutating func run() async throws {
|
|
let session = AVCaptureDevice.DiscoverySession(
|
|
deviceTypes: [.microphone, .external],
|
|
mediaType: .audio,
|
|
position: .unspecified)
|
|
let devices = session.devices
|
|
if devices.isEmpty { print("no audio inputs found"); return }
|
|
for (idx, device) in devices.enumerated() {
|
|
print("[\(idx)] \(device.localizedName)")
|
|
}
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
struct MicSet: ParsableCommand {
|
|
@Argument(help: "Device index from list") var index: Int = 0
|
|
@Option(name: .long("config"), help: "Path to config JSON") var configPath: String?
|
|
|
|
static var commandDescription: CommandDescription {
|
|
CommandDescription(commandName: "set", abstract: "Set default input device index")
|
|
}
|
|
|
|
init() {}
|
|
init(parsed: ParsedValues) {
|
|
self.init()
|
|
if let value = parsed.positional.first, let intVal = Int(value) { index = intVal }
|
|
if let cfg = parsed.options["config"]?.last { configPath = cfg }
|
|
}
|
|
|
|
mutating func run() async throws {
|
|
var cfg = try ConfigLoader.load(at: configURL)
|
|
cfg.audio.deviceIndex = index
|
|
try ConfigLoader.save(cfg, at: configURL)
|
|
print("saved device index \(index)")
|
|
}
|
|
|
|
private var configURL: URL? { configPath.map { URL(fileURLWithPath: $0) } }
|
|
}
|