Closed #1420: Add support for event manager

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@3893 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
Sauw Ming 2011-12-01 10:49:07 +00:00
parent 3d7385c7f9
commit 0fabe1bbb6
25 changed files with 549 additions and 462 deletions

View File

@ -750,19 +750,6 @@ PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_start(
PJ_DECL(pj_bool_t) pjmedia_vid_dev_stream_is_running(pjmedia_vid_dev_stream *strm);
/**
* Get the event publisher object for the video stream. Caller typically use
* the returned object to subscribe or unsubscribe events from the video
* stream.
*
* @param strm The video stream.
*
* @return The event publisher object.
*/
PJ_DECL(pjmedia_event_publisher*)
pjmedia_vid_dev_stream_get_event_publisher(pjmedia_vid_dev_stream *strm);
/**
* Request one frame from the stream. Application needs to call this function
* periodically only if the stream doesn't support "active interface", i.e.

View File

@ -188,9 +188,6 @@ struct pjmedia_vid_dev_stream
/** Operations */
pjmedia_vid_dev_stream_op *op;
/** Event producer */
pjmedia_event_publisher epub;
};

View File

@ -25,7 +25,6 @@
*/
#include <pjmedia/format.h>
#include <pjmedia/signatures.h>
#include <pj/list.h>
PJ_BEGIN_DECL
@ -87,16 +86,6 @@ typedef enum pjmedia_event_type
} pjmedia_event_type;
/**
* Forward declaration for event subscription.
*/
typedef struct pjmedia_event_subscription pjmedia_event_subscription;
/**
* Forward declaration for event publisher.
*/
typedef struct pjmedia_event_publisher pjmedia_event_publisher;
/**
* Additional data/parameters for media format changed event
* (PJMEDIA_EVENT_FMT_CHANGED).
@ -162,8 +151,8 @@ typedef char pjmedia_event_user_data[PJMEDIA_EVENT_DATA_MAX_SIZE];
/**
* This structure describes a media event. It consists mainly of the event
* type and additional data/parameters for the event. Event publishers need
* to use #pjmedia_event_init() to initialize this event structure with
* type and additional data/parameters for the event. Applications can
* use #pjmedia_event_init() to initialize this event structure with
* basic information about the event.
*/
typedef struct pjmedia_event
@ -178,28 +167,23 @@ typedef struct pjmedia_event
*/
pj_timestamp timestamp;
/**
* This keeps count on the number of subscribers that have
* processed this event.
*/
unsigned proc_cnt;
/**
* The object signature of the event publisher. Application may use
* this to check which publisher published the event.
*/
pjmedia_obj_sig epub_sig;
/**
* Pointer information about the source of this event. This field
* is provided mainly so that the event subscribers can compare it
* against the publisher that it subscribed the events from initially,
* a publisher can republish events from other publisher. Event
* subscription must be careful when using this pointer other than for
* comparison purpose, since access to the publisher may require special
* care (e.g. mutex locking).
* is provided mainly for comparison purpose so that event subscribers
* can check which source the event originated from. Usage of this
* pointer for other purpose may require special care such as mutex
* locking or checking whether the object is already destroyed.
*/
const pjmedia_event_publisher *epub;
const void *src;
/**
* Pointer information about the publisher of this event. This field
* is provided mainly for comparison purpose so that event subscribers
* can check which object published the event. Usage of this
* pointer for other purpose may require special care such as mutex
* locking or checking whether the object is already destroyed.
*/
const void *epub;
/**
* Additional data/parameters about the event. The type of data
@ -238,52 +222,92 @@ typedef struct pjmedia_event
} pjmedia_event;
/**
* The callback to receive media events. The callback should increase
* \a proc_cnt field of the event if it processes the event.
* The callback to receive media events.
*
* @param esub The subscription that was made initially to receive
* this event.
* @param event The media event itself.
* @param event The media event.
* @param user_data The user data associated with the callback.
*
* @return If the callback returns non-PJ_SUCCESS, this return
* code may be propagated back to the producer.
* code may be propagated back to the caller.
*/
typedef pj_status_t pjmedia_event_cb(pjmedia_event_subscription *esub,
pjmedia_event *event);
typedef pj_status_t pjmedia_event_cb(pjmedia_event *event,
void *user_data);
/**
* This structure keeps the data needed to maintain an event subscription.
* This data is normally kept by event publishers.
* This enumeration describes flags for event publication via
* #pjmedia_event_publish().
*/
struct pjmedia_event_subscription
typedef enum pjmedia_event_publish_flag
{
/** Standard list members */
PJ_DECL_LIST_MEMBER(pjmedia_event_subscription);
/**
* Publisher will only post the event to the event manager. It is the
* event manager that will later notify all the publisher's subscribers.
*/
PJMEDIA_EVENT_PUBLISH_POST_EVENT = 1
/** Callback that will be called by publisher to report events. */
pjmedia_event_cb *cb;
/** User data for this subscription */
void *user_data;
/** Current publisher it is subscribed to */
pjmedia_event_publisher *subscribe_to;
};
} pjmedia_event_publish_flag;
/**
* This describes an event publisher. An event publisher is an object that
* maintains event subscriptions. When an event is published on behalf of
* a publisher with #pjmedia_event_publish(), that event will be propagated
* to all of the subscribers registered to the publisher.
* Event manager flag.
*/
struct pjmedia_event_publisher
typedef enum pjmedia_event_mgr_flag
{
/** The object signature of the publisher */
pjmedia_obj_sig sig;
/**
* Tell the event manager not to create any event worker thread.
*/
PJMEDIA_EVENT_MGR_NO_THREAD = 1
/** List of subscriptions for this event publisher */
pjmedia_event_subscription subscription_list;
};
} pjmedia_event_mgr_flag;
/**
* Opaque data type for event manager. Typically, the event manager
* is a singleton instance, although application may instantiate more than one
* instances of this if required.
*/
typedef struct pjmedia_event_mgr pjmedia_event_mgr;
/**
* Create a new event manager instance. This will also set the pointer
* to the singleton instance if the value is still NULL.
*
* @param pool Pool to allocate memory from.
* @param options Options. Bitmask flags from #pjmedia_event_mgr_flag
* @param mgr Pointer to hold the created instance of the
* event manager.
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
PJ_DECL(pj_status_t) pjmedia_event_mgr_create(pj_pool_t *pool,
unsigned options,
pjmedia_event_mgr **mgr);
/**
* Get the singleton instance of the event manager.
*
* @return The instance.
*/
PJ_DECL(pjmedia_event_mgr*) pjmedia_event_mgr_instance(void);
/**
* Manually assign a specific event manager instance as the singleton
* instance. Normally this is not needed if only one instance is ever
* going to be created, as the library automatically assign the singleton
* instance.
*
* @param mgr The instance to be used as the singleton instance.
* Application may specify NULL to clear the singleton
* singleton instance.
*/
PJ_DECL(void) pjmedia_event_mgr_set_instance(pjmedia_event_mgr *mgr);
/**
* Destroy an event manager. If the manager happens to be the singleton
* instance, the singleton instance will be set to NULL.
*
* @param mgr The eventmanager. Specify NULL to use
* the singleton instance.
*/
PJ_DECL(void) pjmedia_event_mgr_destroy(pjmedia_event_mgr *mgr);
/**
* Initialize event structure with basic data about the event.
@ -292,110 +316,76 @@ struct pjmedia_event_publisher
* @param type The event type to be set for this event.
* @param ts Event timestamp. May be set to NULL to set the event
* timestamp to zero.
* @param epub Event publisher.
* @param src Event source.
*/
PJ_DECL(void) pjmedia_event_init(pjmedia_event *event,
pjmedia_event_type type,
const pj_timestamp *ts,
const pjmedia_event_publisher *epub);
const void *src);
/**
* Initialize an event publisher structure.
*
* @param epub The event publisher.
* @param sig The object signature of the publisher.
*/
PJ_DECL(void) pjmedia_event_publisher_init(pjmedia_event_publisher *epub,
pjmedia_obj_sig sig);
/**
* Initialize subscription data.
*
* @param esub The event subscription.
* @param cb The callback to receive events.
* @param user_data Arbitrary user data to be associated with the
* subscription.
*/
PJ_DECL(void) pjmedia_event_subscription_init(pjmedia_event_subscription *esub,
pjmedia_event_cb *cb,
void *user_data);
/**
* Subscribe to events published by the specified publisher using the
* specified subscription object. The callback and user data fields of
* the subscription object must have been initialized prior to calling
* this function, and the subscription object must be kept alive throughout
* the duration of the subscription (e.g. it must not be allocated from
* the stack).
*
* Note that the subscriber may receive not only events emitted by
* Subscribe a callback function to events published by the specified
* publisher. Note that the subscriber may receive not only events emitted by
* the specific publisher specified in the argument, but also from other
* publishers contained by the publisher, if the publisher is republishing
* events from other publishers.
*
* @param mgr The event manager.
* @param pool Pool to allocate memory from.
* @param cb The callback function to receive the event.
* @param user_data The user data to be associated with the callback
* function.
* @param epub The event publisher.
* @param esub The event subscription object.
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
PJ_DECL(pj_status_t) pjmedia_event_subscribe(pjmedia_event_publisher *epub,
pjmedia_event_subscription *esub);
PJ_DECL(pj_status_t) pjmedia_event_subscribe(pjmedia_event_mgr *mgr,
pj_pool_t *pool,
pjmedia_event_cb *cb,
void *user_data,
void *epub);
/**
* Unsubscribe the specified subscription object from publisher it is
* currently subscribed to. If the subscription object is not currently
* subscribed to anything, the function will do nothing.
* Unsubscribe the callback associated with the user data from a publisher.
* If the user data is not specified, this function will do the
* unsubscription for all user data. If the publisher, epub, is not
* specified, this function will do the unsubscription from all publishers.
*
* @param esub The event subscription object, which must be the same
* object that was given to #pjmedia_event_subscribe().
* @param mgr The event manager.
* @param cb The callback function.
* @param user_data The user data associated with the callback
* function, can be NULL.
* @param epub The event publisher, can be NULL.
*
* @return PJ_SUCCESS on success or the appropriate error code.
*/
PJ_DECL(pj_status_t)
pjmedia_event_unsubscribe(pjmedia_event_subscription *esub);
/**
* Check if the specified publisher has subscribers.
*
* @param epub The event publisher.
*
* @return PJ_TRUE if the publisher has at least one subscriber.
*/
PJ_DECL(pj_bool_t)
pjmedia_event_publisher_has_sub(pjmedia_event_publisher *epub);
pjmedia_event_unsubscribe(pjmedia_event_mgr *mgr,
pjmedia_event_cb *cb,
void *user_data,
void *epub);
/**
* Publish the specified event to all subscribers of the specified event
* publisher.
* publisher. By default, the function will call all the subcribers'
* callbacks immediately. If the publisher uses the flag
* PJMEDIA_EVENT_PUBLISH_POST_EVENT, publisher will only post the event
* to the event manager and return immediately. It is the event manager
* that will later notify all the publisher's subscribers.
*
* @param mgr The event manager.
* @param epub The event publisher.
* @param event The event to be published.
* @param flag Publication flag.
*
* @return PJ_SUCCESS only if all subscription callbacks returned
* PJ_SUCCESS.
*/
PJ_DECL(pj_status_t) pjmedia_event_publish(pjmedia_event_publisher *epub,
pjmedia_event *event);
PJ_DECL(pj_status_t) pjmedia_event_publish(pjmedia_event_mgr *mgr,
void *epub,
pjmedia_event *event,
pjmedia_event_publish_flag flag);
/**
* Subscribe to events produced by the source publisher in \a esrc and
* republish the events to all subscribers in \a epub publisher.
*
* @param esrc The event source from which events will be
* republished.
* @param epub Events from the event source above will be
* republished to subscribers of this publisher.
* @param esub The subscription object to be used to subscribe
* to \a esrc. This doesn't need to be initialized,
* but it must be kept alive throughout the lifetime
* of the subsciption.
*
* @return PJ_SUCCESS only if all subscription callbacks returned
* PJ_SUCCESS.
*/
PJ_DECL(pj_status_t) pjmedia_event_republish(pjmedia_event_publisher *esrc,
pjmedia_event_publisher *epub,
pjmedia_event_subscription *esub);
/**
* @} PJMEDIA_EVENT

View File

@ -399,11 +399,6 @@ typedef struct pjmedia_port
*/
pj_status_t (*on_destroy)(struct pjmedia_port *this_port);
/**
* Get event publisher for this media port, if any.
*/
pjmedia_event_publisher *(*get_event_pub)(struct pjmedia_port *this_port);
} pjmedia_port;
@ -483,17 +478,6 @@ PJ_DECL(pj_status_t) pjmedia_port_get_frame( pjmedia_port *port,
PJ_DECL(pj_status_t) pjmedia_port_put_frame( pjmedia_port *port,
pjmedia_frame *frame );
/**
* Get the event publisher for the media port, if any.
*
* @param port The media port.
*
* @return The event publisher, or NULL if the port does not publish
* events.
*/
PJ_DECL(pjmedia_event_publisher*)
pjmedia_port_get_event_publisher(pjmedia_port *port);
/**
* Destroy port (and subsequent downstream ports)
*

View File

@ -249,9 +249,6 @@ struct pjmedia_vid_codec
/** Operations to codec. */
pjmedia_vid_codec_op *op;
/** Event publisher object */
pjmedia_event_publisher epub;
};

