Parent directory

Recorder.swift

1749 bytes
 1import AVFoundation
 2
 3// Records 16 kHz mono PCM WAV, matching what the TUI's arecord capture produces.
 4final class Recorder {
 5    private var recorder: AVAudioRecorder?
 6    private var fileURL: URL?
 7
 8    func start() throws {
 9        guard recorder == nil else {
10            return
11        }
12
13        try configureSession()
14
15        let url = FileManager.default.temporaryDirectory
16            .appendingPathComponent(UUID().uuidString)
17            .appendingPathExtension("wav")
18        let settings: [String: Any] = [
19            AVFormatIDKey: kAudioFormatLinearPCM,
20            AVSampleRateKey: 16_000.0,
21            AVNumberOfChannelsKey: 1,
22            AVLinearPCMBitDepthKey: 16,
23        ]
24        let recorder = try AVAudioRecorder(url: url, settings: settings)
25        recorder.record()
26        self.recorder = recorder
27        self.fileURL = url
28    }
29
30    func stop() throws -> Data {
31        defer {
32            recorder?.stop()
33            recorder = nil
34            if let fileURL {
35                try? FileManager.default.removeItem(at: fileURL)
36                self.fileURL = nil
37            }
38        }
39        guard let fileURL else {
40            throw RecorderError.notRecording
41        }
42        return try Data(contentsOf: fileURL)
43    }
44
45    private func configureSession() throws {
46        #if os(iOS)
47        let session = AVAudioSession.sharedInstance()
48        try session.setCategory(.playAndRecord, mode: .measurement, options: [.defaultToSpeaker])
49        try session.setActive(true)
50        #endif
51    }
52}
53
54enum RecorderError: LocalizedError {
55    case notRecording
56
57    var errorDescription: String? {
58        switch self {
59        case .notRecording:
60            "The microphone is not recording."
61        }
62    }
63}