티스토리 뷰

이번 포스팅은 AVAudioPalyer를 이용하여 오디오 파일을 재생, 일시 정지 및 정지하는 방법과 볼륨을 조잘하는 방법 그리고 녹음하는 방법을 알아보려고 한다.

 

바로 들어가보자.


1. 오디오 재생

가장 먼저, 아래와 같이 재생, 일시정지, 정지 버튼과 현재 재생 시간, 끝 시간을 나타낼 레이블 두개 그리고 볼륨을 조절할 슬라이더와 재생 구간을 표시할 프로그래스바로 스토리보드를 구성한다.

기기에 따른 자동 레이아웃을 설정하기 위하여, 가로로 정렬된 아이템들은 가로 스택뷰로 묶고나서 모든 아이템들을 세로 스텍뷰로 묶는다.

 

하나의 스텍뷰로 모든 아이템들을 묶었으면, 상단과 좌우에 알맞는 제약 조건을 아래와 같이 걸어주자.


코드는 동작에 비해 조금 복잡하다고 느낄 수도 있지만, 막상 하나하나 뜯어보면 별 내용 없는 쉬운 코드이다.

 

우선, 각 아이템들에 맞는 outlet변수와 action 함수를 연결해주자.

 

또한 AVAudioPlayer를 사용할 것이기 때문에 해당 모듈을 임포트 해주고, AVAudioPlayerDelegate를 위임해주자.

import UIKit
import AVFoundation

class ViewController: UIViewController, AVAudioPlayerDelegate {

    @IBOutlet var pvProgressPlay: UIProgressView!
    
    @IBOutlet var lblCurrTime: UILabel!
    @IBOutlet var lblEndTime: UILabel!
    
    @IBOutlet var btnPlay: UIButton!
    @IBOutlet var btnPause: UIButton!
    @IBOutlet var btnStop: UIButton!
    
    @IBOutlet var slVolume: UISlider!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }
   
    
    @IBAction func btnPlayAudio(_ sender: UIButton) {
      
    }
    
    @IBAction func btnPauseAudio(_ sender: UIButton) {
     
    }
    
    @IBAction func btnStopAudio(_ sender: UIButton) {

    }

    @IBAction func slChangeVolume(_ sender: UISlider) {

    }

}

 

다음으로 오디오 재생을 위한 초기화 작업을 해줘야 하는데, 우선 필요한 변수들을 선언해주고 viewDidLoad 메서드 내부에 재생할 mp3 파일을 셋팅해준다.

 

var audioPlayer: AVAudioPlayer!

var audioFile: URL!

let MAX_VOLUME: Float = 10.0

var progressTimer: Timer!

override func viewDidLoad() {
    super.viewDidLoad()

    audioFile = Bundle.main.url(forResource: "Sicilian_Breeze", withExtension: "mp3")

    initPlay()
}

 

또한 initPlay() 메서드를 작성해주어 AVAudioPalyer 객체를 할당해주고, 위임자와 각종 변수들을 초기화해준다.

import UIKit
import AVFoundation

class ViewController: UIViewController, AVAudioPlayerDelegate {
    
    var audioPlayer: AVAudioPlayer!
    
    var audioFile: URL!
    
    let MAX_VOLUME: Float = 10.0
    
    var progressTimer: Timer!

    @IBOutlet var pvProgressPlay: UIProgressView!
    
    @IBOutlet var lblCurrTime: UILabel!
    @IBOutlet var lblEndTime: UILabel!
    
    @IBOutlet var btnPlay: UIButton!
    @IBOutlet var btnPause: UIButton!
    @IBOutlet var btnStop: UIButton!
    
    @IBOutlet var slVolume: UISlider!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        audioFile = Bundle.main.url(forResource: "Sicilian_Breeze", withExtension: "mp3")
        
