0
点赞
收藏
分享

微信扫一扫

Pro Android学习笔记(一二八):Media Frameworks(3):用SoundPool的音频播放


作者@恺风Wei。

MediaPlayer在一个时间只能处理一个音频或视频文件,如果我们需要同时播放多个音频文件,可以创建多个MediaPlayer。如果我们有若干个的音频需要播放,还可以使用SoundPool类,SoundPool类使用了MediaPlayer,但我们不需要访问MediaPlayer API,而是简洁使用SoundPool API。

SoundPool只能处理本地媒体资源。SoundPool为了提高播放性能,使用了内存,使用总量限制为1MB。放入内存多少,和比特率、采样频率、channel数(单声道、双声道,杜比的5.1声道)以及音频的长度有关,如果太大,可能会导致加载失败。SoundPool适合短小但经常反复播放的若干音频。

小例子

Pro Android学习笔记(一二八):Media Frameworks(3):用SoundPool的音频播放_ide

我们有5个音频资源,4个位于res/raw,1个位于assets/下面,这些都是时间很短的音频文件。crickets.mp3作为背景音乐不断地循环放松,而其他的4个音乐分别隔某个时间间隔(例如5秒)播放一次。

Pro Android学习笔记(一二八):Media Frameworks(3):用SoundPool的音频播放_循环播放_02

UI很简单,上面是一个ToggleButton,在暂停和播放之间切换,下面是debug信息的显示。

代码分析

我们重点关注代码如何具体利用SoundPool来实现音频播放、循环播放、暂停、继续播放的控制。

public class SoundPoolActivity extends Activity implements SoundPool.OnLoadCompleteListener{ 
    private SoundPool soundpool = null; 
     private AudioManager audioManager = null;      
     private int sid_background,sid_roar,sid_chimp,sid_rooster,sid_bark;    
     … … 
      
     @Override 
     protected void onResume() {  
         super.onResume(); 
         /* 【1】创建我们的SoundPool对象:第一个参数是SoundPool同时共同播放多上个音乐,注意是最大的同时播放数,而不是由多少音频资源。第二参数是音频类型,一般为STREAM_MUSIC;第三个参数目前没有使用,reference建议为0 。*/        soundpool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);  
         /* 【3.pre】将资源load()到SoundPool后,才可以进行播放,因此,需要完成load的回调函数。*/
        soundpool.setOnLoadCompleteListener(this); 

         // 用于获取当前的音量,后面有用 
         audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
         /* 【2】SoundPool load入音频资源,音频流会从文件中解码,放入内存,这提高了SoundPool的性能。我们给出了用资源和fd方式。对于SD卡,可以用soundpool.load("/mnt/sdcard/abc.mp3",1); load()参数的最后一位是PRIORITY,目前没有真正使用,reference建议设置为1,以便兼容未来版本。*/
         sid_background = soundpool.load(this, R.raw.crickets, 1);  
         sid_roar = soundpool.load(this, R.raw.roar, 1); 
         sid_rooster = soundpool.load(this, R.raw.rooster, 1); 
         sid_chimp = soundpool.load(this, R.raw.chimp, 1); 
         
        try{ 
             AssetFileDescriptor afd = getAssets().openFd("dogbark.mp3"); 
             sid_bark = soundpool.load(afd.getFileDescriptor(), 0, afd.getLength(), SOUNDPOOL_LOAD_PRIORITY);
             afd.close();         }catch(Exception e){  
             e.printStackTrace(); 
         } 
        
         debug(… …);          
     } 

     @Override 
     protected void onPause() {  
         soundpool.release(); //停止并释放资源,而停止某个媒体流的播放可以是用stop(sid);SoundPool会释放该媒体流的资源。        soundpool = null; 
         super.onPause(); 
     } 
     
     public void doClick(View v){ 
         debug … …  
        if(((ToggleButton)v).isChecked()){ 
             soundpool.autoResume(); //恢复停止播放的音频流,在本例,在某些情况下,不能重新播放背景音,这是因为我们设置了最大同时播放数为5个,假设5个音频同时播放时,我们按了暂停,resume()是刚好又轮到某个音频流再次播放,这时同时播放数会超过设置的最大数,SoundPool会让出最早的音频流,腾出位置给新的声音。        }else{ 
             soundpool.autoPause();   //会暂停当前播放的音频流,在本例,背景音频流会播放,但是对于通过queueSound()的未来播放不会被终止。 
        } 
     } 

     @Override //load完后,进行播放,
    public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { 
         debug("sid " + sampleId + " status=" + status);
         
         if(status != 0) 
             return;  
         // 获取当前音量,音量范围:0-1.0 
        final float currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
                 / (float)audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
         
         // 如果是背景声音,则不断循环播放,如果是其他,则已某个间隔时间播放 
         /* play() 第一个参数是音频的id;第二和第三个分别是左右音量;第四个参数是音频流的优先级别,0是最低的基本;第5参数标识是否循环播放,0标识不循环,-1表示循环;第6个参数是播放速率,1.0标识按正常速率播放,有效范围是0.5-2.0。如果成功返回音频流的Id,失败返回0  */ 
        if(soundPool.play(sid_background, currentVolume, currentVolume, 1, -1, 1.0f) == 0){ 
             debug("Failed to start sound " + sampleId);            
         }else if(sampleId == sid_chimp){ 
             queueSound(sampleId,5000,currentVolume);  //延后定期发送 
         }else if(sampleId == sid_rooster){ 
             queueSound(sampleId, 17000, currentVolume); 
         }else if(sampleId == sid_roar){ 
             queueSound(sampleId, 12000, currentVolume); 
         }else if(sampleId == sid_bark){ 
             queueSound(sampleId, 7000, currentVolume); 
         } 
         
     } 
     //利用handler实现固定时间间隔的播放,不同的音频流的间隔时间均不同,我们可以听到1~5个音频的混音效果。
     private void queueSound(final int sid , final long delay , final float volume){
         new Handler().postDelayed(new Runnable() {              
             @Override 
             public void run() {  
                 debug("sid " + sid + " queueSound() run in "  + Thread.currentThread().getName());
                 if(soundpool == null) //如果已经onPause(),即soundpool==null,将停止播放及未来播放
                    return;  

                 if(soundpool.play(sid, volume, volume, 1, 0, 1.0f) == 0){ 
                         debug("Fail to start sound " + sid);  
                  }  
                 //每隔delay的时间,重复播放 
                 queueSound(sid, delay, volume); 
             } 
         }, delay); 
     } 

    private void debug(String info){ 
        … …     
     } 
 }

小例子代码在:Pro Android学习:media framworks小例子


举报

相关推荐

0 条评论