天天看點

iPhone 應用開發:音頻播放

在 iPhone 應用或者是遊戲的開發過程中,對聲音的支援是必不可少的。在我做過的幾個應用中,每個都涉及到音效,是以在這裡做個簡單的歸納,很多都是引用自《iPhone Application Programming Guide》(需要有 Apple ID 才能打開連結),加了一些實際使用的經驗。

iPhone OS 主要提供以下了幾種播放音頻的方法:

  • System Sound Services
  • AVAudioPlayer 類
  • Audio Queue Services
  • OpenAL

1. System Sound Services

System Sound Services 是最底層也是最簡單的聲音播放服務,調用 AudioServicesPlaySystemSound這個方法就可以播放一些簡單的音頻檔案,使用此方法隻适合播放一些很小的提示或者警告音,因為它有很多限制:

■ 聲音長度要小于 30 秒

■ In linear PCM 或者 IMA4 (IMA/ADPCM) 格式的

■ 打包成 .caf, .aif, 或者 .wav 的檔案

■ 不能控制播放的進度

■ 調用方法後立即播放聲音

■ 沒有循環播放和立體聲控制

另外,它還可以調用系統的震動功能,方法也很簡單。具體的代碼可以參考官方的示例 SysSound

,但是官方的示例隻有一些簡單的用法,從文檔中我們發現可以通過AudioServicesAddSystemSoundCompletion 方法為音頻播放添加 CallBack 函數,有了 CallBack 函數我們可以解決不少問題,比如可以克服 System Sound Services 本身不支援循環播放的問題。以下代碼可以實作一個在程式中循環播放的背景音樂:

static void completionCallback (SystemSoundID mySSID) {

// Play again after sound play completion

AudioServicesPlaySystemSound(mySSID);

}

- (void) playSound {

// Get the main bundle for the app

CFBundleRef mainBundle;

SystemSoundID soundFileObject;

mainBundle = CFBundleGetMainBundle ();

// Get the URL to the sound file to play

CFURLRef soundFileURLRef = CFBundleCopyResourceURL (

mainBundle,

CFSTR ("background"),

CFSTR ("wav"),

NULL

);

// Create a system sound object representing the sound file

AudioServicesCreateSystemSoundID (

soundFileURLRef,

&soundFileObject

);

// Add sound completion callback

AudioServicesAddSystemSoundCompletion (soundFileObject, NULL, NULL,

completionCallback,

(void*) self);

// Play the audio

AudioServicesPlaySystemSound(soundFileObject);

2. AVAudioPlayer 類

AVAudioPlayer 是 AVFoundation.framework 中定義的一個類,是以使用要先在工程中引入 AVFoundation.framework。我們可以把 AVAudioPlayer 看作是一個進階的播放器,它支援廣泛的音頻格式,主要是以下這些格式:

■ AAC

■ AMR(AdaptiveMulti-Rate, aformatforspeech)

■ ALAC(AppleLossless)

■ iLBC(internetLowBitrateCodec, anotherformatforspeech)

■ IMA4(IMA/ADPCM)

■ linearPCM(uncompressed)

■ µ-lawanda-law

■ MP3(MPEG-1audiolayer3

AVAudioPlayer 可以播放任意長度的音頻檔案、支援循環播放、可以同步播放多個音頻檔案、控制播放進度以及從音頻檔案的任意一點開始播放等,更進階的功能可以參考 AVAudioPlayer 的文檔。要使用 AVAudioPlayer 的對象播放檔案,你隻需為其指定一個音頻檔案并設定一個實作了AVAudioPlayerDelegate 協定的 delegate 對象。這裡舉一個簡單的例子,和上一個例子一樣,實作一直循環播放的背景音樂:

(void) playBackgroundSoundEffect {

NSString *soundFilePath =

[[NSBundle mainBundle] pathForResource: @"background"

ofType: @"wav"];

NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];

AVAudioPlayer *newPlayer =

[[AVAudioPlayer alloc] initWithContentsOfURL: fileURL

error: nil];

[fileURL release];

self.player = newPlayer;

[newPlayer release];

[self.player prepareToPlay];

[self.player setDelegate: self];

self.player.numberOfLoops = -1; // Loop playback until invoke stop method

[self.player play];

可以看到,隻要将 AVAudioPlayer 的 numberOfLoops 屬性設為負數,音頻檔案就會一直循環播放直到調用 stop 方法。

AVAudioPlayer 同樣支援 Callback,這是 AVAudioPlayerDelegate 的一個可選 delegate 方法:

- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) player successfully: (BOOL) flag {

if (player == self.player && flag == YES) {

NSLog(@"Playback finish.");

}

另外,你可以随時控制 AVAudioPlayer 對象的播放、暫停以及停止,通過判斷對象的狀态,分别調用play、pause 和 stop 方法即可:

- (IBAction) playOrPause: (id) sender {

// if playing, pause

if (self.player.playing) {

[self.player pause];

// if stopped or paused, start playing

} else {

[self.player play];

雖然 AVAudioPlayer 可以播放很多格式,但是我們在實際開發過程中還是最好使用一些沒有壓縮的格式,比如 WAVE 檔案,這樣可以減少系統處理單元的資源占用,以便更好的完成程式的其他功能。另外,在使用 AVAudioPlayer 連續播放 mp3 這類經過壓縮的音頻檔案時,在連接配接處可能出現一定的間隔時間。

3. Audio Queue Services

如果以上兩種音頻播放的解決方案都無法滿足你的需求,那麼我想你肯定需要使用 Audio Queue Services。使用 Audio Queue Services 對音頻進行播放,你可以完全實作對聲音的控制。例如,你可以在聲音資料從檔案讀到記憶體緩沖區後對聲音進行一定處理再進行播放,進而實作對音頻的快速/慢速播放的功能。

因為 Audio Queue Services 相對複雜很多,Apple 官方已經把它整理為一本書了,具體可以參考 Audio Queue Services Programming Guide 和 SpeakHere 的程式示例。

4. OpenAL

OpenAL 是一套跨平台的開源的音頻處理接口,與圖形處理的 OpenGL 類似,它為音頻播放提供了一套更加優化的方案。它最适合開發遊戲的音效,用法也與其他平台下相同。

iPhone 支援 OpenAL 1.1,我沒有在實際開發中使用過,具體的文檔可以參考 OpenAL 的網站http://openal.org 和 oalTouch 的程式示例。

繼續閱讀