diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 5b042a96d9938c63534e6b8f1251b09eee87160a..106117de15a20cdf55d91dbd085d5b5008ad95e7 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -929,6 +929,10 @@ enum { * publish. */ AST_FLAG_SNAPSHOT_STAGE = (1 << 25), + /*! + * The data on chan->timingdata is an astobj2 object. + */ + AST_FLAG_TIMINGDATA_IS_AO2_OBJ = (1 << 26), }; /*! \brief ast_bridge_config flags */ @@ -2275,6 +2279,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 567d8c62140d4ca50cf6c42cbf32cde1c7037b7c..a9f0fbb34298cab0a7bc77c363c622cf0dc01d5c 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3420,6 +3420,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; @@ -3444,9 +3449,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 @@ -3795,9 +3811,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 ffdbf1821d54c9331f26474893a4eb73b6630440..458f2544627d5ac5f188c056a2de0917e179df3b 100644 --- a/main/file.c +++ b/main/file.c @@ -902,7 +902,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)); }