多媒體音頻播放簡單介紹

概述

基礎(chǔ)知識-音頻編解碼,音頻格式,音頻會話(session)

  • ios軟硬件音頻編解碼器
  • 音頻會話(Audio Sessions)

播放音頻

  • 使用iPod庫訪問播放音頻項(xiàng)目
  • 使用系統(tǒng)聲音服務(wù)播放UI聲音效果或者調(diào)用震動
  • 使用AVAudioPlayer 播放音樂更輕松
  • 使用音頻隊(duì)列服務(wù)播放控制聲音
  • 使用OpenAL播放定位聲音

音頻錄制

  • 使用AVAudioRecorder 類錄制音頻
  • 使用Audio Queue Services 錄制

解析流式音頻

ios中的音頻單元支持

ios音頻最佳實(shí)戰(zhàn)

  • 使用音頻提示
  • ios的首先音頻格式

今天學(xué)習(xí)開源框架LFLiveKit,看到音頻錄制的部分,該部分是采用的AVFoundation.frame中AVAudio.framework框架來完成的。以前沒有接觸過這部分,因此這里摘錄出來仔細(xì)研究學(xué)習(xí)。

首先想學(xué)習(xí)框架,肯定官網(wǎng)是最佳的場所,我搜尋了下官方文檔,找到這一點(diǎn)相關(guān)知識multimedia Programming guide。一點(diǎn)點(diǎn)學(xué)習(xí)嘛,先學(xué)會這塊再說。

概述

基礎(chǔ)知識-音頻編解碼,音頻格式,音頻會話(session)

ios的音頻開發(fā),了解下ios設(shè)備的硬件和軟件架構(gòu)的有關(guān)知識是很必要的。

ios軟硬件音頻編解碼器

為確保音頻的最佳性能和質(zhì)量,我們需要選擇正確的音頻格式和音頻編解碼器類型。從ios3.0開始,大多數(shù)音頻格式可以使用軟件編碼和解碼(錄制和播放)。軟件編碼器支持多個聲音的同時播放,但是需要大量的cpu開銷。

硬件輔助解碼可以提供很好的性能,但是就不能支持同時播放多個聲音了。如果我們需要在應(yīng)用程序中最大化視頻幀速率,最小的cpu音頻開銷,那么我們需要使用未壓縮的音頻或者IMA4格式,也可以使用硬件幫助解碼壓縮的音頻。

下表是ios設(shè)備上可用的播放音頻編解碼器。

Audio decoder/playback format Hardware-assisted decoding Software-based decoding
AAC (MPEG-4 Advanced Audio Coding) Yes Yes, starting in iOS 3.0
ALAC (Apple Lossless) Yes Yes, starting in iOS 3.0
HE-AAC (MPEG-4 High Efficiency AAC) Yes -
iLBC (internet Low Bitrate Codec, another format for speech) - Yes
IMA4 (IMA/ADPCM) - Yes
Linear PCM (uncompressed, linear pulse-code modulation) - Yes
MP3 (MPEG-1 audio layer 3) Yes Yes, starting in iOS 3.0
μ-law and a-law - Yes

通過上面的表格,我們知道同時支持硬編碼和軟編碼的格式有aac alac 和 mp3.

使用硬件輔助編碼時,設(shè)備一次只能播放一種支持格式的單個實(shí)例。例如,如果我們使用硬件編解碼器播放立體聲mp3音樂,那么第二個同步mp3聲音將使用軟件編碼(硬件只能編碼一個,)。同樣,我們無法使用硬件同時編碼aac和alac格式音樂。

要是要要播放多種聲音,或者在ipod在后臺播放音樂,我們應(yīng)該使用線型PCM(未壓縮)或者IMA4(壓縮)音頻。

要了解運(yùn)行時設(shè)備上可用的硬件和軟件編解碼器。我們可以看kAudioFormatProperty_HardwareCodecCapabilities常量來了解。

如何確定在運(yùn)行時aac硬件編碼器的可用性。
ios4.0以及更高版本支持使用擴(kuò)展音頻文件和音頻轉(zhuǎn)換器api進(jìn)行硬件脫機(jī)編碼。這就是硬編碼
注意 ios3.1 只支持?jǐn)U展音頻文件api。
要檢查acc硬件編碼器的可用性,使用下列代碼

