summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/foundation/ALooper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/foundation/ALooper.cpp')
-rw-r--r--media/libstagefright/foundation/ALooper.cpp196
1 files changed, 196 insertions, 0 deletions
diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
new file mode 100644
index 0000000..831fa2a
--- /dev/null
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ALooper"
+#include <utils/Log.h>
+
+#include <sys/time.h>
+
+#include "ALooper.h"
+
+#include "AHandler.h"
+#include "ALooperRoster.h"
+#include "AMessage.h"
+
+namespace android {
+
+ALooperRoster gLooperRoster;
+
+struct ALooper::LooperThread : public Thread {
+ LooperThread(ALooper *looper)
+ : mLooper(looper) {
+ }
+
+ virtual bool threadLoop() {
+ return mLooper->loop();
+ }
+
+protected:
+ virtual ~LooperThread() {}
+
+private:
+ ALooper *mLooper;
+
+ DISALLOW_EVIL_CONSTRUCTORS(LooperThread);
+};
+
+// static
+int64_t ALooper::GetNowUs() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ return (int64_t)tv.tv_sec * 1000000ll + tv.tv_usec;
+}
+
+ALooper::ALooper()
+ : mRunningLocally(false) {
+}
+
+ALooper::~ALooper() {
+ stop();
+}
+
+ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
+ return gLooperRoster.registerHandler(this, handler);
+}
+
+void ALooper::unregisterHandler(handler_id handlerID) {
+ gLooperRoster.unregisterHandler(handlerID);
+}
+
+status_t ALooper::start(bool runOnCallingThread) {
+ if (runOnCallingThread) {
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mThread != NULL || mRunningLocally) {
+ return INVALID_OPERATION;
+ }
+
+ mRunningLocally = true;
+ }
+
+ do {
+ } while (loop());
+
+ return OK;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (mThread != NULL || mRunningLocally) {
+ return INVALID_OPERATION;
+ }
+
+ mThread = new LooperThread(this);
+
+ status_t err = mThread->run("ALooper");
+ if (err != OK) {
+ mThread.clear();
+ }
+
+ return err;
+}
+
+status_t ALooper::stop() {
+ sp<LooperThread> thread;
+ bool runningLocally;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ thread = mThread;
+ runningLocally = mRunningLocally;
+ mThread.clear();
+ mRunningLocally = false;
+ }
+
+ if (thread == NULL && !runningLocally) {
+ return INVALID_OPERATION;
+ }
+
+ if (thread != NULL) {
+ thread->requestExit();
+ }
+
+ mQueueChangedCondition.signal();
+
+ if (!runningLocally) {
+ thread->requestExitAndWait();
+ }
+
+ return OK;
+}
+
+void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {
+ Mutex::Autolock autoLock(mLock);
+
+ int64_t whenUs;
+ if (delayUs > 0) {
+ whenUs = GetNowUs() + delayUs;
+ } else {
+ whenUs = GetNowUs();
+ }
+
+ List<Event>::iterator it = mEventQueue.begin();
+ while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {
+ ++it;
+ }
+
+ Event event;
+ event.mWhenUs = whenUs;
+ event.mMessage = msg;
+
+ if (it == mEventQueue.begin()) {
+ mQueueChangedCondition.signal();
+ }
+
+ mEventQueue.insert(it, event);
+}
+
+bool ALooper::loop() {
+ Event event;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+ if (mThread == NULL && !mRunningLocally) {
+ return false;
+ }
+ if (mEventQueue.empty()) {
+ mQueueChangedCondition.wait(mLock);
+ return true;
+ }
+ int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
+ int64_t nowUs = GetNowUs();
+
+ if (whenUs > nowUs) {
+ int64_t delayUs = whenUs - nowUs;
+ mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);
+
+ return true;
+ }
+
+ event = *mEventQueue.begin();
+ mEventQueue.erase(mEventQueue.begin());
+ }
+
+ gLooperRoster.deliverMessage(event.mMessage);
+
+ return true;
+}
+
+} // namespace android