summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/speech/tts/AudioPlaybackQueueItem.java32
-rw-r--r--core/java/android/speech/tts/BlockingAudioTrack.java38
-rw-r--r--core/java/android/speech/tts/PlaybackSynthesisCallback.java31
-rw-r--r--core/java/android/speech/tts/SynthesisPlaybackQueueItem.java9
-rw-r--r--core/java/android/speech/tts/TextToSpeech.java12
-rw-r--r--core/java/android/speech/tts/TextToSpeechService.java85
7 files changed, 140 insertions, 68 deletions
diff --git a/api/current.txt b/api/current.txt
index 4716847..9726937 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26660,6 +26660,7 @@ package android.speech.tts {
field public static final java.lang.String KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedTts";
field public static final java.lang.String KEY_FEATURE_NETWORK_SYNTHESIS = "networkTts";
field public static final java.lang.String KEY_PARAM_PAN = "pan";
+ field public static final java.lang.String KEY_PARAM_SESSION_ID = "sessionId";
field public static final java.lang.String KEY_PARAM_STREAM = "streamType";
field public static final java.lang.String KEY_PARAM_UTTERANCE_ID = "utteranceId";
field public static final java.lang.String KEY_PARAM_VOLUME = "volume";
diff --git a/core/java/android/speech/tts/AudioPlaybackQueueItem.java b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
index 03e53ec..c13b47f 100644
--- a/core/java/android/speech/tts/AudioPlaybackQueueItem.java
+++ b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
@@ -16,9 +16,12 @@
package android.speech.tts;
import android.content.Context;
+import android.media.AudioSystem;
+import android.media.AudioTrack;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.ConditionVariable;
+import android.speech.tts.TextToSpeechService.AudioOutputParams;
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
import android.util.Log;
@@ -27,7 +30,7 @@ class AudioPlaybackQueueItem extends PlaybackQueueItem {
private final Context mContext;
private final Uri mUri;
- private final int mStreamType;
+ private final AudioOutputParams mAudioParams;
private final ConditionVariable mDone;
private MediaPlayer mPlayer;
@@ -35,12 +38,12 @@ class AudioPlaybackQueueItem extends PlaybackQueueItem {
AudioPlaybackQueueItem(UtteranceProgressDispatcher dispatcher,
Object callerIdentity,
- Context context, Uri uri, int streamType) {
+ Context context, Uri uri, AudioOutputParams audioParams) {
super(dispatcher, callerIdentity);
mContext = context;
mUri = uri;
- mStreamType = streamType;
+ mAudioParams = audioParams;
mDone = new ConditionVariable();
mPlayer = null;
@@ -73,7 +76,11 @@ class AudioPlaybackQueueItem extends PlaybackQueueItem {
mDone.open();
}
});
- mPlayer.setAudioStreamType(mStreamType);
+ mPlayer.setAudioStreamType(mAudioParams.mStreamType);
+ setupVolume(mPlayer, mAudioParams.mVolume, mAudioParams.mPan);
+ if (mAudioParams.mSessionId != AudioSystem.AUDIO_SESSION_ALLOCATE) {
+ mPlayer.setAudioSessionId(mAudioParams.mSessionId);
+ }
mPlayer.start();
mDone.block();
finish();
@@ -89,6 +96,23 @@ class AudioPlaybackQueueItem extends PlaybackQueueItem {
}
}
+ private static void setupVolume(MediaPlayer player, float volume, float pan) {
+ final float vol = clip(volume, 0.0f, 1.0f);
+ final float panning = clip(pan, -1.0f, 1.0f);
+
+ float volLeft = vol, volRight = vol;
+ if (panning > 0.0f) {
+ volLeft *= (1.0f - panning);
+ } else if (panning < 0.0f) {
+ volRight *= (1.0f + panning);
+ }
+ player.setVolume(volLeft, volRight);
+ }
+
+ private static final float clip(float value, float min, float max) {
+ return value < min ? min : (value < max ? value : max);
+ }
+
private void finish() {
try {
mPlayer.stop();
diff --git a/core/java/android/speech/tts/BlockingAudioTrack.java b/core/java/android/speech/tts/BlockingAudioTrack.java
index 92bb0ac..b405de0 100644
--- a/core/java/android/speech/tts/BlockingAudioTrack.java
+++ b/core/java/android/speech/tts/BlockingAudioTrack.java
@@ -4,6 +4,7 @@ package android.speech.tts;
import android.media.AudioFormat;
import android.media.AudioTrack;
+import android.speech.tts.TextToSpeechService.AudioOutputParams;
import android.util.Log;
/**
@@ -44,12 +45,11 @@ class BlockingAudioTrack {
private static final int MIN_AUDIO_BUFFER_SIZE = 8192;
- private final int mStreamType;
+ private final AudioOutputParams mAudioParams;
private final int mSampleRateInHz;
private final int mAudioFormat;
private final int mChannelCount;
- private final float mVolume;
- private final float mPan;
+
private final int mBytesPerFrame;
/**
@@ -73,15 +73,14 @@ class BlockingAudioTrack {
private AudioTrack mAudioTrack;
private volatile boolean mStopped;
- BlockingAudioTrack(int streamType, int sampleRate,
- int audioFormat, int channelCount,
- float volume, float pan) {
- mStreamType = streamType;
+ private int mSessionId;
+
+ BlockingAudioTrack(AudioOutputParams audioParams, int sampleRate,
+ int audioFormat, int channelCount) {
+ mAudioParams = audioParams;
mSampleRateInHz = sampleRate;
mAudioFormat = audioFormat;
mChannelCount = channelCount;
- mVolume = volume;
- mPan = pan;
mBytesPerFrame = AudioFormat.getBytesPerSample(mAudioFormat) * mChannelCount;
mIsShortUtterance = false;
@@ -215,8 +214,9 @@ class BlockingAudioTrack {
= AudioTrack.getMinBufferSize(mSampleRateInHz, channelConfig, mAudioFormat);
int bufferSizeInBytes = Math.max(MIN_AUDIO_BUFFER_SIZE, minBufferSizeInBytes);
- AudioTrack audioTrack = new AudioTrack(mStreamType, mSampleRateInHz, channelConfig,
- mAudioFormat, bufferSizeInBytes, AudioTrack.MODE_STREAM);
+ AudioTrack audioTrack = new AudioTrack(mAudioParams.mStreamType, mSampleRateInHz,
+ channelConfig, mAudioFormat, bufferSizeInBytes, AudioTrack.MODE_STREAM,
+ mAudioParams.mSessionId);
if (audioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
Log.w(TAG, "Unable to create audio track.");
audioTrack.release();
@@ -225,7 +225,7 @@ class BlockingAudioTrack {
mAudioBufferSize = bufferSizeInBytes;
- setupVolume(audioTrack, mVolume, mPan);
+ setupVolume(audioTrack, mAudioParams.mVolume, mAudioParams.mPan);
return audioTrack;
}
@@ -328,19 +328,11 @@ class BlockingAudioTrack {
}
private static final long clip(long value, long min, long max) {
- if (value < min) {
- return min;
- }
-
- if (value > max) {
- return max;
- }
-
- return value;
+ return value < min ? min : (value < max ? value : max);
}
- private static float clip(float value, float min, float max) {
- return value > max ? max : (value < min ? min : value);
+ private static final float clip(float value, float min, float max) {
+ return value < min ? min : (value < max ? value : max);
}
}
diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
index 7e68d27..f850f10 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -15,6 +15,7 @@
*/
package android.speech.tts;
+import android.speech.tts.TextToSpeechService.AudioOutputParams;
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
import android.util.Log;
@@ -28,23 +29,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
private static final int MIN_AUDIO_BUFFER_SIZE = 8192;
- /**
- * Audio stream type. Must be one of the STREAM_ contants defined in
- * {@link android.media.AudioManager}.
- */
- private final int mStreamType;
-
- /**
- * Volume, in the range [0.0f, 1.0f]. The default value is
- * {@link TextToSpeech.Engine#DEFAULT_VOLUME} (1.0f).
- */
- private final float mVolume;
-
- /**
- * Left/right position of the audio, in the range [-1.0f, 1.0f].
- * The default value is {@link TextToSpeech.Engine#DEFAULT_PAN} (0.0f).
- */
- private final float mPan;
+ private final AudioOutputParams mAudioParams;
/**
* Guards {@link #mAudioTrackHandler}, {@link #mItem} and {@link #mStopped}.
@@ -65,13 +50,11 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
private final Object mCallerIdentity;
private final AbstractEventLogger mLogger;
- PlaybackSynthesisCallback(int streamType, float volume, float pan,
- AudioPlaybackHandler audioTrackHandler, UtteranceProgressDispatcher dispatcher,
- Object callerIdentity, AbstractEventLogger logger, boolean clientIsUsingV2) {
+ PlaybackSynthesisCallback(AudioOutputParams audioParams, AudioPlaybackHandler audioTrackHandler,
+ UtteranceProgressDispatcher dispatcher, Object callerIdentity,
+ AbstractEventLogger logger, boolean clientIsUsingV2) {
super(clientIsUsingV2);
- mStreamType = streamType;
- mVolume = volume;
- mPan = pan;
+ mAudioParams = audioParams;
mAudioTrackHandler = audioTrackHandler;
mDispatcher = dispatcher;
mCallerIdentity = callerIdentity;
@@ -161,7 +144,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
return TextToSpeech.ERROR;
}
SynthesisPlaybackQueueItem item = new SynthesisPlaybackQueueItem(
- mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
+ mAudioParams, sampleRateInHz, audioFormat, channelCount,
mDispatcher, mCallerIdentity, mLogger);
mAudioTrackHandler.enqueue(item);
mItem = item;
diff --git a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
index 104f486..7423933 100644
--- a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
+++ b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
@@ -15,6 +15,7 @@
*/
package android.speech.tts;
+import android.speech.tts.TextToSpeechService.AudioOutputParams;
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
import android.util.Log;
@@ -62,9 +63,8 @@ final class SynthesisPlaybackQueueItem extends PlaybackQueueItem {
private final BlockingAudioTrack mAudioTrack;
private final AbstractEventLogger mLogger;
- SynthesisPlaybackQueueItem(int streamType, int sampleRate,
- int audioFormat, int channelCount,
- float volume, float pan, UtteranceProgressDispatcher dispatcher,
+ SynthesisPlaybackQueueItem(AudioOutputParams audioParams, int sampleRate,
+ int audioFormat, int channelCount, UtteranceProgressDispatcher dispatcher,
Object callerIdentity, AbstractEventLogger logger) {
super(dispatcher, callerIdentity);
@@ -74,8 +74,7 @@ final class SynthesisPlaybackQueueItem extends PlaybackQueueItem {
mDone = false;
mStatusCode = TextToSpeech.SUCCESS;
- mAudioTrack = new BlockingAudioTrack(streamType, sampleRate, audioFormat,
- channelCount, volume, pan);
+ mAudioTrack = new BlockingAudioTrack(audioParams, sampleRate, audioFormat, channelCount);
mLogger = logger;
}
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index a338c19..0d2b69b 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -564,6 +564,17 @@ public class TextToSpeech {
* @see TextToSpeech#getFeatures(java.util.Locale)
*/
public static final String KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedTts";
+
+ /**
+ * Parameter key to specify an audio session identifier (obtained from
+ * {@link AudioManager#allocateAudioSessionId()}) that will be used by the request audio
+ * output. It can be used to associate one of the {@link android.media.audiofx.AudioEffect}
+ * objects with the synthesis (or earcon) output.
+ *
+ * @see TextToSpeech#speak(String, int, HashMap)
+ * @see TextToSpeech#playEarcon(String, int, HashMap)
+ */
+ public static final String KEY_PARAM_SESSION_ID = "sessionId";
}
private final Context mContext;
@@ -1336,6 +1347,7 @@ public class TextToSpeech {
if (params != null && !params.isEmpty()) {
Bundle bundle = new Bundle(mParams);
copyIntParam(bundle, params, Engine.KEY_PARAM_STREAM);
+ copyIntParam(bundle, params, Engine.KEY_PARAM_SESSION_ID);
copyStringParam(bundle, params, Engine.KEY_PARAM_UTTERANCE_ID);
copyFloatParam(bundle, params, Engine.KEY_PARAM_VOLUME);
copyFloatParam(bundle, params, Engine.KEY_PARAM_PAN);
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index a53518f..5a3c5f7 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -17,6 +17,8 @@ package android.speech.tts;
import android.app.Service;
import android.content.Intent;
+import android.media.AudioManager;
+import android.media.AudioSystem;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -419,6 +421,73 @@ public abstract class TextToSpeechService extends Service {
public void dispatchOnError(int errorCode);
}
+
+ /** Set of parameters affecting audio output. */
+ static class AudioOutputParams {
+ /**
+ * Audio session identifier. May be used to associate audio playback with one of the
+ * {@link android.media.audiofx.AudioEffect} objects. If not specified by client,
+ * it should be equal to {@link AudioSystem#AUDIO_SESSION_ALLOCATE}.
+ */
+ public final int mSessionId;
+
+ /**
+ * Audio stream type. Must be one of the STREAM_ contants defined in
+ * {@link android.media.AudioManager}.
+ */
+ public final int mStreamType;
+
+ /**
+ * Volume, in the range [0.0f, 1.0f]. The default value is
+ * {@link TextToSpeech.Engine#DEFAULT_VOLUME} (1.0f).
+ */
+ public final float mVolume;
+
+ /**
+ * Left/right position of the audio, in the range [-1.0f, 1.0f].
+ * The default value is {@link TextToSpeech.Engine#DEFAULT_PAN} (0.0f).
+ */
+ public final float mPan;
+
+ /** Create AudioOutputParams with default values */
+ AudioOutputParams() {
+ mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE;
+ mStreamType = Engine.DEFAULT_STREAM;
+ mVolume = Engine.DEFAULT_VOLUME;
+ mPan = Engine.DEFAULT_PAN;
+ }
+
+ AudioOutputParams(int sessionId, int streamType, float volume, float pan) {
+ mSessionId = sessionId;
+ mStreamType = streamType;
+ mVolume = volume;
+ mPan = pan;
+ }
+
+ /** Create AudioOutputParams from A {@link SynthesisRequest#getParams()} bundle */
+ static AudioOutputParams createFromV1ParamsBundle(Bundle paramsBundle) {
+ if (paramsBundle == null) {
+ return new AudioOutputParams();
+ }
+
+ return new AudioOutputParams(
+ paramsBundle.getInt(
+ Engine.KEY_PARAM_SESSION_ID,
+ AudioSystem.AUDIO_SESSION_ALLOCATE),
+ paramsBundle.getInt(
+ Engine.KEY_PARAM_STREAM,
+ Engine.DEFAULT_STREAM),
+ paramsBundle.getFloat(
+ Engine.KEY_PARAM_VOLUME,
+ Engine.DEFAULT_VOLUME),
+ paramsBundle.getFloat(
+ Engine.KEY_PARAM_PAN,
+ Engine.DEFAULT_PAN));
+ }
+
+ }
+
+
/**
* An item in the synth thread queue.
*/
@@ -592,16 +661,8 @@ public abstract class TextToSpeechService extends Service {
return getStringParam(mParams, Engine.KEY_PARAM_UTTERANCE_ID, null);
}
- int getStreamType() {
- return getIntParam(mParams, Engine.KEY_PARAM_STREAM, Engine.DEFAULT_STREAM);
- }
-
- float getVolume() {
- return getFloatParam(mParams, Engine.KEY_PARAM_VOLUME, Engine.DEFAULT_VOLUME);
- }
-
- float getPan() {
- return getFloatParam(mParams, Engine.KEY_PARAM_PAN, Engine.DEFAULT_PAN);
+ AudioOutputParams getAudioParams() {
+ return AudioOutputParams.createFromV1ParamsBundle(mParams);
}
}
@@ -668,7 +729,7 @@ public abstract class TextToSpeechService extends Service {
}
protected AbstractSynthesisCallback createSynthesisCallback() {
- return new PlaybackSynthesisCallback(getStreamType(), getVolume(), getPan(),
+ return new PlaybackSynthesisCallback(getAudioParams(),
mAudioPlaybackHandler, this, getCallerIdentity(), mEventLogger, false);
}
@@ -743,7 +804,7 @@ public abstract class TextToSpeechService extends Service {
Bundle params, Uri uri) {
super(callerIdentity, callerUid, callerPid, params);
mItem = new AudioPlaybackQueueItem(this, getCallerIdentity(),
- TextToSpeechService.this, uri, getStreamType());
+ TextToSpeechService.this, uri, getAudioParams());
}
@Override