Android SoundPool 播放音效

Android 预设的多媒体框架 (multimedia framework) 是 OpenCore

Android 多媒体框架 OpenCore

OpenCore 的优点是兼顾了 跨平台的移植性,而且已经过多方验证,所以相对来说较為稳定;但是其缺点是过於庞大复杂, 需要耗费相当多的时间去维护

Android 2.0 引进了架构稍微简洁一点的 Stagefright ,当然没有完全抛弃 OpenCore,主要是做了一个 OMX 层,仅仅是对 OpenCore 的 omx-component 部分做了引用

Android 多媒体框架处于 Android 架构的第三层( Libraries ) 的 Media Framework

如果想知道 Android 这套多媒体框架支持什么类型的音视频数据可以访问 Supported Media Formats

SoundPool 播放音效

SoundPool 一般用来播放密集,急促而又短暂的音效, 比如特技音效:Duang~,游戏用得较多

我们可以使用 SoundPool 给 APP 添加诸如酷狗音乐进去的时候播放"哈喽,酷狗"

也可以使用 SoundPool 给 APP 添加收到推送 信息或者新的聊天信息,然后播放提示音

SoundPool 对象可以看作是一个可以从APK中导入资源 或者从文件系统中载入文件的样本集合

SoundPoll 利用 MediaPlayer 服务为音频解码为一个原始 16 位 PCM 流

这个特性使得应用程序可以进行流压缩,而无须忍受在播放音频时解压所带来的 CPU 负载和延时

SoundPool使用 音效池 的概念来管理多个 播放流 ,如果超过流的最大数目, SoundPool会基于优先级自动停止先前播放的流

另外,SoundPool还支持自行设置声音的品质、音量、 播放比率等参数

创建 SoundPool 实例

在 API 21 (Android 5.0) 之前可以使用下面这个构造方法

SoundPool(int maxStreams, int streamType, int srcQuality)

参数说明

参数 说明
maxStreams 指定支持多少个声音,SoundPool 对象中允许同时存在的最大流的数量
streamType 指定声音类型,在 AudioManager 定义了以下几种流类型
STREAM_VOICE_CALL
STREAM_SYSTEM
STREAM_RING
STREAM_MUSIC
STREAM_ALARM
srcQuality 指定声音品质(采样率变换质量),一般直接设置为 0

但在 API 21(Android 5.0) 及以上版本,这个构造方法被废弃了,取而代之的是使用 SoundPool.Builder() 方法

SoundPool.Builder spb = new SoundPool.Builder();
spb.setMaxStreams(10);
spb.setAudioAttributes(null);    //转换音频格式
SoundPool sp = spb.build();      //创建SoundPool对象

因此在使用过程中要对系统的版本进行判断,以选择合适的方法

// 版本大于等于 21 (Anndroid 5.0)
SoundPool sp = null;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {  
    SoundPool.Builder spb = new SoundPool.Builder();
    spb.setMaxStreams(10);
    spb.setAudioAttributes(null);    //转换音频格式
    sp = spb.build();      //创建SoundPool对象 
} else {
    sp = SoundPool(10, AudioManager.STREAM_SYSTEM, 5);
}

SoundPool 常用方法

  1. load()

    用于加载声音资源

    load() 方法有 4 种变体,每种方法都会返回一个声音的 ID

    load(Context context, int resId, int priority)
    load(String path, int priority)
    load(FileDescriptor fd, long offset, long length, int priority)
    load(AssetFileDescriptor afd, int priority)
    

    参数说明

    参数 说明
    context 上下文
    resId 资源id
    priority 没什么用的一个参数,建议设置为1,保持和未来的兼容性
    path 文件路径
    FileDescriptor 文件描述符
    AssetFileDescriptor 从 asset 目录读取某个资源文件,用法
    AssetFileDescriptor descriptor = assetManager.openFd("biaobiao.mp3")
  2. play()

    播放控制

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

    参数说明

    参数 说明
    soundID load() 返回的声音 ID 号
    leftVolume 左声道音量设置
    rightVolume 右声道音量设置
    priority 指定播放声音的优先级,数值越高,优先级越大。
    loop 指定是否循环
    -1 表示无限循环
    0 表示不循环
    其它值表示要重复播放的次数
    rate 指定播放速率,播放速率的取值范围是 0.5 至 2.0
    1.0 的播放率可以使声音按照其原始频率
    2.0 的播放速率,可以使声音按照其原始频率的两倍播放
    0.5的播放率,则播放速率是原始频率的一半
  3. release()

    释放资源

    release()
    release(int soundID)
    

    release() 方法用于释放所有 SoundPool 对象占据的内存和资源

范例

接下来我们就使用 SoundPool 来播放 "哆啦A梦" 的声音,演示效果如下

