PlaybackSynthesisCallback.java revision 754c72ed9e8e83e5a913aa7552fc2e1b1b5277e0
150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert/*
250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * Copyright (C) 2011 The Android Open Source Project
350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert *
450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); you may not
550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * use this file except in compliance with the License. You may obtain a copy of
650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * the License at
750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert *
850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert *
1050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * Unless required by applicable law or agreed to in writing, software
1150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
1250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * License for the specific language governing permissions and limitations under
1450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * the License.
1550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert */
1650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringertpackage android.speech.tts;
1750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
18754c72ed9e8e83e5a913aa7552fc2e1b1b5277e0Narayan Kamathimport android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
1950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringertimport android.util.Log;
2050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
2150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert/**
2250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * Speech synthesis request that plays the audio as it is received.
2350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert */
24e22b69a7de0349b99d3107349d1d3aa72d62c841Narayan Kamathclass PlaybackSynthesisCallback extends AbstractSynthesisCallback {
2550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
2650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private static final String TAG = "PlaybackSynthesisRequest";
2750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private static final boolean DBG = false;
2850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
2950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private static final int MIN_AUDIO_BUFFER_SIZE = 8192;
3050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
3150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    /**
3250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     * Audio stream type. Must be one of the STREAM_ contants defined in
3350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     * {@link android.media.AudioManager}.
3450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     */
3550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private final int mStreamType;
3650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
3750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    /**
3850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     * Volume, in the range [0.0f, 1.0f]. The default value is
3950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     * {@link TextToSpeech.Engine#DEFAULT_VOLUME} (1.0f).
4050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     */
4150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private final float mVolume;
4250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
4350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    /**
4450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     * Left/right position of the audio, in the range [-1.0f, 1.0f].
4550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     * The default value is {@link TextToSpeech.Engine#DEFAULT_PAN} (0.0f).
4650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert     */
4750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private final float mPan;
4850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
498d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    /**
508d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath     * Guards {@link #mAudioTrackHandler}, {@link #mToken} and {@link #mStopped}.
518d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath     */
5250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private final Object mStateLock = new Object();
538d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
548d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    // Handler associated with a thread that plays back audio requests.
558d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    private final AudioPlaybackHandler mAudioTrackHandler;
56c3da8818f0598b3ab2cd6f4168349da6d0f72cb1Narayan Kamath    // A request "token", which will be non null after start() has been called.
578d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    private SynthesisMessageParams mToken = null;
588d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    // Whether this request has been stopped. This is useful for keeping
598d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    // track whether stop() has been called before start(). In all other cases,
608d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    // a non-null value of mToken will provide the same information.
6150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    private boolean mStopped = false;
6250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
638d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath    private volatile boolean mDone = false;
648d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
65754c72ed9e8e83e5a913aa7552fc2e1b1b5277e0Narayan Kamath    private final UtteranceProgressDispatcher mDispatcher;
664924fe38675f0bf69bb0c16fc059ffa1606807ceNarayan Kamath    private final String mCallingApp;
676dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath    private final EventLogger mLogger;
688d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
69e22b69a7de0349b99d3107349d1d3aa72d62c841Narayan Kamath    PlaybackSynthesisCallback(int streamType, float volume, float pan,
70754c72ed9e8e83e5a913aa7552fc2e1b1b5277e0Narayan Kamath            AudioPlaybackHandler audioTrackHandler, UtteranceProgressDispatcher dispatcher,
716dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath            String callingApp, EventLogger logger) {
7250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        mStreamType = streamType;
7350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        mVolume = volume;
7450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        mPan = pan;
75c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath        mAudioTrackHandler = audioTrackHandler;
768d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        mDispatcher = dispatcher;
774924fe38675f0bf69bb0c16fc059ffa1606807ceNarayan Kamath        mCallingApp = callingApp;
786dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        mLogger = logger;
7950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
8050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
8150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    @Override
8250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    void stop() {
8350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        if (DBG) Log.d(TAG, "stop()");
848d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
856dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        // Note that mLogger.mError might be true too at this point.
866dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        mLogger.onStopped();
876dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath
882a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        SynthesisMessageParams token = null;
8950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        synchronized (mStateLock) {
906dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath            if (mStopped) {
916dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath                Log.w(TAG, "stop() called twice");
928d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                return;
938d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            }
94be4ad4ac66d6b4b878ed052975f7fb09af92c6d6Narayan Kamath
956dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath            // mToken will be null if the engine encounters
966dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath            // an error before it called start().
97be4ad4ac66d6b4b878ed052975f7fb09af92c6d6Narayan Kamath            if (mToken == null) {
986dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath                // In all other cases, mAudioTrackHandler.stop() will
996dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath                // result in onComplete being called.
1006dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath                mLogger.onWriteData();
1012a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath            } else {
1022a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath                token = mToken;
1036dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath            }
10450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            mStopped = true;
10550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
1062a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath
1072a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        if (token != null) {
1082a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath            // This might result in the synthesis thread being woken up, at which
1092a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath            // point it will write an additional buffer to the token - but we
1102a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath            // won't worry about that because the audio playback queue will be cleared
1112a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath            // soon after (see SynthHandler#stop(String).
1122a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath            token.clearBuffers();
1132a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        }
11450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
11550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
11671e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    @Override
11771e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    public int getMaxBufferSize() {
11871e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        // The AudioTrack buffer will be at least MIN_AUDIO_BUFFER_SIZE, so that should always be
11971e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        // a safe buffer size to pass in.
12071e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        return MIN_AUDIO_BUFFER_SIZE;
12171e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    }
12271e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert
123360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    @Override
124360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    boolean isDone() {
125360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert        return mDone;
126360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    }
127360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert
12850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    @Override
12950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    public int start(int sampleRateInHz, int audioFormat, int channelCount) {
13050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        if (DBG) {
13150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            Log.d(TAG, "start(" + sampleRateInHz + "," + audioFormat
13250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                    + "," + channelCount + ")");
13350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
13450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
1358d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        int channelConfig = AudioPlaybackHandler.getChannelConfig(channelCount);
1368d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        if (channelConfig == 0) {
1378d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            Log.e(TAG, "Unsupported number of channels :" + channelCount);
1388d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            return TextToSpeech.ERROR;
1398d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        }
1408d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
14150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        synchronized (mStateLock) {
14250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            if (mStopped) {
1438d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                if (DBG) Log.d(TAG, "stop() called before start(), returning.");
14450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                return TextToSpeech.ERROR;
14550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            }
1468d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            SynthesisMessageParams params = new SynthesisMessageParams(
1478d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                    mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
1486dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath                    mDispatcher, mCallingApp, mLogger);
1498d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mAudioTrackHandler.enqueueSynthesisStart(params);
15050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
1518d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mToken = params;
15250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
15350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
15450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        return TextToSpeech.SUCCESS;
15550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
15650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
15750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
15850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    @Override
15950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    public int audioAvailable(byte[] buffer, int offset, int length) {
16050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        if (DBG) {
16150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            Log.d(TAG, "audioAvailable(byte[" + buffer.length + "],"
16271e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert                    + offset + "," + length + ")");
16371e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        }
164c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath        if (length > getMaxBufferSize() || length <= 0) {
165c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath            throw new IllegalArgumentException("buffer is too large or of zero length (" +
166c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath                    + length + " bytes)");
16750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
1688d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
1692a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        SynthesisMessageParams token = null;
17050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        synchronized (mStateLock) {
171be4ad4ac66d6b4b878ed052975f7fb09af92c6d6Narayan Kamath            if (mToken == null || mStopped) {
17250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                return TextToSpeech.ERROR;
17350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            }
1742a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath            token = mToken;
17550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
1768d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
1772a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        // Sigh, another copy.
1782a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        final byte[] bufferCopy = new byte[length];
1792a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        System.arraycopy(buffer, offset, bufferCopy, 0, length);
1802a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        // Might block on mToken.this, if there are too many buffers waiting to
1812a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        // be consumed.
1822a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        token.addBuffer(bufferCopy);
1832a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        mAudioTrackHandler.enqueueSynthesisDataAvailable(token);
1842a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath
1856dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        mLogger.onEngineDataReceived();
1866dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath
1878d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        return TextToSpeech.SUCCESS;
18850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
18950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
19050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    @Override
19150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    public int done() {
19250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        if (DBG) Log.d(TAG, "done()");
1938d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
1942a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        SynthesisMessageParams token = null;
19550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        synchronized (mStateLock) {
1968d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            if (mDone) {
1978d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                Log.w(TAG, "Duplicate call to done()");
19850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                return TextToSpeech.ERROR;
19950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            }
2008d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
2018d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mDone = true;
2028d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
2038d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            if (mToken == null) {
20450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                return TextToSpeech.ERROR;
20550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            }
2068d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
2072a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath            token = mToken;
20850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
2092a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath
2102a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        mAudioTrackHandler.enqueueSynthesisDone(token);
2112a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        mLogger.onEngineComplete();
2122a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath
21350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        return TextToSpeech.SUCCESS;
21450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
21571e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert
21671e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    @Override
217360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    public void error() {
2188d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        if (DBG) Log.d(TAG, "error() [will call stop]");
2196dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        // Currently, this call will not be logged if error( ) is called
2206dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        // before start.
2216dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        mLogger.onError();
2228d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        stop();
223360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    }
224360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert
22553f6f95308854e7da1fcd15081030d7de2fc5a7fNarayan Kamath}
226