        initPlay()
    }
    
    func initPlay() {
        do {
            try audioPlayer = AVAudioPlayer(contentsOf: audioFile)
        } catch let error as NSError {
            print("Error-initPlay : \(error)")
        }
        
        slVolume.maximumValue = MAX_VOLUME
        slVolume.value = 1.0
        pvProgressPlay.progress = 0
        
        audioPlayer.delegate = self
        audioPlayer.prepareToPlay()
        audioPlayer.volume = slVolume.value
       
    }
    
    @IBAction func btnPlayAudio(_ sender: UIButton) {
    
    }
    
    @IBAction func btnPauseAudio(_ sender: UIButton) {

    }
    
    @IBAction func btnStopAudio(_ sender: UIButton) {

    }


    @IBAction func slChangeVolume(_ sender: UISlider) {
    }
    
}

 

이제, 재생 시간을 00:00 으로 표현해야 하는데 AVAudioPlayer 객체가 제공하는 시간 포맷은 초단위 실수 값이므로

convertNSTimeInterval2String 메서드를 작성하여 00:00 포맷으로 재생 시간을 반환 받을 수 있도록 해준다.

import UIKit
import AVFoundation

class ViewController: UIViewController, AVAudioPlayerDelegate {
    
    var audioPlayer: AVAudioPlayer!
    
    var audioFile: URL!
    
    let MAX_VOLUME: Float = 10.0
    
    var progressTimer: Timer!

    @IBOutlet var pvProgressPlay: UIProgressView!
    
    @IBOutlet var lblCurrTime: UILabel!
    @IBOutlet var lblEndTime: UILabel!
    
    @IBOutlet var btnPlay: UIButton!
    @IBOutlet var btnPause: UIButton!
    @IBOutlet var btnStop: UIButton!
    
    @IBOutlet var slVolume: UISlider!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        audioFile = Bundle.main.url(forResource: "Sicilian_Breeze", withExtension: "mp3")
        
        initPlay()
    }
    
    func initPlay() {
        do {
            try audioPlayer = AVAudioPlayer(contentsOf: audioFile)
        } catch let error as NSError {
            print("Error-initPlay : \(error)")
        }
        
        slVolume.maximumValue = MAX_VOLUME
        slVolume.value = 1.0
        pvProgressPlay.progress = 0
        
        audioPlayer.delegate = self
        audioPlayer.prepareToPlay()
        audioPlayer.volume = slVolume.value
        
        lblEndTime.text = convertNSTimeInterval2String(audioPlayer.duration)
        lblCurrTime.text = convertNSTimeInterval2String(0)
    }
    
    func convertNSTimeInterval2String(_ time: TimeInterval) -> String {
        let min = Int(time/60)
        
        //truncatingRemainder = 실수의 모듈러 계산
        let sec = Int(time.truncatingRemainder(dividingBy: 60))
        let strTime = String(format: "%02d:%02d", min, sec)
        
        return strTime
    }
    
    @IBAction func btnPlayAudio(_ sender: UIButton) {
       
    }
    
    @IBAction func btnPauseAudio(_ sender: UIButton) {

    }
    
    @IBAction func btnStopAudio(_ sender: UIButton) {
    
    }


    @IBAction func slChangeVolume(_ sender: UISlider) {

    }
    
}

 

각 재생 상태에 따라 버튼을 제어할 setPlayButtons 메서드와 각 버튼들의 액션 함수가 AVAudioPlayer 객체를 제어할 수 있도록 코드를 작성해준 뒤, selector 객체를 생성하고 해당 selector 객체가 Timer에 추가하여 비동기로 돌릴 updatePlayTime 메서드를 작성해준다.

import UIKit
import AVFoundation

class ViewController: UIViewController, AVAudioPlayerDelegate {
    
    var audioPlayer: AVAudioPlayer!
    
    var audioFile: URL!
    
    let MAX_VOLUME: Float = 10.0
    
    var progressTimer: Timer!

    @IBOutlet var pvProgressPlay: UIProgressView!
    
    @IBOutlet var lblCurrTime: UILabel!
    @IBOutlet var lblEndTime: UILabel!
    
    @IBOutlet var btnPlay: UIButton!
    @IBOutlet var btnPause: UIButton!
    @IBOutlet var btnStop: UIButton!
    
    @IBOutlet var slVolume: UISlider!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        audioFile = Bundle.main.url(forResource: "Sicilian_Breeze", withExtension: "mp3")
        
