blob: 6307bc5b706a55ffdd68fe0f5c05a57afed39b46 [file] [log] [blame]
Andreas Hubere46b7be2009-07-14 16:56:47 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#undef __STRICT_ANSI__
18#define __STDINT_LIMITS
Marco Nelissen7013c8b2009-07-16 17:10:51 -070019#define __STDC_LIMIT_MACROS
Andreas Hubere46b7be2009-07-14 16:56:47 -070020#include <stdint.h>
21
22#define LOG_TAG "TimedEventQueue"
23#include <utils/Log.h>
24
Andreas Huberbd7b43b2009-10-13 10:22:55 -070025#include "include/TimedEventQueue.h"
26
Andreas Hubere46b7be2009-07-14 16:56:47 -070027#include <sys/time.h>
28
Andreas Huberb5ceb9e2009-08-26 14:48:20 -070029#include <media/stagefright/MediaDebug.h>
Andreas Hubere46b7be2009-07-14 16:56:47 -070030
Marco Nelissen7691af92010-02-19 15:16:57 -080031#ifdef ANDROID_SIMULATOR
32#include <jni.h>
33#endif
34
Andreas Hubere46b7be2009-07-14 16:56:47 -070035namespace android {
36
37TimedEventQueue::TimedEventQueue()
Andreas Huber9c540102009-11-17 10:25:01 -080038 : mNextEventID(1),
39 mRunning(false),
Andreas Hubere46b7be2009-07-14 16:56:47 -070040 mStopped(false) {
41}
42
43TimedEventQueue::~TimedEventQueue() {
44 stop();
45}
46
47void TimedEventQueue::start() {
48 if (mRunning) {
49 return;
50 }
51
52 mStopped = false;
53
54 pthread_attr_t attr;
55 pthread_attr_init(&attr);
56 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
57
58 pthread_create(&mThread, &attr, ThreadWrapper, this);
59
60 pthread_attr_destroy(&attr);
61
62 mRunning = true;
63}
64
65void TimedEventQueue::stop(bool flush) {
66 if (!mRunning) {
67 return;
68 }
69
70 if (flush) {
71 postEventToBack(new StopEvent);
72 } else {
73 postTimedEvent(new StopEvent, INT64_MIN);
74 }
75
76 void *dummy;
77 pthread_join(mThread, &dummy);
78
79 mQueue.clear();
80
81 mRunning = false;
82}
83
Andreas Huber9c540102009-11-17 10:25:01 -080084TimedEventQueue::event_id TimedEventQueue::postEvent(const sp<Event> &event) {
Andreas Hubere46b7be2009-07-14 16:56:47 -070085 // Reserve an earlier timeslot an INT64_MIN to be able to post
86 // the StopEvent to the absolute head of the queue.
Andreas Huber9c540102009-11-17 10:25:01 -080087 return postTimedEvent(event, INT64_MIN + 1);
Andreas Hubere46b7be2009-07-14 16:56:47 -070088}
89
Andreas Huber9c540102009-11-17 10:25:01 -080090TimedEventQueue::event_id TimedEventQueue::postEventToBack(
91 const sp<Event> &event) {
92 return postTimedEvent(event, INT64_MAX);
Andreas Hubere46b7be2009-07-14 16:56:47 -070093}
94
Andreas Huber9c540102009-11-17 10:25:01 -080095TimedEventQueue::event_id TimedEventQueue::postEventWithDelay(
Andreas Hubere46b7be2009-07-14 16:56:47 -070096 const sp<Event> &event, int64_t delay_us) {
Andreas Huberb5ceb9e2009-08-26 14:48:20 -070097 CHECK(delay_us >= 0);
Andreas Huber9c540102009-11-17 10:25:01 -080098 return postTimedEvent(event, getRealTimeUs() + delay_us);
Andreas Hubere46b7be2009-07-14 16:56:47 -070099}
100
Andreas Huber9c540102009-11-17 10:25:01 -0800101TimedEventQueue::event_id TimedEventQueue::postTimedEvent(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700102 const sp<Event> &event, int64_t realtime_us) {
103 Mutex::Autolock autoLock(mLock);
104
Andreas Huber9c540102009-11-17 10:25:01 -0800105 event->setEventID(mNextEventID++);
106
Andreas Hubere46b7be2009-07-14 16:56:47 -0700107 List<QueueItem>::iterator it = mQueue.begin();
108 while (it != mQueue.end() && realtime_us >= (*it).realtime_us) {
109 ++it;
110 }
111
112 QueueItem item;
113 item.event = event;
114 item.realtime_us = realtime_us;
115
116 if (it == mQueue.begin()) {
117 mQueueHeadChangedCondition.signal();
118 }
119
120 mQueue.insert(it, item);
121
122 mQueueNotEmptyCondition.signal();
Andreas Huber9c540102009-11-17 10:25:01 -0800123
124 return event->eventID();
Andreas Hubere46b7be2009-07-14 16:56:47 -0700125}
126
Andreas Huber9c540102009-11-17 10:25:01 -0800127static bool MatchesEventID(
128 void *cookie, const sp<TimedEventQueue::Event> &event) {
129 TimedEventQueue::event_id *id =
130 static_cast<TimedEventQueue::event_id *>(cookie);
Andreas Hubere46b7be2009-07-14 16:56:47 -0700131
Andreas Huber9c540102009-11-17 10:25:01 -0800132 if (event->eventID() != *id) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700133 return false;
134 }
135
Andreas Huber9c540102009-11-17 10:25:01 -0800136 *id = 0;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700137
138 return true;
139}
140
Andreas Huber9c540102009-11-17 10:25:01 -0800141bool TimedEventQueue::cancelEvent(event_id id) {
Andreas Huber27366fc2009-11-20 09:32:46 -0800142 if (id == 0) {
143 return false;
144 }
Andreas Huber9c540102009-11-17 10:25:01 -0800145
146 cancelEvents(&MatchesEventID, &id, true /* stopAfterFirstMatch */);
147
148 // if MatchesEventID found a match, it will have set id to 0
149 // (which is not a valid event_id).
150
151 return id == 0;
152}
153
154void TimedEventQueue::cancelEvents(
155 bool (*predicate)(void *cookie, const sp<Event> &event),
156 void *cookie,
157 bool stopAfterFirstMatch) {
158 Mutex::Autolock autoLock(mLock);
159
160 List<QueueItem>::iterator it = mQueue.begin();
161 while (it != mQueue.end()) {
162 if (!(*predicate)(cookie, (*it).event)) {
163 ++it;
164 continue;
165 }
166
167 if (it == mQueue.begin()) {
168 mQueueHeadChangedCondition.signal();
169 }
170
Andreas Huber27366fc2009-11-20 09:32:46 -0800171 (*it).event->setEventID(0);
Andreas Huber9c540102009-11-17 10:25:01 -0800172 it = mQueue.erase(it);
173
174 if (stopAfterFirstMatch) {
175 return;
176 }
177 }
178}
179
Andreas Hubere46b7be2009-07-14 16:56:47 -0700180// static
181int64_t TimedEventQueue::getRealTimeUs() {
182 struct timeval tv;
183 gettimeofday(&tv, NULL);
184
185 return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
186}
187
188// static
189void *TimedEventQueue::ThreadWrapper(void *me) {
Marco Nelissen7691af92010-02-19 15:16:57 -0800190
191#ifdef ANDROID_SIMULATOR
192 // The simulator runs everything as one process, so any
193 // Binder calls happen on this thread instead of a thread
194 // in another process. We therefore need to make sure that
195 // this thread can do calls into interpreted code.
196 // On the device this is not an issue because the remote
197 // thread will already be set up correctly for this.
198 JavaVM *vm;
199 int numvms;
200 JNI_GetCreatedJavaVMs(&vm, 1, &numvms);
201 JNIEnv *env;
202 vm->AttachCurrentThread(&env, NULL);
203#endif
204
Andreas Hubere46b7be2009-07-14 16:56:47 -0700205 static_cast<TimedEventQueue *>(me)->threadEntry();
206
Marco Nelissen7691af92010-02-19 15:16:57 -0800207#ifdef ANDROID_SIMULATOR
208 vm->DetachCurrentThread();
209#endif
Andreas Hubere46b7be2009-07-14 16:56:47 -0700210 return NULL;
211}
212
213void TimedEventQueue::threadEntry() {
214 for (;;) {
215 int64_t now_us;
216 sp<Event> event;
217
218 {
219 Mutex::Autolock autoLock(mLock);
220
221 if (mStopped) {
222 break;
223 }
224
225 while (mQueue.empty()) {
226 mQueueNotEmptyCondition.wait(mLock);
227 }
228
229 List<QueueItem>::iterator it;
230 for (;;) {
231 it = mQueue.begin();
232
233 now_us = getRealTimeUs();
234 int64_t when_us = (*it).realtime_us;
235
236 int64_t delay_us;
237 if (when_us < 0 || when_us == INT64_MAX) {
238 delay_us = 0;
239 } else {
240 delay_us = when_us - now_us;
241 }
242
243 if (delay_us <= 0) {
244 break;
245 }
246
247 status_t err = mQueueHeadChangedCondition.waitRelative(
248 mLock, delay_us * 1000);
249
250 if (err == -ETIMEDOUT) {
251 now_us = getRealTimeUs();
252 break;
253 }
254 }
255
Andreas Huber27366fc2009-11-20 09:32:46 -0800256 if (mQueue.empty()) {
257 continue;
258 }
259
Andreas Hubere46b7be2009-07-14 16:56:47 -0700260 event = (*it).event;
Andreas Huber27366fc2009-11-20 09:32:46 -0800261 event->setEventID(0);
Andreas Hubere46b7be2009-07-14 16:56:47 -0700262 mQueue.erase(it);
263 }
264
265 // Fire event with the lock NOT held.
266 event->fire(this, now_us);
267 }
268}
269
270} // namespace android
271