Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32011ea4 authored by Niels Egberts's avatar Niels Egberts
Browse files

Fix race condition with calling stop() before run()

The code assumed that when stop() is called before run(), it's not
neccessary to signal mNotFull, but in rare cases the synthesizer may
already have filled the buffer before run() is called.

Test: manual

Bug: 70887227
Change-Id: I83117f3541d37830b344bc9eda34e1f380b58e76
parent 2f711fec
Loading
Loading
Loading
Loading
+11 −11
Original line number Diff line number Diff line
@@ -15,17 +15,17 @@
 */
package android.speech.tts;

import android.media.AudioTrack;
import android.speech.tts.TextToSpeechService.AudioOutputParams;
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
import android.media.AudioTrack;
import android.util.Log;

import java.util.LinkedList;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * Manages the playback of a list of byte arrays representing audio data that are queued by the
@@ -157,9 +157,16 @@ final class SynthesisPlaybackQueueItem extends PlaybackQueueItem
            mStopped = true;
            mStatusCode = statusCode;

            // Wake up the synthesis thread if it was waiting on put(). Its
            // buffers will no longer be copied since mStopped is true. The
            // PlaybackSynthesisCallback that this synthesis corresponds to
            // would also have been stopped, and so all calls to
            // Callback.onDataAvailable( ) will return errors too.
            mNotFull.signal();

            if (mRunState.getAndSet(STOP_CALLED) == NOT_RUN) {
                // Dispatch the status code and just finish without signaling
                // if run() has not even started.
                // Dispatch the status code and just finish. Signaling audio
                // playback is not necessary because run() hasn't started.
                dispatchEndStatus();
                return;
            }
@@ -168,13 +175,6 @@ final class SynthesisPlaybackQueueItem extends PlaybackQueueItem
            // take() will return null since mStopped was true, and will then
            // break out of the data write loop.
            mReadReady.signal();

            // Wake up the synthesis thread if it was waiting on put(). Its
            // buffers will no longer be copied since mStopped is true. The
            // PlaybackSynthesisCallback that this synthesis corresponds to
            // would also have been stopped, and so all calls to
            // Callback.onDataAvailable( ) will return errors too.
            mNotFull.signal();
        } finally {
            mListLock.unlock();
        }