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:
Narayan Kamath
2011-11-11 11:47:54 -08:00
committed by Android Git Automerger
11 changed files with 204 additions and 36 deletions

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
}
}
};

View File

@@ -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;
}
}
}

View 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) { }
};
}
}