Boolean IsAACHardwareEncoderAvailable(void)
{
    Boolean isAvailable = false;
    OSStatus error;
    
    // get an array of AudioClassDescriptions for all installed encoders for the given format
    // the specifier is the format that we are interested in - this is 'aac ' in our case
    UInt32 encoderSpecifier = kAudioFormatMPEG4AAC;
    UInt32 size;
    
    error = AudioFormatGetPropertyInfo(kAudioFormatProperty_Encoders, sizeof(encoderSpecifier),
                                       &encoderSpecifier, &size);
    if (error) {
        printf("AudioFormatGetPropertyInfo kAudioFormatProperty_Encoders error %lu %4.4s\n", error, (char*)&error);
        return false;
        
    }
    
    UInt32 numEncoders = size / sizeof(AudioClassDescription);
    AudioClassDescription encoderDescriptions[numEncoders];
    error = AudioFormatGetProperty(kAudioFormatProperty_Encoders, sizeof(encoderSpecifier), &encoderSpecifier, &size, encoderDescriptions);
    if (error) {
        printf("AudioFormatGetProperty kAudioFormatProperty_Encoders error %lu %4.4s\n", error, (char*)&error); return false; }
    
    for (UInt32 i=0; i < numEncoders; ++i) {
        if (encoderDescriptions[i].mSubType == kAudioFormatMPEG4AAC &&
            encoderDescriptions[i].mManufacturer == kAppleHardwareAudioCodecManufacturer) isAvailable = true;
    }
    
    return isAvailable;
}
        

總結(jié)下ios如何支持單個或者多個播放音頻格式

  • 線型PCM 和IMA4(IMA/ADPCM) 我們可以在ios中同時播放多個線型的PCM或者IMA4 音樂,而不會產(chǎn)生cpu 性能問題。對于ILBC語音質(zhì)量格式以及 μ-law 和 a-law 壓縮格式也是一樣的,當(dāng)用壓縮格式,需要檢查音質(zhì)以確保滿足需求。
  • AAC,HE-AAC,MP3和ALAC(Apple Lossless) 對AAC,HE-AAC,MP3和ALAC(Apple Lossless)的播放可以在設(shè)備上使用高效的硬件輔助編碼,但這些編碼都共享一條硬件路徑。因此,硬件編碼只能播放這些格式之一的單個實(shí)例。

AAC,HE-AAC,MP3和ALAC播放的單一硬件路徑對“播放”風(fēng)格應(yīng)用程序(如虛擬鋼琴)有影響。如果用戶正在ipod的應(yīng)用程序中播放這三種格式之一的歌曲,那么我們的應(yīng)用程序?qū)⑼ㄟ^軟編碼進(jìn)行編碼。

下表記錄在ios設(shè)備上可用的錄制音頻編解碼器

Audio encoder/recording format Hardware-assisted encoding Software-based encoding
AAC (MPEG-4 Advanced Audio Coding) Yes, starting in iOS 3.1 for iPhone 3GS and iPod touch (2nd generation) Yes, starting in iOS 3.2 for iPad Yes, starting in iOS 4.0 for iPhone 3GS and iPod touch (2nd generation)
ALAC (Apple Lossless) - Yes
iLBC (internet Low Bitrate Codec, for speech) - Yes
IMA4 (IMA/ADPCM) - Yes
Linear PCM (uncompressed, linear pulse-code modulation) - Yes
μ-law and a-law - Yes

通過上表,我們知道了錄制音頻,同時支持硬件和軟件編碼的之后aac格式編碼

音頻會話(Audio Sessions)

ios音頻會話api允許我們定義應(yīng)用程序的一般音頻行為。相關(guān)api在 Audio Session Services Reference and AVAudioSession Class Reference。這些使用這些api,可以完成下列對音頻的操作:

  • 設(shè)備靜音
  • 音頻是否在屏幕鎖定時停止
  • 當(dāng)音頻開始的時候,其他音頻是否應(yīng)該繼續(xù)播放或者靜音。

音頻會話api還會響應(yīng)用戶操作,例如插入或者播出耳機(jī),以及使用設(shè)備聲音硬件的事件,例如時鐘和日歷鬧鐘以及來電。

音頻會話的三個編程功能如下表

音頻會話功能 描述
設(shè)置categories category是標(biāo)示應(yīng)用程序的一組音頻行為的key。通過設(shè)置category,我們可以向ios表明我們的音頻意圖,例如屏幕鎖定時我們的音頻是否應(yīng)該繼續(xù)。響應(yīng)中斷中描述的六個類別。我們也可以微調(diào)某些category的行為,例如可以看 Use Modes to Specialize the Category.
處理中斷和路由更改 當(dāng)音頻中斷,中斷結(jié)束以及硬件音頻路由發(fā)生變化時,音頻會話會發(fā)布通知。通過這些通知,我們可以優(yōu)雅的響應(yīng)較大音頻環(huán)境中的更改-例如由于來電而導(dǎo)致的中斷。更多細(xì)節(jié)可以看處理音頻硬件路由改變Audio Guidelines By App Type.
優(yōu)化硬件性能 我們可以查詢音頻會話以發(fā)現(xiàn)運(yùn)行的應(yīng)用程序的設(shè)備的特征,例如硬件采樣率,硬件通道數(shù)以及音頻輸入是否可用有關(guān)詳細(xì)細(xì)節(jié)可看Optimizing for Device Hardware.

