Explorar o código

1.字幕优化

wenweiwei %!s(int64=3) %!d(string=hai) anos
pai
achega
4caaebf43f

+ 17 - 21
BFRecordScreenKit/Classes/BFVoiceRecordManager.swift

@@ -10,8 +10,7 @@ import BFMediaKit
 import Foundation
 
 class BFVoiceRecordManager: NSObject {
-    
-    let debugHeader:String = "debugHeaderManger"
+    let debugHeader: String = "debugHeaderManger"
     // 录音相关
     var audioRecorder: BFRecorderManager?
     // 录音结束回调
@@ -21,13 +20,13 @@ class BFVoiceRecordManager: NSObject {
     // 录音进度回调
     var recorderProgrossHandle: ((Float64) -> Void)?
     // 字幕的回调 参数1: 字幕数据 ,参数2 :对应的录音文件
-    var subtitleRecordHandle: ((String?, String?) -> Void)?
+    var subtitleRecordHandle: ((String?, String?, Bool) -> Void)?
 
     // 字幕服务 dubug信息
     var NeoNuiDebugHandle: ((String?) -> Void)?
     // 录音机 dubug信息
     var AudioQueueRecoderDebugHandle: ((String?) -> Void)?
- 
+
     // 音频文件模型
     var voiceModel: PQVoiceModel?
     // 停止是否为取消操作
@@ -43,11 +42,11 @@ class BFVoiceRecordManager: NSObject {
         audioRecorder = BFRecorderManager()
         audioRecorder?.delegate = self
     }
-    
-    deinit{
+
+    deinit {
         audioRecorder?.delegate = nil
     }
- 
+
     /// 开始录音
     func startRecord() {
         BFLog(2, message: "\(debugHeader)开始录音::: \(Date().timeIntervalSince1970)")
@@ -62,20 +61,19 @@ class BFVoiceRecordManager: NSObject {
             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
-
     }
 
     /// 停止录制
@@ -85,12 +83,10 @@ class BFVoiceRecordManager: NSObject {
 
         isStoping = true
         mIsCancel = isCancel
-        //停止录音机录音
+        // 停止录音机录音
         audioRecorder?.voiceRecorder.stop(true)
-        //停止字幕服务
+        // 停止字幕服务
         audioRecorder?.stopNui_dialog(false)
-       
-
     }
 }
 
@@ -130,14 +126,14 @@ extension BFVoiceRecordManager: BFRecorderManagerDelegate {
             // 删除临时 wav 文件
             deleteFile(outfile: wavFilePath)
         }
- 
+
         // 其它逻辑写在上面 保证最后关开关。
         isStoping = false
     }
 
     /// 删除文件
     /// - Parameter outfile: <#outfile description#>
-    public func deleteFile(outfile:String) {
+    public func deleteFile(outfile: String) {
         if FileManager.default.fileExists(atPath: outfile) {
             do {
                 try FileManager.default.removeItem(at: NSURL.fileURL(withPath: outfile))
@@ -146,12 +142,12 @@ extension BFVoiceRecordManager: BFRecorderManagerDelegate {
             }
         }
     }
-    
-    //字幕返回
-    public func eventCallback(_: BFRecorderManager, asrResult: String, audioFilePath: String) {
+
+    // 字幕返回
+    public func eventCallback(_: BFRecorderManager, asrResult: String, audioFilePath: String, isFinish: Bool) {
         // 最后输出的文件是降噪后的
         let noiseFilePath = audioFilePath.replacingOccurrences(of: ".pcm", with: "_noise.wav")
-        subtitleRecordHandle?(asrResult, noiseFilePath)
+        subtitleRecordHandle?(asrResult, noiseFilePath, isFinish)
     }
 
     public func neoNuiDebugHandle(_ msg: String) {

+ 54 - 51
BFRecordScreenKit/Classes/RecordScreen/Controller/BFRecordScreenController.swift

@@ -9,6 +9,7 @@
 import AVFAudio
 import AVFoundation
 import BFCommonKit
+import BFMaterialKit
 import BFMediaKit
 import BFNetRequestKit
 import BFUIKit
@@ -16,7 +17,6 @@ import Foundation
 import GPUImage
 import Photos
 import UIKit
-import BFMaterialKit
 
 struct WithDrawModel {
     var type: Int // 0:拖动; 1:预览播放暂停 2: 录音结束  3: 删除录音
@@ -463,10 +463,9 @@ public class BFRecordScreenController: BFBaseViewController {
 
         _ = checkStatus()
         // mdf by ak 切换外放和请求权限分开 否则会导致首次安装时不能执行切换操作
-        let options:AVAudioSession.CategoryOptions = [.defaultToSpeaker,.allowBluetooth]
+        let options: AVAudioSession.CategoryOptions = [.defaultToSpeaker, .allowBluetooth]
         try? AVAudioSession.sharedInstance().setCategory(.playAndRecord, options: options)
 
-        
         // add by ak 取 nsl token
         BFRecordScreenViewModel.getNlsAccessToken { [weak self] token, appkey in
             BFLog(message: "nls appkey is \(appkey), token is \(token)")
@@ -485,29 +484,30 @@ public class BFRecordScreenController: BFBaseViewController {
         }
 
         // 录音字幕回调
-        recorderManager?.subtitleRecordHandle = { [weak self] asrResult, audioFilePath in
+        recorderManager?.subtitleRecordHandle = { [weak self] asrResult, audioFilePath, _ in
             if asrResult == nil {
                 BFLog(message: "识别结果为空????不能生成字幕数据")
                 return
             }
-            let dicResult: [String: Any]? = jsonStringToDictionary(asrResult!)
-
-            let header = dicResult?["header"] as? [String: Any]
-            let payload = dicResult?["payload"] as? [String: Any]
-            BFLog(1, message: "识别结果:) \(payload?["result"] ?? "") ,taskId:\((header?["task_id"] as? String) ?? "taskId"), 识别时间:\(((payload?["begin_time"]) as? Int) ?? 0) ~ \(((payload?["time"]) as? Int) ?? 0) startTime:\(self?.recorderManager?.voiceModel?.startCMTime.seconds ?? 0.0)")
-
-            DispatchQueue.main.async {
+            DispatchQueue.global().async {
+                let dicResult: [String: Any]? = jsonStringToDictionary(asrResult!)
+                let header = dicResult?["header"] as? [String: Any]
+                let payload = dicResult?["payload"] as? [String: Any]
+                BFLog(1, message: "识别结果:) \(payload?["result"] ?? "") ,taskId:\((header?["task_id"] as? String) ?? "taskId"), 识别时间:\(((payload?["begin_time"]) as? Int) ?? 0) ~ \(((payload?["time"]) as? Int) ?? 0) startTime:\(self?.recorderManager?.voiceModel?.startCMTime.seconds ?? 0.0)")
                 // 1,保存字幕数据 begin_time是开始出现文字的时间,time 是结束文字出现的时间 单位都为毫秒,都是相对于录制音频数据整段时间。self.recorderManager.voiceModel?.startCMTime.seconds 为开始的录制的时间,开始和结束都要加上这个时差
 
                 let newSubtitle = PQEditSubTitleModel()
                 // 任务全局唯一ID,请记录该值,便于排查问题。 每次 startRecorder 和 stopRecoder 之间  task_Id都不会变化
                 let taskID = header?["task_id"] as? String
+                let finish = header?["task_id"] as? String
+
                 newSubtitle.taskID = taskID ?? ""
-                BFLog(1, message: "对应关系:字幕所属地址:\((audioFilePath ?? "b").replacingOccurrences(of: documensDirectory, with: "")), 开始录音输入:\((self?.recorderManager?.voiceModel?.wavFilePath ?? "aa").replacingOccurrences(of: documensDirectory, with: ""))")
+                BFLog(1, message: "对应关系:字幕所属地址:taskID:\(taskID ?? ""),\((audioFilePath ?? "b").replacingOccurrences(of: documensDirectory, with: "")), 开始录音输入:\((self?.recorderManager?.voiceModel?.wavFilePath ?? "aa").replacingOccurrences(of: documensDirectory, with: ""))")
                 // 这里加300ms 是因为返回结果为了切到字,时长提前一些时间,具体时间官方没说和原音频有关系。这里我们先延后300ms 单位:毫秒。
-                var tempVoice:PQVoiceModel?
-                var tempItem:BFRecordItemModel?
-                self?.itemModels.forEach({ item in
+                var tempVoice: PQVoiceModel?
+                var tempItem: BFRecordItemModel?
+                // 1:先通过titleTaskId来找是否存在录音
+                self?.itemModels.enumerated().forEach { index, item in
                     if tempVoice == nil {
                         tempVoice = item.voiceStickers.first { voice in
                             voice.titleTaskId == taskID
@@ -515,12 +515,21 @@ public class BFRecordScreenController: BFBaseViewController {
                         if tempVoice != nil {
                             tempItem = item
                         }
+                        BFLog(3, message: "字幕回调-找到录音文件:taskID=\(taskID ?? ""),audioFilePath=\(audioFilePath ?? ""),index=\(index)")
                     }
-                })
-                guard let currentVoice = tempVoice ?? self?.recorderManager?.voiceModel else {
+                }
+                // 2:如果通过titleTaskId没找到录音文件,则通过
+                if tempVoice == nil && (self?.isRecording ?? false) && self?.itemModels[self?.currItemModelIndex ?? 0].voiceStickers.last?.titleTaskId == nil {
+                    BFLog(3, message: "字幕回调-如果通过titleTaskId没找到录音文件:taskID=\(taskID ?? ""),audioFilePath=\(audioFilePath ?? "")")
+                    tempVoice = self?.itemModels[self?.currItemModelIndex ?? 0].voiceStickers.last
+                }
+                // 3:如果通过titleTaskId跟audioFilePath都没找到录音文件,则默认为recorderManager?.voiceModel
+                guard let currentVoice = (tempVoice ?? self?.recorderManager?.voiceModel) ?? self?.itemModels[self?.currItemModelIndex ?? 0].voiceStickers.last else {
+                    BFLog(3, message: "字幕回调-最终没找到录音文件:taskID=\(taskID ?? ""),audioFilePath=\(audioFilePath ?? "")")
                     return
                 }
                 guard let currentItem = tempItem ?? self?.itemModels[self?.currItemModelIndex ?? 0] else {
+                    BFLog(3, message: "字幕回调-最终没找到录音文件:taskID=\(taskID ?? ""),audioFilePath=\(audioFilePath ?? "")")
                     return
                 }
                 if currentVoice.titleTaskId == nil {
@@ -529,8 +538,7 @@ public class BFRecordScreenController: BFBaseViewController {
                 newSubtitle.timelineIn = currentVoice.startCMTime + CMTime(seconds: Float64((((payload?["begin_time"]) as? Int) ?? 0) + 300) / 1000.0, preferredTimescale: 1000)
                 newSubtitle.timelineOut = currentVoice.startCMTime + CMTime(seconds: Float64(((payload?["time"]) as? Int) ?? 0) / 1000.0, preferredTimescale: 1000)
                 newSubtitle.audioFilePath = currentVoice.wavFilePath
-                BFLog(1, message: "字幕按时回来")
-                BFLog(3, message: "字幕返回begin:\(((payload?["begin_time"]) as? Int) ?? 0),timelineIn:\(newSubtitle.timelineIn.seconds), end:\(((payload?["time"]) as? Int) ?? 0),timelineOut:\(newSubtitle.timelineOut.seconds)")
+                BFLog(3, message: "字幕回调-字幕返回begin:\(((payload?["begin_time"]) as? Int) ?? 0),timelineIn:\(newSubtitle.timelineIn.seconds), end:\(((payload?["time"]) as? Int) ?? 0),timelineOut:\(newSubtitle.timelineOut.seconds)")
                 if (newSubtitle.timelineIn - currentVoice.startCMTime).seconds > 0.1 {
                     BFLog(1, message: "卡在录音尾巴上了1")
                     newSubtitle.timelineIn = newSubtitle.timelineIn - CMTime(seconds: 0.1, preferredTimescale: 1000)
@@ -564,7 +572,7 @@ public class BFRecordScreenController: BFBaseViewController {
                 var deletedVoices = [(PQVoiceModel, Int)]()
                 // 要删除的字幕
                 var deletedTitlesTemp = [PQEditSubTitleModel]()
-                
+
                 // 查找要删除的音频和字幕数据
                 for (i, m) in sself.itemModels[sself.currItemModelIndex].voiceStickers.enumerated() {
                     let originRange = CMTimeRange(start: m.startCMTime, end: CMTime(seconds: m.endCMTime.seconds - 0.02, preferredTimescale: 1000))
@@ -580,8 +588,7 @@ public class BFRecordScreenController: BFBaseViewController {
                         m.wavFilePath == tempM.wavFilePath
                     }
                 }
-                
-                
+
                 BFLog(1, message: "添加录音文件:\(model.startCMTime.seconds) -- \(model.endCMTime.seconds)")
                 sself.itemModels[sself.currItemModelIndex].voiceStickers.append(model)
                 // 录制结束回调
@@ -694,7 +701,7 @@ public class BFRecordScreenController: BFBaseViewController {
         subtitleSettingView.subtitleSettingCallBack = { [weak self] subtitileModel in
 
             self?.setSubtitleStyle(settingModel: subtitileModel.setting)
-            //mdf by ak 这里是设置字幕开关回调
+            // mdf by ak 这里是设置字幕开关回调
             if self?.subTitleBtnClickHandle != nil {
                 self?.subTitleBtnClickHandle!(subtitileModel.setting.subtitleIsShow)
             }
@@ -715,8 +722,6 @@ public class BFRecordScreenController: BFBaseViewController {
             }
 
             self?.setSubtitleStyle(settingModel: (self?.subtitleSettingView.subtitle.setting)!)
-
-         
         }
 
         layoutsubview()
@@ -754,13 +759,13 @@ public class BFRecordScreenController: BFBaseViewController {
             }
             return
         }
-        
+
         if showSubtitleIndex > -1, showSubtitleIndex < itemModels[currItemModelIndex].titleStickers.count {
             let currShowSubtitle = itemModels[currItemModelIndex].titleStickers[showSubtitleIndex]
-    
-            if CMTimeCompare(currShowSubtitle.timelineIn, time) <= 0, CMTimeCompare(currShowSubtitle.timelineOut, time) > 0{
+
+            if CMTimeCompare(currShowSubtitle.timelineIn, time) <= 0, CMTimeCompare(currShowSubtitle.timelineOut, time) > 0 {
                 // 已存在字幕
-                if subtitleLabel.text != currShowSubtitle.text{
+                if subtitleLabel.text != currShowSubtitle.text {
                     subtitleLabel.text = currShowSubtitle.text
                     setSubtitleStyle(settingModel: subtitleSettingView.subtitle.setting)
                 }
@@ -768,8 +773,7 @@ public class BFRecordScreenController: BFBaseViewController {
             }
             showSubtitleIndex = -1
         }
-        
-        
+
         var findShowSubtitle: PQEditSubTitleModel?
         for (index, subtitle) in itemModels[currItemModelIndex].titleStickers.enumerated() {
             if CMTimeCompare(subtitle.timelineIn, time) <= 0, CMTimeCompare(subtitle.timelineOut, time) > 0, subtitle.audioFilePath.count > 0 { //  audioFilePath.count 这个条件是确保这个字幕有对应录音
@@ -779,7 +783,7 @@ public class BFRecordScreenController: BFBaseViewController {
                 break
             }
         }
-        
+
         if findShowSubtitle != nil, subtitleLabel.text != findShowSubtitle!.text {
             subtitleLabel.text = findShowSubtitle!.text
             setSubtitleStyle(settingModel: subtitleSettingView.subtitle.setting)
@@ -787,7 +791,7 @@ public class BFRecordScreenController: BFBaseViewController {
         } else {
             if subtitleLabel.text?.count ?? 0 > 0 {
                 subtitleLabel.text = ""
-                subtitleLabel.backgroundColor = UIColor.clear                
+                subtitleLabel.backgroundColor = UIColor.clear
             }
         }
     }
@@ -816,7 +820,7 @@ public class BFRecordScreenController: BFBaseViewController {
             } else { // 上
                 subtitleLabel.frame = CGRect(x: leftPoint, y: cScreenHeigth * 0.12, width: cScreenWidth - 37 * 2, height: height)
             }
-            //打开的时候主动调用一次显示字幕
+            // 打开的时候主动调用一次显示字幕
             updateSubtitle(time: currentAssetProgress)
         } else {
             subtitleLabel.text = ""
@@ -957,7 +961,7 @@ public class BFRecordScreenController: BFBaseViewController {
     @objc func subTitleClick() {
         BFLog(message: "subTitle Click ")
         subtitleSettingView.isHidden = !subtitleSettingView.isHidden
-  
+
         updateSubtitle(time: currentAssetProgress)
     }
 
@@ -982,7 +986,7 @@ public class BFRecordScreenController: BFBaseViewController {
             }
             return su
         }
-  
+
         BFLog(message: "itemModels[currItemModelIndex].titleStickers  删除后:\(itemModels[currItemModelIndex].titleStickers.count)")
 
         // 清空字幕UI
@@ -1013,21 +1017,20 @@ public class BFRecordScreenController: BFBaseViewController {
                         // 注:开始时间减去duration or 等一前一段录音的结束时间
                         item.startCMTime = item.startCMTime - currDuration
                         item.endCMTime = item.endCMTime - currDuration
-                        
-                        let titlsList = itemModels[currItemModelIndex].titleStickers.filter({ tm in
+
+                        let titlsList = itemModels[currItemModelIndex].titleStickers.filter { tm in
                             tm.taskID == item.titleTaskId
-                        })
-                        
+                        }
+
                         for titleM in titlsList {
                             titleM.timelineIn = titleM.timelineIn - currDuration
                             titleM.timelineOut = titleM.timelineOut - currDuration
-                            
                         }
                     }
                 }
                 /// 重绘录音进度视图
                 resetAllIndirectionView()
-                
+
                 // 判断是否无录音了
                 if itemModels[currItemModelIndex].materialDuraion == 0 {
                     playBtn.isSelected = true
@@ -1199,12 +1202,12 @@ public class BFRecordScreenController: BFBaseViewController {
                     let model = itemModels[currItemModelIndex].voiceStickers[modelIndex]
                     itemModels[currItemModelIndex].voiceStickers.remove(at: modelIndex)
                     indirectionView?.deleteItem(index: modelIndex)
-                    
+
                     // 删除对应字幕
                     itemModels[currItemModelIndex].titleStickers.removeAll { m in
                         m.audioFilePath == model.wavFilePath
                     }
-                    
+
                     // 恢复被覆盖的音频
                     var tuples = action.deletedVoices
                     if tuples != nil, tuples!.count > 0 {
@@ -1273,8 +1276,8 @@ public class BFRecordScreenController: BFBaseViewController {
             let dur = itemModels[currItemModelIndex].materialDuraion
             if dur > 0 {
                 if itemModels[currItemModelIndex].mediaType == .IMAGE {
-                    changeProgress(isBack: true, progress:  Float(jumpTime))
-                }else {
+                    changeProgress(isBack: true, progress: Float(jumpTime))
+                } else {
                     changeProgress(changCMTime: CMTime(seconds: jumpTime, preferredTimescale: 1000))
                 }
             } else {
@@ -1354,7 +1357,7 @@ public class BFRecordScreenController: BFBaseViewController {
         isEndPlay = (progress == 1)
         recorderManager?.voiceModel = nil
         // 视频拖动到最后隐藏录制按钮
-        if itemModels[currItemModelIndex].mediaType == .VIDEO && currentAssetProgress.seconds >= itemModels[currItemModelIndex].materialDuraion {
+        if itemModels[currItemModelIndex].mediaType == .VIDEO, currentAssetProgress.seconds >= itemModels[currItemModelIndex].materialDuraion {
             recordBtn.isHidden = true
         }
     }
@@ -1374,7 +1377,7 @@ public class BFRecordScreenController: BFBaseViewController {
                 if fabs(elems[0].1.endCMTime.seconds - currentAssetProgress.seconds) < 0.5 {
                     BFLog(1, message: "吸附在录音结尾, \(elems[0].1.endCMTime.seconds)")
                     //                changeWithDrawBtnLayout(false)
-                    changeProgress(changCMTime:elems[0].1.endCMTime)
+                    changeProgress(changCMTime: elems[0].1.endCMTime)
                     progressThumV.progress = elems[0].1.endCMTime.seconds
 
 //                    deleteRecordBtn.isHidden = true
@@ -1646,7 +1649,7 @@ public class BFRecordScreenController: BFBaseViewController {
     func play() {
         BFLog(1, message: "开始播放 \(currentAssetProgress.seconds)")
         recorderManager?.voiceModel = nil
-        
+
         itemModels[currItemModelIndex].titleStickers.sort { m1, m2 in
             m1.timelineIn < m2.timelineIn
         }
@@ -1893,7 +1896,7 @@ public class BFRecordScreenController: BFBaseViewController {
 
     // 通过缩略图进度条控制播放进度
     // progress : 图片且isback为true时,表示是时长;  其他情况: 0 - 1,百分比
-    func changeProgress(isBack: Bool = false, progress: Float = -1, changCMTime:CMTime = .zero) {
+    func changeProgress(isBack: Bool = false, progress: Float = -1, changCMTime: CMTime = .zero) {
         var newProgress = progress
         if progress.isNaN || progress.isInfinite {
             newProgress = 0
@@ -1903,7 +1906,7 @@ public class BFRecordScreenController: BFBaseViewController {
             if duration > 0 {
                 if progress == -1 {
                     currentAssetProgress = changCMTime
-                }else{
+                } else {
                     currentAssetProgress = CMTime(seconds: Double(newProgress) * duration, preferredTimescale: 1000)
                 }
                 DispatchQueue.main.async { [weak self] in