BFVoiceRecordManager.swift 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. //
  2. // BFVoiceRecordManager.swift
  3. // BFRecordScreenKit
  4. //
  5. // Created by 胡志强 on 2021/11/24.
  6. //
  7. import BFCommonKit
  8. import BFMediaKit
  9. import Foundation
  10. class BFVoiceRecordManager: NSObject {
  11. let debugHeader: String = "debugHeaderManger"
  12. // 录音相关
  13. var audioRecorder: BFRecorderManager?
  14. // 录音结束回调
  15. var endRecordHandle: ((PQVoiceModel?, Error?) -> Void)?
  16. // 录音取消回调
  17. var cancelRecordHandle: ((PQVoiceModel?) -> Void)?
  18. // 录音进度回调
  19. var recorderProgrossHandle: ((Float64) -> Void)?
  20. // 字幕的回调 参数1: 字幕数据 ,参数2 :对应的录音文件
  21. var subtitleRecordHandle: ((_ eventCode: Int32,_ recordId:String?, String?, String?, Bool) -> Void)?
  22. // 当前录制Id
  23. public var currentRecordId: String?
  24. // 字幕服务 dubug信息
  25. var NeoNuiDebugHandle: ((String?,Bool) -> Void)?
  26. // 录音机 dubug信息
  27. var AudioQueueRecoderDebugHandle: ((String?,Bool) -> Void)?
  28. // 音频文件模型
  29. var voiceModel: PQVoiceModel?
  30. // 停止是否为取消操作
  31. var mIsCancel: Bool = false
  32. // 是否正在停止中,从调用停止方法,到真正停止结束大约要300ms 左右。在这个期间内如果调用在调用了 start 开始时间被重置, 就会触发< 1s的逻辑。
  33. var isStoping: Bool = false
  34. /// 初始化方法
  35. /// - Parameters:
  36. /// - token: NLS token
  37. /// - appid: NLS appid
  38. override public init() {
  39. super.init()
  40. audioRecorder = BFRecorderManager()
  41. audioRecorder?.delegate = self
  42. }
  43. deinit {
  44. audioRecorder?.delegate = nil
  45. }
  46. /// 开始录音
  47. func startRecord() {
  48. BFLog(2, message: "\(debugHeader)开始录音::: \(Date().timeIntervalSince1970)")
  49. if isStoping {
  50. AudioQueueRecoderDebugHandle?("正在停止中,这次开始无效.",false)
  51. BFLog(2, message: "\(debugHeader)正在停止中,这次开始无效.")
  52. return
  53. }
  54. var recorderFilePath = exportAudiosDirectory
  55. if !directoryIsExists(dicPath: recorderFilePath) {
  56. BFLog(message: "\(debugHeader)文件夹不存在 \(recorderFilePath)")
  57. createDirectory(path: recorderFilePath)
  58. }
  59. recorderFilePath.append("recorder_\(Date().timeIntervalSince1970).pcm")
  60. let noiseFilePath = recorderFilePath.replacingOccurrences(of: ".pcm", with: "_noise.wav")
  61. voiceModel?.wavFilePath = noiseFilePath
  62. BFLog(1, message: "\(debugHeader)开始录音::: \(recorderFilePath)")
  63. audioRecorder?.startRecord(recorderFilePath)
  64. }
  65. func cancelTitleService() {
  66. audioRecorder?.stopNui_dialog(true)
  67. isStoping = false
  68. }
  69. /// 停止录制
  70. /// - Parameter isCancel: 是否为取消 ,取消操作会把录制的文件删除和字幕删除
  71. func stopRecord(isCancel: Bool) {
  72. BFLog(2, message: "\(debugHeader)结束录音::: \(Date().timeIntervalSince1970)")
  73. isStoping = true
  74. mIsCancel = isCancel
  75. // 停止录音机录音
  76. audioRecorder?.voiceRecorder.stop(true)
  77. // 停止字幕服务
  78. audioRecorder?.stopNui_dialog(false)
  79. }
  80. }
  81. // MARK: - 录音机回调
  82. extension BFVoiceRecordManager: BFRecorderManagerDelegate {
  83. public func recorderProgress(_: BFRecorderManager, recoderTime: Double) {
  84. // BFLog(message: "录音机进度:\(recoderTime)")
  85. recorderProgrossHandle?(recoderTime)
  86. }
  87. public func recorderDidStop(_ outfile: String) {
  88. if mIsCancel {
  89. // 删除录制的原文件
  90. deleteFile(outfile: outfile)
  91. cancelRecordHandle?(nil)
  92. } else {
  93. var beginRecordTime1 = Date()
  94. // 1转wav
  95. let wavFilePath = outfile.replacingOccurrences(of: ".pcm", with: ".wav")
  96. BFPcmToWaveTool().pcmToWav(inFileName: outfile, outFileName: wavFilePath)
  97. BFLog(message: "\(debugHeader)转 WAV用时\(Date().timeIntervalSince(beginRecordTime1))")
  98. // 删除录制的原文件
  99. deleteFile(outfile: outfile)
  100. // 2处理降噪
  101. beginRecordTime1 = Date()
  102. let noiseFilePath = wavFilePath.replacingOccurrences(of: ".wav", with: "_noise.wav")
  103. // BFLog(1, message: "\(debugHeader)降噪后地址:\(noiseFilePath) 原地址:\(wavFilePath)")
  104. NXNoiseReduction().denoise(wavFilePath, outFile: noiseFilePath)
  105. if let model = voiceModel {
  106. model.wavFilePath = noiseFilePath
  107. endRecordHandle?(model, nil)
  108. BFLog(message: "\(debugHeader)降噪用时\(Date().timeIntervalSince(beginRecordTime1))")
  109. }
  110. // 删除临时 wav 文件
  111. deleteFile(outfile: wavFilePath)
  112. }
  113. // 其它逻辑写在上面 保证最后关开关。
  114. isStoping = false
  115. }
  116. /// 删除文件
  117. /// - Parameter outfile: <#outfile description#>
  118. public func deleteFile(outfile: String) {
  119. if FileManager.default.fileExists(atPath: outfile) {
  120. do {
  121. try FileManager.default.removeItem(at: NSURL.fileURL(withPath: outfile))
  122. } catch {
  123. BFLog(message: "删除文件出错 == \(error) \(outfile)")
  124. }
  125. }
  126. }
  127. // 字幕返回
  128. public func eventCallback(_ manager: BFRecorderManager, eventCode: Int32, asrResult: String, audioFilePath: String, isFinish: Bool) {
  129. // 最后输出的文件是降噪后的
  130. let noiseFilePath = audioFilePath.replacingOccurrences(of: ".pcm", with: "_noise.wav")
  131. let tmprecordId = currentRecordId
  132. if eventCode == 26 {
  133. currentRecordId = nil
  134. }
  135. if eventCode == 0 {
  136. currentRecordId = getUniqueId(desc: "currentRecordId")
  137. if voiceModel?.recordId?.count == nil {
  138. voiceModel?.recordId = currentRecordId
  139. }
  140. }
  141. subtitleRecordHandle?(eventCode, tmprecordId, asrResult, noiseFilePath, isFinish)
  142. }
  143. public func neoNuiDebugHandle(_ msg: String,isShow:Bool) {
  144. BFLog(2, message: "neoNuiDebugHandle :\(msg)")
  145. NeoNuiDebugHandle?(msg,isShow)
  146. }
  147. public func audioQueueRecoderDebugHandle(_ msg: String, isShow: Bool) {
  148. BFLog(2, message: "audioQueueRecoderDebugHandle :\(msg)")
  149. AudioQueueRecoderDebugHandle?(msg,isShow)
  150. }
  151. }