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 185cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniakimport android.speech.tts.TextToSpeechService.AudioOutputParams; 19754c72ed9e8e83e5a913aa7552fc2e1b1b5277e0Narayan Kamathimport android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher; 2050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringertimport android.util.Log; 2150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 2250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert/** 2350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert * Speech synthesis request that plays the audio as it is received. 2450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert */ 25e22b69a7de0349b99d3107349d1d3aa72d62c841Narayan Kamathclass PlaybackSynthesisCallback extends AbstractSynthesisCallback { 2650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 2750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert private static final String TAG = "PlaybackSynthesisRequest"; 2850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert private static final boolean DBG = false; 2950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 3050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert private static final int MIN_AUDIO_BUFFER_SIZE = 8192; 3150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 325cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak private final AudioOutputParams mAudioParams; 3350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 348d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath /** 3567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * Guards {@link #mAudioTrackHandler}, {@link #mItem} and {@link #mStopped}. 368d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath */ 3750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert private final Object mStateLock = new Object(); 388d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 398d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath // Handler associated with a thread that plays back audio requests. 408d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath private final AudioPlaybackHandler mAudioTrackHandler; 41c3da8818f0598b3ab2cd6f4168349da6d0f72cb1Narayan Kamath // A request "token", which will be non null after start() has been called. 4267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath private SynthesisPlaybackQueueItem mItem = null; 4350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 448d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath private volatile boolean mDone = false; 458d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 4690d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak /** Status code of synthesis */ 4790d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak protected int mStatusCode; 4890d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak 49754c72ed9e8e83e5a913aa7552fc2e1b1b5277e0Narayan Kamath private final UtteranceProgressDispatcher mDispatcher; 50492b7f0d51f53164aa6eb974cd7ab6a7889af677Narayan Kamath private final Object mCallerIdentity; 5190d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak private final AbstractEventLogger mLogger; 528d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 535cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak PlaybackSynthesisCallback(AudioOutputParams audioParams, AudioPlaybackHandler audioTrackHandler, 545cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak UtteranceProgressDispatcher dispatcher, Object callerIdentity, 555cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak AbstractEventLogger logger, boolean clientIsUsingV2) { 5690d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak super(clientIsUsingV2); 575cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak mAudioParams = audioParams; 58c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath mAudioTrackHandler = audioTrackHandler; 598d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath mDispatcher = dispatcher; 60492b7f0d51f53164aa6eb974cd7ab6a7889af677Narayan Kamath mCallerIdentity = callerIdentity; 616dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath mLogger = logger; 62fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak mStatusCode = TextToSpeech.SUCCESS; 6350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 6450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 6550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert @Override 6650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert void stop() { 6750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert if (DBG) Log.d(TAG, "stop()"); 688d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 6967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath SynthesisPlaybackQueueItem item; 7050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert synchronized (mStateLock) { 7190d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak if (mDone) { 7290d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak return; 7390d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 74fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak if (mStatusCode == TextToSpeech.STOPPED) { 756dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath Log.w(TAG, "stop() called twice"); 768d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath return; 778d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath } 78be4ad4ac66d6b4b878ed052975f7fb09af92c6d6Narayan Kamath 7967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath item = mItem; 80fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak mStatusCode = TextToSpeech.STOPPED; 8150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 822a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath 8367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath if (item != null) { 842a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath // This might result in the synthesis thread being woken up, at which 8567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // point it will write an additional buffer to the item - but we 862a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath // won't worry about that because the audio playback queue will be cleared 872a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath // soon after (see SynthHandler#stop(String). 88fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak item.stop(TextToSpeech.STOPPED); 8940f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath } else { 9040f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath // This happens when stop() or error() were called before start() was. 9140f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath 9240f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath // In all other cases, mAudioTrackHandler.stop() will 9340f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath // result in onSynthesisDone being called, and we will 9440f71f0be3cefabde9dc066d7707a1e5ebaec820Narayan Kamath // write data there. 95fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak mLogger.onCompleted(TextToSpeech.STOPPED); 9690d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak mDispatcher.dispatchOnStop(); 972a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath } 9850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 9950e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 10071e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert @Override 10171e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert public int getMaxBufferSize() { 10271e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert // The AudioTrack buffer will be at least MIN_AUDIO_BUFFER_SIZE, so that should always be 10371e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert // a safe buffer size to pass in. 10471e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert return MIN_AUDIO_BUFFER_SIZE; 10571e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert } 10671e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert 107360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert @Override 10890d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak public boolean hasStarted() { 10990d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak synchronized (mStateLock) { 11090d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak return mItem != null; 11190d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 112360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert } 113360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert 11450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert @Override 11590d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak public boolean hasFinished() { 11690d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak synchronized (mStateLock) { 11790d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak return mDone; 11850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 11990d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 12090d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak 12190d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak @Override 12290d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak public int start(int sampleRateInHz, int audioFormat, int channelCount) { 12390d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak if (DBG) Log.d(TAG, "start(" + sampleRateInHz + "," + audioFormat + "," + channelCount 12490d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak + ")"); 12550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 12667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath int channelConfig = BlockingAudioTrack.getChannelConfig(channelCount); 1278d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 12850e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert synchronized (mStateLock) { 12990d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak if (channelConfig == 0) { 13090d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak Log.e(TAG, "Unsupported number of channels :" + channelCount); 131fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak mStatusCode = TextToSpeech.ERROR_OUTPUT; 13290d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak return TextToSpeech.ERROR; 13390d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 134fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak if (mStatusCode == TextToSpeech.STOPPED) { 1358d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath if (DBG) Log.d(TAG, "stop() called before start(), returning."); 13690d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak return errorCodeOnStop(); 13790d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 138fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak if (mStatusCode != TextToSpeech.SUCCESS) { 13990d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak if (DBG) Log.d(TAG, "Error was raised"); 14090d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak return TextToSpeech.ERROR; 14190d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 14290d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak if (mItem != null) { 14390d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak Log.e(TAG, "Start called twice"); 14450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert return TextToSpeech.ERROR; 14550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 14667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath SynthesisPlaybackQueueItem item = new SynthesisPlaybackQueueItem( 1475cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak mAudioParams, sampleRateInHz, audioFormat, channelCount, 148492b7f0d51f53164aa6eb974cd7ab6a7889af677Narayan Kamath mDispatcher, mCallerIdentity, mLogger); 14967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mAudioTrackHandler.enqueue(item); 15067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mItem = item; 15150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 15250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 15350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert return TextToSpeech.SUCCESS; 15450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 15550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert 15650e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert @Override 15750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert public int audioAvailable(byte[] buffer, int offset, int length) { 15890d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak if (DBG) Log.d(TAG, "audioAvailable(byte[" + buffer.length + "]," + offset + "," + length 15990d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak + ")"); 16090d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak 161c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath if (length > getMaxBufferSize() || length <= 0) { 162c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath throw new IllegalArgumentException("buffer is too large or of zero length (" + 163c90f1c815dc06d5bb563474a340f7bb158fab2e2Narayan Kamath + length + " bytes)"); 16450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 1658d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 16667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath SynthesisPlaybackQueueItem item = null; 16750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert synchronized (mStateLock) { 16890d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak if (mItem == null) { 169fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak mStatusCode = TextToSpeech.ERROR_OUTPUT; 17050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert return TextToSpeech.ERROR; 17150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 172fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak if (mStatusCode != TextToSpeech.SUCCESS) { 17390d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak if (DBG) Log.d(TAG, "Error was raised"); 17490d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak return TextToSpeech.ERROR; 17590d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 176fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak if (mStatusCode == TextToSpeech.STOPPED) { 17790d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak return errorCodeOnStop(); 17890d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 17967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath item = mItem; 18050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 1818d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 1822a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath // Sigh, another copy. 1832a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath final byte[] bufferCopy = new byte[length]; 1842a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath System.arraycopy(buffer, offset, bufferCopy, 0, length); 18567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 18667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Might block on mItem.this, if there are too many buffers waiting to 1872a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath // be consumed. 18867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath try { 18967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath item.put(bufferCopy); 19067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } catch (InterruptedException ie) { 19190d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak synchronized (mStateLock) { 192fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak mStatusCode = TextToSpeech.ERROR_OUTPUT; 19390d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak return TextToSpeech.ERROR; 19490d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 19567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 1962a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath 1976dabb63307a0b63f9386d61e8444aed29db2081eNarayan Kamath mLogger.onEngineDataReceived(); 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 20590d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak int statusCode = 0; 20667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath SynthesisPlaybackQueueItem item = null; 20750e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert synchronized (mStateLock) { 2088d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath if (mDone) { 2098d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath Log.w(TAG, "Duplicate call to done()"); 21090d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak // Not an error that would prevent synthesis. Hence no 21190d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak // setStatusCode 21250e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert return TextToSpeech.ERROR; 21350e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 214fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak if (mStatusCode == TextToSpeech.STOPPED) { 21590d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak if (DBG) Log.d(TAG, "Request has been aborted."); 21690d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak return errorCodeOnStop(); 21790d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 2188d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath mDone = true; 2198d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 22067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath if (mItem == null) { 22190d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak // .done() was called before .start. Treat it as successful synthesis 22290d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak // for a client, despite service bad implementation. 22390d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak Log.w(TAG, "done() was called before start() call"); 224fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak if (mStatusCode == TextToSpeech.SUCCESS) { 22590d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak mDispatcher.dispatchOnSuccess(); 22690d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } else { 22790d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak mDispatcher.dispatchOnError(mStatusCode); 22890d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 22990d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak mLogger.onEngineComplete(); 23050e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert return TextToSpeech.ERROR; 23150e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 2328d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 23367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath item = mItem; 23490d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak statusCode = mStatusCode; 23550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 2362a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath 23790d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak // Signal done or error to item 238fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak if (statusCode == TextToSpeech.SUCCESS) { 23990d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak item.done(); 24090d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } else { 24190d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak item.stop(statusCode); 24290d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 2432a0518cd1d18dc50ffa063a71133e69de2e866abNarayan Kamath mLogger.onEngineComplete(); 24450e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert return TextToSpeech.SUCCESS; 24550e657bb2d005568f5dd8bc1d904d07b0d94018fBjorn Bringert } 24671e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert 24771e0b4807797c602e7fc787d00d27c4f9c92a507Bjorn Bringert @Override 248360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert public void error() { 249fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak error(TextToSpeech.ERROR_SYNTHESIS); 25090d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 25190d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak 25290d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak @Override 25390d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak public void error(int errorCode) { 2548d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath if (DBG) Log.d(TAG, "error() [will call stop]"); 25590d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak synchronized (mStateLock) { 25690d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak if (mDone) { 25790d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak return; 25890d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 25990d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak mStatusCode = errorCode; 26090d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak } 261360eb168d6f9c967543852c7bbab370ef5d8c1bdBjorn Bringert } 26253f6f95308854e7da1fcd15081030d7de2fc5a7fNarayan Kamath} 263