18d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath/* 28d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath * Copyright (C) 2011 The Android Open Source Project 38d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath * 48d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath * Licensed under the Apache License, Version 2.0 (the "License"); you may not 58d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath * use this file except in compliance with the License. You may obtain a copy of 68d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath * the License at 78d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath * 88d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 98d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath * 108d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath * Unless required by applicable law or agreed to in writing, software 118d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 128d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 138d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath * License for the specific language governing permissions and limitations under 148d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath * the License. 158d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath */ 168d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamathpackage android.speech.tts; 178d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 18af802c6831551323126537cf8edabea97d2fc762Narayan Kamathimport android.content.Context; 195cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniakimport android.media.AudioSystem; 20af802c6831551323126537cf8edabea97d2fc762Narayan Kamathimport android.media.MediaPlayer; 21af802c6831551323126537cf8edabea97d2fc762Narayan Kamathimport android.net.Uri; 22af802c6831551323126537cf8edabea97d2fc762Narayan Kamathimport android.os.ConditionVariable; 235cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniakimport android.speech.tts.TextToSpeechService.AudioOutputParams; 24754c72ed9e8e83e5a913aa7552fc2e1b1b5277e0Narayan Kamathimport android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher; 2567ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathimport android.util.Log; 268d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 2767ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamathclass AudioPlaybackQueueItem extends PlaybackQueueItem { 28af802c6831551323126537cf8edabea97d2fc762Narayan Kamath private static final String TAG = "TTS.AudioQueueItem"; 29af802c6831551323126537cf8edabea97d2fc762Narayan Kamath 30af802c6831551323126537cf8edabea97d2fc762Narayan Kamath private final Context mContext; 31af802c6831551323126537cf8edabea97d2fc762Narayan Kamath private final Uri mUri; 325cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak private final AudioOutputParams mAudioParams; 33af802c6831551323126537cf8edabea97d2fc762Narayan Kamath 34af802c6831551323126537cf8edabea97d2fc762Narayan Kamath private final ConditionVariable mDone; 35af802c6831551323126537cf8edabea97d2fc762Narayan Kamath private MediaPlayer mPlayer; 36af802c6831551323126537cf8edabea97d2fc762Narayan Kamath private volatile boolean mFinished; 378d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 3867ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath AudioPlaybackQueueItem(UtteranceProgressDispatcher dispatcher, 39af802c6831551323126537cf8edabea97d2fc762Narayan Kamath Object callerIdentity, 405cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak Context context, Uri uri, AudioOutputParams audioParams) { 41492b7f0d51f53164aa6eb974cd7ab6a7889af677Narayan Kamath super(dispatcher, callerIdentity); 42af802c6831551323126537cf8edabea97d2fc762Narayan Kamath 43af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mContext = context; 44af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mUri = uri; 455cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak mAudioParams = audioParams; 46af802c6831551323126537cf8edabea97d2fc762Narayan Kamath 47af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mDone = new ConditionVariable(); 48af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mPlayer = null; 49af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mFinished = false; 508d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath } 5167ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath @Override 5267ae6bc83cf2b30b0c61b9ebba5fed7a0038549cNarayan Kamath public void run() { 53af802c6831551323126537cf8edabea97d2fc762Narayan Kamath final UtteranceProgressDispatcher dispatcher = getDispatcher(); 54af802c6831551323126537cf8edabea97d2fc762Narayan Kamath 55af802c6831551323126537cf8edabea97d2fc762Narayan Kamath dispatcher.dispatchOnStart(); 56672695e42387a024083d198f3d665f354ef1d27cPrzemyslaw Szczepaniak 57672695e42387a024083d198f3d665f354ef1d27cPrzemyslaw Szczepaniak int sessionId = mAudioParams.mSessionId; 58672695e42387a024083d198f3d665f354ef1d27cPrzemyslaw Szczepaniak mPlayer = MediaPlayer.create( 59672695e42387a024083d198f3d665f354ef1d27cPrzemyslaw Szczepaniak mContext, mUri, null, mAudioParams.mAudioAttributes, 60672695e42387a024083d198f3d665f354ef1d27cPrzemyslaw Szczepaniak sessionId > 0 ? sessionId : AudioSystem.AUDIO_SESSION_ALLOCATE); 61af802c6831551323126537cf8edabea97d2fc762Narayan Kamath if (mPlayer == null) { 62fc4b2890378eb1b6e0b11d60d703eb6854268064Przemyslaw Szczepaniak dispatcher.dispatchOnError(TextToSpeech.ERROR_OUTPUT); 63af802c6831551323126537cf8edabea97d2fc762Narayan Kamath return; 64af802c6831551323126537cf8edabea97d2fc762Narayan Kamath } 65af802c6831551323126537cf8edabea97d2fc762Narayan Kamath 66af802c6831551323126537cf8edabea97d2fc762Narayan Kamath try { 67af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { 68af802c6831551323126537cf8edabea97d2fc762Narayan Kamath @Override 69af802c6831551323126537cf8edabea97d2fc762Narayan Kamath public boolean onError(MediaPlayer mp, int what, int extra) { 70af802c6831551323126537cf8edabea97d2fc762Narayan Kamath Log.w(TAG, "Audio playback error: " + what + ", " + extra); 71af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mDone.open(); 72af802c6831551323126537cf8edabea97d2fc762Narayan Kamath return true; 73af802c6831551323126537cf8edabea97d2fc762Narayan Kamath } 74af802c6831551323126537cf8edabea97d2fc762Narayan Kamath }); 75af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 76af802c6831551323126537cf8edabea97d2fc762Narayan Kamath @Override 77af802c6831551323126537cf8edabea97d2fc762Narayan Kamath public void onCompletion(MediaPlayer mp) { 78af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mFinished = true; 79af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mDone.open(); 80af802c6831551323126537cf8edabea97d2fc762Narayan Kamath } 81af802c6831551323126537cf8edabea97d2fc762Narayan Kamath }); 82672695e42387a024083d198f3d665f354ef1d27cPrzemyslaw Szczepaniak 835cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak setupVolume(mPlayer, mAudioParams.mVolume, mAudioParams.mPan); 84af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mPlayer.start(); 85af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mDone.block(); 86af802c6831551323126537cf8edabea97d2fc762Narayan Kamath finish(); 87af802c6831551323126537cf8edabea97d2fc762Narayan Kamath } catch (IllegalArgumentException ex) { 88af802c6831551323126537cf8edabea97d2fc762Narayan Kamath Log.w(TAG, "MediaPlayer failed", ex); 89af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mDone.open(); 90af802c6831551323126537cf8edabea97d2fc762Narayan Kamath } 91af802c6831551323126537cf8edabea97d2fc762Narayan Kamath 92af802c6831551323126537cf8edabea97d2fc762Narayan Kamath if (mFinished) { 9390d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak dispatcher.dispatchOnSuccess(); 94af802c6831551323126537cf8edabea97d2fc762Narayan Kamath } else { 9590d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak dispatcher.dispatchOnStop(); 96af802c6831551323126537cf8edabea97d2fc762Narayan Kamath } 97af802c6831551323126537cf8edabea97d2fc762Narayan Kamath } 98af802c6831551323126537cf8edabea97d2fc762Narayan Kamath 995cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak private static void setupVolume(MediaPlayer player, float volume, float pan) { 1005cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak final float vol = clip(volume, 0.0f, 1.0f); 1015cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak final float panning = clip(pan, -1.0f, 1.0f); 1025cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak 1035cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak float volLeft = vol, volRight = vol; 1045cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak if (panning > 0.0f) { 1055cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak volLeft *= (1.0f - panning); 1065cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak } else if (panning < 0.0f) { 1075cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak volRight *= (1.0f + panning); 1085cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak } 1095cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak player.setVolume(volLeft, volRight); 1105cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak } 1115cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak 1125cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak private static final float clip(float value, float min, float max) { 1135cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak return value < min ? min : (value < max ? value : max); 1145cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak } 1155cbf17ca053b09beadd0b031a46ce193ab27a0f8Przemyslaw Szczepaniak 116af802c6831551323126537cf8edabea97d2fc762Narayan Kamath private void finish() { 117af802c6831551323126537cf8edabea97d2fc762Narayan Kamath try { 118af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mPlayer.stop(); 119af802c6831551323126537cf8edabea97d2fc762Narayan Kamath } catch (IllegalStateException ex) { 120af802c6831551323126537cf8edabea97d2fc762Narayan Kamath // Do nothing, the player is already stopped 121af802c6831551323126537cf8edabea97d2fc762Narayan Kamath } 122af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mPlayer.release(); 1238d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath } 1248d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath 1258d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath @Override 12690d15d2371ad85f22254be6985455aa2baa5d15dPrzemyslaw Szczepaniak void stop(int errorCode) { 127af802c6831551323126537cf8edabea97d2fc762Narayan Kamath mDone.open(); 1288d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath } 1298d1fc2403b8277e68d7816b2bbf05464a4c7a58aNarayan Kamath} 130