文章出處

SoundPool —— 適合短促且對反應速度比較高的情況(游戲音效或按鍵聲等)

下面介紹SoundPool的創建過程:

1. 創建一個SoundPool (構造函數)

public SoundPool(int maxStream, int streamType, int srcQuality) 
maxStream —— 同時播放的流的最大數量
streamType —— 流的類型,一般為STREAM_MUSIC(具體在AudioManager類中列出)
srcQuality —— 采樣率轉化質量,當前無效果,使用0作為默認值

 

初始化一個實例:
SoundPool soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0); 
創建了一個最多支持5個流同時播放的,類型標記為音樂的SoundPool。

2. 加載音頻資源 

可以通過四種途徑來記載一個音頻資源:
int load(AssetFileDescriptor afd, int priority) 
通過一個AssetFileDescriptor對象
int load(Context context, int resId, int priority) 
通過一個資源ID
int load(String path, int priority) 
通過指定的路徑加載
int load(FileDescriptor fd, long offset, long length, int priority) 
通過FileDescriptor加載

*API中指出,其中的priority參數目前沒有效果,建議設置為1。 

一個SoundPool能同時管理多個音頻,所以可以通過多次調用load函數來記載,如果記載成功將返回一個非0的soundID ,用于播放時指定特定的音頻。

int soundID1 = soundPool.load(this, R.raw.sound1, 1);
if(soundID1 ==0){
    // 記載失敗
}else{
   // 加載成功
}
int soundID2 = soundPool.load(this, R.raw.sound2, 1);
... 
這里加載了兩個流,并分別記錄了返回的soundID 。

需要注意的是, 
流的加載過程是一個將音頻解壓為原始16位PCM數據的過程,由一個后臺線程來進行處理異步,所以初始化后不能立即播放,需要等待一點時間。

 

 

3. 播放控制 

有以下幾個函數可用于控制播放:
final int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate) 
播放指定音頻的音效,并返回一個streamID 。
        priority —— 流的優先級,值越大優先級高,影響當同時播放數量超出了最大支持數時SoundPool對該流的處理;
        loop —— 循環播放的次數,0為值播放一次,-1為無限循環,其他值為播放loop+1次(例如,3為一共播放4次).
        rate —— 播放的速率,范圍0.5-2.0(0.5為一半速率,1.0為正常速率,2.0為兩倍速率)
final void pause(int streamID) 
暫停指定播放流的音效(streamID 應通過play()返回)。
final void resume(int streamID) 
繼續播放指定播放流的音效(streamID 應通過play()返回)。
final void stop(int streamID) 
終止指定播放流的音效(streamID 應通過play()返回)。

 

這里需要注意的是, 
1.play()函數傳遞的是一個load()返回的soundID——指向一個被記載的音頻資源 ,如果播放成功則返回一個非0的streamID——指向一個成功播放的流 ;同一個soundID 可以通過多次調用play()而獲得多個不同的streamID (只要不超出同時播放的最大數量);
2.pause()、resume()和stop()是針對播放流操作的,傳遞的是play()返回的streamID ;
3.play()中的priority參數,只在同時播放的流的數量超過了預先設定的最大數量是起作用,管理器將自動終止優先級低的播放流。如果存在多個同樣優先級的流,再進一步根據其創建事件來處理,新創建的流的年齡是最小的,將被終止;
4.無論如何,程序退出時,手動終止播放并釋放資源是必要的。

 

4. 更多屬性設置 

其實就是paly()中的一些參數的獨立設置:
final void setLoop(int streamID, int loop) 
設置指定播放流的循環.
final void setVolume(int streamID, float leftVolume, float rightVolume) 
設置指定播放流的音量.
final void setPriority(int streamID, int priority) 
設置指定播放流的優先級,上面已說明priority的作用.
final void setRate(int streamID, float rate) 
設置指定播放流的速率,0.5-2.0.

5. 釋放資源 

可操作的函數有:
final boolean unload(int soundID) 
卸載一個指定的音頻資源.
final void release() 
釋放SoundPool中的所有音頻資源.

下面對以上進行總結:

一個SoundPool可以:
1.管理多個音頻資源,通過load()函數,成功則返回非0的soundID;
2.同時播放多個音頻,通過play()函數,成功則返回非0的streamID;
3.pause()、resume()和stop()等操作是針對streamID(播放流)的;
4.當設置為無限循環時,需要手動調用stop()來終止播放;
5.播放流的優先級(play()中的priority參數),只在同時播放數超過設定的最大數時起作用;
6.程序中不用考慮(play觸發的)播放流的生命周期,無效的soundID/streamID不會導致程序錯誤。

 

示例代碼:

SoundPool sp;
HashMap<Integer, Integer> sounddata;
Context mcontext;
Boolean isLoaded;

//初始化聲音
public void InitSound() { sp = new SoundPool(5, AudioManager.STREAM_MUSIC, 0); sounddata = new HashMap<Integer, Integer>(); sounddata.put(1, sp.load(this, R.raw.mp31, 1)); sounddata.put(2, sp.load(this, R.raw.mp32, 1)); sp.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener(){ @Override public void onLoadComplete(SoundPool sound,int sampleId,int status){ isLoaded=true; Toast.makeText(mcontext, "音效加載完成!", Toast.LENGTH_SHORT); } }); } …… public void playSound(int sound, int number) { AudioManager am = (AudioManager) this .getSystemService(Context.AUDIO_SERVICE); float audioMaxVolumn = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC); float volumnCurrent = am.getStreamVolume(AudioManager.STREAM_MUSIC); float volumnRatio = volumnCurrent / audioMaxVolumn; sp.play(sounddata.get(sound), volumnRatio,// 左聲道音量 volumnRatio,// 右聲道音量 1, // 優先級 number,// 循環播放次數 1);// 回放速度,該值在0.5-2.0之間 1為正常速度 } …… //2.播放聲音 if(isLoaded==true) playSound(1,1);

 

經常有人在使用Soundpool時會報錯:

AudioFlinger could not create track, status: -12 

SoundPool: Error creating AudioTrack

可以從以下幾個方面解決此問題:

1.因為android系統一個設備只允許同時有32個音效文件播放,所以要你在程序中控制同時播放的音頻數。并且在Activity被覆蓋到下面或者鎖屏時對資源進行回收,即調用Soundpool對象的Release()方法。

For audio, there's a hard limit of 32 active AudioTrack objects per device (not per app: you need to share those 32 with rest of the system), and AudioTrack is used internally beneath SoundPool, ToneGenerator, MediaPlayer, native audio based on OpenSL ES, etc. But the actual AudioTrack limit is < 32; it depends more on soft factors such as memory, CPU load, etc. Also note that the limiter in the Android audio mixer does not currently have dynamic range compression, so it is possible to clip if you have a large number of active sounds and they're all loud.

2.每個音頻文件大小要小于100k;可以修改音頻碼率來壓縮音頻大小,把 128kbps改成32kbps ;

3.每次播放一次,soundpool.play方法有個參數是控制重復播放次數的,將之設置為0,即只播放一次;

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()