有兩個用于處理音頻會話的接口:

我們可以混合和匹配AVFoundation和audio sessionServices中的音頻會話代碼-他們兩個是相互兼容的。

音頻會話帶有一些默認(rèn)行為,我們可以使用這些開始開發(fā)。

例如,使用默認(rèn)音頻會話時,當(dāng)自動鎖定時間超時且屏幕鎖定時,應(yīng)用程序中的音頻將停止。 如果要確保在屏幕鎖定的情況下繼續(xù)播放,請?jiān)趹?yīng)用程序的初始化代碼中包含以下行:

NSError *setCategoryErr = nil;
NSError *activationErr  = nil;
[[AVAudioSession sharedInstance]
              setCategory: AVAudioSessionCategoryPlayback
                    error: &setCategoryErr];
[[AVAudioSession sharedInstance]
                setActive: YES
                    error: &activationErr];

AVAudioSessionCategoryPlayback category 確保當(dāng)屏幕鎖屏的時候可以繼續(xù)播放音頻。

如何處理來電或者時鐘以及日歷鬧鐘導(dǎo)致的中斷取決于我們使用的音頻技術(shù)。見下表

Audio technology How interruptions work
AV Foundation framework AVAudioPlayer和AVAudioRecorder類為中斷開始和結(jié)束提供委托方法。實(shí)現(xiàn)這些方法來更新用戶界面,并且我們可以在中斷后,回復(fù)暫停的播放。系統(tǒng)在中斷時會自動的暫停播放和錄制,并在恢復(fù)播放或者錄制時候重新激活音頻會話。如果要在應(yīng)用程序啟動時保存和恢復(fù)播放位置,請?jiān)谥袛嗪蛻?yīng)用程序退出時保存播放位置。
Audio Queue Services, I/O audio unit 我們可以通過該技術(shù)處理中斷。我們需要保存播放盒錄制位置,并且中斷結(jié)束后重新激活音頻會話。實(shí)現(xiàn)AVAudioSession中斷的委托代理方法或者編寫監(jiān)聽回調(diào)函數(shù)-通知
OpenAL 使用openAL 進(jìn)行播放,需要實(shí)現(xiàn)AVAudioSession中斷委托方法或編寫中斷回調(diào)函數(shù)-與使用音頻隊(duì)列服務(wù)時一樣的。這里需要注意的時,委托或者回調(diào)必須重新管理openAL上下文
System Sound Services 用系統(tǒng)聲音服務(wù)播放的音樂在終端開始時保持靜音。如果終端結(jié)束,他們可以自動的再次使用。應(yīng)用程序不能影響使用此播放技術(shù)的聲音的中斷行為

每個ios應(yīng)用程序(極少數(shù)例外)都應(yīng)該主動管理其音頻會話。有關(guān)如何執(zhí)行此操作的完整說明,可以看這里Audio Session Programming Guide

播放音頻

本節(jié)主要介紹如何播放在 iPod library access, System Sound Services, Audio Queue Services, t AV Foundation framework和OpenAL.中聲音。

使用iPod庫訪問播放音頻項(xiàng)目

在ios3.0開始,ipad 庫訪問可以應(yīng)用程序播放用戶的歌曲,有聲讀物或者音頻播客。api設(shè)計使用基本播放非常簡單,同時還支持高級搜索和播放控制。

下圖展示應(yīng)用程序有兩種方法來檢索媒體項(xiàng)目。左側(cè)顯示的媒體項(xiàng)目選擇器是一個易于使用的預(yù)打包視圖控制器,其行為類似于內(nèi)置ipod應(yīng)用程序的音樂選擇界面。對于許多應(yīng)用來說,這已經(jīng)足夠了。如果選擇器不能滿足我們的需求,那么就可以選擇右邊的medai query。他支持來自ipod庫的基于謂詞的項(xiàng)目規(guī)范。


如何將媒體項(xiàng)目添加到應(yīng)用程序的完成實(shí)例,可以參考 *iPod Library Access Programming Guide。例子可以參考 AddMusic工程

