Stagefright is an implementation of OpenMAX IL on android platform, and contains two levels of asynchronous processing. Each is composed of four elements typically present in a reactor pattern in concurrent computing: a generic message data structure, a generic message handler and a message dispatcher, plus a messaging loop/thread.
At the lower level, stagefright implements Open MAX IL in class OMX, which defines struct CallbackDispatcher and struct CallbackDispatcherThread as follow:
struct OMX::CallbackDispatcherThread : public Thread {
CallbackDispatcherThread(CallbackDispatcher *dispatcher)
: mDispatcher(dispatcher) {
}
private:
CallbackDispatcher *mDispatcher;
bool threadLoop();
CallbackDispatcherThread(const CallbackDispatcherThread &);
CallbackDispatcherThread &operator=(const CallbackDispatcherThread &);
};
struct OMX::CallbackDispatcher : public RefBase {
CallbackDispatcher(OMXNodeInstance *owner);
void post(const omx_message &msg);
bool loop();
...
private:
OMXNodeInstance *mOwner;
bool mDone;
List mQueue;
sp mThread;
void dispatch(const omx_message &msg);
CallbackDispatcher(const CallbackDispatcher &);
CallbackDispatcher &operator=(const CallbackDispatcher &);
};
The message struct omx_message is defined in class IOMX as
struct omx_message {
enum {
EVENT,
EMPTY_BUFFER_DONE,
FILL_BUFFER_DONE,
} type;
IOMX::node_id node;
union {
// if type == EVENT
struct {
OMX_EVENTTYPE event;
OMX_U32 data1;
OMX_U32 data2;
} event_data;
// if type == EMPTY_BUFFER_DONE
struct {
IOMX::buffer_id buffer;
} buffer_data;
// if type == FILL_BUFFER_DONE
struct {
IOMX::buffer_id buffer;
OMX_U32 range_offset;
OMX_U32 range_length;
OMX_U32 flags;
OMX_TICKS timestamp;
OMX_PTR platform_private;
OMX_PTR data_ptr;
} extended_buffer_data;
} u;
};
At upper level, stagefright supplies a separate set of messaging data structures.
struct AHandler : public RefBase {
...
ALooper::handler_id id() const;
sp looper();
protected:
virtual void onMessageReceived(const sp &msg) = 0;
private:
friend struct ALooperRoster;
ALooper::handler_id mID;
void setID(ALooper::handler_id id);
};
struct ALooper : public RefBase {
typedef int32_t event_id;
typedef int32_t handler_id;
ALooper();
// Takes effect in a subsequent call to start().
void setName(const char *name);
handler_id registerHandler(const sp &handler);
void unregisterHandler(handler_id handlerID);
status_t start(
bool runOnCallingThread = false,
bool canCallJava = false,
int32_t priority = PRIORITY_DEFAULT
);
status_t stop();
private:
friend struct ALooperRoster;
struct Event {
int64_t mWhenUs;
sp mMessage;
};
AString mName;
List mEventQueue;
struct LooperThread;
sp mThread;
...
void post(const sp &msg, int64_t delayUs);
bool loop();
};
struct AMessage : public RefBase {
AMessage(uint32_t what = 0, ALooper::handler_id target = 0);
static sp FromParcel(const Parcel &parcel);
void writeToParcel(Parcel *parcel) const;
void setWhat(uint32_t what);
uint32_t what() const;
void setTarget(ALooper::handler_id target);
ALooper::handler_id target() const;
void setInt32(const char *name, int32_t value);
void setInt64(const char *name, int64_t value);
void setSize(const char *name, size_t value);
void setFloat(const char *name, float value);
void setDouble(const char *name, double value);
void setPointer(const char *name, void *value);
void setString(const char *name, const char *s, ssize_t len = -1);
void setObject(const char *name, const sp &obj);
void setBuffer(const char *name, const sp &buffer);
void setMessage(const char *name, const sp &obj);
void setRect(
const char *name,
int32_t left, int32_t top, int32_t right, int32_t bottom);
bool findInt32(const char *name, int32_t *value) const;
bool findInt64(const char *name, int64_t *value) const;
bool findSize(const char *name, size_t *value) const;
bool findFloat(const char *name, float *value) const;
bool findDouble(const char *name, double *value) const;
bool findPointer(const char *name, void **value) const;
bool findString(const char *name, AString *value) const;
bool findObject(const char *name, sp *obj) const;
bool findBuffer(const char *name, sp *buffer) const;
bool findMessage(const char *name, sp *obj) const;
bool findRect(
const char *name,
int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const;
void post(int64_t delayUs = 0);
// Posts the message to its target and waits for a response (or error)
// before returning.
status_t postAndAwaitResponse(sp *response);
// If this returns true, the sender of this message is synchronously
// awaiting a response, the “replyID” can be used to send the response
// via “postReply” below.
bool senderAwaitsResponse(uint32_t *replyID) const;
void postReply(uint32_t replyID);
enum Type {
kTypeInt32,
kTypeInt64,
kTypeSize,
kTypeFloat,
kTypeDouble,
kTypePointer,
kTypeString,
kTypeObject,
kTypeMessage,
kTypeRect,
kTypeBuffer,
};
size_t countEntries() const;
const char *getEntryNameAt(size_t index, Type *type) const;
private:
uint32_t mWhat;
ALooper::handler_id mTarget;
struct Rect {
int32_t mLeft, mTop, mRight, mBottom;
};
struct Item {
union {
int32_t int32Value;
int64_t int64Value;
size_t sizeValue;
float floatValue;
double doubleValue;
void *ptrValue;
RefBase *refValue;
AString *stringValue;
Rect rectValue;
} u;
const char *mName;
Type mType;
};
enum {
kMaxNumItems = 64
};
Item mItems[kMaxNumItems];
size_t mNumItems;
Item *allocateItem(const char *name);
void freeItem(Item *item);
const Item *findItem(const char *name, Type type) const;
void setObjectInternal(
const char *name, const sp &obj, Type type);
…
};
struct ALooperRoster {
...
ALooper::handler_id registerHandler(
const sp looper, const sp &handler);
void unregisterHandler(ALooper::handler_id handlerID);
status_t postMessage(const sp &msg, int64_t delayUs = 0);
void deliverMessage(const sp &msg);
status_t postAndAwaitResponse(
const sp &msg, sp *response);
void postReply(uint32_t replyID, const sp &reply);
sp findLooper(ALooper::handler_id handlerID);
private:
struct HandlerInfo {
wp mLooper;
wp mHandler;
};
Mutex mLock;
KeyedVector mHandlers;
ALooper::handler_id mNextHandlerID;
uint32_t mNextReplyID;
…
KeyedVector<uint32_t, sp > mReplies;
status_t postMessage_l(const sp &msg, int64_t delayUs);
};