diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index f072cffcea889cf9e3f63fb4687f1f9be3871e75..82d31177726e86da9c0eaa73118cfe55549123ef 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -901,6 +901,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 */ @@ -2286,6 +2290,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 a42e73f4c4b7a2d0615ee168d96e4a3efc9133e5..de0affdc6a3865fcdaf9df9e2cf311bfaf1538f9 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3554,6 +3554,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; @@ -3578,9 +3583,20 @@ int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const v res = ast_timer_set_rate(ast_channel_timer(c), real_rate); + if (ast_channel_timingdata(c) && ast_test_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ)) { + ao2_ref(ast_channel_timingdata(c), -1); + } + ast_channel_timingfunc_set(c, func); ast_channel_timingdata_set(c, data); + if (data && is_ao2_obj) { + ao2_ref(data, 1); + ast_set_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ); + } else { + ast_clear_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ); + } + if (func == NULL && rate == 0 && ast_channel_fdno(c) == 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 @@ -3913,9 +3929,17 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) /* save a copy of func/data before unlocking the channel */ ast_timing_func_t func = ast_channel_timingfunc(chan); void *data = ast_channel_timingdata(chan); + int got_ref = 0; + if (data && ast_test_flag(ast_channel_flags(chan), AST_FLAG_TIMINGDATA_IS_AO2_OBJ)) { + ao2_ref(data, 1); + got_ref = 1; + } ast_channel_fdno_set(chan, -1); ast_channel_unlock(chan); func(data); + if (got_ref) { + ao2_ref(data, -1); + } } else { ast_timer_set_rate(ast_channel_timer(chan), 0); ast_channel_fdno_set(chan, -1); diff --git a/main/file.c b/main/file.c index c880d13cba330231f6fdb5410cbbcd53c57e0970..12ec4f1d9576e5191ea24555c9bf92372171e162 100644 --- a/main/file.c +++ b/main/file.c @@ -845,7 +845,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 { ast_channel_streamid_set(s->owner, ast_sched_add(ast_channel_sched(s->owner), whennext / (ast_format_rate(&s->fmt->format) / 1000), ast_fsread_audio, s)); }