-
-
Save Denismih/e5de495d529449e0c41f586ee77be9d2 to your computer and use it in GitHub Desktop.
Simple Audio recorder and player in swift 4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// AGAudioRecorder.swift | |
// BaseProject | |
// | |
// Created by AshvinGudaliya on 17/09/18. | |
// Copyright © 2018 AshvinGudaliya. All rights reserved. | |
// | |
import UIKit | |
import AVFoundation | |
enum AGAudioRecorderState { | |
case Pause | |
case Play | |
case Finish | |
case Failed(String) | |
case Recording | |
case Ready | |
case error(Error) | |
} | |
protocol AGAudioRecorderDelegate { | |
func agAudioRecorder(_ recorder: AGAudioRecorder, withStates state: AGAudioRecorderState) | |
func agAudioRecorder(_ recorder: AGAudioRecorder, currentTime timeInterval: TimeInterval, formattedString: String) | |
} | |
class AGAudioRecorder: NSObject { | |
private var isAudioRecordingGranted: Bool = false | |
private var filename: String = "" | |
private var recorderState: AGAudioRecorderState = .Ready { | |
willSet{ | |
delegate?.agAudioRecorder(self, withStates: newValue) | |
} | |
} | |
private var audioRecorder: AVAudioRecorder! = nil | |
private var audioPlayer: AVAudioPlayer! = nil | |
private var meterTimer: Timer! = nil | |
private var currentTimeInterval: TimeInterval = 0.0 | |
var delegate: AGAudioRecorderDelegate? | |
init(withFileName filename: String) { | |
super.init() | |
self.recorderState = .Ready | |
self.filename = filename | |
self.check_record_permission() | |
} | |
private func check_record_permission() { | |
switch AVAudioSession.sharedInstance().recordPermission() { | |
case .granted: | |
isAudioRecordingGranted = true | |
break | |
case .denied: | |
isAudioRecordingGranted = false | |
break | |
case .undetermined: | |
AVAudioSession.sharedInstance().requestRecordPermission({ (allowed) in | |
if allowed { | |
self.isAudioRecordingGranted = true | |
} else { | |
self.isAudioRecordingGranted = false | |
} | |
}) | |
break | |
} | |
} | |
private func documentsDirectory() -> URL { | |
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) | |
let documentsDirectory = paths[0] | |
return documentsDirectory | |
} | |
func fileUrl() -> URL { | |
let filename = "\(self.filename).m4a" | |
let filePath = documentsDirectory().appendingPathComponent(filename) | |
return filePath | |
} | |
func changeFile(withFileName filename: String) { | |
self.filename = filename | |
if audioPlayer != nil { | |
doPause() | |
} | |
if audioRecorder != nil { | |
doStopRecording() | |
setupRecorder() | |
} | |
} | |
private func setupRecorder() { | |
if isAudioRecordingGranted { | |
let session = AVAudioSession.sharedInstance() | |
do { | |
try session.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .defaultToSpeaker) | |
try session.setActive(true) | |
let settings = [ | |
AVFormatIDKey: Int(kAudioFormatMPEG4AAC), | |
AVSampleRateKey: 44100, | |
AVNumberOfChannelsKey: 2, | |
AVEncoderAudioQualityKey:AVAudioQuality.high.rawValue | |
] | |
audioRecorder = try AVAudioRecorder(url: fileUrl(), settings: settings) | |
audioRecorder.delegate = self | |
audioRecorder.isMeteringEnabled = true | |
audioRecorder.prepareToRecord() | |
self.recorderState = .Ready | |
} | |
catch let error { | |
recorderState = .error(error) | |
} | |
} | |
else { | |
recorderState = .Failed("Don't have access to use your microphone.") | |
} | |
} | |
@objc private func updateAudioMeter(timer: Timer) { | |
if audioRecorder.isRecording { | |
currentTimeInterval = currentTimeInterval + 0.01 | |
let hr = Int((currentTimeInterval / 60) / 60) | |
let min = Int(currentTimeInterval / 60) | |
let sec = Int(currentTimeInterval.truncatingRemainder(dividingBy: 60)) | |
let totalTimeString = String(format: "%02d:%02d:%02d", hr, min, sec) | |
delegate?.agAudioRecorder(self, currentTime: currentTimeInterval, formattedString: totalTimeString) | |
audioRecorder.updateMeters() | |
} | |
} | |
private func finishAudioRecording(success: Bool) { | |
if success { | |
audioRecorder?.stop() | |
meterTimer?.invalidate() | |
recorderState = .Finish | |
} | |
else { | |
recorderState = .Failed("Recording failed.") | |
} | |
} | |
private func preparePlay() { | |
do { | |
audioPlayer = try AVAudioPlayer(contentsOf: fileUrl()) | |
audioPlayer.delegate = self | |
audioPlayer.prepareToPlay() | |
recorderState = .Ready | |
} | |
catch { | |
recorderState = .error(error) | |
debugPrint(error) | |
} | |
} | |
func doRecord() { | |
if audioRecorder == nil { | |
setupRecorder() | |
} | |
if audioRecorder.isRecording { | |
doStopRecording() | |
} | |
else { | |
audioRecorder.record() | |
currentTimeInterval = 0.0 | |
meterTimer = Timer.scheduledTimer(timeInterval: 0.01, target:self, selector:#selector(self.updateAudioMeter(timer:)), userInfo:nil, repeats:true) | |
recorderState = .Recording | |
} | |
} | |
func doStopRecording() { | |
guard audioRecorder != nil else { | |
return | |
} | |
audioRecorder.stop() | |
let audioSession = AVAudioSession.sharedInstance() | |
do { | |
try audioSession.setActive(false) | |
finishAudioRecording(success: true) | |
} catch { | |
recorderState = .error(error) | |
} | |
} | |
func doPlay() { | |
if audioPlayer == nil { | |
self.preparePlay() | |
} | |
if audioRecorder != nil, audioRecorder.isRecording { | |
self.doStopRecording() | |
} | |
if audioPlayer.isPlaying { | |
doPause() | |
} | |
else{ | |
if FileManager.default.fileExists(atPath: fileUrl().path) { | |
preparePlay() | |
audioPlayer.play() | |
recorderState = .Play | |
} | |
else { | |
recorderState = .Failed("Audio file is missing.") | |
} | |
} | |
} | |
func doPause() { | |
guard audioPlayer != nil else { | |
return | |
} | |
if audioRecorder != nil, audioRecorder.isRecording { | |
self.doStopRecording() | |
} | |
if (audioPlayer.isPlaying){ | |
audioPlayer.pause() | |
} | |
recorderState = .Pause | |
} | |
} | |
extension AGAudioRecorder: AVAudioRecorderDelegate, AVAudioPlayerDelegate { | |
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) { | |
if !flag { | |
finishAudioRecording(success: false) | |
} | |
} | |
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment