From af23f4acec679cb8a42074206dbe463f8160a370 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Thu, 11 May 2006 14:22:01 +0000 Subject: Fixed bug: incorrect remote and local PT for telephone-events (swapped) git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@435 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/include/pjmedia/jbuf.h | 109 ++++++++++++++++++++++++++++----------- pjmedia/src/pjmedia/jbuf.c | 112 ++++++++++++++++++++++++++++++++++------- pjmedia/src/pjmedia/session.c | 12 ++--- pjmedia/src/pjmedia/stream.c | 13 ++--- 4 files changed, 186 insertions(+), 60 deletions(-) diff --git a/pjmedia/include/pjmedia/jbuf.h b/pjmedia/include/pjmedia/jbuf.h index c289e337..4a5c1abb 100644 --- a/pjmedia/include/pjmedia/jbuf.h +++ b/pjmedia/include/pjmedia/jbuf.h @@ -45,12 +45,34 @@ PJ_BEGIN_DECL */ enum pjmedia_jb_frame_type { - PJMEDIA_JB_MISSING_FRAME = 0, /**< No frame because it's missing. */ - PJMEDIA_JB_NORMAL_FRAME = 1, /**< Normal frame is being returned. */ - PJMEDIA_JB_ZERO_FRAME = 2, /**< Zero frame is being returned. */ + PJMEDIA_JB_MISSING_FRAME = 0, /**< No frame because it's missing */ + PJMEDIA_JB_NORMAL_FRAME = 1, /**< Normal frame is being returned */ + PJMEDIA_JB_ZERO_PREFETCH_FRAME = 2, /**< Zero frame is being returned + because JB is bufferring. */ + PJMEDIA_JB_ZERO_EMPTY_FRAME = 3 /**< Zero frame is being returned + because JB is empty. */ }; +/** + * This structure describes jitter buffer current status. + */ +struct pjmedia_jb_state +{ + unsigned frame_size; /**< Individual frame size, in bytes. */ + unsigned prefetch; /**< Current prefetch value, in frames */ + unsigned min_prefetch; /**< Minimum allowed prefetch, in frms. */ + unsigned max_prefetch; /**< Maximum allowed prefetch, in frms. */ + unsigned size; /**< Current buffer size, in frames. */ +}; + + +/** + * @see pjmedia_jb_state + */ +typedef struct pjmedia_jb_state pjmedia_jb_state; + + /** * The constant PJMEDIA_JB_DEFAULT_INIT_DELAY specifies default jitter * buffer prefetch count during jitter buffer creation. @@ -59,29 +81,69 @@ enum pjmedia_jb_frame_type /** - * Create the jitter buffer. This function may allocate large chunk of - * memory to keep the frames in the buffer. + * Create an adaptive jitter buffer according to the specification. If + * application wants to have a fixed jitter buffer, it may call + * #pjmedia_jbuf_set_fixed() after the jitter buffer is created. + * + * This function may allocate large chunk of memory to keep the frames in + * the buffer. * * @param pool The pool to allocate memory. * @param name Name to identify the jitter buffer for logging * purpose. * @param frame_size The size of each frame that will be kept in the - * jitter buffer. The value here normaly corresponds - * to the RTP payload size according to the codec - * being used. - * @param init_delay Initial jitter buffer delay, in number of frames. - * @param max_count Maximum jitter buffer delay, in number of frames. + * jitter buffer, in bytes. This should correspond + * to the minimum frame size supported by the codec. + * For example, a 10ms frame (80 bytes) would be + * recommended for G.711 codec. + * @param max_count Maximum number of frames that can be kept in the + * jitter buffer. This effectively means the maximum + * delay that may be introduced by this jitter + * buffer. * @param p_jb Pointer to receive jitter buffer instance. * * @return PJ_SUCCESS on success. */ PJ_DECL(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool, const pj_str_t *name, - int frame_size, - int init_delay, - int max_count, + unsigned frame_size, + unsigned max_count, pjmedia_jbuf **p_jb); +/** + * Set the jitter buffer to fixed delay mode. The default behavior + * is to adapt the delay with actual packet delay. + * + * @param jb The jitter buffer + * @param prefetch The fixed delay value, in number of frames. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pjmedia_jbuf_set_fixed( pjmedia_jbuf *jb, + unsigned prefetch); + + +/** + * Set the jitter buffer to adaptive mode. + * + * @param jb The jitter buffer. + * @param prefetch The prefetch value to be applied to the jitter + * buffer. + * @param min_prefetch The minimum delay that must be applied to each + * incoming packets, in number of frames. The + * default value is zero. + * @param max_prefetch The maximum allowable value for prefetch delay, + * in number of frames. The default value is equal + * to the size of the jitter buffer. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pjmedia_jbuf_set_adaptive( pjmedia_jbuf *jb, + unsigned prefetch, + unsigned min_prefetch, + unsigned max_prefetch); + + /** * Destroy jitter buffer instance. * @@ -155,28 +217,17 @@ PJ_DECL(pj_status_t) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb, void *frame, char *p_frm_type); -/** - * Retrieve the current value of jitter buffer minimum delay, in number - * of frames. - * - * @param jb The jitter buffer. - * - * @return Number of frames, indicating the minimum delay that - * will be applied by the jitter buffer between frame - * arrival and frame retrieval. - */ -PJ_DECL(unsigned) pjmedia_jbuf_get_min_delay_size(pjmedia_jbuf *jb); - /** - * Retrieve the current delay value, in number of frames. + * Get jitter buffer state. * * @param jb The jitter buffer. + * @param state Buffer to receive jitter buffer state. * - * @return Number of frames, indicating the delay between frame - * arrival and frame retrieval. + * @return PJ_SUCCESS on success. */ -PJ_DECL(unsigned) pjmedia_jbuf_get_delay(pjmedia_jbuf *jb); +PJ_DECL(pj_status_t) pjmedia_jbuf_get_state( pjmedia_jbuf *jb, + pjmedia_jb_state *state ); diff --git a/pjmedia/src/pjmedia/jbuf.c b/pjmedia/src/pjmedia/jbuf.c index 4392e855..cfee2379 100644 --- a/pjmedia/src/pjmedia/jbuf.c +++ b/pjmedia/src/pjmedia/jbuf.c @@ -64,6 +64,8 @@ struct pjmedia_jbuf int jb_prefetch; // no. of frame to insert before removing some // (at the beginning of the framelist->flist_buffer operation) int jb_prefetch_cnt; // prefetch counter + int jb_min_prefetch; // Minimum allowable prefetch + int jb_max_prefetch; // Maximum allowable prefetch int jb_status; // status is 'init' until the first 'put' operation @@ -137,7 +139,8 @@ static pj_bool_t jb_framelist_get(jb_framelist *framelist, pj_memset(framelist->flist_buffer + framelist->flist_head * framelist->flist_frame_size, 0, framelist->flist_frame_size); - framelist->flist_frame_type[framelist->flist_head] = 0; + framelist->flist_frame_type[framelist->flist_head] = + PJMEDIA_JB_MISSING_FRAME; framelist->flist_origin++; framelist->flist_head = (framelist->flist_head + 1 ) % @@ -181,7 +184,7 @@ static void jb_framelist_remove_head( jb_framelist *framelist, 0, step1*framelist->flist_frame_size); pj_memset(framelist->flist_frame_type+framelist->flist_head, - 0, + PJMEDIA_JB_MISSING_FRAME, step1*sizeof(framelist->flist_frame_type[0])); if (step2) { @@ -189,7 +192,7 @@ static void jb_framelist_remove_head( jb_framelist *framelist, 0, step2*framelist->flist_frame_size); pj_memset(framelist->flist_frame_type, - 0, + PJMEDIA_JB_MISSING_FRAME, step2*sizeof(framelist->flist_frame_type[0])); } @@ -263,9 +266,8 @@ enum pjmedia_jb_op PJ_DEF(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool, const pj_str_t *name, - int frame_size, - int initial_prefetch, - int max_count, + unsigned frame_size, + unsigned max_count, pjmedia_jbuf **p_jb) { pjmedia_jbuf *jb; @@ -284,8 +286,10 @@ PJ_DEF(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool, jb->jb_last_level = 0; jb->jb_last_jitter = 0; jb->jb_last_op = JB_OP_INIT; - jb->jb_prefetch = PJ_MIN(initial_prefetch, max_count*4/5); + jb->jb_prefetch = PJ_MIN(PJMEDIA_JB_DEFAULT_INIT_DELAY,max_count*4/5); jb->jb_prefetch_cnt = 0; + jb->jb_min_prefetch = 0; + jb->jb_max_prefetch = max_count*4/5; jb->jb_stable_hist = 0; jb->jb_status = JB_STATUS_INITIALIZING; jb->jb_max_hist_jitter = 0; @@ -296,6 +300,47 @@ PJ_DEF(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool, } +/* + * Set the jitter buffer to fixed delay mode. The default behavior + * is to adapt the delay with actual packet delay. + * + */ +PJ_DEF(pj_status_t) pjmedia_jbuf_set_fixed( pjmedia_jbuf *jb, + unsigned prefetch) +{ + PJ_ASSERT_RETURN(jb, PJ_EINVAL); + PJ_ASSERT_RETURN(prefetch <= jb->jb_max_count, PJ_EINVAL); + + jb->jb_min_prefetch = jb->jb_max_prefetch = + jb->jb_prefetch = prefetch; + + return PJ_SUCCESS; +} + + +/* + * Set the jitter buffer to adaptive mode. + */ +PJ_DEF(pj_status_t) pjmedia_jbuf_set_adaptive( pjmedia_jbuf *jb, + unsigned prefetch, + unsigned min_prefetch, + unsigned max_prefetch) +{ + PJ_ASSERT_RETURN(jb, PJ_EINVAL); + PJ_ASSERT_RETURN(min_prefetch < max_prefetch && + prefetch >= min_prefetch && + prefetch <= max_prefetch && + max_prefetch <= jb->jb_max_count, + PJ_EINVAL); + + jb->jb_prefetch = prefetch; + jb->jb_min_prefetch = min_prefetch; + jb->jb_max_prefetch = max_prefetch; + + return PJ_SUCCESS; +} + + PJ_DEF(pj_status_t) pjmedia_jbuf_reset(pjmedia_jbuf *jb) { jb->jb_last_seq_no = -1; @@ -336,7 +381,8 @@ static void jbuf_calculate_jitter(pjmedia_jbuf *jb) if (seq_diff<1) seq_diff = 1; jb->jb_prefetch -= seq_diff; - if (jb->jb_prefetch < 1) jb->jb_prefetch = 1; + if (jb->jb_prefetch < jb->jb_min_prefetch) + jb->jb_prefetch = jb->jb_min_prefetch; jb->jb_stable_hist = 0; jb->jb_max_hist_jitter = 0; @@ -357,6 +403,8 @@ static void jbuf_calculate_jitter(pjmedia_jbuf *jb) } else { jb->jb_prefetch = PJ_MIN(jb->jb_last_jitter, (int)(jb->jb_max_count*4/5)); + if (jb->jb_prefetch > jb->jb_max_prefetch) + jb->jb_prefetch = jb->jb_max_prefetch; jb->jb_stable_hist = 0; jb->jb_max_hist_jitter = 0; @@ -431,6 +479,9 @@ PJ_DEF(pj_status_t) pjmedia_jbuf_put_frame(pjmedia_jbuf *jb, return PJ_SUCCESS; } +/* + * Get frame from jitter buffer. + */ PJ_DEF(pj_status_t) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb, void *frame, char *p_frame_type) @@ -445,14 +496,31 @@ PJ_DEF(pj_status_t) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb, jb->jb_prefetch_cnt = 0; } - if ((jb->jb_prefetch_cnt < jb->jb_prefetch) || - jb_framelist_get(&jb->jb_framelist,frame,&ftype) == PJ_FALSE) - { + if ((jb->jb_prefetch_cnt < jb->jb_prefetch)) { + /* Can't return frame because jitter buffer is filling up + * minimum prefetch. + */ + pj_memset(frame, 0, jb->jb_frame_size); + if (jb_framelist_size(&jb->jb_framelist) == 0) + *p_frame_type = PJMEDIA_JB_ZERO_EMPTY_FRAME; + else + *p_frame_type = PJMEDIA_JB_ZERO_PREFETCH_FRAME; + + return PJ_SUCCESS; + } + + /* Retrieve a frame from frame list */ + if (jb_framelist_get(&jb->jb_framelist,frame,&ftype) == PJ_FALSE) { + /* Can't return frame because jitter buffer is empty! */ pj_memset(frame, 0, jb->jb_frame_size); - *p_frame_type = PJMEDIA_JB_ZERO_FRAME; + *p_frame_type = PJMEDIA_JB_ZERO_EMPTY_FRAME; + return PJ_SUCCESS; } + /* We've successfully retrieved a frame from the frame list, but + * the frame could be a blank frame! + */ if (ftype == PJMEDIA_JB_NORMAL_FRAME) { *p_frame_type = PJMEDIA_JB_NORMAL_FRAME; } else { @@ -462,14 +530,20 @@ PJ_DEF(pj_status_t) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb, return PJ_SUCCESS; } -PJ_DEF(unsigned) pjmedia_jbuf_get_min_delay_size(pjmedia_jbuf *jb) +/* + * Get jitter buffer state. + */ +PJ_DEF(pj_status_t) pjmedia_jbuf_get_state( pjmedia_jbuf *jb, + pjmedia_jb_state *state ) { - return jb->jb_prefetch; -} + PJ_ASSERT_RETURN(jb && state, PJ_EINVAL); -PJ_DEF(unsigned) pjmedia_jbuf_get_delay(pjmedia_jbuf *jb) -{ - return jb_framelist_size(&jb->jb_framelist); -} + state->frame_size = jb->jb_frame_size; + state->prefetch = jb->jb_prefetch; + state->min_prefetch = jb->jb_min_prefetch; + state->max_prefetch = jb->jb_max_prefetch; + state->size = jb_framelist_size(&jb->jb_framelist); + return PJ_SUCCESS; +} diff --git a/pjmedia/src/pjmedia/session.c b/pjmedia/src/pjmedia/session.c index c09926b8..42207cad 100644 --- a/pjmedia/src/pjmedia/session.c +++ b/pjmedia/src/pjmedia/session.c @@ -302,8 +302,8 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp( - /* Get local DTMF payload type */ - si->tx_event_pt = -1; + /* Get incomming payload type for telephone-events */ + si->rx_event_pt = -1; for (i=0; iattr_count; ++i) { pjmedia_sdp_rtpmap r; @@ -313,13 +313,13 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp( if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS) continue; if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) { - si->tx_event_pt = pj_strtoul(&r.pt); + si->rx_event_pt = pj_strtoul(&r.pt); break; } } - /* Get remote DTMF payload type */ - si->rx_event_pt = -1; + /* Get outgoing payload type for telephone-events */ + si->tx_event_pt = -1; for (i=0; iattr_count; ++i) { pjmedia_sdp_rtpmap r; @@ -329,7 +329,7 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp( if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS) continue; if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) { - si->rx_event_pt = pj_strtoul(&r.pt); + si->tx_event_pt = pj_strtoul(&r.pt); break; } } diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c index d7a38df4..41f506a0 100644 --- a/pjmedia/src/pjmedia/stream.c +++ b/pjmedia/src/pjmedia/stream.c @@ -174,9 +174,7 @@ static pj_status_t get_frame( pjmedia_port *port, pjmedia_frame *frame) /* Unlock jitter buffer mutex. */ pj_mutex_unlock( stream->jb_mutex ); - if (status != PJ_SUCCESS || frame_type == PJMEDIA_JB_ZERO_FRAME || - frame_type == PJMEDIA_JB_MISSING_FRAME) - { + if (status != PJ_SUCCESS || frame_type != PJMEDIA_JB_NORMAL_FRAME) { frame->type = PJMEDIA_FRAME_TYPE_NONE; return PJ_SUCCESS; } @@ -627,8 +625,10 @@ static void on_rx_rtp( pj_ioqueue_key_t *key, PJ_LOG(4,(stream->port.info.name.ptr, "Jitter buffer reset")); } else { + unsigned ext_seq; + ext_seq = channel->rtp.seq_ctrl.cycles | pj_ntohs(hdr->seq); status = pjmedia_jbuf_put_frame(stream->jb, payload, payloadlen, - pj_ntohs(hdr->seq)); + ext_seq); } pj_mutex_unlock( stream->jb_mutex ); @@ -914,11 +914,12 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt, info->fmt.clock_rate); status = pjmedia_jbuf_create(pool, &stream->port.info.name, stream->frame_size, - jbuf_init, jbuf_max, - &stream->jb); + jbuf_max, &stream->jb); if (status != PJ_SUCCESS) goto err_cleanup; + /* Set jitter buffer to adaptive */ + pjmedia_jbuf_set_adaptive( stream->jb, jbuf_init, 1, jbuf_max * 4 / 5); /* Create decoder channel: */ -- cgit v1.2.3