@ -953,7 +953,7 @@ alertpipe_failed:
}
/*! \brief Queue an outgoing media frame */
int ast_queue_frame( struct ast_channel * chan , struct ast_frame * fin )
static int __ ast_queue_frame( struct ast_channel * chan , struct ast_frame * fin , int head )
{
struct ast_frame * f ;
struct ast_frame * cur ;
@ -962,9 +962,9 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin)
/* Build us a copy and free the original one */
if ( ! ( f = ast_frdup ( fin ) ) ) {
ast_log ( LOG_WARNING , " Unable to duplicate frame \n " ) ;
return - 1 ;
}
ast_channel_lock ( chan ) ;
/* See if the last frame on the queue is a hangup, if so don't queue anything */
@ -991,20 +991,39 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin)
return 0 ;
}
}
AST_LIST_INSERT_TAIL ( & chan - > readq , f , frame_list ) ;
if ( head ) {
AST_LIST_INSERT_HEAD ( & chan - > readq , f , frame_list ) ;
} else {
AST_LIST_INSERT_TAIL ( & chan - > readq , f , frame_list ) ;
}
if ( chan - > alertpipe [ 1 ] > - 1 ) {
if ( write ( chan - > alertpipe [ 1 ] , & blah , sizeof ( blah ) ) ! = sizeof ( blah ) )
if ( write ( chan - > alertpipe [ 1 ] , & blah , sizeof ( blah ) ) ! = sizeof ( blah ) ) {
ast_log ( LOG_WARNING , " Unable to write to alert pipe on %s, frametype/subclass %d/%d (qlen = %d): %s! \n " ,
chan - > name , f - > frametype , f - > subclass , qlen , strerror ( errno ) ) ;
}
} else if ( chan - > timingfd > - 1 ) {
ast_timer_enable_continuous ( chan - > timingfd ) ;
} else if ( ast_test_flag ( chan , AST_FLAG_BLOCKING ) ) {
pthread_kill ( chan - > blocker , SIGURG ) ;
}
ast_channel_unlock ( chan ) ;
return 0 ;
}
int ast_queue_frame ( struct ast_channel * chan , struct ast_frame * fin )
{
return __ast_queue_frame ( chan , fin , 0 ) ;
}
int ast_queue_frame_head ( struct ast_channel * chan , struct ast_frame * fin )
{
return __ast_queue_frame ( chan , fin , 1 ) ;
}
/*! \brief Queue a hangup frame for channel */
int ast_queue_hangup ( struct ast_channel * chan )
{
@ -2370,6 +2389,42 @@ static void ast_read_generator_actions(struct ast_channel *chan, struct ast_fram
}
}
static inline void queue_dtmf_readq ( struct ast_channel * chan , struct ast_frame * f )
{
struct ast_frame * fr = & chan - > dtmff ;
fr - > frametype = AST_FRAME_DTMF_END ;
fr - > subclass = f - > subclass ;
fr - > len = f - > len ;
/* The only time this function will be called is for a frame that just came
* out of the channel driver . So , we want to stick it on the tail of the
* readq . */
ast_queue_frame ( chan , fr ) ;
}
/*!
* \ brief Determine whether or not we should ignore DTMF in the readq
*/
static inline int should_skip_dtmf ( struct ast_channel * chan )
{
if ( ast_test_flag ( chan , AST_FLAG_DEFER_DTMF | AST_FLAG_EMULATE_DTMF ) ) {
/* We're in the middle of emulating a digit, or DTMF has been
* explicitly deferred . Skip this digit , then . */
return 1 ;
}
if ( ! ast_tvzero ( chan - > dtmf_tv ) & &
ast_tvdiff_ms ( ast_tvnow ( ) , chan - > dtmf_tv ) < AST_MIN_DTMF_GAP ) {
/* We're not in the middle of a digit, but it hasn't been long enough
* since the last digit , so we ' ll have to skip DTMF for now . */
return 1 ;
}
return 0 ;
}
static struct ast_frame * __ast_read ( struct ast_channel * chan , int dropaudio )
{
struct ast_frame * f = NULL ; /* the return value */
@ -2403,28 +2458,6 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
}
prestate = chan - > _state ;
if ( ! ast_test_flag ( chan , AST_FLAG_DEFER_DTMF | AST_FLAG_EMULATE_DTMF | AST_FLAG_IN_DTMF ) & &
! ast_strlen_zero ( chan - > dtmfq ) & &
( ast_tvzero ( chan - > dtmf_tv ) | | ast_tvdiff_ms ( ast_tvnow ( ) , chan - > dtmf_tv ) > AST_MIN_DTMF_GAP ) ) {
/* We have DTMF that has been deferred. Return it now */
chan - > dtmff . subclass = chan - > dtmfq [ 0 ] ;
/* Drop first digit from the buffer */
memmove ( chan - > dtmfq , chan - > dtmfq + 1 , sizeof ( chan - > dtmfq ) - 1 ) ;
f = & chan - > dtmff ;
if ( ast_test_flag ( chan , AST_FLAG_END_DTMF_ONLY ) ) {
ast_log ( LOG_DTMF , " DTMF end emulation of '%c' queued on %s \n " , f - > subclass , chan - > name ) ;
chan - > dtmff . frametype = AST_FRAME_DTMF_END ;
} else {
ast_log ( LOG_DTMF , " DTMF begin emulation of '%c' with duration %d queued on %s \n " , f - > subclass , AST_DEFAULT_EMULATE_DTMF_DURATION , chan - > name ) ;
chan - > dtmff . frametype = AST_FRAME_DTMF_BEGIN ;
ast_set_flag ( chan , AST_FLAG_EMULATE_DTMF ) ;
chan - > emulate_dtmf_digit = f - > subclass ;
chan - > emulate_dtmf_duration = AST_DEFAULT_EMULATE_DTMF_DURATION ;
}
chan - > dtmf_tv = ast_tvnow ( ) ;
goto done ;
}
/* Read and ignore anything on the alertpipe, but read only
one sizeof ( blah ) per frame that we send from it */
if ( chan - > alertpipe [ 0 ] > - 1 ) {
@ -2492,7 +2525,35 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
/* Check for pending read queue */
if ( ! AST_LIST_EMPTY ( & chan - > readq ) ) {
f = AST_LIST_REMOVE_HEAD ( & chan - > readq , frame_list ) ;
int skip_dtmf = should_skip_dtmf ( chan ) ;
AST_LIST_TRAVERSE_SAFE_BEGIN ( & chan - > readq , f , frame_list ) {
/* We have to be picky about which frame we pull off of the readq because
* there are cases where we want to leave DTMF frames on the queue until
* some later time . */
if ( ( f - > frametype = = AST_FRAME_DTMF_BEGIN | | f - > frametype = = AST_FRAME_DTMF_END ) & & skip_dtmf ) {
continue ;
}
AST_LIST_REMOVE_CURRENT ( frame_list ) ;
break ;
}
AST_LIST_TRAVERSE_SAFE_END
if ( ! f ) {
/* There were no acceptable frames on the readq. */
f = & ast_null_frame ;
if ( chan - > alertpipe [ 0 ] > - 1 ) {
int poke = 0 ;
/* Restore the state of the alertpipe since we aren't ready for any
* of the frames in the readq . */
if ( write ( chan - > alertpipe [ 1 ] , & poke , sizeof ( poke ) ) ! = sizeof ( poke ) ) {
ast_log ( LOG_ERROR , " Failed to write to alertpipe: %s \n " , strerror ( errno ) ) ;
}
}
}
/* Interpret hangup and return NULL */
/* XXX why not the same for frames from the channel ? */
if ( f - > frametype = = AST_FRAME_CONTROL & & f - > subclass = = AST_CONTROL_HANGUP ) {
@ -2549,26 +2610,16 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
case AST_FRAME_DTMF_END :
send_dtmf_event ( chan , " Received " , f - > subclass , " No " , " Yes " ) ;
ast_log ( LOG_DTMF , " DTMF end '%c' received on %s, duration %ld ms \n " , f - > subclass , chan - > name , f - > len ) ;
/* Queue it up if DTMF is deffered, or if DTMF emulation is forced.
* However , only let emulation be forced if the other end cares about BEGIN frames */
if ( ast_test_flag ( chan , AST_FLAG_DEFER_DTMF ) | |
( ast_test_flag ( chan , AST_FLAG_EMULATE_DTMF ) & & ! ast_test_flag ( chan , AST_FLAG_END_DTMF_ONLY ) ) ) {
if ( strlen ( chan - > dtmfq ) < sizeof ( chan - > dtmfq ) - 2 ) {
ast_log ( LOG_DTMF , " DTMF end '%c' put into dtmf queue on %s \n " , f - > subclass , chan - > name ) ;
chan - > dtmfq [ strlen ( chan - > dtmfq ) ] = f - > subclass ;
} else
ast_log ( LOG_WARNING , " Dropping deferred DTMF digits on %s \n " , chan - > name ) ;
/* Queue it up if DTMF is deferred, or if DTMF emulation is forced. */
if ( ast_test_flag ( chan , AST_FLAG_DEFER_DTMF ) | | ast_test_flag ( chan , AST_FLAG_EMULATE_DTMF ) ) {
queue_dtmf_readq ( chan , f ) ;
ast_frfree ( f ) ;
f = & ast_null_frame ;
} else if ( ! ast_test_flag ( chan , AST_FLAG_IN_DTMF | AST_FLAG_END_DTMF_ONLY ) ) {
if ( ! ast_tvzero ( chan - > dtmf_tv ) & &
ast_tvdiff_ms ( ast_tvnow ( ) , chan - > dtmf_tv ) < AST_MIN_DTMF_GAP ) {
/* If it hasn't been long enough, defer this digit */
if ( strlen ( chan - > dtmfq ) < sizeof ( chan - > dtmfq ) - 2 ) {
ast_log ( LOG_DTMF , " DTMF end '%c' put into dtmf queue on %s \n " , f - > subclass , chan - > name ) ;
chan - > dtmfq [ strlen ( chan - > dtmfq ) ] = f - > subclass ;
} else
ast_log ( LOG_WARNING , " Dropping deferred DTMF digits on %s \n " , chan - > name ) ;
queue_dtmf_readq ( chan , f ) ;
ast_frfree ( f ) ;
f = & ast_null_frame ;
} else {