項目地址:https://github.com/zhuyunlongYL/YLBaseChat
typealias PlayerDidFinishPlayingBlock = () -> Void
class VoiceManager:NSObject{
// 單例
static let shared = VoiceManager()
private override init(){}
var duration:Int = 0 // 錄音時間
var recorder_file_path:String? = nil // 錄音路徑
fileprivate var recorder: AVAudioRecorder? = nil
fileprivate var player: AVAudioPlayer? = nil
fileprivate var timer:Timer? = nil
fileprivate var pathTag:Int = 0
fileprivate var completeBlock:PlayerDidFinishPlayingBlock?
deinit {
timer?.invalidate()
timer = nil
}
// 是否使用揚聲器
func isProximity(_ isProximity:Bool) {
do {
if isProximity {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
}else {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord)
}
} catch let err {
print("設(shè)置揚聲器失敗:\(err.localizedDescription)")
}
}
//開始錄音
func beginRecord() {
duration = 0
let session = AVAudioSession.sharedInstance()
//設(shè)置session類型
do {
try session.setCategory(AVAudioSessionCategoryPlayAndRecord)
} catch let err{
print("設(shè)置類型失敗:\(err.localizedDescription)")
}
//設(shè)置session動作
do {
try session.setActive(true)
} catch let err {
print("初始化動作失敗:\(err.localizedDescription)")
}
//錄音設(shè)置,注意功舀,后面需要轉(zhuǎn)換成NSNumber,如果不轉(zhuǎn)換膝昆,你會發(fā)現(xiàn)组贺,無法錄制音頻文件凸舵,我猜測是因為底層還是用OC寫的原因
let recordSetting: [String: Any] = [AVSampleRateKey: NSNumber(value: 16000),//采樣率
AVFormatIDKey: NSNumber(value: kAudioFormatLinearPCM),//音頻格式
AVLinearPCMBitDepthKey: NSNumber(value: 16),//采樣位數(shù)
AVNumberOfChannelsKey: NSNumber(value: 1),//通道數(shù)
AVEncoderAudioQualityKey: NSNumber(value: AVAudioQuality.min.rawValue)//錄音質(zhì)量
];
//開始錄音
do {
recorder_file_path = getFilePath()
if let file_path = recorder_file_path {
let url = URL(fileURLWithPath: file_path)
recorder = try AVAudioRecorder(url: url, settings: recordSetting)
recorder?.isMeteringEnabled = true
recorder!.prepareToRecord()
recorder!.record()
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: (#selector(VoiceManager.recordingTime)), userInfo: nil, repeats: true)
print("開始錄音")
}
} catch let err {
print("錄音失敗:\(err.localizedDescription)")
}
}
//結(jié)束錄音
func stopRecord() {
timer?.invalidate()
timer = nil
if let recorder = recorder {
if recorder.isRecording {
if let file_path = recorder_file_path {
print("正在錄音,馬上結(jié)束它失尖,文件保存到了:\(file_path)")
}
}else {
print("沒有錄音啊奄,但是依然結(jié)束它")
}
recorder.stop()
self.recorder = nil
}else {
print("沒有初始化")
}
}
// 取消錄音
func cancelRecord() {
stopRecord()
if let file_path = recorder_file_path {
try? FileManager.default.removeItem(at: URL(fileURLWithPath: file_path))
print("刪除錄音:\(file_path)")
}
}
// 錄音獲取音量
func getRecordVolume() -> Float {
var level:Float = 0.0
if let recorder = recorder {
if recorder.isRecording {
recorder.updateMeters()
//獲取音量的平均值 [recorder averagePowerForChannel:0];
//音量的最大值 [recorder peakPowerForChannel:0];
let minDecibels:Float = -80.0
let decibels:Float = recorder.peakPower(forChannel: 0)
if decibels < minDecibels {
level = 0.0
}
else if decibels >= 0.0 {
level = 1.0
}else {
let root:Float = 2.0
let minAmp:Float = powf(10.0, 0.05 * minDecibels)
let inverseAmpRange:Float = 1.0 / (1.0 - minAmp)
let amp = powf(10.0, 0.05 * decibels)
let adjAmp = (amp - minAmp) * inverseAmpRange
level = powf(adjAmp, 1.0 / root)
}
}
}
print("錄音音量大小0~1--\(level)")
return level
}
//播放
func play(_ path: String?,_ block: PlayerDidFinishPlayingBlock?) {
UIDevice.current.isProximityMonitoringEnabled = true
// 默認(rèn)揚聲器播放
isProximity(true)
do {
completeBlock = block
if let path = path {
player = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
player?.delegate = self
player?.prepareToPlay()
player!.play()
}
} catch let err {
UIDevice.current.isProximityMonitoringEnabled = false
print("播放失敗:\(err.localizedDescription)")
}
}
//結(jié)束播放
func stopPlay() {
UIDevice.current.isProximityMonitoringEnabled = false
if let player = player {
if player.isPlaying {
print("停止播放")
}else {
print("沒有播放")
}
player.stop()
completeBlock = nil
self.player?.delegate = nil
self.player = nil
}else {
print("沒有初始化")
}
}
// 錄音記時
@objc fileprivate func recordingTime() {
duration += 1
print("錄音時間:\(duration)")
}
// 獲取路徑
fileprivate func getFilePath() -> String! {
pathTag += 1
if pathTag > 1000 {
pathTag = 0
}
return NSHomeDirectory() + "/Library/Caches/\(pathTag)-\(Date().timeIntervalSince1970).wav"
}
}
//// MARK: - AVAudioPlayerDelegate
extension VoiceManager:AVAudioPlayerDelegate {
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
UIDevice.current.isProximityMonitoringEnabled = false
if let completeBlock = completeBlock {
completeBlock()
}
}
}
// 添加監(jiān)聽
// 監(jiān)聽用戶耳朵靠近手機或者遠離手機
NotificationCenter.default.addObserver(self, selector: #selector(BaseChatVC.proximitySensorChanged), name: NSNotification.Name.UIDeviceProximityStateDidChange, object: nil)
// 監(jiān)聽用戶耳朵靠近手機或者遠離手機
@objc fileprivate func proximitySensorChanged() {
if UIDevice.current.proximityState == true {
VoiceManager.shared.isProximity(false)
}else {
VoiceManager.shared.isProximity(true)
}
}