Skip to content

Commit 754c72e

Browse files
committed
Notifiy callers when a speech synthesis error occurs.
bug:5589877 Change-Id: Ideca8966ea1caa6789b3273e388dd1f25c1e2758
1 parent 08e4296 commit 754c72e

11 files changed

+203
-35
lines changed

api/current.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18890,7 +18890,8 @@ package android.speech.tts {
1889018890
method public int playSilence(long, int, java.util.HashMap<java.lang.String, java.lang.String>);
1889118891
method public deprecated int setEngineByPackageName(java.lang.String);
1889218892
method public int setLanguage(java.util.Locale);
18893-
method public int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
18893+
method public deprecated int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
18894+
method public int setOnUtteranceProgressListener(android.speech.tts.UtteranceProgressListener);
1889418895
method public int setPitch(float);
1889518896
method public int setSpeechRate(float);
1889618897
method public void shutdown();
@@ -18963,6 +18964,13 @@ package android.speech.tts {
1896318964
method protected abstract void onSynthesizeText(android.speech.tts.SynthesisRequest, android.speech.tts.SynthesisCallback);
1896418965
}
1896518966

18967+
public abstract class UtteranceProgressListener {
18968+
ctor public UtteranceProgressListener();
18969+
method public abstract void onDone(java.lang.String);
18970+
method public abstract void onError(java.lang.String);
18971+
method public abstract void onStart(java.lang.String);
18972+
}
18973+
1896618974
}
1896718975