        initPlay()
    }
    
    func initPlay() {
        do {
            try audioPlayer = AVAudioPlayer(contentsOf: audioFile)
        } catch let error as NSError {
            print("Error-initPlay : \(error)")
        }
        
        slVolume.maximumValue = MAX_VOLUME
        slVolume.value = 1.0
        pvProgressPlay.progress = 0
        
        audioPlayer.delegate = self
        audioPlayer.prepareToPlay()
        audioPlayer.volume = slVolume.value
        
        lblEndTime.text = convertNSTimeInterval2String(audioPlayer.duration)
        lblCurrTime.text = convertNSTimeInterval2String(0)
        
        setPlayButtons(true, false, false)
    }
    
    func convertNSTimeInterval2String(_ time: TimeInterval) -> String {
        let min = Int(time/60)
        
        //truncatingRemainder = 실수의 모듈러 계산
        let sec = Int(time.truncatingRemainder(dividingBy: 60))
        let strTime = String(format: "%02d:%02d", min, sec)
        
        return strTime
    }
    
    func setPlayButtons(_ play: Bool, _ pause: Bool, _ stop: Bool) {
        btnPlay.isEnabled = play
        btnStop.isEnabled = pause
        btnStop.isEnabled = stop
    }
    
    @objc func updatePlayTime() {
        lblCurrTime.text = convertNSTimeInterval2String(audioPlayer.currentTime)
        pvProgressPlay.progress = Float(audioPlayer.currentTime/audioPlayer.duration)
    }
    
    @IBAction func btnPlayAudio(_ sender: UIButton) {
        audioPlayer.play()
        setPlayButtons(false, true, true)
        
        progressTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: timePlayerSelector, userInfo: nil, repeats: true)
    }
    
    @IBAction func btnPauseAudio(_ sender: UIButton) {
        audioPlayer.pause()
        
        setPlayButtons(true, false, true)
    }
    
    @IBAction func btnStopAudio(_ sender: UIButton) {
        audioPlayer.stop()
        audioPlayer.currentTime = 0
        
        lblCurrTime.text = convertNSTimeInterval2String(0)
        setPlayButtons(true, false, false)
        
        progressTimer.invalidate()
    }


    @IBAction func slChangeVolume(_ sender: UISlider) {
    
    }
  
}

 

이제 마지막으로 슬라이더를 제어했을 때, 볼륨 값을 할당해주는 코드와 오디오 재생이 모두 끝나면 자동으로 오디오를 재생하기 전 상태로 돌아가야 하기 때문에 AVAudioPlayerDelegate 가 가지고 있는 audioPlayerDidFinishPlaying 메서드를 정의해주면 오디오 재생 코드는 모두 끝이 난다.

import UIKit
import AVFoundation

class ViewController: UIViewController, AVAudioPlayerDelegate {
    
    var audioPlayer: AVAudioPlayer!
    
    var audioFile: URL!
    
    let MAX_VOLUME: Float = 10.0
    
    var progressTimer: Timer!
    
    let timePlayerSelector: Selector = #selector(ViewController.updatePlayTime)

    @IBOutlet var pvProgressPlay: UIProgressView!
    
    @IBOutlet var lblCurrTime: UILabel!
    @IBOutlet var lblEndTime: UILabel!
    
    @IBOutlet var btnPlay: UIButton!
    @IBOutlet var btnPause: UIButton!
    @IBOutlet var btnStop: UIButton!
    
    @IBOutlet var slVolume: UISlider!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        audioFile = Bundle.main.url(forResource: "Sicilian_Breeze", withExtension: "mp3")
        
