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

Commit af802c68 authored by Narayan Kamath's avatar Narayan Kamath
Browse files

Remove BlockingMediaPlayer.

No need to spawn a new thread for every audio item sent to
the TTS class.

Change-Id: Ia52b0951f4249b0da460a5ecaff5dd11a6e5d5fc
parent 4a3d5b04
Loading
Loading
Loading
Loading
+72 −8
Original line number Diff line number Diff line
@@ -15,27 +15,91 @@
 */
package android.speech.tts;

import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.ConditionVariable;
import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
import android.util.Log;

class AudioPlaybackQueueItem extends PlaybackQueueItem {
    private final BlockingMediaPlayer mPlayer;
    private static final String TAG = "TTS.AudioQueueItem";

    private final Context mContext;
    private final Uri mUri;
    private final int mStreamType;

    private final ConditionVariable mDone;
    private MediaPlayer mPlayer;
    private volatile boolean mFinished;

    AudioPlaybackQueueItem(UtteranceProgressDispatcher dispatcher,
            Object callerIdentity, BlockingMediaPlayer player) {
            Object callerIdentity,
            Context context, Uri uri, int streamType) {
        super(dispatcher, callerIdentity);
        mPlayer = player;

        mContext = context;
        mUri = uri;
        mStreamType = streamType;

        mDone = new ConditionVariable();
        mPlayer = null;
        mFinished = false;
    }
    @Override
    public void run() {
        getDispatcher().dispatchOnStart();
        // TODO: This can be avoided. Will be fixed later in this CL.
        mPlayer.startAndWait();
        getDispatcher().dispatchOnDone();
        final UtteranceProgressDispatcher dispatcher = getDispatcher();

        dispatcher.dispatchOnStart();
        mPlayer = MediaPlayer.create(mContext, mUri);
        if (mPlayer == null) {
            dispatcher.dispatchOnError();
            return;
        }

        try {
            mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                @Override
    void stop(boolean isError) {
                public boolean onError(MediaPlayer mp, int what, int extra) {
                    Log.w(TAG, "Audio playback error: " + what + ", " + extra);
                    mDone.open();
                    return true;
                }
            });
            mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    mFinished = true;
                    mDone.open();
                }
            });
            mPlayer.setAudioStreamType(mStreamType);
            mPlayer.start();
            mDone.block();
            finish();
        } catch (IllegalArgumentException ex) {
            Log.w(TAG, "MediaPlayer failed", ex);
            mDone.open();
        }

        if (mFinished) {
            dispatcher.dispatchOnDone();
        } else {
            dispatcher.dispatchOnError();
        }
    }

    private void finish() {
        try {
            mPlayer.stop();
        } catch (IllegalStateException ex) {
            // Do nothing, the player is already stopped
        }
        mPlayer.release();
    }

    @Override
    void stop(boolean isError) {
        mDone.open();
    }
}
+0 −145
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package android.speech.tts;

import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.Log;

/**
 * A media player that allows blocking to wait for it to finish.
 */
class BlockingMediaPlayer {

    private static final String TAG = "BlockMediaPlayer";

    private static final String MEDIA_PLAYER_THREAD_NAME = "TTS-MediaPlayer";

    private final Context mContext;
    private final Uri mUri;
    private final int mStreamType;
    private final ConditionVariable mDone;
    // Only accessed on the Handler thread
    private MediaPlayer mPlayer;
    private volatile boolean mFinished;

    /**
     * Creates a new blocking media player.
     * Creating a blocking media player is a cheap operation.
     *
     * @param context
     * @param uri
     * @param streamType
     */
    public BlockingMediaPlayer(Context context, Uri uri, int streamType) {
        mContext = context;
        mUri = uri;
        mStreamType = streamType;
        mDone = new ConditionVariable();
    }

