PlaybackSynthesisCallback.java revision 40f71f0be3cefabde9dc066d7707a1e5ebaec820
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() { 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 9240f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath SynthesisMessageParams token; 9350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert synchronized (mStateLock) { 946dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath if (mStopped) { 956dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath Log.w(TAG, "stop() called twice"); 968d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath return; 978d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath } 98be4ad4ac66d6b4b878ed052975f7fb09af92c6d6Narayan Kamath 9940f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath token = mToken; 10050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert mStopped = true; 10150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 1022a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath 1032a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath if (token != null) { 1042a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath // This might result in the synthesis thread being woken up, at which 1052a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath // point it will write an additional buffer to the token - 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). 10840f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath token.setIsError(wasError); 1092a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath token.clearBuffers(); 11040f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath if (wasError) { 11140f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath // Also clean up the audio track if an error occurs. 11240f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath mAudioTrackHandler.enqueueSynthesisDone(token); 11340f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath } 11440f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath } else { 11540f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath // This happens when stop() or error() were called before start() was. 11640f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath 11740f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath // In all other cases, mAudioTrackHandler.stop() will 11840f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath // result in onSynthesisDone being called, and we will 11940f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath // write data there. 12040f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath mLogger.onWriteData(); 12140f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath 12240f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath if (wasError) { 12340f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath // We have to dispatch the error ourselves. 12440f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath mDispatcher.dispatchOnError(); 12540f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath } 1262a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath } 12750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 12850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 12971e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert @Override 13071e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert public int getMaxBufferSize() { 13171e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert // The AudioTrack buffer will be at least MIN_AUDIO_BUFFER_SIZE, so that should always be 13271e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert // a safe buffer size to pass in. 13371e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert return MIN_AUDIO_BUFFER_SIZE; 13471e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert } 13571e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert 136360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert @Override 137360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert boolean isDone() { 138360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert return mDone; 139360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert } 140360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert 14150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert @Override 14250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert public int start(int sampleRateInHz, int audioFormat, int channelCount) { 14350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert if (DBG) { 14450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert Log.d(TAG, "start(" + sampleRateInHz + "," + audioFormat 14550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert + "," + channelCount + ")"); 14650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 14750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 1488d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath int channelConfig = AudioPlaybackHandler.getChannelConfig(channelCount); 1498d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath if (channelConfig == 0) { 1508d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath Log.e(TAG, "Unsupported number of channels :" + channelCount); 1518d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath return TextToSpeech.ERROR; 1528d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath } 1538d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 15450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert synchronized (mStateLock) { 15550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert if (mStopped) { 1568d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath if (DBG) Log.d(TAG, "stop() called before start(), returning."); 15750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert return TextToSpeech.ERROR; 15850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 1598d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath SynthesisMessageParams params = new SynthesisMessageParams( 1608d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan, 1616dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath mDispatcher, mCallingApp, mLogger); 1628d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath mAudioTrackHandler.enqueueSynthesisStart(params); 16350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 1648d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath mToken = params; 16550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 16650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 16750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert return TextToSpeech.SUCCESS; 16850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 16950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 17050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 17150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert @Override 17250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert public int audioAvailable(byte[] buffer, int offset, int length) { 17350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert if (DBG) { 17450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert Log.d(TAG, "audioAvailable(byte[" + buffer.length + "]," 17571e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert + offset + "," + length + ")"); 17671e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert } 177c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath if (length > getMaxBufferSize() || length <= 0) { 178c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath throw new IllegalArgumentException("buffer is too large or of zero length (" + 179c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath + length + " bytes)"); 18050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 1818d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 1822a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath SynthesisMessageParams token = null; 18350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert synchronized (mStateLock) { 184be4ad4ac66d6b4b878ed052975f7fb09af92c6d6Narayan Kamath if (mToken == null || mStopped) { 18550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert return TextToSpeech.ERROR; 18650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 1872a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath token = mToken; 18850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 1898d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 1902a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath // Sigh, another copy. 1912a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath final byte[] bufferCopy = new byte[length]; 1922a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath System.arraycopy(buffer, offset, bufferCopy, 0, length); 1932a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath // Might block on mToken.this, if there are too many buffers waiting to 1942a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath // be consumed. 1952a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath token.addBuffer(bufferCopy); 1962a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath mAudioTrackHandler.enqueueSynthesisDataAvailable(token); 1972a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath 1986dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath mLogger.onEngineDataReceived(); 1996dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath 2008d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath return TextToSpeech.SUCCESS; 20150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 20250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 20350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert @Override 20450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert public int done() { 20550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert if (DBG) Log.d(TAG, "done()"); 2068d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 2072a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath SynthesisMessageParams token = null; 20850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert synchronized (mStateLock) { 2098d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath if (mDone) { 2108d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath Log.w(TAG, "Duplicate call to done()"); 21150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert return TextToSpeech.ERROR; 21250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 2138d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 2148d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath mDone = true; 2158d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 2168d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath if (mToken == null) { 21750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert return TextToSpeech.ERROR; 21850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 2198d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 2202a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath token = mToken; 22150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 2222a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath 2232a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath mAudioTrackHandler.enqueueSynthesisDone(token); 2242a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath mLogger.onEngineComplete(); 2252a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath 22650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert return TextToSpeech.SUCCESS; 22750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 22871e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert 22971e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert @Override 230360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert public void error() { 2318d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath if (DBG) Log.d(TAG, "error() [will call stop]"); 2326dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath // Currently, this call will not be logged if error( ) is called 2336dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath // before start. 2346dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath mLogger.onError(); 23540f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath stopImpl(true); 236360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert } 237360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert 23853f6f95308854e7da1fcd15081030d7de2fc5a7fNarayan Kamath} 239