Android短音频播放

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wang_yong_hui_1234/article/details/85239358

在项目开发过程中,如果需要播放音频,我们通常会用MediaPlayer。但是MediaPlayer用起来并不是很方便,使用中也会遇到一些问题。对于一些短音频,比如一些提示音,像这种短音频我们可以使用SoundPool。

一,SoundPool基本介绍

1,创建SoundPool实例
SoundPool(int maxStream, int streamType, int srcQuality)

  • maxStream —— 同时播放的流的最大数量
  • streamType —— 流的类型,一般为STREAM_MUSIC(具体在AudioManager类中列出)
  • srcQuality —— 采样率转化质量,当前无效果,使用0作为默认值

初始化一个实例
SoundPool soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);

2,加载资源
通常我们会把音频文件放在raw下,SoundPool推荐的语音格式是OGG,不过mp3文件也没问题,最好还是按推荐的来。

可以通过四种途径来记载一个音频资源:

  1. int load(AssetFileDescriptor afd, int priority)
    通过一个AssetFileDescriptor对象
  2. int load(Context context, int resId, int priority)
    通过一个资源ID通过一个资源ID
  3. int load(String path, int priority)
    通过指定的路径加载通过指定的路径加载
  4. int load(FileDescriptor fd, long offset, long length, int priority)
    通过FileDescriptor加载

其中的priority参数目前没有效果,建议设置为1

注意:SoundPool的加载过程是一个将音频解压为原始16位PCM数据的过程,由一个后台线程来进行处理异步,所以初始化后不能立即播放,需要等待一点时间

3,流程控制
①,播放

final int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate) 

soundID:播放音频ID,比如同时load多个资源,那么第一个就是1,以此类推。
leftVolume:左声道音量
rightVolume:右声道音量
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) 

③,继续

final void resume(int streamID) 

④,停止

final void stop(int streamID) 

⑤,释放资源

final void release()

4,其他调用方法

  • final void setLoop(int streamID, int loop)
    设置指定播放流的循环
  • final void setVolume(int streamID, float leftVolume, floatrightVolume)
    设置指定播放流的音量
  • final void setPriority(int streamID, int priority)
    设置指定播放流的优先级
  • final void setRate(int streamID, float rate)
    设置指定播放流的速率

5,资源加载监听

       soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
            @Override
            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                Log.i(TAG, "onLoadComplete: 资源加载完成");
            }
        });

二,封装工具类

public class SoundPlayUtils {
 // SoundPool对象
private static SoundPool mSoundPlayer = new SoundPool(10,AudioManager.STREAM_SYSTEM, 5);
private static volatile SoundPlayUtils soundPlayUtils;

/**
 * 初始化
 *
 * @param context
 */
public static SoundPlayUtils init(Context context) {
    if (soundPlayUtils == null) {
        synchronized (SoundPlayUtils.class) {
            if (soundPlayUtils == null) {
                soundPlayUtils = new SoundPlayUtils(context);
            }
        }
    }
    return soundPlayUtils;
}

public SoundPlayUtils(Context context) {
    //加载3个音频文件
    mSoundPlayer.load(context, R.raw.one, 1);//1
    mSoundPlayer.load(context, R.raw.two, 1);//2
    mSoundPlayer.load(context, R.raw.three, 1);//3

}

/**
 * 播放声音
 *
 * @param soundID
 */
public void play(int soundID) {
    Log.d("####","play voice:"+soundID);
    mSoundPlayer.play(soundID, 1, 1, 0, 0, 1);
}

在需要的时候调用该工具类,代码如下:

SoundPool.init(mApplication).play(1);//调用第一个音频文件

那么问题来了,如果这样第一次调用会播放无效,原因是因为load加载资源是在子线程中进行的,会有一定延时,资源没有加载完成是无法播放的。当然如果我先调用SoundPool.init(mApplication)进行加载,之后再进行播放也是可以的。既然是工具类其实可以不用单例来实现,我们通常会用静态方法来实现。

三,工具类改进

public class SoundPlayUtils {
    // SoundPool对象
    private static SoundPool mSoundPlayer = new SoundPool(10, AudioManager.STREAM_SYSTEM, 5);
    private static SoundPlayUtils soundPlayUtils;

    public static SoundPlayUtils init(Context context) {
      if (soundPlayUtils == null) {
          soundPlayUtils = new SoundPlayUtils();
       }
        mSoundPlayer.load(context, R.raw.one, 1);
        mSoundPlayer.load(context, R.raw.two, 1);
        mSoundPlayer.load(context, R.raw.three, 1);
       return soundPlayUtils;
     }

     /**
      * 播放声音
      *
      * @param soundID
      */
      public static void play(int soundID) {
           mSoundPlayer.play(soundID, 1, 1, 0, 0, 1);
      }
      
      /**
      * 释放资源
      */
      public static void relesse() {
          mSoundPlayer.release();
      }
}

在项目中的调用

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化
        SoundPlayUtils.init(getApplicationContext());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //释放资源
        SoundPlayUtils.relesse();
    }
}

猜你喜欢

转载自blog.csdn.net/wang_yong_hui_1234/article/details/85239358