Files
alice-backend/room-eq/record-mac.swift
T

62 lines
2.5 KiB
Swift

import AVFoundation
import Foundation
@main
struct RecordRoom {
static func main() throws {
guard CommandLine.arguments.count == 2 else {
throw NSError(domain: "RoomMic", code: 1)
}
let engine = AVAudioEngine()
let input = engine.inputNode
let format = input.outputFormat(forBus: 0)
guard format.sampleRate > 0, format.channelCount > 0 else {
throw NSError(domain: "RoomMic", code: 2, userInfo: [NSLocalizedDescriptionKey: "Нет входа микрофона."])
}
let destination = URL(fileURLWithPath: CommandLine.arguments[1])
let output = try AVAudioFile(forWriting: destination, settings: [
AVFormatIDKey: kAudioFormatLinearPCM,
AVSampleRateKey: format.sampleRate,
AVNumberOfChannelsKey: format.channelCount,
AVLinearPCMBitDepthKey: 16,
AVLinearPCMIsFloatKey: false,
AVLinearPCMIsBigEndianKey: false,
AVLinearPCMIsNonInterleaved: false,
], commonFormat: format.commonFormat, interleaved: format.isInterleaved)
let limit = Int(format.sampleRate * 13)
let complete = DispatchSemaphore(value: 0)
let state = Recording(limit)
input.installTap(onBus: 0, bufferSize: 1024, format: format) { buffer, _ in
guard state.remaining > 0 else { return }
buffer.frameLength = min(buffer.frameLength, AVAudioFrameCount(state.remaining))
do {
try output.write(from: buffer)
state.remaining -= Int(buffer.frameLength)
} catch {
state.failure = error
state.remaining = 0
}
if state.remaining == 0 { complete.signal() }
}
defer {
engine.stop()
input.removeTap(onBus: 0)
}
engine.prepare()
try engine.start()
FileHandle.standardOutput.write(Data("ready\n".utf8))
guard complete.wait(timeout: .now() + 17) == .success else {
throw NSError(domain: "RoomMic", code: 3, userInfo: [NSLocalizedDescriptionKey: "Микрофон не отдал запись вовремя."])
}
if let failure = state.failure { throw failure }
}
}
private final class Recording: @unchecked Sendable {
// The tap owns this state. The main thread reads the result after the semaphore.
var remaining: Int
var failure: Error?
init(_ remaining: Int) { self.remaining = remaining }
}