iOS 录音功能实现
音頻基本知識
-
采樣率(sampleRate)
所謂采樣就是在時間軸上對信號進行數(shù)字化。根據(jù)奈奎斯特定理(也稱為采樣定理),按比聲音最高頻率高2倍以上的頻率對聲音進行采樣(也稱為AD轉(zhuǎn)換),對于高質(zhì)量的音頻信號,其頻率范圍(人耳能夠聽到的頻率范圍)是20Hz~20kHz,所以采樣頻率一般為44.1kHz,這樣就可以保證采樣聲音達到20kHz也能被數(shù)字化,從而使得經(jīng)過數(shù)字化處理之后,人耳聽到的聲音質(zhì)量不會被降低。而所謂的44.1kHz就是代表1秒會采樣44100次。 -
量化格式(sampleFormat)
量化是指在幅度軸上對信號進行數(shù)字化,比如用16比特的二進制信號來表示聲音的一個采樣,而16比特(一個short)所表示的范圍是[-32768,32767],共有65536個可能取值,因此最終模擬的音頻信號在幅度上也分為了65536層 -
聲道數(shù)(channel)
聲道(Sound Channel) 是指聲音在錄制或播放時在不同空間位置采集或回放的相互獨立的音頻信號,所以聲道數(shù)也就是聲音錄制時的音源數(shù)量或回放時相應(yīng)的揚聲器數(shù)量。 -
PCM
通常所說的音頻的裸數(shù)據(jù)格式就是脈沖編碼調(diào)制(Pulse Code Modulation,PCM)數(shù)據(jù)。描述一段PCM數(shù)據(jù)一般需要以下幾個概念:量化格式(sampleFormat)、采樣率(sampleRate)、聲道數(shù)(channel)。以CD的音質(zhì)為例:量化格式(有的地方描述為位深度)為16比特(2字節(jié)),采樣率為44100,聲道數(shù)為2,這些信息就描述了CD的音質(zhì)。而對于聲音格式,還有一個概念用來描述它的大小,稱為數(shù)據(jù)比特率,即1秒時間內(nèi)的比特數(shù)目,它用于衡量音頻數(shù)據(jù)單位時間內(nèi)的容量大小。而對于CD音質(zhì)的數(shù)據(jù),比特率為多少呢?計算如下:
44100 * 16 * 2 = 1378.125kbps
介紹幾種常用的壓縮編碼格式。
WAV編碼
PCM(通常所說的音頻的裸數(shù)據(jù)格式就是脈沖編碼調(diào)制(Pulse Code Modulation,PCM)數(shù)據(jù)),WAV編碼的一種實現(xiàn)(有多種實現(xiàn)方式,但是都不會進行壓縮操作)就是在PCM數(shù)據(jù)格式的前面加上44字節(jié),分別用來描述PCM的采樣率、聲道數(shù)、數(shù)據(jù)格式等信息。
- 特點:音質(zhì)非常好,大量軟件都支持。
- 適用場合:多媒體開發(fā)的中間文件、保存音樂和音效素材。
MP3編碼
MP3具有不錯的壓縮比,使用LAME編碼(MP3編碼格式的一種實現(xiàn))的中高碼率的MP3文件,聽感上非常接近源WAV文件,當然在不同的應(yīng)用場景下,應(yīng)該調(diào)整合適的參數(shù)以達到最好的效果。
- 特點:音質(zhì)在128Kbit/s以上表現(xiàn)還不錯,壓縮比比較高,大量軟件和硬件都支持,兼容性好。
- 適用場合:高比特率下對兼容性有要求的音樂欣賞。
AAC編碼
AAC是新一代的音頻有損壓縮技術(shù),它通過一些附加的編碼技術(shù)(比如PS、SBR等),衍生出了LC-AAC、HE-AAC、HE-AAC v2三種主要的編碼格式。LC-AAC是比較傳統(tǒng)的AAC,相對而言,其主要應(yīng)用于中高碼率場景的編碼(≥80Kbit/s);HE-AAC(相當于AAC+SBR)主要應(yīng)用于中低碼率場景的編碼(≤80Kbit/s);而新近推出的HE-AACv2(相當于AAC+SBR+PS)主要應(yīng)用于低碼率場景的編碼(≤48Kbit/s)。事實上大部分編碼器都設(shè)置為≤48Kbit/s自動啟用PS技術(shù),而>48Kbit/s則不加PS,相當于普通的HE-AAC。
- 特點:在小于128Kbit/s的碼率下表現(xiàn)優(yōu)異,并且多用于視頻中的音頻編碼。
- 適用場合:128Kbit/s以下的音頻編碼,多用于視頻中音頻軌的編碼。
Ogg編碼
Ogg是一種非常有潛力的編碼,在各種碼率下都有比較優(yōu)秀的表現(xiàn),尤其是在中低碼率場景下。Ogg除了音質(zhì)好之外,還是完全免費的,這為Ogg獲得更多的支持打好了基礎(chǔ)。Ogg有著非常出色的算法,可以用更小的碼率達到更好的音質(zhì),128Kbit/s的Ogg比192Kbit/s甚至更高碼率的MP3還要出色。但目前因為還沒有媒體服務(wù)軟件的支持,因此基于Ogg的數(shù)字廣播還無法實現(xiàn)。Ogg目前受支持的情況還不夠好,無論是軟件上的還是硬件上的支持,都無法和MP3相提并論。
- 特點:可以用比MP3更小的碼率實現(xiàn)比MP3更好的音質(zhì),高中低碼率下均有良好的表現(xiàn),兼容性不夠好,流媒體特性不支持。
- 適用場合:語音聊天的音頻消息場景。
在info.plist 添加
<key>NSMicrophoneUsageDescription</key> <string>獲取麥克風(fēng)權(quán)限</string>向系統(tǒng)申請麥克風(fēng)權(quán)限
AVCaptureDevice.requestAccess(for: AVMediaType.audio) {(granted: Bool) in}封裝的簡單工具類
import AVFoundation/// 采樣率 enum AudioSampleRate:Int {case AudioSampleRate8KHZ = 8000case AudioSampleRate12KHZ = 12000case AudioSampleRate16KHZ = 16000case AudioSampleRate24KHZ = 24000case AudioSampleRate32KHZ = 32000 }///聲道數(shù) enum AudioNumberOfChannels:Int {case AudioNumberOfChannelsOne = 1case AudioNumberOfChannelsTwo = 2 }///量化格式 enum AudioLinearPCMBitDepth:Int {case AudioLinearPCMBitDepthKey8 = 8case AudioLinearPCMBitDepthKey16 = 16case AudioLinearPCMBitDepthKey24 = 24case AudioLinearPCMBitDepthKey32 = 32 }enum AudioAuthorizationStatus: Int, CustomStringConvertible {case notDetermined = 0case notAuthorizedcase authorizedpublic var description: String {get {switch self {case .notDetermined:return "用戶沒有做選擇"case .notAuthorized:return "沒有獲得權(quán)限"case .authorized:return "獲得權(quán)限"}}} }class AudioManager:NSObject{static let shared = AudioManager()//采樣間隔var audioSetting:[String:Any] = [:]/// 設(shè)置編碼格式var formatKey:AudioFormatID = kAudioFormatLinearPCM/// 抽樣率var sampleRate:AudioSampleRate = .AudioSampleRate8KHZ/// 聲道數(shù)var numberOfChannels:AudioNumberOfChannels = .AudioNumberOfChannelsOne/// 位寬(量化格式)var linearPCMBitDepth:AudioLinearPCMBitDepth = .AudioLinearPCMBitDepthKey8/// 音頻權(quán)限var audioAuthorizationStatus:AudioAuthorizationStatus = .notDeterminedvar audioRecorder:AVAudioRecorder?var audioPlayer:AVAudioPlayer?private override init() {super.init()self.checkAudioAuthorization()} }extension AudioManager{func checkAudioAuthorization() {let status = AVCaptureDevice.authorizationStatus(for: AVMediaType.audio)switch status {case .notDetermined:self.audioAuthorizationStatus = .notDeterminedcase .restricted:self.audioAuthorizationStatus = .notAuthorizedcase .denied:self.audioAuthorizationStatus = .notAuthorizedcase .authorized:self.audioAuthorizationStatus = .authorized@unknown default:self.audioAuthorizationStatus = .notDetermined}}func requestAudioAuthorization(completionHandler:@escaping (AudioAuthorizationStatus)->()){AVCaptureDevice.requestAccess(for: AVMediaType.audio) {[weak self] (granted: Bool) inself?.audioAuthorizationStatus = granted ? .authorized : .notAuthorizedDispatchQueue.main.async {completionHandler((granted ? .authorized : .notAuthorized))}}} }extension AudioManager{func startRecorder(voiceUrl:URL) {guard self.audioAuthorizationStatus == .authorized else {self.requestAudioAuthorization { (status) -> () in}return}do {//[AVSampleRateKey:sampleRate,AVFormatIDKey:formatKey,AVNumberOfChannelsKey:numberOfChannels,AVLinearPCMIsFloatKey:linearPCMBitDepth]try audioRecorder = AVAudioRecorder.init(url: voiceUrl, settings:[AVFormatIDKey:formatKey] )try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.record)audioRecorder?.delegate = selfaudioRecorder?.isMeteringEnabled = trueguard let success = audioRecorder?.record()else{return}if success == true{print("開始錄音")}else{print("錄音失敗")}} catch _ {print("錄音異常")}}func pauseRecorderAudio() {audioRecorder?.pause()print("暫停錄音")}func stopRecorderAudio(){audioRecorder?.stop()print("停止錄音")} }extension AudioManager{func playAudio(voiceUrl:URL){do {try audioPlayer = AVAudioPlayer.init(contentsOf:voiceUrl)try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)audioPlayer?.delegate = selfguard let success = audioPlayer?.play() else {return}if success == true {print("開始播放")}else{print("開始播放失敗")}} catch _{print("播放異常")}}func audioPause() {audioPlayer?.pause()print("暫停播放")}func audioStop() {audioPlayer?.stop()print("停止播放")} }extension AudioManager:AVAudioRecorderDelegate{func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) {}func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {} }extension AudioManager:AVAudioPlayerDelegate{func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {}func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) {} }總結(jié)
以上是生活随笔為你收集整理的iOS 录音功能实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通过pyhive连接hive需要的Pyt
- 下一篇: 机器学习建模流程