View File

@ -104,16 +104,6 @@ PJ_DECL(void) pjmedia_vid_port_set_cb(pjmedia_vid_port *vid_port,
const pjmedia_vid_dev_cb *cb,
void *user_data);
/**
* Get the event publisher instance of the video port.
*
* @param vid_port The video port.
*
* @return The event publisher of the video port.
*/
PJ_DECL(pjmedia_event_publisher*)
pjmedia_vid_port_get_event_publisher(pjmedia_vid_port *vid_port);
/**
* Return the underlying video stream of the video port.
*

View File

@ -1609,15 +1609,15 @@ static pj_status_t ffmpeg_codec_decode_whole(pjmedia_vid_codec *codec,
}
/* Broadcast event */
if (pjmedia_event_publisher_has_sub(&codec->epub)) {
{
pjmedia_event event;
pjmedia_event_init(&event, PJMEDIA_EVENT_FMT_CHANGED,
&input->timestamp, &codec->epub);
&input->timestamp, codec);
event.data.fmt_changed.dir = PJMEDIA_DIR_DECODING;
pj_memcpy(&event.data.fmt_changed.new_fmt, &ff->param.dec_fmt,
sizeof(ff->param.dec_fmt));
pjmedia_event_publish(&codec->epub, &event);
pjmedia_event_publish(NULL, codec, &event, 0);
}
}
@ -1651,13 +1651,13 @@ static pj_status_t ffmpeg_codec_decode_whole(pjmedia_vid_codec *codec,
output->size = vafp->framebytes;
/* Check if we got key frame */
if (avframe.key_frame && pjmedia_event_publisher_has_sub(&codec->epub))
if (avframe.key_frame)
{
pjmedia_event event;
pjmedia_event_init(&event, PJMEDIA_EVENT_KEY_FRAME_FOUND,
&output->timestamp, &codec->epub);
pjmedia_event_publish(&codec->epub, &event);
&output->timestamp, codec);
pjmedia_event_publish(NULL, codec, &event, 0);
}
} else {
output->type = PJMEDIA_FRAME_TYPE_NONE;

View File

@ -416,7 +416,6 @@ static pj_status_t cbar_factory_create_stream(
strm->cbfi = cbfi;
pj_memcpy(&strm->vafp, &vafp, sizeof(vafp));
strm->ts_inc = PJMEDIA_SPF2(param->clock_rate, &vfd->fps, 1);
pjmedia_event_publisher_init(&strm->base.epub, PJMEDIA_SIG_VID_DEV_COLORBAR);
for (i = 0; i < vfi->plane_cnt; ++i) {
strm->first_line[i] = pj_pool_alloc(pool, vafp.strides[i]);

View File

@ -869,7 +869,6 @@ static pj_status_t dshow_factory_create_stream(
strm->pool = pool;
pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
strm->user_data = user_data;
pjmedia_event_publisher_init(&strm->base.epub, PJMEDIA_SIG_VID_DEV_DSHOW);
if (param->dir & PJMEDIA_DIR_CAPTURE) {
const pjmedia_video_format_detail *vfd;

View File

@ -383,7 +383,6 @@ static pj_status_t ffmpeg_factory_create_stream(
strm->factory = (ffmpeg_factory*)f;
strm->pool = pool;
pj_memcpy(&strm->param, param, sizeof(*param));
pjmedia_event_publisher_init(&strm->base.epub);
/* Done */
strm->base.op = &stream_op;

View File

@ -308,7 +308,7 @@ static struct sdl_stream* find_stream(struct sdl_factory *sf,
if (strm)
pjmedia_event_init(pevent, PJMEDIA_EVENT_NONE, &strm->last_ts,
&strm->base.epub);
strm);
return strm;
}
@ -354,7 +354,7 @@ static pj_status_t handle_event(void *data)
if (strm && pevent.type != PJMEDIA_EVENT_NONE) {
pj_status_t status;
pjmedia_event_publish(&strm->base.epub, &pevent);
pjmedia_event_publish(NULL, strm, &pevent, 0);
switch (pevent.type) {
case PJMEDIA_EVENT_WND_RESIZED:
@ -375,9 +375,8 @@ static pj_status_t handle_event(void *data)
sdl_stream_stop(&strm->base);
sdl_destroy_all(strm);
pjmedia_event_init(&pevent, PJMEDIA_EVENT_WND_CLOSED,
&strm->last_ts,
&strm->base.epub);
pjmedia_event_publish(&strm->base.epub, &pevent);
&strm->last_ts, strm);
pjmedia_event_publish(NULL, strm, &pevent, 0);
/*
* Note: don't access the stream after this point, it
@ -916,7 +915,6 @@ static pj_status_t sdl_factory_create_stream(
strm->sf = sf;
pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
strm->user_data = user_data;
pjmedia_event_publisher_init(&strm->base.epub, PJMEDIA_SIG_VID_DEV_SDL);
/* Create render stream here */
if (param->dir & PJMEDIA_DIR_RENDER) {

View File

@ -785,12 +785,6 @@ PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_set_cap(
return strm->op->set_cap(strm, cap, value);
}
PJ_DEF(pjmedia_event_publisher*)
pjmedia_vid_dev_stream_get_event_publisher(pjmedia_vid_dev_stream *strm)
{
return &strm->epub;
}
/* API: Start the stream. */
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_start(pjmedia_vid_dev_stream *strm)
{

View File

@ -19,150 +19,342 @@
#include <pjmedia/event.h>
#include <pjmedia/errno.h>
#include <pj/assert.h>
#include <pj/list.h>
#include <pj/log.h>
#include <pj/os.h>
#include <pj/pool.h>
#include <pj/string.h>
#define THIS_FILE "event.c"
#if 1
# define TRACE_(x) PJ_LOG(6,x)
#else
# define TRACE_(x)
#endif
#define MAX_EVENTS 16
typedef struct esub esub;
struct esub
{
PJ_DECL_LIST_MEMBER(esub);
pjmedia_event_cb *cb;
void *user_data;
void *epub;
};
typedef struct event_queue
{
pjmedia_event events[MAX_EVENTS]; /**< array of events. */
int head, tail;
pj_bool_t is_full;
} event_queue;
struct pjmedia_event_mgr
{
pj_thread_t *thread; /**< worker thread. */
pj_bool_t is_quitting;
pj_sem_t *sem;
pj_mutex_t *mutex;
event_queue ev_queue;
event_queue *pub_ev_queue; /**< publish() event queue. */
esub esub_list; /**< list of subscribers. */
esub *th_next_sub, /**< worker thread's next sub. */
*pub_next_sub; /**< publish() next sub. */
};
static pjmedia_event_mgr *event_manager_instance;
static pj_status_t event_queue_add_event(event_queue* ev_queue,
pjmedia_event *event)
{
if (ev_queue->is_full) {
char ev_name[5];
/* This event will be ignored. */
PJ_LOG(4, (THIS_FILE, "Lost event %s from publisher [0x%p] "
"due to full queue.",
pjmedia_fourcc_name(event->type, ev_name),
event->epub));
return PJ_ETOOMANY;
}
pj_memcpy(&ev_queue->events[ev_queue->tail], event, sizeof(*event));
ev_queue->tail = (ev_queue->tail + 1) % MAX_EVENTS;
if (ev_queue->tail == ev_queue->head)
ev_queue->is_full = PJ_TRUE;
return PJ_SUCCESS;
}
static pj_status_t event_mgr_distribute_events(pjmedia_event_mgr *mgr,
event_queue *ev_queue,
esub **next_sub)
{
pj_status_t err = PJ_SUCCESS;
esub * sub = mgr->esub_list.next;
pjmedia_event *ev = &ev_queue->events[ev_queue->head];
while (sub != &mgr->esub_list) {
*next_sub = sub->next;
/* Check if the subscriber is interested in
* receiving the event from the publisher.
*/
if (sub->epub == ev->epub || !sub->epub) {
pj_status_t status = (*sub->cb)(ev, sub->user_data);
if (status != PJ_SUCCESS && err == PJ_SUCCESS)
err = status;
}
sub = *next_sub;
}
*next_sub = NULL;
ev_queue->head = (ev_queue->head + 1) % MAX_EVENTS;
ev_queue->is_full = PJ_FALSE;
return err;
}
/* Event worker thread function. */
static int event_worker_thread(void *arg)
{
pjmedia_event_mgr *mgr = (pjmedia_event_mgr *)arg;
while (1) {
/* Wait until there is an event. */
pj_sem_wait(mgr->sem);
if (mgr->is_quitting)
break;
pj_mutex_lock(mgr->mutex);
event_mgr_distribute_events(mgr, &mgr->ev_queue, &mgr->th_next_sub);
pj_mutex_unlock(mgr->mutex);
}
return 0;
}
PJ_DEF(pj_status_t) pjmedia_event_mgr_create(pj_pool_t *pool,
unsigned options,
pjmedia_event_mgr **p_mgr)
{
pjmedia_event_mgr *mgr;
pj_status_t status;
mgr = PJ_POOL_ZALLOC_T(pool, pjmedia_event_mgr);
pj_list_init(&mgr->esub_list);
if (!(options & PJMEDIA_EVENT_MGR_NO_THREAD)) {
status = pj_sem_create(pool, "ev_sem", 0, MAX_EVENTS + 1, &mgr->sem);
if (status != PJ_SUCCESS)
return status;
status = pj_thread_create(pool, "ev_thread", &event_worker_thread,
mgr, 0, 0, &mgr->thread);
if (status != PJ_SUCCESS) {
pjmedia_event_mgr_destroy(mgr);
return status;
}
}
status = pj_mutex_create_recursive(pool, "ev_mutex", &mgr->mutex);
if (status != PJ_SUCCESS) {
pjmedia_event_mgr_destroy(mgr);
return status;
}
if (!event_manager_instance)
event_manager_instance = mgr;
if (p_mgr)
*p_mgr = mgr;
return PJ_SUCCESS;
}
PJ_DEF(pjmedia_event_mgr*) pjmedia_event_mgr_instance(void)
{
return event_manager_instance;
}
PJ_DEF(void) pjmedia_event_mgr_set_instance(pjmedia_event_mgr *mgr)
{
event_manager_instance = mgr;
}
PJ_DEF(void) pjmedia_event_mgr_destroy(pjmedia_event_mgr *mgr)
{
esub *sub;
if (!mgr) mgr = pjmedia_event_mgr_instance();
PJ_ASSERT_ON_FAIL(mgr != NULL, return);
if (mgr->thread) {
mgr->is_quitting = PJ_TRUE;
pj_sem_post(mgr->sem);
pj_thread_join(mgr->thread);
}
if (mgr->sem) {
pj_sem_destroy(mgr->sem);
mgr->sem = NULL;
}
if (mgr->mutex) {
pj_mutex_destroy(mgr->mutex);
mgr->mutex = NULL;
}
sub = mgr->esub_list.next;
while (sub != &mgr->esub_list) {
esub *next = sub->next;
pj_list_erase(sub);
sub = next;
}
if (event_manager_instance == mgr)
event_manager_instance = NULL;
}
PJ_DEF(void) pjmedia_event_init( pjmedia_event *event,
pjmedia_event_type type,
const pj_timestamp *ts,
const pjmedia_event_publisher *epub)
const void *src)
{
pj_bzero(event, sizeof(*event));
event->type = type;
if (ts)
event->timestamp.u64 = ts->u64;
event->epub = epub;
if (epub)
event->epub_sig = epub->sig;
event->epub = event->src = src;
}
PJ_DEF(void) pjmedia_event_publisher_init(pjmedia_event_publisher *epub,
pjmedia_obj_sig sig)
PJ_DEF(pj_status_t) pjmedia_event_subscribe( pjmedia_event_mgr *mgr,
pj_pool_t *pool,
pjmedia_event_cb *cb,
void *user_data,
void *epub)
{
pj_bzero(epub, sizeof(*epub));
pj_list_init(&epub->subscription_list);
epub->sig = sig;
}
esub *sub;
PJ_DEF(void) pjmedia_event_subscription_init( pjmedia_event_subscription *esub,
pjmedia_event_cb *cb,
void *user_data)
{
pj_bzero(esub, sizeof(*esub));
esub->cb = cb;
esub->user_data = user_data;
}
PJ_ASSERT_RETURN(pool && cb, PJ_EINVAL);
PJ_DEF(pj_bool_t)
pjmedia_event_publisher_has_sub(pjmedia_event_publisher *epub)
{
PJ_ASSERT_RETURN(epub, PJ_FALSE);
return epub->subscription_list.next &&
(!pj_list_empty(&epub->subscription_list));
}
if (!mgr) mgr = pjmedia_event_mgr_instance();
PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
PJ_DEF(pj_status_t) pjmedia_event_subscribe( pjmedia_event_publisher *epub,
pjmedia_event_subscription *esub)
{
char epub_name[5];
PJ_ASSERT_RETURN(epub && esub && esub->cb, PJ_EINVAL);
/* Must not currently subscribe to anything */
PJ_ASSERT_RETURN(esub->subscribe_to == NULL, PJ_EINVALIDOP);
TRACE_((THIS_FILE, "Subscription [0x%p] to publisher %s",
esub,
pjmedia_fourcc_name(epub->sig, epub_name)));
/* Suppress compiler warning if trace is disabled */
PJ_UNUSED_ARG(epub_name);
pj_list_push_back(&epub->subscription_list, esub);
esub->subscribe_to = epub;
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjmedia_event_unsubscribe(pjmedia_event_subscription *esub)
{
PJ_ASSERT_RETURN(esub, PJ_EINVAL);
if (esub->subscribe_to) {
char epub_name[5];
TRACE_((THIS_FILE, "Unsubscription [0x%p] to publisher %s",
esub,
pjmedia_fourcc_name(esub->subscribe_to->sig,
epub_name)));
/* Suppress compiler warning if trace is disabled */
PJ_UNUSED_ARG(epub_name);
PJ_ASSERT_RETURN(
pj_list_find_node(&esub->subscribe_to->subscription_list,
esub)==esub, PJ_ENOTFOUND);
pj_list_erase(esub);
esub->subscribe_to = NULL;
pj_mutex_lock(mgr->mutex);
/* Check whether callback function with the same user data is already
* subscribed to the publisher. This is to prevent the callback function
* receiving the same event from the same publisher more than once.
*/
sub = mgr->esub_list.next;
while (sub != &mgr->esub_list) {
esub *next = sub->next;
if (sub->cb == cb && sub->user_data == user_data &&
sub->epub == epub)
{
pj_mutex_unlock(mgr->mutex);
return PJ_SUCCESS;
}
sub = next;
}
sub = PJ_POOL_ZALLOC_T(pool, esub);
sub->cb = cb;
sub->user_data = user_data;
sub->epub = epub;
pj_list_push_back(&mgr->esub_list, sub);
pj_mutex_unlock(mgr->mutex);
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjmedia_event_publish( pjmedia_event_publisher *epub,
pjmedia_event *event)
PJ_DEF(pj_status_t)
pjmedia_event_unsubscribe(pjmedia_event_mgr *mgr,
pjmedia_event_cb *cb,
void *user_data,
void *epub)
{
esub *sub;
PJ_ASSERT_RETURN(cb, PJ_EINVAL);
if (!mgr) mgr = pjmedia_event_mgr_instance();
PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
pj_mutex_lock(mgr->mutex);
sub = mgr->esub_list.next;
while (sub != &mgr->esub_list) {
esub *next = sub->next;
if (sub->cb == cb && (sub->user_data == user_data || !user_data) &&
(sub->epub == epub || !epub))
{
/* If the worker thread or pjmedia_event_publish() API is
* in the process of distributing events, make sure that
* its pointer to the next subscriber stays valid.
*/
if (mgr->th_next_sub == sub)
mgr->th_next_sub = sub->next;
if (mgr->pub_next_sub == sub)
mgr->pub_next_sub = sub->next;
pj_list_erase(sub);
if (user_data && epub)
break;
}
sub = next;
}
pj_mutex_unlock(mgr->mutex);
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjmedia_event_publish( pjmedia_event_mgr *mgr,
void *epub,
pjmedia_event *event,
pjmedia_event_publish_flag flag)
{
pjmedia_event_subscription *esub;
char event_name[5];
char epub_name[5];
pj_status_t err = PJ_SUCCESS;
PJ_ASSERT_RETURN(epub && event, PJ_EINVAL);
TRACE_((THIS_FILE, "Event %s is published by publisher %s",
pjmedia_fourcc_name(event->type, event_name),
pjmedia_fourcc_name(epub->sig, epub_name)));
/* Suppress compiler warning if trace is disabled */
PJ_UNUSED_ARG(event_name);
PJ_UNUSED_ARG(epub_name);
if (!mgr) mgr = pjmedia_event_mgr_instance();
PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
esub = epub->subscription_list.next;
if (!esub)
return err;
event->epub = epub;
while (esub != &epub->subscription_list) {
pjmedia_event_subscription *next;
pj_status_t status;
pj_mutex_lock(mgr->mutex);
if (flag & PJMEDIA_EVENT_PUBLISH_POST_EVENT) {
if (event_queue_add_event(&mgr->ev_queue, event) == PJ_SUCCESS)
pj_sem_post(mgr->sem);
} else {
/* For nested pjmedia_event_publish() calls, i.e. calling publish()
* inside the subscriber's callback, the function will only add
* the event to the event queue of the first publish() call. It
* is the first publish() call that will be responsible to
* distribute the events.
*/
if (mgr->pub_ev_queue) {
event_queue_add_event(mgr->pub_ev_queue, event);
} else {
static event_queue ev_queue;
pj_status_t status;
/* just in case esub is destroyed in the callback */
next = esub->next;
ev_queue.head = ev_queue.tail = 0;
ev_queue.is_full = PJ_FALSE;
mgr->pub_ev_queue = &ev_queue;
status = (*esub->cb)(esub, event);
if (status != PJ_SUCCESS && err == PJ_SUCCESS)
err = status;
event_queue_add_event(mgr->pub_ev_queue, event);
esub = next;
do {
status = event_mgr_distribute_events(mgr, mgr->pub_ev_queue,
&mgr->pub_next_sub);
if (status != PJ_SUCCESS && err == PJ_SUCCESS)
err = status;
} while(ev_queue.head != ev_queue.tail || ev_queue.is_full);
mgr->pub_ev_queue = NULL;
}
}
pj_mutex_unlock(mgr->mutex);
return err;
}
static pj_status_t republisher_cb(pjmedia_event_subscription *esub,
pjmedia_event *event)
{
return pjmedia_event_publish((pjmedia_event_publisher*)esub->user_data,
event);
}
PJ_DEF(pj_status_t) pjmedia_event_republish(pjmedia_event_publisher *esrc,
pjmedia_event_publisher *epub,
pjmedia_event_subscription *esub)
{
PJ_ASSERT_RETURN(esrc && epub && esub, PJ_EINVAL);
pjmedia_event_subscription_init(esub, &republisher_cb, epub);
return pjmedia_event_subscribe(esrc, esub);
}

View File

@ -117,20 +117,6 @@ PJ_DEF(pj_status_t) pjmedia_port_put_frame( pjmedia_port *port,
return PJ_EINVALIDOP;
}
/*
* Get event publisher
*/
PJ_DEF(pjmedia_event_publisher*)
pjmedia_port_get_event_publisher(pjmedia_port *port)
{
PJ_ASSERT_RETURN(port, NULL);
if (port->get_event_pub)
return (*port->get_event_pub)(port);
return NULL;
}
/**
* Destroy port (and subsequent downstream ports)
*/

View File

@ -77,7 +77,6 @@ PJ_DEF(void) pjmedia_vid_codec_reset(pjmedia_vid_codec *codec,
pjmedia_obj_sig sig)
{
pj_bzero(codec, sizeof(*codec));
pjmedia_event_publisher_init(&codec->epub, sig);
}
/*

View File

@ -61,10 +61,6 @@ struct pjmedia_vid_port
pj_size_t conv_buf_size;
pjmedia_conversion_param conv_param;
pjmedia_event_publisher epub;
pjmedia_event_subscription esub_dev;
pjmedia_event_subscription esub_client_port;
pjmedia_clock *clock;
pjmedia_clock_src clocksrc;
@ -94,10 +90,10 @@ static pj_status_t vidstream_cap_cb(pjmedia_vid_dev_stream *stream,
static pj_status_t vidstream_render_cb(pjmedia_vid_dev_stream *stream,
void *user_data,
pjmedia_frame *frame);
static pj_status_t vidstream_event_cb(pjmedia_event_subscription *esub,
pjmedia_event *event);
static pj_status_t client_port_event_cb(pjmedia_event_subscription *esub,
pjmedia_event *event);
static pj_status_t vidstream_event_cb(pjmedia_event *event,
void *user_data);
static pj_status_t client_port_event_cb(pjmedia_event *event,
void *user_data);
static void enc_clock_cb(const pj_timestamp *ts, void *user_data);
static void dec_clock_cb(const pj_timestamp *ts, void *user_data);
@ -206,7 +202,6 @@ PJ_DEF(pj_status_t) pjmedia_vid_port_create( pj_pool_t *pool,
vp->role = prm->active ? ROLE_ACTIVE : ROLE_PASSIVE;
vp->dir = prm->vidparam.dir;
// vp->cap_size = vfd->size;
pjmedia_event_publisher_init(&vp->epub, SIGNATURE);
vparam = prm->vidparam;
dev_name[0] = '\0';
@ -272,10 +267,8 @@ PJ_DEF(pj_status_t) pjmedia_vid_port_create( pj_pool_t *pool,
vparam.fmt.det.vid.fps.num, vparam.fmt.det.vid.fps.denum));
/* Subscribe to device's events */
pjmedia_event_subscription_init(&vp->esub_dev, vidstream_event_cb, vp);
pjmedia_event_subscribe(
pjmedia_vid_dev_stream_get_event_publisher(vp->strm),
&vp->esub_dev);
pjmedia_event_subscribe(NULL, vp->pool, &vidstream_event_cb,
vp, vp->strm);
if (vp->dir & PJMEDIA_DIR_CAPTURE) {
pjmedia_format_copy(&vp->conv_param.src, &vparam.fmt);
@ -370,13 +363,6 @@ PJ_DEF(void) pjmedia_vid_port_set_cb(pjmedia_vid_port *vid_port,
vid_port->strm_cb_data = user_data;
}
PJ_DEF(pjmedia_event_publisher*)
pjmedia_vid_port_get_event_publisher(pjmedia_vid_port *vid_port)
{
PJ_ASSERT_RETURN(vid_port, NULL);
return &vid_port->epub;
}
PJ_DEF(pjmedia_vid_dev_stream*)
pjmedia_vid_port_get_stream(pjmedia_vid_port *vp)
{
@ -419,20 +405,14 @@ PJ_DEF(pj_status_t) pjmedia_vid_port_connect(pjmedia_vid_port *vp,
pjmedia_port *port,
pj_bool_t destroy)
{
pjmedia_event_publisher *epub;
PJ_ASSERT_RETURN(vp && vp->role==ROLE_ACTIVE, PJ_EINVAL);
vp->destroy_client_port = destroy;
vp->client_port = port;
/* Subscribe to client port's events */
epub = pjmedia_port_get_event_publisher(port);
if (epub) {
pjmedia_event_subscription_init(&vp->esub_client_port,
&client_port_event_cb,
vp);
pjmedia_event_subscribe(epub, &vp->esub_client_port);
}
pjmedia_event_subscribe(NULL, vp->pool, &client_port_event_cb, vp,
vp->client_port);
return PJ_SUCCESS;
}
@ -441,10 +421,10 @@ PJ_DEF(pj_status_t) pjmedia_vid_port_disconnect(pjmedia_vid_port *vp)
{
PJ_ASSERT_RETURN(vp && vp->role==ROLE_ACTIVE, PJ_EINVAL);
if (vp->client_port) {
pjmedia_event_unsubscribe(&vp->esub_client_port);
vp->client_port = NULL;
}
pjmedia_event_unsubscribe(NULL, &client_port_event_cb, vp,
vp->client_port);
vp->client_port = NULL;
return PJ_SUCCESS;
}
@ -510,10 +490,13 @@ PJ_DEF(void) pjmedia_vid_port_destroy(pjmedia_vid_port *vp)
vp->clock = NULL;
}
if (vp->strm) {
pjmedia_event_unsubscribe(NULL, &vidstream_event_cb, vp, vp->strm);
pjmedia_vid_dev_stream_destroy(vp->strm);
vp->strm = NULL;
}
if (vp->client_port) {
pjmedia_event_unsubscribe(NULL, &client_port_event_cb, vp,
vp->client_port);
if (vp->destroy_client_port)
pjmedia_port_destroy(vp->client_port);
vp->client_port = NULL;
@ -560,26 +543,24 @@ static void save_rgb_frame(int width, int height, const pjmedia_frame *frm)
*/
/* Handle event from vidstream */
static pj_status_t vidstream_event_cb(pjmedia_event_subscription *esub,
pjmedia_event *event)
static pj_status_t vidstream_event_cb(pjmedia_event *event,
void *user_data)
{
pjmedia_vid_port *vp = (pjmedia_vid_port*)esub->user_data;
pjmedia_vid_port *vp = (pjmedia_vid_port*)user_data;
/* Just republish the event to our client */
return pjmedia_event_publish(&vp->epub, event);
return pjmedia_event_publish(NULL, vp, event, 0);
}
static pj_status_t client_port_event_cb(pjmedia_event_subscription *esub,
pjmedia_event *event)
static pj_status_t client_port_event_cb(pjmedia_event *event,
void *user_data)
{
pjmedia_vid_port *vp = (pjmedia_vid_port*)esub->user_data;
pjmedia_vid_port *vp = (pjmedia_vid_port*)user_data;
if (event->type == PJMEDIA_EVENT_FMT_CHANGED) {
const pjmedia_video_format_detail *vfd;
pj_status_t status;
++event->proc_cnt;
pjmedia_vid_port_stop(vp);
/* Retrieve the video format detail */
@ -633,8 +614,11 @@ static pj_status_t client_port_event_cb(pjmedia_event_subscription *esub,
pjmedia_vid_port_start(vp);
}
/* Republish the event */
return pjmedia_event_publish(&vp->epub, event);
/* Republish the event, post the event to the event manager
* to avoid deadlock if vidport is trying to stop the clock.
*/
return pjmedia_event_publish(NULL, vp, event,
PJMEDIA_EVENT_PUBLISH_POST_EVENT);
}
static pj_status_t convert_frame(pjmedia_vid_port *vp,

View File

@ -147,9 +147,6 @@ struct pjmedia_vid_stream
pjmedia_vid_codec *codec; /**< Codec instance being used. */
pj_uint32_t last_dec_ts; /**< Last decoded timestamp. */
int last_dec_seq; /**< Last decoded sequence. */
pjmedia_event_subscription esub_codec; /**< To subscribe codec events */
pjmedia_event_publisher epub; /**< To publish events */
};
/* Prototypes */
@ -339,18 +336,15 @@ static void dump_port_info(const pjmedia_vid_channel *chan,
/*
* Handle events from stream components.
*/
static pj_status_t stream_event_cb(pjmedia_event_subscription *esub,
pjmedia_event *event)
static pj_status_t stream_event_cb(pjmedia_event *event,
void *user_data)
{
pjmedia_vid_stream *stream = (pjmedia_vid_stream*)esub->user_data;
pjmedia_vid_stream *stream = (pjmedia_vid_stream*)user_data;
if (esub == &stream->esub_codec) {
if (event->epub == stream->codec) {
/* This is codec event */
switch (event->type) {
case PJMEDIA_EVENT_FMT_CHANGED:
/* we process the event */
++event->proc_cnt;
/* Copy the event to avoid deadlock if we publish the event
* now. This happens because fmt_event may trigger restart
* while we're still holding the jb_mutex.
@ -362,13 +356,7 @@ static pj_status_t stream_event_cb(pjmedia_event_subscription *esub,
}
}
return pjmedia_event_publish(&stream->epub, event);
}
static pjmedia_event_publisher *port_get_epub(pjmedia_port *port)
{
pjmedia_vid_stream *stream = (pjmedia_vid_stream*) port->port_data.pdata;
return &stream->epub;
return pjmedia_event_publish(NULL, stream, event, 0);
}
#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA != 0
@ -1031,18 +1019,18 @@ static pj_status_t decode_frame(pjmedia_vid_stream *stream,
vfd->fps.num / vfd->fps.denum));
/* Publish PJMEDIA_EVENT_FMT_CHANGED event */
if (pjmedia_event_publisher_has_sub(&stream->epub)) {
{
pjmedia_event event;
dump_port_info(stream->dec, "changed");
pjmedia_event_init(&event, PJMEDIA_EVENT_FMT_CHANGED,
&frame->timestamp, &stream->epub);
&frame->timestamp, &stream);
event.data.fmt_changed.dir = PJMEDIA_DIR_DECODING;
pj_memcpy(&event.data.fmt_changed.new_fmt,
&stream->info.codec_param->dec_fmt,
sizeof(pjmedia_format));
pjmedia_event_publish(&stream->epub, &event);
pjmedia_event_publish(NULL, stream, &event, 0);
}
}
}
@ -1086,7 +1074,7 @@ static pj_status_t get_frame(pjmedia_port *port,
stream->dec : stream->enc,
"changed");
pjmedia_event_publish(&stream->epub, &stream->fmt_event);
pjmedia_event_publish(NULL, stream, &stream->fmt_event, 0);
stream->fmt_event.type = PJMEDIA_EVENT_NONE;
}
@ -1211,7 +1199,6 @@ static pj_status_t create_channel( pj_pool_t *pool,
/* Init port. */
channel->port.port_data.pdata = stream;
channel->port.get_event_pub = &port_get_epub;
PJ_LOG(5, (name.ptr,
"%s channel created %dx%d %s%s%.*s %d/%d(~%d)fps",
@ -1345,11 +1332,9 @@ PJ_DEF(pj_status_t) pjmedia_vid_stream_create(
if (status != PJ_SUCCESS)
return status;
/* Init event publisher and subscribe to codec events */
pjmedia_event_publisher_init(&stream->epub, SIGNATURE);
pjmedia_event_subscription_init(&stream->esub_codec, &stream_event_cb,
stream);
pjmedia_event_subscribe(&stream->codec->epub, &stream->esub_codec);
/* Subscribe to codec events */
pjmedia_event_subscribe(NULL, pool, &stream_event_cb, stream,
stream->codec);
/* Estimate the maximum frame size */
stream->frame_size = vfd_enc->size.w * vfd_enc->size.h * 4;
@ -1556,6 +1541,8 @@ PJ_DEF(pj_status_t) pjmedia_vid_stream_destroy( pjmedia_vid_stream *stream )
/* Free codec. */
if (stream->codec) {
pjmedia_event_unsubscribe(NULL, &stream_event_cb, stream,
stream->codec);
pjmedia_vid_codec_close(stream->codec);
pjmedia_vid_codec_mgr_dealloc_codec(stream->codec_mgr, stream->codec);
stream->codec = NULL;

View File

@ -72,6 +72,7 @@ int test_main(void)
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
pjmedia_converter_mgr_create(pool, NULL);
pjmedia_event_mgr_create(pool, 0, NULL);
pjmedia_vid_codec_mgr_create(pool, NULL);
#endif
@ -115,6 +116,7 @@ on_return:
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
pjmedia_video_format_mgr_destroy(pjmedia_video_format_mgr_instance());
pjmedia_converter_mgr_destroy(pjmedia_converter_mgr_instance());
pjmedia_event_mgr_destroy(pjmedia_event_mgr_instance());
pjmedia_vid_codec_mgr_destroy(pjmedia_vid_codec_mgr_instance());
#endif

View File

@ -47,18 +47,16 @@ typedef struct codec_port_data_t
pj_size_t pack_buf_size;
} codec_port_data_t;
static pj_status_t codec_on_event(pjmedia_event_subscription *esub,
pjmedia_event *event)
static pj_status_t codec_on_event(pjmedia_event *event,
void *user_data)
{
codec_port_data_t *port_data = (codec_port_data_t*)esub->user_data;
codec_port_data_t *port_data = (codec_port_data_t*)user_data;
if (event->type == PJMEDIA_EVENT_FMT_CHANGED) {
pjmedia_vid_codec *codec = port_data->codec;
pjmedia_vid_codec_param codec_param;
pj_status_t status;
++event->proc_cnt;
status = pjmedia_vid_codec_get_param(codec, &codec_param);
if (status != PJ_SUCCESS)
return status;
@ -200,7 +198,6 @@ static int encode_decode_test(pj_pool_t *pool, const char *codec_id,
pjmedia_vid_port *capture=NULL, *renderer=NULL;
pjmedia_vid_port_param vport_param;
pjmedia_video_format_detail *vfd;
pjmedia_event_subscription esub;
char codec_name[5];
pj_status_t status;
int rc = 0;
@ -323,9 +320,8 @@ static int encode_decode_test(pj_pool_t *pool, const char *codec_id,
codec_param.dec_fmt.det = codec_param.enc_fmt.det;
/* Subscribe to codec events */
pjmedia_event_subscription_init(&esub, &codec_on_event,
&codec_port_data);
pjmedia_event_subscribe(&codec->epub, &esub);
pjmedia_event_subscribe(NULL, pool, &codec_on_event, &codec_port_data,
codec);
}
pjmedia_vid_port_param_default(&vport_param);
@ -430,6 +426,8 @@ on_return:
pjmedia_vid_port_destroy(renderer);
}
if (codec) {
pjmedia_event_unsubscribe(NULL, &codec_on_event, &codec_port_data,
codec);
pjmedia_vid_codec_close(codec);
pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
}

View File

@ -76,10 +76,10 @@ static int enum_devs(void)
return PJ_SUCCESS;
}
static pj_status_t vid_event_cb(pjmedia_event_subscription *esub,
pjmedia_event *event)
static pj_status_t vid_event_cb(pjmedia_event *event,
void *user_data)
{
PJ_UNUSED_ARG(esub);
PJ_UNUSED_ARG(user_data);
if (event->type == PJMEDIA_EVENT_WND_CLOSED)
is_quitting = PJ_TRUE;
@ -95,7 +95,6 @@ static int capture_render_loopback(int cap_dev_id, int rend_dev_id,
pjmedia_vid_dev_info cdi, rdi;
pjmedia_vid_port_param param;
pjmedia_video_format_detail *vfd;
pjmedia_event_subscription esub;
pj_status_t status;
int rc = 0, i;
@ -161,10 +160,7 @@ static int capture_render_loopback(int cap_dev_id, int rend_dev_id,
}
/* Set event handler */
pjmedia_event_subscription_init(&esub, &vid_event_cb, NULL);
pjmedia_event_subscribe(
pjmedia_vid_port_get_event_publisher(renderer),
&esub);
pjmedia_event_subscribe(NULL, pool, &vid_event_cb, NULL, renderer);
/* Connect capture to renderer */
status = pjmedia_vid_port_connect(
@ -196,8 +192,10 @@ on_return:
if (capture)
pjmedia_vid_port_destroy(capture);
if (renderer)
if (renderer) {
pjmedia_event_unsubscribe(NULL, &vid_event_cb, NULL, renderer);
pjmedia_vid_port_destroy(renderer);
}
pj_pool_release(pool);
return rc;

View File

@ -32,10 +32,10 @@
static pj_bool_t is_quitting = PJ_FALSE;
static pj_status_t vid_event_cb(pjmedia_event_subscription *esub,
pjmedia_event *event)
static pj_status_t vid_event_cb(pjmedia_event *event,
void *user_data)
{
PJ_UNUSED_ARG(esub);
PJ_UNUSED_ARG(user_data);
if (event->type == PJMEDIA_EVENT_WND_CLOSED)
is_quitting = PJ_TRUE;
@ -52,7 +52,6 @@ static int capture_render_loopback(pj_bool_t active,
pjmedia_vid_dev_info cdi, rdi;
pjmedia_vid_port_param param;
pjmedia_video_format_detail *vfd;
pjmedia_event_subscription esub;
pj_status_t status;
int rc = 0, i;
@ -118,10 +117,7 @@ static int capture_render_loopback(pj_bool_t active,
}
/* Set event handler */
pjmedia_event_subscription_init(&esub, &vid_event_cb, NULL);
pjmedia_event_subscribe(
pjmedia_vid_port_get_event_publisher(renderer),
&esub);
pjmedia_event_subscribe(NULL, pool, &vid_event_cb, NULL, renderer);
/* Connect capture to renderer */
status = pjmedia_vid_port_connect(
@ -153,8 +149,10 @@ on_return:
if (capture)
pjmedia_vid_port_destroy(capture);
if (renderer)
if (renderer) {
pjmedia_event_unsubscribe(NULL, &vid_event_cb, NULL, renderer);
pjmedia_vid_port_destroy(renderer);
}
pj_pool_release(pool);
return rc;

View File

@ -105,10 +105,10 @@ typedef struct codec_port_data_t
pjmedia_converter *conv;
} codec_port_data_t;
static pj_status_t avi_event_cb(pjmedia_event_subscription *esub,
pjmedia_event *event)
static pj_status_t avi_event_cb(pjmedia_event *event,
void *user_data)
{
avi_port_t *ap = (avi_port_t *)esub->user_data;
avi_port_t *ap = (avi_port_t *)user_data;
switch (event->type) {
case PJMEDIA_EVENT_WND_CLOSED:
@ -191,7 +191,6 @@ static int aviplay(pj_pool_t *pool, const char *fname)
pjmedia_avi_stream *vid_stream, *aud_stream;
pjmedia_port *vid_port = NULL, *aud_port = NULL;
pjmedia_vid_codec *codec=NULL;
pjmedia_event_subscription esub;
avi_port_t avi_port;
pj_bzero(&avi_port, sizeof(avi_port));
@ -402,10 +401,8 @@ static int aviplay(pj_pool_t *pool, const char *fname)
pjmedia_vid_port_set_cb(renderer, &cb, &avi_port);
/* subscribe events */
pjmedia_event_subscription_init(&esub, &avi_event_cb, &avi_port);
pjmedia_event_subscribe(
pjmedia_vid_port_get_event_publisher(renderer),
&esub);
pjmedia_event_subscribe(NULL, pool, &avi_event_cb, &avi_port,
renderer);
if (snd_port) {
/* Synchronize video rendering and audio playback */
@ -436,8 +433,11 @@ on_return:
pj_thread_sleep(100);
pjmedia_snd_port_destroy(snd_port);
}
if (renderer)
if (renderer) {
pjmedia_event_unsubscribe(NULL, &avi_event_cb, &avi_port,
renderer);
pjmedia_vid_port_destroy(renderer);
}
if (aud_port)
pjmedia_port_destroy(aud_port);
if (vid_port)
@ -482,6 +482,7 @@ static int main_func(int argc, char *argv[])
pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
pjmedia_converter_mgr_create(pool, NULL);
pjmedia_event_mgr_create(pool, 0, NULL);
pjmedia_vid_codec_mgr_create(pool, NULL);
status = pjmedia_vid_dev_subsys_init(&cp.factory);
@ -519,6 +520,7 @@ on_return:
pjmedia_video_format_mgr_destroy(pjmedia_video_format_mgr_instance());
pjmedia_converter_mgr_destroy(pjmedia_converter_mgr_instance());
pjmedia_event_mgr_destroy(pjmedia_event_mgr_instance());
pjmedia_vid_codec_mgr_destroy(pjmedia_vid_codec_mgr_instance());
/* Release application pool */

View File

@ -85,9 +85,6 @@ struct pjsua_call_media
address) */
pjmedia_srtp_use rem_srtp_use; /**< Remote's SRTP usage policy. */
pjmedia_event_subscription esub_rend;/**< Subscribe renderer events. */
pjmedia_event_subscription esub_cap;/**< Subscribe capture events. */
pjsua_med_tp_state_cb med_init_cb;/**< Media transport
initialization callback. */
@ -565,6 +562,9 @@ pj_status_t video_channel_update(pjsua_call_media *call_med,
void stop_video_stream(pjsua_call_media *call_med);
void set_media_tp_state(pjsua_call_media *call_med, pjsua_med_tp_st tp_st);
/* Callback to receive media events */
pj_status_t call_media_on_event(pjmedia_event *event,
void *user_data);
/**
* Init presence.

View File

@ -1253,14 +1253,13 @@ static void sort_media(const pjmedia_sdp_session *sdp,
}
/* Callback to receive media events */
static pj_status_t call_media_on_event(pjmedia_event_subscription *esub,
pjmedia_event *event)
pj_status_t call_media_on_event(pjmedia_event *event,
void *user_data)
{
pjsua_call_media *call_med = (pjsua_call_media*)esub->user_data;
pjsua_call_media *call_med = (pjsua_call_media*)user_data;
pjsua_call *call = call_med->call;
if (pjsua_var.ua_cfg.cb.on_call_media_event && call) {
++event->proc_cnt;
(*pjsua_var.ua_cfg.cb.on_call_media_event)(call->index,
call_med->idx, event);
}
@ -1424,12 +1423,6 @@ pj_status_t pjsua_call_media_init(pjsua_call_media *call_med,
pjmedia_vid_dev_get_info(call_med->strm.v.cap_dev, &info);
call_med->strm.v.cap_dev = info.id;
}
/* Init event subscribtion */
pjmedia_event_subscription_init(&call_med->esub_rend, &call_media_on_event,
call_med);
pjmedia_event_subscription_init(&call_med->esub_cap, &call_media_on_event,
call_med);
}
#endif

View File

@ -57,6 +57,13 @@ pj_status_t pjsua_vid_subsys_init(void)
goto on_error;
}
status = pjmedia_event_mgr_create(pjsua_var.pool, 0, NULL);
if (status != PJ_SUCCESS) {
PJ_PERROR(1,(THIS_FILE, status,
"Error creating PJMEDIA event manager"));
goto on_error;
}
status = pjmedia_vid_codec_mgr_create(pjsua_var.pool, NULL);
if (status != PJ_SUCCESS) {
PJ_PERROR(1,(THIS_FILE, status,
@ -130,6 +137,9 @@ pj_status_t pjsua_vid_subsys_destroy(void)
if (pjmedia_converter_mgr_instance())
pjmedia_converter_mgr_destroy(NULL);
if (pjmedia_event_mgr_instance())
pjmedia_event_mgr_destroy(NULL);
if (pjmedia_video_format_mgr_instance())
pjmedia_video_format_mgr_destroy(NULL);
@ -613,11 +623,15 @@ static void free_vid_win(pjsua_vid_win_id wid)
pj_log_push_indent();
if (w->vp_cap) {
pjmedia_event_unsubscribe(NULL, &call_media_on_event, NULL,
w->vp_cap);
pjmedia_vid_port_stop(w->vp_cap);
pjmedia_vid_port_disconnect(w->vp_cap);
pjmedia_vid_port_destroy(w->vp_cap);
}
if (w->vp_rend) {
pjmedia_event_unsubscribe(NULL, &call_media_on_event, NULL,
w->vp_rend);
pjmedia_vid_port_stop(w->vp_rend);
pjmedia_vid_port_destroy(w->vp_rend);
}
@ -815,9 +829,8 @@ pj_status_t video_channel_update(pjsua_call_media *call_med,
#if ENABLE_EVENT
/* Register to video events */
pjmedia_event_subscribe(
pjmedia_vid_port_get_event_publisher(w->vp_rend),
&call_med->esub_rend);
pjmedia_event_subscribe(NULL, w->pool, &call_media_on_event,
call_med, w->vp_rend);
#endif
/* Connect renderer to stream */
@ -886,9 +899,8 @@ pj_status_t video_channel_update(pjsua_call_media *call_med,
w = &pjsua_var.win[wid];
#if ENABLE_EVENT
pjmedia_event_subscribe(
pjmedia_vid_port_get_event_publisher(w->vp_cap),
&call_med->esub_cap);
pjmedia_event_subscribe(NULL, w->pool, &call_media_on_event,
call_med, w->vp_cap);
#endif
/* Connect stream to capturer (via video window tee) */
@ -1006,7 +1018,8 @@ void stop_video_stream(pjsua_call_media *call_med)
}
/* Unsubscribe event */
pjmedia_event_unsubscribe(&call_med->esub_cap);
pjmedia_event_unsubscribe(NULL, &call_media_on_event, call_med,
w->vp_cap);
/* Re-start capture again, if it is used by other stream */
if (w->ref_cnt > 1)
@ -1021,7 +1034,8 @@ void stop_video_stream(pjsua_call_media *call_med)
/* Stop the render before unsubscribing event */
pjmedia_vid_port_stop(w->vp_rend);
pjmedia_event_unsubscribe(&call_med->esub_rend);
pjmedia_event_unsubscribe(NULL, &call_media_on_event, call_med,
w->vp_rend);
dec_vid_win(call_med->strm.v.rdr_win_id);
call_med->strm.v.rdr_win_id = PJSUA_INVALID_ID;
@ -1835,7 +1849,8 @@ static pj_status_t call_change_cap_dev(pjsua_call *call,
if (status != PJ_SUCCESS)
return status;
pjmedia_event_unsubscribe(&call_med->esub_cap);
pjmedia_event_unsubscribe(NULL, &call_media_on_event, call_med,
w->vp_cap);
/* temporarily disconnect while we operate on the tee. */
pjmedia_vid_port_disconnect(w->vp_cap);
@ -1893,9 +1908,8 @@ static pj_status_t call_change_cap_dev(pjsua_call *call,
}
#if ENABLE_EVENT
pjmedia_event_subscribe(
pjmedia_vid_port_get_event_publisher(new_w->vp_cap),
&call_med->esub_cap);
pjmedia_event_subscribe(NULL, new_w->pool, &call_media_on_event,
call_med, new_w->vp_cap);
#endif
/* Start capturer */
@ -1919,7 +1933,8 @@ on_error:
if (new_w) {
/* Unsubscribe, just in case */
pjmedia_event_unsubscribe(&call_med->esub_cap);
pjmedia_event_unsubscribe(NULL, &call_media_on_event, call_med,
new_w->vp_cap);
/* Disconnect media port from the new capturer */
pjmedia_vid_tee_remove_dst_port(new_w->tee, media_port);
/* Release the new capturer */
@ -1935,9 +1950,8 @@ on_error:
#if ENABLE_EVENT
/* Resubscribe */
pjmedia_event_subscribe(
pjmedia_vid_port_get_event_publisher(w->vp_cap),
&call_med->esub_cap);
pjmedia_event_subscribe(NULL, w->pool, &call_media_on_event,
call_med, w->vp_cap);
#endif
return status;