| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 | ////  BFVoiceRecordManager.swift//  BFRecordScreenKit////  Created by 胡志强 on 2021/11/24.//import BFCommonKitimport BFMediaKitimport Foundationclass BFVoiceRecordManager: NSObject {    let debugHeader: String = "debugHeaderManger"    // 录音相关    var audioRecorder: BFRecorderManager?    // 录音结束回调    var endRecordHandle: ((PQVoiceModel?, Error?) -> Void)?    // 录音取消回调    var cancelRecordHandle: ((PQVoiceModel?) -> Void)?    // 录音进度回调    var recorderProgrossHandle: ((Float64) -> Void)?    // 字幕的回调 参数1: 字幕数据 ,参数2 :对应的录音文件    var subtitleRecordHandle: ((_ eventCode: Int32,_ recordId:String?, String?, String?, Bool) -> Void)?        // 当前录制Id    public var currentRecordId: String?    // 字幕服务 dubug信息    var NeoNuiDebugHandle: ((String?,Bool) -> Void)?    // 录音机 dubug信息     var AudioQueueRecoderDebugHandle: ((String?,Bool) -> Void)?     // 音频文件模型    var voiceModel: PQVoiceModel?    // 停止是否为取消操作    var mIsCancel: Bool = false    // 是否正在停止中,从调用停止方法,到真正停止结束大约要300ms 左右。在这个期间内如果调用在调用了 start 开始时间被重置, 就会触发< 1s的逻辑。    var isStoping: Bool = false    /// 初始化方法    /// - Parameters:    ///   - token: NLS token    ///   - appid: NLS appid    override public init() {        super.init()        audioRecorder = BFRecorderManager()        audioRecorder?.delegate = self    }    deinit {        audioRecorder?.delegate = nil    }    /// 开始录音    func startRecord() {        BFLog(2, message: "\(debugHeader)开始录音::: \(Date().timeIntervalSince1970)")        if isStoping {            AudioQueueRecoderDebugHandle?("正在停止中,这次开始无效.",false)            BFLog(2, message: "\(debugHeader)正在停止中,这次开始无效.")            return        }        var recorderFilePath = exportAudiosDirectory        if !directoryIsExists(dicPath: recorderFilePath) {            BFLog(message: "\(debugHeader)文件夹不存在 \(recorderFilePath)")            createDirectory(path: recorderFilePath)        }        recorderFilePath.append("recorder_\(Date().timeIntervalSince1970).pcm")        let noiseFilePath = recorderFilePath.replacingOccurrences(of: ".pcm", with: "_noise.wav")        voiceModel?.wavFilePath = noiseFilePath        BFLog(1, message: "\(debugHeader)开始录音::: \(recorderFilePath)")        audioRecorder?.startRecord(recorderFilePath)    }    func cancelTitleService() {        audioRecorder?.stopNui_dialog(true)        isStoping = false    }    /// 停止录制    /// - Parameter isCancel: 是否为取消 ,取消操作会把录制的文件删除和字幕删除    func stopRecord(isCancel: Bool) {        BFLog(2, message: "\(debugHeader)结束录音::: \(Date().timeIntervalSince1970)")        isStoping = true        mIsCancel = isCancel        // 停止录音机录音        audioRecorder?.voiceRecorder.stop(true)        // 停止字幕服务        audioRecorder?.stopNui_dialog(false)    }}// MARK: - 录音机回调extension BFVoiceRecordManager: BFRecorderManagerDelegate {    public func recorderProgress(_: BFRecorderManager, recoderTime: Double) {//        BFLog(message: "录音机进度:\(recoderTime)")        recorderProgrossHandle?(recoderTime)    }    public func recorderDidStop(_ outfile: String) {        if mIsCancel {            // 删除录制的原文件            deleteFile(outfile: outfile)            cancelRecordHandle?(nil)        } else {            var beginRecordTime1 = Date()            // 1转wav            let wavFilePath = outfile.replacingOccurrences(of: ".pcm", with: ".wav")            BFPcmToWaveTool().pcmToWav(inFileName: outfile, outFileName: wavFilePath)            BFLog(message: "\(debugHeader)转 WAV用时\(Date().timeIntervalSince(beginRecordTime1))")            // 删除录制的原文件            deleteFile(outfile: outfile)            // 2处理降噪            beginRecordTime1 = Date()            let noiseFilePath = wavFilePath.replacingOccurrences(of: ".wav", with: "_noise.wav")//            BFLog(1, message: "\(debugHeader)降噪后地址:\(noiseFilePath) 原地址:\(wavFilePath)")            NXNoiseReduction().denoise(wavFilePath, outFile: noiseFilePath)            if let model = voiceModel {                model.wavFilePath = noiseFilePath                endRecordHandle?(model, nil)                BFLog(message: "\(debugHeader)降噪用时\(Date().timeIntervalSince(beginRecordTime1))")            }            // 删除临时 wav 文件            deleteFile(outfile: wavFilePath)        }        // 其它逻辑写在上面 保证最后关开关。        isStoping = false    }    /// 删除文件    /// - Parameter outfile: <#outfile description#>    public func deleteFile(outfile: String) {        if FileManager.default.fileExists(atPath: outfile) {            do {                try FileManager.default.removeItem(at: NSURL.fileURL(withPath: outfile))            } catch {                BFLog(message: "删除文件出错 == \(error) \(outfile)")            }        }    }    // 字幕返回    public func eventCallback(_ manager: BFRecorderManager, eventCode: Int32, asrResult: String, audioFilePath: String, isFinish: Bool) {        // 最后输出的文件是降噪后的        let noiseFilePath = audioFilePath.replacingOccurrences(of: ".pcm", with: "_noise.wav")        let tmprecordId = currentRecordId        if eventCode == 26 {            currentRecordId = nil        }        if eventCode == 0 {            currentRecordId = getUniqueId(desc: "currentRecordId")            if voiceModel?.recordId?.count == nil {                voiceModel?.recordId = currentRecordId            }        }        subtitleRecordHandle?(eventCode, tmprecordId, asrResult, noiseFilePath, isFinish)    }    public func neoNuiDebugHandle(_ msg: String,isShow:Bool) {        BFLog(2, message: "neoNuiDebugHandle :\(msg)")        NeoNuiDebugHandle?(msg,isShow)    }    public func audioQueueRecoderDebugHandle(_ msg: String, isShow: Bool) {        BFLog(2, message: "audioQueueRecoderDebugHandle :\(msg)")        AudioQueueRecoderDebugHandle?(msg,isShow)    }  }
 |