AVAudioRecorder與AVAudioPlayer相似,它們都屬於AVFoundation的類。AVAudioRecorder的功能相似於一個錄音器,使用AVAudioRecorder錄製音頻十分簡單,當程序控制AVAudioRecorder對象建立完成以後,能夠調用AVAudioRecorder的以下方法進行錄製。session
一、prepareToRecord:準備開始錄製。調用record方法時,若是音頻尚未準備好,程序會隱式先執行該方法。app
二、record:開始或恢復錄製。調用該方法是,若是音頻尚未準備好,程序會隱式執行prepareToRecord方法。less
三、recordAtTime:在指定時間點開始或恢復錄製。async
四、record(atTime time: TimeInterval, forDuration duration: TimeInterval) -> Bool 在指定時間點開始或恢復錄製,並指定錄製的持續時間。ide
五、pause:暫停。stop:中止url
六、prepareToPlay:準備開始播放。若是play方法沒有準備好時,會隱式先執行該方法。spa
一、建立AVAudioRecorder對象。在建立AVAudioRecorder對象以前,先準備一個Dictionary對象,該對象中封裝了音頻的相關設置信息。code
//建立字典,用於保存錄制屬性 let recordSettings:[String:Any] = [ //設置錄製音頻的格式 AVFormatIDKey:kAudioFormatAppleLossless, AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue, AVEncoderBitRateKey: 32000, //設置錄製音頻的每一個樣點的通道數 AVNumberOfChannelsKey: 2, //設置錄製音頻的採樣率 AVSampleRateKey: 44100.0 ]
二、若是須要監聽錄製完成、錄製被中斷的事件,則應該爲AVAudioRecorder對象設置delegate對象,delegate對象須要實現AVAudioRecorderDelegate協議。orm
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) { print("錄製完成") stopBtn.isEnabled = false playBtn.isEnabled = true recordBtn.setTitle("錄製", for: .normal) //彈窗選擇 let alert = UIAlertController(title: "錄製", message: "錄製完成", preferredStyle:.alert) alert.addAction(UIAlertAction(title: "保存", style: .default, handler: {[unowned self] _ in self.recorder = nil })) alert.addAction(UIAlertAction(title: "刪除", style:.default, handler: { [unowned self] _ in self.recorder.deleteRecording() })) self.present(alert, animated: true, completion: nil) } func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) { print("\(#function)") if let e = error { print("\(e.localizedDescription)") } }
三、調用AVAudioRecorder對象的record方法錄製視頻。視頻
import UIKit import AVFoundation import AVKit class NAPublishViewController : UIViewController { var recorder : AVAudioRecorder! var player : AVAudioPlayer! var meterTimer : Timer! var soundFileUrl : URL! lazy var recordBtn : UIButton = { let recordBtn = UIButton() recordBtn.setTitle("錄音", for: .normal) recordBtn.setTitleColor(.black, for: .normal) recordBtn.addTarget(self, action: #selector(recordAction(sender:)), for: .touchUpInside) return recordBtn }() lazy var stopBtn : UIButton = { let stopBtn = UIButton() stopBtn.setTitle("中止", for: .normal) stopBtn.setTitleColor(.black, for: .normal) stopBtn.addTarget(self, action:#selector(stopBtnAction(sender:)) , for: .touchUpInside) return stopBtn }() lazy var playBtn : UIButton = { let playBtn = UIButton() playBtn.setTitle("播放", for: .normal) playBtn.setTitleColor(.black, for: .normal) playBtn.addTarget(self , action: #selector(playBtnAction(sender:)), for: .touchUpInside) return playBtn }() lazy var statusLabel : UILabel = { let statusLabel = UILabel() statusLabel.text = "00:00" statusLabel.textColor = .black return statusLabel }() override func viewDidLoad() { super.viewDidLoad() setSubViewsConstraints() stopBtn.isEnabled = false playBtn.isEnabled = false setSessionPlayback() } @objc func playBtnAction(sender:UIButton) -> Void { var url: URL? if self.recorder != nil { url = self.recorder.url } else { url = self.soundFileUrl! } print("playing \(String(describing: url))") do { self.player = try AVAudioPlayer(contentsOf: url!) stopBtn.isEnabled = true player.delegate = self player.prepareToPlay() player.volume = 1.0 player.play() } catch { self.player = nil print(error.localizedDescription) } } @objc func stopBtnAction(sender:UIButton) -> Void { recorder?.stop() player?.stop() meterTimer.invalidate() recordBtn.setTitle("錄音", for: .normal) let session = AVAudioSession.sharedInstance() do { try session.setActive(false) playBtn.isEnabled = true stopBtn.isEnabled = false recordBtn.isEnabled = true } catch { print(error.localizedDescription) } } @objc func recordAction(sender:UIButton) -> Void { if player != nil && player.isPlaying { print("stopping") player.stop() } if recorder == nil { recordBtn.setTitle("暫停", for: .normal) playBtn.isEnabled = false stopBtn.isEnabled = true recordWithPermission(true) return } if recorder != nil && recorder.isRecording { recorder.pause() recordBtn.setTitle("繼續", for: .normal) } else { recordBtn.setTitle("暫停", for: .normal) playBtn.isEnabled = false stopBtn.isEnabled = true recordWithPermission(false) } } func recordWithPermission(_ setup: Bool) { AVAudioSession.sharedInstance().requestRecordPermission { (granted) in if granted { DispatchQueue.main.async { self.setSessionPlayAndRecord() if setup { self.setupRecorder() } self.recorder.record() self.meterTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.updateAudioMeter(_:)), userInfo: nil, repeats: true) } } else { print("Permission to record not granted") } } if AVAudioSession.sharedInstance().recordPermission == .denied { print("permission denied") } } func setupRecorder() { let format = DateFormatter() format.dateFormat="yyyy-MM-dd-HH-mm-ss" let currentFileName = "recording-\(format.string(from: Date())).m4a" print(currentFileName) //獲取沙盒文件目錄 let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] //拼接路徑 self.soundFileUrl = documentsDirectory.appendingPathComponent(currentFileName) print("writing to soundfile url: '\(soundFileUrl!)'") if FileManager.default.fileExists(atPath: soundFileUrl.absoluteString) { print("soundfile \(soundFileUrl.absoluteString) 存在") } //建立字典,用於保存錄制屬性 let recordSettings:[String:Any] = [ //設置錄製音頻的格式 AVFormatIDKey:kAudioFormatAppleLossless, AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue, AVEncoderBitRateKey: 32000, //設置錄製音頻的每一個樣點的通道數 AVNumberOfChannelsKey: 2, //設置錄製音頻的採樣率 AVSampleRateKey: 44100.0 ] do { recorder = try AVAudioRecorder(url: soundFileUrl, settings: recordSettings) recorder.delegate = self recorder.isMeteringEnabled = true recorder.prepareToRecord() } catch { recorder = nil print(error.localizedDescription) } } func setSessionPlayAndRecord() { //獲取當前應用的音頻會話 let session = AVAudioSession.sharedInstance() do { //設置音頻類別,PlayAndRecord - 這說明當前音頻會話既可播放,又可錄製 try session.setCategory(AVAudioSession.Category.playAndRecord, options: AVAudioSession.CategoryOptions.defaultToSpeaker) } catch { print(error.localizedDescription) } do { try session.setActive(true) } catch { print(error.localizedDescription) } } func setSessionPlayback() { //獲取當前應用的音頻會話 let session = AVAudioSession.sharedInstance() do { //設置音頻類別 try session.setCategory(AVAudioSession.Category.playback, options: AVAudioSession.CategoryOptions.defaultToSpeaker) } catch { print("不能設置session category") print(error.localizedDescription) } do { //激活當前應用的音頻會話 try session.setActive(true, options: AVAudioSession.SetActiveOptions.notifyOthersOnDeactivation) } catch { print("不能設置session active") print(error.localizedDescription) } } @objc func updateAudioMeter(_ timer: Timer) { if let recorder = self.recorder { if recorder.isRecording { let min = Int(recorder.currentTime / 60) let sec = Int(recorder.currentTime.truncatingRemainder(dividingBy: 60)) let s = String(format: "%02d:%02d", min, sec) statusLabel.text = s recorder.updateMeters() } } } func setSubViewsConstraints() -> Void { view.addSubview(recordBtn) recordBtn.snp.makeConstraints { (make) in make.left.width.height.equalTo(50) make.top.equalTo(100) } view.addSubview(stopBtn) stopBtn.snp.makeConstraints { (make) in make.centerX.equalToSuperview() make.width.height.equalTo(50) make.top.equalTo(100) } view.addSubview(playBtn) playBtn.snp.makeConstraints { (make) in make.right.equalTo(-50) make.width.height.equalTo(50) make.top.equalTo(100) } view.addSubview(statusLabel) statusLabel.snp.makeConstraints { (make) in make.centerX.equalToSuperview() make.width.height.equalTo(50) make.top.equalTo(stopBtn.snp_bottom).offset(30) } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() recorder = nil player = nil } } extension NAPublishViewController : AVAudioRecorderDelegate { func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) { print("錄製完成") stopBtn.isEnabled = false playBtn.isEnabled = true recordBtn.setTitle("錄製", for: .normal) //彈窗選擇 let alert = UIAlertController(title: "錄製", message: "錄製完成", preferredStyle:.alert) alert.addAction(UIAlertAction(title: "保存", style: .default, handler: {[unowned self] _ in self.recorder = nil })) alert.addAction(UIAlertAction(title: "刪除", style:.default, handler: { [unowned self] _ in self.recorder.deleteRecording() })) self.present(alert, animated: true, completion: nil) } func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) { print("\(#function)") if let e = error { print("\(e.localizedDescription)") } } } extension NAPublishViewController : AVAudioPlayerDelegate { func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { recordBtn.isEnabled = true stopBtn.isEnabled = false } func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) { print("\(#function)") if let e = error { print("\(e.localizedDescription)") } } }