iOS 音頻學習錄音AVAudioRecorder

0、錄音前很重要的一步, 創建音頻會話者
 let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
        } catch {
            print(error)
        }

在整個錄音或播放音頻的過程中只需要初始化一次就好
其中setCategory的值決定這個會話者的功能
音頻會話分類

分類 作用 是否允許跟其他應用混音 支持音頻輸入 支持音頻輸出
AVAudioSessionCategoryAmbient 一般app應用 ?? ??
...SoloAmbient (默認) 一般app應用 ??
...Playback 音頻播放器 可選 ??
...Record 錄音機,音頻捕捉 ??
...PlayAndRecord VoIp,語音聊天 可選 ?? ??
...AudioProcessing 離線會話和處理(僅需要用到編解碼處理功能的)
...MultiRoute 使用外設硬件的應用 ?? ??

其中一些分類可以使用option和modes進行進一步配置.

我們來看看AVAudioRecorder的API

1、初始化一個AVAudioRecorder對象

蘋果提供了兩個初始化方法

第一個初始化方法:

    傳入保存這個錄音文件的URL路徑, setting這個參數是個字典, 里面是一個音頻設置信息,字典相對應的key, 可以去參考 AVAudioSettings.h ,值都是NSNumber類型
    public init(url: URL, settings: [String : Any]) throws
    ```
第一個初始化AVAudioRecorder方法中的setting字典一般設置的內容, 可以參考相關術語概念[iOS 音頻學習基本術語和概念](http://www.lxweimin.com/p/3802d2c6f051)
 `AVSampleRateKey: String` 采樣率   8000, 44100等
`AVNumberOfChannelsKey: String` 聲道數 1為單聲道, 2為雙聲道(立體聲)
`AVLinearPCMBitDepthKey: String` 位寬 數據一般為: 8, 16, 24, 32 
 `AVEncoderAudioQualityKey: String` 錄音質量,在`AVAudioQuality`枚舉中,值有`min low medium  high  max`四個
`AVLinearPCMIsBigEndianKey: String` 大小端編碼:1為大端, 0為小端.   如果你不懂什么是大小端可以看[iOS 關于大小端以及一些數據補位](http://www.lxweimin.com/p/79f349409cbf)
` AVFormatIDKey: String` 錄音數據格式 可以參考CoreAudio 里面相關的值
其中 `AVFormatIDKey`的值有

public var kAudioFormatLinearPCM: AudioFormatID { get }
public var kAudioFormatAC3: AudioFormatID { get }
public var kAudioFormat60958AC3: AudioFormatID { get }
public var kAudioFormatAppleIMA4: AudioFormatID { get }
public var kAudioFormatMPEG4AAC: AudioFormatID { get }
public var kAudioFormatMPEG4CELP: AudioFormatID { get }
public var kAudioFormatMPEG4HVXC: AudioFormatID { get }
public var kAudioFormatMPEG4TwinVQ: AudioFormatID { get }
public var kAudioFormatMACE3: AudioFormatID { get }
public var kAudioFormatMACE6: AudioFormatID { get }
public var kAudioFormatULaw: AudioFormatID { get }
public var kAudioFormatALaw: AudioFormatID { get }
public var kAudioFormatQDesign: AudioFormatID { get }
public var kAudioFormatQDesign2: AudioFormatID { get }
public var kAudioFormatQUALCOMM: AudioFormatID { get }
public var kAudioFormatMPEGLayer1: AudioFormatID { get }
public var kAudioFormatMPEGLayer2: AudioFormatID { get }
public var kAudioFormatMPEGLayer3: AudioFormatID { get }
public var kAudioFormatTimeCode: AudioFormatID { get }
public var kAudioFormatMIDIStream: AudioFormatID { get }
public var kAudioFormatParameterValueStream: AudioFormatID { get }
public var kAudioFormatAppleLossless: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_HE: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_LD: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_ELD: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_ELD_SBR: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_ELD_V2: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_HE_V2: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_Spatial: AudioFormatID { get }
public var kAudioFormatAMR: AudioFormatID { get }
public var kAudioFormatAMR_WB: AudioFormatID { get }
public var kAudioFormatAudible: AudioFormatID { get }
public var kAudioFormatiLBC: AudioFormatID { get }
public var kAudioFormatDVIIntelIMA: AudioFormatID { get }
public var kAudioFormatMicrosoftGSM: AudioFormatID { get }
public var kAudioFormatAES3: AudioFormatID { get }
public var kAudioFormatEnhancedAC3: AudioFormatID { get }

setting字典的代碼:

////定義音頻的編碼參數,這部分比較重要,決定錄制音頻文件的格式、音質、容量大小等
let recordSettings = [AVSampleRateKey : NSNumber(value: Float(44100.0) as Float),//聲音采樣率
AVFormatIDKey : NSNumber(value: Int32(kAudioFormatMPEG4AAC) as Int32),//編碼格式
AVNumberOfChannelsKey : NSNumber(value: 1 as Int32),//采集音軌
AVEncoderAudioQualityKey : NSNumber(value: Int32(AVAudioQuality.medium.rawValue) as Int32)]//音頻質量

初始化代碼:
do {
     try audioRecorder = AVAudioRecorder(url: self.directoryURL()!,
            settings: recordSettings)//初始化實例
        audioRecorder.prepareToRecord()//準備錄音
    } catch {
        print(error)
 }

//錄音保存路徑
func directoryURL() -> URL? {
//定義并構建一個url來保存音頻,音頻文件名為ddMMyyyyHHmmss.caf
//根據時間來設置存儲文件名
let currentDateTime = Date()
let formatter = DateFormatter()
formatter.dateFormat = "ddMMyyyyHHmmss"
let recordingName = formatter.string(from: currentDateTime)+".caf"
print(recordingName)

    let fileManager = FileManager.default
    let urls = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
    let documentDirectory = urls[0] as URL
    let soundURL = documentDirectory.appendingPathComponent(recordingName)
    return soundURL
}
>第二個初始化方法

傳入保存這個錄音文件的URL路徑, 還有AVAudioFormat
@available(iOS 10.0, *)
public init(url: URL, format: AVAudioFormat) throws

`AVAudioFormat`其實就是包裝了一下`Core Audio`框架中的`AudioStreamBasicDescription(asbd)`這個結構體,所以`AVAudioFormat`的初始化基本都要的參數都要傳入`AudioStreamBasicDescription `的值
那么`AudioStreamBasicDescription`是什么呢, 簡單理解就是描述音頻的基本格式信息, 跟第一個初始化AVAudioRecorder方法中的setting差不多, 只是更詳細

public struct AudioStreamBasicDescription {

public var mSampleRate: Float64 采樣率

public var mFormatID: AudioFormatID 數據格式
public var mFormatFlags: AudioFormatFlags 數據格式的標志, 這個不知道干嘛的, 還沒理解,linear PCM一般傳kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked

public var mBytesPerPacket: UInt32  多少個字節每包

public var mFramesPerPacket: UInt32  多少幀每包

public var mBytesPerFrame: UInt32  多少個字節每一幀

public var mChannelsPerFrame: UInt32  聲音通道數

public var mBitsPerChannel: UInt32  位寬 每個聲音通道的位寬

public var mReserved: UInt32  預留屬性

}

我們再看看提供的方法, 用起來還是比較簡單的, 所以備注一下就好了

open func prepareToRecord() -> Bool    準備錄音, 這個在錄音之前要調用一下, 底層可能會給你做一些事

open func record() -> Bool    錄音

@available(iOS 6.0, *)
open func record(atTime time: TimeInterval) -> Bool    在未來的某個時刻開始錄音

open func record(forDuration duration: TimeInterval) -> Bool  錄音, 控制時長

@available(iOS 6.0, *)
open func record(atTime time: TimeInterval, forDuration duration: TimeInterval) -> Bool  在未來的某段時間錄多少時間的音頻

open func pause()  暫停

open func stop()  停止


open func deleteRecording() -> Bool  刪除錄音
下面是屬性
open var isRecording: Bool { get }   是否正在錄音


open var url: URL { get }  錄音存放的url

open var settings: [String : Any] { get } 錄音格式配置字典

@available(iOS 10.0, *)
open var format: AVAudioFormat { get }  錄音格式配置



unowned(unsafe) open var delegate: AVAudioRecorderDelegate? 代理



open var currentTime: TimeInterval { get }  當前錄音的時長


@available(iOS 6.0, *)
open var deviceCurrentTime: TimeInterval { get }  設備當前時間


open func updateMeters()   更新音量等數據


open func peakPower(forChannel channelNumber: Int) -> Float  最高音量

open func averagePower(forChannel channelNumber: Int) -> Float  平均音量

@available(iOS 7.0, *)
open var channelAssignments: [AVAudioSessionChannelDescription]? 每個聲音通道描述數組
錄音操作代碼:

@IBAction func startRecord(_ sender: AnyObject) {
//開始錄音
if !audioRecorder.isRecording {
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setActive(true)
audioRecorder.record()
print("record!")
} catch {
}
}
}
@IBAction func stopRecord(_ sender: AnyObject) {
//停止錄音
audioRecorder.stop()
let audioSession = AVAudioSession.sharedInstance()

    do {
        try audioSession.setActive(false)
        print("stop!!")
    } catch {
    }
}
下面是錄音器的代理

public protocol AVAudioRecorderDelegate : NSObjectProtocol {

@available(iOS 3.0, *)
optional public func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool)  錄音成功的回調



@available(iOS 3.0, *)
optional public func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) 錄音發生錯誤的的回調


@available(iOS, introduced: 2.2, deprecated: 8.0)
optional public func audioRecorderBeginInterruption(_ recorder: AVAudioRecorder)    錄音開始中斷的回調

@available(iOS, introduced: 6.0, deprecated: 8.0)
optional public func audioRecorderEndInterruption(_ recorder: AVAudioRecorder, withOptions flags: Int) 錄音結束中斷的回調
###錄音播放AVAudioPlayer
里面的屬性和方法跟AVAudioRecorder差不多, 所以就不多說了, 附上簡單的代碼

@IBAction func startPlaying(_ sender: AnyObject) {
//開始播放
if (!audioRecorder.isRecording){
do {
try audioPlayer = AVAudioPlayer(contentsOf: audioRecorder.url)
audioPlayer.play()
print("play!!")
} catch {
}
}
}

@IBAction func pausePlaying(_ sender: AnyObject) {
    //暫停播放
    if (!audioRecorder.isRecording){
        do {
            try audioPlayer = AVAudioPlayer(contentsOf: audioRecorder.url)
            audioPlayer.pause()
            
            print("pause!!")
        } catch {
        }
    }
    
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容