Android声音播放之SoundPool

Android中播发声音目前主要采用MediaPlayer、SoundPool两种方式。MediaPlayer比较适合播放时间较长、文件大的音频文件.MediaPlayer存在如下的缺点:资源占用量高,延迟时间长、不支持多外音频同时播放。SoundPool的优点刚好可以弥补MediaPlayer的缺点,资源占用少,反应延迟小,还支持自行设置声音品质,音量,播放比率等。但是使用SoundPool要注意以下问题:1.SoundPool最大只能申请1M内存的空间,我们只能播发一些短小的声音片段;2.SoundPool中提供的pause、stop方法不推荐使用,可能会使你的应用程序莫名其妙终止。只建议在以下情况使用:1.程序中的短暂提示音(按键、消息提示音等);2.游戏中密集而短暂的声音。

1.创建SoundPool对象

    private void intSoundPool() {
        mSoundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
        mSoundIDs = new HashMap<Integer, Integer>();
        mSoundIDs.put(1, mSoundPool.load(this, R.raw.praise1, 1));
        mSoundIDs.put(2, mSoundPool.load(this, R.raw.praise2, 1));
        mSoundIDs.put(3, mSoundPool.load(this, R.raw.praise3, 1));
    }

SoundPool的构造函数定义如下(Android源码):

    /**
     * Constructor. Constructs a SoundPool object with the following
     * characteristics:
     *
     * @param maxStreams the maximum number of simultaneous streams for this
     *                   SoundPool object
     * @param streamType the audio stream type as described in AudioManager 
     *                   For example, game applications will normally use
     *                   {@link AudioManager#STREAM_MUSIC}.
     * @param srcQuality the sample-rate converter quality. Currently has no
     *                   effect. Use 0 for the default.
     * @return a SoundPool object, or null if creation failed
     * @deprecated use {@link SoundPool.Builder} instead to create and configure a
     *     SoundPool instance
     */
    public SoundPool(int maxStreams, int streamType, int srcQuality) {
        this(maxStreams,
                new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build());
    }

第一个参数maxStreams表示SoundPool能同时播放的声音最大数量,切忌合理使用,写的太大后会报“AudioFlinger could not create track, status: -12……”, 一旦报了这个错,就听不到声音了;
第二个参数streamType表示SoundPool播放的声音类型,通常我们设置为AudioManager.STREAM_MUSIC;
第三个参数srcQuality,该参数已失效,设置为0即可。

SoundPool通过load方法来加载声音(Android源码):

    /**
     * Load the sound from the specified APK resource.
     *
     * Note that the extension is dropped. For example, if you want to load
     * a sound from the raw resource file "explosion.mp3", you would specify
     * "R.raw.explosion" as the resource ID. Note that this means you cannot
     * have both an "explosion.wav" and an "explosion.mp3" in the res/raw
     * directory.
     * 
     * @param context the application context
     * @param resId the resource ID
     * @param priority the priority of the sound. Currently has no effect. Use
     *                 a value of 1 for future compatibility.
     * @return a sound ID. This value can be used to play or unload the sound.
     */
    public int load(Context context, int resId, int priority) {
        return mImpl.load(context, resId, priority);
    }

参数都很好理解分别对应上下文、资源ID、优先级(已失效,设置为1即可);
返回一个id,我们需要把该id保存下来,在之后调用play、unload方法时作为参数使用。当调用load方法的时候,实际就是把音效加载到了 SoundPool中,此时返回的streamId其实就是该音效在SoundPool中的id。这个id从1递增,要注意的是,不要超过 256 这个临界点。也就是说,第257个声音加载进去后,调用play方法其实是播不出来的,说不定还会挤掉一些前面加载好的声音。这个256的限制通过查看SDK源码基本就能了解清楚,它底层就那么实现的,用一个类似堆栈来存。

2.使用SoundPool播放声音

    private void playSound(int type) {
        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        float audioMaxVolum = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC); // 获取设备最大音量
        float audioCurrentVolum = am.getStreamVolume(AudioManager.STREAM_MUSIC); // 获取设备当前音量
        float audioRatio = audioCurrentVolum / audioMaxVolum; // 获取当前音量系数
        mSoundPool.play(mSoundIDs.get(type), audioRatio, audioRatio, 1, 0, 1); //播发声音
        startPraiseAnim();
    }

SoundPool调用play方法进行声音播放(Android源码):

    /**
     * Play a sound from a sound ID.
     *
     * Play the sound specified by the soundID. This is the value 
     * returned by the load() function. Returns a non-zero streamID
     * if successful, zero if it fails. The streamID can be used to
     * further control playback. Note that calling play() may cause
     * another sound to stop playing if the maximum number of active
     * streams is exceeded. A loop value of -1 means loop forever,
     * a value of 0 means don't loop, other values indicate the
     * number of repeats, e.g. a value of 1 plays the audio twice.
     * The playback rate allows the application to vary the playback
     * rate (pitch) of the sound. A value of 1.0 means play back at
     * the original frequency. A value of 2.0 means play back twice
     * as fast, and a value of 0.5 means playback at half speed.
     *
     * @param soundID a soundID returned by the load() function
     * @param leftVolume left volume value (range = 0.0 to 1.0)
     * @param rightVolume right volume value (range = 0.0 to 1.0)
     * @param priority stream priority (0 = lowest priority)
     * @param loop loop mode (0 = no loop, -1 = loop forever)
     * @param rate playback rate (1.0 = normal playback, range 0.5 to 2.0)
     * @return non-zero streamID if successful, zero if failed
     */
    public final int play(int soundID, float leftVolume, float rightVolume,
            int priority, int loop, float rate) {
        return mImpl.play(
            soundID, leftVolume, rightVolume, priority, loop, rate);
    }

参数soundID是我们调用load方法时返回的对应id;
参数leftVolume、rightVolume分别对应左右声道声音大小,0~1.0的系数;
参数 priority是声音流优先级,最小值为0;
参数loop是否循环,0:否,-1:是;
参数rate是播放速率,1.0:正常,0.5~2.0慢速或加快;
返回值,返回非零的id表示播放成功,否则返回0表示播放失败。

3.SoundPool的资源释放

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        mSoundPool.release();
        super.onDestroy();
    }

调用SoundPool的release释放所有加载的声音资源,一定要记得。public final boolean unload(int soundID)方法卸载声音。
4.关于unload方法和release方法
如果你音效多,也不要指望unload方法来清除掉一些音效后再load新的进去,虽然unload后音效卸载了,但是前面分给它在SoundPool里面的Id可没有释放掉,也就是说这个时候你load新的进去只会在后面继续累加,然后累加多了就超过256了,然后就就听不到声音,然后就没有然后了。要想彻底清掉前面的音效请使用release方法,它会连内存中占用的资源一起释放掉。
5.load需要一点点时间,load后不要马上unload,load —play–unload的做法并不可取,不要load太大的音效,它只会申请1M的内存空间。SoundPool出错后通常会看到retuen的值是0。

源码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值