음악을 재생하고 제어하는 클래스인 AVAudioPlayer를 활용하는 간단한 예제를 만들어 보았다.
원하는 레이블을 스택 뷰로 묶는 방법이다. 가로로 배치된 두개의 레이블을 묶어서, 가로로 스택 뷰가 생성되는 것을 볼 수 있다.
가로로 묶인 스택 뷰를 다시 세로로 스텍 뷰로 묶고, 상단의 여백을 40으로 설정하였다.
import UIKit
import AVFoundation
class ViewController: UIViewController, AVAudioPlayerDelegate, AVAudioRecorderDelegate{
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)
var audioRecorder : AVAudioRecorder!
var isRecordMode = false
@IBOutlet var pvProgressPlay: UIProgressView!
@IBOutlet var lblCurrentTime: 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()
// Do any additional setup after loading the view.
selectAudioFile()
if !isRecordMode{ //재생 모드일 때
initPlay()
btnRecord.isEnabled = false
lblRecordTime.isEnabled = false
} else { // 녹음 모드일 때
initRecord()
}
}
//재생 모드 초기화
func initPlay(){
do {
audioPlayer = try AVAudioPlayer(contentsOf: audioFile)
} catch let error as NSError {
print("Error-iniPlay : \(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)
lblCurrentTime.text = convertNSTimeInterval2String(0)
setPlayButtons(true, pause: false, stop: false)
}
//재생 모드의 버튼들을 활성화, 비활성화 하는 함수
func setPlayButtons(_ play:Bool, pause:Bool, stop:Bool) {
btnPlay.isEnabled = play
btnPause.isEnabled = pause
btnStop.isEnabled = stop
}
// 00:00 형태의 문자열로 변환
func convertNSTimeInterval2String(_ time:TimeInterval) -> String {
let min = Int(time/60)
let sec = Int(time.truncatingRemainder(dividingBy: 60))
let strTime = String(format: "%02d:%02d", min, sec)
return strTime
}
// 재생이 종료되었을 때 호출하는 함수
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool){
progressTimer.invalidate()
setPlayButtons(true, pause:false, stop: false)
}
// 재생 모드와 녹음 모드에 따라 다른 파일을 선택하는 함수
func selectAudioFile(){
if !isRecordMode {
audioFile = Bundle.main.url(forResource: "걱정말아요 그대", withExtension: "mp3")
} else {
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
audioFile = documentDirectory.appendingPathComponent("recordFile.m4a")
}
}
// 녹음 모드 초기화
func initRecord(){
let recordSettings = [
AVFormatIDKey : NSNumber(value: kAudioFormatAppleLossless as UInt32),
AVEncoderAudioQualityKey : AVAudioQuality.max.rawValue,
AVEncoderBitRateKey : 320000,
AVNumberOfChannelsKey : 2,
AVSampleRateKey : 44100.0] as [String : Any]
do {
audioRecorder = try AVAudioRecorder(url: audioFile, settings: recordSettings)
} catch let error as NSError {
print("Error-initRecord : \(error)")
}
audioRecorder.delegate = self
slVolume.value = 1.0
audioPlayer.volume = slVolume.value
lblEndTime.text = convertNSTimeInterval2String(0)
lblCurrentTime.text = convertNSTimeInterval2String(0)
setPlayButtons(false, pause: false, stop: false)
let session = AVAudioSession.sharedInstance()
do {
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default)
try AVAudioSession.sharedInstance().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)")
}
}
//0.1초마다 호출되어 재생 시간 표시
@objc func updatePlayTime() {
lblCurrentTime.text = convertNSTimeInterval2String(audioPlayer.currentTime)
pvProgressPlay.progress = Float(audioPlayer.currentTime/audioPlayer.duration)
}
//0.1초마다 호출되어 녹음 시간 표시
@objc func updateRecordTime() {
lblRecordTime.text = convertNSTimeInterval2String(audioRecorder.currentTime)
}
//재생 버튼 클릭 시 음악 재생
@IBAction func btnPlayAudio(_ sender: UIButton) {
audioPlayer.play()
setPlayButtons(false, pause: true, stop: true)
progressTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: timePlayerSelector, userInfo: nil, repeats: true)
}
//일시 정지 버튼 클릭 시 음악 일시정지
@IBAction func btnPauseAudio(_ sender: UIButton) {
audioPlayer.pause()
setPlayButtons(true, pause: false, stop: true)
}
//정지 버튼 클릭 시 음악 재생 종료
@IBAction func btnStopAudio(_ sender: UIButton) {
audioPlayer.stop()
audioPlayer.currentTime = 0
setPlayButtons(true, pause: false, stop: false)
lblCurrentTime.text = convertNSTimeInterval2String(0)
progressTimer.invalidate()
}
//볼륨 슬라이더 값을 실제 볼륨 값에 대입
@IBAction func slChangeVolume(_ sender: UISlider) {
audioPlayer.volume = slVolume.value
}
//스위치를 통한 녹음, 재생 모드 변환
@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()
progressTimer.invalidate()
(sender as AnyObject).setTitle("Record", for: UIControl.State())
btnPlay.isEnabled = true
initPlay()
}
}
}
소리가 나와야 하는데...녹음이 안된다ㅠㅠ