美文网首页
聊天界面 AVFoundation(录音、播放)的封装

聊天界面 AVFoundation(录音、播放)的封装

作者: 朱云龙 | 来源:发表于2017-06-13 09:46 被阅读0次

    项目地址:https://github.com/zhuyunlongYL/YLBaseChat

    typealias PlayerDidFinishPlayingBlock = () -> Void
    
    class VoiceManager:NSObject{
        
        // 单例
        static let shared = VoiceManager()
        private override init(){}
        
        var duration:Int = 0 // 录音时间
        var recorder_file_path:String? = nil // 录音路径
        
        fileprivate var recorder: AVAudioRecorder? = nil
        fileprivate var player: AVAudioPlayer? = nil
        
        fileprivate var timer:Timer? = nil
        fileprivate var pathTag:Int = 0
        
        fileprivate var completeBlock:PlayerDidFinishPlayingBlock?
        
        deinit {
            timer?.invalidate()
            timer = nil
        }
        
        // 是否使用扬声器
        func isProximity(_ isProximity:Bool) {
            do {
                if isProximity {
                    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
                }else {
                    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord)
                }
            } catch let err {
                print("设置扬声器失败:\(err.localizedDescription)")
            }
        }
        
        //开始录音
        func beginRecord() {
            duration = 0
            
            let session = AVAudioSession.sharedInstance()
            //设置session类型
            do {
                try session.setCategory(AVAudioSessionCategoryPlayAndRecord)
            } catch let err{
                print("设置类型失败:\(err.localizedDescription)")
            }
            //设置session动作
            do {
                try session.setActive(true)
            } catch let err {
                print("初始化动作失败:\(err.localizedDescription)")
            }
            
            //录音设置,注意,后面需要转换成NSNumber,如果不转换,你会发现,无法录制音频文件,我猜测是因为底层还是用OC写的原因
            let recordSetting: [String: Any] = [AVSampleRateKey: NSNumber(value: 16000),//采样率
                AVFormatIDKey: NSNumber(value: kAudioFormatLinearPCM),//音频格式
                AVLinearPCMBitDepthKey: NSNumber(value: 16),//采样位数
                AVNumberOfChannelsKey: NSNumber(value: 1),//通道数
                AVEncoderAudioQualityKey: NSNumber(value: AVAudioQuality.min.rawValue)//录音质量
            ];
            //开始录音
            do {
                recorder_file_path = getFilePath()
                if let file_path = recorder_file_path {
                    let url = URL(fileURLWithPath: file_path)
                    recorder = try AVAudioRecorder(url: url, settings: recordSetting)
                    recorder?.isMeteringEnabled = true
                    recorder!.prepareToRecord()
                    recorder!.record()
                    
                    timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: (#selector(VoiceManager.recordingTime)), userInfo: nil, repeats: true)
                    print("开始录音")
                }
            } catch let err {
                print("录音失败:\(err.localizedDescription)")
            }
        }
        
        //结束录音
        func stopRecord() {
            timer?.invalidate()
            timer = nil
            if let recorder = recorder {
                if recorder.isRecording {
                    if let file_path = recorder_file_path {
                        print("正在录音,马上结束它,文件保存到了:\(file_path)")
                    }
                }else {
                    print("没有录音,但是依然结束它")
                }
                recorder.stop()
                self.recorder = nil
            }else {
                print("没有初始化")
            }
        }
        
        // 取消录音
        func cancelRecord() {
            stopRecord()
            if let file_path = recorder_file_path {
                try? FileManager.default.removeItem(at: URL(fileURLWithPath: file_path))
                print("删除录音:\(file_path)")
            }
            
        }
        
        // 录音获取音量
        func getRecordVolume() -> Float {
            var level:Float = 0.0
            if let recorder = recorder {
                if recorder.isRecording {
                    recorder.updateMeters()
                    //获取音量的平均值  [recorder averagePowerForChannel:0];
                    //音量的最大值  [recorder peakPowerForChannel:0];
                    let minDecibels:Float = -80.0
                    let decibels:Float = recorder.peakPower(forChannel: 0)
                    if decibels < minDecibels {
                        level = 0.0
                    }
                    else if decibels >= 0.0 {
                        level = 1.0
                    }else {
                        let root:Float = 2.0
                        let minAmp:Float = powf(10.0, 0.05 * minDecibels)
                        let inverseAmpRange:Float = 1.0 / (1.0 - minAmp)
                        let amp = powf(10.0, 0.05 * decibels)
                        let adjAmp = (amp - minAmp) * inverseAmpRange
                        
                        level = powf(adjAmp, 1.0 / root)
                    }
                    
                }
            }
            print("录音音量大小0~1--\(level)")
            return level
        }
        
        //播放
        func play(_ path: String?,_ block: PlayerDidFinishPlayingBlock?) {
            
            UIDevice.current.isProximityMonitoringEnabled = true
            
            // 默认扬声器播放
            isProximity(true)
            
            do {
                completeBlock = block
                
                if let path = path {
                    player = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
                    player?.delegate = self
                    player?.prepareToPlay()
                    player!.play()
                }
            } catch let err {
                UIDevice.current.isProximityMonitoringEnabled = false
                print("播放失败:\(err.localizedDescription)")
            }
        }
        
        //结束播放
        func stopPlay() {
            UIDevice.current.isProximityMonitoringEnabled = false
            if let player = player {
                if player.isPlaying {
                    print("停止播放")
                }else {
                    print("没有播放")
                }
                player.stop()
                completeBlock = nil
                self.player?.delegate = nil
                self.player = nil
            }else {
                print("没有初始化")
            }
        }
        
        
        // 录音记时
        @objc fileprivate func recordingTime() {
            
            duration += 1
            print("录音时间:\(duration)")
        }
        
        // 获取路径
        fileprivate func getFilePath() -> String! {
            
            pathTag += 1
            
            if pathTag > 1000 {
                pathTag = 0
            }
            
            return NSHomeDirectory() + "/Library/Caches/\(pathTag)-\(Date().timeIntervalSince1970).wav"
        }
        
    }
    
    
    //// MARK: - AVAudioPlayerDelegate
    extension VoiceManager:AVAudioPlayerDelegate {
        
        func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
            UIDevice.current.isProximityMonitoringEnabled = false
            if let completeBlock = completeBlock {
                completeBlock()
            }
            
        }
        
    }
    
    // 添加监听
    // 监听用户耳朵靠近手机或者远离手机
            NotificationCenter.default.addObserver(self, selector: #selector(BaseChatVC.proximitySensorChanged), name: NSNotification.Name.UIDeviceProximityStateDidChange, object: nil)
    
    // 监听用户耳朵靠近手机或者远离手机
        @objc fileprivate func proximitySensorChanged() {
        
            if UIDevice.current.proximityState == true {
                VoiceManager.shared.isProximity(false)
            }else {
                VoiceManager.shared.isProximity(true)
            }
            
        }

    相关文章

      网友评论

          本文标题:聊天界面 AVFoundation(录音、播放)的封装

          本文链接:https://www.haomeiwen.com/subject/ywxdqxtx.html