167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath/* 267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * Copyright (C) 2011 The Android Open Source Project 367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * 467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * Licensed under the Apache License, Version 2.0 (the "License"); you may not 567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * use this file except in compliance with the License. You may obtain a copy of 667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * the License at 767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * 867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * 1067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * Unless required by applicable law or agreed to in writing, software 1167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 1267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 1367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * License for the specific language governing permissions and limitations under 1467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * the License. 1567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath */ 1667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathpackage android.speech.tts; 1767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 185cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniakimport android.speech.tts.TextToSpeechService.AudioOutputParams; 1967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathimport android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher; 2067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathimport android.util.Log; 2167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 2267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathimport java.util.LinkedList; 2367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathimport java.util.concurrent.locks.Condition; 2467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathimport java.util.concurrent.locks.Lock; 2567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathimport java.util.concurrent.locks.ReentrantLock; 2667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 2767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath/** 2867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * Manages the playback of a list of byte arrays representing audio data 2967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * that are queued by the engine to an audio track. 3067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath */ 3167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathfinal class SynthesisPlaybackQueueItem extends PlaybackQueueItem { 3267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath private static final String TAG = "TTS.SynthQueueItem"; 3367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath private static final boolean DBG = false; 3467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 3567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath /** 3667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * Maximum length of audio we leave unconsumed by the audio track. 3767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * Calls to {@link #put(byte[])} will block until we have less than 3867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * this amount of audio left to play back. 3967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath */ 4067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath private static final long MAX_UNCONSUMED_AUDIO_MS = 500; 4167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 4267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath /** 4367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * Guards accesses to mDataBufferList and mUnconsumedBytes. 4467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath */ 4567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath private final Lock mListLock = new ReentrantLock(); 4667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath private final Condition mReadReady = mListLock.newCondition(); 4767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath private final Condition mNotFull = mListLock.newCondition(); 4867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 4967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Guarded by mListLock. 5067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath private final LinkedList<ListEntry> mDataBufferList = new LinkedList<ListEntry>(); 5167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Guarded by mListLock. 5267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath private int mUnconsumedBytes; 5367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 5467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath /* 5567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * While mStopped and mIsError can be written from any thread, mDone is written 5667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * only from the synthesis thread. All three variables are read from the 5767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * audio playback thread. 5867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath */ 5967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath private volatile boolean mStopped; 6067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath private volatile boolean mDone; 6190d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak private volatile int mStatusCode; 6267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 6367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath private final BlockingAudioTrack mAudioTrack; 6490d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak private final AbstractEventLogger mLogger; 6567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 665cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak SynthesisPlaybackQueueItem(AudioOutputParams audioParams, int sampleRate, 675cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak int audioFormat, int channelCount, UtteranceProgressDispatcher dispatcher, 6890d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak Object callerIdentity, AbstractEventLogger logger) { 6967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath super(dispatcher, callerIdentity); 7067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 7167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mUnconsumedBytes = 0; 7267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 7367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mStopped = false; 7467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mDone = false; 75fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak mStatusCode = TextToSpeech.SUCCESS; 7667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 775cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak mAudioTrack = new BlockingAudioTrack(audioParams, sampleRate, audioFormat, channelCount); 7867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mLogger = logger; 7967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 8067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 8167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 8267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath @Override 8367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath public void run() { 8467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath final UtteranceProgressDispatcher dispatcher = getDispatcher(); 8567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath dispatcher.dispatchOnStart(); 8667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 87ed4e541a20cc662b8399844684d18ad0060bd1cbNarayan Kamath if (!mAudioTrack.init()) { 88fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak dispatcher.dispatchOnError(TextToSpeech.ERROR_OUTPUT); 89ed4e541a20cc662b8399844684d18ad0060bd1cbNarayan Kamath return; 90ed4e541a20cc662b8399844684d18ad0060bd1cbNarayan Kamath } 9167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 9267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath try { 9367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath byte[] buffer = null; 9467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 9567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // take() will block until: 9667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // 9767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // (a) there is a buffer available to tread. In which case 9867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // a non null value is returned. 9967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // OR (b) stop() is called in which case it will return null. 10067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // OR (c) done() is called in which case it will return null. 10167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath while ((buffer = take()) != null) { 10267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mAudioTrack.write(buffer); 10367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mLogger.onAudioDataWritten(); 10467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 10567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 10667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } catch (InterruptedException ie) { 10767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath if (DBG) Log.d(TAG, "Interrupted waiting for buffers, cleaning up."); 10867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 10967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 11067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mAudioTrack.waitAndRelease(); 11167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 112fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak if (mStatusCode == TextToSpeech.SUCCESS) { 11390d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak dispatcher.dispatchOnSuccess(); 114fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak } else if(mStatusCode == TextToSpeech.STOPPED) { 11590d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak dispatcher.dispatchOnStop(); 11667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } else { 11790d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak dispatcher.dispatchOnError(mStatusCode); 11867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 11967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 12090d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak mLogger.onCompleted(mStatusCode); 12167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 12267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 12367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath @Override 12490d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak void stop(int statusCode) { 12567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath try { 12667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mListLock.lock(); 12767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 12867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Update our internal state. 12967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mStopped = true; 13090d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak mStatusCode = statusCode; 13167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 13267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Wake up the audio playback thread if it was waiting on take(). 13367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // take() will return null since mStopped was true, and will then 13467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // break out of the data write loop. 13567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mReadReady.signal(); 13667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 13767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Wake up the synthesis thread if it was waiting on put(). Its 13867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // buffers will no longer be copied since mStopped is true. The 13967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // PlaybackSynthesisCallback that this synthesis corresponds to 14067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // would also have been stopped, and so all calls to 14167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Callback.onDataAvailable( ) will return errors too. 14267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mNotFull.signal(); 14367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } finally { 14467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mListLock.unlock(); 14567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 14667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 14767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Stop the underlying audio track. This will stop sending 14867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // data to the mixer and discard any pending buffers that the 14967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // track holds. 15067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mAudioTrack.stop(); 15167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 15267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 15367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath void done() { 15467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath try { 15567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mListLock.lock(); 15667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 15767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Update state. 15867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mDone = true; 15967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 16067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Unblocks the audio playback thread if it was waiting on take() 16167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // after having consumed all available buffers. It will then return 16267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // null and leave the write loop. 16367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mReadReady.signal(); 16467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 16567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Just so that engines that try to queue buffers after 16667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // calling done() don't block the synthesis thread forever. Ideally 16767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // this should be called from the same thread as put() is, and hence 16867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // this call should be pointless. 16967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mNotFull.signal(); 17067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } finally { 17167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mListLock.unlock(); 17267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 17367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 17467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 17567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 17667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath void put(byte[] buffer) throws InterruptedException { 17767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath try { 17867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mListLock.lock(); 17967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath long unconsumedAudioMs = 0; 18067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 18167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath while ((unconsumedAudioMs = mAudioTrack.getAudioLengthMs(mUnconsumedBytes)) > 18267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath MAX_UNCONSUMED_AUDIO_MS && !mStopped) { 18367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mNotFull.await(); 18467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 18567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 18667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Don't bother queueing the buffer if we've stopped. The playback thread 18767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // would have woken up when stop() is called (if it was blocked) and will 18867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // proceed to leave the write loop since take() will return null when 18967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // stopped. 19067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath if (mStopped) { 19167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath return; 19267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 19367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 19467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mDataBufferList.add(new ListEntry(buffer)); 19567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mUnconsumedBytes += buffer.length; 19667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mReadReady.signal(); 19767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } finally { 19867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mListLock.unlock(); 19967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 20067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 20167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 20267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath private byte[] take() throws InterruptedException { 20367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath try { 20467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mListLock.lock(); 20567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 20667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Block if there are no available buffers, and stop() has not 20767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // been called and done() has not been called. 20867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath while (mDataBufferList.size() == 0 && !mStopped && !mDone) { 20967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mReadReady.await(); 21067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 21167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 21267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // If stopped, return null so that we can exit the playback loop 21367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // as soon as possible. 21467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath if (mStopped) { 21567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath return null; 21667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 21767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 21867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Remove the first entry from the queue. 21967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath ListEntry entry = mDataBufferList.poll(); 22067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 22167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // This is the normal playback loop exit case, when done() was 22267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // called. (mDone will be true at this point). 22367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath if (entry == null) { 22467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath return null; 22567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 22667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 22767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mUnconsumedBytes -= entry.mBytes.length; 22867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Unblock the waiting writer. We use signal() and not signalAll() 22967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // because there will only be one thread waiting on this (the 23067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath // Synthesis thread). 23167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mNotFull.signal(); 23267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 23367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath return entry.mBytes; 23467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } finally { 23567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mListLock.unlock(); 23667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 23767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 23867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 23967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath static final class ListEntry { 24067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath final byte[] mBytes; 24167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath 24267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath ListEntry(byte[] bytes) { 24367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath mBytes = bytes; 24467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 24567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath } 24667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath} 247