|
@@ -20,17 +20,21 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
|
|
|
// MARK: - 录制参数
|
|
|
public var asset:PHAsset?
|
|
|
-
|
|
|
+// var shouldPlayRecordIndex:Int = -1 // 当前应该播放的录音资源序号
|
|
|
+ var currentPlayRecordIndex:Int = -1 // 当前正在播放的录音资源序号
|
|
|
+ var isRecording = false // 是否正在录音
|
|
|
+ var isNormalPlaying = false { // 是否正在录音
|
|
|
+ didSet{
|
|
|
+ playBtn.isSelected = isNormalPlaying
|
|
|
+ }
|
|
|
+ }
|
|
|
// 视频素材
|
|
|
public var avasset:AVURLAsset?
|
|
|
public var recordList:[PQVoiceModel] = [PQVoiceModel]()
|
|
|
var assetPlayer:AVPlayer? // 原视频音频播放器
|
|
|
- lazy var recordPlayer:AVAudioPlayer = {// 录音音频播放器
|
|
|
- let player = AVAudioPlayer()
|
|
|
- player.volume = 1
|
|
|
- return player
|
|
|
-
|
|
|
- }()
|
|
|
+ var isCompletePlay = true
|
|
|
+ var hadPrepareToPlayRecord = false // 录音播放器准备
|
|
|
+ var recordPlayer:AVPlayer? // 录音音频播放器
|
|
|
var movie :GPUImageMovie? // 视频预览
|
|
|
var playView :GPUImageView? // 视频展示视图
|
|
|
var isDragingProgressSlder : Bool = false // 是否在拖动进度条
|
|
@@ -53,15 +57,17 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
manager.endRecordHandle = {[weak self] (isTimeout, model) in
|
|
|
if FileManager.default.fileExists(atPath: model?.wavFilePath ?? ""){
|
|
|
// 加入到语音数组里
|
|
|
+ model?.endTime = CMTimeGetSeconds(self?.assetPlayer?.currentItem?.currentTime() ?? CMTime.zero)
|
|
|
while let m = self?.recordList.last{
|
|
|
- if m.startTime < model!.startTime {
|
|
|
+ if model!.startTime < m.startTime {
|
|
|
self?.recordList.removeLast()
|
|
|
- }else if m.endTime < model!.startTime {
|
|
|
+ }else if m.endTime > model!.startTime {
|
|
|
m.endTime = model!.startTime
|
|
|
}else{
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
+ BFLog(1, message: "添加录音文件:\(model?.startTime) -- \(model?.endTime)")
|
|
|
self?.recordList.append(model!)
|
|
|
self?.drewRecordProgessLable()
|
|
|
}
|
|
@@ -75,6 +81,16 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
var touchStart:CGPoint = CGPoint(x: 0, y: 0)
|
|
|
var avplayerTimeObserver: NSKeyValueObservation?
|
|
|
|
|
|
+ lazy var progreddL : UILabel = {
|
|
|
+ let l = UILabel(frame: CGRect(x: 0, y: cDevice_iPhoneStatusBarHei, width: cScreenWidth, height: 14))
|
|
|
+ l.textAlignment = .center
|
|
|
+ l.font = UIFont.systemFont(ofSize: 10)
|
|
|
+ l.textColor = .white
|
|
|
+ l.shadowColor = .black
|
|
|
+ l.shadowOffset = CGSize(width: 1, height: 1)
|
|
|
+ return l
|
|
|
+ }()
|
|
|
+
|
|
|
lazy var playBtn:UIButton = {
|
|
|
let btn = UIButton(frame: view.bounds)
|
|
|
btn.addTarget(self, action: #selector(playVideo(btn:)), for: .touchUpInside)
|
|
@@ -126,7 +142,7 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
lazy var closeBtn:UIButton = {
|
|
|
let btn = UIButton(type: .custom)
|
|
|
btn.setImage(imageInRecordScreenKit(by: "xx"), for: .normal)
|
|
|
- btn.addTarget(self, action: #selector(close), for: .touchUpInside)
|
|
|
+ btn.addTarget(self, action: #selector(closePage), for: .touchUpInside)
|
|
|
return btn
|
|
|
}()
|
|
|
|
|
@@ -159,7 +175,7 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
avplayerTimeObserver?.invalidate()
|
|
|
recorderManager.stopRecord(isCancel: true)
|
|
|
assetPlayer?.pause()
|
|
|
- recordPlayer.pause()
|
|
|
+ recordPlayer?.pause()
|
|
|
|
|
|
}
|
|
|
|
|
@@ -181,7 +197,8 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
|
|
|
view.addSubview(playBtn)
|
|
|
view.addSubview(bottomeView)
|
|
|
- view.addSubview(toolV)
|
|
|
+ view.addSubview(progreddL)
|
|
|
+// view.addSubview(toolV)
|
|
|
bottomeView.addSubview(recordBtn)
|
|
|
bottomeView.addSubview(progessSilde)
|
|
|
bottomeView.addSubview(closeBtn)
|
|
@@ -227,9 +244,9 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
|
|
|
// MARK: - 按钮事件响应
|
|
|
|
|
|
- // 觸發拖曳手勢後 執行的動作
|
|
|
+ // 触发拖曳手势后,执行的动作
|
|
|
@objc func pan(recognizer: UIPanGestureRecognizer) {
|
|
|
- // 設置 UIView 新的位置
|
|
|
+ // 设置 UIView 新的位置
|
|
|
if !checkStatus(show: false) {
|
|
|
return
|
|
|
}
|
|
@@ -271,6 +288,8 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
@objc func startRecord(btn:UIButton){
|
|
|
btn.setImage(imageInRecordScreenKit(by: "mic2"), for: .normal)
|
|
|
BFLog(1, message: "start \(UIControl.Event.touchDown)")
|
|
|
+ pause()
|
|
|
+
|
|
|
let model = PQVoiceModel()
|
|
|
model.startTime = CMTimeGetSeconds(assetPlayer?.currentItem?.currentTime() ?? CMTime.zero)
|
|
|
recorderManager.voiceModel? = model
|
|
@@ -278,21 +297,26 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
movie?.startProcessing()
|
|
|
assetPlayer?.volume = 0
|
|
|
assetPlayer?.play()
|
|
|
+ isRecording = true
|
|
|
}
|
|
|
|
|
|
@objc func endRecord(btn:UIButton){
|
|
|
recordBtn.setImage(imageInRecordScreenKit(by: "mic1"), for: .normal)
|
|
|
// 存储录音
|
|
|
recorderManager.endRecord()
|
|
|
+ isRecording = false
|
|
|
+
|
|
|
pause()
|
|
|
}
|
|
|
|
|
|
func cancleRecord(){
|
|
|
recordBtn.setImage(imageInRecordScreenKit(by: "mic1"), for: .normal)
|
|
|
recorderManager.cancleRecord()
|
|
|
+ isRecording = false
|
|
|
+
|
|
|
pause()
|
|
|
}
|
|
|
- @objc func close(){
|
|
|
+ @objc func closePage(){
|
|
|
pause()
|
|
|
closeActionHandle?()
|
|
|
}
|
|
@@ -302,25 +326,19 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
}
|
|
|
|
|
|
@objc func playVideo(btn:UIButton){
|
|
|
- btn.isSelected = !btn.isSelected
|
|
|
- BFLog(1, message: "点击")
|
|
|
- if btn.isSelected{
|
|
|
- play()
|
|
|
-
|
|
|
- }else{
|
|
|
- pause()
|
|
|
- }
|
|
|
+ btn.isSelected ? pause() : play()
|
|
|
}
|
|
|
|
|
|
@objc public func sliderTouchBegan(sender _: UISlider) {
|
|
|
-// isDragingProgressSlder = true
|
|
|
-// pause()
|
|
|
+ isDragingProgressSlder = true
|
|
|
+ pause()
|
|
|
}
|
|
|
|
|
|
@objc public func sliderTouchEnded(sender: UISlider) {
|
|
|
-// changeProgress(progress: sender.value)
|
|
|
-// isDragingProgressSlder = false
|
|
|
-// play()
|
|
|
+ changeProgress(progress: sender.value)
|
|
|
+ isDragingProgressSlder = false
|
|
|
+ currentPlayRecordIndex = -1
|
|
|
+
|
|
|
}
|
|
|
|
|
|
// MARK: - 权限申请
|
|
@@ -369,35 +387,83 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
}
|
|
|
|
|
|
// MARK: - 音视频处理
|
|
|
- func playRecord(at duration:CMTime){
|
|
|
- if recordList.count > 0, let player = try? AVAudioPlayer(contentsOf: URL(fileURLWithPath: (recordList.first?.wavFilePath)!)) {
|
|
|
- self.recordPlayer = player
|
|
|
- self.recordPlayer.volume = 1
|
|
|
- self.recordPlayer.play()
|
|
|
- }else{
|
|
|
- self.recordPlayer.pause()
|
|
|
+ func playRecord(at currentT:CMTime){
|
|
|
+ let (shouldPlayRecordIndex, recordedAudio) = recordList.enumerated().first { model in
|
|
|
+ model.1.endTime > CMTimeGetSeconds(currentT)
|
|
|
+ } ?? (-1, nil)
|
|
|
+
|
|
|
+ guard let recordedAudio = recordedAudio else {
|
|
|
+ return
|
|
|
}
|
|
|
+
|
|
|
+ BFLog(1, message: "当前时间:\(CMTimeGetSeconds(currentT)), 找到的音频:\(recordedAudio.startTime), \(recordedAudio.endTime)")
|
|
|
+
|
|
|
+ // 创建播放器
|
|
|
+ if self.recordPlayer == nil || (self.recordPlayer?.currentItem?.asset as? AVURLAsset)?.url.lastPathComponent != (recordedAudio.wavFilePath as NSString).lastPathComponent {
|
|
|
+ self.recordPlayer?.pause()
|
|
|
+ self.recordPlayer = AVPlayer(url: URL(fileURLWithPath: recordedAudio.wavFilePath))
|
|
|
+ self.recordPlayer!.volume = 1
|
|
|
+ // self.recordPlayer?.prepareToPlay()
|
|
|
+ currentPlayRecordIndex = -1
|
|
|
+ hadPrepareToPlayRecord = false
|
|
|
+ BFLog(1, message: "录音播放器初始化")
|
|
|
+ }
|
|
|
+
|
|
|
+ synced(currentPlayRecordIndex) {
|
|
|
+ if CMTimeGetSeconds(currentT) >= recordedAudio.startTime && !hadPrepareToPlayRecord{
|
|
|
+ // 应当开始播放了
|
|
|
+ // 两个逻辑:如果在播,则跳过;如果暂停拖动到中间,则seek
|
|
|
+ if currentPlayRecordIndex == -1 {
|
|
|
+ let second = CMTimeGetSeconds(currentT) - recordedAudio.startTime
|
|
|
+ recordPlayer?.seek(to: CMTime(value: CMTimeValue(second), timescale: 100), toleranceBefore: CMTime(value: 1, timescale: 1000), toleranceAfter: CMTime(value: 1, timescale: 1000), completionHandler: {[weak recordPlayer] finished in
|
|
|
+ if finished {
|
|
|
+ recordPlayer?.play()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ currentPlayRecordIndex = shouldPlayRecordIndex
|
|
|
+ hadPrepareToPlayRecord = true
|
|
|
+ BFLog(1, message: "录音开始播放2 \(second), \(recordPlayer?.currentItem?.duration)")
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ BFLog(1, message: "应当播放:\(shouldPlayRecordIndex), 当前播放:\(currentPlayRecordIndex)")
|
|
|
+// if let recordedAudio = recordedAudio {
|
|
|
+//
|
|
|
+//
|
|
|
+// if shouldPlayRecordIndex != currentPlayRecordIndex {
|
|
|
+// // 设置新的播放资源
|
|
|
+//
|
|
|
+//// self.recordPlayer.delegate = self
|
|
|
+// self.recordPlayer.play()
|
|
|
+//
|
|
|
+// } else {
|
|
|
+// // 更新播放进度
|
|
|
+// let second = CMTimeGetSeconds(duration) - recordedAudio.startTime
|
|
|
+// self.recordPlayer.seek(to: CMTime(seconds: second, preferredTimescale: 25), toleranceBefore: CMTime(value: 1, timescale: 1000), toleranceAfter: CMTime(value: 1, timescale: 1000))
|
|
|
+// }
|
|
|
+// }
|
|
|
}
|
|
|
|
|
|
func play(){
|
|
|
- cShowHUB(superView: nil, msg: "开始播放")
|
|
|
- assetPlayer?.volume = 0.5
|
|
|
+ BFLog(1, message: "开始播放")
|
|
|
+ assetPlayer?.volume = 0.02
|
|
|
movie?.startProcessing()
|
|
|
-
|
|
|
+ isNormalPlaying = true
|
|
|
let second = assetPlayer?.currentItem?.currentTime()
|
|
|
- assetPlayer?.seek(to: second ?? CMTime.zero, toleranceBefore: .zero, toleranceAfter: .zero, completionHandler: {[weak self] finished in
|
|
|
+ assetPlayer?.seek(to: second ?? CMTime.zero, toleranceBefore: CMTime(value: 1, timescale: 1000), toleranceAfter: CMTime(value: 1, timescale: 1000), completionHandler: {[weak self] finished in
|
|
|
if finished {
|
|
|
self?.assetPlayer?.play()
|
|
|
}
|
|
|
})
|
|
|
- playRecord(at: CMTime.zero)
|
|
|
}
|
|
|
|
|
|
func pause(){
|
|
|
- cShowHUB(superView: nil, msg: "暂停播放")
|
|
|
+ BFLog(1, message: "暂停播放")
|
|
|
movie?.cancelProcessing()
|
|
|
assetPlayer?.pause()
|
|
|
- recordPlayer.pause()
|
|
|
+ recordPlayer?.pause()
|
|
|
+ isNormalPlaying = false
|
|
|
}
|
|
|
|
|
|
func fetchVideo(){
|
|
@@ -491,14 +557,17 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
assetPlayer?.replaceCurrentItem(with: item)
|
|
|
}else {
|
|
|
assetPlayer = AVPlayer(playerItem: item)
|
|
|
- avplayerTimeObserver = assetPlayer?.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 10), queue: DispatchQueue.global()) {[weak self] time in
|
|
|
+ avplayerTimeObserver = assetPlayer?.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 100), queue: DispatchQueue.global()) {[weak self] time in
|
|
|
// 进度监控
|
|
|
BFLog(1, message: "curr:\(CMTimeGetSeconds(time))")
|
|
|
if CMTimeGetSeconds(item.duration) > 0, !(self?.isDragingProgressSlder ?? false) {
|
|
|
DispatchQueue.main.async { [weak self] in
|
|
|
self?.progessSilde.value = Float(CMTimeGetSeconds(time) / CMTimeGetSeconds(item.duration))
|
|
|
+ self?.progreddL.text = String(format: "%.2f / %.2f", CMTimeGetSeconds(time), CMTimeGetSeconds(item.duration))
|
|
|
}
|
|
|
}
|
|
|
+ // 播放对应的录音音频
|
|
|
+ self?.playRecord(at: time)
|
|
|
} as? NSKeyValueObservation
|
|
|
}
|
|
|
|
|
@@ -507,6 +576,7 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
BFLog(message: "AVPlayerItemDidPlayToEndTime = \(notify)")
|
|
|
self?.assetPlayer?.seek(to: CMTime.zero)
|
|
|
self?.playBtn.isSelected = false
|
|
|
+ self?.currentPlayRecordIndex = -1
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -524,11 +594,11 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
//MARK: - 录音对应图像绘制
|
|
|
|
|
|
func changeProgress(progress:Float) {
|
|
|
- if let item = assetPlayer?.currentItem {
|
|
|
- let duration = CMTimeGetSeconds(item.duration)
|
|
|
- item.seek(to: CMTime(value: CMTimeValue(progress * Float(duration) * 100), timescale: 100)) { finished in
|
|
|
+ if let duration = assetPlayer?.currentItem?.duration {
|
|
|
+ assetPlayer!.seek(to: CMTime(value: CMTimeValue(progress * Float(CMTimeGetSeconds(duration)) * 100), timescale: 100), toleranceBefore: CMTime(value: 1, timescale: 1000), toleranceAfter: CMTime(value: 1, timescale: 1000)) {[weak self] finished in
|
|
|
if finished{
|
|
|
BFLog(1, message: "拖动成功")
|
|
|
+ self?.movie?.startProcessing()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -542,10 +612,18 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
extension BFRecordScreenController:GPUImageMovieDelegate {
|
|
|
public func didCompletePlayingMovie(){
|
|
|
BFLog(1, message: "播放结束")
|
|
|
-
|
|
|
+ currentPlayRecordIndex = -1
|
|
|
}
|
|
|
}
|
|
|
|
|
|
extension BFRecordScreenController:AVAudioRecorderDelegate {
|
|
|
-
|
|
|
+ public func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
|
|
|
+ BFLog(1, message: "录音结束")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension BFRecordScreenController : AVAudioPlayerDelegate {
|
|
|
+ public func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
|
|
|
+ BFLog(1, message: "录音播放结束")
|
|
|
+ }
|
|
|
}
|