1896818976
package android.telephony {

core/java/android/speech/tts/AudioMessageParams.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
*/
1616
package android.speech.tts;
1717

18-
import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
18+
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
1919

2020
class AudioMessageParams extends MessageParams {
2121
private final BlockingMediaPlayer mPlayer;
2222

23-
AudioMessageParams(UtteranceCompletedDispatcher dispatcher,
23+
AudioMessageParams(UtteranceProgressDispatcher dispatcher,
2424
String callingApp, BlockingMediaPlayer player) {
2525
super(dispatcher, callingApp);
2626
mPlayer = player;

core/java/android/speech/tts/AudioPlaybackHandler.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,22 +312,24 @@ private void handleMessage(ListEntry entry) {
312312
private void handleSilence(MessageParams msg) {
313313
if (DBG) Log.d(TAG, "handleSilence()");
314314
SilenceMessageParams params = (SilenceMessageParams) msg;
315+
params.getDispatcher().dispatchOnStart();
315316
if (params.getSilenceDurationMs() > 0) {
316317
params.getConditionVariable().block(params.getSilenceDurationMs());
317318
}
318-
params.getDispatcher().dispatchUtteranceCompleted();
319+
params.getDispatcher().dispatchOnDone();
319320
if (DBG) Log.d(TAG, "handleSilence() done.");
320321
}
321322

322323
// Plays back audio from a given URI. No TTS engine involvement here.
323324
private void handleAudio(MessageParams msg) {
324325
if (DBG) Log.d(TAG, "handleAudio()");
325326
AudioMessageParams params = (AudioMessageParams) msg;
327+
params.getDispatcher().dispatchOnStart();
326328
// Note that the BlockingMediaPlayer spawns a separate thread.
327329
//
328330
// TODO: This can be avoided.
329331
params.getPlayer().startAndWait();
330-
params.getDispatcher().dispatchUtteranceCompleted();
332+
params.getDispatcher().dispatchOnDone();
331333
if (DBG) Log.d(TAG, "handleAudio() done.");
332334
}
333335

@@ -361,6 +363,7 @@ private void handleSynthesisStart(MessageParams msg) {
361363
if (DBG) Log.d(TAG, "Created audio track [" + audioTrack.hashCode() + "]");
362364

363365
param.setAudioTrack(audioTrack);
366+
msg.getDispatcher().dispatchOnStart();
364367
}
365368

366369
// More data available to be flushed to the audio track.
@@ -411,6 +414,7 @@ private void handleSynthesisDone(MessageParams msg) {
411414
final AudioTrack audioTrack = params.getAudioTrack();
412415

413416
if (audioTrack == null) {
417+
params.getDispatcher().dispatchOnError();
414418
return;
415419
}
416420

@@ -439,7 +443,7 @@ private void handleSynthesisDone(MessageParams msg) {
439443
audioTrack.release();
440444
params.setAudioTrack(null);
441445
}
442-
params.getDispatcher().dispatchUtteranceCompleted();
446+
params.getDispatcher().dispatchOnDone();
443447
mLastSynthesisRequest = null;
444448
params.mLogger.onWriteData();
445449
}

core/java/android/speech/tts/ITextToSpeechCallback.aidl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,7 @@ package android.speech.tts;
2121
* {@hide}
2222
*/
2323
oneway interface ITextToSpeechCallback {
24-
void utteranceCompleted(String utteranceId);
24+
void onStart(String utteranceId);
25+
void onDone(String utteranceId);
26+
void onError(String utteranceId);
2527
}

core/java/android/speech/tts/MessageParams.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,22 @@
1515
*/
1616
package android.speech.tts;
1717

18-
import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
18+
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
1919

2020
abstract class MessageParams {
2121
static final int TYPE_SYNTHESIS = 1;
2222
static final int TYPE_AUDIO = 2;
2323
static final int TYPE_SILENCE = 3;
2424

25-
private final UtteranceCompletedDispatcher mDispatcher;
25+
private final UtteranceProgressDispatcher mDispatcher;
2626
private final String mCallingApp;
2727

28-
MessageParams(UtteranceCompletedDispatcher dispatcher, String callingApp) {
28+
MessageParams(UtteranceProgressDispatcher dispatcher, String callingApp) {
2929
mDispatcher = dispatcher;
3030
mCallingApp = callingApp;
3131
}
3232

33-
UtteranceCompletedDispatcher getDispatcher() {
33+
UtteranceProgressDispatcher getDispatcher() {
3434
return mDispatcher;
3535
}
3636

core/java/android/speech/tts/PlaybackSynthesisCallback.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616
package android.speech.tts;
1717

18-
import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
18+
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
1919
import android.util.Log;
2020

2121
/**
@@ -62,12 +62,12 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback {
6262

6363
private volatile boolean mDone = false;
6464

65-
private final UtteranceCompletedDispatcher mDispatcher;
65+
private final UtteranceProgressDispatcher mDispatcher;
6666
private final String mCallingApp;
6767
private final EventLogger mLogger;
6868

6969
PlaybackSynthesisCallback(int streamType, float volume, float pan,
70-
AudioPlaybackHandler audioTrackHandler, UtteranceCompletedDispatcher dispatcher,
70+
AudioPlaybackHandler audioTrackHandler, UtteranceProgressDispatcher dispatcher,
7171
String callingApp, EventLogger logger) {
7272
mStreamType = streamType;
7373
mVolume = volume;

core/java/android/speech/tts/SilenceMessageParams.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
package android.speech.tts;
1717

1818
import android.os.ConditionVariable;
19-
import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
19+
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
2020

2121
class SilenceMessageParams extends MessageParams {
2222
private final ConditionVariable mCondVar = new ConditionVariable();
2323
private final long mSilenceDurationMs;
2424

25-
SilenceMessageParams(UtteranceCompletedDispatcher dispatcher,
25+
SilenceMessageParams(UtteranceProgressDispatcher dispatcher,
2626
String callingApp, long silenceDurationMs) {
2727
super(dispatcher, callingApp);
2828
mSilenceDurationMs = silenceDurationMs;

core/java/android/speech/tts/SynthesisMessageParams.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import android.media.AudioFormat;
1919
import android.media.AudioTrack;
20-
import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
20+
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
2121

2222
import java.util.LinkedList;
2323

@@ -56,7 +56,7 @@ final class SynthesisMessageParams extends MessageParams {
5656

5757
SynthesisMessageParams(int streamType, int sampleRate,
5858
int audioFormat, int channelCount,
59-
float volume, float pan, UtteranceCompletedDispatcher dispatcher,
59+
float volume, float pan, UtteranceProgressDispatcher dispatcher,
6060
String callingApp, EventLogger logger) {
6161
super(dispatcher, callingApp);
6262

core/java/android/speech/tts/TextToSpeech.java

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ public class Engine {
482482
private OnInitListener mInitListener;
483483
// Written from an unspecified application thread, read from
484484
// a binder thread.
485-
private volatile OnUtteranceCompletedListener mUtteranceCompletedListener;
485+
private volatile UtteranceProgressListener mUtteranceProgressListener;
486486
private final Object mStartLock = new Object();
487487

488488
private String mRequestedEngine;
@@ -1146,9 +1146,28 @@ private void copyFloatParam(Bundle bundle, HashMap<String, String> params, Strin
11461146
* @param listener The listener to use.
11471147
*
11481148
* @return {@link #ERROR} or {@link #SUCCESS}.
1149+
*
1150+
* @deprecated Use {@link #setOnUtteranceProgressListener(UtteranceProgressListener)}
1151+
* instead.
11491152
*/
1153+
@Deprecated
11501154
public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) {
1151-
mUtteranceCompletedListener = listener;
1155+
mUtteranceProgressListener = UtteranceProgressListener.from(listener);
1156+
return TextToSpeech.SUCCESS;
1157+
}
1158+
1159+
/**
1160+
* Sets the listener that will be notified of various events related to the
1161+
* synthesis of a given utterance.
1162+
*
1163+
* See {@link UtteranceProgressListener} and
1164+
* {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
1165+
*
1166+
* @param listener the listener to use.
1167+
* @return {@link #ERROR} or {@link #SUCCESS}
1168+
*/
1169+
public int setOnUtteranceProgressListener(UtteranceProgressListener listener) {
1170+
mUtteranceProgressListener = listener;
11521171
return TextToSpeech.SUCCESS;
11531172
}
11541173

@@ -1204,10 +1223,26 @@ private class Connection implements ServiceConnection {
12041223
private ITextToSpeechService mService;
12051224
private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
12061225
@Override
1207-
public void utteranceCompleted(String utteranceId) {
1208-
OnUtteranceCompletedListener listener = mUtteranceCompletedListener;
1226+
public void onDone(String utteranceId) {
1227+
UtteranceProgressListener listener = mUtteranceProgressListener;
1228+
if (listener != null) {
1229+
listener.onDone(utteranceId);
1230+
}
1231+
}
1232+
1233+
@Override
1234+
public void onError(String utteranceId) {
1235+
UtteranceProgressListener listener = mUtteranceProgressListener;
1236+
if (listener != null) {
1237+
listener.onError(utteranceId);
1238+
}
1239+
}
1240+
1241+
@Override
1242+
public void onStart(String utteranceId) {
1243+
UtteranceProgressListener listener = mUtteranceProgressListener;
12091244
if (listener != null) {
1210-
listener.onUtteranceCompleted(utteranceId);
1245+
listener.onStart(utteranceId);
12111246
}
12121247
}
12131248
};

core/java/android/speech/tts/TextToSpeechService.java

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ public void quit() {
306306
*/
307307
public int enqueueSpeechItem(int queueMode, final SpeechItem speechItem) {
308308
if (!speechItem.isValid()) {
309+
speechItem.dispatchOnError();
309310
return TextToSpeech.ERROR;
310311
}
311312

@@ -332,6 +333,7 @@ public void run() {
332333
return TextToSpeech.SUCCESS;
333334
} else {
334335
Log.w(TAG, "SynthThread has quit");
336+
speechItem.dispatchOnError();
335337
return TextToSpeech.ERROR;
336338
}
337339
}
@@ -381,14 +383,16 @@ public int stopAll() {
381383
}
382384
}
383385

384-
interface UtteranceCompletedDispatcher {
385-
public void dispatchUtteranceCompleted();
386+
interface UtteranceProgressDispatcher {
387+
public void dispatchOnDone();
388+
public void dispatchOnStart();
389+
public void dispatchOnError();
386390
}
387391

388392
/**
389393
* An item in the synth thread queue.
390394
*/
391-
private abstract class SpeechItem implements UtteranceCompletedDispatcher {
395+
private abstract class SpeechItem implements UtteranceProgressDispatcher {
392396
private final String mCallingApp;
393397
protected final Bundle mParams;
394398
private boolean mStarted = false;
@@ -443,10 +447,27 @@ public void stop() {
443447
stopImpl();
444448
}
445449

446-
public void dispatchUtteranceCompleted() {
450+
@Override
451+
public void dispatchOnDone() {
452+
final String utteranceId = getUtteranceId();
453+
if (!TextUtils.isEmpty(utteranceId)) {
454+
mCallbacks.dispatchOnDone(getCallingApp(), utteranceId);
455+
}
456+
}
457+
458+
@Override
459+
public void dispatchOnStart() {
460+
final String utteranceId = getUtteranceId();
461+
if (!TextUtils.isEmpty(utteranceId)) {
462+
mCallbacks.dispatchOnStart(getCallingApp(), utteranceId);
463+
}
464+
}
465+
466+
@Override
467+
public void dispatchOnError() {
447468
final String utteranceId = getUtteranceId();
448469
if (!TextUtils.isEmpty(utteranceId)) {
449-
mCallbacks.dispatchUtteranceCompleted(getCallingApp(), utteranceId);
470+
mCallbacks.dispatchOnError(getCallingApp(), utteranceId);
450471
}
451472
}
452473

@@ -617,9 +638,12 @@ protected AbstractSynthesisCallback createSynthesisCallback() {
617638

618639
@Override
619640
protected int playImpl() {
641+
dispatchOnStart();
620642
int status = super.playImpl();
621643
if (status == TextToSpeech.SUCCESS) {
622-
dispatchUtteranceCompleted();
644+
dispatchOnDone();
645+
} else {
646+
dispatchOnError();
623647
}
624648
return status;
625649
}
@@ -856,16 +880,34 @@ public void setCallback(String packageName, ITextToSpeechCallback cb) {
856880
}
857881
}
858882

859-
public void dispatchUtteranceCompleted(String packageName, String utteranceId) {
860-
ITextToSpeechCallback cb;
861-
synchronized (mAppToCallback) {
862-
cb = mAppToCallback.get(packageName);
883+
public void dispatchOnDone(String packageName, String utteranceId) {
884+
ITextToSpeechCallback cb = getCallbackFor(packageName);
885+
if (cb == null) return;
886+
try {
887+
cb.onDone(utteranceId);
888+
} catch (RemoteException e) {
889+
Log.e(TAG, "Callback onDone failed: " + e);
863890
}
891+
}
892+
893+
public void dispatchOnStart(String packageName, String utteranceId) {
894+
ITextToSpeechCallback cb = getCallbackFor(packageName);
895+
if (cb == null) return;
896+
try {
897+
cb.onStart(utteranceId);
898+
} catch (RemoteException e) {
899+
Log.e(TAG, "Callback onStart failed: " + e);
900+
}
901+
902+
}
903+
904+
public void dispatchOnError(String packageName, String utteranceId) {
905+
ITextToSpeechCallback cb = getCallbackFor(packageName);
864906
if (cb == null) return;
865907
try {
866-
cb.utteranceCompleted(utteranceId);
908+
cb.onError(utteranceId);
867909
} catch (RemoteException e) {
868-
Log.e(TAG, "Callback failed: " + e);
910+
Log.e(TAG, "Callback onError failed: " + e);
869911
}
870912
}
871913

@@ -886,6 +928,15 @@ public void kill() {
886928
}
887929
}
888930

931+
private ITextToSpeechCallback getCallbackFor(String packageName) {
932+
ITextToSpeechCallback cb;
933+
synchronized (mAppToCallback) {
934+
cb = mAppToCallback.get(packageName);
935+
}
936+
937+
return cb;
938+
}
939+
889940
}
890941

891942
}

0 commit comments

Comments
 (0)