PlaybackSynthesisCallback.java revision be4ad4ac66d6b4b878ed052975f7fb09af92c6d6
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 */ 16package android.speech.tts; 17 18import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher; 19import android.util.Log; 20 21/** 22 * Speech synthesis request that plays the audio as it is received. 23 */ 24class PlaybackSynthesisCallback extends AbstractSynthesisCallback { 25 26 private static final String TAG = "PlaybackSynthesisRequest"; 27 private static final boolean DBG = false; 28 29 private static final int MIN_AUDIO_BUFFER_SIZE = 8192; 30 31 /** 32 * Audio stream type. Must be one of the STREAM_ contants defined in 33 * {@link android.media.AudioManager}. 34 */ 35 private final int mStreamType; 36 37 /** 38 * Volume, in the range [0.0f, 1.0f]. The default value is 39 * {@link TextToSpeech.Engine#DEFAULT_VOLUME} (1.0f). 40 */ 41 private final float mVolume; 42 43 /** 44 * Left/right position of the audio, in the range [-1.0f, 1.0f]. 45 * The default value is {@link TextToSpeech.Engine#DEFAULT_PAN} (0.0f). 46 */ 47 private final float mPan; 48 49 /** 50 * Guards {@link #mAudioTrackHandler}, {@link #mToken} and {@link #mStopped}. 51 */ 52 private final Object mStateLock = new Object(); 53 54 // Handler associated with a thread that plays back audio requests. 55 private final AudioPlaybackHandler mAudioTrackHandler; 56 // A request "token", which will be non null after start() has been called. 57 private SynthesisMessageParams mToken = null; 58 // Whether this request has been stopped. This is useful for keeping 59 // track whether stop() has been called before start(). In all other cases, 60 // a non-null value of mToken will provide the same information. 61 private boolean mStopped = false; 62 63 private volatile boolean mDone = false; 64 65 private final UtteranceCompletedDispatcher mDispatcher; 66 private final String mCallingApp; 67 private final EventLogger mLogger; 68 69 PlaybackSynthesisCallback(int streamType, float volume, float pan, 70 AudioPlaybackHandler audioTrackHandler, UtteranceCompletedDispatcher dispatcher, 71 String callingApp, EventLogger logger) { 72 mStreamType = streamType; 73 mVolume = volume; 74 mPan = pan; 75 mAudioTrackHandler = audioTrackHandler; 76 mDispatcher = dispatcher; 77 mCallingApp = callingApp; 78 mLogger = logger; 79 } 80 81 @Override 82 void stop() { 83 if (DBG) Log.d(TAG, "stop()"); 84 85 // Note that mLogger.mError might be true too at this point. 86 mLogger.onStopped(); 87 88 synchronized (mStateLock) { 89 if (mStopped) { 90 Log.w(TAG, "stop() called twice"); 91 return; 92 } 93 94 // mToken will be null if the engine encounters 95 // an error before it called start(). 96 if (mToken == null) { 97 // In all other cases, mAudioTrackHandler.stop() will 98 // result in onComplete being called. 99 mLogger.onWriteData(); 100 } 101 mStopped = true; 102 } 103 } 104 105 @Override 106 public int getMaxBufferSize() { 107 // The AudioTrack buffer will be at least MIN_AUDIO_BUFFER_SIZE, so that should always be 108 // a safe buffer size to pass in. 109 return MIN_AUDIO_BUFFER_SIZE; 110 } 111 112 @Override 113 boolean isDone() { 114 return mDone; 115 } 116 117 @Override 118 public int start(int sampleRateInHz, int audioFormat, int channelCount) { 119 if (DBG) { 120 Log.d(TAG, "start(" + sampleRateInHz + "," + audioFormat 121 + "," + channelCount + ")"); 122 } 123 124 int channelConfig = AudioPlaybackHandler.getChannelConfig(channelCount); 125 if (channelConfig == 0) { 126 Log.e(TAG, "Unsupported number of channels :" + channelCount); 127 return TextToSpeech.ERROR; 128 } 129 130 synchronized (mStateLock) { 131 if (mStopped) { 132 if (DBG) Log.d(TAG, "stop() called before start(), returning."); 133 return TextToSpeech.ERROR; 134 } 135 SynthesisMessageParams params = new SynthesisMessageParams( 136 mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan, 137 mDispatcher, mCallingApp, mLogger); 138 mAudioTrackHandler.enqueueSynthesisStart(params); 139 140 mToken = params; 141 } 142 143 return TextToSpeech.SUCCESS; 144 } 145 146 147 @Override 148 public int audioAvailable(byte[] buffer, int offset, int length) { 149 if (DBG) { 150 Log.d(TAG, "audioAvailable(byte[" + buffer.length + "]," 151 + offset + "," + length + ")"); 152 } 153 if (length > getMaxBufferSize() || length <= 0) { 154 throw new IllegalArgumentException("buffer is too large or of zero length (" + 155 + length + " bytes)"); 156 } 157 158 synchronized (mStateLock) { 159 if (mToken == null || mStopped) { 160 return TextToSpeech.ERROR; 161 } 162 163 // Sigh, another copy. 164 final byte[] bufferCopy = new byte[length]; 165 System.arraycopy(buffer, offset, bufferCopy, 0, length); 166 mToken.addBuffer(bufferCopy); 167 mAudioTrackHandler.enqueueSynthesisDataAvailable(mToken); 168 } 169 170 mLogger.onEngineDataReceived(); 171 172 return TextToSpeech.SUCCESS; 173 } 174 175 @Override 176 public int done() { 177 if (DBG) Log.d(TAG, "done()"); 178 179 synchronized (mStateLock) { 180 if (mDone) { 181 Log.w(TAG, "Duplicate call to done()"); 182 return TextToSpeech.ERROR; 183 } 184 185 mDone = true; 186 187 if (mToken == null) { 188 return TextToSpeech.ERROR; 189 } 190 191 mAudioTrackHandler.enqueueSynthesisDone(mToken); 192 mLogger.onEngineComplete(); 193 } 194 return TextToSpeech.SUCCESS; 195 } 196 197 @Override 198 public void error() { 199 if (DBG) Log.d(TAG, "error() [will call stop]"); 200 // Currently, this call will not be logged if error( ) is called 201 // before start. 202 mLogger.onError(); 203 stop(); 204 } 205 206} 207