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    /**
5067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath     * Guards {@link #mAudioTrackHandler}, {@link #mItem} 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.
5767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private SynthesisPlaybackQueueItem mItem = 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,
6067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    // a non-null value of mItem 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;
66492b7f0d51f53164aa6eb974cd7ab6a7889af677Narayan Kamath    private final Object mCallerIdentity;
676dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath    private final EventLogger mLogger;
688d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
69e22b69a7de0349b99d3107349d1d3aa72d62c841Narayan Kamath    PlaybackSynthesisCallback(int streamType, float volume, float pan,
70754c72ed9e8e83e5a913aa7552fc2e1b1b5277e0Narayan Kamath            AudioPlaybackHandler audioTrackHandler, UtteranceProgressDispatcher dispatcher,
71492b7f0d51f53164aa6eb974cd7ab6a7889af677Narayan Kamath            Object callerIdentity, EventLogger logger) {
7250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        mStreamType = streamType;
7350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        mVolume = volume;
7450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        mPan = pan;
75c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath        mAudioTrackHandler = audioTrackHandler;
768d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        mDispatcher = dispatcher;
77492b7f0d51f53164aa6eb974cd7ab6a7889af677Narayan Kamath        mCallerIdentity = callerIdentity;
786dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        mLogger = logger;
7950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
8050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
8150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    @Override
8250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    void stop() {
8340f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath        stopImpl(false);
8440f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath    }
8540f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath
8640f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath    void stopImpl(boolean wasError) {
8750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        if (DBG) Log.d(TAG, "stop()");
888d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
896dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        // Note that mLogger.mError might be true too at this point.
906dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        mLogger.onStopped();
916dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath
9267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        SynthesisPlaybackQueueItem item;
9350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        synchronized (mStateLock) {
946dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath            if (mStopped) {
956dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath                Log.w(TAG, "stop() called twice");
968d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                return;
978d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            }
98be4ad4ac66d6b4b878ed052975f7fb09af92c6d6Narayan Kamath
9967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            item = mItem;
10050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            mStopped = true;
10150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
1022a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath
10367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        if (item != null) {
1042a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath            // This might result in the synthesis thread being woken up, at which
10567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // point it will write an additional buffer to the item - but we
1062a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath            // won't worry about that because the audio playback queue will be cleared
1072a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath            // soon after (see SynthHandler#stop(String).
10867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            item.stop(wasError);
10940f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath        } else {
11040f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath            // This happens when stop() or error() were called before start() was.
11140f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath
11240f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath            // In all other cases, mAudioTrackHandler.stop() will
11340f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath            // result in onSynthesisDone being called, and we will
11440f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath            // write data there.
11540f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath            mLogger.onWriteData();
11640f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath
11740f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath            if (wasError) {
11840f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath                // We have to dispatch the error ourselves.
11940f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath                mDispatcher.dispatchOnError();
12040f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath            }
1212a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        }
12250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
12350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
12471e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    @Override
12571e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    public int getMaxBufferSize() {
12671e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        // The AudioTrack buffer will be at least MIN_AUDIO_BUFFER_SIZE, so that should always be
12771e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        // a safe buffer size to pass in.
12871e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        return MIN_AUDIO_BUFFER_SIZE;
12971e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    }
13071e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert
131360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    @Override
132360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    boolean isDone() {
133360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert        return mDone;
134360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    }
135360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert
13650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    @Override
13750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    public int start(int sampleRateInHz, int audioFormat, int channelCount) {
13850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        if (DBG) {
13950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            Log.d(TAG, "start(" + sampleRateInHz + "," + audioFormat
14050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                    + "," + channelCount + ")");
14150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
14250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
14367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        int channelConfig = BlockingAudioTrack.getChannelConfig(channelCount);
1448d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        if (channelConfig == 0) {
1458d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            Log.e(TAG, "Unsupported number of channels :" + channelCount);
1468d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            return TextToSpeech.ERROR;
1478d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        }
1488d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
14950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        synchronized (mStateLock) {
15050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            if (mStopped) {
1518d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                if (DBG) Log.d(TAG, "stop() called before start(), returning.");
15250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                return TextToSpeech.ERROR;
15350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            }
15467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            SynthesisPlaybackQueueItem item = new SynthesisPlaybackQueueItem(
1558d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                    mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
156492b7f0d51f53164aa6eb974cd7ab6a7889af677Narayan Kamath                    mDispatcher, mCallerIdentity, mLogger);
15767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mAudioTrackHandler.enqueue(item);
15867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mItem = item;
15950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
16050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
16150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        return TextToSpeech.SUCCESS;
16250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
16350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
16450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
16550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    @Override
16650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    public int audioAvailable(byte[] buffer, int offset, int length) {
16750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        if (DBG) {
16850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            Log.d(TAG, "audioAvailable(byte[" + buffer.length + "],"
16971e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert                    + offset + "," + length + ")");
17071e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert        }
171c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath        if (length > getMaxBufferSize() || length <= 0) {
172c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath            throw new IllegalArgumentException("buffer is too large or of zero length (" +
173c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath                    + length + " bytes)");
17450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
1758d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
17667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        SynthesisPlaybackQueueItem item = null;
17750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        synchronized (mStateLock) {
17867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            if (mItem == null || mStopped) {
17950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                return TextToSpeech.ERROR;
18050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            }
18167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            item = mItem;
18250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
1838d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
1842a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        // Sigh, another copy.
1852a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        final byte[] bufferCopy = new byte[length];
1862a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        System.arraycopy(buffer, offset, bufferCopy, 0, length);
18767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
18867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        // Might block on mItem.this, if there are too many buffers waiting to
1892a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        // be consumed.
19067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        try {
19167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            item.put(bufferCopy);
19267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        } catch (InterruptedException ie) {
19367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            return TextToSpeech.ERROR;
19467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        }
1952a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath
1966dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        mLogger.onEngineDataReceived();
1976dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath
1988d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        return TextToSpeech.SUCCESS;
19950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
20050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert
20150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    @Override
20250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    public int done() {
20350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        if (DBG) Log.d(TAG, "done()");
2048d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
20567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        SynthesisPlaybackQueueItem item = null;
20650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        synchronized (mStateLock) {
2078d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            if (mDone) {
2088d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath                Log.w(TAG, "Duplicate call to done()");
20950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                return TextToSpeech.ERROR;
21050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            }
2118d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
2128d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath            mDone = true;
2138d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
21467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            if (mItem == null) {
21550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert                return TextToSpeech.ERROR;
21650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert            }
2178d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath
21867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            item = mItem;
21950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        }
2202a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath
22167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        item.done();
2222a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath        mLogger.onEngineComplete();
2232a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath
22450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert        return TextToSpeech.SUCCESS;
22550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert    }
22671e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert
22771e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert    @Override
228360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    public void error() {
2298d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath        if (DBG) Log.d(TAG, "error() [will call stop]");
2306dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        // Currently, this call will not be logged if error( ) is called
2316dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        // before start.
2326dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath        mLogger.onError();
23340f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath        stopImpl(true);
234360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert    }
235360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert
23653f6f95308854e7da1fcd15081030d7de2fc5a7fNarayan Kamath}
237