現在你應該對AVFoundation
有了比較深入的瞭解,並且對數字媒體的細節也有了一定認識,下面介紹一下 AVFoundation
的文字轉語音功能
AVSpeechSynthesizer
開發者可以使用AVFoundation
中的AVSpeechSynthesizer
類向iOS應用程式中新增類似功能,這個類用來播放一個或多個語音內容,這些語音內容都是名為AVSpeechUtterance
的類的例項。具體的實現程式碼如下所示:
let synthesizer = AVSpeechSynthesizer()
synthesizer.speak(AVSpeechUtterance(string: "Hello AV Foundation. How are you?"))
複製程式碼
就兩行程式碼解決了文字轉語音功能。當然很多人會有自己的需求,那麼還需要對具體對話中用到的聲音和語音字串定義屬性。
AVSpeechUtterance
如果我們想定義聲音的語速和語種那麼我們就需要用AVSpeechUtterance
類來設定一下自定義的屬性
let synthesizer = AVSpeechSynthesizer()
//如果播放語音內容 需要用到 AVSpeechUtterance 類
let utterance = AVSpeechUtterance(string: "Hello AV Foundation. How are you?")
//定義播放的語音語種
utterance.voice = AVSpeechSynthesisVoice(language: "en-US")
//定義播放語音內容的速率
utterance.rate = 0.5
//可在播放特定語句時改變聲音的音調 pitchMultiplier 的允許值一般介於0.5(低音調)和2.0(高音調)之間
utterance.pitchMultiplier = 1.0
//讓語音合成器在播放下一語句之前有短暫時間暫停
utterance.postUtteranceDelay = 0.5
//播放
synthesizer.speak(utterance)
複製程式碼
強調一下AVSpeechUtterance
中的voice
屬性
Arabic (ar-SA)
Chinese (zh-CN, zh-HK, zh-TW)
Czech (cs-CZ)
Danish (da-DK)
Dutch (nl-BE, nl-NL)
English (en-AU, en-GB, en-IE, en-US, en-ZA)
Finnish (fi-FI)
French (fr-CA, fr-FR)
German (de-DE)
Greek (el-GR)
Hebrew (he-IL)
Hindi (hi-IN)
Hungarian (hu-HU)
Indonesian (id-ID)
Italian (it-IT)
Japanese (ja-JP)
Korean (ko-KR)
Norwegian (no-NO)
Polish (pl-PL)
Portuguese (pt-BR, pt-PT)
Romanian (ro-RO)
Russian (ru-RU)
Slovak (sk-SK)
Spanish (es-ES, es-MX)
Swedish (sv-SE)
Thai (th-TH)
Turkish (tr-TR)
複製程式碼
AVSpeechSynthesizer
常用的delegate
//開始朗讀
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didStart utterance: AVSpeechUtterance) {
}
//結束朗讀
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
}
//暫停朗讀
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didPause utterance: AVSpeechUtterance) {
}
//繼續朗讀
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didContinue utterance: AVSpeechUtterance) {
}
//將要播放的語音文字
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, willSpeakRangeOfSpeechString characterRange: NSRange, utterance: AVSpeechUtterance) {
}
複製程式碼
常用的文字轉語音功能介紹完了 接下來介紹下常用的音訊錄製和播放功能
所有iOS應用程式都具有音訊會話,無論其是否使用。預設音訊會話來自於以下一些預配置:
- 啟用了音訊播放,但是音訊錄音未啟用
- 當使用者切換響鈴/靜音開光到“靜音”模式時,應用程式播放的所有音訊都會消失
- 當裝置顯示解鎖螢幕時,應用程式的音訊處於靜音狀態
- 當應用程式播放音訊時,所有後臺播放的音訊都會處於靜音狀態
AVFoundation
定義了7種分類來描述應用程式所使用的音訊行為。
分類 | 作用 | 是否允許混音 | 音訊輸入 | 音訊輸出 |
---|---|---|---|---|
Ambient | 遊戲 效率應用程式 | 是 | 否 | 是 |
Solo Ambient (預設) | 遊戲 效率應用程式 | 否 | 否 | 是 |
Playback | 音訊和視訊播放器 | 可選 | 否 | 是 |
Record | 錄音機 音訊捕捉 | 否 | 是 | 否 |
Play and Record | VoIP 語音聊天 | 可選 | 是 | 是 |
Audio Processing | 離線會話和處理 | 否 | 否 | 否 |
Multi-Route | 使用外部硬體的高階A/V應用程式 | 否 | 是 | 是 |
上述分類所提供的幾種常見行為可以滿足大部分應用程式的需要,不過如果開發者需要更復雜的功能,其中一些分類可以通過使用options和modes
方法進一步自定義開發。
音訊會話在應用程式的生命週期中是可以修改的,但通常我們只對其配置一次,就是在應用程式啟動時。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let session = AVAudioSession.sharedInstance()
do {
/*AVAudioSession.Category:
.ambient 混合播放,會把後臺播放的音樂混合起來播放
.soloAmbient 進入後臺,先會把之前的後臺音樂停止,在播放自己的
.playback 進入後臺的時候播放音樂 不會隨著靜音鍵和螢幕關閉而靜音
.record 用於需要錄音的應用,除了來電鈴聲,鬧鐘或日曆提醒之外的其它系統聲音都不會被播放
.playAndRecord 用於既需要播放聲音又需要錄音的應用 該Category提供錄音和播放功能。如果你的應用需要用到iPhone上的聽筒,該category是你唯一的選擇,在該Category下聲音的預設出口為聽筒(在沒有外接裝置的情況下)
.audioProcessing 主要用於音訊格式處理,一般可以配合AudioUnit進行使用
.multiRoute 這個類別可以支援多個裝置輸入輸出。
上面介紹的這個七大類別,可以認為是設定了七種主場景,而這七類肯定是不能滿足開發者所有的需求的。CoreAudio提供的方法是,首先定下七種的一種基調,然後在進行微調。CoreAudio為每種Category都提供了些許選項來進行微調。在設定完類別後,可以通過 AVAudioSession.CategoryOptions屬性 檢視當前類別設定了哪些選項
AVAudioSession.CategoryOptions:
.mixWithOthers 是否可以和其他後臺APP進行混音
.duckOthers 是否壓低其他APP聲音
.allowBluetooth 是否支援藍芽耳機
.defaultToSpeaker 是否預設用擴音聲音
除此之外,在iOS9還提供了.interruptSpokenAudioAndMixWithOthers iOS10又新加了兩個.allowBluetoothA2DP 和 .allowAirPlay用來支援藍芽A2DP耳機和AirPlay
通過上面的七大類別,我們基本覆蓋了常用的主場景,在每個主場景中可以通過Option進行微調。為此CoreAudio提供了七大比較常見微調後的子場景。叫做各個類別的模式。
AVAudioSession.Mode:
.default 每種類別預設的就是這個模式,所有要想還原的話,就設定成這個模式。
.voiceChat 主要用於VoIP場景,此時系統會選擇最佳的輸入裝置,比如插上耳機就使用耳機上的麥克風進行採集。此時有個副作用,他會設定類別的選項為".allowBluetooth"從而支援藍芽耳機。 適用於 .playAndRecord
.gameChat 適用於遊戲App的採集和播放,比如“GKVoiceChat”物件,一般不需要手動設定 適用於 .playAndRecord
.videoRecording 錄製視訊時 適用於 .playAndRecord .record
.measurement 最小系統 適用於 .playAndRecord .record .playback
.moviePlayback 視訊播放 適用於 .playback
.videoChat 主要用於視訊通話,比如QQ視訊、FaceTime。時系統也會選擇最佳的輸入裝置,比如插上耳機就使用耳機上的麥克風進行採集並且會設定類別的選項為".allowBluetooth" 和 ".defaultToSpeaker"。 適用於 .playAndRecord
*/
try session.setCategory(.playback, mode: .default, options: .mixWithOthers)
try session.setActive(true, options: .notifyOthersOnDeactivation)
} catch let error as Error {
print(error)
}
return true
}
複製程式碼
使用AVAudionPlayer 播放音訊
AVAudioPlayer
構建於Core Audio
中的C-based Audio Qucue Serics
的最頂層。所以它可以提供所有你在 Audio Oucue Services
中所能找到的核心功能, 比如播放、迴圈甚至音訊計量。除非你需要從網路流中播放音訊、需要訪問原始音訊樣本或者需要非常低的時延,否則AVAudioPlayer
都能勝任。
建立 AVAudionPlayer
let fileurl = Bundle.main.url(forResource: "rock", withExtension: "mp3")
let player = try AVAudioPlayer.init(contentsOf: fileurl!)
if player != nil {
player.prepareToPlay()
}
複製程式碼
如果返回一個有效的播放例項,建議開發者呼叫 prepareToPlay
方法。這樣做會取得需要的音訊硬體並預載入Audio Queue
的緩衝區。呼叫 prepareToPlay
這個動作是可選的,當呼叫Play
方法時會隱形啟用,不過在建立時準備播放器可以降低呼叫Play
方法和聽到聲音之間的延時
AVAudioPlayer
常用屬性
//設定聲音的大小 範圍為(0到1)
player?.volume = 0.5
//設定迴圈次數,如果為負數,就是無限迴圈
player?.numberOfLoops = -1
//設定播放進度
player?.currentTime = 0
//調整播放率 範圍 0.5 - 2.0
player?.rate = 0.5
//允許使用立體聲播放聲音 範圍從 -1.0(極左)到 1.0(極右) 預設值為0.0(居中)
player?.pan = 1.0
複製程式碼
pause
和stop
方法的區別:
pause
和stop
方法在應用程式外面看來實現的功能都是停止當前播放行為,這兩者最主要的區別在底層處理上。掉用stop
方法會撤銷掉用prepareToPlay
時所做的設定,而呼叫pause
方法則不會。
使用AVAudionRecorder 播放音訊
AVAudionRecorder
同其於播放音訊的兄弟類一樣,構建於Audio Qucue Serics
之上,是一個功能強大且程式碼簡單易用的類。我們可以在Mac
機器和iOS
裝置上使用這個類來從內建的麥克風錄製視訊,也可從外部音訊裝置進行錄製,比如數字音訊介面或USB麥克風
建立 AVAudionRecorder
let tmpDir = NSTemporaryDirectory()
let fileURL = URL.init(string: tmpDir)!.appendingPathComponent("memo.caf")
/*AVEncoderAudioQualityKey:聲音質量 需要的引數是一個列舉 :
AVAudioQualityMin 最小的質量
AVAudioQualityLow 比較低的質量
AVAudioQualityMedium 中間的質量
AVAudioQualityHigh 高的質量
AVAudioQualityMax 最好的質量
AVLinearPCMBitDepthKey:位元率 8 16 32
*/
let settings = [AVFormatIDKey : [kAudioFormatAppleIMA4],
AVSampleRateKey : "44100.0",
AVNumberOfChannelsKey : "1",
AVEncoderBitDepthHintKey : "16",
AVEncoderAudioQualityKey : [kRenderQuality_Medium]
] as [String : Any]
do {
try recorder = AVAudioRecorder.init(url: fileURL, settings: settings)
recorder?.delegate = self
recorder?.isMeteringEnabled = true
recorder?.prepareToRecord()
} catch _ {
}
複製程式碼
成功建立AVAudioRecorder
例項,建議呼叫期prepareToRecord
方法,與AVPlayer
的prepareToPlay
方法類似。這個方法執行底層Audio Queue初始化的必要過程。該方法還在URL引數指定的位置一個檔案,將錄製啟動時的延遲降到最小。
在設定字典中指定的鍵值資訊也值得討論一番,開發者可以使用的完整可用鍵資訊在<ACFoundation/AVAudioSettings.h>
中定義。大部分的鍵都專門定義了特有的各式,不過下面介紹的都是一些通用的音訊格式
1.音訊格式
AVFormatIDKey
鍵定義了寫入內容的音訊格式,下面的常量都是音訊格式所支援的值:
kAudioFormatLinearPCM = 'lpcm',
kAudioFormatAC3 = 'ac-3',
kAudioFormat60958AC3 = 'cac3',
kAudioFormatAppleIMA4 = 'ima4',
kAudioFormatMPEG4AAC = 'aac ',
kAudioFormatMPEG4CELP = 'celp',
kAudioFormatMPEG4HVXC = 'hvxc',
kAudioFormatMPEG4TwinVQ = 'twvq',
kAudioFormatMACE3 = 'MAC3',
kAudioFormatMACE6 = 'MAC6',
kAudioFormatULaw = 'ulaw',
kAudioFormatALaw = 'alaw',
kAudioFormatQDesign = 'QDMC',
kAudioFormatQDesign2 = 'QDM2',
kAudioFormatQUALCOMM = 'Qclp',
kAudioFormatMPEGLayer1 = '.mp1',
kAudioFormatMPEGLayer2 = '.mp2',
kAudioFormatMPEGLayer3 = '.mp3',
kAudioFormatTimeCode = 'time',
kAudioFormatMIDIStream = 'midi',
kAudioFormatParameterValueStream = 'apvs',
kAudioFormatAppleLossless = 'alac',
kAudioFormatMPEG4AAC_HE = 'aach',
kAudioFormatMPEG4AAC_LD = 'aacl',
kAudioFormatMPEG4AAC_ELD = 'aace',
kAudioFormatMPEG4AAC_ELD_SBR = 'aacf',
kAudioFormatMPEG4AAC_ELD_V2 = 'aacg',
kAudioFormatMPEG4AAC_HE_V2 = 'aacp',
kAudioFormatMPEG4AAC_Spatial = 'aacs',
kAudioFormatAMR = 'samr',
kAudioFormatAMR_WB = 'sawb',
kAudioFormatAudible = 'AUDB',
kAudioFormatiLBC = 'ilbc',
kAudioFormatDVIIntelIMA = 0x6D730011,
kAudioFormatMicrosoftGSM = 0x6D730031,
kAudioFormatAES3 = 'aes3',
kAudioFormatEnhancedAC3 = 'ec-3',
kAudioFormatFLAC = 'flac',
kAudioFormatOpus = 'opus'
複製程式碼
指定kAudioFormatLinearPCM
會將未壓縮的音訊流寫入到檔案中。這種格式的保真度最高,不過相應的檔案也最大。選擇諸如AAC
或Apple IMA4
的壓縮格式會顯著縮小檔案,還能保證高質量的音訊內容
2.取樣率
AVSampleRateKey
用於定義錄音器的取樣率,取樣率定義了對輸入的模擬音訊訊號每一秒內的取樣數。在錄製音訊的質量及最終檔案大小方面,取樣率扮演著至關重要的角色。使用低取樣率,比如8kHz
, 會導致粗粒度、 AM廣播型別的錄製效果,不過檔案會比較小,使用44.1kHz
的取樣率(CD質量的取樣率)會得到非常高質量的內容,不過檔案就比較大。對於使用什麼取樣率最好 沒有一個明確的定義,不過開發者應該儘量使用標準的取樣率,比如8000
、16000
、22 050
或44 100
。最終是我們的耳朵在進行判斷。
3.通道數
AVNumberOfChannelsKey
用於定義記錄音訊內容的通道數。指定預設值1意味著使用單聲道錄製,設定為2意味著使用立體聲錄製。除非使用外部硬體進行錄製,否則通常應該建立單聲道錄音。
4.指定格式的鍵
處理Linear PCM
或壓縮音訊格式時,可以定義一些其他指定格式的鍵。 可在Xcode幫助文件中的AV Foundation Audio Sttings Constants
引用中找到完整的列表。
AVAudionRecorder
常用的API
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 func updateMeters() 更新音量等資料
open func peakPower(forChannel channelNumber: Int) -> Float 最高音量
open func averagePower(forChannel channelNumber: Int) -> Float 平均音量
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 } 裝置當前時間
@available(iOS 7.0, *)
open var channelAssignments: [AVAudioSessionChannelDescription]? 每個聲音通道描述陣列
複製程式碼
AVAudioRecorderDelegate
@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) 錄音結束中斷的回撥
複製程式碼
使用Audio Metering
AVAudioRecorder
和AVAudioPlayer
中最強大和最實用的功能就是對音訊進行測量。Audio Metering
可讓開發者讀取音訊的平均分貝和峰值分貝資料,並使用這些資料以視覺化方式將聲音的大小呈現給終端使用者。
這兩個類使用的方法都是**averagePowerForChannel
和peakPowerForChannel
**。兩個方法都會返回一個用於表示聲音分貝(dB)等級的浮點值。這個值的範圍從表示最大分貝的0Db(fullscale)到表示最小分貝或靜音的-160dB。
在可以讀取這些值之前,首先要通過設定錄音器的**isMeteringEnabled = true
才可以支援對音訊進行測量。這就使得錄音器可以對捕捉到的音訊樣本進行分貝計算。每當需要讀取值時,首頁需要呼叫updateMeters()
**方法才能獲取最新的值。
建立一個新的CADisplayLink 定時器 來實時重新整理 獲取分貝 定時器方法內部實現:
recorder?.updateMeters()
var level = 0.0
//獲取分貝
let peakPower = recorder?.peakPower(forChannel: 0)
//設定一個最低分貝
let minDecibels:Float = -60
if peakPower < minDecibels {
level = 0.0
}else if peakPower >= 0.0 {
level = 1.0
}else {
let root = 2.0;
//最小分貝的波形幅度值 公式: db 分貝 A 波形幅度值 dB=20∗log(A)→A=pow(10,(db/20.0))
let minAmp = powf(10.0, 0.05 * minDecibels);
let inverseAmpRange = 1.0 / (1.0 - minAmp);
//實時獲取到波形幅度值 公式同上
let amp = powf(10.0, 0.05 * peakPower);
//(實時資料 - 最小資料)/(最大資料 - 最小資料) 應該計算的一個比例值吧
let adjAmp = (amp - minAmp) * inverseAmpRange;
level = powf(adjAmp, 1.0 / root);
}
複製程式碼
本章我們見識了AVFoundation
的音訊類所能提供的強大功能。AVAudionSession
作為應用程式和更在的iOS音訊環境的中間環節,可通過使用分類在語義上定義應用程式的行為,並且提供工具來觀察中斷和線路變化。AVAudionPlayer
和AVAudioRecorder
提供了一種簡單但功能強大的介面,用於處理音訊的播放和錄製。這兩個類都構建與Core Audio
框架之上,但為在應用程式中實現音訊錄製和播放提供了一種更便捷的方法。