AudioRecorder.swift (8214B)
1 // 2 // AudioRecorder.swift 3 // captainsLog 4 // 5 // Created by Benjamin Welner on 10/29/19. 6 // Copyright © 2019 FIGBERT Industries. All rights reserved. 7 // 8 9 import Foundation 10 import SwiftUI 11 import Combine 12 import AVFoundation 13 14 class AudioRecorder: NSObject, ObservableObject { 15 16 override init() { 17 super.init() 18 fetchRecordings() 19 } 20 21 var audioRecorder: AVAudioRecorder! 22 @Published var recordings = [Recording]() 23 @Published var recording: Bool = false 24 @Published var hasRecorded: Bool = false 25 26 func startRecording() { 27 if (!hasRecorded) { 28 let recordingSession = AVAudioSession.sharedInstance() 29 do { 30 try recordingSession.setCategory(.playAndRecord, mode: .default) 31 try recordingSession.setActive(true) 32 } catch { 33 print("Failed to set up audio session") 34 } 35 let documentPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] 36 let rawDate = Date() 37 let dateMatch = rawDate.toString(dateFormat: "dd-MM-YY_'at'_HH:mm:ss") 38 let audioFilename = documentPath.appendingPathComponent("\(dateMatch).m4a") 39 let jsonFilename = documentPath.appendingPathComponent("\(dateMatch).json") 40 let title = "alertHere" 41 let number = recordings.count+1 42 let detailObject = Recording(audioURL: audioFilename, fileURL: jsonFilename, createdAt: rawDate, title: title, number: number) 43 let json = try! JSONEncoder().encode(detailObject) 44 let settings = [ 45 AVFormatIDKey: Int(kAudioFormatMPEG4AAC), 46 AVSampleRateKey: 12000, 47 AVNumberOfChannelsKey: 1, 48 AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue 49 ] 50 do { 51 audioRecorder = try AVAudioRecorder(url: audioFilename, settings: settings) 52 audioRecorder.record() 53 recording = true 54 hasRecorded = true 55 } catch { 56 print("Could not start recording") 57 } 58 do { 59 try json.write(to: jsonFilename) 60 } catch { 61 print("Could not write files") 62 } 63 } else { 64 audioRecorder.record() 65 recording = true 66 } 67 } 68 69 func pauseRecording() { 70 audioRecorder.pause() 71 recording = false 72 } 73 74 func endRecording() { 75 audioRecorder.stop() 76 recording = false 77 hasRecorded = false 78 fetchRecordings() 79 } 80 81 func getCreationDate(for file: URL) -> Date { 82 if let attributes = try? FileManager.default.attributesOfItem(atPath: file.path) as [FileAttributeKey: Any], 83 let creationDate = attributes[FileAttributeKey.creationDate] as? Date { 84 return creationDate 85 } else { 86 return Date() 87 } 88 } 89 90 func fetchRecordings() { 91 recordings.removeAll() 92 let fileManager = FileManager.default 93 let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0] 94 let directoryContents = try! fileManager.contentsOfDirectory(at: documentDirectory, includingPropertiesForKeys: nil) 95 for file in directoryContents { 96 if (file.pathExtension == "json") { 97 let contents = try! String(contentsOf: file, encoding: .utf8) 98 let serialized = contents.data(using: .utf8)! 99 let recording = try! JSONDecoder().decode(Recording.self, from: serialized) 100 recordings.append(recording) 101 } 102 } 103 recordings.sort(by: { $0.createdAt.compare($1.createdAt) == .orderedAscending}) 104 for (index, _) in recordings.enumerated() { 105 recordings[index].number = index + 1 106 } 107 } 108 109 func deleteRecording(urlsToDelete: [URL]) { 110 for url in urlsToDelete { 111 do { 112 try FileManager.default.removeItem(at: url) 113 } catch { 114 print("File could not be deleted") 115 } 116 } 117 fetchRecordings() 118 } 119 } 120 121 struct RecordingRow: View { 122 var audioURL: URL 123 let createdAt: Date 124 let title: String 125 let number: Int 126 @State private var strDate: String = "" 127 @ObservedObject var audioPlayer = AudioPlayer() 128 @EnvironmentObject var globalVars: GlobalVars 129 var body: some View { 130 HStack { 131 VStack(alignment: .leading) { 132 Text("\(title)") 133 .font(.headline) 134 Group { 135 if (globalVars.currentDateFormat == 1) { 136 Text("#\(number) – \(createdAt.multi(type: "Jewish").joined(separator: ""))") 137 .font(.caption) 138 } else if (globalVars.currentDateFormat == 2) { 139 Text("#\(number) – \(createdAt.multi(type: "Islamic").joined(separator: ""))") 140 .font(.caption) 141 } else if (globalVars.currentDateFormat == 3) { 142 Text("#\(number) – \(createdAt.multi(type: "Persian").joined(separator: ""))") 143 .font(.caption) 144 } else if (globalVars.currentDateFormat == 4) { 145 Text("#\(number) – \(createdAt.multi(type: "Indian").joined(separator: ""))") 146 .font(.caption) 147 } else if (globalVars.currentDateFormat == 5) { 148 Text("#\(number) – \(createdAt.multi(type: "Coptic").joined(separator: ""))") 149 .font(.caption) 150 } else if (globalVars.currentDateFormat == 6) { 151 Text("#\(number) – \(createdAt.multi(type: "Chinese").joined(separator: ""))") 152 .font(.caption) 153 } else if (globalVars.currentDateFormat == 7) { 154 Text("#\(number) – \(createdAt.multi(type: "Japanese").joined(separator: ""))") 155 .font(.caption) 156 } else if (globalVars.currentDateFormat == 8) { 157 Text("#\(number) – \(createdAt.multi(type: "Ethiopian").joined(separator: ""))") 158 .font(.caption) 159 } else if (globalVars.currentDateFormat == 9) { 160 Text("#\(number) – \(createdAt.multi(type: "Gregorian").joined(separator: ""))") 161 .font(.caption) 162 } else { 163 Text("#\(number) – \(createdAt.stardate().joined(separator: " "))") 164 .font(.caption) 165 } 166 } 167 } 168 Spacer() 169 if (!audioPlayer.isPlaying) { 170 Button(action: { 171 self.audioPlayer.startPlayback(audio: self.audioURL) 172 }) { 173 Image( 174 uiImage: UIImage( 175 systemName: "play.circle", 176 withConfiguration: UIImage.SymbolConfiguration( 177 pointSize: CGFloat.init(15), 178 weight: .regular, 179 scale: .large 180 ) 181 )! 182 ) 183 } 184 } else { 185 Button(action: { 186 self.audioPlayer.pausePlayback() 187 }) { 188 Image( 189 uiImage: UIImage ( 190 systemName: "pause.circle", 191 withConfiguration: UIImage.SymbolConfiguration( 192 pointSize: CGFloat.init(15), 193 weight: .regular, 194 scale: .large 195 ) 196 )! 197 ) 198 } 199 } 200 } 201 } 202 } 203 204 struct Recording: Codable { 205 let audioURL: URL 206 let fileURL: URL 207 let createdAt: Date 208 let title: String 209 var number: Int 210 }