    /**
     * Starts playback and waits for it to finish.
     * Can be called from any thread.
     *
     * @return {@code true} if the playback finished normally, {@code false} if the playback
     *         failed or {@link #stop} was called before the playback finished.
     */
    public boolean startAndWait() {
        HandlerThread thread = new HandlerThread(MEDIA_PLAYER_THREAD_NAME);
        thread.start();
        Handler handler = new Handler(thread.getLooper());
        mFinished = false;
        handler.post(new Runnable() {
            @Override
            public void run() {
                startPlaying();
            }
        });
        mDone.block();
        handler.post(new Runnable() {
            @Override
            public void run() {
                finish();
                // No new messages should get posted to the handler thread after this
                Looper.myLooper().quit();
            }
        });
        return mFinished;
    }

    /**
     * Stops playback. Can be called multiple times.
     * Can be called from any thread.
     */
    public void stop() {
        mDone.open();
    }

    /**
     * Starts playback.
     * Called on the handler thread.
     */
    private void startPlaying() {
        mPlayer = MediaPlayer.create(mContext, mUri);
        if (mPlayer == null) {
            Log.w(TAG, "Failed to play " + mUri);
            mDone.open();
            return;
        }
        try {
            mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                @Override
                public boolean onError(MediaPlayer mp, int what, int extra) {
                    Log.w(TAG, "Audio playback error: " + what + ", " + extra);
                    mDone.open();
                    return true;
                }
            });
            mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    mFinished = true;
                    mDone.open();
                }
            });
            mPlayer.setAudioStreamType(mStreamType);
            mPlayer.start();
        } catch (IllegalArgumentException ex) {
            Log.w(TAG, "MediaPlayer failed", ex);
            mDone.open();
        }
    }

    /**
     * Stops playback and release the media player.
     * Called on the handler thread.
     */
    private void finish() {
        try {
            mPlayer.stop();
        } catch (IllegalStateException ex) {
            // Do nothing, the player is already stopped
        }
        mPlayer.release();
    }

}
 No newline at end of file
+0 −47
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package android.speech.tts;

import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;

abstract class MessageParams {
    static final int TYPE_SYNTHESIS = 1;
    static final int TYPE_AUDIO = 2;
    static final int TYPE_SILENCE = 3;

    private final UtteranceProgressDispatcher mDispatcher;
    private final Object mCallerIdentity;

    MessageParams(UtteranceProgressDispatcher dispatcher, Object callerIdentity) {
        mDispatcher = dispatcher;
        mCallerIdentity = callerIdentity;
    }

    UtteranceProgressDispatcher getDispatcher() {
        return mDispatcher;
    }

    Object getCallerIdentity() {
        return mCallerIdentity;
    }

    @Override
    public String toString() {
        return "MessageParams[" + hashCode() + "]";
    }

    abstract int getType();
}
+4 −5
Original line number Diff line number Diff line
@@ -694,12 +694,12 @@ public abstract class TextToSpeechService extends Service {
    }

    private class AudioSpeechItem extends SpeechItem {
        private final BlockingMediaPlayer mPlayer;

        private final AudioPlaybackQueueItem mItem;
        public AudioSpeechItem(Object callerIdentity, int callerUid, int callerPid,
                Bundle params, Uri uri) {
            super(callerIdentity, callerUid, callerPid, params);
            mPlayer = new BlockingMediaPlayer(TextToSpeechService.this, uri, getStreamType());
            mItem = new AudioPlaybackQueueItem(this, getCallerIdentity(),
                    TextToSpeechService.this, uri, getStreamType());
        }

        @Override
@@ -709,8 +709,7 @@ public abstract class TextToSpeechService extends Service {

        @Override
        protected int playImpl() {
            mAudioPlaybackHandler.enqueue(new AudioPlaybackQueueItem(
                    this, getCallerIdentity(), mPlayer));
            mAudioPlaybackHandler.enqueue(mItem);
            return TextToSpeech.SUCCESS;
        }