android 音頻播放總結 soundlPool,MediaPlay

轉自:https://www.cnblogs.com/minyc/p/myc201607201527.html


soundlPool 用於小音頻的播放多個同時播放。

使用步驟:

步驟一:

  首先下載音頻文件可以將其放入assets文件夾下或者res下的raw文件夾下,區別在於assets下可以再新建文件夾而raw不行,assets內部單個文件超過1m時可能存在bug而raw不會。soundpool的音頻文件大小不能超過1M同時時間超過5-6秒可能會出錯。

步驟二:

  構造實例

  SoundPool(int maxStreams, int streamType, int srcQuality) 參數依次是:

  • ①指定支持多少個聲音,SoundPool對象中允許同時存在的最大流的數量,該值太大就會報錯AudioFlinger could not  create track, status: -12 ,就聽不到聲音
  • ②指定聲音類型,流類型可以分爲STREAM_VOICE_CALLSTREAM_SYSTEMSTREAM_RING,STREAM_MUSIC 和STREAM_ALARM四種類型。在AudioManager中定義。
  •   ③指定聲音品質(採樣率變換質量),一般直接設置爲0!

  在低版本中可以用上述構造方法,而API 21(Android 5.0)後這個構造方法就過時了! 而用到一個SoundPool.Builder的東東,我們要實例化SoundPool只需調用:

SoundPool.Builder spb = new SoundPool.Builder();
spb.setMaxStreams(10);
spb.setAudioAttributes(null);    //轉換音頻格式
SoundPool sp = spb.build();      //創建SoundPool對象

要使用上述代碼的話,TargetSDK版本要設置大於等於21哦!而且如果minSDK版本小於21 會出現下面的提醒:

 

步驟三:

  加載聲音資源文件

  • load(Context context, int resId, int priority) //從APK資源載入
  • load(String path, int priority)
  • load(FileDescriptor fd, long offset, long length, int priority)
  • load(AssetFileDescriptor afd, int priority)

參數介紹

  • context:上下文
  • resId:資源id,如蔥raw文件獲取填寫R.raw.xxx
  • priority:沒什麼用的一個參數,建議設置爲1,保持和未來的兼容性
  • path:文件路徑,文件的絕對路線,如存放在sd卡中的音頻
  • FileDescriptor:貌似是流吧,這個我也不知道  http://www.fengfly.com/plus/view-214059-1.html
  • AssetFileDescriptor:從asset目錄讀取某個資源文件,context.getAssets().openFd("xxx"),xxx表示文件名

上述方法都會返回一個聲音的ID,Integer類型,我們可以通過建立一個Map<Integer,Integer> 來存儲和獲取聲音方法如下,

Map<Integer,Integer> map=new HashMap<Integer, Integer>();
map.put(1,soundPool.load(context.getAssets().openFd("FadeOut.ogg"),1));

注意:

當調用load方法的時候實際就是把音效加載到了 SoundPool中,此時返回的streamId其實就是該音效在SoundPool中的Id,這個ID從0還是1來着(有點記不清了)增,不過要注意的是,不要超過  256  這個臨界點。也就是說第257個聲音加載進去後,調用play方法其實是播不出來的,說不定還會擠掉一些前面加載好的聲音。這個256的限制通過查看SDK源碼基本就能瞭解清楚,它底層就那麼實現的,用一個類似堆棧來存。

步驟四:

播放音頻文件

  play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate),其返回值爲一個int類型的數字

  參數依次是:

  • soundID:Load()返回的聲音ID號,以上可以通過map.get(1)獲取
  • leftVolume:左聲道音量設置  一般爲0-1,默認填1
  • rightVolume:右聲道音量設置 一般爲0-1,默認填1
  • priority:指定播放聲音的優先級,數值越高,優先級越大。默認填0
  • loop:指定是否循環:-1表示無限循環,0表示不循環,其他值表示要重複播放的次數
  • rate:指定播放速率:1.0的播放率可以使聲音按照其原始頻率,而2.0的播放速率,可以使聲音按照其 原始頻率的兩倍播放。如果爲0.5的播放率,則播放速率是原始頻率的一半。播放速率的取值範圍是0.5至2.0。

  如果SoundPool剛調完加載load函數之後,直接調用SoundPool的play函數可能出現error "sample 1 not READY",所以建議,調用加載資源函數load之後,實現資源加載結束的監聽函數,在這個監聽到資源加載結束之後,播放音頻文件。

soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
            @Override
            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                soundPool.play(map.get(1),1,1,0,0,1);
            }
        });

 

步驟五:

去除音頻或者停止播放重置資源

soundPool.pause(int streamID)  暫停指定播放流的音效
  • streamID:應通過play()返回

soundPool.resume(int streamID)  繼續播放指定播放流的音效

  • streamID:應通過play()返回
soundPool.stop(int streamID) 終止指定播放流的音效
  • streamID:應通過play()返回
soundPool.unload(int soundID) 卸載一個指定的音頻資源.
  • soundID:Load()返回的聲音ID號,以上可以通過map.get(1)獲取
 soundPool.release(); 釋放SoundPool中的所有音頻資源.


注意,:
1.play()函數傳遞的是一個load()返回的soundID——指向一個被記載的音頻資源 ,如果播放成功則返回一個非0的streamID——指向一個成功播放的流 ;同一個soundID 可以通過多次調用play()而獲得多個不同的streamID (只要不超出同時播放的最大數量);
2.pause()、resume()和stop()是針對播放流操作的,傳遞的是play()返回的streamID ;
3.play()中的priority參數,只在同時播放的流的數量超過了預先設定的最大數量是起作用,管理器將自動終止優先級低的播放流。如果存在多個同樣優先級的流,再進一步根據其創建事件來處理,新創建的流的年齡是最小的,將被終止;
4.無論如何,程序退出時,手動終止播放並釋放資源是必要的。
5.如果你音效多,也不要指望unload方法來清除掉一些音效後再load新的進去,雖然unload後音效卸載了,但是前面分給它在SoundPool裏面的Id可沒有釋放掉,也就是說這個時候你load新的進去只會在後面繼續累加,然後累加多了就超過256了,然後就就聽不到聲音,然後就沒有然後了。要想徹底清掉前面的音效請使用release方法,它會連內存中佔用的資源一起釋放掉。
6.其他還有點什麼呢,load需要一點點時間,load後不要馬上unload,load ---play--unload的做法並不可取,不要load太大的音效,它只會申請1M的內存空間。SoundPool出錯後通常會看到retuen的值是0。

mediaPlay播放音頻文件。
使用步驟:
1.新建對象
MediaPlayer mp = new MediaPlayer();//使用這種方式獲取對象是因爲你所播放的音頻文件在sd卡或者是網絡音頻等,隨後需要添加(setDataSource)自己需要播放的音頻,使用這種方式新建的對象需要將播放器進入prepare狀態,下面會說。
MediaPlayer mp = MediaPlayer.create(this, R.raw.music);//使用這種方式直接將工程中的音頻播放,使用這種方式不用將播放器進入prepare狀態,因爲在creat時已經自己做了這步操作。
2.添加需要播放的音頻文件
mediaplay播放的音頻主要來自於4個來源
1、res文件夾下的raw文件,添加方式如下
  MediaPlayer.create(this, R.raw.test);
2、src/main下的assets文件,添加方式如下
  AssetFileDescriptor fileDescriptor = getAssets().openFd("music.mp3");
  mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(), fileDescriptor.getLength());
3、網絡上的音頻文件
  mp.setDataSource("http://www.xxxxxxx/music.mp3");
4、本地sd卡下的文件
  mp.setDataSource("/sdcard/music.mp3");


3.控制播放器進入prepare狀態
prepare()和prepareAsync() 提供了同步和異步兩種方式設置播放器進入prepare狀態,需要注意的是,如果MediaPlayer實例是由create方法創建的,那麼第一次啓動播放前不需要再調用prepare()了,因爲create方法裏已經調用過了。
 start()
 pause()和stop()比較簡單,起到暫停和停止播放的作用
 seekTo()是定位方法,可以讓播放器從指定的位置開始播放,需要注意的是該方法是個異步方法,也就是說該方法返回時並不意味着定位完成,尤其是播放的網絡文件,真正定位完成時會觸發OnSeekComplete.onSeekComplete(),如果需要是可以調用setOnSeekCompleteListener(OnSeekCompleteListener)設置監聽器來處理的。
 release()可以釋放播放器佔用的資源,一旦確定不再使用播放器時應當儘早調用它釋放資源。
 reset()可以使播放器從Error狀態中恢復過來,重新會到Idle狀態。
 setLooping()設置循環播放
 setOnCompletionListener(MediaPlayer.OnCompletionListener listener)播放完成監聽。
 setOnErrorListener(MediaPlayer.OnErrorListener listener)播放錯誤監聽

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章