From 070c6a1f21fb75982716948e1390dd449088ef60 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Mon, 12 Jun 2006 10:13:31 +0000 Subject: Added mutex protection and option not to delete upstream/downstream port in master_port.c git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@498 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/include/pjmedia/master_port.h | 57 ++++++++++++++++-- pjmedia/src/pjmedia/clock_thread.c | 28 +++++++-- pjmedia/src/pjmedia/master_port.c | 108 ++++++++++++++++++++++++++++++++-- 3 files changed, 178 insertions(+), 15 deletions(-) diff --git a/pjmedia/include/pjmedia/master_port.h b/pjmedia/include/pjmedia/master_port.h index 44b7db78..06af20b3 100644 --- a/pjmedia/include/pjmedia/master_port.h +++ b/pjmedia/include/pjmedia/master_port.h @@ -52,7 +52,7 @@ typedef struct pjmedia_master_port pjmedia_master_port; * @param pool Pool to allocate master port from. * @param u_port Upstream port. * @param d_port Downstream port. - * @param options Options flags. + * @param options Options flags, bitmask from #pjmedia_master_port_flag. * @param p_m Pointer to receive the master port instance. * * @return PJ_SUCCESS on success. @@ -64,7 +64,6 @@ PJ_DECL(pj_status_t) pjmedia_master_port_create(pj_pool_t *pool, pjmedia_master_port **p_m); - /** * Start the media flow. * @@ -75,7 +74,6 @@ PJ_DECL(pj_status_t) pjmedia_master_port_create(pj_pool_t *pool, PJ_DECL(pj_status_t) pjmedia_master_port_start(pjmedia_master_port *m); - /** * Stop the media flow. * @@ -86,15 +84,66 @@ PJ_DECL(pj_status_t) pjmedia_master_port_start(pjmedia_master_port *m); PJ_DECL(pj_status_t) pjmedia_master_port_stop(pjmedia_master_port *m); +/** + * Change the upstream port. Note that application is responsible to destroy + * current upstream port (the one that is going to be replaced with the + * new port). + * + * @param m The master port. + * @param port Port to be used for upstream port. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pjmedia_master_port_set_uport(pjmedia_master_port *m, + pjmedia_port *port); + + +/** + * Get the upstream port. + * + * @param m The master port. + * + * @return The upstream port. + */ +PJ_DECL(pjmedia_port*) pjmedia_master_port_get_uport(pjmedia_master_port*m); + + +/** + * Change the downstream port. Note that application is responsible to destroy + * current downstream port (the one that is going to be replaced with the + * new port). + * + * @param m The master port. + * @param port Port to be used for downstream port. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pjmedia_master_port_set_dport(pjmedia_master_port *m, + pjmedia_port *port); + + +/** + * Get the downstream port. + * + * @param m The master port. + * + * @return The downstream port. + */ +PJ_DECL(pjmedia_port*) pjmedia_master_port_get_dport(pjmedia_master_port*m); + + /** * Destroy the master port, and optionally destroy the upstream and * downstream ports. * * @param m The master port. + * @param destroy_ports If non-zero, the function will destroy both + * upstream and downstream ports too. * * @return PJ_SUCCESS on success. */ -PJ_DECL(pj_status_t) pjmedia_master_port_destroy(pjmedia_master_port *m); +PJ_DECL(pj_status_t) pjmedia_master_port_destroy(pjmedia_master_port *m, + pj_bool_t destroy_ports); diff --git a/pjmedia/src/pjmedia/clock_thread.c b/pjmedia/src/pjmedia/clock_thread.c index dad7447a..391f7d1f 100644 --- a/pjmedia/src/pjmedia/clock_thread.c +++ b/pjmedia/src/pjmedia/clock_thread.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,7 @@ struct pjmedia_clock pj_thread_t *thread; pj_bool_t running; pj_bool_t quitting; + pj_lock_t *lock; }; @@ -82,10 +84,17 @@ PJ_DEF(pj_status_t) pjmedia_clock_create( pj_pool_t *pool, clock->running = PJ_FALSE; clock->quitting = PJ_FALSE; + /* I don't think we need a mutex, so we'll use null. */ + status = pj_lock_create_null_mutex(pool, "clock", &clock->lock); + if (status != PJ_SUCCESS) + return status; + status = pj_thread_create(pool, "clock", &clock_thread, clock, 0, 0, &clock->thread); - if (status != PJ_SUCCESS) + if (status != PJ_SUCCESS) { + pj_lock_destroy(clock->lock); return status; + } *p_clock = clock; @@ -104,12 +113,17 @@ PJ_DEF(pj_status_t) pjmedia_clock_start(pjmedia_clock *clock) PJ_ASSERT_RETURN(clock != NULL, PJ_EINVAL); + if (clock->running) + return PJ_SUCCESS; + status = pj_get_timestamp(&now); if (status != PJ_SUCCESS) return status; + pj_lock_acquire(clock->lock); clock->next_tick.u64 = now.u64 + clock->interval.u64; clock->running = PJ_TRUE; + pj_lock_release(clock->lock); return status; } @@ -205,6 +219,8 @@ static int clock_thread(void *arg) if (!clock->running) continue; + pj_lock_acquire(clock->lock); + /* Call callback, if any */ if (clock->cb) (*clock->cb)(&clock->timestamp, clock->user_data); @@ -215,7 +231,7 @@ static int clock_thread(void *arg) /* Calculate next tick */ clock->next_tick.u64 += clock->interval.u64; - + pj_lock_release(clock->lock); } return 0; @@ -238,10 +254,12 @@ PJ_DEF(pj_status_t) pjmedia_clock_destroy(pjmedia_clock *clock) clock->thread = NULL; } + if (clock->lock) { + pj_lock_destroy(clock->lock); + clock->lock = NULL; + } + return PJ_SUCCESS; } - - - diff --git a/pjmedia/src/pjmedia/master_port.c b/pjmedia/src/pjmedia/master_port.c index 42edd96e..ce45038a 100644 --- a/pjmedia/src/pjmedia/master_port.c +++ b/pjmedia/src/pjmedia/master_port.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,7 @@ struct pjmedia_master_port pjmedia_port *d_port; unsigned buff_size; void *buff; + pj_lock_t *lock; }; @@ -90,13 +92,18 @@ PJ_DEF(pj_status_t) pjmedia_master_port_create( pj_pool_t *pool, if (!m->buff) return PJ_ENOMEM; + /* Create lock object */ + status = pj_lock_create_simple_mutex(pool, "mport", &m->lock); + if (status != PJ_SUCCESS) + return status; /* Create media clock */ status = pjmedia_clock_create(pool, clock_rate, samples_per_frame, 0, &clock_callback, m, &m->clock); - if (status != PJ_SUCCESS) + if (status != PJ_SUCCESS) { + pj_lock_destroy(m->lock); return status; - + } /* Done */ *p_m = m; @@ -117,7 +124,6 @@ PJ_DEF(pj_status_t) pjmedia_master_port_start(pjmedia_master_port *m) } - /* * Stop the media flow. */ @@ -138,6 +144,9 @@ static void clock_callback(const pj_timestamp *ts, void *user_data) pjmedia_frame frame; pj_status_t status; + + /* Lock access to ports. */ + pj_lock_acquire(m->lock); /* Get frame from upstream port and pass it to downstream port */ pj_memset(&frame, 0, sizeof(frame)); @@ -162,6 +171,87 @@ static void clock_callback(const pj_timestamp *ts, void *user_data) frame.type = PJMEDIA_FRAME_TYPE_NONE; status = pjmedia_port_put_frame(m->u_port, &frame); + + /* Release lock */ + pj_lock_release(m->lock); +} + + +/* + * Change the upstream port. + */ +PJ_DEF(pj_status_t) pjmedia_master_port_set_uport(pjmedia_master_port *m, + pjmedia_port *port) +{ + PJ_ASSERT_RETURN(m && port, PJ_EINVAL); + + /* If we have downstream port, make sure they have matching samples per + * frame. + */ + if (m->d_port) { + PJ_ASSERT_RETURN( + port->info.clock_rate/port->info.samples_per_frame== + m->d_port->info.clock_rate/m->d_port->info.samples_per_frame, + PJMEDIA_ENCSAMPLESPFRAME + ); + } + + pj_lock_acquire(m->lock); + + m->u_port = port; + + pj_lock_release(m->lock); + + return PJ_SUCCESS; +} + + +/* + * Get the upstream port. + */ +PJ_DEF(pjmedia_port*) pjmedia_master_port_get_uport(pjmedia_master_port*m) +{ + PJ_ASSERT_RETURN(m, NULL); + return m->u_port; +} + + +/* + * Change the downstream port. + */ +PJ_DEF(pj_status_t) pjmedia_master_port_set_dport(pjmedia_master_port *m, + pjmedia_port *port) +{ + PJ_ASSERT_RETURN(m && port, PJ_EINVAL); + + /* If we have upstream port, make sure they have matching samples per + * frame. + */ + if (m->u_port) { + PJ_ASSERT_RETURN( + port->info.clock_rate/port->info.samples_per_frame== + m->u_port->info.clock_rate/m->u_port->info.samples_per_frame, + PJMEDIA_ENCSAMPLESPFRAME + ); + } + + pj_lock_acquire(m->lock); + + m->d_port = port; + + pj_lock_release(m->lock); + + return PJ_SUCCESS; +} + + +/* + * Get the downstream port. + */ +PJ_DEF(pjmedia_port*) pjmedia_master_port_get_dport(pjmedia_master_port*m) +{ + PJ_ASSERT_RETURN(m, NULL); + return m->d_port; } @@ -169,7 +259,8 @@ static void clock_callback(const pj_timestamp *ts, void *user_data) * Destroy the master port, and optionally destroy the u_port and * d_port ports. */ -PJ_DEF(pj_status_t) pjmedia_master_port_destroy(pjmedia_master_port *m) +PJ_DEF(pj_status_t) pjmedia_master_port_destroy(pjmedia_master_port *m, + pj_bool_t destroy_ports) { PJ_ASSERT_RETURN(m, PJ_EINVAL); @@ -178,16 +269,21 @@ PJ_DEF(pj_status_t) pjmedia_master_port_destroy(pjmedia_master_port *m) m->clock = NULL; } - if (m->u_port) { + if (m->u_port && destroy_ports) { pjmedia_port_destroy(m->u_port); m->u_port = NULL; } - if (m->d_port) { + if (m->d_port && destroy_ports) { pjmedia_port_destroy(m->d_port); m->d_port = NULL; } + if (m->lock) { + pj_lock_destroy(m->lock); + m->lock = NULL; + } + return PJ_SUCCESS; } -- cgit v1.2.3