使用系統(tǒng)聲音服務(wù)播放UI聲音效果或者調(diào)用震動

想要播放用戶界面聲音效果(如按鈕點(diǎn)擊),或在支持他的設(shè)備上調(diào)用振動,請使用系統(tǒng)服務(wù)聲音服務(wù)。詳細(xì)講解在System Sound Services Reference。我們可以在 iOS Dev Center中找到簡單的代碼。

注意:使用聲音系統(tǒng)服務(wù)播放的聲音不受使用音頻會話的配置限制。因此,我們無法使system sound services 音頻的行為和應(yīng)用程序中的其他音頻行為保持一致。這是避免將system sound services用于除預(yù)期用途之外的任何音頻的最重要原因。

AudioServicesPlaySystemSound 函數(shù)能讓我們可以非常簡單的播放簡短的聲音文件。簡單必定帶來一些限制。我們的聲音文件必須是滿足下列要求:

  • 持續(xù)時間不能超過30s
  • 采用pcm 或者IMA4(IMA/ADPCM)格式
  • 打包在.caf .aif 或者 .wav文件中

此外,我們可以使用AudioServicesPlaySystemSound函數(shù)時:

  • 聲音播放使用當(dāng)前系統(tǒng)音量,沒有可用的編程音量控制
  • 聲音立刻播放
  • 無法進(jìn)行循環(huán)和立體聲定位
  • 同時不放不可用:我們一次只能播放一種聲音

有個類似的AudioServicesPlayAlertSound函數(shù),可以用來播放短聲音作為警報。如果用戶已將其設(shè)備配置為在“震動設(shè)置”中的震動,那么調(diào)用此功能除了播放聲音文件之外還會調(diào)用振動。

注意:應(yīng)用程序無法使用系統(tǒng)提供的警報聲和系統(tǒng)提供的用戶界面聲音效果。例如,使用kSystemSoundID_UserPreferredAlert常量作為AudioServicesPlayAlertSound函數(shù)的參數(shù)將不會播放任何內(nèi)容。

舉例如下:

  // Get the main bundle for the app
    CFBundleRef mainBundle = CFBundleGetMainBundle ();
    
    // Get the URL to the sound file to play. The file in this case
    // is "tap.aif"
    CFURLRef soundFileURLRef;
    soundFileURLRef  = CFBundleCopyResourceURL(mainBundle,CFSTR ("2"),CFSTR ("caf"),NULL);
    SystemSoundID soundFileObject =0 ;
    AudioServicesCreateSystemSoundID (soundFileURLRef,
    &soundFileObject);
    self.soundFileObject = soundFileObject;

播放音樂

    AudioServicesPlaySystemSound (self.soundFileObject);

如何獲取.caf 文件呢?
通過終端命令,將簡單的mp3文件轉(zhuǎn)換,命令如下
afconvert /Users/Mina/Desktop/1.mp3 /Users/Mina/Desktop/2.caf -d ima4 -f caff -v

在典型的使用中,包含偶爾或者重復(fù)播放音樂,我們需要保留聲音的ID對象,知道應(yīng)用程序退出釋放對象。如果我們知道只使用一次,那我們可以播放聲音后里面銷毀對象,釋放內(nèi)存。

在支持振動的ios設(shè)備上運(yùn)行的app可以使用 system sound services 觸發(fā)該共功能。使用kSystemSoundID_Vibrate標(biāo)識符指定vibrate(振動) 選項(xiàng)。要觸發(fā)她,使用AudioServicesPlaySystemSound函數(shù)。

#import <AudioToolbox/AudioToolbox.h>
#import <UIKit/UIKit.h>
- (void) vibratePhone {
    AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);
}

iPod touch不支持此功能。

使用AVAudioPlayer 播放音樂更輕松

AVAudioPlayer 類提供了一個簡單的oc接口,用于播放聲音。如果我們的app不需要立體聲定位或者精確同步,并且不需要播放從網(wǎng)絡(luò)流捕獲的音頻。我們可以使用此類播放。
該類可以完成下列功能:

  • 播放任何持續(xù)時間的聲音
  • 播放文件或內(nèi)存緩存區(qū)的聲音
  • 循環(huán)聲音
  • 同時播放多個聲音(沒有精確同步)
  • 控制正在播放的每個聲音的相對播放水平
  • 尋找聲音文件中的特定點(diǎn),該文件吃吃快進(jìn)和快退等功能
  • 獲取音頻的電源數(shù)據(jù),該數(shù)據(jù)可以用來音頻水平的測量。

