am 754c72ed: Notifiy callers when a speech synthesis error occurs.
* commit '754c72ed9e8e83e5a913aa7552fc2e1b1b5277e0': Notifiy callers when a speech synthesis error occurs.
This commit is contained in:
@@ -18890,7 +18890,8 @@ package android.speech.tts {
|
||||
method public int playSilence(long, int, java.util.HashMap<java.lang.String, java.lang.String>);
|
||||
method public deprecated int setEngineByPackageName(java.lang.String);
|
||||
method public int setLanguage(java.util.Locale);
|
||||
method public int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
|
||||
method public deprecated int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
|
||||
method public int setOnUtteranceProgressListener(android.speech.tts.UtteranceProgressListener);
|
||||
method public int setPitch(float);
|
||||
method public int setSpeechRate(float);
|
||||
method public void shutdown();
|
||||
@@ -18963,6 +18964,13 @@ package android.speech.tts {
|
||||
method protected abstract void onSynthesizeText(android.speech.tts.SynthesisRequest, android.speech.tts.SynthesisCallback);
|
||||
}
|
||||
|
||||
public abstract class UtteranceProgressListener {
|
||||
ctor public UtteranceProgressListener();
|
||||
method public abstract void onDone(java.lang.String);
|
||||
method public abstract void onError(java.lang.String);
|
||||
method public abstract void onStart(java.lang.String);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.telephony {
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
*/
|
||||
package android.speech.tts;
|
||||
|
||||
import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
|
||||
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
|
||||
|
||||
class AudioMessageParams extends MessageParams {
|
||||
private final BlockingMediaPlayer mPlayer;
|
||||
|
||||
AudioMessageParams(UtteranceCompletedDispatcher dispatcher,
|
||||
AudioMessageParams(UtteranceProgressDispatcher dispatcher,
|
||||
String callingApp, BlockingMediaPlayer player) {
|
||||
super(dispatcher, callingApp);
|
||||
mPlayer = player;
|
||||
|
||||
@@ -312,10 +312,11 @@ class AudioPlaybackHandler {
|
||||
private void handleSilence(MessageParams msg) {
|
||||
if (DBG) Log.d(TAG, "handleSilence()");
|
||||
SilenceMessageParams params = (SilenceMessageParams) msg;
|
||||
params.getDispatcher().dispatchOnStart();
|
||||
if (params.getSilenceDurationMs() > 0) {
|
||||
params.getConditionVariable().block(params.getSilenceDurationMs());
|
||||
}
|
||||
params.getDispatcher().dispatchUtteranceCompleted();
|
||||
params.getDispatcher().dispatchOnDone();
|
||||
if (DBG) Log.d(TAG, "handleSilence() done.");
|
||||
}
|
||||
|
||||
@@ -323,11 +324,12 @@ class AudioPlaybackHandler {
|
||||
private void handleAudio(MessageParams msg) {
|
||||
if (DBG) Log.d(TAG, "handleAudio()");
|
||||
AudioMessageParams params = (AudioMessageParams) msg;
|
||||
params.getDispatcher().dispatchOnStart();
|
||||
// Note that the BlockingMediaPlayer spawns a separate thread.
|
||||
//
|
||||
// TODO: This can be avoided.
|
||||
params.getPlayer().startAndWait();
|
||||
params.getDispatcher().dispatchUtteranceCompleted();
|
||||
params.getDispatcher().dispatchOnDone();
|
||||
if (DBG) Log.d(TAG, "handleAudio() done.");
|
||||
}
|
||||
|
||||
@@ -361,6 +363,7 @@ class AudioPlaybackHandler {
|
||||
if (DBG) Log.d(TAG, "Created audio track [" + audioTrack.hashCode() + "]");
|
||||
|
||||
param.setAudioTrack(audioTrack);
|
||||
msg.getDispatcher().dispatchOnStart();
|
||||
}
|
||||
|
||||
// More data available to be flushed to the audio track.
|
||||
@@ -411,6 +414,7 @@ class AudioPlaybackHandler {
|
||||
final AudioTrack audioTrack = params.getAudioTrack();
|
||||
|
||||
if (audioTrack == null) {
|
||||
params.getDispatcher().dispatchOnError();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -439,7 +443,7 @@ class AudioPlaybackHandler {
|
||||
audioTrack.release();
|
||||
params.setAudioTrack(null);
|
||||
}
|
||||
params.getDispatcher().dispatchUtteranceCompleted();
|
||||
params.getDispatcher().dispatchOnDone();
|
||||
mLastSynthesisRequest = null;
|
||||
params.mLogger.onWriteData();
|
||||
}
|
||||
|
||||
@@ -21,5 +21,7 @@ package android.speech.tts;
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface ITextToSpeechCallback {
|
||||
void utteranceCompleted(String utteranceId);
|
||||
void onStart(String utteranceId);
|
||||
void onDone(String utteranceId);
|
||||
void onError(String utteranceId);
|
||||
}
|
||||
|
||||
@@ -15,22 +15,22 @@
|
||||
*/
|
||||
package android.speech.tts;
|
||||
|
||||
import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
|
||||
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
|
||||
|
||||
abstract class MessageParams {
|
||||
static final int TYPE_SYNTHESIS = 1;
|
||||
static final int TYPE_AUDIO = 2;
|
||||
static final int TYPE_SILENCE = 3;
|
||||
|
||||
private final UtteranceCompletedDispatcher mDispatcher;
|
||||
private final UtteranceProgressDispatcher mDispatcher;
|
||||
private final String mCallingApp;
|
||||
|
||||
MessageParams(UtteranceCompletedDispatcher dispatcher, String callingApp) {
|
||||
MessageParams(UtteranceProgressDispatcher dispatcher, String callingApp) {
|
||||
mDispatcher = dispatcher;
|
||||
mCallingApp = callingApp;
|
||||
}
|
||||
|
||||
UtteranceCompletedDispatcher getDispatcher() {
|
||||
UtteranceProgressDispatcher getDispatcher() {
|
||||
return mDispatcher;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package android.speech.tts;
|
||||
|
||||
import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
|
||||
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
@@ -62,12 +62,12 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
|
||||
|
||||
private volatile boolean mDone = false;
|
||||
|
||||
private final UtteranceCompletedDispatcher mDispatcher;
|
||||
private final UtteranceProgressDispatcher mDispatcher;
|
||||
private final String mCallingApp;
|
||||
private final EventLogger mLogger;
|
||||
|
||||
PlaybackSynthesisCallback(int streamType, float volume, float pan,
|
||||
AudioPlaybackHandler audioTrackHandler, UtteranceCompletedDispatcher dispatcher,
|
||||
AudioPlaybackHandler audioTrackHandler, UtteranceProgressDispatcher dispatcher,
|
||||
String callingApp, EventLogger logger) {
|
||||
mStreamType = streamType;
|
||||
mVolume = volume;
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
package android.speech.tts;
|
||||
|
||||
import android.os.ConditionVariable;
|
||||
import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
|
||||
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
|
||||
|
||||
class SilenceMessageParams extends MessageParams {
|
||||
private final ConditionVariable mCondVar = new ConditionVariable();
|
||||
private final long mSilenceDurationMs;
|
||||
|
||||
SilenceMessageParams(UtteranceCompletedDispatcher dispatcher,
|
||||
SilenceMessageParams(UtteranceProgressDispatcher dispatcher,
|
||||
String callingApp, long silenceDurationMs) {
|
||||
super(dispatcher, callingApp);
|
||||
mSilenceDurationMs = silenceDurationMs;
|
||||
|
||||
@@ -17,7 +17,7 @@ package android.speech.tts;
|
||||
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioTrack;
|
||||
import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
|
||||
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
@@ -56,7 +56,7 @@ final class SynthesisMessageParams extends MessageParams {
|
||||
|
||||
SynthesisMessageParams(int streamType, int sampleRate,
|
||||
int audioFormat, int channelCount,
|
||||
float volume, float pan, UtteranceCompletedDispatcher dispatcher,
|
||||
float volume, float pan, UtteranceProgressDispatcher dispatcher,
|
||||
String callingApp, EventLogger logger) {
|
||||
super(dispatcher, callingApp);
|
||||
|
||||
|
||||
@@ -482,7 +482,7 @@ public class TextToSpeech {
|
||||
private OnInitListener mInitListener;
|
||||
// Written from an unspecified application thread, read from
|
||||
// a binder thread.
|
||||
private volatile OnUtteranceCompletedListener mUtteranceCompletedListener;
|
||||
private volatile UtteranceProgressListener mUtteranceProgressListener;
|
||||
private final Object mStartLock = new Object();
|
||||
|
||||
private String mRequestedEngine;
|
||||
@@ -1146,9 +1146,28 @@ public class TextToSpeech {
|
||||
* @param listener The listener to use.
|
||||
*
|
||||
* @return {@link #ERROR} or {@link #SUCCESS}.
|
||||
*
|
||||
* @deprecated Use {@link #setOnUtteranceProgressListener(UtteranceProgressListener)}
|
||||
* instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) {
|
||||
mUtteranceCompletedListener = listener;
|
||||
mUtteranceProgressListener = UtteranceProgressListener.from(listener);
|
||||
return TextToSpeech.SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the listener that will be notified of various events related to the
|
||||
* synthesis of a given utterance.
|
||||
*
|
||||
* See {@link UtteranceProgressListener} and
|
||||
* {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
|
||||
*
|
||||
* @param listener the listener to use.
|
||||
* @return {@link #ERROR} or {@link #SUCCESS}
|
||||
*/
|
||||
public int setOnUtteranceProgressListener(UtteranceProgressListener listener) {
|
||||
mUtteranceProgressListener = listener;
|
||||
return TextToSpeech.SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1204,10 +1223,26 @@ public class TextToSpeech {
|
||||
private ITextToSpeechService mService;
|
||||
private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
|
||||
@Override
|
||||
public void utteranceCompleted(String utteranceId) {
|
||||
OnUtteranceCompletedListener listener = mUtteranceCompletedListener;
|
||||
public void onDone(String utteranceId) {
|
||||
UtteranceProgressListener listener = mUtteranceProgressListener;
|
||||
if (listener != null) {
|
||||
listener.onUtteranceCompleted(utteranceId);
|
||||
listener.onDone(utteranceId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String utteranceId) {
|
||||
UtteranceProgressListener listener = mUtteranceProgressListener;
|
||||
if (listener != null) {
|
||||
listener.onError(utteranceId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(String utteranceId) {
|
||||
UtteranceProgressListener listener = mUtteranceProgressListener;
|
||||
if (listener != null) {
|
||||
listener.onStart(utteranceId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -306,6 +306,7 @@ public abstract class TextToSpeechService extends Service {
|
||||
*/
|
||||
public int enqueueSpeechItem(int queueMode, final SpeechItem speechItem) {
|
||||
if (!speechItem.isValid()) {
|
||||
speechItem.dispatchOnError();
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
|
||||
@@ -332,6 +333,7 @@ public abstract class TextToSpeechService extends Service {
|
||||
return TextToSpeech.SUCCESS;
|
||||
} else {
|
||||
Log.w(TAG, "SynthThread has quit");
|
||||
speechItem.dispatchOnError();
|
||||
return TextToSpeech.ERROR;
|
||||
}
|
||||
}
|
||||
@@ -381,14 +383,16 @@ public abstract class TextToSpeechService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
interface UtteranceCompletedDispatcher {
|
||||
public void dispatchUtteranceCompleted();
|
||||
interface UtteranceProgressDispatcher {
|
||||
public void dispatchOnDone();
|
||||
public void dispatchOnStart();
|
||||
public void dispatchOnError();
|
||||
}
|
||||
|
||||
/**
|
||||
* An item in the synth thread queue.
|
||||
*/
|
||||
private abstract class SpeechItem implements UtteranceCompletedDispatcher {
|
||||
private abstract class SpeechItem implements UtteranceProgressDispatcher {
|
||||
private final String mCallingApp;
|
||||
protected final Bundle mParams;
|
||||
private boolean mStarted = false;
|
||||
@@ -443,10 +447,27 @@ public abstract class TextToSpeechService extends Service {
|
||||
stopImpl();
|
||||
}
|
||||
|
||||
public void dispatchUtteranceCompleted() {
|
||||
@Override
|
||||
public void dispatchOnDone() {
|
||||
final String utteranceId = getUtteranceId();
|
||||
if (!TextUtils.isEmpty(utteranceId)) {
|
||||
mCallbacks.dispatchUtteranceCompleted(getCallingApp(), utteranceId);
|
||||
mCallbacks.dispatchOnDone(getCallingApp(), utteranceId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchOnStart() {
|
||||
final String utteranceId = getUtteranceId();
|
||||
if (!TextUtils.isEmpty(utteranceId)) {
|
||||
mCallbacks.dispatchOnStart(getCallingApp(), utteranceId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchOnError() {
|
||||
final String utteranceId = getUtteranceId();
|
||||
if (!TextUtils.isEmpty(utteranceId)) {
|
||||
mCallbacks.dispatchOnError(getCallingApp(), utteranceId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -617,9 +638,12 @@ public abstract class TextToSpeechService extends Service {
|
||||
|
||||
@Override
|
||||
protected int playImpl() {
|
||||
dispatchOnStart();
|
||||
int status = super.playImpl();
|
||||
if (status == TextToSpeech.SUCCESS) {
|
||||
dispatchUtteranceCompleted();
|
||||
dispatchOnDone();
|
||||
} else {
|
||||
dispatchOnError();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -856,16 +880,34 @@ public abstract class TextToSpeechService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
public void dispatchUtteranceCompleted(String packageName, String utteranceId) {
|
||||
ITextToSpeechCallback cb;
|
||||
synchronized (mAppToCallback) {
|
||||
cb = mAppToCallback.get(packageName);
|
||||
}
|
||||
public void dispatchOnDone(String packageName, String utteranceId) {
|
||||
ITextToSpeechCallback cb = getCallbackFor(packageName);
|
||||
if (cb == null) return;
|
||||
try {
|
||||
cb.utteranceCompleted(utteranceId);
|
||||
cb.onDone(utteranceId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Callback failed: " + e);
|
||||
Log.e(TAG, "Callback onDone failed: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
public void dispatchOnStart(String packageName, String utteranceId) {
|
||||
ITextToSpeechCallback cb = getCallbackFor(packageName);
|
||||
if (cb == null) return;
|
||||
try {
|
||||
cb.onStart(utteranceId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Callback onStart failed: " + e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void dispatchOnError(String packageName, String utteranceId) {
|
||||
ITextToSpeechCallback cb = getCallbackFor(packageName);
|
||||
if (cb == null) return;
|
||||
try {
|
||||
cb.onError(utteranceId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Callback onError failed: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -886,6 +928,15 @@ public abstract class TextToSpeechService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
private ITextToSpeechCallback getCallbackFor(String packageName) {
|
||||
ITextToSpeechCallback cb;
|
||||
synchronized (mAppToCallback) {
|
||||
cb = mAppToCallback.get(packageName);
|
||||
}
|
||||
|
||||
return cb;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
68
core/java/android/speech/tts/UtteranceProgressListener.java
Normal file
68
core/java/android/speech/tts/UtteranceProgressListener.java
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
|
||||
package android.speech.tts;
|
||||
|
||||
/**
|
||||
* Listener for events relating to the progress of an utterance through
|
||||
* the synthesis queue. Each utterance is associated with a call to
|
||||
* {@link TextToSpeech#speak} or {@link TextToSpeech#synthesizeToFile} with an
|
||||
* associated utterance identifier, as per {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
|
||||
*
|
||||
* The callbacks specified in this method can be called from multiple threads.
|
||||
*/
|
||||
public abstract class UtteranceProgressListener {
|
||||
/**
|
||||
* Called when an utterance "starts" as perceived by the caller. This will
|
||||
* be soon before audio is played back in the case of a {@link TextToSpeech#speak}
|
||||
* or before the first bytes of a file are written to storage in the case
|
||||
* of {@link TextToSpeech#synthesizeToFile}.
|
||||
*
|
||||
* @param utteranceId the utterance ID of the utterance.
|
||||
*/
|
||||
public abstract void onStart(String utteranceId);
|
||||
|
||||
/**
|
||||
* Called when an utterance has successfully completed processing.
|
||||
* All audio will have been played back by this point for audible output, and all
|
||||
* output will have been written to disk for file synthesis requests.
|
||||
*
|
||||
* This request is guaranteed to be called after {@link #onStart(String)}.
|
||||
*
|
||||
* @param utteranceId the utterance ID of the utterance.
|
||||
*/
|
||||
public abstract void onDone(String utteranceId);
|
||||
|
||||
/**
|
||||
* Called when an error has occurred during processing. This can be called
|
||||
* at any point in the synthesis process. Note that there might be calls
|
||||
* to {@link #onStart(String)} for specified utteranceId but there will never
|
||||
* be a call to both {@link #onDone(String)} and {@link #onError(String)} for
|
||||
* the same utterance.
|
||||
*
|
||||
* @param utteranceId the utterance ID of the utterance.
|
||||
*/
|
||||
public abstract void onError(String utteranceId);
|
||||
|
||||
/**
|
||||
* Wraps an old deprecated OnUtteranceCompletedListener with a shiny new
|
||||
* progress listener.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
static UtteranceProgressListener from(
|
||||
final TextToSpeech.OnUtteranceCompletedListener listener) {
|
||||
return new UtteranceProgressListener() {
|
||||
@Override
|
||||
public synchronized void onDone(String utteranceId) {
|
||||
listener.onUtteranceCompleted(utteranceId);
|
||||
}
|
||||
|
||||
// The following methods are left unimplemented.
|
||||
@Override
|
||||
public void onStart(String utteranceId) { }
|
||||
|
||||
@Override
|
||||
public void onError(String utteranceId) { }
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user