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
1867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathimport android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
1967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathimport android.util.Log;
2067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
2167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathimport java.util.LinkedList;
2267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathimport java.util.concurrent.locks.Condition;
2367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathimport java.util.concurrent.locks.Lock;
2467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathimport java.util.concurrent.locks.ReentrantLock;
2567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
2667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath/**
2767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * Manages the playback of a list of byte arrays representing audio data
2867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath * that are queued by the engine to an audio track.
2967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath */
3067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathfinal class SynthesisPlaybackQueueItem extends PlaybackQueueItem {
3167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private static final String TAG = "TTS.SynthQueueItem";
3267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private static final boolean DBG = false;
3367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
3467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    /**
3567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath     * Maximum length of audio we leave unconsumed by the audio track.
3667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath     * Calls to {@link #put(byte[])} will block until we have less than
3767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath     * this amount of audio left to play back.
3867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath     */
3967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private static final long MAX_UNCONSUMED_AUDIO_MS = 500;
4067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
4167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    /**
4267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath     * Guards accesses to mDataBufferList and mUnconsumedBytes.
4367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath     */
4467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private final Lock mListLock = new ReentrantLock();
4567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private final Condition mReadReady = mListLock.newCondition();
4667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private final Condition mNotFull = mListLock.newCondition();
4767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
4867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    // Guarded by mListLock.
4967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private final LinkedList<ListEntry> mDataBufferList = new LinkedList<ListEntry>();
5067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    // Guarded by mListLock.
5167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private int mUnconsumedBytes;
5267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
5367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    /*
5467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath     * While mStopped and mIsError can be written from any thread, mDone is written
5567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath     * only from the synthesis thread. All three variables are read from the
5667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath     * audio playback thread.
5767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath     */
5867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private volatile boolean mStopped;
5967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private volatile boolean mDone;
6067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private volatile boolean mIsError;
6167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
6267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private final BlockingAudioTrack mAudioTrack;
6367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private final EventLogger mLogger;
6467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
6567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
6667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    SynthesisPlaybackQueueItem(int streamType, int sampleRate,
6767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            int audioFormat, int channelCount,
6867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            float volume, float pan, UtteranceProgressDispatcher dispatcher,
6967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            Object callerIdentity, EventLogger logger) {
7067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        super(dispatcher, callerIdentity);
7167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
7267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        mUnconsumedBytes = 0;
7367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
7467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        mStopped = false;
7567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        mDone = false;
7667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        mIsError = false;
7767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
7867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        mAudioTrack = new BlockingAudioTrack(streamType, sampleRate, audioFormat,
7967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath                channelCount, volume, pan);
8067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        mLogger = logger;
8167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    }
8267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
8367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
8467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    @Override
8567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    public void run() {
8667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        final UtteranceProgressDispatcher dispatcher = getDispatcher();
8767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        dispatcher.dispatchOnStart();
8867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
8967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
90ed4e541a20cc662b8399844684d18ad0060bd1cbNarayan Kamath        if (!mAudioTrack.init()) {
91ed4e541a20cc662b8399844684d18ad0060bd1cbNarayan Kamath            dispatcher.dispatchOnError();
92ed4e541a20cc662b8399844684d18ad0060bd1cbNarayan Kamath            return;
93ed4e541a20cc662b8399844684d18ad0060bd1cbNarayan Kamath        }
9467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
9567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        try {
9667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            byte[] buffer = null;
9767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
9867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // take() will block until:
9967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            //
10067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // (a) there is a buffer available to tread. In which case
10167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // a non null value is returned.
10267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // OR (b) stop() is called in which case it will return null.
10367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // OR (c) done() is called in which case it will return null.
10467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            while ((buffer = take()) != null) {
10567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath                mAudioTrack.write(buffer);
10667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath                mLogger.onAudioDataWritten();
10767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            }
10867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
10967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        } catch (InterruptedException ie) {
11067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            if (DBG) Log.d(TAG, "Interrupted waiting for buffers, cleaning up.");
11167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        }
11267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
11367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        mAudioTrack.waitAndRelease();
11467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
11567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        if (mIsError) {
11667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            dispatcher.dispatchOnError();
11767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        } else {
11867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            dispatcher.dispatchOnDone();
11967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        }
12067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
12167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        mLogger.onWriteData();
12267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    }
12367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
12467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    @Override
12567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    void stop(boolean isError) {
12667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        try {
12767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mListLock.lock();
12867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
12967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // Update our internal state.
13067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mStopped = true;
13167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mIsError = isError;
13267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
13367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // Wake up the audio playback thread if it was waiting on take().
13467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // take() will return null since mStopped was true, and will then
13567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // break out of the data write loop.
13667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mReadReady.signal();
13767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
13867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // Wake up the synthesis thread if it was waiting on put(). Its
13967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // buffers will no longer be copied since mStopped is true. The
14067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // PlaybackSynthesisCallback that this synthesis corresponds to
14167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // would also have been stopped, and so all calls to
14267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // Callback.onDataAvailable( ) will return errors too.
14367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mNotFull.signal();
14467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        } finally {
14567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mListLock.unlock();
14667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        }
14767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
14867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        // Stop the underlying audio track. This will stop sending
14967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        // data to the mixer and discard any pending buffers that the
15067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        // track holds.
15167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        mAudioTrack.stop();
15267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    }
15367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
15467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    void done() {
15567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        try {
15667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mListLock.lock();
15767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
15867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // Update state.
15967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mDone = true;
16067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
16167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // Unblocks the audio playback thread if it was waiting on take()
16267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // after having consumed all available buffers. It will then return
16367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // null and leave the write loop.
16467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mReadReady.signal();
16567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
16667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // Just so that engines that try to queue buffers after
16767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // calling done() don't block the synthesis thread forever. Ideally
16867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // this should be called from the same thread as put() is, and hence
16967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // this call should be pointless.
17067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mNotFull.signal();
17167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        } finally {
17267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mListLock.unlock();
17367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        }
17467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    }
17567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
17667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
17767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    void put(byte[] buffer) throws InterruptedException {
17867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        try {
17967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mListLock.lock();
18067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            long unconsumedAudioMs = 0;
18167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
18267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            while ((unconsumedAudioMs = mAudioTrack.getAudioLengthMs(mUnconsumedBytes)) >
18367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath                    MAX_UNCONSUMED_AUDIO_MS && !mStopped) {
18467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath                mNotFull.await();
18567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            }
18667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
18767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // Don't bother queueing the buffer if we've stopped. The playback thread
18867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // would have woken up when stop() is called (if it was blocked) and will
18967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // proceed to leave the write loop since take() will return null when
19067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // stopped.
19167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            if (mStopped) {
19267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath                return;
19367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            }
19467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
19567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mDataBufferList.add(new ListEntry(buffer));
19667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mUnconsumedBytes += buffer.length;
19767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mReadReady.signal();
19867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        } finally {
19967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mListLock.unlock();
20067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        }
20167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    }
20267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
20367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    private byte[] take() throws InterruptedException {
20467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        try {
20567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mListLock.lock();
20667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
20767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // Block if there are no available buffers, and stop() has not
20867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // been called and done() has not been called.
20967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            while (mDataBufferList.size() == 0 && !mStopped && !mDone) {
21067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath                mReadReady.await();
21167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            }
21267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
21367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // If stopped, return null so that we can exit the playback loop
21467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // as soon as possible.
21567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            if (mStopped) {
21667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath                return null;
21767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            }
21867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
21967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // Remove the first entry from the queue.
22067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            ListEntry entry = mDataBufferList.poll();
22167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
22267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // This is the normal playback loop exit case, when done() was
22367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // called. (mDone will be true at this point).
22467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            if (entry == null) {
22567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath                return null;
22667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            }
22767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
22867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mUnconsumedBytes -= entry.mBytes.length;
22967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // Unblock the waiting writer. We use signal() and not signalAll()
23067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // because there will only be one thread waiting on this (the
23167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            // Synthesis thread).
23267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mNotFull.signal();
23367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
23467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            return entry.mBytes;
23567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        } finally {
23667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mListLock.unlock();
23767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        }
23867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    }
23967ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
24067ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    static final class ListEntry {
24167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        final byte[] mBytes;
24267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath
24367ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        ListEntry(byte[] bytes) {
24467ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath            mBytes = bytes;
24567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath        }
24667ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath    }
24767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath}
248