Index: res/res_agi.c =================================================================== --- res/res_agi.c (revision 61679) +++ res/res_agi.c (working copy) @@ -63,6 +63,8 @@ #include "asterisk/lock.h" #include "asterisk/strings.h" #include "asterisk/agi.h" +#include "asterisk/sched.h" +#include "asterisk/translate.h" #define MAX_ARGS 128 #define MAX_COMMANDS 128 @@ -95,6 +97,9 @@ "Use the CLI command 'show agi' to list available agi commands\n"; static int agidebug = 0; +static struct sched_context *sched; +static pthread_t monitor_thread = AST_PTHREADT_NULL; +AST_MUTEX_DEFINE_STATIC(monlock); STANDARD_LOCAL_USER; @@ -108,6 +113,26 @@ #define AGI_PORT 4573 +static void *do_monitor(void *data) +{ + int res; + for (;;) { + res = ast_sched_wait(sched); + if (res != 0) { /* Nothing immediate */ + pthread_yield(); + pthread_testcancel(); + continue; + } + pthread_testcancel(); + ast_mutex_lock(&monlock); + ast_sched_runq(sched); + ast_mutex_unlock(&monlock); + pthread_testcancel(); + } + /* Never reached */ + return NULL; +} + static void agi_debug_cli(int fd, char *fmt, ...) { char *stuff; @@ -876,7 +901,38 @@ fdprintf(agi->fd, "200 result=0\n"); return RESULT_SUCCESS; } - + +static int poke_with_silence(void *data) +{ + struct ast_channel *chan = data; + struct ast_frame *f = NULL, *f2 = NULL; + struct ast_filestream *fs = ast_readfile("silence/1", "gsm", "", 0, 0, 0); + struct ast_trans_pvt *trans = ast_translator_build_path(chan->rawwriteformat, 2); + int blocking = ast_test_flag(chan, AST_FLAG_BLOCKING); + + if (fs) { + if (blocking) + ast_clear_flag(chan, AST_FLAG_BLOCKING); + + while ((f = ast_readframe(fs))) { + f2 = ast_translate(trans, f, 1); + /* Send everything unless/until we get an error on write */ + if (ast_write(chan, f2)) + break; + ast_frfree(f2); + f2 = NULL; + } + ast_closestream(fs); + if (f2) + ast_frfree(f2); + if (blocking) + ast_set_flag(chan, AST_FLAG_BLOCKING); + } + ast_translator_free_path(trans); + /* Ensure this gets re-scheduled */ + return -1; +} + static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) { struct ast_filestream *fs; @@ -885,6 +941,7 @@ long sample_offset = 0; int res = 0; int ms; + int sched_id = 0; struct ast_dsp *sildet=NULL; /* silence detector dsp */ int totalsilence = 0; @@ -948,6 +1005,9 @@ if (!res) res = ast_waitstream(chan, argv[4]); + if (sched) + sched_id = ast_sched_add(sched, 60000, poke_with_silence, chan); + if (res) { fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset); } else { @@ -957,6 +1017,8 @@ fdprintf(agi->fd, "200 result=%d (writefile)\n", res); if (sildet) ast_dsp_free(sildet); + if (sched && sched_id) + ast_sched_del(sched, sched_id); return RESULT_FAILURE; } @@ -977,6 +1039,8 @@ fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset); if (sildet) ast_dsp_free(sildet); + if (sched && sched_id) + ast_sched_del(sched, sched_id); return RESULT_FAILURE; } f = ast_read(chan); @@ -985,6 +1049,8 @@ ast_closestream(fs); if (sildet) ast_dsp_free(sildet); + if (sched && sched_id) + ast_sched_del(sched, sched_id); return RESULT_FAILURE; } switch(f->frametype) { @@ -1001,6 +1067,8 @@ ast_frfree(f); if (sildet) ast_dsp_free(sildet); + if (sched && sched_id) + ast_sched_del(sched, sched_id); return RESULT_SUCCESS; } break; @@ -1049,6 +1117,8 @@ ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); ast_dsp_free(sildet); } + if (sched && sched_id) + ast_sched_del(sched, sched_id); return RESULT_SUCCESS; } @@ -2129,11 +2199,22 @@ ast_cli_unregister(&cli_no_debug); ast_unregister_application(eapp); ast_unregister_application(deadapp); + ast_mutex_lock(&monlock); + pthread_cancel(monitor_thread); + pthread_kill(monitor_thread, SIGURG); + pthread_join(monitor_thread, NULL); + ast_mutex_unlock(&monlock); + sched_context_destroy(sched); return ast_unregister_application(app); } int load_module(void) { + sched = sched_context_create(); + if (!sched) + ast_log(LOG_WARNING, "Unable to create schedule context\n"); + if (ast_pthread_create(&monitor_thread, NULL, do_monitor, NULL) < 0) + ast_log(LOG_WARNING, "Unable to start schedule thread\n"); ast_cli_register(&showagi); ast_cli_register(&dumpagihtml); ast_cli_register(&cli_debug);