Flow control for playing voice commands changed to clarify flow

If API LEVEL > 8: AudioManager is used to gain temporary audio focus.
This commit is contained in:
chgenly 2012-09-09 00:13:14 -07:00
parent 8a532752eb
commit a79e7e5da7

View file

@ -11,7 +11,9 @@ import net.osmand.plus.OsmandSettings;
import org.apache.commons.logging.Log;
import android.annotation.SuppressLint;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
/**
@ -19,7 +21,7 @@ import android.media.MediaPlayer;
* It gets commands from input, analyze what files should be played and play
* them using media player
*/
public class MediaCommandPlayerImpl extends AbstractPrologCommandPlayer {
public class MediaCommandPlayerImpl extends AbstractPrologCommandPlayer implements MediaPlayer.OnCompletionListener {
private static final String CONFIG_FILE = "_config.p";
private static final int[] MEDIA_VOICE_VERSION = new int[] { 0 }; // MUST BE SORTED, list of supported versions
@ -29,15 +31,17 @@ public class MediaCommandPlayerImpl extends AbstractPrologCommandPlayer {
// playing media
private MediaPlayer mediaPlayer;
// indicates that player is ready to play first file
private volatile boolean playNext = true;
private List<String> filesToPlay = Collections.synchronizedList(new ArrayList<String>());
private int streamType;
private final Context mCtx;
private AudioFocusHelper mAudioFocusHelper;
public MediaCommandPlayerImpl(Context ctx, OsmandSettings settings, String voiceProvider)
throws CommandPlayerException
{
super(ctx, settings, voiceProvider, CONFIG_FILE, MEDIA_VOICE_VERSION);
mCtx = ctx;
this.streamType = settings.AUDIO_STREAM_GUIDANCE.get();
}
@ -53,82 +57,125 @@ public class MediaCommandPlayerImpl extends AbstractPrologCommandPlayer {
}
@Override
public void playCommands(CommandBuilder builder){
public synchronized void playCommands(CommandBuilder builder) {
filesToPlay.addAll(builder.execute());
playQueue();
// If we have not already started to play audio, start.
if (mediaPlayer == null) {
if (android.os.Build.VERSION.SDK_INT >= 8) {
mAudioFocusHelper = new AudioFocusHelper(mCtx);
} else {
mAudioFocusHelper = null;
}
if (mAudioFocusHelper != null)
mAudioFocusHelper.requestFocus();
playQueue();
}
}
private synchronized void playQueue() {
if (!playNext)
return;
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
}
performDelays();
File file = getNextFileToPlay();
if (file != null) {
playFile(file);
// Will continue with onCompletion()
} else {
// Release the media player only when we are done speaking.
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
if (mAudioFocusHelper != null)
mAudioFocusHelper.abandonFocus();
}
}
}
@Override
public void onCompletion(MediaPlayer mp) {
playQueue();
}
private void performDelays() {
int sleep = 0;
while (!filesToPlay.isEmpty() && filesToPlay.get(0).startsWith(DELAY_CONST)) {
String s = filesToPlay.remove(0).substring(DELAY_CONST.length());
try {
sleep += Integer.parseInt(s);
} catch (NumberFormatException e) {
}
}
try {
if (sleep != 0)
Thread.sleep(sleep);
} catch (InterruptedException e) {
}
}
private File getNextFileToPlay() {
while (!filesToPlay.isEmpty()) {
String f = filesToPlay.remove(0);
if (f != null && voiceDir != null) {
// if(voiceZipFile != null){
// ZipEntry entry = voiceZipFile.getEntry(f);
// exists = entry != null;
// voiceZipFile.getInputStream(entry);
//
// } else {
File file = new File(voiceDir, f);
if (file.exists()) {
log.debug("Playing file : " + f); //$NON-NLS-1$
playNext = false;
try {
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
}
// Can't play sound file from zip it seams to be impossible only unpack and play!!!
mediaPlayer.setAudioStreamType(streamType);
mediaPlayer.setDataSource(file.getAbsolutePath());
mediaPlayer.prepare();
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// Reset prepares to speak again. Don't release because if we have more to
// say, we don't want our speech interrupted by other audio, such as music
// or a podcast. We will release when we are done speaking.
mp.reset();
int sleep = 60;
boolean delay = true;
while (!filesToPlay.isEmpty() && delay) {
delay = filesToPlay.get(0).startsWith(DELAY_CONST);
if (delay) {
String s = filesToPlay.remove(0).substring(DELAY_CONST.length());
try {
sleep += Integer.parseInt(s);
} catch (NumberFormatException e) {
}
}
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
}
playNext = true;
playQueue();
}
});
mediaPlayer.start();
} catch (Exception e) {
log.error("Error while playing voice command", e); //$NON-NLS-1$
playNext = true;
}
} else {
log.info("Play file not found : " + f); //$NON-NLS-1$
}
}
if (file.exists())
return file;
else
log.error("Unable to play, does not exist: "+file);
}
}
// Release the media player only when we are done speaking.
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
return null;
}
private void playFile(File file) {
log.debug("Playing file : " + file); //$NON-NLS-1$
try {
mediaPlayer.reset();
mediaPlayer.setAudioStreamType(streamType);
mediaPlayer.setDataSource(file.getAbsolutePath());
mediaPlayer.prepare();
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.start();
} catch (Exception e) {
log.error("Error while playing voice command", e); //$NON-NLS-1$
playQueue();
}
}
public static boolean isMyData(File voiceDir) {
return new File(voiceDir, CONFIG_FILE).exists();
}
// We Use API level 8 calls here, suppress warnings.
@SuppressLint("NewApi")
public class AudioFocusHelper implements AudioManager.OnAudioFocusChangeListener {
private Context mContext;
private AudioManager mAudioManager;
public AudioFocusHelper(Context context) {
mContext = context;
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
}
public boolean requestFocus() {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
mAudioManager.requestAudioFocus(this, streamType, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
}
public boolean abandonFocus() {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
mAudioManager.abandonAudioFocus(this);
}
@Override
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_GAIN)
playQueue();
else
log.error("Unable to gain audio focus");
}
}
}