        initPlay()
    }
    
    func initPlay() {
        do {
            try audioPlayer = AVAudioPlayer(contentsOf: audioFile)
        } catch let error as NSError {
            print("Error-initPlay : \(error)")
        }
        
        slVolume.maximumValue = MAX_VOLUME
        slVolume.value = 1.0
        pvProgressPlay.progress = 0
        
        audioPlayer.delegate = self
        audioPlayer.prepareToPlay()
        audioPlayer.volume = slVolume.value
        
        lblEndTime.text = convertNSTimeInterval2String(audioPlayer.duration)
        lblCurrTime.text = convertNSTimeInterval2String(0)
        
        setPlayButtons(true, false, false)
    }
    
    func convertNSTimeInterval2String(_ time: TimeInterval) -> String {
        let min = Int(time/60)
        
        //truncatingRemainder = 실수의 모듈러 계산
        let sec = Int(time.truncatingRemainder(dividingBy: 60))
        let strTime = String(format: "%02d:%02d", min, sec)
        
        return strTime
    }
    
    func setPlayButtons(_ play: Bool, _ pause: Bool, _ stop: Bool) {
        btnPlay.isEnabled = play
        btnStop.isEnabled = pause
        btnStop.isEnabled = stop
    }
    
    @objc func updatePlayTime() {
        lblCurrTime.text = convertNSTimeInterval2String(audioPlayer.currentTime)
        pvProgressPlay.progress = Float(audioPlayer.currentTime/audioPlayer.duration)
    }
    
    @IBAction func btnPlayAudio(_ sender: UIButton) {
        audioPlayer.play()
        setPlayButtons(false, true, true)
        
        progressTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: timePlayerSelector, userInfo: nil, repeats: true)
    }
    
    @IBAction func btnPauseAudio(_ sender: UIButton) {
        audioPlayer.pause()
        
        setPlayButtons(true, false, true)
    }
    
    @IBAction func btnStopAudio(_ sender: UIButton) {
        audioPlayer.stop()
        audioPlayer.currentTime = 0
        
        lblCurrTime.text = convertNSTimeInterval2String(0)
        setPlayButtons(true, false, false)
        
        progressTimer.invalidate()
    }


    @IBAction func slChangeVolume(_ sender: UISlider) {
        audioPlayer.volume = slVolume.value
    }
    
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        progressTimer.invalidate()
        setPlayButtons(true, false, false)
    }
}

2.  녹음

이제 녹음 기능을 위에서 만든 오디오 재생 앱에 추가해보자.

 

위에서 구성한 오디오 재생 스택 뷰 아래에 다음과 같이 녹음 스위치와 버튼, 레이블들을 추가한다.

 

마찬가지로 다음과 같이 스택 뷰로 묶어준 뒤, 해당 스택뷰를 오디오 재생 스택 뷰에 드래그하여 제약 조건을 추가해준다.

 

녹음 기능을 위한 스토리보드 구성은 이것으로 끝이다.

 

코드를 작성해보자.


전체 코드가 이미 오디오 재생 코드로 길어졌기 때문에 각 부분별로 코드를 잘라서 작성하겠다.

 

마찬가지로 새로 추가한 Item에 대한 Outlet 변수와 Action 함수를 추가하자.

@IBOutlet var btnRecord: UIButton!
@IBOutlet var lblRecordTime: UILabel!

@IBAction func swRecordMode(_ sender: UISwitch) {

}

@IBAction func btnRecord(_ sender: UIButton) {

}

 

다음으로 AVAudioRecorder와 녹음 모드를 확인할 Bool 타입을 선언해준다.

    var audioRecorder: AVAudioRecorder!
    var isRecordMode = false

 

이제 viewDidLoad 메서드에서 녹음 모드에 따라 기존에 있는 오디오 파일을 선택할 것인지, 녹음 파일을 새로 만들고 녹음 준비를 할 것인지 판단해야 하기 때문에 기존 viewDidLoad 메서드를 수정한다.

 

○기존

override func viewDidLoad() {
    super.viewDidLoad()

    audioFile = Bundle.main.url(forResource: "Sicilian_Breeze", withExtension: "mp3")

    initPlay()
}

 

○변경

override func viewDidLoad() {
    super.viewDidLoad()

    selectAudioFile()

    initPlay()
}

func selectAudioFile() {
    if !isRecordMode {
        audioFile = Bundle.main.url(forResource: "Sicilian_Breeze", withExtension: "mp3")
    } else {
        let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) [0]
        audioFile = documentDirectory.appendingPathComponent("recordFile.m4a")
    }
}

 

또한 initPlay() 메서드도 녹음 모드에서는 사용을 안하기 때문에 아래와 같이 initRecord 메서드를 하나 생성하여 분기해준다.

