int ast_register_translator(struct ast_translator *t) { char tmp[80]; t->srcfmt = powerof(t->srcfmt); t->dstfmt = powerof(t->dstfmt); if (t->srcfmt >= MAX_FORMAT) { ast_log(LOG_WARNING, "Source format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt)); return -1; } if (t->dstfmt >= MAX_FORMAT) { ast_log(LOG_WARNING, "Destination format %s is larger than MAX_FORMAT\n", ast_getformatname(t->dstfmt)); return -1; } calc_cost(t,1); if (option_verbose > 1) ast_verbose(VERBOSE_PREFIX_2 "Registered translator '%s' from format %s to %s, cost %d\n", term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt), t->cost); ast_mutex_lock(&list_lock); if (!added_cli) { ast_cli_register(&show_trans); added_cli++; } t->next = list; list = t; rebuild_matrix(0); ast_mutex_unlock(&list_lock); return 0; }
static int func_channel_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len) { int ret = 0; if (!strcasecmp(data, "audionativeformat")) /* use the _multiple version when chan->nativeformats holds multiple formats */ /* ast_getformatname_multiple(buf, len, chan->nativeformats & AST_FORMAT_AUDIO_MASK); */ ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_AUDIO_MASK), len); else if (!strcasecmp(data, "videonativeformat")) /* use the _multiple version when chan->nativeformats holds multiple formats */ /* ast_getformatname_multiple(buf, len, chan->nativeformats & AST_FORMAT_VIDEO_MASK); */ ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_VIDEO_MASK), len); else if (!strcasecmp(data, "audioreadformat")) ast_copy_string(buf, ast_getformatname(chan->readformat), len); else if (!strcasecmp(data, "audiowriteformat")) ast_copy_string(buf, ast_getformatname(chan->writeformat), len); #ifdef CHANNEL_TRACE else if (!strcasecmp(data, "trace")) { ast_channel_lock(chan); ast_copy_string(buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len); ast_channel_unlock(chan); } #endif else if (!strcasecmp(data, "tonezone") && chan->zone) locked_copy_string(chan, buf, chan->zone->country, len); else if (!strcasecmp(data, "language")) locked_copy_string(chan, buf, chan->language, len); else if (!strcasecmp(data, "musicclass")) locked_copy_string(chan, buf, chan->musicclass, len); else if (!strcasecmp(data, "parkinglot")) locked_copy_string(chan, buf, chan->parkinglot, len); else if (!strcasecmp(data, "state")) locked_copy_string(chan, buf, ast_state2str(chan->_state), len); else if (!strcasecmp(data, "channeltype")) locked_copy_string(chan, buf, chan->tech->type, len); else if (!strcasecmp(data, "transfercapability")) locked_copy_string(chan, buf, transfercapability_table[chan->transfercapability & 0x1f], len); else if (!strcasecmp(data, "callgroup")) { char groupbuf[256]; locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), chan->callgroup), len); } else if (!chan->tech->func_channel_read || chan->tech->func_channel_read(chan, function, data, buf, len)) { ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data); ret = -1; } return ret; }
/*! Build a set of translators based upon the given source and destination formats */ struct ast_trans_pvt *ast_translator_build_path(int dest, int source) { struct ast_trans_pvt *tmpr = NULL, *tmp = NULL; source = powerof(source); dest = powerof(dest); while(source != dest) { if (!tr_matrix[source][dest].step) { /* We shouldn't have allocated any memory */ ast_log(LOG_WARNING, "No translator path from %s to %s\n", ast_getformatname(source), ast_getformatname(dest)); return NULL; } if (tmp) { tmp->next = malloc(sizeof(*tmp)); tmp = tmp->next; } else tmp = malloc(sizeof(*tmp)); if (!tmp) { ast_log(LOG_WARNING, "Out of memory\n"); if (tmpr) ast_translator_free_path(tmpr); return NULL; } /* Set the root, if it doesn't exist yet... */ if (!tmpr) tmpr = tmp; tmp->next = NULL; tmp->nextin = tmp->nextout = ast_tv(0, 0); tmp->step = tr_matrix[source][dest].step; tmp->state = tmp->step->newpvt(); if (!tmp->state) { ast_log(LOG_WARNING, "Failed to build translator step from %d to %d\n", source, dest); ast_translator_free_path(tmpr); return NULL; } /* Keep going if this isn't the final destination */ source = tmp->step->dstfmt; } return tmpr; }
int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size) { int x; struct ast_format format; size_t total_len, slen; const char *formatname; memset(buf, 0, size); total_len = size; buf[0] = '('; total_len--; for (x = 0; x < AST_CODEC_PREF_SIZE; x++) { if (total_len <= 0) break; if (!(ast_codec_pref_index(pref, x, &format))) break; if ((formatname = ast_getformatname(&format))) { slen = strlen(formatname); if (slen > total_len) break; strncat(buf, formatname, total_len - 1); /* safe */ total_len -= slen; } if (total_len && x < AST_CODEC_PREF_SIZE - 1 && ast_codec_pref_index(pref, x + 1, &format)) { strncat(buf, "|", total_len - 1); /* safe */ total_len--; } } if (total_len) { strncat(buf, ")", total_len - 1); /* safe */ total_len--; } return size - total_len; }
static int pcm_write(struct ast_filestream *fs, struct ast_frame *f) { int res; if (f->frametype != AST_FRAME_VOICE) { ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); return -1; } if (ast_format_cmp(&f->subclass.format, &fs->fmt->format) == AST_FORMAT_CMP_NOT_EQUAL) { ast_log(LOG_WARNING, "Asked to write incompatible format frame (%s)!\n", ast_getformatname(&f->subclass.format)); return -1; } #ifdef REALTIME_WRITE if (s->fmt->format == AST_FORMAT_ALAW) { struct pcm_desc *pd = (struct pcm_desc *)fs->_private; struct stat stat_buf; unsigned long cur_time = get_time(); unsigned long fpos = ( cur_time - pd->start_time ) * 8; /* 8 bytes per msec */ /* Check if we have written to this position yet. If we have, then increment pos by one frame * for some degree of protection against receiving packets in the same clock tick. */ fstat(fileno(fs->f), &stat_buf ); if (stat_buf.st_size > fpos ) fpos += f->datalen; /* Incrementing with the size of this current frame */ if (stat_buf.st_size < fpos) { /* fill the gap with 0x55 rather than 0. */ char buf[1024]; unsigned long cur, to_write; cur = stat_buf.st_size; if (fseek(fs->f, cur, SEEK_SET) < 0) { ast_log( LOG_WARNING, "Cannot seek in file: %s\n", strerror(errno) ); return -1; } memset(buf, 0x55, 512); while (cur < fpos) { to_write = fpos - cur; if (to_write > sizeof(buf)) to_write = sizeof(buf); fwrite(buf, 1, to_write, fs->f); cur += to_write; } } if (fseek(s->f, fpos, SEEK_SET) < 0) { ast_log( LOG_WARNING, "Cannot seek in file: %s\n", strerror(errno) ); return -1; } } #endif /* REALTIME_WRITE */ if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) { ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno)); return -1; } return 0; }
static int h264_write(struct ast_filestream *s, struct ast_frame *f) { int res; unsigned int ts; unsigned short len; int mark; if (f->frametype != AST_FRAME_VIDEO) { ast_log(LOG_WARNING, "Asked to write non-video frame!\n"); return -1; } mark = (f->subclass.codec & 0x1) ? 0x8000 : 0; if ((f->subclass.codec & ~0x1) != AST_FORMAT_H264) { ast_log(LOG_WARNING, "Asked to write non-h264 frame (%s)!\n", ast_getformatname(f->subclass.codec)); return -1; } ts = htonl(f->samples); if ((res = fwrite(&ts, 1, sizeof(ts), s->f)) != sizeof(ts)) { ast_log(LOG_WARNING, "Bad write (%d/4): %s\n", res, strerror(errno)); return -1; } len = htons(f->datalen | mark); if ((res = fwrite(&len, 1, sizeof(len), s->f)) != sizeof(len)) { ast_log(LOG_WARNING, "Bad write (%d/2): %s\n", res, strerror(errno)); return -1; } if ((res = fwrite(f->data.ptr, 1, f->datalen, s->f)) != f->datalen) { ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno)); return -1; } return 0; }
int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f) { struct ast_frame *begin_frame = f, *duped_frame = NULL, *frame_ptr; unsigned int x; /* In some cases, we can be passed a frame which has no data in it, but * which has a positive number of samples defined. Once such situation is * when a jitter buffer is in use and the jitter buffer interpolates a frame. * The frame it produces has data set to NULL, datalen set to 0, and samples * set to either 160 or 240. */ if (!f->data) { return 0; } if (f->subclass != AST_FORMAT_SLINEAR) { if (sf->trans && f->subclass != sf->format) { ast_translator_free_path(sf->trans); sf->trans = NULL; } if (!sf->trans) { if ((sf->trans = ast_translator_build_path(AST_FORMAT_SLINEAR, f->subclass)) == NULL) { ast_log(LOG_WARNING, "Cannot build a path from %s to slin\n", ast_getformatname(f->subclass)); return 0; } else { sf->format = f->subclass; } } if (!(begin_frame = ast_translate(sf->trans, f, 0))) return 0; duped_frame = ast_frdup(begin_frame); ast_frfree(begin_frame); if (!duped_frame) return 0; } else { if (!(duped_frame = ast_frdup(f))) return 0; } x = 0; AST_LIST_TRAVERSE(&sf->queue, frame_ptr, frame_list) x++; AST_LIST_INSERT_TAIL(&sf->queue, duped_frame, frame_list); sf->size += duped_frame->samples; return x; }
/*! \brief CLI "show translation" command handler */ static int show_translation(int fd, int argc, char *argv[]) { #define SHOW_TRANS 11 int x, y, z; char line[80]; if (argc > 4) return RESULT_SHOWUSAGE; ast_mutex_lock(&list_lock); if (argv[2] && !strcasecmp(argv[2],"recalc")) { z = argv[3] ? atoi(argv[3]) : 1; if (z <= 0) { ast_cli(fd," C'mon let's be serious here... defaulting to 1.\n"); z = 1; } if (z > MAX_RECALC) { ast_cli(fd," Maximum limit of recalc exceeded by %d, truncating value to %d\n",z-MAX_RECALC,MAX_RECALC); z = MAX_RECALC; } ast_cli(fd," Recalculating Codec Translation (number of sample seconds: %d)\n\n",z); rebuild_matrix(z); } ast_cli(fd, " Translation times between formats (in milliseconds)\n"); ast_cli(fd, " Source Format (Rows) Destination Format(Columns)\n\n"); for (x = -1; x < SHOW_TRANS; x++) { /* next 2 lines run faster than using strcpy() */ line[0] = ' '; line[1] = '\0'; for (y=-1;y<SHOW_TRANS;y++) { if (x >= 0 && y >= 0 && tr_matrix[x][y].step) snprintf(line + strlen(line), sizeof(line) - strlen(line), " %5d", tr_matrix[x][y].cost >= 99999 ? tr_matrix[x][y].cost-99999 : tr_matrix[x][y].cost); else if (((x == -1 && y >= 0) || (y == -1 && x >= 0))) { snprintf(line + strlen(line), sizeof(line) - strlen(line), " %5s", ast_getformatname(1<<(x+y+1)) ); } else if (x != -1 && y != -1) { snprintf(line + strlen(line), sizeof(line) - strlen(line), " -"); } else { snprintf(line + strlen(line), sizeof(line) - strlen(line), " "); } } snprintf(line + strlen(line), sizeof(line) - strlen(line), "\n"); ast_cli(fd, line); } ast_mutex_unlock(&list_lock); return RESULT_SUCCESS; }
static int show_image_formats(int fd, int argc, char *argv[]) { #define FORMAT "%10s %10s %50s %10s\n" #define FORMAT2 "%10s %10s %50s %10s\n" struct ast_imager *i; if (argc != 3) return RESULT_SHOWUSAGE; ast_cli(fd, FORMAT, "Name", "Extensions", "Description", "Format"); i = list; while(i) { ast_cli(fd, FORMAT2, i->name, i->exts, i->desc, ast_getformatname(i->format)); i = i->next; }; return RESULT_SUCCESS; }
static int phone_setup(struct ast_channel *ast) { struct phone_pvt *p; p = ast->pvt->pvt; ioctl(p->fd, PHONE_CPT_STOP); /* Nothing to answering really, just start recording */ if (ast->pvt->rawreadformat == AST_FORMAT_G723_1) { /* Prefer g723 */ ioctl(p->fd, PHONE_REC_STOP); if (p->lastinput != AST_FORMAT_G723_1) { p->lastinput = AST_FORMAT_G723_1; if (ioctl(p->fd, PHONE_REC_CODEC, G723_63)) { ast_log(LOG_WARNING, "Failed to set codec to g723.1\n"); return -1; } } } else if (ast->pvt->rawreadformat == AST_FORMAT_SLINEAR) { ioctl(p->fd, PHONE_REC_STOP); if (p->lastinput != AST_FORMAT_SLINEAR) { p->lastinput = AST_FORMAT_SLINEAR; if (ioctl(p->fd, PHONE_REC_CODEC, LINEAR16)) { ast_log(LOG_WARNING, "Failed to set codec to signed linear 16\n"); return -1; } } } else if (ast->pvt->rawreadformat == AST_FORMAT_ULAW) { ioctl(p->fd, PHONE_REC_STOP); if (p->lastinput != AST_FORMAT_ULAW) { p->lastinput = AST_FORMAT_ULAW; if (ioctl(p->fd, PHONE_REC_CODEC, ULAW)) { ast_log(LOG_WARNING, "Failed to set codec to uLaw\n"); return -1; } } } else { ast_log(LOG_WARNING, "Can't do format %s\n", ast_getformatname(ast->pvt->rawreadformat)); return -1; } if (ioctl(p->fd, PHONE_REC_START)) { ast_log(LOG_WARNING, "Failed to start recording\n"); return -1; } //set the DTMF times (the default is too short) ioctl(p->fd, PHONE_SET_TONE_ON_TIME, 300); ioctl(p->fd, PHONE_SET_TONE_OFF_TIME, 200); return 0; }
int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f) { struct ast_frame *frame, *frame_ptr; if (!f) { return 0; } if (f->subclass != AST_FORMAT_SLINEAR) { if (sf->trans && f->subclass != sf->format) { ast_translator_free_path(sf->trans); sf->trans = NULL; } if (!sf->trans) { if ((sf->trans = ast_translator_build_path(AST_FORMAT_SLINEAR, f->subclass)) == NULL) { ast_log(LOG_WARNING, "Cannot build a path from %s to slin\n", ast_getformatname(f->subclass)); return 0; } else { sf->format = f->subclass; } } } if (sf->trans) { frame = ast_translate(sf->trans, f, 0); } else { frame = ast_frdup(f); } if (frame) { int x = 0; for (frame_ptr = sf->queue; frame_ptr && frame_ptr->next; frame_ptr=frame_ptr->next) { x++; } if (frame_ptr) { frame_ptr->next = frame; } else { sf->queue = frame; } frame->next = NULL; sf->size += frame->datalen; return x; } return 0; }
static int vox_write(struct ast_filestream *s, struct ast_frame *f) { int res; if (f->frametype != AST_FRAME_VOICE) { ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); return -1; } if (f->subclass.codec != AST_FORMAT_ADPCM) { ast_log(LOG_WARNING, "Asked to write non-ADPCM frame (%s)!\n", ast_getformatname(f->subclass.codec)); return -1; } if ((res = fwrite(f->data.ptr, 1, f->datalen, s->f)) != f->datalen) { ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno)); return -1; } return 0; }
static int wav_write(struct ast_filestream *s, struct ast_frame *f) { int len; int size; struct wavg_desc *fs = (struct wavg_desc *)s->_private; if (f->frametype != AST_FRAME_VOICE) { ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); return -1; } if (f->subclass.format.id != AST_FORMAT_GSM) { ast_log(LOG_WARNING, "Asked to write non-GSM frame (%s)!\n", ast_getformatname(&f->subclass.format)); return -1; } /* XXX this might fail... if the input is a multiple of MSGSM_FRAME_SIZE * we assume it is already in the correct format. */ if (!(f->datalen % MSGSM_FRAME_SIZE)) { size = MSGSM_FRAME_SIZE; fs->secondhalf = 0; } else { size = GSM_FRAME_SIZE; } for (len = 0; len < f->datalen ; len += size) { int res; unsigned char *src, msdata[MSGSM_FRAME_SIZE]; if (fs->secondhalf) { /* second half of raw gsm to be converted */ memcpy(s->buf + GSM_FRAME_SIZE, f->data.ptr + len, GSM_FRAME_SIZE); conv66((unsigned char *) s->buf, msdata); src = msdata; fs->secondhalf = 0; } else if (size == GSM_FRAME_SIZE) { /* first half of raw gsm */ memcpy(s->buf, f->data.ptr + len, GSM_FRAME_SIZE); src = NULL; /* nothing to write */ fs->secondhalf = 1; } else { /* raw msgsm data */ src = f->data.ptr + len; } if (src && (res = fwrite(src, 1, MSGSM_FRAME_SIZE, s->f)) != MSGSM_FRAME_SIZE) { ast_log(LOG_WARNING, "Bad write (%d/65): %s\n", res, strerror(errno)); return -1; } update_header(s->f); /* XXX inefficient! */ } return 0; }
static int generic_write(struct ast_filestream *fs, struct ast_frame *f, enum ast_format_id id) { int res; if (f->frametype != AST_FRAME_VOICE) { ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); return -1; } if (f->subclass.format.id != id) { ast_log(LOG_WARNING, "Asked to write non-slinear frame (%s)!\n", ast_getformatname(&f->subclass.format)); return -1; } if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) { ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno)); return -1; } return 0; }
static int siren14write(struct ast_filestream *fs, struct ast_frame *f) { int res; if (f->frametype != AST_FRAME_VOICE) { ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); return -1; } if (f->subclass.format.id != AST_FORMAT_SIREN14) { ast_log(LOG_WARNING, "Asked to write non-Siren14 frame (%s)!\n", ast_getformatname(&f->subclass.format)); return -1; } if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) { ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno)); return -1; } return 0; }
static int g729_write(struct ast_filestream *fs, struct ast_frame *f) { int res; if (f->frametype != AST_FRAME_VOICE) { ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); return -1; } if (f->subclass.codec != AST_FORMAT_G729A) { ast_log(LOG_WARNING, "Asked to write non-G729 frame (%s)!\n", ast_getformatname(f->subclass.codec)); return -1; } if (f->datalen % 10) { ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 10\n", f->datalen); return -1; } if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) { ast_log(LOG_WARNING, "Bad write (%d/10): %s\n", res, strerror(errno)); return -1; } return 0; }
/*! \brief Add format/lang pairs to the array embedded in the sound object */ static int add_format_information_cb(void *obj, void *arg, int flags) { char *language = obj; struct lang_format_info *args = arg; struct ast_format format; RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy); RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup); if (!sounds_index) { return CMP_STOP; } cap = ast_media_get_format_cap(sounds_index, args->filename, language); if (!cap) { return CMP_STOP; } ast_format_cap_iter_start(cap); while (!ast_format_cap_iter_next(cap, &format)) { struct ast_json *lang_format_pair; const char *format_name = ast_getformatname(&format); if (!ast_strlen_zero(args->format_filter) && strcmp(args->format_filter, format_name)) { continue; } lang_format_pair = ast_json_pack("{s: s, s: s}", "language", language, "format", format_name); if (!lang_format_pair) { ast_format_cap_iter_end(cap); return CMP_STOP; } ast_json_array_append(args->format_list, lang_format_pair); } ast_format_cap_iter_end(cap); return 0; }
/*! * \brief Write audio data from a frame to an OGG/Vorbis filestream. * \param fs An OGG/Vorbis filestream. * \param f A frame containing audio to be written to the filestream. * \return -1 if there was an error, 0 on success. */ static int ogg_vorbis_write(struct ast_filestream *fs, struct ast_frame *f) { int i; float **buffer; short *data; struct ogg_vorbis_desc *s = (struct ogg_vorbis_desc *) fs->_private; if (!s->writing) { ast_log(LOG_ERROR, "This stream is not set up for writing!\n"); return -1; } if (f->frametype != AST_FRAME_VOICE) { ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); return -1; } if (f->subclass.format.id != AST_FORMAT_SLINEAR) { ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%s)!\n", ast_getformatname(&f->subclass.format)); return -1; } if (!f->datalen) return -1; data = (short *) f->data.ptr; buffer = vorbis_analysis_buffer(&s->vd, f->samples); for (i = 0; i < f->samples; i++) buffer[0][i] = (double)data[i] / 32768.0; vorbis_analysis_wrote(&s->vd, f->samples); write_stream(s, fs->f); s->writing_pcm_pos += f->samples; return 0; }
static int gsm_write(struct ast_filestream *fs, struct ast_frame *f) { int res; unsigned char gsm[2*GSM_FRAME_SIZE]; if (f->frametype != AST_FRAME_VOICE) { ast_log(LOG_WARNING, "Asked to write non-voice frame!\n"); return -1; } if (f->subclass.format.id != AST_FORMAT_GSM) { ast_log(LOG_WARNING, "Asked to write non-GSM frame (%s)!\n", ast_getformatname(&f->subclass.format)); return -1; } if (!(f->datalen % 65)) { /* This is in MSGSM format, need to be converted */ int len=0; while(len < f->datalen) { conv65(f->data.ptr + len, gsm); if ((res = fwrite(gsm, 1, 2*GSM_FRAME_SIZE, fs->f)) != 2*GSM_FRAME_SIZE) { ast_log(LOG_WARNING, "Bad write (%d/66): %s\n", res, strerror(errno)); return -1; } len += 65; } } else { if (f->datalen % GSM_FRAME_SIZE) { ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 33\n", f->datalen); return -1; } if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) { ast_log(LOG_WARNING, "Bad write (%d/33): %s\n", res, strerror(errno)); return -1; } } return 0; }
static void print_frame(struct ast_frame *frame) { switch (frame->frametype) { case AST_FRAME_DTMF_END: ast_verbose("FrameType: DTMF END\n"); ast_verbose("Digit: %d\n", frame->subclass.integer); break; case AST_FRAME_VOICE: ast_verbose("FrameType: VOICE\n"); ast_verbose("Codec: %s\n", ast_getformatname(&frame->subclass.format)); ast_verbose("MS: %ld\n", frame->len); ast_verbose("Samples: %d\n", frame->samples); ast_verbose("Bytes: %d\n", frame->datalen); break; case AST_FRAME_VIDEO: ast_verbose("FrameType: VIDEO\n"); ast_verbose("Codec: %s\n", ast_getformatname(&frame->subclass.format)); ast_verbose("MS: %ld\n", frame->len); ast_verbose("Samples: %d\n", frame->samples); ast_verbose("Bytes: %d\n", frame->datalen); break; case AST_FRAME_CONTROL: ast_verbose("FrameType: CONTROL\n"); switch ((enum ast_control_frame_type) frame->subclass.integer) { case AST_CONTROL_HANGUP: ast_verbose("SubClass: HANGUP\n"); break; case AST_CONTROL_RING: ast_verbose("SubClass: RING\n"); break; case AST_CONTROL_RINGING: ast_verbose("SubClass: RINGING\n"); break; case AST_CONTROL_ANSWER: ast_verbose("SubClass: ANSWER\n"); break; case AST_CONTROL_BUSY: ast_verbose("SubClass: BUSY\n"); break; case AST_CONTROL_TAKEOFFHOOK: ast_verbose("SubClass: TAKEOFFHOOK\n"); break; case AST_CONTROL_OFFHOOK: ast_verbose("SubClass: OFFHOOK\n"); break; case AST_CONTROL_CONGESTION: ast_verbose("SubClass: CONGESTION\n"); break; case AST_CONTROL_FLASH: ast_verbose("SubClass: FLASH\n"); break; case AST_CONTROL_WINK: ast_verbose("SubClass: WINK\n"); break; case AST_CONTROL_OPTION: ast_verbose("SubClass: OPTION\n"); break; case AST_CONTROL_RADIO_KEY: ast_verbose("SubClass: RADIO KEY\n"); break; case AST_CONTROL_RADIO_UNKEY: ast_verbose("SubClass: RADIO UNKEY\n"); break; case AST_CONTROL_PROGRESS: ast_verbose("SubClass: PROGRESS\n"); break; case AST_CONTROL_PROCEEDING: ast_verbose("SubClass: PROCEEDING\n"); break; case AST_CONTROL_HOLD: ast_verbose("SubClass: HOLD\n"); break; case AST_CONTROL_UNHOLD: ast_verbose("SubClass: UNHOLD\n"); break; case AST_CONTROL_VIDUPDATE: ast_verbose("SubClass: VIDUPDATE\n"); break; case _XXX_AST_CONTROL_T38: ast_verbose("SubClass: XXX T38\n"); break; case AST_CONTROL_SRCUPDATE: ast_verbose("SubClass: SRCUPDATE\n"); break; case AST_CONTROL_TRANSFER: ast_verbose("SubClass: TRANSFER\n"); break; case AST_CONTROL_CONNECTED_LINE: ast_verbose("SubClass: CONNECTED LINE\n"); break; case AST_CONTROL_REDIRECTING: ast_verbose("SubClass: REDIRECTING\n"); break; case AST_CONTROL_T38_PARAMETERS: ast_verbose("SubClass: T38 PARAMETERS\n"); break; case AST_CONTROL_CC: ast_verbose("SubClass: CC\n"); break; case AST_CONTROL_SRCCHANGE: ast_verbose("SubClass: SRCCHANGE\n"); break; case AST_CONTROL_READ_ACTION: ast_verbose("SubClass: READ ACTION\n"); break; case AST_CONTROL_AOC: ast_verbose("SubClass: AOC\n"); break; case AST_CONTROL_MCID: ast_verbose("SubClass: MCID\n"); break; case AST_CONTROL_INCOMPLETE: ast_verbose("SubClass: INCOMPLETE\n"); break; case AST_CONTROL_END_OF_Q: ast_verbose("SubClass: END_OF_Q\n"); break; case AST_CONTROL_UPDATE_RTP_PEER: ast_verbose("SubClass: UPDATE_RTP_PEER\n"); break; } if (frame->subclass.integer == -1) { ast_verbose("SubClass: %d\n", frame->subclass.integer); } ast_verbose("Bytes: %d\n", frame->datalen); break; case AST_FRAME_NULL: ast_verbose("FrameType: NULL\n"); break; case AST_FRAME_IAX: ast_verbose("FrameType: IAX\n"); break; case AST_FRAME_TEXT: ast_verbose("FrameType: TXT\n"); break; case AST_FRAME_IMAGE: ast_verbose("FrameType: IMAGE\n"); break; case AST_FRAME_HTML: ast_verbose("FrameType: HTML\n"); break; case AST_FRAME_CNG: ast_verbose("FrameType: CNG\n"); break; case AST_FRAME_MODEM: ast_verbose("FrameType: MODEM\n"); break; case AST_FRAME_DTMF_BEGIN: ast_verbose("FrameType: DTMF BEGIN\n"); ast_verbose("Digit: %d\n", frame->subclass.integer); break; } ast_verbose("Src: %s\n", ast_strlen_zero(frame->src) ? "NOT PRESENT" : frame->src); ast_verbose("\n"); }
AST_DECLARE_APP_ARGS(args, AST_APP_ARG(argInitialSilence); AST_APP_ARG(argGreeting); AST_APP_ARG(argAfterGreetingSilence); AST_APP_ARG(argTotalAnalysisTime); AST_APP_ARG(argMinimumWordLength); AST_APP_ARG(argBetweenWordsSilence); AST_APP_ARG(argMaximumNumberOfWords); AST_APP_ARG(argSilenceThreshold); AST_APP_ARG(argMaximumWordLength); ); ast_verb(3, "AMD: %s %s %s (Fmt: %s)\n", chan->name, S_COR(chan->caller.ani.number.valid, chan->caller.ani.number.str, "(N/A)"), S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, "(N/A)"), ast_getformatname(chan->readformat)); /* Lets parse the arguments. */ if (!ast_strlen_zero(parse)) { /* Some arguments have been passed. Lets parse them and overwrite the defaults. */ AST_STANDARD_APP_ARGS(args, parse); if (!ast_strlen_zero(args.argInitialSilence)) initialSilence = atoi(args.argInitialSilence); if (!ast_strlen_zero(args.argGreeting)) greeting = atoi(args.argGreeting); if (!ast_strlen_zero(args.argAfterGreetingSilence)) afterGreetingSilence = atoi(args.argAfterGreetingSilence); if (!ast_strlen_zero(args.argTotalAnalysisTime)) totalAnalysisTime = atoi(args.argTotalAnalysisTime); if (!ast_strlen_zero(args.argMinimumWordLength)) minimumWordLength = atoi(args.argMinimumWordLength);
int AST_OPTIONAL_API_NAME(ast_adsi_transmit_message_full)(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait) { unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL }; int msglens[5], msgtypes[5], newdatamode = (ast_channel_adsicpe(chan) & ADSI_FLAG_DATAMODE), res, x, waitforswitch = 0; struct ast_format writeformat; struct ast_format readformat; ast_format_copy(&writeformat, ast_channel_writeformat(chan)); ast_format_copy(&readformat, ast_channel_readformat(chan)); for (x = 0; x < msglen; x += (msg[x+1]+2)) { if (msg[x] == ADSI_SWITCH_TO_DATA) { ast_debug(1, "Switch to data is sent!\n"); waitforswitch++; newdatamode = ADSI_FLAG_DATAMODE; } if (msg[x] == ADSI_SWITCH_TO_VOICE) { ast_debug(1, "Switch to voice is sent!\n"); waitforswitch++; newdatamode = 0; } } msgs[0] = msg; msglens[0] = msglen; msgtypes[0] = msgtype; if (msglen > 253) { ast_log(LOG_WARNING, "Can't send ADSI message of %d bytes, too large\n", msglen); return -1; } ast_stopstream(chan); if (ast_set_write_format_by_id(chan, AST_FORMAT_ULAW)) { ast_log(LOG_WARNING, "Unable to set write format to ULAW\n"); return -1; } if (ast_set_read_format_by_id(chan, AST_FORMAT_ULAW)) { ast_log(LOG_WARNING, "Unable to set read format to ULAW\n"); if (writeformat.id) { if (ast_set_write_format(chan, &writeformat)) { ast_log(LOG_WARNING, "Unable to restore write format to %s\n", ast_getformatname(&writeformat)); } } return -1; } res = __adsi_transmit_messages(chan, msgs, msglens, msgtypes); if (dowait) { ast_debug(1, "Wait for switch is '%d'\n", waitforswitch); while (waitforswitch-- && ((res = ast_waitfordigit(chan, 1000)) > 0)) { res = 0; ast_debug(1, "Waiting for 'B'...\n"); } } if (!res) { ast_channel_adsicpe_set(chan, (ast_channel_adsicpe(chan) & ~ADSI_FLAG_DATAMODE) | newdatamode); } if (writeformat.id) { ast_set_write_format(chan, &writeformat); } if (readformat.id) { ast_set_read_format(chan, &readformat); } if (!res) { res = ast_safe_sleep(chan, 100 ); } return res; }
static int do_waiting(struct ast_channel *chan, int maxsilence) { struct ast_frame *f; int totalsilence = 0; int dspsilence = 0; int gotsilence = 0; static int silencethreshold = 128; int rfmt = 0; int res = 0; struct ast_dsp *sildet; /* silence detector dsp */ time_t start, now; time(&start); rfmt = chan->readformat; /* Set to linear mode */ res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); return -1; } sildet = ast_dsp_new(); /* Create the silence detector */ if (!sildet) { ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } ast_dsp_set_threshold(sildet, silencethreshold); /* Await silence... */ f = NULL; for(;;) { res = ast_waitfor(chan, 2000); if (!res) { ast_log(LOG_WARNING, "One waitfor failed, trying another\n"); /* Try one more time in case of masq */ res = ast_waitfor(chan, 2000); if (!res) { ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name); res = -1; } } if (res < 0) { f = NULL; break; } f = ast_read(chan); if (!f) break; if (f->frametype == AST_FRAME_VOICE) { dspsilence = 0; ast_dsp_silence(sildet, f, &dspsilence); if (dspsilence) { totalsilence = dspsilence; time(&start); } else { totalsilence = 0; } if (totalsilence >= maxsilence) { if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Exiting with %dms silence > %dms required\n", totalsilence, maxsilence); /* Ended happily with silence */ gotsilence = 1; pbx_builtin_setvar_helper(chan, "WAITSTATUS", "SILENCE"); ast_log(LOG_DEBUG, "WAITSTATUS was set to SILENCE\n"); ast_frfree(f); break; } else if ( difftime(time(&now),start) >= maxsilence/1000 ) { pbx_builtin_setvar_helper(chan, "WAITSTATUS", "TIMEOUT"); ast_log(LOG_DEBUG, "WAITSTATUS was set to TIMEOUT\n"); ast_frfree(f); break; } } ast_frfree(f); } if (rfmt && ast_set_read_format(chan, rfmt)) { ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name); } ast_dsp_free(sildet); return gotsilence; }
static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart, int timeout, int wait_for_silence) { struct ast_frame *f = NULL; int dsptime = 0; struct ast_format rfmt; int res = 0; struct ast_dsp *sildet; /* silence detector dsp */ time_t now; /*Either silence or noise calc depending on wait_for_silence flag*/ int (*ast_dsp_func)(struct ast_dsp*, struct ast_frame*, int*) = wait_for_silence ? ast_dsp_silence : ast_dsp_noise; ast_format_copy(&rfmt, &chan->readformat); /* Set to linear mode */ if ((res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) < 0) { ast_log(LOG_WARNING, "Unable to set channel to linear mode, giving up\n"); return -1; } /* Create the silence detector */ if (!(sildet = ast_dsp_new())) { ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); return -1; } ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE)); /* Await silence... */ for (;;) { /* Start with no silence received */ dsptime = 0; res = ast_waitfor(chan, timereqd); /* Must have gotten a hangup; let's exit */ if (res < 0) { pbx_builtin_setvar_helper(chan, "WAITSTATUS", "HANGUP"); break; } /* We waited and got no frame; sounds like digital silence or a muted digital channel */ if (res == 0) { dsptime = timereqd; } else { /* Looks like we did get a frame, so let's check it out */ if (!(f = ast_read(chan))) { pbx_builtin_setvar_helper(chan, "WAITSTATUS", "HANGUP"); break; } if (f->frametype == AST_FRAME_VOICE) { ast_dsp_func(sildet, f, &dsptime); } ast_frfree(f); } ast_verb(6, "Got %dms %s < %dms required\n", dsptime, wait_for_silence ? "silence" : "noise", timereqd); if (dsptime >= timereqd) { ast_verb(3, "Exiting with %dms %s >= %dms required\n", dsptime, wait_for_silence ? "silence" : "noise", timereqd); /* Ended happily with silence */ res = 1; pbx_builtin_setvar_helper(chan, "WAITSTATUS", wait_for_silence ? "SILENCE" : "NOISE"); ast_debug(1, "WAITSTATUS was set to %s\n", wait_for_silence ? "SILENCE" : "NOISE"); break; } if (timeout && (difftime(time(&now), waitstart) >= timeout)) { pbx_builtin_setvar_helper(chan, "WAITSTATUS", "TIMEOUT"); ast_debug(1, "WAITSTATUS was set to TIMEOUT\n"); res = 0; break; } } if (rfmt.id && ast_set_read_format(chan, &rfmt)) { ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(&rfmt), chan->name); } ast_dsp_free(sildet); return res; }
/*! \brief Use the list of translators to build a translation matrix */ static void rebuild_matrix(int samples) { struct ast_translator *t; int changed; int x,y,z; if (option_debug) ast_log(LOG_DEBUG, "Resetting translation matrix\n"); memset(tr_matrix, 0, sizeof(tr_matrix)); t = list; while(t) { if(samples) calc_cost(t, samples); if (!tr_matrix[t->srcfmt][t->dstfmt].step || tr_matrix[t->srcfmt][t->dstfmt].cost > t->cost) { tr_matrix[t->srcfmt][t->dstfmt].step = t; tr_matrix[t->srcfmt][t->dstfmt].cost = t->cost; } t = t->next; } do { changed = 0; /* Don't you just love O(N^3) operations? */ for (x=0; x< MAX_FORMAT; x++) /* For each source format */ for (y=0; y < MAX_FORMAT; y++) /* And each destination format */ if (x != y) /* Except ourselves, of course */ for (z=0; z < MAX_FORMAT; z++) /* And each format it might convert to */ if ((x!=z) && (y!=z)) /* Don't ever convert back to us */ if (tr_matrix[x][y].step && /* We can convert from x to y */ tr_matrix[y][z].step && /* And from y to z and... */ (!tr_matrix[x][z].step || /* Either there isn't an x->z conversion */ (tr_matrix[x][y].cost + tr_matrix[y][z].cost < /* Or we're cheaper than the existing */ tr_matrix[x][z].cost) /* solution */ )) { /* We can get from x to z via y with a cost that is the sum of the transition from x to y and from y to z */ tr_matrix[x][z].step = tr_matrix[x][y].step; tr_matrix[x][z].cost = tr_matrix[x][y].cost + tr_matrix[y][z].cost; if (option_debug) ast_log(LOG_DEBUG, "Discovered %d cost path from %s to %s, via %d\n", tr_matrix[x][z].cost, ast_getformatname(x), ast_getformatname(z), y); changed++; } } while (changed); }
/*! \brief Get packet size for codec */ struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, struct ast_format *format) { int x, idx = -1, framems = 0; struct ast_format_list fmt = { { 0, }, }; size_t f_len = 0; const struct ast_format_list *f_list = ast_format_list_get(&f_len); for (x = 0; x < f_len; x++) { if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) { fmt = f_list[x]; idx = x; break; } } if (idx < 0) { ast_log(AST_LOG_WARNING, "Format %s unknown; unable to get preferred codec packet size\n", ast_getformatname(format)); ast_format_list_destroy(f_list); return fmt; } for (x = 0; x < f_len; x++) { if (pref->order[x] == (idx + 1)) { framems = pref->framing[x]; break; } } /* size validation */ if (!framems) framems = f_list[idx].def_ms; if (f_list[idx].inc_ms && framems % f_list[idx].inc_ms) /* avoid division by zero */ framems -= framems % f_list[idx].inc_ms; if (framems < f_list[idx].min_ms) framems = f_list[idx].min_ms; if (framems > f_list[idx].max_ms) framems = f_list[idx].max_ms; fmt.cur_ms = framems; ast_format_list_destroy(f_list); return fmt; }
/*! \brief unregister codec translator */ int ast_unregister_translator(struct ast_translator *t) { char tmp[80]; struct ast_translator *u, *ul = NULL; ast_mutex_lock(&list_lock); u = list; while(u) { if (u == t) { if (ul) ul->next = u->next; else list = u->next; if (option_verbose > 1) ast_verbose(VERBOSE_PREFIX_2 "Unregistered translator '%s' from format %s to %s\n", term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt)); break; } ul = u; u = u->next; } rebuild_matrix(0); ast_mutex_unlock(&list_lock); return (u ? 0 : -1); }
static int func_channel_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len) { int ret = 0; char tmp[512]; struct ast_format_cap *tmpcap; if (!strcasecmp(data, "audionativeformat")) { if ((tmpcap = ast_format_cap_get_type(chan->nativeformats, AST_FORMAT_TYPE_AUDIO))) { ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len); tmpcap = ast_format_cap_destroy(tmpcap); } } else if (!strcasecmp(data, "videonativeformat")) { if ((tmpcap = ast_format_cap_get_type(chan->nativeformats, AST_FORMAT_TYPE_VIDEO))) { ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len); tmpcap = ast_format_cap_destroy(tmpcap); } } else if (!strcasecmp(data, "audioreadformat")) { ast_copy_string(buf, ast_getformatname(&chan->readformat), len); } else if (!strcasecmp(data, "audiowriteformat")) { ast_copy_string(buf, ast_getformatname(&chan->writeformat), len); #ifdef CHANNEL_TRACE } else if (!strcasecmp(data, "trace")) { ast_channel_lock(chan); ast_copy_string(buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len); ast_channel_unlock(chan); #endif } else if (!strcasecmp(data, "tonezone") && chan->zone) locked_copy_string(chan, buf, chan->zone->country, len); else if (!strcasecmp(data, "language")) locked_copy_string(chan, buf, chan->language, len); else if (!strcasecmp(data, "musicclass")) locked_copy_string(chan, buf, chan->musicclass, len); else if (!strcasecmp(data, "name")) { locked_copy_string(chan, buf, chan->name, len); } else if (!strcasecmp(data, "parkinglot")) locked_copy_string(chan, buf, chan->parkinglot, len); else if (!strcasecmp(data, "state")) locked_copy_string(chan, buf, ast_state2str(chan->_state), len); else if (!strcasecmp(data, "channeltype")) locked_copy_string(chan, buf, chan->tech->type, len); else if (!strcasecmp(data, "accountcode")) locked_copy_string(chan, buf, chan->accountcode, len); else if (!strcasecmp(data, "checkhangup")) { ast_channel_lock(chan); ast_copy_string(buf, ast_check_hangup(chan) ? "1" : "0", len); ast_channel_unlock(chan); } else if (!strcasecmp(data, "peeraccount")) locked_copy_string(chan, buf, chan->peeraccount, len); else if (!strcasecmp(data, "hangupsource")) locked_copy_string(chan, buf, chan->hangupsource, len); else if (!strcasecmp(data, "appname") && chan->appl) locked_copy_string(chan, buf, chan->appl, len); else if (!strcasecmp(data, "appdata") && chan->data) locked_copy_string(chan, buf, chan->data, len); else if (!strcasecmp(data, "exten") && chan->data) locked_copy_string(chan, buf, chan->exten, len); else if (!strcasecmp(data, "context") && chan->data) locked_copy_string(chan, buf, chan->context, len); else if (!strcasecmp(data, "userfield") && chan->data) locked_copy_string(chan, buf, chan->userfield, len); else if (!strcasecmp(data, "channame") && chan->data) locked_copy_string(chan, buf, chan->name, len); else if (!strcasecmp(data, "linkedid")) { ast_channel_lock(chan); if (ast_strlen_zero(chan->linkedid)) { /* fall back on the channel's uniqueid if linkedid is unset */ ast_copy_string(buf, chan->uniqueid, len); } else { ast_copy_string(buf, chan->linkedid, len); } ast_channel_unlock(chan); } else if (!strcasecmp(data, "peer")) { struct ast_channel *p; ast_channel_lock(chan); p = ast_bridged_channel(chan); if (p || chan->tech || chan->cdr) /* dummy channel? if so, we hid the peer name in the language */ ast_copy_string(buf, (p ? p->name : ""), len); else { /* a dummy channel can still pass along bridged peer info via the BRIDGEPEER variable */ const char *pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER"); if (!ast_strlen_zero(pname)) ast_copy_string(buf, pname, len); /* a horrible kludge, but... how else? */ else buf[0] = 0; } ast_channel_unlock(chan); } else if (!strcasecmp(data, "uniqueid")) { locked_copy_string(chan, buf, chan->uniqueid, len); } else if (!strcasecmp(data, "transfercapability")) { locked_copy_string(chan, buf, transfercapability_table[chan->transfercapability & 0x1f], len); } else if (!strcasecmp(data, "callgroup")) { char groupbuf[256]; locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), chan->callgroup), len); } else if (!strcasecmp(data, "pickupgroup")) { char groupbuf[256]; locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), chan->pickupgroup), len); } else if (!strcasecmp(data, "amaflags")) { char amabuf[256]; snprintf(amabuf,sizeof(amabuf), "%d", chan->amaflags); locked_copy_string(chan, buf, amabuf, len); } else if (!strncasecmp(data, "secure_bridge_", 14)) { struct ast_datastore *ds; ast_channel_lock(chan); if ((ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) { struct ast_secure_call_store *encrypt = ds->data; if (!strcasecmp(data, "secure_bridge_signaling")) { snprintf(buf, len, "%s", encrypt->signaling ? "1" : ""); } else if (!strcasecmp(data, "secure_bridge_media")) { snprintf(buf, len, "%s", encrypt->media ? "1" : ""); } } ast_channel_unlock(chan); } else if (!chan->tech || !chan->tech->func_channel_read || chan->tech->func_channel_read(chan, function, data, buf, len)) { ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data); ret = -1; } return ret; }
static int nv_detectfax_exec(struct ast_channel *chan, const char *data) { int res = 0; char tmp[256] = "\0"; char *p = NULL; char *waitstr = NULL; char *options = NULL; char *silstr = NULL; char *minstr = NULL; char *maxstr = NULL; struct ast_frame *fr = NULL; struct ast_frame *fr2 = NULL; int notsilent = 0; struct timeval start = {0, 0}, end = {0, 0}; int waitdur = 4; int sildur = 1000; int mindur = 100; int maxdur = -1; int skipanswer = 0; int noextneeded = 0; int ignoredtmf = 0; int ignorefax = 0; int ignoretalk = 0; int x = 0; struct ast_format* origrformat = NULL; int features = 0; time_t timeout = 0; struct ast_dsp *dsp = NULL; struct ast_format_cap *cap; struct ast_format linearFormat; /* linear format capabilities */ ast_format_set(&linearFormat, AST_FORMAT_SLINEAR, 0); cap = ast_format_cap_alloc_nolock(); ast_format_cap_add(cap, &linearFormat); /* done */ pbx_builtin_setvar_helper(chan, "FAX_DETECTED", ""); pbx_builtin_setvar_helper(chan, "FAXEXTEN", ""); pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", ""); pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ""); if (data || !ast_strlen_zero(data)) { strncpy(tmp, data, sizeof(tmp)-1); } p = tmp; waitstr = strsep(&p, ","); options = strsep(&p, ","); silstr = strsep(&p, ","); minstr = strsep(&p, ","); maxstr = strsep(&p, ","); if (waitstr) { if ((sscanf(waitstr, "%d", &x) == 1) && (x > 0)) waitdur = x; } if (options) { if (strchr(options, 'n')) skipanswer = 1; if (strchr(options, 'x')) noextneeded = 1; if (strchr(options, 'd')) ignoredtmf = 1; if (strchr(options, 'f')) ignorefax = 1; if (strchr(options, 't')) ignoretalk = 1; } if (silstr) { if ((sscanf(silstr, "%d", &x) == 1) && (x > 0)) sildur = x; } if (minstr) { if ((sscanf(minstr, "%d", &x) == 1) && (x > 0)) mindur = x; } if (maxstr) { if ((sscanf(maxstr, "%d", &x) == 1) && (x > 0)) maxdur = x; } ast_log(LOG_DEBUG, "Preparing detect of fax (waitdur=%dms, sildur=%dms, mindur=%dms, maxdur=%dms)\n", waitdur, sildur, mindur, maxdur); // LOCAL_USER_ADD(u); // if (chan->_state != AST_STATE_UP && !skipanswer) { if (ast_channel_state(chan) != AST_STATE_UP && !skipanswer) { /* Otherwise answer unless we're supposed to send this while on-hook */ res = ast_answer(chan); } if (!res) { // origrformat = chan->readformat; origrformat = ast_channel_readformat(chan); // if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR))) if ((res = ast_set_read_format_from_cap(chan, cap)) ){ ast_log(LOG_WARNING, "Unable to set read format to linear!\n"); } } if (!(dsp = ast_dsp_new())) { ast_log(LOG_WARNING, "Unable to allocate DSP!\n"); res = -1; } if (dsp) { if (!ignoretalk) ; /* features |= DSP_FEATURE_SILENCE_SUPPRESS; */ if (!ignorefax) features |= DSP_FEATURE_FAX_DETECT; //if (!ignoredtmf) features |= DSP_FEATURE_DIGIT_DETECT; ast_dsp_set_threshold(dsp, 256); ast_dsp_set_features(dsp, features | DSP_DIGITMODE_RELAXDTMF); ast_dsp_set_digitmode(dsp, DSP_DIGITMODE_DTMF); } if (!res) { if (waitdur > 0) timeout = time(NULL) + (time_t)waitdur; while(ast_waitfor(chan, -1) > -1) { if (waitdur > 0 && time(NULL) > timeout) { res = 0; break; } fr = ast_read(chan); if (!fr) { ast_log(LOG_DEBUG, "Got hangup\n"); res = -1; break; } fr2 = ast_dsp_process(chan, dsp, fr); if (!fr2) { ast_log(LOG_WARNING, "Bad DSP received (what happened?)\n"); fr2 = fr; } if (fr2->frametype == AST_FRAME_DTMF) { if (fr2->subclass.integer == 'f' && !ignorefax) { /* Fax tone -- Handle and return NULL */ ast_log(LOG_DEBUG, "Fax detected on %s\n", ast_channel_name(chan)); ast_log(LOG_DEBUG, "Fax detected on %s\n", ast_channel_name(chan)); if (strcmp(ast_channel_exten(chan), "fax")) { ast_log(LOG_NOTICE, "Redirecting %s to fax extension\n", ast_channel_name(chan)); pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "1"); pbx_builtin_setvar_helper(chan,"FAXEXTEN",ast_channel_exten(chan)); if (ast_exists_extension(chan, ast_channel_context(chan), "fax", 1, ast_channel_caller(chan)->id.number.str)) { /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ // strncpy(ast_channel_exten(chan), "fax", sizeof(ast_channel_exten(chan))-1); // chan->priority = 0; ast_channel_exten_set(chan, "fax"); ast_channel_priority_set(chan, 0); } else ast_log(LOG_WARNING, "Fax detected, but no fax extension\n"); } else ast_log(LOG_WARNING, "Already in a fax extension, not redirecting\n"); res = 0; ast_frfree(fr); break; } else if (!ignoredtmf) { ast_log(LOG_DEBUG, "DTMF detected on %s\n", ast_channel_name(chan)); char t[2]; t[0] = fr2->subclass.integer; t[1] = '\0'; if (noextneeded || ast_canmatch_extension(chan, ast_channel_context(chan), t, 1, ast_channel_caller(chan)->id.number.str)) { pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "1"); /* They entered a valid extension, or might be anyhow */ if (noextneeded) { ast_log(LOG_NOTICE, "DTMF received (not matching to exten)\n"); res = 0; } else { ast_log(LOG_NOTICE, "DTMF received (matching to exten)\n"); res = fr2->subclass.integer; } ast_frfree(fr); break; } else ast_log(LOG_DEBUG, "Valid extension requested and DTMF did not match\n"); } // } else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR) && !ignoretalk) { } else if ((fr->frametype == AST_FRAME_VOICE) && ( ast_format_cap_iscompatible(cap, &fr->subclass.format)) && !ignoretalk) { int totalsilence; int ms; res = ast_dsp_silence(dsp, fr, &totalsilence); if (res && (totalsilence > sildur)) { /* We've been quiet a little while */ if (notsilent) { /* We had heard some talking */ gettimeofday(&end, NULL); ms = (end.tv_sec - start.tv_sec) * 1000; ms += (end.tv_usec - start.tv_usec) / 1000; ms -= sildur; if (ms < 0) ms = 0; if ((ms > mindur) && ((maxdur < 0) || (ms < maxdur))) { char ms_str[10]; ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms); ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", ast_channel_name(chan)); /* Save detected talk time (in milliseconds) */ sprintf(ms_str, "%d", ms); pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str); if (ast_exists_extension(chan, ast_channel_context(chan), "talk", 1, ast_channel_caller(chan)->id.number.str)) { // strncpy(ast_channel_exten(chan), "talk", sizeof(ast_channel_exten(chan)) - 1); // chan->priority = 0; ast_channel_exten_set(chan, "talk"); ast_channel_priority_set(chan, 0); } else ast_log(LOG_WARNING, "Talk detected, but no talk extension\n"); res = 0; ast_frfree(fr); break; } else ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms); notsilent = 0; } } else { if (!notsilent) { /* Heard some audio, mark the begining of the token */ gettimeofday(&start, NULL); ast_log(LOG_DEBUG, "Start of voice token!\n"); notsilent = 1; } } } ast_frfree(fr); } } else ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(chan)); if (res > -1) { if (origrformat && ast_set_read_format(chan, origrformat)) { ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", ast_channel_name(chan), ast_getformatname(origrformat)); } } if (dsp) ast_dsp_free(dsp); // LOCAL_USER_REMOVE(u); ast_format_cap_destroy(cap); return res; }
static int serialize_showchan(struct ast_channel *c, char *buf, size_t size) { struct timeval now; long elapsed_seconds = 0; int hour = 0, min = 0, sec = 0; char nf[256]; char cgrp[256]; char pgrp[256]; struct ast_str *write_transpath = ast_str_alloca(256); struct ast_str *read_transpath = ast_str_alloca(256); now = ast_tvnow(); memset(buf, 0, size); if (!c) return 0; if (ast_channel_cdr(c)) { elapsed_seconds = now.tv_sec - ast_channel_cdr(c)->start.tv_sec; hour = elapsed_seconds / 3600; min = (elapsed_seconds % 3600) / 60; sec = elapsed_seconds % 60; } snprintf(buf,size, "Name= %s\n" "Type= %s\n" "UniqueID= %s\n" "LinkedID= %s\n" "CallerIDNum= %s\n" "CallerIDName= %s\n" "ConnectedLineIDNum= %s\n" "ConnectedLineIDName=%s\n" "DNIDDigits= %s\n" "RDNIS= %s\n" "Parkinglot= %s\n" "Language= %s\n" "State= %s (%d)\n" "Rings= %d\n" "NativeFormat= %s\n" "WriteFormat= %s\n" "ReadFormat= %s\n" "RawWriteFormat= %s\n" "RawReadFormat= %s\n" "WriteTranscode= %s %s\n" "ReadTranscode= %s %s\n" "1stFileDescriptor= %d\n" "Framesin= %d %s\n" "Framesout= %d %s\n" "TimetoHangup= %ld\n" "ElapsedTime= %dh%dm%ds\n" "DirectBridge= %s\n" "IndirectBridge= %s\n" "Context= %s\n" "Extension= %s\n" "Priority= %d\n" "CallGroup= %s\n" "PickupGroup= %s\n" "Application= %s\n" "Data= %s\n" "Blocking_in= %s\n", ast_channel_name(c), ast_channel_tech(c)->type, ast_channel_uniqueid(c), ast_channel_linkedid(c), S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "(N/A)"), S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "(N/A)"), S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "(N/A)"), S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "(N/A)"), S_OR(ast_channel_dialed(c)->number.str, "(N/A)"), S_COR(ast_channel_redirecting(c)->from.number.valid, ast_channel_redirecting(c)->from.number.str, "(N/A)"), ast_channel_parkinglot(c), ast_channel_language(c), ast_state2str(ast_channel_state(c)), ast_channel_state(c), ast_channel_rings(c), ast_getformatname_multiple(nf, sizeof(nf), ast_channel_nativeformats(c)), ast_getformatname(ast_channel_writeformat(c)), ast_getformatname(ast_channel_readformat(c)), ast_getformatname(ast_channel_rawwriteformat(c)), ast_getformatname(ast_channel_rawreadformat(c)), ast_channel_writetrans(c) ? "Yes" : "No", ast_translate_path_to_str(ast_channel_writetrans(c), &write_transpath), ast_channel_readtrans(c) ? "Yes" : "No", ast_translate_path_to_str(ast_channel_readtrans(c), &read_transpath), ast_channel_fd(c, 0), ast_channel_fin(c) & ~DEBUGCHAN_FLAG, (ast_channel_fin(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", ast_channel_fout(c) & ~DEBUGCHAN_FLAG, (ast_channel_fout(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", (long)ast_channel_whentohangup(c)->tv_sec, hour, min, sec, ast_channel_internal_bridged_channel(c) ? ast_channel_name(ast_channel_internal_bridged_channel(c)) : "<none>", ast_bridged_channel(c) ? ast_channel_name(ast_bridged_channel(c)) : "<none>", ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_print_group(cgrp, sizeof(cgrp), ast_channel_callgroup(c)), ast_print_group(pgrp, sizeof(pgrp), ast_channel_pickupgroup(c)), ast_channel_appl(c) ? ast_channel_appl(c) : "(N/A)", ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)") : "(None)", (ast_test_flag(ast_channel_flags(c), AST_FLAG_BLOCKING) ? ast_channel_blockproc(c) : "(Not Blocking)")); return 0; }