AVAudioPlayer 類允許我們在ios中使用可用的任何音頻格式播放音樂。具體可以參考 AVAudioPlayer Class Reference

如何配置音頻播放器

  • 1.指定一個音樂文件給音頻播放器
  • 2.準(zhǔn)備播放音頻播放器,獲取所需的硬件資源
  • 3.指定音頻播放器委托對象,該對象處理中斷以及播放完成的事件。

具體可看下面例子

-(void)avplay{
    NSString *soundFilePath =
    [[NSBundle mainBundle] pathForResource: @"1"
                                    ofType: @"mp3"];
    
    NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
    AVAudioPlayer *newPlayer =
    [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
                                           error: nil];
    self.player = newPlayer;
    [self.player prepareToPlay];
    [self.player setDelegate: self];
}

-(void)buttonEvent:(id)button{
    [self.player play];
}

我們可以設(shè)置音量

[self.player setVolume: 1.0];    // available range is 0.0 through 1.0

對于更多信息,可以看AVAudioPlayer Class Reference

使用音頻隊(duì)列服務(wù)播放控制聲音

音頻隊(duì)列服務(wù)增加了AVAudioPlayer的可用的播放功能。使用音頻隊(duì)列服務(wù)進(jìn)行播放可以實(shí)現(xiàn)下來功能:

  • 精確的安排播放音樂,允許同步
  • 在煮個緩沖區(qū)的基礎(chǔ)上精確的控制音量
  • 使用音頻文件流服務(wù)播放您從六中捕獲的音頻。

音頻隊(duì)列服務(wù)允許我們播放任何可用的音頻格式音樂。該技術(shù)不僅可以播放,也可以用來錄制。
對于更多細(xì)節(jié),可以看 Audio Queue Services Programming GuideAudio Queue Services Reference。 簡單代碼可以看SpeakHere

創(chuàng)建音頻隊(duì)列對象
創(chuàng)建音頻隊(duì)列對象進(jìn)行播放音樂,用一下幾步:

  • 1.創(chuàng)建數(shù)據(jù)結(jié)構(gòu)以管理音頻對象所需的信息,例如我們需要播放的數(shù)據(jù)的音頻格式。
  • 2.定義用于管理音頻隊(duì)列緩沖區(qū)的回調(diào)函數(shù)?;卣{(diào)使用音頻文件服務(wù)來讀取我們需要播放的文件。
  • 3.使用AudioQueueNewOutput函數(shù)實(shí)例化播放音頻隊(duì)列

代碼如下:

static const int kNumberBuffers = 3;
// Create a data structure to manage information needed by the audio queue
struct myAQStruct {
    AudioFileID                     mAudioFile;
    CAStreamBasicDescription        mDataFormat;
    AudioQueueRef                   mQueue;
    AudioQueueBufferRef             mBuffers[kNumberBuffers];
    SInt64                          mCurrentPacket;
    UInt32                          mNumPacketsToRead;
    AudioStreamPacketDescription    *mPacketDescs;
    bool                            mDone;
};
// Define a playback audio queue callback function
static void AQTestBufferCallback(
    void                   *inUserData,
    AudioQueueRef          inAQ,
    AudioQueueBufferRef    inCompleteAQBuffer
) {
    myAQStruct *myInfo = (myAQStruct *)inUserData;
    if (myInfo->mDone) return;
    UInt32 numBytes;
    UInt32 nPackets = myInfo->mNumPacketsToRead;
 
    AudioFileReadPackets (
        myInfo->mAudioFile,
        false,
        &numBytes,
        myInfo->mPacketDescs,
        myInfo->mCurrentPacket,
        &nPackets,
        inCompleteAQBuffer->mAudioData
    );
    if (nPackets > 0) {
        inCompleteAQBuffer->mAudioDataByteSize = numBytes;
        AudioQueueEnqueueBuffer (
            inAQ,
            inCompleteAQBuffer,
            (myInfo->mPacketDescs ? nPackets : 0),
            myInfo->mPacketDescs
        );
        myInfo->mCurrentPacket += nPackets;
    } else {
        AudioQueueStop (
            myInfo->mQueue,
            false
        );
        myInfo->mDone = true;
    }
}
// Instantiate an audio queue object
AudioQueueNewOutput (
    &myInfo.mDataFormat,
    AQTestBufferCallback,
    &myInfo,
    CFRunLoopGetCurrent(),
    kCFRunLoopCommonModes,
    0,
    &myInfo.mQueue
);

這段代碼直接復(fù)制到工程中會發(fā)生錯誤的.想要詳細(xì)了如何使用應(yīng)該看SpeakHere,改工程中包含以上代碼。

因?yàn)檫@篇文章只是講解音頻知識的大概。所以不會過多設(shè)計技術(shù)細(xì)節(jié)。

