|
@@ -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
|