142 lines
4.1 KiB
Java
142 lines
4.1 KiB
Java
/*
|
|
* Copyright (C) 2011 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
* use this file except in compliance with the License. You may obtain a copy of
|
|
* the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations under
|
|
* the License.
|
|
*/
|
|
package android.speech.tts;
|
|
|
|
import android.util.Log;
|
|
|
|
import java.util.Iterator;
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
|
|
class AudioPlaybackHandler {
|
|
private static final String TAG = "TTS.AudioPlaybackHandler";
|
|
private static final boolean DBG = false;
|
|
|
|
private final LinkedBlockingQueue<PlaybackQueueItem> mQueue =
|
|
new LinkedBlockingQueue<PlaybackQueueItem>();
|
|
private final Thread mHandlerThread;
|
|
|
|
private volatile PlaybackQueueItem mCurrentWorkItem = null;
|
|
|
|
AudioPlaybackHandler() {
|
|
mHandlerThread = new Thread(new MessageLoop(), "TTS.AudioPlaybackThread");
|
|
}
|
|
|
|
public void start() {
|
|
mHandlerThread.start();
|
|
}
|
|
|
|
private void stop(PlaybackQueueItem item) {
|
|
if (item == null) {
|
|
return;
|
|
}
|
|
|
|
item.stop(TextToSpeech.STOPPED);
|
|
}
|
|
|
|
public void enqueue(PlaybackQueueItem item) {
|
|
try {
|
|
mQueue.put(item);
|
|
} catch (InterruptedException ie) {
|
|
// This exception will never be thrown, since we allow our queue
|
|
// to be have an unbounded size. put() will therefore never block.
|
|
}
|
|
}
|
|
|
|
public void stopForApp(Object callerIdentity) {
|
|
if (DBG) Log.d(TAG, "Removing all callback items for : " + callerIdentity);
|
|
removeWorkItemsFor(callerIdentity);
|
|
|
|
final PlaybackQueueItem current = mCurrentWorkItem;
|
|
if (current != null && (current.getCallerIdentity() == callerIdentity)) {
|
|
stop(current);
|
|
}
|
|
}
|
|
|
|
public void stop() {
|
|
if (DBG) Log.d(TAG, "Stopping all items");
|
|
removeAllMessages();
|
|
|
|
stop(mCurrentWorkItem);
|
|
}
|
|
|
|
/**
|
|
* @return false iff the queue is empty and no queue item is currently
|
|
* being handled, true otherwise.
|
|
*/
|
|
public boolean isSpeaking() {
|
|
return (mQueue.peek() != null) || (mCurrentWorkItem != null);
|
|
}
|
|
|
|
/**
|
|
* Shut down the audio playback thread.
|
|
*/
|
|
public void quit() {
|
|
removeAllMessages();
|
|
stop(mCurrentWorkItem);
|
|
mHandlerThread.interrupt();
|
|
}
|
|
|
|
/*
|
|
* Atomically clear the queue of all messages.
|
|
*/
|
|
private void removeAllMessages() {
|
|
mQueue.clear();
|
|
}
|
|
|
|
/*
|
|
* Remove all messages that originate from a given calling app.
|
|
*/
|
|
private void removeWorkItemsFor(Object callerIdentity) {
|
|
Iterator<PlaybackQueueItem> it = mQueue.iterator();
|
|
|
|
while (it.hasNext()) {
|
|
final PlaybackQueueItem item = it.next();
|
|
if (item.getCallerIdentity() == callerIdentity) {
|
|
it.remove();
|
|
stop(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The MessageLoop is a handler like implementation that
|
|
* processes messages from a priority queue.
|
|
*/
|
|
private final class MessageLoop implements Runnable {
|
|
@Override
|
|
public void run() {
|
|
while (true) {
|
|
PlaybackQueueItem item = null;
|
|
try {
|
|
item = mQueue.take();
|
|
} catch (InterruptedException ie) {
|
|
if (DBG) Log.d(TAG, "MessageLoop : Shutting down (interrupted)");
|
|
return;
|
|
}
|
|
|
|
// If stop() or stopForApp() are called between mQueue.take()
|
|
// returning and mCurrentWorkItem being set, the current work item
|
|
// will be run anyway.
|
|
|
|
mCurrentWorkItem = item;
|
|
item.run();
|
|
mCurrentWorkItem = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|