Narayan Kamath | 8d1fc24 | 2011-06-03 18:11:54 +0100 | [diff] [blame] | 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 | |
Narayan Kamath | 8d1fc24 | 2011-06-03 18:11:54 +0100 | [diff] [blame] | 18 | import android.util.Log; |
| 19 | |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 20 | import java.util.Iterator; |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 21 | import java.util.concurrent.LinkedBlockingQueue; |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 22 | |
| 23 | class AudioPlaybackHandler { |
Narayan Kamath | 8d1fc24 | 2011-06-03 18:11:54 +0100 | [diff] [blame] | 24 | private static final String TAG = "TTS.AudioPlaybackHandler"; |
| 25 | private static final boolean DBG = false; |
| 26 | |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 27 | private final LinkedBlockingQueue<PlaybackQueueItem> mQueue = |
| 28 | new LinkedBlockingQueue<PlaybackQueueItem>(); |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 29 | private final Thread mHandlerThread; |
| 30 | |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 31 | private volatile PlaybackQueueItem mCurrentWorkItem = null; |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 32 | |
| 33 | AudioPlaybackHandler() { |
| 34 | mHandlerThread = new Thread(new MessageLoop(), "TTS.AudioPlaybackThread"); |
Narayan Kamath | 8d1fc24 | 2011-06-03 18:11:54 +0100 | [diff] [blame] | 35 | } |
| 36 | |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 37 | public void start() { |
| 38 | mHandlerThread.start(); |
Narayan Kamath | 8d1fc24 | 2011-06-03 18:11:54 +0100 | [diff] [blame] | 39 | } |
| 40 | |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 41 | private void stop(PlaybackQueueItem item) { |
| 42 | if (item == null) { |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 43 | return; |
| 44 | } |
| 45 | |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 46 | item.stop(false); |
| 47 | } |
Narayan Kamath | 8d1fc24 | 2011-06-03 18:11:54 +0100 | [diff] [blame] | 48 | |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 49 | public void enqueue(PlaybackQueueItem item) { |
| 50 | try { |
| 51 | mQueue.put(item); |
| 52 | } catch (InterruptedException ie) { |
| 53 | // This exception will never be thrown, since we allow our queue |
| 54 | // to be have an unbounded size. put() will therefore never block. |
Narayan Kamath | 8d1fc24 | 2011-06-03 18:11:54 +0100 | [diff] [blame] | 55 | } |
| 56 | } |
| 57 | |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 58 | public void stopForApp(Object callerIdentity) { |
| 59 | if (DBG) Log.d(TAG, "Removing all callback items for : " + callerIdentity); |
| 60 | removeWorkItemsFor(callerIdentity); |
Narayan Kamath | be4ad4a | 2011-07-15 13:01:09 +0100 | [diff] [blame] | 61 | |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 62 | final PlaybackQueueItem current = mCurrentWorkItem; |
Narayan Kamath | 492b7f0 | 2011-11-29 17:02:06 +0000 | [diff] [blame] | 63 | if (current != null && (current.getCallerIdentity() == callerIdentity)) { |
Narayan Kamath | be4ad4a | 2011-07-15 13:01:09 +0100 | [diff] [blame] | 64 | stop(current); |
| 65 | } |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 66 | } |
| 67 | |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 68 | public void stop() { |
| 69 | if (DBG) Log.d(TAG, "Stopping all items"); |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 70 | removeAllMessages(); |
Narayan Kamath | 40f71f0 | 2011-11-23 16:42:53 +0000 | [diff] [blame] | 71 | |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 72 | stop(mCurrentWorkItem); |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 73 | } |
| 74 | |
Narayan Kamath | 8d1fc24 | 2011-06-03 18:11:54 +0100 | [diff] [blame] | 75 | /** |
Narayan Kamath | c34f76f | 2011-07-15 11:13:10 +0100 | [diff] [blame] | 76 | * @return false iff the queue is empty and no queue item is currently |
| 77 | * being handled, true otherwise. |
| 78 | */ |
| 79 | public boolean isSpeaking() { |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 80 | return (mQueue.peek() != null) || (mCurrentWorkItem != null); |
Narayan Kamath | c34f76f | 2011-07-15 11:13:10 +0100 | [diff] [blame] | 81 | } |
| 82 | |
| 83 | /** |
Narayan Kamath | 8d1fc24 | 2011-06-03 18:11:54 +0100 | [diff] [blame] | 84 | * Shut down the audio playback thread. |
| 85 | */ |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 86 | public void quit() { |
Narayan Kamath | be4ad4a | 2011-07-15 13:01:09 +0100 | [diff] [blame] | 87 | removeAllMessages(); |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 88 | stop(mCurrentWorkItem); |
| 89 | mHandlerThread.interrupt(); |
Narayan Kamath | 8d1fc24 | 2011-06-03 18:11:54 +0100 | [diff] [blame] | 90 | } |
| 91 | |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 92 | /* |
| 93 | * Atomically clear the queue of all messages. |
| 94 | */ |
| 95 | private void removeAllMessages() { |
| 96 | mQueue.clear(); |
Narayan Kamath | 8d1fc24 | 2011-06-03 18:11:54 +0100 | [diff] [blame] | 97 | } |
| 98 | |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 99 | /* |
| 100 | * Remove all messages that originate from a given calling app. |
| 101 | */ |
| 102 | private void removeWorkItemsFor(Object callerIdentity) { |
| 103 | Iterator<PlaybackQueueItem> it = mQueue.iterator(); |
| 104 | |
| 105 | while (it.hasNext()) { |
| 106 | final PlaybackQueueItem item = it.next(); |
| 107 | if (item.getCallerIdentity() == callerIdentity) { |
| 108 | it.remove(); |
| 109 | } |
| 110 | } |
Narayan Kamath | 8d1fc24 | 2011-06-03 18:11:54 +0100 | [diff] [blame] | 111 | } |
| 112 | |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 113 | /* |
| 114 | * The MessageLoop is a handler like implementation that |
| 115 | * processes messages from a priority queue. |
| 116 | */ |
| 117 | private final class MessageLoop implements Runnable { |
| 118 | @Override |
| 119 | public void run() { |
| 120 | while (true) { |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 121 | PlaybackQueueItem item = null; |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 122 | try { |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 123 | item = mQueue.take(); |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 124 | } catch (InterruptedException ie) { |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 125 | if (DBG) Log.d(TAG, "MessageLoop : Shutting down (interrupted)"); |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 126 | return; |
| 127 | } |
| 128 | |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 129 | // If stop() or stopForApp() are called between mQueue.take() |
| 130 | // returning and mCurrentWorkItem being set, the current work item |
| 131 | // will be run anyway. |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 132 | |
Narayan Kamath | 67ae6bc | 2011-11-30 14:51:00 +0000 | [diff] [blame] | 133 | mCurrentWorkItem = item; |
| 134 | item.run(); |
| 135 | mCurrentWorkItem = null; |
Narayan Kamath | 4924fe3 | 2011-06-09 11:35:13 +0100 | [diff] [blame] | 136 | } |
| 137 | } |
| 138 | } |
| 139 | |
Narayan Kamath | 8d1fc24 | 2011-06-03 18:11:54 +0100 | [diff] [blame] | 140 | } |