O2RecordVoiceManager.swift 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. //
  2. // O2RecordVoiceManager.swift
  3. // O2Platform
  4. //
  5. // Created by FancyLou on 2020/6/17.
  6. // Copyright © 2020 zoneland. All rights reserved.
  7. //
  8. import UIKit
  9. import AVFoundation
  10. fileprivate func < <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
  11. switch (lhs, rhs) {
  12. case let (l?, r?):
  13. return l < r
  14. case (nil, _?):
  15. return true
  16. default:
  17. return false
  18. }
  19. }
  20. fileprivate func > <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
  21. switch (lhs, rhs) {
  22. case let (l?, r?):
  23. return l > r
  24. default:
  25. return rhs < lhs
  26. }
  27. }
  28. typealias O2RecordCompletionCallBack = () -> Void
  29. protocol O2RecordVoiceDelegate {
  30. func beyondLimit(_ time: TimeInterval)
  31. }
  32. class O2RecordVoiceManager: NSObject {
  33. private let maxRecordTime = 60.0
  34. private var startRecordCompleted: O2RecordCompletionCallBack?
  35. private var recorder: AVAudioRecorder?
  36. private var recordProgress: Float?
  37. private var theTimer: Timer?
  38. private var currentTimeInterval: TimeInterval?
  39. var recordPath: String?
  40. var recordDuration: String?
  41. var stopRecordCompletion: O2RecordCompletionCallBack?
  42. var cancelledDeleteCompletion: O2RecordCompletionCallBack?
  43. var delegate: O2RecordVoiceDelegate?
  44. override init() {
  45. super.init()
  46. }
  47. deinit {
  48. stopRecord()
  49. recordPath = nil
  50. }
  51. @objc private func updateMeters() {
  52. if recorder == nil {
  53. return
  54. }
  55. currentTimeInterval = recorder?.currentTime
  56. recordProgress = recorder?.peakPower(forChannel: 0)
  57. if currentTimeInterval > maxRecordTime {
  58. stopRecord()
  59. delegate?.beyondLimit(currentTimeInterval!)
  60. if stopRecordCompletion != nil {
  61. DispatchQueue.main.async(execute: stopRecordCompletion!)
  62. recorder?.updateMeters()
  63. }
  64. }
  65. }
  66. private func getVoiceDuration(_ recordPath:String) {
  67. do {
  68. let player:AVAudioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: recordPath))
  69. player.play()
  70. let duration = player.duration
  71. self.recordDuration = "\(Int(duration))"
  72. } catch let error as NSError {
  73. print("get AVAudioPlayer is fail \(error)")
  74. self.recordDuration = "0"
  75. }
  76. }
  77. private func resetTimer() {
  78. if theTimer == nil {
  79. return
  80. } else {
  81. theTimer!.invalidate()
  82. theTimer = nil
  83. }
  84. }
  85. private func cancelRecording() {
  86. if recorder == nil {
  87. return
  88. }
  89. if recorder?.isRecording != false {
  90. recorder?.stop()
  91. }
  92. recorder = nil
  93. }
  94. private func stopRecord() {
  95. cancelRecording()
  96. resetTimer()
  97. }
  98. func startRecordingWithPath(_ path:String, startRecordCompleted:@escaping O2RecordCompletionCallBack) {
  99. print("Action - startRecordingWithPath:")
  100. self.startRecordCompleted = startRecordCompleted
  101. self.recordPath = path
  102. let audioSession:AVAudioSession = AVAudioSession.sharedInstance()
  103. do {
  104. try audioSession.setCategory(AVAudioSession.Category.playAndRecord, mode: .default, options: .defaultToSpeaker)
  105. } catch let error as NSError {
  106. print("could not set session category")
  107. print(error.localizedDescription)
  108. }
  109. do {
  110. try audioSession.setActive(true)
  111. } catch let error as NSError {
  112. print("could not set session active")
  113. print(error.localizedDescription)
  114. }
  115. // let recordSettings:[String : AnyObject] = [
  116. // AVFormatIDKey: NSNumber(value: kAudioFormatAppleIMA4 as UInt32),
  117. // AVNumberOfChannelsKey: 1 as AnyObject,
  118. // AVSampleRateKey : 16000.0 as AnyObject
  119. // ]
  120. let recordSetting: [String: Any] = [
  121. AVSampleRateKey: NSNumber(value: 16000),//采样率
  122. AVEncoderBitRateKey:NSNumber(value: 16000),
  123. AVFormatIDKey: NSNumber(value: kAudioFormatLinearPCM),//音频格式
  124. AVNumberOfChannelsKey: NSNumber(value: 1),//通道数
  125. AVLinearPCMBitDepthKey:NSNumber(value: 16),
  126. AVEncoderAudioQualityKey: NSNumber(value: AVAudioQuality.high.rawValue)//录音质量
  127. ]
  128. do {
  129. self.recorder = try AVAudioRecorder(url: URL(fileURLWithPath: self.recordPath!), settings: recordSetting)
  130. self.recorder!.delegate = self
  131. self.recorder!.prepareToRecord()
  132. self.recorder?.record(forDuration: 160.0)
  133. } catch let error as NSError {
  134. recorder = nil
  135. print(error.localizedDescription)
  136. }
  137. if ((self.recorder?.record()) != false) {
  138. self.resetTimer()
  139. self.theTimer = Timer.scheduledTimer(timeInterval: 0.05, target: self, selector: #selector(updateMeters), userInfo: nil, repeats: true)
  140. } else {
  141. print("fail record")
  142. }
  143. if self.startRecordCompleted != nil {
  144. DispatchQueue.main.async(execute: self.startRecordCompleted!)
  145. }
  146. }
  147. func finishRecordingCompletion() {
  148. stopRecord()
  149. getVoiceDuration(recordPath!)
  150. if stopRecordCompletion != nil {
  151. DispatchQueue.main.async(execute: stopRecordCompletion!)
  152. }
  153. }
  154. func cancelledDeleteWithCompletion() {
  155. stopRecord()
  156. if recordPath != nil {
  157. let fileManager:FileManager = FileManager.default
  158. if fileManager.fileExists(atPath: recordPath!) == true {
  159. do {
  160. try fileManager.removeItem(atPath: recordPath!)
  161. } catch let error as NSError {
  162. print("can no to remove the voice file \(error.localizedDescription)")
  163. }
  164. } else {
  165. if cancelledDeleteCompletion != nil {
  166. DispatchQueue.main.async(execute: cancelledDeleteCompletion!)
  167. }
  168. }
  169. }
  170. }
  171. // test player
  172. func playVoice(_ recordPath:String) {
  173. do {
  174. print("\(recordPath)")
  175. let player:AVAudioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: recordPath))
  176. player.volume = 1
  177. player.delegate = self
  178. player.numberOfLoops = -1
  179. player.prepareToPlay()
  180. player.play()
  181. } catch let error as NSError {
  182. print("get AVAudioPlayer is fail \(error)")
  183. }
  184. }
  185. //caf文件转mp3
  186. func convertCafToMp3(cafPath: String, mp3Path: String){
  187. ConvertMp3().audioPCMtoMP3(cafPath, mp3File: mp3Path)
  188. print("caf源文件:\(cafPath)")
  189. print("mp3文件:\(mp3Path)")
  190. }
  191. }
  192. extension O2RecordVoiceManager: AVAudioPlayerDelegate, AVAudioRecorderDelegate {
  193. func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
  194. print("finished playing \(flag)")
  195. }
  196. func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) {
  197. if let e = error {
  198. print("\(e.localizedDescription)")
  199. }
  200. }
  201. }