控制播放水平
音頻隊(duì)列對象為我們提供了兩種控制播放級別的方法。
最直接的方式是用下列代碼

Float32 volume = 1;    // linear scale, range from 0.0 through 1.0
AudioQueueSetParameter (
    myAQstruct.audioQueueObject,
    kAudioQueueParam_Volume,
    volume
);

這里說的播放水平就是音量大小啦。
我們還可以使用AudioQueueEnqueueBufferWithParameters函數(shù)設(shè)置音頻隊(duì)列緩沖區(qū)的播放級別。這可以讓我們指定音頻隊(duì)列來設(shè)置,產(chǎn)生的效果是,改隊(duì)列攜帶了這次操作,當(dāng)該隊(duì)列進(jìn)行播放是,該設(shè)置才能生效。

以上兩種方式更改音頻隊(duì)列將一直有效。

提高播放水平

我們可以通過下列方式獲取當(dāng)前播放水平:

  • 通過將kAudioQueueProperty_EnableLevelMetering屬性設(shè)置為true來啟用音頻隊(duì)列對象的計量
  • 查詢音頻隊(duì)列對象的kAudioQueueProperty_CurrentLevelMeter

此屬性的值是AudioQueueLevelMeterState結(jié)構(gòu)的數(shù)組,每個通道一個。

typedef struct AudioQueueLevelMeterState {
    Float32     mAveragePower;
    Float32     mPeakPower;
};  AudioQueueLevelMeterState;

播放多個音樂

要同時播放多個聲音,我們需要為每個聲音創(chuàng)建一個播放音頻隊(duì)列對象。對于每個音頻隊(duì)列,使用AudioQueueEnqueueBufferWithParameters函數(shù)安排第一個音頻緩沖區(qū)同時啟動。

從iOS 3.0開始,幾乎所有支持的音頻格式都可用于同步播放 - 即所有可以使用軟件解碼播放的格式,如表1-1所示。 對于處理器效率最高的多重播放,請使用線性PCM(未壓縮)或IMA4(壓縮)音頻。

使用OpenAL播放定位聲音

OpenAL框架中的ios中的提供的開源openAL 音頻api提供了一個優(yōu)化的界面,用于在播放期間定位立體生成中的聲音。播放,定位和移動聲音就想其他的平臺上一樣。openAL 還可以讓你混合聲音。openAL使用I / O單元進(jìn)行播放,從而實(shí)現(xiàn)最低延遲。

出于以上原因,openAL是基于ios的設(shè)備上播放游戲應(yīng)用程序中的聲音的最佳選擇。但是,openAL也是一般ios應(yīng)用程序音頻播放需求的不錯的選擇。

對于更多的使用,我們可以看OpenAL FAQ for iPhone OS。demo 可以看oalTouch

音頻錄制

ios 可以使用AVAudioRecorder類和Audio Queue Services 進(jìn)行音頻錄制。這些接口可以根據(jù)需要連接音頻硬件,管理內(nèi)存和使用編解碼器。錄制音頻的格式見上面的表。

錄制音頻可以在系統(tǒng)定義的輸入水平進(jìn)行。系統(tǒng)可以從用戶選擇的音頻源來獲取輸入信息-例如內(nèi)置的麥克風(fēng),或者如果耳機(jī)連接,那么輸入源也可以是耳機(jī)麥克風(fēng)或者其他輸入源。

使用AVAudioRecorder 類錄制音頻

在ios 中錄制聲音的最簡單的方式是使用AVAudioRecorder類。該類提供了一個高度簡化的oc接口,可以輕松的提供諸如暫?;謴?fù)錄制和處理音頻中斷等復(fù)雜操作。同時,我們也可以控制錄音的格式。

準(zhǔn)備錄音需要以下步驟:

  • 1.指定一個聲音文件地址
  • 2.設(shè)置音頻會話
  • 3.配置音頻錄制的初始化的狀態(tài)

app在啟動的時候就對此部分進(jìn)行配置是很好的時機(jī)。如下

- (void) audioRecorder {
    
    NSString *tempDir = NSTemporaryDirectory ();
    NSString *soundFilePath =
    [tempDir stringByAppendingString: @"sound.caf"];
    
    NSURL *newURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
    self.soundFileURL = newURL;
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    audioSession.delegate = self;
    [audioSession setActive: YES error: nil];
}

