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.AudioManager; 20 import android.media.MediaPlayer; 21 import android.net.Uri; 22 import android.os.ConditionVariable; 23 import android.speech.tts.TextToSpeechService.AudioOutputParams; 24 import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher; 25 import android.util.Log; 26 27 class AudioPlaybackQueueItem extends PlaybackQueueItem { 28 private static final String TAG = "TTS.AudioQueueItem"; 29 30 private final Context mContext; 31 private final Uri mUri; 32 private final AudioOutputParams mAudioParams; 33 34 private final ConditionVariable mDone; 35 private MediaPlayer mPlayer; 36 private volatile boolean mFinished; 37 AudioPlaybackQueueItem(UtteranceProgressDispatcher dispatcher, Object callerIdentity, Context context, Uri uri, AudioOutputParams audioParams)38 AudioPlaybackQueueItem(UtteranceProgressDispatcher dispatcher, 39 Object callerIdentity, 40 Context context, Uri uri, AudioOutputParams audioParams) { 41 super(dispatcher, callerIdentity); 42 43 mContext = context; 44 mUri = uri; 45 mAudioParams = audioParams; 46 47 mDone = new ConditionVariable(); 48 mPlayer = null; 49 mFinished = false; 50 } 51 @Override run()52 public void run() { 53 final UtteranceProgressDispatcher dispatcher = getDispatcher(); 54 55 dispatcher.dispatchOnStart(); 56 57 int sessionId = mAudioParams.mSessionId; 58 mPlayer = MediaPlayer.create( 59 mContext, mUri, null, mAudioParams.mAudioAttributes, 60 sessionId > 0 ? sessionId : AudioManager.AUDIO_SESSION_ID_GENERATE); 61 if (mPlayer == null) { 62 dispatcher.dispatchOnError(TextToSpeech.ERROR_OUTPUT); 63 return; 64 } 65 66 try { 67 mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { 68 @Override 69 public boolean onError(MediaPlayer mp, int what, int extra) { 70 Log.w(TAG, "Audio playback error: " + what + ", " + extra); 71 mDone.open(); 72 return true; 73 } 74 }); 75 mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 76 @Override 77 public void onCompletion(MediaPlayer mp) { 78 mFinished = true; 79 mDone.open(); 80 } 81 }); 82 83 setupVolume(mPlayer, mAudioParams.mVolume, mAudioParams.mPan); 84 mPlayer.start(); 85 mDone.block(); 86 finish(); 87 } catch (IllegalArgumentException ex) { 88 Log.w(TAG, "MediaPlayer failed", ex); 89 mDone.open(); 90 } 91 92 if (mFinished) { 93 dispatcher.dispatchOnSuccess(); 94 } else { 95 dispatcher.dispatchOnStop(); 96 } 97 } 98 setupVolume(MediaPlayer player, float volume, float pan)99 private static void setupVolume(MediaPlayer player, float volume, float pan) { 100 final float vol = clip(volume, 0.0f, 1.0f); 101 final float panning = clip(pan, -1.0f, 1.0f); 102 103 float volLeft = vol, volRight = vol; 104 if (panning > 0.0f) { 105 volLeft *= (1.0f - panning); 106 } else if (panning < 0.0f) { 107 volRight *= (1.0f + panning); 108 } 109 player.setVolume(volLeft, volRight); 110 } 111 clip(float value, float min, float max)112 private static final float clip(float value, float min, float max) { 113 return value < min ? min : (value < max ? value : max); 114 } 115 finish()116 private void finish() { 117 try { 118 mPlayer.stop(); 119 } catch (IllegalStateException ex) { 120 // Do nothing, the player is already stopped 121 } 122 mPlayer.release(); 123 } 124 125 @Override stop(int errorCode)126 void stop(int errorCode) { 127 mDone.open(); 128 } 129 } 130