blob: 2900c8382dfc5231ccdba10815269bdf88a9ff10 [file] [log] [blame]
Narayan Kamath8d1fc242011-06-03 18:11:54 +01001/*
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
Narayan Kamath8d1fc242011-06-03 18:11:54 +010018import android.util.Log;
19
Narayan Kamath4924fe32011-06-09 11:35:13 +010020import java.util.Iterator;
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000021import java.util.concurrent.LinkedBlockingQueue;
Narayan Kamath4924fe32011-06-09 11:35:13 +010022
23class AudioPlaybackHandler {
Narayan Kamath8d1fc242011-06-03 18:11:54 +010024 private static final String TAG = "TTS.AudioPlaybackHandler";
25 private static final boolean DBG = false;
26
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000027 private final LinkedBlockingQueue<PlaybackQueueItem> mQueue =
28 new LinkedBlockingQueue<PlaybackQueueItem>();
Narayan Kamath4924fe32011-06-09 11:35:13 +010029 private final Thread mHandlerThread;
30
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000031 private volatile PlaybackQueueItem mCurrentWorkItem = null;
Narayan Kamath4924fe32011-06-09 11:35:13 +010032
33 AudioPlaybackHandler() {
34 mHandlerThread = new Thread(new MessageLoop(), "TTS.AudioPlaybackThread");
Narayan Kamath8d1fc242011-06-03 18:11:54 +010035 }
36
Narayan Kamath4924fe32011-06-09 11:35:13 +010037 public void start() {
38 mHandlerThread.start();
Narayan Kamath8d1fc242011-06-03 18:11:54 +010039 }
40
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000041 private void stop(PlaybackQueueItem item) {
42 if (item == null) {
Narayan Kamath4924fe32011-06-09 11:35:13 +010043 return;
44 }
45
Przemyslaw Szczepaniakfc4b2892014-06-26 11:52:20 +010046 item.stop(TextToSpeech.STOPPED);
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000047 }
Narayan Kamath8d1fc242011-06-03 18:11:54 +010048
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000049 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 Kamath8d1fc242011-06-03 18:11:54 +010055 }
56 }
57
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000058 public void stopForApp(Object callerIdentity) {
59 if (DBG) Log.d(TAG, "Removing all callback items for : " + callerIdentity);
60 removeWorkItemsFor(callerIdentity);
Narayan Kamathbe4ad4a2011-07-15 13:01:09 +010061
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000062 final PlaybackQueueItem current = mCurrentWorkItem;
Narayan Kamath492b7f02011-11-29 17:02:06 +000063 if (current != null && (current.getCallerIdentity() == callerIdentity)) {
Narayan Kamathbe4ad4a2011-07-15 13:01:09 +010064 stop(current);
65 }
Narayan Kamath4924fe32011-06-09 11:35:13 +010066 }
67
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000068 public void stop() {
69 if (DBG) Log.d(TAG, "Stopping all items");
Narayan Kamath4924fe32011-06-09 11:35:13 +010070 removeAllMessages();
Narayan Kamath40f71f02011-11-23 16:42:53 +000071
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000072 stop(mCurrentWorkItem);
Narayan Kamath4924fe32011-06-09 11:35:13 +010073 }
74
Narayan Kamath8d1fc242011-06-03 18:11:54 +010075 /**
Narayan Kamathc34f76f2011-07-15 11:13:10 +010076 * @return false iff the queue is empty and no queue item is currently
77 * being handled, true otherwise.
78 */
79 public boolean isSpeaking() {
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000080 return (mQueue.peek() != null) || (mCurrentWorkItem != null);
Narayan Kamathc34f76f2011-07-15 11:13:10 +010081 }
82
83 /**
Narayan Kamath8d1fc242011-06-03 18:11:54 +010084 * Shut down the audio playback thread.
85 */
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000086 public void quit() {
Narayan Kamathbe4ad4a2011-07-15 13:01:09 +010087 removeAllMessages();
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000088 stop(mCurrentWorkItem);
89 mHandlerThread.interrupt();
Narayan Kamath8d1fc242011-06-03 18:11:54 +010090 }
91
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000092 /*
93 * Atomically clear the queue of all messages.
94 */
95 private void removeAllMessages() {
96 mQueue.clear();
Narayan Kamath8d1fc242011-06-03 18:11:54 +010097 }
98
Narayan Kamath67ae6bc2011-11-30 14:51:00 +000099 /*
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();
Kazuhiro Inabaa81d17b2017-07-25 13:16:13 +0900109 stop(item);
Narayan Kamath67ae6bc2011-11-30 14:51:00 +0000110 }
111 }
Narayan Kamath8d1fc242011-06-03 18:11:54 +0100112 }
113
Narayan Kamath4924fe32011-06-09 11:35:13 +0100114 /*
115 * The MessageLoop is a handler like implementation that
116 * processes messages from a priority queue.
117 */
118 private final class MessageLoop implements Runnable {
119 @Override
120 public void run() {
121 while (true) {
Narayan Kamath67ae6bc2011-11-30 14:51:00 +0000122 PlaybackQueueItem item = null;
Narayan Kamath4924fe32011-06-09 11:35:13 +0100123 try {
Narayan Kamath67ae6bc2011-11-30 14:51:00 +0000124 item = mQueue.take();
Narayan Kamath4924fe32011-06-09 11:35:13 +0100125 } catch (InterruptedException ie) {
Narayan Kamath67ae6bc2011-11-30 14:51:00 +0000126 if (DBG) Log.d(TAG, "MessageLoop : Shutting down (interrupted)");
Narayan Kamath4924fe32011-06-09 11:35:13 +0100127 return;
128 }
129
Narayan Kamath67ae6bc2011-11-30 14:51:00 +0000130 // If stop() or stopForApp() are called between mQueue.take()
131 // returning and mCurrentWorkItem being set, the current work item
132 // will be run anyway.
Narayan Kamath4924fe32011-06-09 11:35:13 +0100133
Narayan Kamath67ae6bc2011-11-30 14:51:00 +0000134 mCurrentWorkItem = item;
135 item.run();
136 mCurrentWorkItem = null;
Narayan Kamath4924fe32011-06-09 11:35:13 +0100137 }
138 }
139 }
140
Narayan Kamath8d1fc242011-06-03 18:11:54 +0100141}