Home | History | Annotate | Download | only in tts
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 package android.speech.tts;
     17 
     18 import android.content.Context;
     19 import android.media.MediaPlayer;
     20 import android.net.Uri;
     21 import android.os.ConditionVariable;
     22 import android.os.Handler;
     23 import android.os.HandlerThread;
     24 import android.os.Looper;
     25 import android.util.Log;
     26 
     27 /**
     28  * A media player that allows blocking to wait for it to finish.
     29  */
     30 class BlockingMediaPlayer {
     31 
     32     private static final String TAG = "BlockMediaPlayer";
     33 
     34     private static final String MEDIA_PLAYER_THREAD_NAME = "TTS-MediaPlayer";
     35 
     36     private final Context mContext;
     37     private final Uri mUri;
     38     private final int mStreamType;
     39     private final ConditionVariable mDone;
     40     // Only accessed on the Handler thread
     41     private MediaPlayer mPlayer;
     42     private volatile boolean mFinished;
     43 
     44     /**
     45      * Creates a new blocking media player.
     46      * Creating a blocking media player is a cheap operation.
     47      *
     48      * @param context
     49      * @param uri
     50      * @param streamType
     51      */
     52     public BlockingMediaPlayer(Context context, Uri uri, int streamType) {
     53         mContext = context;
     54         mUri = uri;
     55         mStreamType = streamType;
     56         mDone = new ConditionVariable();
     57 
     58     }
     59 
     60     /**
     61      * Starts playback and waits for it to finish.
     62      * Can be called from any thread.
     63      *
     64      * @return {@code true} if the playback finished normally, {@code false} if the playback
     65      *         failed or {@link #stop} was called before the playback finished.
     66      */
     67     public boolean startAndWait() {
     68         HandlerThread thread = new HandlerThread(MEDIA_PLAYER_THREAD_NAME);
     69         thread.start();
     70         Handler handler = new Handler(thread.getLooper());
     71         mFinished = false;
     72         handler.post(new Runnable() {
     73             @Override
     74             public void run() {
     75                 startPlaying();
     76             }
     77         });
     78         mDone.block();
     79         handler.post(new Runnable() {
     80             @Override
     81             public void run() {
     82                 finish();
     83                 // No new messages should get posted to the handler thread after this
     84                 Looper.myLooper().quit();
     85             }
     86         });
     87         return mFinished;
     88     }
     89 
     90     /**
     91      * Stops playback. Can be called multiple times.
     92      * Can be called from any thread.
     93      */
     94     public void stop() {
     95         mDone.open();
     96     }
     97 
     98     /**
     99      * Starts playback.
    100      * Called on the handler thread.
    101      */
    102     private void startPlaying() {
    103         mPlayer = MediaPlayer.create(mContext, mUri);
    104         if (mPlayer == null) {
    105             Log.w(TAG, "Failed to play " + mUri);
    106             mDone.open();
    107             return;
    108         }
    109         try {
    110             mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
    111                 @Override
    112                 public boolean onError(MediaPlayer mp, int what, int extra) {
    113                     Log.w(TAG, "Audio playback error: " + what + ", " + extra);
    114                     mDone.open();
    115                     return true;
    116                 }
    117             });
    118             mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
    119                 @Override
    120                 public void onCompletion(MediaPlayer mp) {
    121                     mFinished = true;
    122                     mDone.open();
    123                 }
    124             });
    125             mPlayer.setAudioStreamType(mStreamType);
    126             mPlayer.start();
    127         } catch (IllegalArgumentException ex) {
    128             Log.w(TAG, "MediaPlayer failed", ex);
    129             mDone.open();
    130         }
    131     }
    132 
    133     /**
    134      * Stops playback and release the media player.
    135      * Called on the handler thread.
    136      */
    137     private void finish() {
    138         try {
    139             mPlayer.stop();
    140         } catch (IllegalStateException ex) {
    141             // Do nothing, the player is already stopped
    142         }
    143         mPlayer.release();
    144     }
    145 
    146 }