Android SoundPool 的使用

它是一个“pool”,我们可以加载多个音频资源到内存。加载资源到内存是需要花费少许时间的,因此我们需要监听加载资源完毕的事件,在加载完毕后才能进行播放,以免发生不可预期的错误。

除了以上介绍外,SoundPool 还有诸多其他功能,诸如调节左右声道的音量值、调整播放的语速、设置播放的优先级以及播放的次数等等。

SoundPool 的创建
SoundPool 的创建方式在不同版本中会有所不同,为了更好的兼容性,应该对api版本进行判断,再对应的进行创建. 在 5.0 以前 ,直接使用它的构造方法即可,而在这之后,则需要使用Builder模式来创建。

创建完 SoundPool 后,通过setOnLoadCompleteListener设置监听,用来监听资源加载完毕的事件发生。

        /**
         * 创建SoundPool ,注意 api 等级
         */
        private void createSoundPoolIfNeeded() {
            if (mSoundPool == null) {
                // 5.0 及 之后
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
                    AudioAttributes audioAttributes = null;
                    audioAttributes = new AudioAttributes.Builder()
                            .setUsage(AudioAttributes.USAGE_MEDIA)
                            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                            .build();
    
                    mSoundPool = new SoundPool.Builder()
                            .setMaxStreams(16)
                            .setAudioAttributes(audioAttributes)
                            .build();
                } else { // 5.0 以前
                    mSoundPool = new SoundPool(16, AudioManager.STREAM_MUSIC, 0);  // 创建SoundPool
                }
    
                mSoundPool.setOnLoadCompleteListener(this);  // 设置加载完成监听
            }
        }  
5.0 之前,直接通过SoundPool的构造方法来创建,有三个参数:

1.maxStreams 同时播放流的最大数量,当播放的流的数目大于此值,则会选择性停止优先级较低的流
2.streamType 流类型,比如 STREAM_MUSIC
3.srcQuality 采样率转换器质量,目前没有什么作用,默认填充0

5.0 之后,使用Builder模式进行构造.Builder可以设置多个参数.

setAudioAttributes用来设置audio 属性,此值要么不设,要么设置不为null的值,否则会导致异常产生
如下代码摘录自 SoundPool.Builder 类,可以发现给 setAudioAttributes 传 null 是会抛出异常的,如果不设置的话,在build方法中则会默认创建一个,usage设置为USAGE_MEDIA

    public Builder setAudioAttributes(AudioAttributes attributes)
                throws IllegalArgumentException {
            if (attributes == null) {
                throw new IllegalArgumentException("Invalid null AudioAttributes");
            }
            mAudioAttributes = attributes;
            return this;
        }

        public SoundPool build() {
            if (mAudioAttributes == null) {
                mAudioAttributes = new AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_MEDIA).build();
            }
            return new SoundPool(mMaxStreams, mAudioAttributes);
        }

AudioAttributes 也是使用Builder模式来构造的,setUsage用来设置用途(比如是游戏还是媒体), setContentType用来设置内容类型(比如是视频还是音乐)


资源加载与播放
当资源没加载时,首先需要调用 SoundPool 的load 方法进行加载,并返回一个mSoundId,它代表一个已加载的资源的id,可以用来播放音效。

加载音频资源异步执行,此过程是需要时间的,当加载成功后,会调用 onLoadComplete 方法

 
此处的load方法是从res/raw 下加载的,需要注意的是,通过这种方式加载的资源会忽略后缀名,因此不同类型的资源不能重名. 实际上, 提供了多个load 方法, 以方便不同的需求:

 // Load the sound from the specified path.  根据路径加载
 public int load(String path, int priority)

// Load the sound from the specified APK resource  使用应用的资源
public int load(Context context, int resId, int priority)

// Load the sound from an asset file descriptor   使用 assert  文件描述符
public int load(AssetFileDescriptor afd, int priority) {

// Load the sound from a FileDescriptor.   使用文件描述符
public int load(FileDescriptor fd, long offset, long length, int priority)

通过 unload 方法来卸载之前加载的资源 ,参数为已加载过的资源 id
    public native final boolean unload(int soundID);


mStreamID = mSoundPool.play(mSoundId, mCruLeftVolume, mCurRightVolume, 16, -1, 1.0f);
当活跃的stream数量大于maxStreams,调用该方法可导致另一个播放声音被停止:

1.soundID load方法返回的值,指向某个已加载的音频资源
2.leftVolume\rightVolume 左右声道的值.范围 0.0f ~ 1.0f
3.priority 流的优先级
4.loop 循环播放的次数, -1 表示无限循环
5.rate 播放的速率 , 2 表示2倍速度
返回值streamID , 返回0则播放失败,否则成功。通过这个id可以进一步进行控制. 比如 pause\resume

    
播放控制
streamID是对流的特定实例的引用,通过 SoundPool 的 pause\resume\stop 方法, 就可以对播放进行控制。

pause方法用来暂停指定mStreamID的流 (暂停播放)
resume方法用来恢复指定mStreamID的流 (恢复播放)
stop方法用来停止指定mStreamID的流 (停止播放)
     mSoundPool.pause(mStreamID);

   
播放音量调节
通过 SoundPool 的 setVolume 方法就可以设置指定 mStreamID 的流的左右声道的音量值.
如下,通过SeekBar 进行动态调节

    private OnSeekBarChangeListenerAdapter seekBarListener = new OnSeekBarChangeListenerAdapter() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            super.onProgressChanged(seekBar, progress, fromUser);
            if(mSoundPool == null) return;
            float volume = progress * 1.0f / seekBar.getMax();
            switch (seekBar.getId()) {
                case R.id.id_sk_left_vloume:  // 设置左 volume
                    mCruLeftVolume = volume;
                    mSoundPool.setVolume(mStreamID, mCruLeftVolume, mCurRightVolume);
                    break;
                case R.id.id_sk_right_vloume: // 设置又 volume
                    mCurRightVolume = volume;
                    mSoundPool.setVolume(mStreamID, mCruLeftVolume, mCurRightVolume);
                    break;
            }
        }
    };


资源释放
通过unload 方法来卸载之前load的资源 , 并通过 release 方法释放SoundPool占用的资源

    /**
     * 释放资源
     */
    private void releaseSoundPool() {
        if (mSoundPool != null) {
            mSoundPool.autoPause();
            mSoundPool.unload(mSoundId);
            mSoundPool.release();
            mSoundPool = null;
        }
    }


注意事项
并不是所有的音频格式都支持,可能有些格式是不支持的
尽量使用占用内存较小的音频文件,时长也不要过长,因为 SoundPool 也只会播放很短的时间
加载资源的数目也需要注意(256限制),过多可能会导致问题
播放之前一定要确保资源以及加载完毕了,否则可能会出现异常情况
设置流的优先级的问题,当同时播放的活动流的数目超过设置的maxStreams值的时候,会根据优先级来停止优先级较低的流,如果有多个具有相同低优先级的流,它将选择要停止的最旧流,并且该流不再有效;如果要播放的流的优先级最低,则会播放失败,返回的streamID为零ID
可以设置播放的重复次数,当设置为-1 则表示会无限循环下去,此时若要停止,需要显示的调用stop() 方法
可以设置播放速率,设置范围为0.5 ~ 2.0 , 正常为 1.0

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值