/*! \brief Pick a codec */ struct ast_format *ast_codec_choose(struct ast_codec_pref *pref, struct ast_format_cap *cap, int find_best, struct ast_format *result) { int x, slot, found; size_t f_len = 0; const struct ast_format_list *f_list = ast_format_list_get(&f_len); for (x = 0; x < f_len; x++) { slot = pref->order[x]; if (!slot) break; if (ast_format_cap_get_compatible_format(cap, &f_list[slot-1].format, result)) { found = 1; /*format is found and stored in result */ break; } } ast_format_list_destroy(f_list); if (found && (AST_FORMAT_GET_TYPE(result->id) == AST_FORMAT_TYPE_AUDIO)) { return result; } ast_format_clear(result); ast_debug(4, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec"); return find_best ? ast_best_codec(cap, result) : NULL; }
/* The entry point of the application. */ static int app_synth_exec(struct ast_channel *chan, ast_app_data data) { ast_format_compat nwriteformat; ast_format_clear(&nwriteformat); get_synth_format(chan, &nwriteformat); int samplerate = 8000; /* int framesize = DEFAULT_FRAMESIZE; */ int framesize = format_to_bytes_per_sample(&nwriteformat) * (DEFAULT_FRAMESIZE / 2); struct ast_frame *f; struct ast_frame fr; struct timeval next; int ms; apr_size_t len; int rres; ast_mrcp_profile_t *profile; apr_uint32_t speech_channel_number = get_next_speech_channel_number(); const char *name; char buffer[framesize]; speech_channel_status_t status; char *parse; int i; mrcpsynth_options_t mrcpsynth_options; mrcpsynth_session_t mrcpsynth_session; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(prompt); AST_APP_ARG(options); );
/** \brief Version dependent prototypes of uni_recog_create() function */ #if AST_VERSION_AT_LEAST(10,0,0) static int uni_recog_create(struct ast_speech *speech, ast_format_compat *format) { return uni_recog_create_internal(speech,format); } #elif AST_VERSION_AT_LEAST(1,6,0) static int uni_recog_create(struct ast_speech *speech, int format_id) { ast_format_compat format; ast_format_clear(&format); format.id = format_id; return uni_recog_create_internal(speech,&format); } #else /* 1.4 */ static int uni_recog_create(struct ast_speech *speech) { ast_format_compat format; ast_format_clear(&format); format.id = 0; return uni_recog_create_internal(speech,&format); }
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; }
int ast_format_cap_best_byid(const struct ast_format_cap *cap, enum ast_format_id id, struct ast_format *result) { struct byid_data data; data.result = result; data.id = id; ast_format_clear(result); ao2_callback(cap->formats, OBJ_MULTIPLE | OBJ_NODATA | cap->nolock, find_best_byid_cb, &data); return result->id ? 1 : 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; }
struct ast_format *ast_format_set(struct ast_format *format, enum ast_format_id id, int set_attributes, ... ) { /* initialize the structure before setting it. */ ast_format_clear(format); format->id = id; if (set_attributes) { va_list ap; va_start(ap, set_attributes); format_set_helper(format, ap); va_end(ap); } return format; }
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; }
struct ast_format *convertH323CapToAsteriskCap(int cap, struct ast_format *result) { ast_format_clear(result); switch(cap) { case OO_G711ULAW64K: return ast_format_set(result, AST_FORMAT_ULAW, 0); case OO_G711ALAW64K: return ast_format_set(result, AST_FORMAT_ALAW, 0); case OO_GSMFULLRATE: return ast_format_set(result, AST_FORMAT_GSM, 0); #ifdef AST_FORMAT_AMRNB case OO_AMRNB: return ast_format_set(result, AST_FORMAT_AMRNB, 0); #endif #ifdef AST_FORMAT_SPEEX case OO_SPEEX: return ast_format_set(result, AST_FORMAT_SPEEX, 0); #endif case OO_G729: return ast_format_set(result, AST_FORMAT_G729A, 0); case OO_G729A: return ast_format_set(result, AST_FORMAT_G729A, 0); case OO_G729B: return ast_format_set(result, AST_FORMAT_G729A, 0); case OO_G7231: return ast_format_set(result, AST_FORMAT_G723_1, 0); case OO_G726: return ast_format_set(result, AST_FORMAT_G726, 0); case OO_G726AAL2: return ast_format_set(result, AST_FORMAT_G726_AAL2, 0); case OO_H263VIDEO: return ast_format_set(result, AST_FORMAT_H263, 0); default: ast_debug(1, "Cap %d is not supported by driver yet\n", cap); return NULL; } return NULL; }
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; }
struct ast_format *ast_format_from_old_bitfield(struct ast_format *dst, uint64_t src) { switch (src) { /*! G.723.1 compression */ case (1ULL << 0): return ast_format_set(dst, AST_FORMAT_G723_1, 0); /*! GSM compression */ case (1ULL << 1): return ast_format_set(dst, AST_FORMAT_GSM, 0); /*! Raw mu-law data (G.711) */ case (1ULL << 2): return ast_format_set(dst, AST_FORMAT_ULAW, 0); /*! Raw A-law data (G.711) */ case (1ULL << 3): return ast_format_set(dst, AST_FORMAT_ALAW, 0); /*! ADPCM (G.726, 32kbps, AAL2 codeword packing) */ case (1ULL << 4): return ast_format_set(dst, AST_FORMAT_G726_AAL2, 0); /*! ADPCM (IMA) */ case (1ULL << 5): return ast_format_set(dst, AST_FORMAT_ADPCM, 0); /*! Raw 16-bit Signed Linear (8000 Hz) PCM */ case (1ULL << 6): return ast_format_set(dst, AST_FORMAT_SLINEAR, 0); /*! LPC10, 180 samples/frame */ case (1ULL << 7): return ast_format_set(dst, AST_FORMAT_LPC10, 0); /*! G.729A audio */ case (1ULL << 8): return ast_format_set(dst, AST_FORMAT_G729A, 0); /*! SpeeX Free Compression */ case (1ULL << 9): return ast_format_set(dst, AST_FORMAT_SPEEX, 0); /*! iLBC Free Compression */ case (1ULL << 10): return ast_format_set(dst, AST_FORMAT_ILBC, 0); /*! ADPCM (G.726, 32kbps, RFC3551 codeword packing) */ case (1ULL << 11): return ast_format_set(dst, AST_FORMAT_G726, 0); /*! G.722 */ case (1ULL << 12): return ast_format_set(dst, AST_FORMAT_G722, 0); /*! G.722.1 (also known as Siren7, 32kbps assumed) */ case (1ULL << 13): return ast_format_set(dst, AST_FORMAT_SIREN7, 0); /*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */ case (1ULL << 14): return ast_format_set(dst, AST_FORMAT_SIREN14, 0); /*! Raw 16-bit Signed Linear (16000 Hz) PCM */ case (1ULL << 15): return ast_format_set(dst, AST_FORMAT_SLINEAR16, 0); /*! G.719 (64 kbps assumed) */ case (1ULL << 32): return ast_format_set(dst, AST_FORMAT_G719, 0); /*! SpeeX Wideband (16kHz) Free Compression */ case (1ULL << 33): return ast_format_set(dst, AST_FORMAT_SPEEX16, 0); /*! Raw mu-law data (G.711) */ case (1ULL << 47): return ast_format_set(dst, AST_FORMAT_TESTLAW, 0); /*! H.261 Video */ case (1ULL << 18): return ast_format_set(dst, AST_FORMAT_H261, 0); /*! H.263 Video */ case (1ULL << 19): return ast_format_set(dst, AST_FORMAT_H263, 0); /*! H.263+ Video */ case (1ULL << 20): return ast_format_set(dst, AST_FORMAT_H263_PLUS, 0); /*! H.264 Video */ case (1ULL << 21): return ast_format_set(dst, AST_FORMAT_H264, 0); /*! MPEG4 Video */ case (1ULL << 22): return ast_format_set(dst, AST_FORMAT_MP4_VIDEO, 0); /*! JPEG Images */ case (1ULL << 16): return ast_format_set(dst, AST_FORMAT_JPEG, 0); /*! PNG Images */ case (1ULL << 17): return ast_format_set(dst, AST_FORMAT_PNG, 0); /*! T.140 RED Text format RFC 4103 */ case (1ULL << 26): return ast_format_set(dst, AST_FORMAT_T140RED, 0); /*! T.140 Text format - ITU T.140, RFC 4103 */ case (1ULL << 27): return ast_format_set(dst, AST_FORMAT_T140, 0); } ast_format_clear(dst); return NULL; }
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 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 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; }
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; }