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}