BFVoiceRecordManager.swift 5.5 KB

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