override func viewDidLoad() {
    super.viewDidLoad()

    selectAudioFile()

    if !isRecordMode {
        initPlay()
        btnRecord.isEnabled = false
        lblRecordTime.isEnabled = false
    } else {
        initRecord()
    }
}

func initRecord() {
    let recordSettings = [
        // 포맷은 kAudioFormatAppleLossless 로
        AVFormatIDKey : NSNumber(value: kAudioFormatAppleLossless as UInt32),
        // 음질은 최대
        AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue,
        // 비트율은 320000bps
        AVEncoderBitRateKey : 320000,
        // 오디오 채널은 2
        AVNumberOfChannelsKey : 2,
        // 샘플률 44100 Hz
        AVSampleRateKey: 44100.0
    ] as [String : Any]
}

 

이제 initRecord() 메서드에 audioRecord를 초기화하는 코드와 위임자를 self로 선언하는 코드를 추가하자.

 

물론 위임자도 상속 받아야 한다.

func initRecord() {
    let recordSettings = [
        // 포맷은 kAudioFormatAppleLossless 로
        AVFormatIDKey : NSNumber(value: kAudioFormatAppleLossless as UInt32),
        // 음질은 최대
        AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue,
        // 비트율은 320000bps
        AVEncoderBitRateKey : 320000,
        // 오디오 채널은 2
        AVNumberOfChannelsKey : 2,
        // 샘플률 44100 Hz
        AVSampleRateKey: 44100.0
    ] as [String : Any]

    do {
        audioRecorder = try AVAudioRecorder(url: audioFile, settings: recordSettings)
    } catch let error as NSError {
        print("Erorr-initRecord : \(error)")
    }

    audioRecorder.delegate = self
}
class ViewController: UIViewController, AVAudioPlayerDelegate, AVAudioRecorderDelegate

 

이제 initRecord 메서드의 마무리로 녹음 모드에서 currTime과 endTime, 볼륨을 설정하고, AVAudioSession의 카테고리와 엑션을 셋팅해준다.

func initRecord() {
        let recordSettings = [
            // 포맷은 kAudioFormatAppleLossless 로
            AVFormatIDKey : NSNumber(value: kAudioFormatAppleLossless as UInt32),
            // 음질은 최대
            AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue,
            // 비트율은 320000bps
            AVEncoderBitRateKey : 320000,
            // 오디오 채널은 2
            AVNumberOfChannelsKey : 2,
            // 샘플률 44100 Hz
            AVSampleRateKey: 44100.0
        ] as [String : Any]
        
        do {
            audioRecorder = try AVAudioRecorder(url: audioFile, settings: recordSettings)
        } catch let error as NSError {
            print("Erorr-initRecord : \(error)")
        }
        
        audioRecorder.delegate = self
        
        audioPlayer.volume = slVolume.value
        lblEndTime.text = convertNSTimeInterval2String(0)
        lblCurrTime.text = convertNSTimeInterval2String(0)
        setPlayButtons(false, false, false)
        
        let session = AVAudioSession.sharedInstance()
        
        do {
            try session.setCategory(.playback, mode: .default)
            try session.setActive(true)
        } catch let error as NSError {
            print("Error-setCategory : \(error)")
        }
        
        do {
            try session.setActive(true)
        } catch let error as NSError {
            print("Error-setActive : \(error)")
        }
        
    }

 

이제 녹음 스위치를 변경했을 때, 재생모드와 녹음모드가 스위치되게 코드를 작성한다.

 @IBAction func swRecordMode(_ sender: UISwitch) {
    if sender.isOn {
        audioPlayer.stop()
        audioPlayer.currentTime = 0
        lblRecordTime!.text = convertNSTimeInterval2String(0)

        isRecordMode = true
        btnRecord.isEnabled = true
        lblRecordTime.isEnabled = true
    } else {
        isRecordMode = false
        btnRecord.isEnabled = false
        lblRecordTime.isEnabled = false
        lblRecordTime.text = convertNSTimeInterval2String(0)
    }
    selectAudioFile()

    if !isRecordMode {
        initPlay()
    } else {
        initRecord()
    }
}

 

