int ast_format_cache_set(struct ast_format *format) { SCOPED_AO2WRLOCK(lock, formats); struct ast_format *old_format; ast_assert(format != NULL); if (ast_strlen_zero(ast_format_get_name(format))) { return -1; } old_format = ao2_find(formats, ast_format_get_name(format), OBJ_SEARCH_KEY | OBJ_NOLOCK); if (old_format) { ao2_unlink_flags(formats, old_format, OBJ_NOLOCK); } ao2_link_flags(formats, format, OBJ_NOLOCK); set_cached_format(ast_format_get_name(format), format); ast_verb(2, "%s cached format with name '%s'\n", old_format ? "Updated" : "Created", ast_format_get_name(format)); ao2_cleanup(old_format); return 0; }
static int format_cmp_cb(void *obj, void *arg, int flags) { const struct ast_format *left = obj; const struct ast_format *right = arg; const char *right_key = arg; int cmp; switch (flags & OBJ_SEARCH_MASK) { case OBJ_SEARCH_OBJECT: right_key = ast_format_get_name(right); /* Fall through */ case OBJ_SEARCH_KEY: cmp = strcasecmp(ast_format_get_name(left), right_key); break; case OBJ_SEARCH_PARTIAL_KEY: cmp = strncasecmp(ast_format_get_name(left), right_key, strlen(right_key)); break; default: ast_assert(0); cmp = 0; break; } if (cmp) { return 0; } return CMP_MATCH; }
/*! \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; int idx; RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup); 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; } for (idx = 0; idx < ast_format_cap_count(cap); idx++) { struct ast_format *format = ast_format_cap_get_format(cap, idx); struct ast_json *lang_format_pair; if (!ast_strlen_zero(args->format_filter) && strcmp(args->format_filter, ast_format_get_name(format))) { ao2_ref(format, -1); continue; } lang_format_pair = ast_json_pack("{s: s, s: s}", "language", language, "format", ast_format_get_name(format)); if (!lang_format_pair) { ao2_ref(format, -1); return CMP_STOP; } ast_json_array_append(args->format_list, lang_format_pair); ao2_ref(format, -1); } return 0; }
static struct ast_frame *g719read(struct ast_filestream *s, int *whennext) { size_t res; /* Send a frame from the file to the appropriate channel */ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (res) { ast_log(LOG_WARNING, "Short read of %s data (expected %d bytes, read %zu): %s\n", ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res, strerror(errno)); } return NULL; } *whennext = s->fr.samples = BYTES_TO_SAMPLES(res); return &s->fr; }
static int format_hash_cb(const void *obj, int flags) { const struct ast_format *format; const char *key; switch (flags & OBJ_SEARCH_MASK) { case OBJ_SEARCH_KEY: key = obj; return ast_str_case_hash(key); case OBJ_SEARCH_OBJECT: format = obj; return ast_str_case_hash(ast_format_get_name(format)); default: /* Hash can only work on something with a full key. */ ast_assert(0); return 0; } }
static struct ast_frame *g726_read(struct ast_filestream *s, int *whennext) { size_t res; struct g726_desc *fs = (struct g726_desc *)s->_private; /* Send a frame from the file to the appropriate channel */ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, frame_size[fs->rate]); s->fr.samples = 8 * FRAME_TIME; if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (res) { ast_log(LOG_WARNING, "Short read of %s data (expected %d bytes, read %zu): %s\n", ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res, strerror(errno)); } return NULL; } *whennext = s->fr.samples; return &s->fr; }
static struct ast_frame *g723_read(struct ast_filestream *s, int *whennext) { unsigned short size; size_t res; int delay; /* Read the delay for the next packet, and schedule again if necessary */ /* XXX is this ignored ? */ if (fread(&delay, 1, 4, s->f) == 4) delay = ntohl(delay); else delay = -1; if (fread(&size, 1, 2, s->f) != 2) { /* Out of data, or the file is no longer valid. In any case go ahead and stop the stream */ return NULL; } /* Looks like we have a frame to read from here */ size = ntohs(size); if (size > G723_MAX_SIZE) { ast_log(LOG_WARNING, "Size %d is invalid\n", size); /* The file is apparently no longer any good, as we shouldn't ever get frames even close to this size. */ return NULL; } /* Read the data into the buffer */ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, size); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (res) { ast_log(LOG_WARNING, "Short read of %s data (expected %d bytes, read %zu): %s\n", ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res, strerror(errno)); } return NULL; } *whennext = s->fr.samples = 240; return &s->fr; }
unsigned int ast_codec_samples_count(struct ast_frame *frame) { struct ast_codec *codec; unsigned int samples = 0; if ((frame->frametype != AST_FRAME_VOICE) && (frame->frametype != AST_FRAME_VIDEO) && (frame->frametype != AST_FRAME_IMAGE)) { return 0; } codec = ast_format_get_codec(frame->subclass.format); if (codec->samples_count) { samples = codec->samples_count(frame); } else { ast_log(LOG_WARNING, "Unable to calculate samples for codec %s\n", ast_format_get_name(frame->subclass.format)); } ao2_ref(codec, -1); return samples; }
static int serialize_showchan(struct ast_channel *c, char *buf, size_t size) { long elapsed_seconds = 0; int hour = 0, min = 0, sec = 0; struct ast_str *format_buf = ast_str_alloca(64); char cgrp[256]; char pgrp[256]; struct ast_str *write_transpath = ast_str_alloca(256); struct ast_str *read_transpath = ast_str_alloca(256); struct ast_bridge *bridge; memset(buf, 0, size); if (!c) return 0; elapsed_seconds = ast_channel_get_duration(c); hour = elapsed_seconds / 3600; min = (elapsed_seconds % 3600) / 60; sec = elapsed_seconds % 60; ast_channel_lock(c); bridge = ast_channel_get_bridge(c); ast_channel_unlock(c); 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 (%u)\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= %u %s\n" "Framesout= %u %s\n" "TimetoHangup= %ld\n" "ElapsedTime= %dh%dm%ds\n" "BridgeID= %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_format_cap_get_names(ast_channel_nativeformats(c), &format_buf), ast_format_get_name(ast_channel_writeformat(c)), ast_format_get_name(ast_channel_readformat(c)), ast_format_get_name(ast_channel_rawwriteformat(c)), ast_format_get_name(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, bridge ? bridge->uniqueid : "(Not bridged)", 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)")); ao2_cleanup(bridge); return 0; }
static int func_channel_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len) { int ret = 0; struct ast_format_cap *tmpcap; if (!chan) { ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function); return -1; } if (!strcasecmp(data, "audionativeformat")) { tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (tmpcap) { struct ast_str *codec_buf = ast_str_alloca(128); ast_channel_lock(chan); ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_AUDIO); ast_channel_unlock(chan); ast_copy_string(buf, ast_format_cap_get_names(tmpcap, &codec_buf), len); ao2_ref(tmpcap, -1); } } else if (!strcasecmp(data, "videonativeformat")) { tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (tmpcap) { struct ast_str *codec_buf = ast_str_alloca(128); ast_channel_lock(chan); ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO); ast_channel_unlock(chan); ast_copy_string(buf, ast_format_cap_get_names(tmpcap, &codec_buf), len); ao2_ref(tmpcap, -1); } } else if (!strcasecmp(data, "audioreadformat")) { locked_copy_string(chan, buf, ast_format_get_name(ast_channel_readformat(chan)), len); } else if (!strcasecmp(data, "audiowriteformat")) { locked_copy_string(chan, buf, ast_format_get_name(ast_channel_writeformat(chan)), len); #ifdef CHANNEL_TRACE } else if (!strcasecmp(data, "trace")) { locked_copy_string(chan, buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len); #endif } else if (!strcasecmp(data, "tonezone") && ast_channel_zone(chan)) { locked_copy_string(chan, buf, ast_channel_zone(chan)->country, len); } else if (!strcasecmp(data, "dtmf_features")) { if (ast_bridge_features_ds_get_string(chan, buf, len)) { buf[0] = '\0'; } } else if (!strcasecmp(data, "language")) locked_copy_string(chan, buf, ast_channel_language(chan), len); else if (!strcasecmp(data, "musicclass")) locked_copy_string(chan, buf, ast_channel_musicclass(chan), len); else if (!strcasecmp(data, "name")) { locked_copy_string(chan, buf, ast_channel_name(chan), len); } else if (!strcasecmp(data, "parkinglot")) locked_copy_string(chan, buf, ast_channel_parkinglot(chan), len); else if (!strcasecmp(data, "state")) locked_copy_string(chan, buf, ast_state2str(ast_channel_state(chan)), len); else if (!strcasecmp(data, "onhold")) { locked_copy_string(chan, buf, ast_channel_hold_state(chan) == AST_CONTROL_HOLD ? "1" : "0", len); } else if (!strcasecmp(data, "channeltype")) locked_copy_string(chan, buf, ast_channel_tech(chan)->type, len); else if (!strcasecmp(data, "accountcode")) locked_copy_string(chan, buf, ast_channel_accountcode(chan), len); else if (!strcasecmp(data, "checkhangup")) { locked_copy_string(chan, buf, ast_check_hangup(chan) ? "1" : "0", len); } else if (!strcasecmp(data, "peeraccount")) locked_copy_string(chan, buf, ast_channel_peeraccount(chan), len); else if (!strcasecmp(data, "hangupsource")) locked_copy_string(chan, buf, ast_channel_hangupsource(chan), len); else if (!strcasecmp(data, "appname") && ast_channel_appl(chan)) locked_copy_string(chan, buf, ast_channel_appl(chan), len); else if (!strcasecmp(data, "appdata") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_data(chan), len); else if (!strcasecmp(data, "exten") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_exten(chan), len); else if (!strcasecmp(data, "context") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_context(chan), len); else if (!strcasecmp(data, "userfield") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_userfield(chan), len); else if (!strcasecmp(data, "channame") && ast_channel_data(chan)) locked_copy_string(chan, buf, ast_channel_name(chan), len); else if (!strcasecmp(data, "linkedid")) { ast_channel_lock(chan); if (ast_strlen_zero(ast_channel_linkedid(chan))) { /* fall back on the channel's uniqueid if linkedid is unset */ ast_copy_string(buf, ast_channel_uniqueid(chan), len); } else { ast_copy_string(buf, ast_channel_linkedid(chan), len); } ast_channel_unlock(chan); } else if (!strcasecmp(data, "peer")) { struct ast_channel *peer; peer = ast_channel_bridge_peer(chan); if (peer) { /* Only real channels could have a bridge peer this way. */ ast_channel_lock(peer); ast_copy_string(buf, ast_channel_name(peer), len); ast_channel_unlock(peer); ast_channel_unref(peer); } else { buf[0] = '\0'; ast_channel_lock(chan); if (!ast_channel_tech(chan)) { const char *pname; /* * A dummy channel can still pass along bridged peer info * via the BRIDGEPEER variable. * * A horrible kludge, but... how else? */ pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER"); if (!ast_strlen_zero(pname)) { ast_copy_string(buf, pname, len); } } ast_channel_unlock(chan); } } else if (!strcasecmp(data, "uniqueid")) { locked_copy_string(chan, buf, ast_channel_uniqueid(chan), len); } else if (!strcasecmp(data, "transfercapability")) { locked_copy_string(chan, buf, transfercapability_table[ast_channel_transfercapability(chan) & 0x1f], len); } else if (!strcasecmp(data, "callgroup")) { char groupbuf[256]; locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_callgroup(chan)), len); } else if (!strcasecmp(data, "pickupgroup")) { char groupbuf[256]; locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_pickupgroup(chan)), len); } else if (!strcasecmp(data, "namedcallgroup")) { struct ast_str *tmp_str = ast_str_alloca(1024); locked_copy_string(chan, buf, ast_print_namedgroups(&tmp_str, ast_channel_named_callgroups(chan)), len); } else if (!strcasecmp(data, "namedpickupgroup")) { struct ast_str *tmp_str = ast_str_alloca(1024); locked_copy_string(chan, buf, ast_print_namedgroups(&tmp_str, ast_channel_named_pickupgroups(chan)), len); } else if (!strcasecmp(data, "after_bridge_goto")) { ast_bridge_read_after_goto(chan, buf, len); } else if (!strcasecmp(data, "amaflags")) { ast_channel_lock(chan); snprintf(buf, len, "%u", ast_channel_amaflags(chan)); ast_channel_unlock(chan); } else if (!strncasecmp(data, "secure_bridge_", 14)) { struct ast_datastore *ds; buf[0] = '\0'; 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 (!strcasecmp(data, "max_forwards")) { ast_channel_lock(chan); snprintf(buf, len, "%d", ast_max_forwards_get(chan)); ast_channel_unlock(chan); } else if (!ast_channel_tech(chan) || !ast_channel_tech(chan)->func_channel_read || ast_channel_tech(chan)->func_channel_read(chan, function, data, buf, len)) { ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data); ret = -1; } return ret; }
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", ast_channel_name(chan), S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, "(N/A)"), S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "(N/A)"), ast_format_get_name(ast_channel_readformat(chan))); /* 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);
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; RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup); 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; rfmt = ao2_bump(ast_channel_readformat(chan)); if ((res = ast_set_read_format(chan, ast_format_slin)) < 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_debug(1, "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 && ast_set_read_format(chan, rfmt)) { ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_format_get_name(rfmt), ast_channel_name(chan)); } ast_dsp_free(sildet); return res; }
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: 0x%02X '%c'\n", (unsigned)frame->subclass.integer, frame->subclass.integer < ' ' ? ' ' : frame->subclass.integer); break; case AST_FRAME_VOICE: ast_verbose("FrameType: VOICE\n"); ast_verbose("Codec: %s\n", ast_format_get_name(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_format_get_name(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; case AST_CONTROL_PVT_CAUSE_CODE: ast_verbose("SubClass: PVT_CAUSE_CODE\n"); break; case AST_CONTROL_MASQUERADE_NOTIFY: /* Should never happen. */ ast_assert(0); break; case AST_CONTROL_STREAM_STOP: ast_verbose("SubClass: STREAM_STOP\n"); break; case AST_CONTROL_STREAM_SUSPEND: ast_verbose("SubClass: STREAM_SUSPEND\n"); break; case AST_CONTROL_STREAM_RESTART: ast_verbose("SubClass: STREAM_RESTART\n"); break; case AST_CONTROL_STREAM_REVERSE: ast_verbose("SubClass: STREAM_REVERSE\n"); break; case AST_CONTROL_STREAM_FORWARD: ast_verbose("SubClass: STREAM_FORWARD\n"); break; case AST_CONTROL_RECORD_CANCEL: ast_verbose("SubClass: RECORD_CANCEL\n"); break; case AST_CONTROL_RECORD_STOP: ast_verbose("SubClass: RECORD_STOP\n"); break; case AST_CONTROL_RECORD_SUSPEND: ast_verbose("SubClass: RECORD_SUSPEND\n"); break; case AST_CONTROL_RECORD_MUTE: ast_verbose("SubClass: RECORD_MUTE\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: 0x%02X '%c'\n", (unsigned)frame->subclass.integer, frame->subclass.integer < ' ' ? ' ' : frame->subclass.integer); break; case AST_FRAME_BRIDGE_ACTION: ast_verbose("FrameType: Bridge\n"); ast_verbose("SubClass: %d\n", frame->subclass.integer); break; case AST_FRAME_BRIDGE_ACTION_SYNC: ast_verbose("Frametype: Synchronous Bridge\n"); ast_verbose("Subclass: %d\n", frame->subclass.integer); break; } ast_verbose("Src: %s\n", ast_strlen_zero(frame->src) ? "NOT PRESENT" : frame->src); ast_verbose("\n"); }
static int cli_channelstats_print_body(void *obj, void *arg, int flags) { struct ast_sip_cli_context *context = arg; const struct ast_channel_snapshot *snapshot = obj; struct ast_channel *channel = ast_channel_get_by_name(snapshot->name); struct ast_sip_channel_pvt *cpvt = channel ? ast_channel_tech_pvt(channel) : NULL; struct ast_sip_session *session; struct ast_sip_session_media *media; struct ast_rtp_instance *rtp; struct ast_rtp_instance_stats stats; char *print_name = NULL; char *print_time = alloca(32); char codec_in_use[7]; ast_assert(context->output_buffer != NULL); if (!channel) { ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name); return -1; } ast_channel_lock(channel); session = cpvt->session; if (!session) { ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name); ast_channel_unlock(channel); ao2_cleanup(channel); return -1; } media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]; if (!media || !media->rtp) { ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name); ast_channel_unlock(channel); ao2_cleanup(channel); return -1; } rtp = ao2_bump(media->rtp); codec_in_use[0] = '\0'; if (ast_channel_rawreadformat(channel)) { ast_copy_string(codec_in_use, ast_format_get_name(ast_channel_rawreadformat(channel)), sizeof(codec_in_use)); } ast_channel_unlock(channel); print_name = ast_strdupa(snapshot->name); /* Skip the PJSIP/. We know what channel type it is and we need the space. */ print_name += 6; ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32); if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) { ast_str_append(&context->output_buffer, 0, "%s direct media\n", snapshot->name); } else { ast_str_append(&context->output_buffer, 0, " %8.8s %-18.18s %-8.8s %-6.6s %6u%s %6u%s %3u %7.3f %6u%s %6u%s %3u %7.3f %7.3f\n", snapshot->bridgeid, print_name, print_time, codec_in_use, stats.rxcount > 100000 ? stats.rxcount / 1000 : stats.rxcount, stats.rxcount > 100000 ? "K": " ", stats.rxploss > 100000 ? stats.rxploss / 1000 : stats.rxploss, stats.rxploss > 100000 ? "K": " ", stats.rxcount ? (stats.rxploss * 100) / stats.rxcount : 0, MIN(stats.rxjitter, 999.999), stats.txcount > 100000 ? stats.txcount / 1000 : stats.txcount, stats.txcount > 100000 ? "K": " ", stats.txploss > 100000 ? stats.txploss / 1000 : stats.txploss, stats.txploss > 100000 ? "K": " ", stats.txcount ? (stats.txploss * 100) / stats.txcount : 0, MIN(stats.txjitter, 999.999), MIN(stats.normdevrtt, 999.999) ); } ao2_cleanup(rtp); ao2_cleanup(channel); return 0; }
static int transmit_audio(fax_session *s) { int res = -1; struct ast_format *original_read_fmt; struct ast_format *original_write_fmt = NULL; fax_state_t fax; t30_state_t *t30state; struct ast_frame *inf = NULL; int last_state = 0; struct timeval now, start, state_change; enum ast_t38_state t38_state; struct ast_control_t38_parameters t38_parameters = { .version = 0, .max_ifp = 800, .rate = AST_T38_RATE_14400, .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF, .fill_bit_removal = 1, /* * spandsp has API calls to support MMR and JBIG transcoding, but they aren't * implemented quite yet... so don't offer them to the remote endpoint * .transcoding_mmr = 1, * .transcoding_jbig = 1, */ }; /* if in called party mode, try to use T.38 */ if (s->caller_mode == FALSE) { /* check if we are already in T.38 mode (unlikely), or if we can request * a switch... if so, request it now and wait for the result, rather * than starting an audio FAX session that will have to be cancelled */ if ((t38_state = ast_channel_get_t38_state(s->chan)) == T38_STATE_NEGOTIATED) { return 1; } else if ((t38_state != T38_STATE_UNAVAILABLE) && (t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE, (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0))) { /* wait up to five seconds for negotiation to complete */ unsigned int timeout = 5000; int ms; ast_debug(1, "Negotiating T.38 for receive on %s\n", ast_channel_name(s->chan)); while (timeout > 0) { ms = ast_waitfor(s->chan, 1000); if (ms < 0) { ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan)); return -1; } if (!ms) { /* nothing happened */ if (timeout > 0) { timeout -= 1000; continue; } else { ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", ast_channel_name(s->chan)); break; } } if (!(inf = ast_read(s->chan))) { return -1; } if ((inf->frametype == AST_FRAME_CONTROL) && (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) && (inf->datalen == sizeof(t38_parameters))) { struct ast_control_t38_parameters *parameters = inf->data.ptr; switch (parameters->request_response) { case AST_T38_NEGOTIATED: ast_debug(1, "Negotiated T.38 for receive on %s\n", ast_channel_name(s->chan)); res = 1; break; case AST_T38_REFUSED: ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", ast_channel_name(s->chan)); break; default: ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", ast_channel_name(s->chan)); break; } ast_frfree(inf); if (res == 1) { return 1; } else { break; } } ast_frfree(inf); } } } #if SPANDSP_RELEASE_DATE >= 20080725 /* for spandsp shaphots 0.0.6 and higher */ t30state = &fax.t30; #else /* for spandsp release 0.0.5 */ t30state = &fax.t30_state; #endif original_read_fmt = ao2_bump(ast_channel_readformat(s->chan)); res = ast_set_read_format(s->chan, ast_format_slin); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n"); goto done; } original_write_fmt = ao2_bump(ast_channel_writeformat(s->chan)); res = ast_set_write_format(s->chan, ast_format_slin); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n"); goto done; } /* Initialize T30 terminal */ fax_init(&fax, s->caller_mode); /* Setup logging */ set_logging(&fax.logging); set_logging(&t30state->logging); /* Configure terminal */ set_local_info(t30state, s); set_file(t30state, s); set_ecm(t30state, TRUE); fax_set_transmit_on_idle(&fax, TRUE); t30_set_phase_e_handler(t30state, phase_e_handler, s); start = state_change = ast_tvnow(); ast_activate_generator(s->chan, &generator, &fax); while (!s->finished) { inf = NULL; if ((res = ast_waitfor(s->chan, 25)) < 0) { ast_debug(1, "Error waiting for a frame\n"); break; } /* Watchdog */ now = ast_tvnow(); if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) { ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n"); res = -1; break; } if (!res) { /* There was timeout waiting for a frame. Loop around and wait again */ continue; } /* There is a frame available. Get it */ res = 0; if (!(inf = ast_read(s->chan))) { ast_debug(1, "Channel hangup\n"); res = -1; break; } ast_debug(10, "frame %d/%s, len=%d\n", inf->frametype, ast_format_get_name(inf->subclass.format), inf->datalen); /* Check the frame type. Format also must be checked because there is a chance that a frame in old format was already queued before we set channel format to slinear so it will still be received by ast_read */ if (inf->frametype == AST_FRAME_VOICE && (ast_format_cmp(inf->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL)) { if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) { /* I know fax_rx never returns errors. The check here is for good style only */ ast_log(LOG_WARNING, "fax_rx returned error\n"); res = -1; break; } if (last_state != t30state->state) { state_change = ast_tvnow(); last_state = t30state->state; } } else if ((inf->frametype == AST_FRAME_CONTROL) && (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS)) { struct ast_control_t38_parameters *parameters = inf->data.ptr; if (parameters->request_response == AST_T38_NEGOTIATED) { /* T38 switchover completed */ s->t38parameters = *parameters; ast_debug(1, "T38 negotiated, finishing audio loop\n"); res = 1; break; } else if (parameters->request_response == AST_T38_REQUEST_NEGOTIATE) { t38_parameters.request_response = AST_T38_NEGOTIATED; ast_debug(1, "T38 request received, accepting\n"); /* Complete T38 switchover */ ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)); /* Do not break audio loop, wait until channel driver finally acks switchover * with AST_T38_NEGOTIATED */ } } ast_frfree(inf); inf = NULL; } ast_debug(1, "Loop finished, res=%d\n", res); if (inf) ast_frfree(inf); ast_deactivate_generator(s->chan); /* If we are switching to T38, remove phase E handler. Otherwise it will be executed by t30_terminate, display diagnostics and set status variables although no transmittion has taken place yet. */ if (res > 0) { t30_set_phase_e_handler(t30state, NULL, NULL); } t30_terminate(t30state); fax_release(&fax); done: if (original_write_fmt) { if (ast_set_write_format(s->chan, original_write_fmt) < 0) ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", ast_channel_name(s->chan)); ao2_ref(original_write_fmt, -1); } if (original_read_fmt) { if (ast_set_read_format(s->chan, original_read_fmt) < 0) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", ast_channel_name(s->chan)); ao2_ref(original_read_fmt, -1); } return res; } static int transmit_t38(fax_session *s) { int res = 0; t38_terminal_state_t t38; struct ast_frame *inf = NULL; int last_state = 0; struct timeval now, start, state_change, last_frame; t30_state_t *t30state; t38_core_state_t *t38state; #if SPANDSP_RELEASE_DATE >= 20080725 /* for spandsp shaphots 0.0.6 and higher */ t30state = &t38.t30; t38state = &t38.t38_fe.t38; #else /* for spandsp releases 0.0.5 */ t30state = &t38.t30_state; t38state = &t38.t38; #endif /* Initialize terminal */ memset(&t38, 0, sizeof(t38)); if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) { ast_log(LOG_WARNING, "Unable to start T.38 termination.\n"); res = -1; goto disable_t38; } t38_set_max_datagram_size(t38state, s->t38parameters.max_ifp); if (s->t38parameters.fill_bit_removal) { t38_set_fill_bit_removal(t38state, TRUE); } if (s->t38parameters.transcoding_mmr) { t38_set_mmr_transcoding(t38state, TRUE); } if (s->t38parameters.transcoding_jbig) { t38_set_jbig_transcoding(t38state, TRUE); } /* Setup logging */ set_logging(&t38.logging); set_logging(&t30state->logging); set_logging(&t38state->logging); /* Configure terminal */ set_local_info(t30state, s); set_file(t30state, s); set_ecm(t30state, TRUE); t30_set_phase_e_handler(t30state, phase_e_handler, s); now = start = state_change = ast_tvnow(); while (!s->finished) { inf = NULL; if ((res = ast_waitfor(s->chan, 25)) < 0) { ast_debug(1, "Error waiting for a frame\n"); break; } last_frame = now; /* Watchdog */ now = ast_tvnow(); if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) { ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n"); res = -1; break; } t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000)); if (!res) { /* There was timeout waiting for a frame. Loop around and wait again */ continue; } /* There is a frame available. Get it */ res = 0; if (!(inf = ast_read(s->chan))) { ast_debug(1, "Channel hangup\n"); res = -1; break; } ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass.integer, inf->datalen); if (inf->frametype == AST_FRAME_MODEM && inf->subclass.integer == AST_MODEM_T38) { t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno); if (last_state != t30state->state) { state_change = ast_tvnow(); last_state = t30state->state; } } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) { struct ast_control_t38_parameters *parameters = inf->data.ptr; if (parameters->request_response == AST_T38_TERMINATED) { ast_debug(1, "T38 down, finishing\n"); break; } } ast_frfree(inf); inf = NULL; } ast_debug(1, "Loop finished, res=%d\n", res); if (inf) ast_frfree(inf); t30_terminate(t30state); t38_terminal_release(&t38); disable_t38: /* if we are not the caller, it's our job to shut down the T.38 * session when the FAX transmisson is complete. */ if ((s->caller_mode == FALSE) && (ast_channel_get_t38_state(s->chan) == T38_STATE_NEGOTIATED)) { struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, }; if (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0) { /* wait up to five seconds for negotiation to complete */ unsigned int timeout = 5000; int ms; ast_debug(1, "Shutting down T.38 on %s\n", ast_channel_name(s->chan)); while (timeout > 0) { ms = ast_waitfor(s->chan, 1000); if (ms < 0) { ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(s->chan)); return -1; } if (!ms) { /* nothing happened */ if (timeout > 0) { timeout -= 1000; continue; } else { ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 shutdown.\n", ast_channel_name(s->chan)); break; } } if (!(inf = ast_read(s->chan))) { return -1; } if ((inf->frametype == AST_FRAME_CONTROL) && (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) && (inf->datalen == sizeof(t38_parameters))) { struct ast_control_t38_parameters *parameters = inf->data.ptr; switch (parameters->request_response) { case AST_T38_TERMINATED: ast_debug(1, "Shut down T.38 on %s\n", ast_channel_name(s->chan)); break; case AST_T38_REFUSED: ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", ast_channel_name(s->chan)); break; default: ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", ast_channel_name(s->chan)); break; } ast_frfree(inf); break; } ast_frfree(inf); } } } return res; }