diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index a3f0c3d292..d232e5c6af 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -951,6 +951,10 @@ enum { * to continue. */ AST_FLAG_BRIDGE_DUAL_REDIRECT_WAIT = (1 << 22), + /*! + * The data on chan->timingdata is an astobj2 object. + */ + AST_FLAG_TIMINGDATA_IS_AO2_OBJ = (1 << 23), }; /*! \brief ast_bridge_config flags */ @@ -2260,6 +2264,7 @@ int ast_autoservice_ignore(struct ast_channel *chan, enum ast_frame_type ftype); * \version 1.6.1 changed samples parameter to rate, accomodates new timing methods */ int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data); +int ast_settimeout_full(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data, unsigned int is_ao2_obj); /*! * \brief Transfer a channel (if supported). diff --git a/main/channel.c b/main/channel.c index 28f0741efe..b923649e42 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3544,6 +3544,11 @@ int ast_waitfordigit(struct ast_channel *c, int ms) } int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data) +{ + return ast_settimeout_full(c, rate, func, data, 0); +} + +int ast_settimeout_full(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data, unsigned int is_ao2_obj) { int res; unsigned int real_rate = rate, max_rate; @@ -3568,9 +3573,20 @@ int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const v res = ast_timer_set_rate(c->timer, real_rate); + if (c->timingdata && ast_test_flag(c, AST_FLAG_TIMINGDATA_IS_AO2_OBJ)) { + ao2_ref(c->timingdata, -1); + } + c->timingfunc = func; c->timingdata = data; + if (data && is_ao2_obj) { + ao2_ref(data, 1); + ast_set_flag(c, AST_FLAG_TIMINGDATA_IS_AO2_OBJ); + } else { + ast_clear_flag(c, AST_FLAG_TIMINGDATA_IS_AO2_OBJ); + } + if (func == NULL && rate == 0 && c->fdno == AST_TIMING_FD) { /* Clearing the timing func and setting the rate to 0 * means that we don't want to be reading from the timingfd @@ -3877,9 +3893,17 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) /* save a copy of func/data before unlocking the channel */ int (*func)(const void *) = chan->timingfunc; void *data = chan->timingdata; + int got_ref = 0; + if (data && ast_test_flag(chan, AST_FLAG_TIMINGDATA_IS_AO2_OBJ)) { + ao2_ref(data, 1); + got_ref = 1; + } chan->fdno = -1; ast_channel_unlock(chan); func(data); + if (got_ref) { + ao2_ref(data, -1); + } } else { ast_timer_set_rate(chan->timer, 0); chan->fdno = -1; diff --git a/main/file.c b/main/file.c index abcdfd65d5..b19382e579 100644 --- a/main/file.c +++ b/main/file.c @@ -782,7 +782,7 @@ static enum fsread_res ast_readaudio_callback(struct ast_filestream *s) rate = (unsigned int) roundf(samp_rate / ((float) whennext)); - ast_settimeout(s->owner, rate, ast_fsread_audio, s); + ast_settimeout_full(s->owner, rate, ast_fsread_audio, s, 1); } else { s->owner->streamid = ast_sched_add(s->owner->sched, whennext / (ast_format_rate(s->fmt->format) / 1000), ast_fsread_audio, s);