BFVoiceRecordManager.swift 5.9 KB

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