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

Commit a81d17b7 authored by Kazuhiro Inaba's avatar Kazuhiro Inaba
Browse files

TTS: Ensure to callback onStop() from SynthesisPlaybackQueueItem.

The previous implementation calls back the dispatcher only at the end
of run() loop. It means, if stop() is called after enqueueing and
before running, none of onSuccess, onStop, or onError is called for
the items in the queue.

Bug: 63649835
Test: android.speech.tts.cts.TextToSpeechServiceTest#testSpeakStop
Change-Id: Ib20cb0e9157859866f694439858a27369ba8026e
parent 6105698c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ class AudioPlaybackHandler {
            final PlaybackQueueItem item = it.next();
            if (item.getCallerIdentity() == callerIdentity) {
                it.remove();
                stop(item);
            }
        }
    }
+24 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.media.AudioTrack;
import android.util.Log;

import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -70,6 +71,11 @@ final class SynthesisPlaybackQueueItem extends PlaybackQueueItem
    // wait for the next one.
    private ConcurrentLinkedQueue<ProgressMarker> markerList = new ConcurrentLinkedQueue<>();

    private static final int NOT_RUN = 0;
    private static final int RUN_CALLED = 1;
    private static final int STOP_CALLED = 2;
    private final AtomicInteger mRunState = new AtomicInteger(NOT_RUN);

    SynthesisPlaybackQueueItem(AudioOutputParams audioParams, int sampleRate,
            int audioFormat, int channelCount, UtteranceProgressDispatcher dispatcher,
            Object callerIdentity, AbstractEventLogger logger) {
@@ -88,6 +94,11 @@ final class SynthesisPlaybackQueueItem extends PlaybackQueueItem

    @Override
    public void run() {
        if (!mRunState.compareAndSet(NOT_RUN, RUN_CALLED)) {
            // stop() was already called before run(). Do nothing and just finish.
            return;
        }

        final UtteranceProgressDispatcher dispatcher = getDispatcher();
        dispatcher.dispatchOnStart();

@@ -120,6 +131,12 @@ final class SynthesisPlaybackQueueItem extends PlaybackQueueItem

        mAudioTrack.waitAndRelease();

        dispatchEndStatus();
    }

    private void dispatchEndStatus() {
        final UtteranceProgressDispatcher dispatcher = getDispatcher();

        if (mStatusCode == TextToSpeech.SUCCESS) {
            dispatcher.dispatchOnSuccess();
        } else if(mStatusCode == TextToSpeech.STOPPED) {
@@ -140,6 +157,13 @@ final class SynthesisPlaybackQueueItem extends PlaybackQueueItem
            mStopped = true;
            mStatusCode = statusCode;

            if (mRunState.getAndSet(STOP_CALLED) == NOT_RUN) {
                // Dispatch the status code and just finish without signaling
                // if run() has not even started.
                dispatchEndStatus();
                return;
            }

            // Wake up the audio playback thread if it was waiting on take().
            // take() will return null since mStopped was true, and will then
            // break out of the data write loop.