Index: apps/app_meetme.c =================================================================== --- apps/app_meetme.c (revision 43634) +++ apps/app_meetme.c (working copy) @@ -101,7 +101,14 @@ " 'x' -- close the conference when last marked user exits\n" " 'X' -- allow user to exit the conference by entering a valid single\n" " digit extension ${MEETME_EXIT_CONTEXT} or the current context\n" -" if that variable is not defined.\n"; +" if that variable is not defined.\n" +" 'S(x)' -- Kick the user 'x' seconds *after* he entered into the conference.\n" +" 'L(x[:y][:z])' - Limit the conference to 'x' ms. Play a warning when 'y' ms are\n" +" left. Repeat the warning every 'z' ms. The following special\n" +" variables can be used with this option:\n" +" * CONF_LIMIT_TIMEOUT_FILE File to play when time is up.\n" +" * CONF_LIMIT_WARNING_FILE File to play as warning if 'y' is defined.\n" +" The default is to say the time remaining.\n"; static const char *descrip2 = " MeetMeCount(confno[|var]): Plays back the number of users in the specified\n" @@ -168,6 +175,13 @@ char usrvalue[50]; /* Custom User Value */ char namerecloc[PATH_MAX]; /* Name Recorded file Location */ time_t jointime; /* Time the user joined the conference */ + time_t kicktime; /* Time the user will be kicked from the conference */ + struct timeval start_time; /* Time the user entered into the conference */ + long timelimit; /* Time limit for the user to be in the conference L(x:y:z) */ + long play_warning; /* Play a warning when 'y' ms are left */ + long warning_freq; /* Repeat the warning every 'z' ms */ + char *warning_sound; /* File to play as warning if 'y' is defined */ + char *end_sound; /* File to play when time is up. */ struct volume talk; struct volume listen; }; @@ -227,12 +241,17 @@ #define CONFFLAG_EMPTY (1 << 19) #define CONFFLAG_EMPTYNOPIN (1 << 20) #define CONFFLAG_ALWAYSPROMPT (1 << 21) +#define CONFFLAG_DURATION_STOP (1 << 22) +#define CONFFLAG_DURATION_LIMIT (1 << 23) enum { OPT_ARG_WAITMARKED = 0, - OPT_ARG_ARRAY_SIZE = 1, + OPT_ARG_DURATION_STOP = 1, + OPT_ARG_DURATION_LIMIT = 2, + OPT_ARG_ARRAY_SIZE = 3, } meetme_option_args; + AST_APP_OPTIONS(meetme_opts, { AST_APP_OPTION('a', CONFFLAG_ADMIN ), AST_APP_OPTION('c', CONFFLAG_ANNOUNCEUSERCOUNT ), @@ -255,6 +274,8 @@ AST_APP_OPTION('e', CONFFLAG_EMPTY ), AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ), AST_APP_OPTION('P', CONFFLAG_ALWAYSPROMPT ), + AST_APP_OPTION_ARG('S', CONFFLAG_DURATION_STOP, OPT_ARG_DURATION_STOP), + AST_APP_OPTION_ARG('L', CONFFLAG_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT), }); static char *istalking(int x) @@ -832,6 +853,19 @@ ZT_BUFFERINFO bi; char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; char *buf = __buf + AST_FRIENDLY_OFFSET; + time_t myt; + unsigned int calldurationlimit=0; + long timelimit = 0; + long play_warning = 0; + long warning_freq=0; + char *warning_sound=NULL; + char *end_sound=NULL; + char *var; + char *parse; + long time_left_ms=0; + struct timeval nexteventts = { 0, }; + int to; + int min=0, sec=0, remain=0; if (!user) { ast_log(LOG_ERROR, "Out of memory\n"); @@ -845,7 +879,63 @@ (opt_waitmarked_timeout > 0)) { timeout = time(NULL) + opt_waitmarked_timeout; } + + if ((confflags & CONFFLAG_DURATION_STOP) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_STOP])) { + calldurationlimit = atoi(optargs[OPT_ARG_DURATION_STOP]); + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Setting call duration limit to %d seconds.\n",calldurationlimit); + } + + if ((confflags & CONFFLAG_DURATION_LIMIT) && !ast_strlen_zero(optargs[OPT_ARG_DURATION_LIMIT])) { + char *limit_str, *warning_str, *warnfreq_str; + parse = optargs[OPT_ARG_DURATION_LIMIT]; + limit_str = strsep(&parse, ":"); + warning_str = strsep(&parse, ":"); + warnfreq_str = parse; + + timelimit = atol(limit_str); + if (warning_str) + play_warning = atol(warning_str); + if (warnfreq_str) + warning_freq = atol(warnfreq_str); + + if (!timelimit) { + timelimit = play_warning = warning_freq = 0; + warning_sound = NULL; + } else if (play_warning > timelimit) { + if (!warning_freq) { + play_warning = 0; + } else { + while (play_warning > timelimit) + play_warning -= warning_freq; + if (play_warning < 1) + play_warning = warning_freq = 0; + } + } + + var = pbx_builtin_getvar_helper(chan,"CONF_LIMIT_WARNING_FILE"); + warning_sound = var ? var : "timeleft"; + + var = pbx_builtin_getvar_helper(chan,"CONF_LIMIT_TIMEOUT_FILE"); + end_sound = var ? var : NULL; + + /* undo effect of S(x) in case they are both used */ + calldurationlimit = 0; + /* more efficient do it like S(x) does since no advanced opts */ + if (!play_warning && !end_sound && timelimit) { + calldurationlimit = timelimit/1000; + timelimit = play_warning = warning_freq = 0; + } else if (option_verbose > 2) { + ast_verbose(VERBOSE_PREFIX_3 "Limit Data for this call:\n"); + ast_verbose(VERBOSE_PREFIX_3 "- timelimit = %ld\n", timelimit); + ast_verbose(VERBOSE_PREFIX_3 "- play_warning = %ld\n", play_warning); + ast_verbose(VERBOSE_PREFIX_3 "- warning_freq = %ld\n", warning_freq); + ast_verbose(VERBOSE_PREFIX_3 "- warning_sound = %s\n", warning_sound ? warning_sound : "UNDEF"); + ast_verbose(VERBOSE_PREFIX_3 "- end_sound = %s\n", end_sound ? end_sound : "UNDEF"); + } + } + if (confflags & CONFFLAG_RECORDCONF && conf->recording !=MEETME_RECORD_ACTIVE) { conf->recordingfilename = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFILE"); if (!conf->recordingfilename) { @@ -865,6 +955,26 @@ } time(&user->jointime); + + user->timelimit = timelimit; + user->play_warning = play_warning; + user->warning_freq = warning_freq; + user->warning_sound = warning_sound; + user->end_sound = end_sound; + + if (calldurationlimit > 0) { + time(&user->kicktime); + user->kicktime = user->kicktime + calldurationlimit; + } + + if (ast_tvzero(user->start_time)) + user->start_time = ast_tvnow(); + time_left_ms = user->timelimit; + + if (user->timelimit) { + nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000)); + nexteventts = ast_tvsub(nexteventts, ast_samp2tv(user->play_warning, 1000)); + } if (conf->locked && (!(confflags & CONFFLAG_ADMIN))) { /* Sorry, but this confernce is locked! */ @@ -1127,12 +1237,75 @@ ast_log(LOG_WARNING, "Unable to allocate DSP!\n"); res = -1; } - for(;;) { + for(;;) { int menu_was_active = 0; - outfd = -1; ms = -1; + + time(&myt); /* get current time */ + if (user->kicktime && (user->kicktime < myt)) break; + to = -1; + if (user->timelimit) { + struct timeval now; + + now = ast_tvnow(); + to = ast_tvdiff_ms(nexteventts, now); + if (to < 0) + to = 0; + time_left_ms = user->timelimit - ast_tvdiff_ms(now, user->start_time); + if (time_left_ms < to) + to = time_left_ms; + + if (time_left_ms <= 0) { + if (user->end_sound){ + res = ast_streamfile(chan, user->end_sound, chan->language); + res = ast_waitstream(chan, ""); + } + break; + } + + if (!to) { + if (time_left_ms >= 5000) { + + remain = (time_left_ms + 500) / 1000; + if (remain / 60 >= 1) { + min = remain / 60; + sec = remain % 60; + } else { + sec = remain; + } + + /* force the time left to round up if appropriate */ + if (user->warning_sound && user->play_warning){ + if (!strcmp(user->warning_sound,"timeleft")) { + + res = ast_streamfile(chan, "vm-youhave", chan->language); + res = ast_waitstream(chan, ""); + if (min) { + res = ast_say_number(chan, min, AST_DIGIT_ANY, chan->language, (char *) NULL); + res = ast_streamfile(chan, "queue-minutes", chan->language); + res = ast_waitstream(chan, ""); + } + if (sec) { + res = ast_say_number(chan, sec, AST_DIGIT_ANY, chan->language, (char *) NULL); + res = ast_streamfile(chan, "queue-seconds", chan->language); + res = ast_waitstream(chan, ""); + } + } else { + res = ast_streamfile(chan, user->warning_sound, chan->language); + res = ast_waitstream(chan, ""); + } + } + } + if (user->warning_freq) + nexteventts = ast_tvadd(nexteventts, ast_samp2tv(user->warning_freq, 1000)); + else + nexteventts = ast_tvadd(user->start_time, ast_samp2tv(user->timelimit, 1000)); + } + } + + if (timeout && time(NULL) >= timeout) break; @@ -2296,4 +2469,3 @@ { return ASTERISK_GPL_KEY; } -