要處理中斷和錄制完成,我們需要增加AVAudioSessionDelegate和AVAudioRecorderDelegate協(xié)議的實(shí)現(xiàn)。如果我們的應(yīng)用程序也需要播放,我們需要參考AVAudioPlayerDelegate Protocol Reference

開啟錄制代碼如下

- (IBAction) recordOrStop: (id) sender {
    
        
        [[AVAudioSession sharedInstance]
         setCategory: AVAudioSessionCategoryRecord
         error: nil];
        
        NSDictionary *recordSettings =
        [[NSDictionary alloc] initWithObjectsAndKeys:
         [NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
         [NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
         [NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
         [NSNumber numberWithInt: AVAudioQualityMax],
         AVEncoderAudioQualityKey,
         nil];
        
        AVAudioRecorder *newRecorder =
        [[AVAudioRecorder alloc] initWithURL: self.soundFileURL  settings: recordSettings
                                       error: nil];
        self.soundRecorder = newRecorder;
        self.soundRecorder.delegate = self;
        [self.soundRecorder prepareToRecord];
        [self.soundRecorder record];    
}

想要了解更多AVAudioRecorder信息可以看AVAudioRecorder Class Reference

使用Audio Queue Services 錄制

用Audio Queue Services錄制音頻,首先我們需要實(shí)例化一個錄制音頻隊(duì)列對象,提供一個回調(diào)函數(shù)?;卣{(diào)將傳入的音頻數(shù)據(jù)存儲在內(nèi)存中以供立即使用,或者將其寫入文件以進(jìn)行長期存儲。

與回放功能一樣,我們可以通過查詢其kAudioQueueProperty_CurrentLevelMeter屬性從音頻隊(duì)列對象獲取當(dāng)前錄制音頻級別。

對于更多細(xì)節(jié)如何使用Audio Queue Services錄制音頻,可以參考Recording Audio inAudio Queue Services Programming Guide

解析流式音頻

要播放流式音頻內(nèi)容,例如來說網(wǎng)絡(luò)的內(nèi)容,我們需要用Audio Queue Services中的音頻文件流服務(wù)。音頻文件流服務(wù)從網(wǎng)絡(luò)比特流中的公共音頻文件容器格式解析音頻數(shù)據(jù)包和元數(shù)據(jù)。我們也可以使用他來解析磁盤文件中的數(shù)據(jù)包和元數(shù)據(jù)。

在ios中,我們可以解析的音頻文件和比特流數(shù)據(jù)形式如下

  • MPEG-1 Audio Layer 3, used for .mp3 files
  • MPEG-2 ADTS, used for the .aac audio data format
  • AIFC
  • AIFF
  • CAF
  • MPEG-4, used for .m4a, .mp4, and .3gp files
  • NeXT
  • WAVE

檢索到音頻數(shù)據(jù)包后,我們可以播放ios中支持的任何格式的恢復(fù)聲音。

想了解更多流信息,參考Audio File Stream Services Reference

ios中的音頻單元支持

ios提供了一組音頻處理插件,稱為音頻單元,可以在任何的應(yīng)用程序中使用。Audio Unit框架中的接口允許我們打開,連接和使用這些音頻單元。

使用audio unit框架的功能,我們需要將audio toolbox 框架添加到xocde工程中。 #import <AudioToolbox/AudioToolbox.h>

下列表就是在ios提供的 audio units

Audio unit Description
iPod Equalizer unit iPod EQ單元的類型是kAudioUnitSubType_AUiPodEQ,它提供一個簡單的,基于預(yù)設(shè)的均衡器,可以在app中使用。有關(guān)如何使用此音頻單元,參考Mixer iPodEQ AUGraph Test
3D Mixer unit 3D混音器單元的類型是kAudioUnitSubType_AU3DMixerEmbedded,可以讓我們混合多個音頻流,指定立體聲輸出平移,操作播放速率等。OpenAL構(gòu)建于此音頻單元之上,提供更適合游戲應(yīng)用程序的更高級API
Multichannel Mixer unit 多通道混音器單元,類型是kAudioUnitSubType_MultiChannelMixer,允許將多個單聲道或者立體聲音頻流混合到單個立體聲中。他還支持每個輸入的左/右平移。
Remote I/O unit 遠(yuǎn)程I/O單元,類型是kAudioUnitSubType_RemoteIO,連接到音頻輸入和輸出硬件,并支持實(shí)時I.O. aurioTouch
Voice Processing I/O unit 語音處理I/O,單元類型是kAudioUnitSubType_VoiceProcessingIO,具有I/O一單元的特性,并為雙向通信添加了回聲抑制和其他功能
Generic Output unit 通用輸出單元,類型是kAudioUnitSubType_GenericOutput,支持轉(zhuǎn)換為線型PCM格式和從線型PCM格式的轉(zhuǎn)換。;可以用于啟動和停止 graph
Converter unit 轉(zhuǎn)換器單元的類型是kAudioUnitSubType_AUConverter,允許我們將音頻數(shù)據(jù)從一種格式轉(zhuǎn)換成領(lǐng)一種格式。通常使用包含轉(zhuǎn)換器單元的遠(yuǎn)程I/O單元獲得此音頻單元的功能

更多細(xì)節(jié)參考 Audio Unit Hosting Guide for iOS

簡單demo aurioTouch

ios音頻最佳實(shí)戰(zhàn)

使用音頻提示
Tip Action
適當(dāng)使用壓縮視頻 對于aac,mp3,alac音頻,可以使用硬件輔助編碼器進(jìn)行解碼。雖然有效,但一次僅限一個音頻流。如果需要同時播放多個聲音,請使用IMA4(壓縮)或者線型PCM(未壓縮)格式存儲這些聲音
轉(zhuǎn)換為我們需要的數(shù)據(jù)格式和文件 Mac OS X中的afconvert工具允許我們轉(zhuǎn)換為各種音頻數(shù)據(jù)格式和文件類型。 具體用法可以用man afconvert 或者 Preferred Audio Formats in iOS
評估音頻內(nèi)存問題 使用音頻隊(duì)列服務(wù)播放聲音時,我們需要編寫一個回調(diào),將短段音頻數(shù)據(jù)發(fā)送到音頻隊(duì)列的緩沖區(qū)。在默寫情況下,最好將整個聲音文件加載到內(nèi)存中進(jìn)行播放,從而最大限度的減少磁盤訪問。在其他情況下,一次加載足夠的數(shù)據(jù)以保持緩沖區(qū)滿是最好的。
通過限制采樣率,位深度和通道來減小音頻文件大小 采樣率和每個采樣的位數(shù)會直接影響音頻文件的大小。如果您需要播放許多此類聲音或者長時間聲音,需要考慮減少這些值以減少音頻數(shù)據(jù)的內(nèi)存占用。例如,我們可以使用32KHZ或者更低的采樣率,而不是使用44.2KHZ的采樣率來獲取合理的音質(zhì)效果。使用單聲道音頻而不是立體聲(雙聲道)可減少文件大小。對于每個聲音asset,需要考慮單聲道是否可以滿足需求
選擇合適的技術(shù) 如果需要方便的高階界面來定位立體聲場中的聲音或者低延遲播放時,可以使用openAL。要解析文件或網(wǎng)絡(luò)流總的音頻數(shù)據(jù)包,請使用 Audio File Stream Services。要簡單播放單個或者多個聲音,請使用AVAudioRecorder類。對于音頻聊天,可以使用語音處理I/O單元。要播放從用戶的iTunes資料庫同步的音頻資源,使用iPod Library Access。當(dāng)我們需要音頻播放警報和用戶界面音效時,我們使用Core Audio’s System Sound Services。對于其他音頻應(yīng)用程序,包含流式音頻的播放,精確同步以及對傳入音頻數(shù)據(jù)包的訪問,使用Audio Queue Services.
低延遲的代碼 要獲得盡可能低的播放延遲,使用openAL或者直接使用I/O單元
ios的首先音頻格式

對于未壓縮(最高質(zhì)量的)音頻,請使用導(dǎo)報在caf文件中的16位小端線型PCM 音頻格式。我們可以使用afconvert 命令行工具來mac os x中將音頻文件轉(zhuǎn)換為此格式

/usr/bin/afconvert -f caff -d LEI16 {INPUT} {OUTPUT}

afconvert 工具允許我們轉(zhuǎn)換為各種音頻數(shù)據(jù)格式和文件類型。我們可以用 man afconvert 查看其功能?;蛘遖fconvert -h 查看

 man afconvert

對于一次播放一個聲音的壓縮音頻,以及當(dāng)不需要與ipod應(yīng)用程序同時播放音頻時,可以使用CAF或者m4a文件中打包成aac格式。

當(dāng)需要同時播放多個聲音時候,為了減少內(nèi)存使用量,使用IMA4(IMA/ADPCM)壓縮。這樣可以減少文件大小,但在解壓縮過程中對CPU的影響最小。與線型PCM數(shù)據(jù)一樣,在caf 文件中打包IMA4 數(shù)據(jù)。


Audio Session Programming Guide

multimedia Programming guide

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容