static struct ast_channel *rec_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause) { struct ast_channel *chan; struct ast_format format; const char *conf_name = data; chan = ast_channel_alloc(1, AST_STATE_UP, NULL, NULL, NULL, NULL, NULL, NULL, 0, "CBRec/conf-%s-uid-%d", conf_name, (int) ast_random()); if (!chan) { return NULL; } if (ast_channel_add_bridge_role(chan, "recorder")) { ast_channel_release(chan); return NULL; } ast_format_set(&format, AST_FORMAT_SLINEAR, 0); ast_channel_tech_set(chan, conf_record_get_tech()); ast_format_cap_add_all(ast_channel_nativeformats(chan)); ast_format_copy(ast_channel_writeformat(chan), &format); ast_format_copy(ast_channel_rawwriteformat(chan), &format); ast_format_copy(ast_channel_readformat(chan), &format); ast_format_copy(ast_channel_rawreadformat(chan), &format); return chan; }
static void jb_get_and_deliver(struct ast_channel *chan) { struct ast_jb *jb = ast_channel_jb(chan); const struct ast_jb_impl *jbimpl = jb->impl; void *jbobj = jb->jbobj; struct ast_frame *f, finterp = { .frametype = AST_FRAME_VOICE, }; long now; int interpolation_len, res; now = get_now(jb, NULL); jb->next = jbimpl->next(jbobj); if (now < jb->next) { jb_framelog("\tJB_GET {now=%ld}: now < next=%ld\n", now, jb->next); return; } while (now >= jb->next) { interpolation_len = ast_codec_interp_len(&jb->last_format); res = jbimpl->get(jbobj, &f, now, interpolation_len); switch (res) { case AST_JB_IMPL_OK: /* deliver the frame */ ast_write(chan, f); case AST_JB_IMPL_DROP: jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n", now, jb_get_actions[res], f->ts, f->len); ast_format_copy(&jb->last_format, &f->subclass.format); ast_frfree(f); break; case AST_JB_IMPL_INTERP: /* interpolate a frame */ f = &finterp; ast_format_copy(&f->subclass.format, &jb->last_format); f->samples = interpolation_len * 8; f->src = "JB interpolation"; f->delivery = ast_tvadd(jb->timebase, ast_samp2tv(jb->next, 1000)); f->offset = AST_FRIENDLY_OFFSET; /* deliver the interpolated frame */ ast_write(chan, f); jb_framelog("\tJB_GET {now=%ld}: Interpolated frame with len=%d\n", now, interpolation_len); break; case AST_JB_IMPL_NOFRAME: ast_log(LOG_WARNING, "AST_JB_IMPL_NOFRAME is returned from the %s jb when now=%ld >= next=%ld, jbnext=%ld!\n", jbimpl->name, now, jb->next, jbimpl->next(jbobj)); jb_framelog("\tJB_GET {now=%ld}: No frame for now!?\n", now); return; default: ast_log(LOG_ERROR, "This should never happen!\n"); ast_assert("JB type unknown" == NULL); break; } jb->next = jbimpl->next(jbobj); } }
/*! \brief Prepend codec to list */ void ast_codec_pref_prepend(struct ast_codec_pref *pref, struct ast_format *format, int only_if_existing) { int x, newindex = 0; size_t f_len = 0; const struct ast_format_list *f_list = ast_format_list_get(&f_len); /* First step is to get the codecs "index number" */ for (x = 0; x < f_len; x++) { if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) { newindex = x + 1; break; } } /* Done if its unknown */ if (!newindex) { ast_format_list_destroy(f_list); return; } /* Now find any existing occurrence, or the end */ for (x = 0; x < AST_CODEC_PREF_SIZE; x++) { if (!pref->order[x] || pref->order[x] == newindex) break; } /* If we failed to find any occurrence, set to the end */ if (x == AST_CODEC_PREF_SIZE) { --x; } if (only_if_existing && !pref->order[x]) { ast_format_list_destroy(f_list); return; } /* Move down to make space to insert - either all the way to the end, or as far as the existing location (which will be overwritten) */ for (; x > 0; x--) { pref->order[x] = pref->order[x - 1]; pref->framing[x] = pref->framing[x - 1]; ast_format_copy(&pref->formats[x], &pref->formats[x - 1]); } /* And insert the new entry */ pref->order[0] = newindex; pref->framing[0] = 0; /* ? */ ast_format_copy(&pref->formats[0], format); ast_format_list_destroy(f_list); }
/*! \brief Append all codecs to a preference list, without distrubing existing order */ void ast_codec_pref_append_all(struct ast_codec_pref *pref) { int x, y, found; size_t f_len = 0; const struct ast_format_list *f_list = ast_format_list_get(&f_len); /* leave any existing entries, and don't create duplicates (e.g. allow=ulaw,all) */ for (x = 0; x < f_len; x++) { /* x = codec to add */ found = 0; for (y = 0; y < f_len; y++) { /* y = scan of existing preferences */ if (!pref->order[y]) { break; } if (x + 1 == pref->order[y]) { found = 1; break; } } if (found) { continue; } for (; y < f_len; y++) { /* add x to the end of y */ if (!pref->order[y]) { pref->order[y] = x + 1; ast_format_copy(&pref->formats[y], &f_list[x].format); break; } } } }
static void *playtones_alloc(struct ast_channel *chan, void *params) { struct playtones_def *pd = params; struct playtones_state *ps = NULL; if (!(ps = ast_calloc(1, sizeof(*ps)))) { return NULL; } ast_format_copy(&ps->origwfmt, ast_channel_writeformat(chan)); if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR)) { ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", ast_channel_name(chan)); playtones_release(NULL, ps); ps = NULL; } else { ps->vol = pd->vol; ps->reppos = pd->reppos; ps->nitems = pd->nitems; ps->items = pd->items; ps->oldnpos = -1; } /* Let interrupts interrupt :) */ if (pd->interruptible) { ast_set_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT); } else { ast_clear_flag(ast_channel_flags(chan), AST_FLAG_WRITE_INT); } return ps; }
void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right) { size_t f_len; const const struct ast_format_list *f_list = ast_format_list_get(&f_len); int x, differential = (int) 'A', mem; char *from, *to; /* TODO re-evaluate this function. It is using the order of the formats specified * in the global format list in a way that may not be safe. */ if (right) { from = pref->order; to = buf; mem = size; } else { to = pref->order; from = buf; mem = AST_CODEC_PREF_SIZE; } memset(to, 0, mem); for (x = 0; x < AST_CODEC_PREF_SIZE; x++) { if (!from[x]) { break; } to[x] = right ? (from[x] + differential) : (from[x] - differential); if (!right && to[x] && (to[x] < f_len)) { ast_format_copy(&pref->formats[x], &f_list[to[x]-1].format); } } ast_format_list_destroy(f_list); }
/*! \brief Remove codec from pref list */ void ast_codec_pref_remove(struct ast_codec_pref *pref, struct ast_format *format) { struct ast_codec_pref oldorder; int x, y = 0; size_t f_len = 0; const const struct ast_format_list *f_list; if (!pref->order[0]) { return; } f_list = ast_format_list_get(&f_len); memcpy(&oldorder, pref, sizeof(oldorder)); memset(pref, 0, sizeof(*pref)); for (x = 0; x < f_len; x++) { if (!oldorder.order[x]) { break; } if (ast_format_cmp(&f_list[oldorder.order[x]-1].format, format) == AST_FORMAT_CMP_NOT_EQUAL) { pref->order[y] = oldorder.order[x]; ast_format_copy(&pref->formats[y], &oldorder.formats[x]); pref->framing[y++] = oldorder.framing[x]; } } ast_format_list_destroy(f_list); }
/*! \brief Append codec to list */ int ast_codec_pref_append(struct ast_codec_pref *pref, struct ast_format *format) { int x, newindex = 0; size_t f_len = 0; const struct ast_format_list *f_list = ast_format_list_get(&f_len); ast_codec_pref_remove(pref, format); for (x = 0; x < f_len; x++) { if (ast_format_cmp(&f_list[x].format, format) == AST_FORMAT_CMP_EQUAL) { newindex = x + 1; break; } } if (newindex) { for (x = 0; x < f_len; x++) { if (!pref->order[x]) { pref->order[x] = newindex; ast_format_copy(&pref->formats[x], format); break; } } } ast_format_list_destroy(f_list); return x; }
static int measurenoise(struct ast_channel *chan, int ms, char *who) { int res=0; int mssofar; int noise=0; int samples=0; int x; short *foo; struct timeval start; struct ast_frame *f; struct ast_format rformat; ast_format_copy(&rformat, ast_channel_readformat(chan)); if (ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR)) { ast_log(LOG_NOTICE, "Unable to set to linear mode!\n"); return -1; } start = ast_tvnow(); for(;;) { mssofar = ast_tvdiff_ms(ast_tvnow(), start); if (mssofar > ms) break; res = ast_waitfor(chan, ms - mssofar); if (res < 1) break; f = ast_read(chan); if (!f) { res = -1; break; } if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) { foo = (short *)f->data.ptr; for (x=0; x<f->samples; x++) { noise += abs(foo[x]); samples++; } } ast_frfree(f); } if (rformat.id) { if (ast_set_read_format(chan, &rformat)) { ast_log(LOG_NOTICE, "Unable to restore original format!\n"); return -1; } } if (res < 0) return res; if (!samples) { ast_log(LOG_NOTICE, "No samples were received from the other side!\n"); return -1; } ast_debug(1, "%s: Noise: %d, samples: %d, avg: %d\n", who, noise, samples, noise / samples); return (noise / samples); }
struct ast_format *ast_codec_pref_index(struct ast_codec_pref *pref, int idx, struct ast_format *result) { if ((idx >= 0) && (idx < sizeof(pref->order)) && pref->formats[idx].id) { ast_format_copy(result, &pref->formats[idx]); } else { ast_format_clear(result); return NULL; } return result; }
static int find_best_byid_cb(void *obj, void *arg, int flag) { struct ast_format *format = obj; struct byid_data *data = arg; if (data->id != format->id) { return 0; } if (!data->result->id || (ast_format_rate(data->result) < ast_format_rate(format))) { ast_format_copy(data->result, format); } return 0; }
int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const struct ast_format *format, struct ast_format *result) { struct ast_format *f; struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap; f = ao2_find(tmp_cap->formats, (struct ast_format *) format, OBJ_POINTER | tmp_cap->nolock); if (f) { ast_format_copy(result, f); ao2_ref(f, -1); return 1; } ast_format_clear(result); return 0; }
/*! \brief Called when we want to place a call somewhere, but not actually call it... yet */ static struct ast_channel *bridge_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, void *data, int *cause) { struct bridge_pvt *p = NULL; struct ast_format slin; /* Try to allocate memory for our very minimal pvt structure */ if (!(p = ao2_alloc(sizeof(*p), NULL))) { return NULL; } /* Try to grab two Asterisk channels to use as input and output channels */ if (!(p->input = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", requestor ? requestor->linkedid : NULL, 0, "Bridge/%p-input", p))) { ao2_ref(p, -1); return NULL; } if (!(p->output = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", requestor ? requestor->linkedid : NULL, 0, "Bridge/%p-output", p))) { p->input = ast_channel_release(p->input); ao2_ref(p, -1); return NULL; } /* Setup parameters on both new channels */ p->input->tech = p->output->tech = &bridge_tech; ao2_ref(p, 2); p->input->tech_pvt = p->output->tech_pvt = p; ast_format_set(&slin, AST_FORMAT_SLINEAR, 0); ast_format_cap_add(p->input->nativeformats, &slin); ast_format_cap_add(p->output->nativeformats, &slin); ast_format_copy(&p->input->readformat, &slin); ast_format_copy(&p->output->readformat, &slin); ast_format_copy(&p->input->rawreadformat, &slin); ast_format_copy(&p->output->rawreadformat, &slin); ast_format_copy(&p->input->writeformat, &slin); ast_format_copy(&p->output->writeformat, &slin); ast_format_copy(&p->input->rawwriteformat, &slin); ast_format_copy(&p->output->rawwriteformat, &slin); ast_answer(p->output); ast_answer(p->input); /* remove the reference from the alloc. The channels now own the pvt. */ ao2_ref(p, -1); return p->input; }
static int dahdiscan_exec(struct ast_channel *chan, const char *data) { const char *spec = "DAHDI"; struct ast_flags flags; struct spy_dtmf_options user_options = { .cycle = '#', .volume = '\0', .exit = '*', }; struct ast_format oldwf; int res; char *mygroup = NULL; /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ ast_clear_flag(&flags, AST_FLAGS_ALL); ast_format_clear(&oldwf); if (!ast_strlen_zero(data)) { mygroup = ast_strdupa(data); } ast_set_flag(&flags, OPTION_DTMF_EXIT); ast_set_flag(&flags, OPTION_DTMF_CYCLE); ast_set_flag(&flags, OPTION_DAHDI_SCAN); ast_format_copy(&oldwf, ast_channel_writeformat(chan)); if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return -1; } res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL); if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0) ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return res; } static int unload_module(void) { int res = 0; res |= ast_unregister_application(app_chan); res |= ast_unregister_application(app_ext); res |= ast_unregister_application(app_dahdiscan); return res; }
void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *format) { struct ast_format *fnew; if (!format || !format->id) { return; } if (!(fnew = ao2_alloc(sizeof(struct ast_format), NULL))) { return; } ast_format_copy(fnew, format); if (cap->nolock) { ao2_link_nolock(cap->formats, fnew); } else { ao2_link(cap->formats, fnew); } ao2_ref(fnew, -1); }
struct ast_format *ast_getformatbyname(const char *name, struct ast_format *result) { int x; size_t f_len; const struct ast_format_list *f_list = ast_format_list_get(&f_len); for (x = 0; x < f_len; x++) { if (!strcasecmp(f_list[x].name, name) || !strcasecmp(f_list[x].name, ast_expand_codec_alias(name))) { ast_format_copy(result, &f_list[x].format); f_list = ast_format_list_destroy(f_list); return result; } } f_list = ast_format_list_destroy(f_list); return NULL; }
static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext) { int res; /* Send a frame from the file to the appropriate channel */ s->fr.frametype = AST_FRAME_VOICE; ast_format_copy(&s->fr.subclass.format, &s->fmt->format); s->fr.mallocd = 0; 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)) < 1) { if (res) ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); return NULL; } s->fr.datalen = res; if (s->fmt->format.id == AST_FORMAT_G722) *whennext = s->fr.samples = res * 2; else *whennext = s->fr.samples = res; return &s->fr; }
static int transmit_audio(fax_session *s) { int res = -1; struct ast_format original_read_fmt; struct ast_format original_write_fmt; 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, */ }; ast_format_clear(&original_read_fmt); ast_format_clear(&original_write_fmt); /* 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 ast_format_copy(&original_read_fmt, ast_channel_readformat(s->chan)); if (original_read_fmt.id != AST_FORMAT_SLINEAR) { res = ast_set_read_format_by_id(s->chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n"); goto done; } } ast_format_copy(&original_write_fmt, ast_channel_writeformat(s->chan)); if (original_write_fmt.id != AST_FORMAT_SLINEAR) { res = ast_set_write_format_by_id(s->chan, AST_FORMAT_SLINEAR); 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/%u, len=%d\n", inf->frametype, (unsigned int) inf->subclass.format.id, 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 && inf->subclass.format.id == AST_FORMAT_SLINEAR) { 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.id != AST_FORMAT_SLINEAR) { 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)); } if (original_read_fmt.id != AST_FORMAT_SLINEAR) { 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)); } 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; }
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 NBScat_exec(struct ast_channel *chan, const char *data) { int res=0; int fds[2]; int ms = -1; int pid = -1; struct ast_format owriteformat; struct timeval next; struct ast_frame *f; struct myframe { struct ast_frame f; char offset[AST_FRIENDLY_OFFSET]; short frdata[160]; } myf; ast_format_clear(&owriteformat); if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds)) { ast_log(LOG_WARNING, "Unable to create socketpair\n"); return -1; } ast_stopstream(chan); ast_format_copy(&owriteformat, &chan->writeformat); res = ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); return -1; } res = NBScatplay(fds[1]); /* Wait 1000 ms first */ next = ast_tvnow(); next.tv_sec += 1; if (res >= 0) { pid = res; /* Order is important -- there's almost always going to be mp3... we want to prioritize the user */ for (;;) { ms = ast_tvdiff_ms(next, ast_tvnow()); if (ms <= 0) { res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata)); if (res > 0) { myf.f.frametype = AST_FRAME_VOICE; ast_format_set(&myf.f.subclass.format, AST_FORMAT_SLINEAR, 0); myf.f.datalen = res; myf.f.samples = res / 2; myf.f.mallocd = 0; myf.f.offset = AST_FRIENDLY_OFFSET; myf.f.src = __PRETTY_FUNCTION__; myf.f.delivery.tv_sec = 0; myf.f.delivery.tv_usec = 0; myf.f.data.ptr = myf.frdata; if (ast_write(chan, &myf.f) < 0) { res = -1; break; } } else { ast_debug(1, "No more mp3\n"); res = 0; break; } next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000)); } else { ms = ast_waitfor(chan, ms); if (ms < 0) { ast_debug(1, "Hangup detected\n"); res = -1; break; } if (ms) { f = ast_read(chan); if (!f) { ast_debug(1, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == AST_FRAME_DTMF) { ast_debug(1, "User pressed a key\n"); ast_frfree(f); res = 0; break; } ast_frfree(f); } } } } close(fds[0]); close(fds[1]); if (pid > -1) kill(pid, SIGKILL); if (!res && owriteformat.id) ast_set_write_format(chan, &owriteformat); return res; }
static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, int length, char *intkeys) { int res = 0; int fds[2]; int needed = 0; struct ast_format owriteformat; struct ast_frame *f; struct myframe { struct ast_frame f; char offset[AST_FRIENDLY_OFFSET]; char frdata[2048]; } myf = { .f = { 0, }, }; ast_format_clear(&owriteformat); if (pipe(fds)) { ast_log(LOG_WARNING, "Unable to create pipe\n"); return -1; } /* Answer if it's not already going */ if (ast_channel_state(chan) != AST_STATE_UP) ast_answer(chan); ast_stopstream(chan); ast_indicate(chan, -1); ast_format_copy(&owriteformat, ast_channel_writeformat(chan)); res = ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); return -1; } res = send_waveform_to_fd(waveform, length, fds[1]); if (res >= 0) { /* Order is important -- there's almost always going to be mp3... we want to prioritize the user */ for (;;) { res = ast_waitfor(chan, 1000); if (res < 1) { res = -1; break; } f = ast_read(chan); if (!f) { ast_log(LOG_WARNING, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == AST_FRAME_DTMF) { ast_debug(1, "User pressed a key\n"); if (intkeys && strchr(intkeys, f->subclass.integer)) { res = f->subclass.integer; ast_frfree(f); break; } } if (f->frametype == AST_FRAME_VOICE) { /* Treat as a generator */ needed = f->samples * 2; if (needed > sizeof(myf.frdata)) { ast_log(LOG_WARNING, "Only able to deliver %d of %d requested samples\n", (int)sizeof(myf.frdata) / 2, needed/2); needed = sizeof(myf.frdata); } res = read(fds[0], myf.frdata, needed); if (res > 0) { myf.f.frametype = AST_FRAME_VOICE; ast_format_set(&myf.f.subclass.format, AST_FORMAT_SLINEAR, 0); myf.f.datalen = res; myf.f.samples = res / 2; myf.f.offset = AST_FRIENDLY_OFFSET; myf.f.src = __PRETTY_FUNCTION__; myf.f.data.ptr = myf.frdata; if (ast_write(chan, &myf.f) < 0) { res = -1; ast_frfree(f); break; } if (res < needed) { /* last frame */ ast_debug(1, "Last frame\n"); res = 0; ast_frfree(f); break; } } else { ast_debug(1, "No more waveform\n"); res = 0; } } ast_frfree(f); } } close(fds[0]); close(fds[1]); if (!res && owriteformat.id) ast_set_write_format(chan, &owriteformat); return res; }
int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2) { struct ao2_iterator it; struct ast_format *tmp; struct find_joint_data data = { .joint_found = 0, .joint_cap = NULL, }; it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0); while ((tmp = ao2_iterator_next(&it))) { data.format = tmp; ao2_callback(cap2->formats, OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock, find_joint_cb, &data); ao2_ref(tmp, -1); } ao2_iterator_destroy(&it); return data.joint_found ? 1 : 0; } int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2) { struct ao2_iterator it; struct ast_format *tmp; if (ao2_container_count(cap1->formats) != ao2_container_count(cap2->formats)) { return 0; /* if they are not the same size, they are not identical */ } it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0); while ((tmp = ao2_iterator_next(&it))) { if (!ast_format_cap_iscompatible(cap2, tmp)) { ao2_ref(tmp, -1); ao2_iterator_destroy(&it); return 0; } ao2_ref(tmp, -1); } ao2_iterator_destroy(&it); return 1; } struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2) { struct ao2_iterator it; struct ast_format_cap *result = ast_format_cap_alloc_nolock(); struct ast_format *tmp; struct find_joint_data data = { .joint_found = 0, .joint_cap = result, }; if (!result) { return NULL; } it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0); while ((tmp = ao2_iterator_next(&it))) { data.format = tmp; ao2_callback(cap2->formats, OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock, find_joint_cb, &data); ao2_ref(tmp, -1); } ao2_iterator_destroy(&it); if (ao2_container_count(result->formats)) { return result; } result = ast_format_cap_destroy(result); return NULL; } static int joint_copy_helper(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result, int append) { struct ao2_iterator it; struct ast_format *tmp; struct find_joint_data data = { .joint_cap = result, .joint_found = 0, }; if (!append) { ast_format_cap_remove_all(result); } it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0); while ((tmp = ao2_iterator_next(&it))) { data.format = tmp; ao2_callback(cap2->formats, OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock, find_joint_cb, &data); ao2_ref(tmp, -1); } ao2_iterator_destroy(&it); return ao2_container_count(result->formats) ? 1 : 0; } int ast_format_cap_joint_append(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result) { return joint_copy_helper(cap1, cap2, result, 1); } int ast_format_cap_joint_copy(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result) { return joint_copy_helper(cap1, cap2, result, 0); } struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap, enum ast_format_type ftype) { struct ao2_iterator it; struct ast_format_cap *result = ast_format_cap_alloc_nolock(); struct ast_format *tmp; if (!result) { return NULL; } /* for each format in cap1, see if that format is * compatible with cap2. If so copy it to the result */ it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0); while ((tmp = ao2_iterator_next(&it))) { if (AST_FORMAT_GET_TYPE(tmp->id) == ftype) { /* copy format */ ast_format_cap_add(result, tmp); } ao2_ref(tmp, -1); } ao2_iterator_destroy(&it); if (ao2_container_count(result->formats)) { return result; } result = ast_format_cap_destroy(result); return NULL; } int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_type type) { struct ao2_iterator it; struct ast_format *tmp; it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0); while ((tmp = ao2_iterator_next(&it))) { if (AST_FORMAT_GET_TYPE(tmp->id) == type) { ao2_ref(tmp, -1); ao2_iterator_destroy(&it); return 1; } ao2_ref(tmp, -1); } ao2_iterator_destroy(&it); return 0; } void ast_format_cap_iter_start(struct ast_format_cap *cap) { if (!cap->nolock) { ao2_lock(cap->formats); } cap->it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0); } void ast_format_cap_iter_end(struct ast_format_cap *cap) { ao2_iterator_destroy(&cap->it); if (!cap->nolock) { ao2_unlock(cap->formats); } } int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format) { struct ast_format *tmp = ao2_iterator_next(&cap->it); if (!tmp) { return -1; } ast_format_copy(format, tmp); ao2_ref(tmp, -1); return 0; } char *ast_getformatname_multiple(char *buf, size_t size, struct ast_format_cap *cap) { int x; unsigned len; char *start, *end = buf; struct ast_format tmp_fmt; size_t f_len; const struct ast_format_list *f_list = ast_format_list_get(&f_len); if (!size) { f_list = ast_format_list_destroy(f_list); return buf; } snprintf(end, size, "("); len = strlen(end); end += len; size -= len; start = end; for (x = 0; x < f_len; x++) { ast_format_copy(&tmp_fmt, &f_list[x].format); if (ast_format_cap_iscompatible(cap, &tmp_fmt)) { snprintf(end, size, "%s|", f_list[x].name); len = strlen(end); end += len; size -= len; } } if (start == end) { ast_copy_string(start, "nothing)", size); } else if (size > 1) { *(end - 1) = ')'; } f_list = ast_format_list_destroy(f_list); return buf; } uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap) { uint64_t res = 0; struct ao2_iterator it; struct ast_format *tmp; it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0); while ((tmp = ao2_iterator_next(&it))) { res |= ast_format_to_old_bitfield(tmp); ao2_ref(tmp, -1); } ao2_iterator_destroy(&it); return res; }
static int app_exec(struct ast_channel *chan, const char *data) { int res = 0, argc = 0, max_digits = 0, timeout = 0, alreadyran = 0; int ms, len, availatend; char *argv[3], *parse = NULL, *text = NULL, *rc = NULL; char tmp_exten[2], results[20]; struct ast_module_user *u; struct ast_frame *f; struct timeval next; struct stuff *ps; struct ast_format oldwf; struct myframe { struct ast_frame f; char offset[AST_FRIENDLY_OFFSET]; char frdata[framesize]; } myf; ast_format_clear(&oldwf); swift_engine *engine; swift_port *port = NULL; swift_voice *voice; swift_params *params; swift_result_t sresult; swift_background_t tts_stream; unsigned int event_mask; memset(results, 0 ,20); memset(tmp_exten, 0, 2); memset(argv, 0, 3); parse = ast_strdupa(data); u = ast_module_user_add(chan); argc = ast_app_separate_args(parse, '|', argv, 3); text = argv[0]; if (!ast_strlen_zero(argv[1])) { timeout = strtol(argv[1], NULL, 0); } if (!ast_strlen_zero(argv[2])) { max_digits = strtol(argv[2], NULL, 0); } if (ast_strlen_zero(text)) { ast_log(LOG_WARNING, "%s requires text to speak!\n", app); return -1; } if (!ast_strlen_zero(text)) { ast_log(LOG_DEBUG, "Text to Speak : %s\n", text); } if (timeout > 0) { ast_log(LOG_DEBUG, "Timeout : %d\n", timeout); } if (max_digits > 0) { ast_log(LOG_DEBUG, "Max Digits : %d\n", max_digits); } ps = malloc(sizeof(struct stuff)); swift_init_stuff(ps); /* Setup synthesis */ if ((engine = swift_engine_open(NULL)) == NULL) { ast_log(LOG_ERROR, "Failed to open Swift Engine.\n"); goto exception; } params = swift_params_new(NULL); swift_params_set_string(params, "audio/encoding", "ulaw"); swift_params_set_string(params, "audio/sampling-rate", "8000"); swift_params_set_string(params, "audio/output-format", "raw"); swift_params_set_string(params, "tts/text-encoding", "utf-8"); /* Additional swift parameters * * swift_params_set_float(params, "speech/pitch/shift", 1.0); * swift_params_set_int(params, "speech/rate", 150); * swift_params_set_int(params, "audio/volume", 110); * swift_params_set_int(params, "audio/deadair", 0); */ if ((port = swift_port_open(engine, params)) == NULL) { ast_log(LOG_ERROR, "Failed to open Swift Port.\n"); goto exception; } if ((voice = swift_port_set_voice_by_name(port, cfg_voice)) == NULL) { ast_log(LOG_ERROR, "Failed to set voice.\n"); goto exception; } event_mask = SWIFT_EVENT_AUDIO | SWIFT_EVENT_END; swift_port_set_callback(port, &swift_cb, event_mask, ps); if (SWIFT_FAILED(swift_port_speak_text(port, text, 0, NULL, &tts_stream, NULL))) { ast_log(LOG_ERROR, "Failed to speak.\n"); goto exception; } if (chan->_state != AST_STATE_UP) { ast_answer(chan); } ast_stopstream(chan); ast_format_copy(&oldwf, &chan->writeformat); if (ast_set_write_format_by_id(chan, AST_FORMAT_ULAW) < 0) { ast_log(LOG_WARNING, "Unable to set write format.\n"); goto exception; } res = 0; /* Wait 100ms first for synthesis to start crankin'; if that's not * enough the */ next = ast_tvadd(ast_tvnow(), ast_tv(0, 100000)); while (swift_generator_running(ps)) { ms = ast_tvdiff_ms(next, ast_tvnow()); if (ms <= 0) { if (swift_bytes_available(ps) > 0) { ASTOBJ_WRLOCK(ps); len = fmin(framesize, ps->qc); availatend = cfg_buffer_size - (ps->pq_r - ps->q); if (len > availatend) { /* read #1: to end of q buf */ memcpy(myf.frdata, ps->pq_r, availatend); ps->qc -= availatend; /* read #2: reset to start of q buf and get rest */ ps->pq_r = ps->q; memcpy(myf.frdata + availatend, ps->pq_r, len - availatend); ps->qc -= len - availatend; ps->pq_r += len - availatend; } else { ast_log(LOG_DEBUG, "Easy read; %d bytes and %d at end, %d free\n", len, availatend, cfg_buffer_size - ps->qc); memcpy(myf.frdata, ps->pq_r, len); ps->qc -= len; ps->pq_r += len; } myf.f.frametype = AST_FRAME_VOICE; ast_format_set(&myf.f.subclass.format, AST_FORMAT_ULAW, 0); myf.f.datalen = len; myf.f.samples = len; myf.f.data.ptr = myf.frdata; myf.f.mallocd = 0; myf.f.offset = AST_FRIENDLY_OFFSET; myf.f.src = __PRETTY_FUNCTION__; myf.f.delivery.tv_sec = 0; myf.f.delivery.tv_usec = 0; if (ast_write(chan, &myf.f) < 0) { ast_log(LOG_DEBUG, "ast_write failed\n"); } ast_log(LOG_DEBUG, "wrote a frame of %d\n", len); if (ps->qc < 0) { ast_log(LOG_DEBUG, "queue claims to contain negative bytes. Huh? qc < 0\n"); } ASTOBJ_UNLOCK(ps); next = ast_tvadd(next, ast_samp2tv(myf.f.samples, samplerate)); } else { next = ast_tvadd(next, ast_samp2tv(framesize / 2, samplerate)); ast_log(LOG_DEBUG, "Whoops, writer starved for audio\n"); } } else { ms = ast_waitfor(chan, ms); if (ms < 0) { ast_log(LOG_DEBUG, "Hangup detected\n"); res = -1; ASTOBJ_WRLOCK(ps); ps->immediate_exit = 1; ASTOBJ_UNLOCK(ps); } else if (ms) { f = ast_read(chan); if (!f) { ast_log(LOG_DEBUG, "Null frame == hangup() detected\n"); res = -1; ASTOBJ_WRLOCK(ps); ps->immediate_exit = 1; ASTOBJ_UNLOCK(ps); } else { if (f->frametype == AST_FRAME_DTMF && timeout > 0 && max_digits > 0) { char originalDTMF = f->subclass.integer; alreadyran = 1; res = 0; ASTOBJ_WRLOCK(ps); ps->immediate_exit = 1; ASTOBJ_UNLOCK(ps); if (max_digits > 1) { rc = listen_for_dtmf(chan, timeout, max_digits - 1); } if (rc) { sprintf(results, "%c%s", originalDTMF, rc); } else { sprintf(results, "%c", originalDTMF); } ast_log(LOG_NOTICE, "DTMF = %s\n", results); pbx_builtin_setvar_helper(chan, "SWIFT_DTMF", results); } } ast_frfree(f); } } ASTOBJ_RDLOCK(ps); if (ps->immediate_exit && !ps->generating_done) { if (SWIFT_FAILED(sresult = swift_port_stop(port, tts_stream, SWIFT_EVENT_NOW))) { ast_log(LOG_NOTICE, "Early top of swift port failed\n"); } } ASTOBJ_UNLOCK(ps); } if (alreadyran == 0 && timeout > 0 && max_digits > 0) { rc = listen_for_dtmf(chan, timeout, max_digits); if (rc != NULL) { sprintf(results, "%s", rc); ast_log(LOG_NOTICE, "DTMF = %s\n", results); pbx_builtin_setvar_helper(chan, "SWIFT_DTMF", results); } } if (max_digits >= 1 && results != NULL) { if (cfg_goto_exten) { ast_log(LOG_NOTICE, "GoTo(%s|%s|%d) : ", chan->context, results, 1); if (ast_exists_extension (chan, chan->context, results, 1, chan->caller.id.number.str)) { ast_log(LOG_NOTICE, "OK\n"); ast_copy_string(chan->exten, results, sizeof(chan->exten) - 1); chan->priority = 0; } else { ast_log(LOG_NOTICE, "FAILED\n"); } } } exception: if (port != NULL) { swift_port_close(port); } if (engine != NULL) { swift_engine_close(engine); } if (ps && ps->q) { ast_free(ps->q); ps->q = NULL; } if (ps) { ast_free(ps); ps = NULL; } if (!res) { ast_set_write_format(chan, &oldwf); } ast_module_user_remove(u); return res; }
struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap) { struct ast_unreal_pvt *unreal; static const struct ast_jb_conf jb_conf = { .flags = 0, .max_size = -1, .resync_threshold = -1, .impl = "", .target_extra = -1, }; unreal = ao2_alloc(size, destructor); if (!unreal) { return NULL; } unreal->reqcap = ast_format_cap_dup(cap); if (!unreal->reqcap) { ao2_ref(unreal, -1); return NULL; } memcpy(&unreal->jb_conf, &jb_conf, sizeof(unreal->jb_conf)); return unreal; } struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p, const struct ast_channel_tech *tech, int semi1_state, int semi2_state, const char *exten, const char *context, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, struct ast_callid *callid) { struct ast_channel *owner; struct ast_channel *chan; struct ast_format fmt; struct ast_assigned_ids id1 = {NULL, NULL}; struct ast_assigned_ids id2 = {NULL, NULL}; int generated_seqno = ast_atomic_fetchadd_int((int *) &name_sequence, +1); /* set unique ids for the two channels */ if (assignedids && !ast_strlen_zero(assignedids->uniqueid)) { id1.uniqueid = assignedids->uniqueid; id2.uniqueid = assignedids->uniqueid2; } /* if id1 given but not id2, use default of id1;2 */ if (id1.uniqueid && ast_strlen_zero(id2.uniqueid)) { char *uniqueid2; uniqueid2 = ast_alloca(strlen(id1.uniqueid) + 2); strcpy(uniqueid2, id1.uniqueid);/* Safe */ strcat(uniqueid2, ";2");/* Safe */ id2.uniqueid = uniqueid2; } /* * Allocate two new Asterisk channels * * Make sure that the ;2 channel gets the same linkedid as ;1. * You can't pass linkedid to both allocations since if linkedid * isn't set, then each channel will generate its own linkedid. */ if (!(owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL, exten, context, &id1, requestor, 0, "%s/%s-%08x;1", tech->type, p->name, generated_seqno))) { ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n"); return NULL; } if (callid) { ast_channel_callid_set(owner, callid); } ast_channel_tech_set(owner, tech); ao2_ref(p, +1); ast_channel_tech_pvt_set(owner, p); ast_format_cap_copy(ast_channel_nativeformats(owner), p->reqcap); /* Determine our read/write format and set it on each channel */ ast_best_codec(p->reqcap, &fmt); ast_format_copy(ast_channel_writeformat(owner), &fmt); ast_format_copy(ast_channel_rawwriteformat(owner), &fmt); ast_format_copy(ast_channel_readformat(owner), &fmt); ast_format_copy(ast_channel_rawreadformat(owner), &fmt); ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE); ast_jb_configure(owner, &p->jb_conf); if (ast_channel_cc_params_init(owner, requestor ? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) { ao2_ref(p, -1); ast_channel_unlock(owner); ast_channel_release(owner); return NULL; } p->owner = owner; ast_channel_unlock(owner); if (!(chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL, exten, context, &id2, owner, 0, "%s/%s-%08x;2", tech->type, p->name, generated_seqno))) { ast_log(LOG_WARNING, "Unable to allocate chan channel structure\n"); ao2_ref(p, -1); ast_channel_release(owner); return NULL; } if (callid) { ast_channel_callid_set(chan, callid); } ast_channel_tech_set(chan, tech); ao2_ref(p, +1); ast_channel_tech_pvt_set(chan, p); ast_format_cap_copy(ast_channel_nativeformats(chan), p->reqcap); /* Format was already determined when setting up owner */ ast_format_copy(ast_channel_writeformat(chan), &fmt); ast_format_copy(ast_channel_rawwriteformat(chan), &fmt); ast_format_copy(ast_channel_readformat(chan), &fmt); ast_format_copy(ast_channel_rawreadformat(chan), &fmt); ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE); p->chan = chan; ast_channel_unlock(chan); return owner; }
static int ices_exec(struct ast_channel *chan, const char *data) { int res = 0; int fds[2]; int ms = -1; int pid = -1; int flags; struct ast_format oreadformat; struct ast_frame *f; char filename[256]=""; char *c; ast_format_clear(&oreadformat); if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n"); return -1; } if (pipe(fds)) { ast_log(LOG_WARNING, "Unable to create pipe\n"); return -1; } flags = fcntl(fds[1], F_GETFL); fcntl(fds[1], F_SETFL, flags | O_NONBLOCK); ast_stopstream(chan); if (ast_channel_state(chan) != AST_STATE_UP) res = ast_answer(chan); if (res) { close(fds[0]); close(fds[1]); ast_log(LOG_WARNING, "Answer failed!\n"); return -1; } ast_format_copy(&oreadformat, ast_channel_readformat(chan)); res = ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR); if (res < 0) { close(fds[0]); close(fds[1]); ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); return -1; } if (((char *)data)[0] == '/') ast_copy_string(filename, (char *) data, sizeof(filename)); else snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_CONFIG_DIR, (char *)data); /* Placeholder for options */ c = strchr(filename, '|'); if (c) *c = '\0'; res = icesencode(filename, fds[0]); if (res >= 0) { pid = res; for (;;) { /* Wait for audio, and stream */ ms = ast_waitfor(chan, -1); if (ms < 0) { ast_debug(1, "Hangup detected\n"); res = -1; break; } f = ast_read(chan); if (!f) { ast_debug(1, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == AST_FRAME_VOICE) { res = write(fds[1], f->data.ptr, f->datalen); if (res < 0) { if (errno != EAGAIN) { ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno)); res = -1; ast_frfree(f); break; } } } ast_frfree(f); } } close(fds[0]); close(fds[1]); if (pid > -1) kill(pid, SIGKILL); if (!res && oreadformat.id) ast_set_read_format(chan, &oreadformat); return res; }
static int extenspy_exec(struct ast_channel *chan, const char *data) { char *ptr, *exten = NULL; char *mygroup = NULL; char *recbase = NULL; int fd = 0; struct ast_flags flags; struct spy_dtmf_options user_options = { .cycle = '*', .volume = '#', .exit = '\0', }; struct ast_format oldwf; int volfactor = 0; int res; char *mailbox = NULL; char *name_context = NULL; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(context); AST_APP_ARG(options); ); char *parse = ast_strdupa(data); AST_STANDARD_APP_ARGS(args, parse); ast_format_clear(&oldwf); if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) { exten = args.context; *ptr++ = '\0'; args.context = ptr; } if (ast_strlen_zero(args.context)) args.context = ast_strdupa(ast_channel_context(chan)); if (args.options) { char *opts[OPT_ARG_ARRAY_SIZE]; char tmp; ast_app_parse_options(spy_opts, &flags, opts, args.options); if (ast_test_flag(&flags, OPTION_GROUP)) mygroup = opts[OPT_ARG_GROUP]; if (ast_test_flag(&flags, OPTION_RECORD) && !(recbase = opts[OPT_ARG_RECORD])) recbase = "chanspy"; if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) { tmp = opts[OPT_ARG_EXIT][0]; if (strchr("0123456789*#", tmp) && tmp != '\0') { user_options.exit = tmp; } else { ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n"); } } if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) { tmp = opts[OPT_ARG_CYCLE][0]; if (strchr("0123456789*#", tmp) && tmp != '\0') { user_options.cycle = tmp; } else { ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n"); } } if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { int vol; if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); else volfactor = vol; } if (ast_test_flag(&flags, OPTION_PRIVATE)) ast_set_flag(&flags, OPTION_WHISPER); if (ast_test_flag(&flags, OPTION_NAME)) { if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { char *delimiter; if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { mailbox = opts[OPT_ARG_NAME]; *delimiter++ = '\0'; name_context = delimiter; } else { mailbox = opts[OPT_ARG_NAME]; } } } } else { /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ ast_clear_flag(&flags, AST_FLAGS_ALL); } ast_format_copy(&oldwf, ast_channel_writeformat(chan)); if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return -1; } if (recbase) { char filename[PATH_MAX]; snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); fd = 0; } } res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context); if (fd) close(fd); if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0) ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); return res; }
static int create_jb(struct ast_channel *chan, struct ast_frame *frr) { struct ast_jb *jb = ast_channel_jb(chan); struct ast_jb_conf *jbconf = &jb->conf; const struct ast_jb_impl *jbimpl = jb->impl; void *jbobj; struct ast_channel *bridged; long now; char logfile_pathname[20 + AST_JB_IMPL_NAME_SIZE + 2*AST_CHANNEL_NAME + 1]; char name1[AST_CHANNEL_NAME], name2[AST_CHANNEL_NAME], *tmp; int res; jbobj = jb->jbobj = jbimpl->create(jbconf, jbconf->resync_threshold); if (!jbobj) { ast_log(LOG_WARNING, "Failed to create jitterbuffer on channel '%s'\n", ast_channel_name(chan)); return -1; } now = get_now(jb, NULL); res = jbimpl->put_first(jbobj, frr, now); /* The result of putting the first frame should not differ from OK. However, its possible some implementations (i.e. adaptive's when resynch_threshold is specified) to drop it. */ if (res != AST_JB_IMPL_OK) { ast_log(LOG_WARNING, "Failed to put first frame in the jitterbuffer on channel '%s'\n", ast_channel_name(chan)); /* jbimpl->destroy(jbobj); return -1; */ } /* Init next */ jb->next = jbimpl->next(jbobj); /* Init last format for a first time. */ ast_format_copy(&jb->last_format, &frr->subclass.format); /* Create a frame log file */ if (ast_test_flag(jbconf, AST_JB_LOG)) { char safe_logfile[30] = "/tmp/logfile-XXXXXX"; int safe_fd; snprintf(name2, sizeof(name2), "%s", ast_channel_name(chan)); if ((tmp = strchr(name2, '/'))) { *tmp = '#'; } bridged = ast_bridged_channel(chan); /* We should always have bridged chan if a jitterbuffer is in use */ ast_assert(bridged != NULL); snprintf(name1, sizeof(name1), "%s", ast_channel_name(bridged)); if ((tmp = strchr(name1, '/'))) { *tmp = '#'; } snprintf(logfile_pathname, sizeof(logfile_pathname), "/tmp/ast_%s_jb_%s--%s.log", jbimpl->name, name1, name2); unlink(logfile_pathname); safe_fd = mkstemp(safe_logfile); if (safe_fd < 0 || link(safe_logfile, logfile_pathname) || unlink(safe_logfile) || !(jb->logfile = fdopen(safe_fd, "w+b"))) { ast_log(LOG_ERROR, "Failed to create frame log file with pathname '%s': %s\n", logfile_pathname, strerror(errno)); jb->logfile = NULL; if (safe_fd > -1) { close(safe_fd); } } if (res == AST_JB_IMPL_OK) { jb_framelog("JB_PUT_FIRST {now=%ld}: Queued frame with ts=%ld and len=%ld\n", now, frr->ts, frr->len); } else { jb_framelog("JB_PUT_FIRST {now=%ld}: Dropped frame with ts=%ld and len=%ld\n", now, frr->ts, frr->len); } } ast_verb(3, "%s jitterbuffer created on channel %s\n", jbimpl->name, ast_channel_name(chan)); /* Free the frame if it has not been queued in the jb */ if (res != AST_JB_IMPL_OK) { ast_frfree(frr); } return 0; }
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 Function called when we should prepare to call the destination */ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause) { char *tmp = ast_strdupa(data), *multicast_type = tmp, *destination, *control; struct ast_rtp_instance *instance; struct ast_sockaddr control_address; struct ast_sockaddr destination_address; struct ast_channel *chan; struct ast_format fmt; ast_best_codec(cap, &fmt); ast_sockaddr_setnull(&control_address); /* If no type was given we can't do anything */ if (ast_strlen_zero(multicast_type)) { goto failure; } if (!(destination = strchr(tmp, '/'))) { goto failure; } *destination++ = '\0'; if ((control = strchr(destination, '/'))) { *control++ = '\0'; if (!ast_sockaddr_parse(&control_address, control, PARSE_PORT_REQUIRE)) { goto failure; } } if (!ast_sockaddr_parse(&destination_address, destination, PARSE_PORT_REQUIRE)) { goto failure; } if (!(instance = ast_rtp_instance_new("multicast", NULL, &control_address, multicast_type))) { goto failure; } if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", requestor ? ast_channel_linkedid(requestor) : "", 0, "MulticastRTP/%p", instance))) { ast_rtp_instance_destroy(instance); goto failure; } ast_rtp_instance_set_channel_id(instance, ast_channel_uniqueid(chan)); ast_rtp_instance_set_remote_address(instance, &destination_address); ast_channel_tech_set(chan, &multicast_rtp_tech); ast_format_cap_add(ast_channel_nativeformats(chan), &fmt); ast_format_copy(ast_channel_writeformat(chan), &fmt); ast_format_copy(ast_channel_rawwriteformat(chan), &fmt); ast_format_copy(ast_channel_readformat(chan), &fmt); ast_format_copy(ast_channel_rawreadformat(chan), &fmt); ast_channel_tech_pvt_set(chan, instance); return chan; failure: *cause = AST_CAUSE_FAILURE; return NULL; }
/* And decode everything we can in the buffer */ static struct ast_frame *lintosilk_frameout(struct ast_trans_pvt *pvt) { struct silk_coder_pvt *coder = pvt->pvt; SKP_int ret = 0; SKP_int16 nBytesOut = 0; int datalen = 0; int samples = 0; int numPackets = 0; struct ast_frame *f; /* we can only work on multiples of a 10 ms sample * and no more than encControl->packetSize. * So we shove in packetSize samples repeatedly until * we are out */ /* We only do stuff if we have more than packetSize */ if (pvt->samples < coder->encControl.packetSize) { return NULL; } while (pvt->samples >= coder->encControl.packetSize) { nBytesOut = SILK_BUFFER_SIZE_BYTES - datalen; ret = SKP_Silk_SDK_Encode(coder->psEnc, &coder->encControl, (SKP_int16*)(coder->buf + samples), coder->encControl.packetSize, (SKP_uint8*)(pvt->outbuf.ui8 + datalen), &nBytesOut); if (ret) { ast_log(LOG_WARNING, "Silk_Encode returned %d\n", ret); } /* nBytesOut now holds the number of bytes encoded */ datalen += nBytesOut; samples += coder->encControl.packetSize; pvt->samples -= coder->encControl.packetSize; if(nBytesOut > 0){ /* if stuff came out, we have encoded a packet */ numPackets++; } } /* Move the remaining buffer stuff down */ if (pvt->samples) { memmove(coder->buf, coder->buf + samples, pvt->samples *2); } if(datalen == 0){ /* we shoved a bunch of samples in, but got no packets * out. We return NULL to the caller, like * if we could not encode anything */ return NULL; } /* we build the frame ourselves because we have an explicit dest */ f = &pvt->f; f->samples = coder->encControl.packetSize * numPackets; f->datalen = datalen; f->frametype = AST_FRAME_VOICE; ast_format_copy(&f->subclass.format, &pvt->explicit_dst); f->mallocd = 0; f->offset = AST_FRIENDLY_OFFSET; f->src = pvt->t->name; f->data.ptr = pvt->outbuf.c; return ast_frisolate(f); }