Android 实现多个Audio文件的顺序播放
最近开发Android通讯录播报号码时需用到播放多个连续音频文件,用传统的MediaManager无法满足复杂性需求,而 SoundPool则满足,于是写了一个SoundPool的管理类SoundManager管理音频的播放。
代码如下:
package com.yous365.android.util;
import org.xml.sax.SAXException;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Handler;
import android.util.Log;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import javax.xml.parsers.ParserConfigurationException;
public class SoundManager {
private SoundPool mSoundPool;
private HashMap<String, Integer> mSoundPoolMap;
private AudioManager mAudioManager;
private Context mContext;
private Handler mHandler = new Handler();
private Vector<Integer> mKillSoundQueue = new Vector<Integer>();
private VoicePhoneNumberUtil util;
private long delay = 1000;
private long seperateTime = 700;
private float rate = 1.0f;
private String locale;
static private SoundManager _instance;
/**
* Requests the instance of the Sound Manager and creates it if it does not
* exist.
*
* @return Returns the single instance of the SoundManager
*/
static synchronized public SoundManager getInstance() {
if (_instance == null)
_instance = new SoundManager();
return _instance;
}
/**
*
*/
private SoundManager() {
util = VoicePhoneNumberUtil.getInstance();
}
/**
* Initialises the storage for the sounds
*
* @param theContext The Application context
*/
public void initSounds(Context theContext) {
mContext = theContext;
mSoundPool = new SoundPool(1,
AudioManager.STREAM_MUSIC, 0);
mSoundPoolMap = new HashMap<String, Integer>();
mAudioManager = (AudioManager) mContext
.getSystemService(Context.AUDIO_SERVICE);
}
/**
* Add a new Sound to the SoundPool
*
* @param key - The Sound Index for Retrieval
* @param SoundID - The Android ID for the Sound asset.
*/
public void addSound(String key, int SoundID) {
mSoundPoolMap.put(key,
mSoundPool.load(mContext, SoundID, 1));
}
/**
*
* @param key the key we need to get the sound later
* @param afd the fie store in the asset
*/
public void addSound(String key, AssetFileDescriptor afd) {
mSoundPoolMap.put(key, mSoundPool.load(
afd.getFileDescriptor(),
afd.getStartOffset(), afd.getLength(), 1));
}
/**
* play the sound loaded to the SoundPool by the key we set
* @param key the key in the map
*/
public void playSound(String key) {
int streamVolume = mAudioManager
.getStreamVolume(AudioManager.STREAM_MUSIC);
streamVolume = streamVolume
/ mAudioManager
.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
int soundId = mSoundPool.play(
mSoundPoolMap.get(key), streamVolume,
streamVolume, 1, 0, rate);
mKillSoundQueue.add(soundId);
// schedule the current sound to stop after set milliseconds
mHandler.postDelayed(new Runnable() {
public void run() {
if (!mKillSoundQueue.isEmpty()) {
mSoundPool.stop(mKillSoundQueue
.firstElement());
}
}
}, delay);
}
/**
*
* @param key the key in the map
*/
public void playLoopedSound(String key) {
int streamVolume = mAudioManager
.getStreamVolume(AudioManager.STREAM_MUSIC);
streamVolume = streamVolume
/ mAudioManager
.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
int soundId = mSoundPool.play(
mSoundPoolMap.get(key), streamVolume,
streamVolume, 1, -1, rate);
mKillSoundQueue.add(soundId);
// schedule the current sound to stop after set milliseconds
mHandler.postDelayed(new Runnable() {
public void run() {
if (!mKillSoundQueue.isEmpty()) {
mSoundPool.stop(mKillSoundQueue
.firstElement());
}
}
}, delay);
}
/**
* play the sounds have loaded in SoundPool
* @param keys the files key stored in the map
* @throws InterruptedException
*/
public void playMutilSounds(String keys[])
throws InterruptedException {
int streamVolume = mAudioManager
.getStreamVolume(AudioManager.STREAM_MUSIC);
streamVolume = streamVolume
/ mAudioManager
.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
for (String key : keys) {
Log.d("playMutilSounds", key);
if (mSoundPoolMap.containsKey(key)) {
int soundId = mSoundPool.play(
mSoundPoolMap.get(key),
streamVolume, streamVolume, 1, 0,
rate);
//sleep for a while for SoundPool play
Thread.sleep(seperateTime);
mKillSoundQueue.add(soundId);
}
}
// schedule the current sound to stop after set milliseconds
mHandler.postDelayed(new Runnable() {
public void run() {
if (!mKillSoundQueue.isEmpty()) {
mSoundPool.stop(mKillSoundQueue
.firstElement());
}
}
}, delay);
}
/**
* Loads the various sound assets
* @param locale the load to load audio files
*/
public void loadSounds(String locale)
throws SAXException, IOException,
ParserConfigurationException {
Log.d("load locale", locale);
this.locale = locale;
AssetFileDescriptor afd;
Map<String, String> audioFiles = util
.getAudioFileConfig(locale,
mContext.getAssets());
for (String key : audioFiles.keySet()) {
afd = mContext.getAssets().openFd(
audioFiles.get(key));
addSound(key, afd);
}
}
/**
* Stop a Sound
*
* @param index - index of the sound to be stopped
*/
public void stopSound(int index) {
mSoundPool.stop(mSoundPoolMap.get(index));
}
/**
* Deallocates the resources and Instance of SoundManager
*/
public void cleanup() {
mSoundPool.release();
mSoundPool = null;
mSoundPoolMap.clear();
mAudioManager.unloadSoundEffects();
_instance = null;
}
/**
* unload all resource in the sound pool
* support for user change VoiceLanguage or Locale or user close the voice function !
*/
public void unloadAllSoundsIn() {
if (mSoundPoolMap.size() > 0) {
for (String key : mSoundPoolMap.keySet()) {
mSoundPool.unload(mSoundPoolMap.get(key));
}
}
mKillSoundQueue.clear();
mSoundPoolMap.clear();
}
/**
* set the speed of soundPool
*
* @param i i<0 means slow i= 0 means normal i>0 means fast
*/
public void setVoiceSpeed(int i) {
if (i > 0) {
rate = 1.2f;
}
else if (i < 0) {
rate = 0.8f;
}
else {
rate = 1.0f;
}
}
/**
* set the delay after one number's sound have played
*
* @param i i<0 means short i= 0 means normal i>0 means long
*/
public void setVoiceDelay(int i) {
if (i > 0) {
seperateTime = 700;
}
else if (i < 0) {
seperateTime = 400;
}
else {
seperateTime = 500;
}
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
}