거의 다 왔다.

 

이제 녹음 버튼을 눌러 실제 녹음을 수행하도록 작성하면 끝이다.

 

녹음 시간을 실시간으로 변경하기 위한 selector를 우선 선언하고, 

let timeRecordSelector: Selector = #selector(ViewController.updateRecordTime)

 

아래와 같이 녹음 버튼을 눌렀을 때, 해당 타이머와 함께 녹음을 수행하도록 코드를 작성하자.

@IBAction func btnRecord(_ sender: UIButton) {
    if (sender as AnyObject).titleLabel?.text == "Record" {
        audioRecorder.record()
        (sender as AnyObject).setTitle("Stop", for: UIControl.State())
        progressTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: timeRecordSelector, userInfo: nil, repeats: true)
    } else {
        audioRecorder.stop()
        (sender as AnyObject).setTitle("Record", for: UIControl.State())
        progressTimer.invalidate()
        btnPlay.isEnabled = true
        initPlay()
    }
}

@objc func updateRecordTime() {
    lblRecordTime.text = convertNSTimeInterval2String(audioRecorder.currentTime)
}

 

이제 모두 끝이 났다!

 

처음 시작할 때 별 거 아니라고 했었지만... 오디오의 재생과 녹음을 동시에 하기 때문에 코드의 양은 상당했다...

 

전체 코드를 한번 정리하면 아래와 같다.

//
//  ViewController.swift
//  example_project12
//
//  Created by choonham on 2022/12/21.
//

import UIKit
import AVFoundation

class ViewController: UIViewController, AVAudioPlayerDelegate, AVAudioRecorderDelegate {
    
    var audioRecorder: AVAudioRecorder!
    var isRecordMode = false
    
    var audioPlayer: AVAudioPlayer!
    
    var audioFile: URL!
    
    let MAX_VOLUME: Float = 10.0
    
    var progressTimer: Timer!
    
    let timePlayerSelector: Selector = #selector(ViewController.updatePlayTime)
    let timeRecordSelector: Selector = #selector(ViewController.updateRecordTime)

    @IBOutlet var pvProgressPlay: UIProgressView!
    
    @IBOutlet var lblCurrTime: UILabel!
    @IBOutlet var lblEndTime: UILabel!
    
    @IBOutlet var btnPlay: UIButton!
    @IBOutlet var btnPause: UIButton!
    @IBOutlet var btnStop: UIButton!
    
    @IBOutlet var slVolume: UISlider!
    
    @IBOutlet var btnRecord: UIButton!
    @IBOutlet var lblRecordTime: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
           
        selectAudioFile()
        
