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