iOS音频与视频的开发(二)- 使用AVAudioRecorder进行录制音频

1、使用AVAudioRecorder录制视频

  AVAudioRecorder与AVAudioPlayer类似,它们都属于AVFoundation的类。AVAudioRecorder的功能类似于一个录音器,使用AVAudioRecorder录制音频十分简单,当程序控制AVAudioRecorder对象创建完成之后,可以调用AVAudioRecorder的如下方法进行录制。

  1、prepareToRecord:准备开始录制。调用record方法时,如果音频还没有准备好,程序会隐式先执行该方法。

  2、record:开始或恢复录制。调用该方法是,如果音频还没有准备好,程序会隐式执行prepareToRecord方法。

  3、recordAtTime:在指定时间点开始或恢复录制。

  4、record(atTime time: TimeInterval, forDuration duration: TimeInterval) -> Bool 在指定时间点开始或恢复录制,并指定录制的持续时间。

  5、pause:暂停。stop:停止

  6、prepareToPlay:准备开始播放。如果play方法没有准备好时,会隐式先执行该方法。

  使用AVAudioRecorder录制视频的步骤如下:

  1、创建AVAudioRecorder对象。在创建AVAudioRecorder对象之前,先准备一个Dictionary对象,该对象中封装了音频的相关设置信息。

//创建字典,用于保存录制属性
        let recordSettings:[String:Any] = [
            //设置录制音频的格式
            AVFormatIDKey:kAudioFormatAppleLossless,
            AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue,
            AVEncoderBitRateKey: 32000,
             //设置录制音频的每个样点的通道数
            AVNumberOfChannelsKey: 2,
            //设置录制音频的采样率
            AVSampleRateKey: 44100.0
        ]

  2、如果需要监听录制完成、录制被中断的事件,则应该为AVAudioRecorder对象设置delegate对象,delegate对象需要实现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)")
        }
    }

  3、调用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)")
        }
        
    }
}
使用AVAudioRecorder进行录制视频

   运行效果图: 

 

posted @ 2019-05-25 15:27  Mr·Xu  阅读(1665)  评论(0编辑  收藏  举报