        if !isRecordMode {
            initPlay()
            btnRecord.isEnabled = false
            lblRecordTime.isEnabled = false
        } else {
            initRecord()
        }
    }
    
    func selectAudioFile() {
        if !isRecordMode {
            audioFile = Bundle.main.url(forResource: "Sicilian_Breeze", withExtension: "mp3")
        } else {
            let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) [0]
            audioFile = documentDirectory.appendingPathComponent("recordFile.m4a")
        }
    }
    
    func initPlay() {
        do {
            try audioPlayer = AVAudioPlayer(contentsOf: audioFile)
        } catch let error as NSError {
            print("Error-initPlay : \(error)")
        }
        
        slVolume.maximumValue = MAX_VOLUME
        slVolume.value = 1.0
        pvProgressPlay.progress = 0
        
        audioPlayer.delegate = self
        audioPlayer.prepareToPlay()
        audioPlayer.volume = slVolume.value
        
        lblEndTime.text = convertNSTimeInterval2String(audioPlayer.duration)
        lblCurrTime.text = convertNSTimeInterval2String(0)
        
        setPlayButtons(true, false, false)
    }
    
    func initRecord() {
        let recordSettings = [
            // 포맷은 kAudioFormatAppleLossless 로
            AVFormatIDKey : NSNumber(value: kAudioFormatAppleLossless as UInt32),
            // 음질은 최대
            AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue,
            // 비트율은 320000bps
            AVEncoderBitRateKey : 320000,
            // 오디오 채널은 2
            AVNumberOfChannelsKey : 2,
            // 샘플률 44100 Hz
            AVSampleRateKey: 44100.0
        ] as [String : Any]
        
        do {
            audioRecorder = try AVAudioRecorder(url: audioFile, settings: recordSettings)
        } catch let error as NSError {
            print("Erorr-initRecord : \(error)")
        }
        
        audioRecorder.delegate = self
        
        audioPlayer.volume = slVolume.value
        lblEndTime.text = convertNSTimeInterval2String(0)
        lblCurrTime.text = convertNSTimeInterval2String(0)
        setPlayButtons(false, false, false)
        
        let session = AVAudioSession.sharedInstance()
        
        do {
            try session.setCategory(.playback, mode: .default)
            try session.setActive(true)
        } catch let error as NSError {
            print("Error-setCategory : \(error)")
        }
        
        do {
            try session.setActive(true)
        } catch let error as NSError {
            print("Error-setActive : \(error)")
        }
        
    }
    
    func convertNSTimeInterval2String(_ time: TimeInterval) -> String {
        let min = Int(time/60)
        
        //truncatingRemainder = 실수의 모듈러 계산
        let sec = Int(time.truncatingRemainder(dividingBy: 60))
        let strTime = String(format: "%02d:%02d", min, sec)
        
        return strTime
    }
    
    func setPlayButtons(_ play: Bool, _ pause: Bool, _ stop: Bool) {
        btnPlay.isEnabled = play
        btnPause.isEnabled = pause
        btnStop.isEnabled = stop
    }
    
    @objc func updatePlayTime() {
        lblCurrTime.text = convertNSTimeInterval2String(audioPlayer.currentTime)
        pvProgressPlay.progress = Float(audioPlayer.currentTime/audioPlayer.duration)
    }
    
    @IBAction func btnPlayAudio(_ sender: UIButton) {
        audioPlayer.play()
        setPlayButtons(false, true, true)
        
        progressTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: timePlayerSelector, userInfo: nil, repeats: true)
    }
    
    @IBAction func btnPauseAudio(_ sender: UIButton) {
        audioPlayer.pause()
        
        setPlayButtons(true, false, true)
    }
    
    @IBAction func btnStopAudio(_ sender: UIButton) {
        audioPlayer.stop()
        audioPlayer.currentTime = 0
        
        lblCurrTime.text = convertNSTimeInterval2String(0)
        setPlayButtons(true, false, false)
        
        progressTimer.invalidate()
    }


    @IBAction func slChangeVolume(_ sender: UISlider) {
        audioPlayer.volume = slVolume.value
    }
    
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        progressTimer.invalidate()
        setPlayButtons(true, false, false)
    }
    
    @IBAction func swRecordMode(_ sender: UISwitch) {
        if sender.isOn {
            audioPlayer.stop()
            audioPlayer.currentTime = 0
            lblRecordTime!.text = convertNSTimeInterval2String(0)
            
            isRecordMode = true
            btnRecord.isEnabled = true
            lblRecordTime.isEnabled = true
        } else {
            isRecordMode = false
            btnRecord.isEnabled = false
            lblRecordTime.isEnabled = false
            lblRecordTime.text = convertNSTimeInterval2String(0)
        }
        selectAudioFile()
        
        if !isRecordMode {
            initPlay()
        } else {
            initRecord()
        }
    }
    
    @IBAction func btnRecord(_ sender: UIButton) {
        if (sender as AnyObject).titleLabel?.text == "Record" {
            audioRecorder.record()
            (sender as AnyObject).setTitle("Stop", for: UIControl.State())
            progressTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: timeRecordSelector, userInfo: nil, repeats: true)
        } else {
            audioRecorder.stop()
            (sender as AnyObject).setTitle("Record", for: UIControl.State())
            progressTimer.invalidate()
            btnPlay.isEnabled = true
            initPlay()
        }
    }
    
    @objc func updateRecordTime() {
        lblRecordTime.text = convertNSTimeInterval2String(audioRecorder.currentTime)
    }
}

이제 실행해보면, 

아주 만족스럽게 실행이 잘 되는 것을 확인할 수 있다.

 

 

 

끝!

Comments