Fix regressions in TTS completion callbacks.

(a) onUtteranceCompleted should be called on errors too. Also,
fix up the error handling so that onUtteranceCompleted is
always called.
(b) Don't treat empty utterances as errors, and let the engine
synthesize them, as before.

bug:5662598
Change-Id: I9223592bc6fe5f47d71103f4f02f046b54a655a8
This commit is contained in:
Narayan Kamath
2011-11-23 16:42:53 +00:00
parent 8bb56180d2
commit 40f71f0be3
5 changed files with 65 additions and 19 deletions

View File

@@ -118,12 +118,26 @@ class AudioPlaybackHandler {
if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) {
stop(current);
}
final MessageParams lastSynthesis = mLastSynthesisRequest;
if (lastSynthesis != null && lastSynthesis != current &&
TextUtils.equals(callingApp, lastSynthesis.getCallingApp())) {
stop(lastSynthesis);
}
}
synchronized public void removeAllItems() {
if (DBG_THREADING) Log.d(TAG, "Removing all items");
removeAllMessages();
stop(getCurrentParams());
final MessageParams current = getCurrentParams();
final MessageParams lastSynthesis = mLastSynthesisRequest;
stop(current);
if (lastSynthesis != null && lastSynthesis != current) {
stop(lastSynthesis);
}
}
/**
@@ -350,7 +364,7 @@ class AudioPlaybackHandler {
// extra trouble to clean the data to prevent the AudioTrack resources
// from being leaked.
if (mLastSynthesisRequest != null) {
Log.w(TAG, "Error : Missing call to done() for request : " +
Log.e(TAG, "Error : Missing call to done() for request : " +
mLastSynthesisRequest);
handleSynthesisDone(mLastSynthesisRequest);
}
@@ -443,7 +457,11 @@ class AudioPlaybackHandler {
audioTrack.release();
params.setAudioTrack(null);
}
params.getDispatcher().dispatchOnDone();
if (params.isError()) {
params.getDispatcher().dispatchOnError();
} else {
params.getDispatcher().dispatchOnDone();
}
mLastSynthesisRequest = null;
params.mLogger.onWriteData();
}

View File

@@ -80,27 +80,23 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
@Override
void stop() {
stopImpl(false);
}
void stopImpl(boolean wasError) {
if (DBG) Log.d(TAG, "stop()");
// Note that mLogger.mError might be true too at this point.
mLogger.onStopped();
SynthesisMessageParams token = null;
SynthesisMessageParams token;
synchronized (mStateLock) {
if (mStopped) {
Log.w(TAG, "stop() called twice");
return;
}
// mToken will be null if the engine encounters
// an error before it called start().
if (mToken == null) {
// In all other cases, mAudioTrackHandler.stop() will
// result in onComplete being called.
mLogger.onWriteData();
} else {
token = mToken;
}
token = mToken;
mStopped = true;
}
@@ -109,7 +105,24 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
// point it will write an additional buffer to the token - but we
// won't worry about that because the audio playback queue will be cleared
// soon after (see SynthHandler#stop(String).
token.setIsError(wasError);
token.clearBuffers();
if (wasError) {
// Also clean up the audio track if an error occurs.
mAudioTrackHandler.enqueueSynthesisDone(token);
}
} else {
// This happens when stop() or error() were called before start() was.
// In all other cases, mAudioTrackHandler.stop() will
// result in onSynthesisDone being called, and we will
// write data there.
mLogger.onWriteData();
if (wasError) {
// We have to dispatch the error ourselves.
mDispatcher.dispatchOnError();
}
}
}
@@ -219,7 +232,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
// Currently, this call will not be logged if error( ) is called
// before start.
mLogger.onError();
stop();
stopImpl(true);
}
}

View File

@@ -51,6 +51,7 @@ final class SynthesisMessageParams extends MessageParams {
int mAudioBufferSize;
// Always synchronized on "this".
int mUnconsumedBytes;
volatile boolean mIsError;
private final LinkedList<ListEntry> mDataBufferList = new LinkedList<ListEntry>();
@@ -74,6 +75,7 @@ final class SynthesisMessageParams extends MessageParams {
mAudioTrack = null;
mBytesWritten = 0;
mAudioBufferSize = 0;
mIsError = false;
}
@Override
@@ -120,6 +122,14 @@ final class SynthesisMessageParams extends MessageParams {
return mAudioTrack;
}
void setIsError(boolean isError) {
mIsError = isError;
}
boolean isError() {
return mIsError;
}
// Must be called synchronized on this.
private long getUnconsumedAudioLengthMs() {
final int unconsumedFrames = mUnconsumedBytes / mBytesPerFrame;

View File

@@ -509,6 +509,7 @@ public abstract class TextToSpeechService extends Service {
}
class SynthesisSpeechItem extends SpeechItem {
// Never null.
private final String mText;
private final SynthesisRequest mSynthesisRequest;
private final String[] mDefaultLocale;
@@ -532,8 +533,8 @@ public abstract class TextToSpeechService extends Service {
@Override
public boolean isValid() {
if (TextUtils.isEmpty(mText)) {
Log.w(TAG, "Got empty text");
if (mText == null) {
Log.wtf(TAG, "Got null text");
return false;
}
if (mText.length() >= MAX_SPEECH_ITEM_CHAR_LENGTH) {

View File

@@ -57,12 +57,16 @@ public abstract class UtteranceProgressListener {
listener.onUtteranceCompleted(utteranceId);
}
// The following methods are left unimplemented.
@Override
public void onStart(String utteranceId) { }
public void onError(String utteranceId) {
listener.onUtteranceCompleted(utteranceId);
}
@Override
public void onError(String utteranceId) { }
public void onStart(String utteranceId) {
// Left unimplemented, has no equivalent in the old
// API.
}
};
}
}