diff --git a/main/autoservice.c b/main/autoservice.c index 853c1dfab6..02aa713a49 100644 --- a/main/autoservice.c +++ b/main/autoservice.c @@ -51,6 +51,7 @@ struct asent { * channel. It will ensure that it doesn't actually get stopped until * it gets stopped for the last time. */ unsigned int use_count; + unsigned int orig_end_dtmf_flag:1; AST_LIST_HEAD_NOLOCK(, ast_frame) dtmf_frames; AST_LIST_ENTRY(asent) list; }; @@ -151,42 +152,50 @@ int ast_autoservice_start(struct ast_channel *chan) struct asent *as; AST_RWLIST_WRLOCK(&aslist); - - /* Check if the channel already has autoservice */ AST_RWLIST_TRAVERSE(&aslist, as, list) { if (as->chan == chan) { as->use_count++; break; } } + AST_RWLIST_UNLOCK(&aslist); - /* If not, start autoservice on channel */ if (as) { - /* Entry extist, autoservice is already handling this channel */ - } else if ((as = ast_calloc(1, sizeof(*as))) == NULL) { - /* Memory allocation failed */ - res = -1; - } else { - /* New entry created */ - as->chan = chan; - ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY); - as->use_count = 1; - AST_RWLIST_INSERT_HEAD(&aslist, as, list); - if (asthread == AST_PTHREADT_NULL) { /* need start the thread */ - if (ast_pthread_create_background(&asthread, NULL, autoservice_run, NULL)) { - ast_log(LOG_WARNING, "Unable to create autoservice thread :(\n"); - /* There will only be a single member in the list at this point, - the one we just added. */ - AST_RWLIST_REMOVE(&aslist, as, list); - ast_free(as); - res = -1; - } else - pthread_kill(asthread, SIGURG); - } + /* Entry exists, autoservice is already handling this channel */ + return 0; } + if (!(as = ast_calloc(1, sizeof(*as)))) + return -1; + + /* New entry created */ + as->chan = chan; + as->use_count = 1; + + ast_channel_lock(chan); + as->orig_end_dtmf_flag = ast_test_flag(chan, AST_FLAG_END_DTMF_ONLY) ? 1 : 0; + if (!as->orig_end_dtmf_flag) + ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY); + ast_channel_unlock(chan); + + AST_RWLIST_WRLOCK(&aslist); + AST_RWLIST_INSERT_HEAD(&aslist, as, list); AST_RWLIST_UNLOCK(&aslist); + if (asthread == AST_PTHREADT_NULL) { /* need start the thread */ + if (ast_pthread_create_background(&asthread, NULL, autoservice_run, NULL)) { + ast_log(LOG_WARNING, "Unable to create autoservice thread :(\n"); + /* There will only be a single member in the list at this point, + the one we just added. */ + AST_RWLIST_WRLOCK(&aslist); + AST_RWLIST_REMOVE(&aslist, as, list); + AST_RWLIST_UNLOCK(&aslist); + free(as); + res = -1; + } else + pthread_kill(asthread, SIGURG); + } + return res; } @@ -197,6 +206,7 @@ int ast_autoservice_stop(struct ast_channel *chan) AST_LIST_HEAD_NOLOCK(, ast_frame) dtmf_frames; struct ast_frame *f; int removed = 0; + int orig_end_dtmf_flag = 0; AST_LIST_HEAD_INIT_NOLOCK(&dtmf_frames); @@ -208,11 +218,11 @@ int ast_autoservice_stop(struct ast_channel *chan) if (as->use_count) break; AST_LIST_APPEND_LIST(&dtmf_frames, &as->dtmf_frames, frame_list); + orig_end_dtmf_flag = as->orig_end_dtmf_flag; ast_free(as); removed = 1; if (!ast_check_hangup(chan)) res = 0; - ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); break; } } @@ -226,6 +236,9 @@ int ast_autoservice_stop(struct ast_channel *chan) if (!removed) return 0; + if (!orig_end_dtmf_flag) + ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); + /* Wait for it to un-block */ while (ast_test_flag(chan, AST_FLAG_BLOCKING)) usleep(1000);