• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
BlockingMediaPlayer(Context context, Uri uri, int streamType)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      */
startAndWait()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      */
stop()94     public void stop() {
95         mDone.open();
96     }
97 
98     /**
99      * Starts playback.
100      * Called on the handler thread.
101      */
startPlaying()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      */
finish()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 }