[Change]
开始USB摄像头的功能集成,还无法获取usb连接广播需要调试 Signed-off-by: donghongyu <donghongyu@zhidaoauto.com>
This commit is contained in:
@@ -0,0 +1,515 @@
|
||||
package com.serenegiant.utils;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public abstract class MessageTask implements Runnable {
|
||||
// private static final boolean DEBUG = false; // FIXME 実働時はfalseにすること
|
||||
private static final String TAG = MessageTask.class.getSimpleName();
|
||||
|
||||
public static class TaskBreak extends RuntimeException {
|
||||
}
|
||||
|
||||
protected static final class Request {
|
||||
int request;
|
||||
int arg1;
|
||||
int arg2;
|
||||
Object obj;
|
||||
int request_for_result;
|
||||
Object result;
|
||||
|
||||
private Request() {
|
||||
request = request_for_result = REQUEST_TASK_NON;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param _request minus value is reserved internal use
|
||||
* @param _arg1
|
||||
* @param _arg2
|
||||
* @param _obj
|
||||
*/
|
||||
public Request(final int _request, final int _arg1, final int _arg2, final Object _obj) {
|
||||
request = _request;
|
||||
arg1 = _arg1;
|
||||
arg2 = _arg2;
|
||||
obj = _obj;
|
||||
request_for_result = REQUEST_TASK_NON;
|
||||
}
|
||||
|
||||
public void setResult(final Object result) {
|
||||
synchronized (this) {
|
||||
this.result = result;
|
||||
request = request_for_result = REQUEST_TASK_NON;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
return (o instanceof Request)
|
||||
? (request == ((Request) o).request)
|
||||
&& (request_for_result == ((Request)o).request_for_result)
|
||||
&& (arg1 == ((Request) o).arg1)
|
||||
&& (arg2 == ((Request) o).arg2)
|
||||
&& (obj == ((Request) o).obj)
|
||||
: super.equals(o);
|
||||
}
|
||||
}
|
||||
|
||||
// minus values and zero are reserved for internal use
|
||||
protected static final int REQUEST_TASK_NON = 0;
|
||||
protected static final int REQUEST_TASK_RUN = -1;
|
||||
protected static final int REQUEST_TASK_RUN_AND_WAIT = -2;
|
||||
protected static final int REQUEST_TASK_START = -8;
|
||||
protected static final int REQUEST_TASK_QUIT = -9;
|
||||
|
||||
private final Object mSync = new Object();
|
||||
/** プール/キューのサイズ, -1なら無制限 */
|
||||
private final int mMaxRequest;
|
||||
private final LinkedBlockingQueue<Request> mRequestPool; // FIXME これはArrayListにした方が速いかも
|
||||
private final LinkedBlockingDeque<Request> mRequestQueue;
|
||||
private volatile boolean mIsRunning, mFinished;
|
||||
private Thread mWorkerThread;
|
||||
|
||||
/**
|
||||
* コンストラクタ
|
||||
* プール&キューのサイズは無制限
|
||||
* プールは空で生成
|
||||
*/
|
||||
public MessageTask() {
|
||||
mMaxRequest = -1;
|
||||
mRequestPool = new LinkedBlockingQueue<Request>();
|
||||
mRequestQueue = new LinkedBlockingDeque<Request>();
|
||||
}
|
||||
|
||||
/**
|
||||
* コンストラクタ
|
||||
* プール&キューのサイズは無制限
|
||||
* @param init_num プールするRequestの初期数を指定
|
||||
*/
|
||||
public MessageTask(final int init_num) {
|
||||
mMaxRequest = -1;
|
||||
mRequestPool = new LinkedBlockingQueue<Request>();
|
||||
mRequestQueue = new LinkedBlockingDeque<Request>();
|
||||
for (int i = 0; i < init_num; i++) {
|
||||
if (!mRequestPool.offer(new Request())) break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* コンストラクタ
|
||||
* プール及びキュー可能な最大サイズを指定して初期化
|
||||
* @param max_request キューの最大サイズを指定
|
||||
* @param init_num プールするRequestの初期数を指定, max_requestよりも大きければ切り捨てる
|
||||
*/
|
||||
public MessageTask(final int max_request, final int init_num) {
|
||||
mMaxRequest = max_request;
|
||||
mRequestPool = new LinkedBlockingQueue<Request>(max_request);
|
||||
mRequestQueue = new LinkedBlockingDeque<Request>(max_request);
|
||||
for (int i = 0; i < init_num; i++) {
|
||||
if (!mRequestPool.offer(new Request())) break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初期化要求。継承クラスのコンストラクタから呼び出すこと
|
||||
* パラメータはonInitに引き渡される
|
||||
* @param arg1
|
||||
* @param arg2
|
||||
* @param obj
|
||||
*/
|
||||
protected void init(final int arg1, final int arg2, final Object obj) {
|
||||
mFinished = false;
|
||||
mRequestQueue.offer(obtain(REQUEST_TASK_START, arg1, arg2, obj));
|
||||
// offer(REQUEST_TASK_START, arg1, arg2, obj);
|
||||
}
|
||||
|
||||
/** 初期化処理 */
|
||||
protected abstract void onInit(final int arg1, final int arg2, final Object obj);
|
||||
|
||||
/** 要求処理ループ開始直前に呼ばれる */
|
||||
protected abstract void onStart();
|
||||
|
||||
/** onStopの直前に呼び出される, interruptされた時は呼び出されない */
|
||||
protected void onBeforeStop() {}
|
||||
|
||||
/** 停止処理, interruptされた時は呼び出されない */
|
||||
protected abstract void onStop();
|
||||
|
||||
/** onStop後に呼び出される。onStopで例外発生しても呼ばれる */
|
||||
protected abstract void onRelease();
|
||||
|
||||
/**
|
||||
* メッセージ処理ループ中でのエラー発生時の処理
|
||||
* デフフォルトはtrueを返しメッセージ処理ループを終了する
|
||||
* @return trueを返すとメッセージ処理ループを終了する
|
||||
*/
|
||||
protected boolean onError(final Exception e) {
|
||||
// if (DEBUG) Log.w(TAG, e);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 要求メッセージの処理(内部メッセージは来ない)
|
||||
* TaskBreakをthrowすると要求メッセージ処理ループを終了する */
|
||||
protected abstract Object processRequest(final int request, final int arg1, final int arg2, final Object obj) throws TaskBreak;
|
||||
|
||||
/** 要求メッセージを取り出す処理(要求メッセージがなければブロックされる) */
|
||||
protected Request takeRequest() throws InterruptedException {
|
||||
return mRequestQueue.take();
|
||||
}
|
||||
|
||||
public boolean waitReady() {
|
||||
synchronized (mSync) {
|
||||
for ( ; !mIsRunning && !mFinished ; ) {
|
||||
try {
|
||||
mSync.wait(500);
|
||||
} catch (final InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mIsRunning;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return mIsRunning;
|
||||
}
|
||||
|
||||
public boolean isFinished() {
|
||||
return mFinished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Request request = null;
|
||||
mIsRunning = true;
|
||||
try {
|
||||
request = mRequestQueue.take();
|
||||
} catch (final InterruptedException e) {
|
||||
mIsRunning = false;
|
||||
mFinished = true;
|
||||
}
|
||||
synchronized (mSync) {
|
||||
if (mIsRunning) {
|
||||
mWorkerThread = Thread.currentThread();
|
||||
try {
|
||||
onInit(request.arg1, request.arg2, request.obj);
|
||||
} catch (final Exception e) {
|
||||
Log.w(TAG, e);
|
||||
mIsRunning = false;
|
||||
mFinished = true;
|
||||
}
|
||||
}
|
||||
mSync.notifyAll();
|
||||
}
|
||||
if (mIsRunning) {
|
||||
try {
|
||||
onStart();
|
||||
} catch (final Exception e) {
|
||||
if (callOnError(e)) {
|
||||
mIsRunning = false;
|
||||
mFinished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOOP: for (; mIsRunning; ) {
|
||||
try {
|
||||
request = takeRequest();
|
||||
switch (request.request) {
|
||||
case REQUEST_TASK_NON:
|
||||
break;
|
||||
case REQUEST_TASK_QUIT:
|
||||
break LOOP;
|
||||
case REQUEST_TASK_RUN:
|
||||
if (request.obj instanceof Runnable)
|
||||
try {
|
||||
((Runnable)request.obj).run();
|
||||
} catch (final Exception e) {
|
||||
if (callOnError(e))
|
||||
break LOOP;
|
||||
}
|
||||
break;
|
||||
case REQUEST_TASK_RUN_AND_WAIT:
|
||||
try {
|
||||
request.setResult(processRequest(request.request_for_result, request.arg1, request.arg2, request.obj));
|
||||
} catch (final TaskBreak e) {
|
||||
request.setResult(null);
|
||||
break LOOP;
|
||||
} catch (final Exception e) {
|
||||
request.setResult(null);
|
||||
if (callOnError(e))
|
||||
break LOOP;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
try {
|
||||
processRequest(request.request, request.arg1, request.arg2, request.obj);
|
||||
} catch (final TaskBreak e) {
|
||||
break LOOP;
|
||||
} catch (final Exception e) {
|
||||
if (callOnError(e))
|
||||
break LOOP;
|
||||
}
|
||||
break;
|
||||
}
|
||||
request.request = request.request_for_result = REQUEST_TASK_NON;
|
||||
// プールへ返却する
|
||||
mRequestPool.offer(request);
|
||||
} catch (final InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
final boolean interrupted = Thread.interrupted();
|
||||
synchronized (mSync) {
|
||||
mWorkerThread = null;
|
||||
mIsRunning = false;
|
||||
mFinished = true;
|
||||
}
|
||||
if (!interrupted) {
|
||||
try {
|
||||
onBeforeStop();
|
||||
onStop();
|
||||
} catch (final Exception e) {
|
||||
callOnError(e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
onRelease();
|
||||
} catch (final Exception e) {
|
||||
// callOnError(e);
|
||||
}
|
||||
synchronized (mSync) {
|
||||
mSync.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* エラー処理。onErrorを呼び出す。
|
||||
* trueを返すと要求メッセージ処理ループを終了する
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
protected boolean callOnError(final Exception e) {
|
||||
try {
|
||||
return onError(e);
|
||||
} catch (final Exception e2) {
|
||||
// if (DEBUG) Log.e(TAG, "exception occurred in callOnError", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* RequestプールからRequestを取得する
|
||||
* プールが空の場合は新規に生成する
|
||||
* @param request minus values and zero are reserved
|
||||
* @param arg1
|
||||
* @param arg2
|
||||
* @param obj
|
||||
* @return Request
|
||||
*/
|
||||
protected Request obtain(final int request, final int arg1, final int arg2, final Object obj) {
|
||||
Request req = mRequestPool.poll();
|
||||
if (req != null) {
|
||||
req.request = request;
|
||||
req.arg1 = arg1;
|
||||
req.arg2 = arg2;
|
||||
req.obj = obj;
|
||||
} else {
|
||||
req = new Request(request, arg1, arg2, obj);
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
/**
|
||||
* offer request to run on worker thread
|
||||
* @param request minus values and zero are reserved
|
||||
* @param arg1
|
||||
* @param arg2
|
||||
* @param obj
|
||||
* @return true if success offer
|
||||
*/
|
||||
public boolean offer(final int request, final int arg1, final int arg2, final Object obj) {
|
||||
return !mFinished && mRequestQueue.offer(obtain(request, arg1, arg2, obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* offer request to run on worker thread
|
||||
* @param request minus values and zero are reserved
|
||||
* @param arg1
|
||||
* @param obj
|
||||
* @return true if success offer
|
||||
*/
|
||||
public boolean offer(final int request, final int arg1, final Object obj) {
|
||||
return !mFinished && mRequestQueue.offer(obtain(request, arg1, 0, obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* offer request to run on worker thread
|
||||
* @param request minus values and zero are reserved
|
||||
* @param arg1
|
||||
* @param arg2
|
||||
* @return true if success offer
|
||||
*/
|
||||
public boolean offer(final int request, final int arg1, final int arg2) {
|
||||
return !mFinished && mIsRunning && mRequestQueue.offer(obtain(request, arg1, arg2, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* offer request to run on worker thread
|
||||
* @param request minus values and zero are reserved
|
||||
* @param arg1
|
||||
* @return true if success offer
|
||||
*/
|
||||
public boolean offer(final int request, final int arg1) {
|
||||
return !mFinished && mIsRunning && mRequestQueue.offer(obtain(request, arg1, 0, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* offer request to run on worker thread
|
||||
* @param request minus values and zero are reserved
|
||||
* @return true if success offer
|
||||
*/
|
||||
public boolean offer(final int request) {
|
||||
return !mFinished && mIsRunning && mRequestQueue.offer(obtain(request, 0, 0, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* offer request to run on worker thread
|
||||
* @param request minus values and zero are reserved
|
||||
* @param obj
|
||||
* @return true if success offer
|
||||
*/
|
||||
public boolean offer(final int request, final Object obj) {
|
||||
return !mFinished && mIsRunning && mRequestQueue.offer(obtain(request, 0, 0, obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* offer request to run on worker thread on top of the request queue
|
||||
* @param request minus values and zero are reserved
|
||||
* @param arg1
|
||||
* @param arg2
|
||||
*/
|
||||
public boolean offerFirst(final int request, final int arg1, final int arg2, final Object obj) {
|
||||
return !mFinished && mIsRunning && mRequestQueue.offerFirst(obtain(request, arg1, arg2, obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* offer request to run on worker thread and wait for result
|
||||
* caller thread is blocked until the request finished running on worker thread
|
||||
* FIXME このメソッドはMessageTaskを実行中のスレッド上で呼び出すとデッドロックする
|
||||
* @param request
|
||||
* @param arg1
|
||||
* @param arg2
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
public Object offerAndWait(final int request, final int arg1, final int arg2, final Object obj) {
|
||||
if (!mFinished && (request > REQUEST_TASK_NON)) {
|
||||
final Request req = obtain(REQUEST_TASK_RUN_AND_WAIT, arg1, arg2, obj);
|
||||
synchronized (req) {
|
||||
req.request_for_result = request;
|
||||
req.result = null;
|
||||
mRequestQueue.offer(req);
|
||||
for (; mIsRunning && (req.request_for_result != REQUEST_TASK_NON); ) {
|
||||
try {
|
||||
req.wait(100);
|
||||
} catch (final InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return req.result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* request to run on worker thread
|
||||
* @param task
|
||||
* @return true if success queue
|
||||
*/
|
||||
public boolean queueEvent(final Runnable task) {
|
||||
return !mFinished && (task != null) && offer(REQUEST_TASK_RUN, task);
|
||||
}
|
||||
|
||||
public void removeRequest(final Request request) {
|
||||
for (final Request req: mRequestQueue) {
|
||||
if (!mIsRunning || mFinished) break;
|
||||
if (req.equals(request)) {
|
||||
mRequestQueue.remove(req);
|
||||
mRequestPool.offer(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeRequest(final int request) {
|
||||
for (final Request req: mRequestQueue) {
|
||||
if (!mIsRunning || mFinished) break;
|
||||
if (req.request == request) {
|
||||
mRequestQueue.remove(req);
|
||||
mRequestPool.offer(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* request terminate worker thread and release all related resources
|
||||
*/
|
||||
public void release() {
|
||||
release(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* request terminate worker thread and release all related resources
|
||||
* @param interrupt trueなら実行中のタスクをinterruptする
|
||||
*/
|
||||
public void release(final boolean interrupt) {
|
||||
final boolean b = mIsRunning;
|
||||
mIsRunning = false;
|
||||
if (!mFinished) {
|
||||
mRequestQueue.clear();
|
||||
mRequestQueue.offerFirst(obtain(REQUEST_TASK_QUIT, 0, 0, null));
|
||||
synchronized (mSync) {
|
||||
if (b) {
|
||||
final long current = Thread.currentThread().getId();
|
||||
final long id = mWorkerThread != null ? mWorkerThread.getId() : current;
|
||||
if (id != current) {
|
||||
if (interrupt && (mWorkerThread != null)) {
|
||||
mWorkerThread.interrupt();
|
||||
}
|
||||
for ( ; !mFinished ; ) {
|
||||
try {
|
||||
mSync.wait(300);
|
||||
} catch (final InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 実行中のタスクが終了後開放する
|
||||
*/
|
||||
public void releaseSelf() {
|
||||
mIsRunning = false;
|
||||
if (!mFinished) {
|
||||
mRequestQueue.clear();
|
||||
mRequestQueue.offerFirst(obtain(REQUEST_TASK_QUIT, 0, 0, null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* processRequest内でメッセージループを非常終了させるためのヘルパーメソッド
|
||||
* 単にTaskBreakをthrowするだけ
|
||||
* @throws TaskBreak
|
||||
*/
|
||||
public void userBreak() throws TaskBreak {
|
||||
throw new TaskBreak();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user