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.media.AudioFormat; 19 import android.media.AudioTrack; 20 import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher; 21 22 import java.util.LinkedList; 23 24 /** 25 * Params required to play back a synthesis request. 26 */ 27 final class SynthesisMessageParams extends MessageParams { 28 private static final long MAX_UNCONSUMED_AUDIO_MS = 500; 29 30 final int mStreamType; 31 final int mSampleRateInHz; 32 final int mAudioFormat; 33 final int mChannelCount; 34 final float mVolume; 35 final float mPan; 36 final EventLogger mLogger; 37 38 final int mBytesPerFrame; 39 40 volatile AudioTrack mAudioTrack; 41 // Written by the synthesis thread, but read on the audio playback 42 // thread. 43 volatile int mBytesWritten; 44 // A "short utterance" is one that uses less bytes than the audio 45 // track buffer size (mAudioBufferSize). In this case, we need to call 46 // AudioTrack#stop() to send pending buffers to the mixer, and slightly 47 // different logic is required to wait for the track to finish. 48 // 49 // Not volatile, accessed only from the audio playback thread. 50 boolean mIsShortUtterance; 51 int mAudioBufferSize; 52 // Always synchronized on "this". 53 int mUnconsumedBytes; 54 55 private final LinkedList<ListEntry> mDataBufferList = new LinkedList<ListEntry>(); 56 57 SynthesisMessageParams(int streamType, int sampleRate, 58 int audioFormat, int channelCount, 59 float volume, float pan, UtteranceCompletedDispatcher dispatcher, 60 String callingApp, EventLogger logger) { 61 super(dispatcher, callingApp); 62 63 mStreamType = streamType; 64 mSampleRateInHz = sampleRate; 65 mAudioFormat = audioFormat; 66 mChannelCount = channelCount; 67 mVolume = volume; 68 mPan = pan; 69 mLogger = logger; 70 71 mBytesPerFrame = getBytesPerFrame(mAudioFormat) * mChannelCount; 72 73 // initially null. 74 mAudioTrack = null; 75 mBytesWritten = 0; 76 mAudioBufferSize = 0; 77 } 78 79 @Override 80 int getType() { 81 return TYPE_SYNTHESIS; 82 } 83 84 synchronized void addBuffer(byte[] buffer) { 85 long unconsumedAudioMs = 0; 86 87 while ((unconsumedAudioMs = getUnconsumedAudioLengthMs()) > MAX_UNCONSUMED_AUDIO_MS) { 88 try { 89 wait(); 90 } catch (InterruptedException ie) { 91 return; 92 } 93 } 94 95 mDataBufferList.add(new ListEntry(buffer)); 96 mUnconsumedBytes += buffer.length; 97 } 98 99 synchronized void clearBuffers() { 100 mDataBufferList.clear(); 101 mUnconsumedBytes = 0; 102 notifyAll(); 103 } 104 105 synchronized ListEntry getNextBuffer() { 106 ListEntry entry = mDataBufferList.poll(); 107 if (entry != null) { 108 mUnconsumedBytes -= entry.mBytes.length; 109 notifyAll(); 110 } 111 112 return entry; 113 } 114 115 void setAudioTrack(AudioTrack audioTrack) { 116 mAudioTrack = audioTrack; 117 } 118 119 AudioTrack getAudioTrack() { 120 return mAudioTrack; 121 } 122 123 // Must be called synchronized on this. 124 private long getUnconsumedAudioLengthMs() { 125 final int unconsumedFrames = mUnconsumedBytes / mBytesPerFrame; 126 final long estimatedTimeMs = unconsumedFrames * 1000 / mSampleRateInHz; 127 128 return estimatedTimeMs; 129 } 130 131 private static int getBytesPerFrame(int audioFormat) { 132 if (audioFormat == AudioFormat.ENCODING_PCM_8BIT) { 133 return 1; 134 } else if (audioFormat == AudioFormat.ENCODING_PCM_16BIT) { 135 return 2; 136 } 137 138 return -1; 139 } 140 141 static final class ListEntry { 142 final byte[] mBytes; 143 144 ListEntry(byte[] bytes) { 145 mBytes = bytes; 146 } 147 } 148 } 149 150