当点击按钮的时候会,会播放 "哆啦A梦" 的铃声


好好玩,很魔幻的声音

  1. 创建一个 空的 Android 项目 cn.twle.android.SoundPoll

  2. 在 res 目录上点右键,然后选择 Android resource directory,在弹出的界面中 Resource type 项选择 raw 然后点击 OK

  3. app 目录上点右键,然后选择 Folder->Assets Folder 创建 assets 目录

  4. 下载音频文件 /static/i/android/biaobiao.mp3 并放到 res/raw 目录下

  5. 下载音频文件 /static/i/android/biaobiao.mp3 并放到 assets 目录下

  6. 修改 activity_main.xml

    <?xml version="1.0" encoding="utf-8" ?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
        <Button
            android:id="@+id/btn_play1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="播放声音1" />
    
        <Button
            android:id="@+id/btn_play2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="播放声音2" />
    
        <Button
            android:id="@+id/btn_play3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="播放声音3" />
    
        <Button
            android:id="@+id/btn_play4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="播放声音4" />
    
        <Button
            android:id="@+id/btn_play5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="播放声音5" />
    
        <Button
            android:id="@+id/btn_release"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="释放 SoundPool" />
    </LinearLayout>
    
  7. 修改 MainActivity.java 创建 SoundPool 实例并播放 res/raw 目录下的 biaobiao.mp3 文件

    package cn.twle.android.soundpoll;
    
    import android.content.res.AssetManager;
    import android.media.AudioManager;
    import android.media.SoundPool;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.Button;
    
    import java.util.HashMap;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    
        private Button btn_play1;
        private Button btn_play2;
        private Button btn_play3;
        private Button btn_play4;
        private Button btn_play5;
        private Button btn_release;
        private AssetManager aManager;
        private SoundPool mSoundPool = null;
        private HashMap<Integer, Integer> soundID = new HashMap<Integer, Integer>();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            aManager = getAssets();
            try {
                initSP();
            } catch (Exception e) {
                e.printStackTrace();
            }
            bindViews();
        }
    
        private void bindViews() {
            btn_play1 = (Button) findViewById(R.id.btn_play1);
            btn_play2 = (Button) findViewById(R.id.btn_play2);
            btn_play3 = (Button) findViewById(R.id.btn_play3);
            btn_play4 = (Button) findViewById(R.id.btn_play4);
            btn_play5 = (Button) findViewById(R.id.btn_play5);
            btn_release = (Button) findViewById(R.id.btn_release);
    
            btn_play1.setOnClickListener(this);
            btn_play2.setOnClickListener(this);
            btn_play3.setOnClickListener(this);
            btn_play4.setOnClickListener(this);
            btn_play5.setOnClickListener(this);
            btn_release.setOnClickListener(this);
    
        }
    
        private void initSP() throws Exception{
            //设置最多可容纳5个音频流,音频的品质为5
            mSoundPool = new SoundPool(5, AudioManager.STREAM_SYSTEM, 5);
            soundID.put(1, mSoundPool.load(this, R.raw.biaobiao, 1));
            soundID.put(2 , mSoundPool.load(getAssets().openFd("biaobiao.mp3") , 1));  //需要捕获IO异常
            soundID.put(3, mSoundPool.load(this, R.raw.biaobiao, 1));
            soundID.put(4, mSoundPool.load(this, R.raw.biaobiao, 1));
            soundID.put(5, mSoundPool.load(this, R.raw.biaobiao, 1));
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()){
                case R.id.btn_play1:
                    mSoundPool.play(soundID.get(1), 1, 1, 0, 0, 1);
                    break;
                case R.id.btn_play2:
                    mSoundPool.play(soundID.get(2), 1, 1, 0, 0, 1);
                    break;
                case R.id.btn_play3:
                    mSoundPool.play(soundID.get(3), 1, 1, 0, 0, 1);
                    break;
                case R.id.btn_play4:
                    mSoundPool.play(soundID.get(4), 1, 1, 0, 0, 1);
                    break;
                case R.id.btn_play5:
                    mSoundPool.play(soundID.get(5), 1, 1, 0, 0, 1);
                    break;
                case R.id.btn_release:
                    mSoundPool.release();   //回收SoundPool资源
                    break;
            }
        }
    }
    

当点击了最后一个按钮释放 SoundPool 后,此后如果再点击其它按钮就不会 Duang

SoundPool 支持的事件

SoundPool 支持 OnLoadCompleteListener 事件,用于监听声音文件是否加载完毕

我们可以给 SoundPool 实例添加该事件并重写 onLoadComplete()

mSoundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
    @Override
    public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
        Toast.makeText(MainActivity.this,"加特技准备完毕~",Toast.LENGTH_SHORT).show();
    }
});

参考文档

  1. Android SoundPool

Android 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.