static void *fast_originate(void *data) { int res = 0, reason; struct fast_originate_helper *in = data; struct cw_channel *chan = NULL; cw_indicate(in->frommember->chan, CW_CONTROL_RINGING); if (1) { res = cw_pbx_outgoing_app( in->tech, CW_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, !cw_strlen_zero(in->cid_num) ? in->cid_num : NULL, !cw_strlen_zero(in->cid_name) ? in->cid_name : NULL, in->vars, &chan ); } else { res = cw_pbx_outgoing_exten( in->tech, CW_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, !cw_strlen_zero(in->cid_num) ? in->cid_num : NULL, !cw_strlen_zero(in->cid_name) ? in->cid_name : NULL, in->vars, NULL ); } cw_log(CW_CONF_DEBUG,"Originate returned %d \n",reason); cw_indicate(in->frommember->chan, -1); if ( reason == CW_CONTROL_ANSWER ) { conference_queue_sound( in->frommember, "beep" ); } else { conference_queue_sound( in->frommember, "beeperr" ); } if (chan) cw_mutex_unlock(&chan->lock); free(in); return NULL; }
static int record_exec(struct cw_channel *chan, int argc, char **argv) { int res = 0; int count = 0; int percentflag = 0; char *ext = NULL; int i = 0; char tmp[256]; struct cw_filestream *s = '\0'; struct localuser *u; struct cw_frame *f = NULL; struct cw_dsp *sildet = NULL; /* silence detector dsp */ int totalsilence = 0; int dspsilence = 0; int silence = 0; /* amount of silence to allow */ int gotsilence = 0; /* did we timeout for silence? */ int maxduration = 0; /* max duration of recording in milliseconds */ int gottimeout = 0; /* did we timeout for maxduration exceeded? */ int option_skip = 0; int option_noanswer = 0; int option_append = 0; int terminator = '#'; int option_quiet = 0; int rfmt = 0; int flags; if (argc < 1 || argc > 4 || !argv[0][0]) { cw_log(LOG_ERROR, "Syntax: %s\n", record_syntax); return -1; } LOCAL_USER_ADD(u); if (strstr(argv[0], "%d")) percentflag = 1; ext = strrchr(argv[0], '.'); /* to support filename with a . in the filename, not format */ if (!ext) ext = strchr(argv[0], ':'); if (ext) { *ext = '\0'; ext++; } if (!ext) { cw_log(LOG_WARNING, "No extension specified to filename!\n"); LOCAL_USER_REMOVE(u); return -1; } if (argc > 1) { silence = atoi(argv[1]); if (silence > 0) silence *= 1000; else if (silence < 0) silence = 0; } if (argc > 2) { maxduration = atoi(argv[2]); if (maxduration > 0) maxduration *= 1000; else if (maxduration < 0) maxduration = 0; } if (argc > 3) { /* Retain backwards compatibility with old style options */ if (!strcasecmp(argv[3], "skip")) option_skip = 1; else if (!strcasecmp(argv[3], "noanswer")) option_noanswer = 1; else { if (strchr(argv[3], 's')) option_skip = 1; if (strchr(argv[3], 'n')) option_noanswer = 1; if (strchr(argv[3], 'a')) option_append = 1; if (strchr(argv[3], 't')) terminator = '*'; if (strchr(argv[3], 'q')) option_quiet = 1; } } /* done parsing */ /* these are to allow the use of the %d in the config file for a wild card of sort to create a new file with the inputed name scheme */ if (percentflag) { char *piece[100]; int pieces; /* Separate each piece out by the format specifier */ pieces = cw_separate_app_args(argv[0], '%', arraysize(piece), piece); do { int tmplen; /* First piece has no leading percent, so it's copied verbatim */ cw_copy_string(tmp, piece[0], sizeof(tmp)); tmplen = strlen(tmp); for (i = 1; i < pieces; i++) { if (piece[i][0] == 'd') { /* Substitute the count */ snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "%d", count); tmplen += strlen(tmp + tmplen); } else if (tmplen + 2 < sizeof(tmp)) { /* Unknown format specifier - just copy it verbatim */ tmp[tmplen++] = '%'; tmp[tmplen++] = piece[i][0]; } /* Copy the remaining portion of the piece */ cw_copy_string(tmp + tmplen, &(piece[i][1]), sizeof(tmp) - tmplen); } count++; } while ( cw_fileexists(tmp, ext, chan->language) != -1 ); pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp); } else strncpy(tmp, argv[0], sizeof(tmp)-1); /* end of routine mentioned */ if (chan->_state != CW_STATE_UP) { if (option_skip) { /* At the user's option, skip if the line is not up */ LOCAL_USER_REMOVE(u); return 0; } else if (!option_noanswer) { /* Otherwise answer unless we're supposed to record while on-hook */ res = cw_answer(chan); } } if (!res) { if (!option_quiet) { /* Some code to play a nice little beep to signify the start of the record operation */ res = cw_streamfile(chan, "beep", chan->language); if (!res) { res = cw_waitstream(chan, ""); } else { cw_log(LOG_WARNING, "cw_streamfile failed on %s\n", chan->name); } cw_stopstream(chan); } /* The end of beep code. Now the recording starts */ if (silence > 0) { rfmt = chan->readformat; res = cw_set_read_format(chan, CW_FORMAT_SLINEAR); if (res < 0) { cw_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); LOCAL_USER_REMOVE(u); return -1; } sildet = cw_dsp_new(); if (!sildet) { cw_log(LOG_WARNING, "Unable to create silence detector :(\n"); LOCAL_USER_REMOVE(u); return -1; } cw_dsp_set_threshold(sildet, 256); } flags = option_append ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY; s = cw_writefile( tmp, ext, NULL, flags , 0, 0644); if (s) { int waitres; /* Request a video update */ cw_indicate(chan, CW_CONTROL_VIDUPDATE); if (maxduration <= 0) maxduration = -1; while ((waitres = cw_waitfor(chan, maxduration)) > -1) { if (maxduration > 0) { if (waitres == 0) { gottimeout = 1; break; } maxduration = waitres; } f = cw_read(chan); if (!f) { res = -1; break; } if (f->frametype == CW_FRAME_VOICE) { res = cw_writestream(s, f); if (res) { cw_log(LOG_WARNING, "Problem writing frame\n"); cw_fr_free(f); break; } if (silence > 0) { dspsilence = 0; cw_dsp_silence(sildet, f, &dspsilence); if (dspsilence) { totalsilence = dspsilence; } else { totalsilence = 0; } if (totalsilence > silence) { /* Ended happily with silence */ cw_fr_free(f); gotsilence = 1; break; } } } if (f->frametype == CW_FRAME_VIDEO) { res = cw_writestream(s, f); if (res) { cw_log(LOG_WARNING, "Problem writing frame\n"); cw_fr_free(f); break; } } if ((f->frametype == CW_FRAME_DTMF) && (f->subclass == terminator)) { cw_fr_free(f); break; } cw_fr_free(f); } if (!f) { cw_log(LOG_DEBUG, "Got hangup\n"); res = -1; } if (gotsilence) { cw_stream_rewind(s, silence-1000); cw_truncstream(s); } else if (!gottimeout) { /* Strip off the last 1/4 second of it */ cw_stream_rewind(s, 250); cw_truncstream(s); } cw_closestream(s); } else cw_log(LOG_WARNING, "Could not create file %s\n", tmp); } else cw_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name); if ((silence > 0) && rfmt) { res = cw_set_read_format(chan, rfmt); if (res) cw_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); if (sildet) cw_dsp_free(sildet); } LOCAL_USER_REMOVE(u); return res; }
int cw_play_and_record(struct cw_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path) { int d; char *fmts; char comment[256]; int x, fmtcnt=1, res=-1,outmsg=0; struct cw_frame *f; struct cw_filestream *others[MAX_OTHER_FORMATS]; char *sfmt[MAX_OTHER_FORMATS]; char *stringp=NULL; time_t start, end; struct cw_dsp *sildet=NULL; /* silence detector dsp */ int totalsilence = 0; int dspsilence = 0; int gotsilence = 0; /* did we timeout for silence? */ int rfmt=0; if (silencethreshold < 0) silencethreshold = global_silence_threshold; if (maxsilence < 0) maxsilence = global_maxsilence; /* barf if no pointer passed to store duration in */ if (duration == NULL) { cw_log(LOG_WARNING, "Error play_and_record called without duration pointer\n"); return -1; } cw_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt); snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name); if (playfile) { d = cw_play_and_wait(chan, playfile); if (d > -1) d = cw_streamfile(chan, "beep",chan->language); if (!d) d = cw_waitstream(chan,""); if (d < 0) return -1; } fmts = cw_strdupa(fmt); stringp=fmts; strsep(&stringp, "|,"); cw_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts); sfmt[0] = cw_strdupa(fmts); while((fmt = strsep(&stringp, "|,"))) { if (fmtcnt > MAX_OTHER_FORMATS - 1) { cw_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n"); break; } sfmt[fmtcnt++] = cw_strdupa(fmt); } time(&start); end=start; /* pre-initialize end to be same as start in case we never get into loop */ for (x=0;x<fmtcnt;x++) { others[x] = cw_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700); cw_verbose( VERBOSE_PREFIX_3 "x=%d, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]); if (!others[x]) { break; } } if (path) cw_unlock_path(path); if (maxsilence > 0) { sildet = cw_dsp_new(); /* Create the silence detector */ if (!sildet) { cw_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } cw_dsp_set_threshold(sildet, silencethreshold); rfmt = chan->readformat; res = cw_set_read_format(chan, CW_FORMAT_SLINEAR); if (res < 0) { cw_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); cw_dsp_free(sildet); return -1; } } /* Request a video update */ cw_indicate(chan, CW_CONTROL_VIDUPDATE); if (x == fmtcnt) { /* Loop forever, writing the packets we read to the writer(s), until we read a # or get a hangup */ f = NULL; for(;;) { res = cw_waitfor(chan, 2000); if (!res) { cw_log(LOG_DEBUG, "One waitfor failed, trying another\n"); /* Try one more time in case of masq */ res = cw_waitfor(chan, 2000); if (!res) { cw_log(LOG_WARNING, "No audio available on %s??\n", chan->name); res = -1; } } if (res < 0) { f = NULL; break; } f = cw_read(chan); if (!f) break; if (f->frametype == CW_FRAME_VOICE) { /* write each format */ for (x=0;x<fmtcnt;x++) { res = cw_writestream(others[x], f); } /* Silence Detection */ if (maxsilence > 0) { dspsilence = 0; cw_dsp_silence(sildet, f, &dspsilence); if (dspsilence) totalsilence = dspsilence; else totalsilence = 0; if (totalsilence > maxsilence) { /* Ended happily with silence */ if (option_verbose > 2) cw_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000); cw_fr_free(f); gotsilence = 1; outmsg=2; break; } } /* Exit on any error */ if (res) { cw_log(LOG_WARNING, "Error writing frame\n"); cw_fr_free(f); break; } } else if (f->frametype == CW_FRAME_VIDEO) { /* Write only once */ cw_writestream(others[0], f); } else if (f->frametype == CW_FRAME_DTMF) { if (f->subclass == '#') { if (option_verbose > 2) cw_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass); res = '#'; outmsg = 2; cw_fr_free(f); break; } if (f->subclass == '0') { /* Check for a '0' during message recording also, in case caller wants operator */ if (option_verbose > 2) cw_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass); res = '0'; outmsg = 0; cw_fr_free(f); break; } } if (maxtime) { time(&end); if (maxtime < (end - start)) { if (option_verbose > 2) cw_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n"); outmsg = 2; res = 't'; cw_fr_free(f); break; } } cw_fr_free(f); } if (end == start) time(&end); if (!f) { if (option_verbose > 2) cw_verbose( VERBOSE_PREFIX_3 "User hung up\n"); res = -1; outmsg=1; } } else { cw_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]); } *duration = end - start; for (x=0;x<fmtcnt;x++) { if (!others[x]) break; if (res > 0) { if (totalsilence) cw_stream_rewind(others[x], totalsilence-200); else cw_stream_rewind(others[x], 200); } cw_truncstream(others[x]); cw_closestream(others[x]); } if (rfmt) { if (cw_set_read_format(chan, rfmt)) { cw_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", cw_getformatname(rfmt), chan->name); } } if (outmsg > 1) { /* Let them know recording is stopped */ if(!cw_streamfile(chan, "auth-thankyou", chan->language)) cw_waitstream(chan, ""); } if (sildet) cw_dsp_free(sildet); return res; }