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); } }
static int echo_exec(struct ast_channel *chan, const char *data) { int res = -1; int fir_sent = 0; while (ast_waitfor(chan, -1) > -1) { struct ast_frame *f = ast_read(chan); if (!f) { break; } f->delivery.tv_sec = 0; f->delivery.tv_usec = 0; if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_VIDUPDATE && !fir_sent) { if (ast_write(chan, f) < 0) { ast_frfree(f); goto end; } fir_sent = 1; } if (!fir_sent && f->frametype == AST_FRAME_VIDEO) { struct ast_frame frame = { .frametype = AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_VIDUPDATE, }; ast_write(chan, &frame); fir_sent = 1; } if (f->frametype != AST_FRAME_CONTROL && f->frametype != AST_FRAME_MODEM && f->frametype != AST_FRAME_NULL && ast_write(chan, f)) { ast_frfree(f); goto end; } if ((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '#')) { res = 0; ast_frfree(f); goto end; } ast_frfree(f); } end: return res; } static int unload_module(void) { return ast_unregister_application(app); } static int load_module(void) { return ast_register_application_xml(app, echo_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Echo Application");
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) { struct chanspy_translation_helper *csth = data; struct ast_frame *f = NULL; ast_audiohook_lock(&csth->spy_audiohook); if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { /* Channel is already gone more than likely */ ast_audiohook_unlock(&csth->spy_audiohook); return -1; } f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR); ast_audiohook_unlock(&csth->spy_audiohook); if (!f) return 0; if (ast_write(chan, f)) { ast_frfree(f); return -1; } if (csth->fd) write(csth->fd, f->data, f->datalen); ast_frfree(f); return 0; }
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) { struct chanspy_translation_helper *csth = data; struct ast_frame *f; if (csth->spy.status != CHANSPY_RUNNING) /* Channel is already gone more than likely */ return -1; ast_mutex_lock(&csth->spy.lock); f = ast_channel_spy_read_frame(&csth->spy, samples); ast_mutex_unlock(&csth->spy.lock); if (!f) return 0; if (ast_write(chan, f)) { ast_frfree(f); return -1; } if (csth->fd) write(csth->fd, f->data, f->datalen); ast_frfree(f); return 0; }
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) { struct chanspy_translation_helper *csth = data; struct ast_frame *f, *cur; ast_audiohook_lock(&csth->spy_audiohook); if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { ast_audiohook_unlock(&csth->spy_audiohook); return -1; } f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR); ast_audiohook_unlock(&csth->spy_audiohook); if (!f) return 0; for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) { if (ast_write(chan, cur)) { ast_frfree(f); return -1; } if (csth->fd) { if (write(csth->fd, cur->data, cur->datalen) < 0) { ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); } } } ast_frfree(f); return 0; }
static int linear_generator(struct ast_channel *chan, void *data, int len, int samples) { struct ast_frame f; short buf[2048 + AST_FRIENDLY_OFFSET / 2]; struct linear_state *ls = data; int res; len = samples * 2; if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" ,len); len = sizeof(buf) - AST_FRIENDLY_OFFSET; } memset(&f, 0, sizeof(f)); res = read(ls->fd, buf + AST_FRIENDLY_OFFSET/2, len); if (res > 0) { f.frametype = AST_FRAME_VOICE; f.subclass = AST_FORMAT_SLINEAR; f.data = buf + AST_FRIENDLY_OFFSET/2; f.datalen = res; f.samples = res / 2; f.offset = AST_FRIENDLY_OFFSET; ast_write(chan, &f); if (res == len) return 0; } return -1; }
static int echo_exec(struct ast_channel *chan, const char *data) { int res = -1; struct ast_format format; ast_best_codec(chan->nativeformats, &format); ast_set_write_format(chan, &format); ast_set_read_format(chan, &format); while (ast_waitfor(chan, -1) > -1) { struct ast_frame *f = ast_read(chan); if (!f) { break; } f->delivery.tv_sec = 0; f->delivery.tv_usec = 0; if (ast_write(chan, f)) { ast_frfree(f); goto end; } if ((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '#')) { res = 0; ast_frfree(f); goto end; } ast_frfree(f); } end: return res; }
static int milliwatt_generate(struct ast_channel *chan, void *data, int len, int samples) { struct ast_frame wf; unsigned char buf[AST_FRIENDLY_OFFSET + 640]; int i,*indexp = (int *) data; if (len + AST_FRIENDLY_OFFSET > sizeof(buf)) { ast_log(LOG_WARNING,"Only doing %d bytes (%d bytes requested)\n",(int)(sizeof(buf) - AST_FRIENDLY_OFFSET),len); len = sizeof(buf) - AST_FRIENDLY_OFFSET; } wf.frametype = AST_FRAME_VOICE; wf.subclass = AST_FORMAT_ULAW; wf.offset = AST_FRIENDLY_OFFSET; wf.mallocd = 0; wf.data = buf + AST_FRIENDLY_OFFSET; wf.datalen = len; wf.samples = wf.datalen; wf.src = "app_milliwatt"; wf.delivery.tv_sec = 0; wf.delivery.tv_usec = 0; wf.prev = wf.next = NULL; /* create a buffer containing the digital milliwatt pattern */ for(i = 0; i < len; i++) { buf[AST_FRIENDLY_OFFSET + i] = digital_milliwatt[(*indexp)++]; *indexp &= 7; } if (ast_write(chan,&wf) < 0) { ast_log(LOG_WARNING,"Failed to write frame to '%s': %s\n",chan->name,strerror(errno)); return -1; } return 0; }
/* Incoming TTS data from UniMRCP. */ static apt_bool_t synth_stream_write(mpf_audio_stream_t *stream, const mpf_frame_t *frame) { speech_channel_t *schannel; if (stream) schannel = (speech_channel_t *)stream->obj; else schannel = NULL; if(!schannel || !frame) { ast_log(LOG_ERROR, "synth_stream_write: unknown channel error!\n"); return FALSE; } if (frame->codec_frame.size > 0 && (frame->type & MEDIA_FRAME_TYPE_AUDIO) == MEDIA_FRAME_TYPE_AUDIO) { struct ast_frame fr; ast_frame_fill(schannel->format, &fr, frame->codec_frame.buffer, frame->codec_frame.size); if (ast_write(schannel->chan, &fr) < 0) { ast_log(LOG_WARNING, "(%s) Unable to write frame to channel: %s\n", schannel->name, strerror(errno)); } } return TRUE; }
static int echo_exec(struct ast_channel *chan, void *data) { int res = -1; int format; struct ast_module_user *u; u = ast_module_user_add(chan); format = ast_best_codec(chan->nativeformats); ast_set_write_format(chan, format); ast_set_read_format(chan, format); while (ast_waitfor(chan, -1) > -1) { struct ast_frame *f = ast_read(chan); if (!f) break; f->delivery.tv_sec = 0; f->delivery.tv_usec = 0; if (ast_write(chan, f)) { ast_frfree(f); goto end; } if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) { res = 0; ast_frfree(f); goto end; } ast_frfree(f); } end: ast_module_user_remove(u); return res; }
static int fax_generator_generate(struct ast_channel *chan, void *data, int len, int samples) { fax_state_t *fax = (fax_state_t*) data; uint8_t buffer[AST_FRIENDLY_OFFSET + MAX_SAMPLES * sizeof(uint16_t)]; int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET); struct ast_frame outf = { .frametype = AST_FRAME_VOICE, .src = __FUNCTION__, }; ast_format_set(&outf.subclass.format, AST_FORMAT_SLINEAR, 0); if (samples > MAX_SAMPLES) { ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples); samples = MAX_SAMPLES; } if ((len = fax_tx(fax, buf, samples)) > 0) { outf.samples = len; AST_FRAME_SET_BUFFER(&outf, buffer, AST_FRIENDLY_OFFSET, len * sizeof(int16_t)); if (ast_write(chan, &outf) < 0) { ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno)); return -1; } } return 0; }
static int send_tone_burst(struct ast_channel *chan, float freq, int duration, int tldn) { int res = 0; int i = 0; int x = 0; struct ast_frame *f, wf; struct { unsigned char offset[AST_FRIENDLY_OFFSET]; unsigned char buf[640]; } tone_block; for(;;) { if (ast_waitfor(chan, -1) < 0){ res = -1; break; } f = ast_read(chan); if (!f){ res = -1; break; } if (f->frametype == AST_FRAME_VOICE) { wf.frametype = AST_FRAME_VOICE; wf.subclass = AST_FORMAT_ULAW; wf.offset = AST_FRIENDLY_OFFSET; wf.mallocd = 0; wf.data = tone_block.buf; wf.datalen = f->datalen; wf.samples = wf.datalen; make_tone_burst(tone_block.buf, freq, (float) tldn, wf.datalen, &x); i += wf.datalen / 8; if (i > duration) { ast_frfree(f); break; } if (ast_write(chan, &wf)){ if(option_verbose >= 4) ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Failed to write frame on %s\n", chan->name); ast_log(LOG_WARNING, "AlarmReceiver Failed to write frame on %s\n",chan->name); res = -1; ast_frfree(f); break; } } ast_frfree(f); } return res; }
int t_write(ast_runtime* rt, t* t_v) { int status = AST_NOERR; int i = 0; status = ast_write(rt,ast_int32,1,&t_v->f1_f); if(!status) {goto done;} if(t_v->f2_f.exists) { status = ast_write(rt,ast_float,2,&t_v->f2_f.value); if(!status) {goto done;} } for(i=0;i<t_v->f3_f.count;i++) { status = ast_write(rt,ast_sint32,3,&t_v->f3_f.values[i]); if(!status) {goto done;} } status = m2_write(rt,t_v->f4_f); if(!status) {goto done;} done: return status; } /*t_write*/
static int milliwatt_generate(struct ast_channel *chan, void *data, int len, int samples) { unsigned char buf[AST_FRIENDLY_OFFSET + 640]; const int maxsamples = ARRAY_LEN(buf); int i, *indexp = (int *) data; struct ast_frame wf = { .frametype = AST_FRAME_VOICE, .subclass.codec = AST_FORMAT_ULAW, .offset = AST_FRIENDLY_OFFSET, .src = __FUNCTION__, }; wf.data.ptr = buf + AST_FRIENDLY_OFFSET; /* Instead of len, use samples, because channel.c generator_force * generate(chan, tmp, 0, 160) ignores len. In any case, len is * a multiple of samples, given by number of samples times bytes per * sample. In the case of ulaw, len = samples. for signed linear * len = 2 * samples */ if (samples > maxsamples) { ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n", maxsamples, samples); samples = maxsamples; } len = samples * sizeof (buf[0]); wf.datalen = len; wf.samples = samples; /* create a buffer containing the digital milliwatt pattern */ for (i = 0; i < len; i++) { buf[AST_FRIENDLY_OFFSET + i] = digital_milliwatt[(*indexp)++]; *indexp &= 7; } if (ast_write(chan,&wf) < 0) { ast_log(LOG_WARNING,"Failed to write frame to '%s': %s\n",chan->name,strerror(errno)); return -1; } return 0; } static struct ast_generator milliwattgen = { alloc: milliwatt_alloc, release: milliwatt_release, generate: milliwatt_generate, };
/*! \brief Write function for writing frames into the bridge */ static enum ast_bridge_write_result multiplexed_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame) { struct ast_bridge_channel *other; if (AST_LIST_FIRST(&bridge->channels) == AST_LIST_LAST(&bridge->channels)) { return AST_BRIDGE_WRITE_FAILED; } if (!(other = (AST_LIST_FIRST(&bridge->channels) == bridge_channel ? AST_LIST_LAST(&bridge->channels) : AST_LIST_FIRST(&bridge->channels)))) { return AST_BRIDGE_WRITE_FAILED; } if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) { ast_write(other->chan, frame); } return AST_BRIDGE_WRITE_SUCCESS; }
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples) { struct chanspy_translation_helper *csth = data; struct ast_frame *f, *cur; struct ast_format format_slin; ast_format_set(&format_slin, AST_FORMAT_SLINEAR, 0); ast_audiohook_lock(&csth->spy_audiohook); if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { /* Channel is already gone more than likely */ ast_audiohook_unlock(&csth->spy_audiohook); return -1; } if (ast_test_flag(&csth->flags, OPTION_READONLY)) { /* Option 'o' was set, so don't mix channel audio */ f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, &format_slin); } else { f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, &format_slin); } ast_audiohook_unlock(&csth->spy_audiohook); if (!f) return 0; for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) { if (ast_write(chan, cur)) { ast_frfree(f); return -1; } if (csth->fd) { if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) { ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); } } } ast_frfree(f); return 0; }
static int echo_exec(struct ast_channel *chan, void *data) { int res = -1; int format; struct localuser *u; LOCAL_USER_ADD(u); format = ast_best_codec(chan->nativeformats); ast_set_write_format(chan, format); ast_set_read_format(chan, format); while (ast_waitfor(chan, -1) > -1) { struct ast_frame *f = ast_read(chan); if (!f) break; f->delivery.tv_sec = 0; f->delivery.tv_usec = 0; switch (f->frametype) { case AST_FRAME_DTMF: case AST_FRAME_DTMF_END: if (f->subclass == '#') { res = 0; ast_frfree(f); goto end; } /* fall through */ case AST_FRAME_DTMF_BEGIN: case AST_FRAME_VOICE: case AST_FRAME_VIDEO: case AST_FRAME_TEXT: case AST_FRAME_HTML: case AST_FRAME_IMAGE: if (ast_write(chan, f)) { ast_frfree(f); goto end; } } ast_frfree(f); } end: LOCAL_USER_REMOVE(u); return res; }
int ast_dtmf_stream(struct ast_channel *chan,struct ast_channel *peer,char *digits,int between) { char *ptr=NULL; int res=0; struct ast_frame f; if (!between) between = 100; if (peer) res = ast_autoservice_start(peer); if (!res) { res = ast_waitfor(chan,100); if (res > -1) { for (ptr=digits; *ptr; *ptr++) { if (*ptr == 'w') { res = ast_safe_sleep(chan, 500); if (res) break; continue; } memset(&f, 0, sizeof(f)); f.frametype = AST_FRAME_DTMF; f.subclass = *ptr; f.src = "ast_dtmf_stream"; if (strchr("0123456789*#abcdABCD",*ptr)==NULL) { ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr); } else { res = ast_write(chan, &f); if (res) break; /* pause between digits */ res = ast_safe_sleep(chan,between); if (res) break; } } } if (peer) res = ast_autoservice_stop(peer); } return res; }
static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) { struct ast_channel *chan = (struct ast_channel *) user_data; struct ast_frame outf = { .frametype = AST_FRAME_MODEM, .subclass = AST_MODEM_T38, .src = __FUNCTION__, }; /* TODO: Asterisk does not provide means of resending the same packet multiple times so count is ignored at the moment */ AST_FRAME_SET_BUFFER(&outf, buf, 0, len); if (ast_write(chan, &outf) < 0) { ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno)); return -1; } return 0; }
// process outgoing frames for the channel, playing either normal conference audio, // or requested sounds static int process_outgoing( struct ast_conf_member *member, int samples ) { int res; struct ast_frame *cf = NULL; ast_mutex_lock(&member->lock); cf=get_outgoing_frame( member->conf, member, samples ) ; ast_mutex_unlock(&member->lock); /* ast_log(LOG_WARNING, "OURGen: samples %d - conf %s - speak: %d - format: %d\n", samples, member->chan->name, member->is_speaking , cf->frametype ); */ // if there's no frames exit the loop. if( cf == NULL ) { ast_log( LOG_ERROR, "Nothing to write to the conference, channel => %s\n", member->channel_name ) ; return 0; } // send the voice frame res = ast_write( member->chan, cf ); if ( ( res != 0) ) { // log 'dropped' outgoing frame ast_log( LOG_ERROR, "unable to write voice frame to channel, channel => %s, samples %d \n", member->channel_name, samples ) ; } // clean up frame ast_frfree(cf); return 0; }
static int gen_generate(struct ast_channel *chan, void *data, int len, int samples) { struct gen_state *state = data; struct ast_frame *f = NULL; int res = 0; state->sample_queue += samples; while (state->sample_queue > 0) { if (!(f = gen_readframe(state))) return -1; res = ast_write(chan, f); ast_frfree(f); if (res < 0) { ast_chan_log(LOG_WARNING, chan, "Failed to write frame: %s\n", strerror(errno)); return -1; } state->sample_queue -= f->samples; } return res; }
static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) { struct ast_channel *chan = (struct ast_channel *) user_data; struct ast_frame outf = { .frametype = AST_FRAME_MODEM, .subclass.integer = AST_MODEM_T38, .src = __FUNCTION__, }; /* TODO: Asterisk does not provide means of resending the same packet multiple times so count is ignored at the moment */ AST_FRAME_SET_BUFFER(&outf, buf, 0, len); if (ast_write(chan, &outf) < 0) { ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno)); return -1; } return 0; } static void phase_e_handler(t30_state_t *f, void *user_data, int result) { const char *local_ident; const char *far_ident; char buf[20]; fax_session *s = (fax_session *) user_data; t30_stats_t stat; int pages_transferred; ast_debug(1, "Fax phase E handler. result=%d\n", result); t30_get_transfer_statistics(f, &stat); s = (fax_session *) user_data; if (result != T30_ERR_OK) { s->finished = -1; /* FAXSTATUS is already set to FAILED */ pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result)); ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result)); return; } s->finished = 1; local_ident = S_OR(t30_get_tx_ident(f), ""); far_ident = S_OR(t30_get_rx_ident(f), ""); pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS"); pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL); pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident); #if SPANDSP_RELEASE_DATE >= 20090220 pages_transferred = (s->direction) ? stat.pages_tx : stat.pages_rx; #else pages_transferred = stat.pages_transferred; #endif snprintf(buf, sizeof(buf), "%d", pages_transferred); pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf); snprintf(buf, sizeof(buf), "%d", stat.y_resolution); pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf); snprintf(buf, sizeof(buf), "%d", stat.bit_rate); pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf); ast_debug(1, "Fax transmitted successfully.\n"); ast_debug(1, " Remote station ID: %s\n", far_ident); ast_debug(1, " Pages transferred: %d\n", pages_transferred); ast_debug(1, " Image resolution: %d x %d\n", stat.x_resolution, stat.y_resolution); ast_debug(1, " Transfer Rate: %d\n", stat.bit_rate); ast_manager_event(s->chan, EVENT_FLAG_CALL, s->direction ? "FaxSent" : "FaxReceived", "Channel: %s\r\n" "Exten: %s\r\n" "CallerID: %s\r\n" "CallerIDName: %s\r\n" "ConnectedLineNum: %s\r\n" "ConnectedLineName: %s\r\n" "RemoteStationID: %s\r\n" "LocalStationID: %s\r\n" "PagesTransferred: %d\r\n" "Resolution: %d\r\n" "TransferRate: %d\r\n" "FileName: %s\r\n", ast_channel_name(s->chan), ast_channel_exten(s->chan), S_COR(ast_channel_caller(s->chan)->id.number.valid, ast_channel_caller(s->chan)->id.number.str, ""), S_COR(ast_channel_caller(s->chan)->id.name.valid, ast_channel_caller(s->chan)->id.name.str, ""), S_COR(ast_channel_connected(s->chan)->id.number.valid, ast_channel_connected(s->chan)->id.number.str, ""), S_COR(ast_channel_connected(s->chan)->id.name.valid, ast_channel_connected(s->chan)->id.name.str, ""), far_ident, local_ident, pages_transferred, stat.y_resolution, stat.bit_rate, s->file_name); } /* === Helper functions to configure fax === */ /* Setup SPAN logging according to Asterisk debug level */ static int set_logging(logging_state_t *state) { int level = SPAN_LOG_WARNING + option_debug; span_log_set_message_handler(state, span_message); span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level); return 0; }
static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int len, int *remainder) { /* Sends carefully on a full duplex channel by using reading for timing */ struct ast_frame *inf, outf; int amt; /* Zero out our outgoing frame */ memset(&outf, 0, sizeof(outf)); if (remainder && *remainder) { amt = len; /* Send remainder if provided */ if (amt > *remainder) amt = *remainder; else *remainder = *remainder - amt; outf.frametype = AST_FRAME_VOICE; outf.subclass = AST_FORMAT_ULAW; outf.data = buf; outf.datalen = amt; outf.samples = amt; if (ast_write(chan, &outf)) { ast_log(LOG_WARNING, "Failed to carefully write frame\n"); return -1; } /* Update pointers and lengths */ buf += amt; len -= amt; } while(len) { amt = len; /* If we don't get anything at all back in a second, forget about it */ if (ast_waitfor(chan, 1000) < 1) return -1; inf = ast_read(chan); /* Detect hangup */ if (!inf) return -1; if (inf->frametype == AST_FRAME_VOICE) { /* Read a voice frame */ if (inf->subclass != AST_FORMAT_ULAW) { ast_log(LOG_WARNING, "Channel not in ulaw?\n"); return -1; } /* Send no more than they sent us */ if (amt > inf->datalen) amt = inf->datalen; else if (remainder) *remainder = inf->datalen - amt; outf.frametype = AST_FRAME_VOICE; outf.subclass = AST_FORMAT_ULAW; outf.data = buf; outf.datalen = amt; outf.samples = amt; if (ast_write(chan, &outf)) { ast_log(LOG_WARNING, "Failed to carefully write frame\n"); return -1; } /* Update pointers and lengths */ buf += amt; len -= amt; } ast_frfree(inf); } return 0; }
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags) { struct ast_conference *prev=NULL, *cur; struct ast_conf_user *user = malloc(sizeof(struct ast_conf_user)); int fd; struct zt_confinfo ztc; struct ast_frame *f; struct ast_channel *c; struct ast_frame fr; int outfd; int ms; int nfds; int res; int flags; int retryzap; int origfd; int musiconhold = 0; int firstpass = 0; int origquiet; int ret = -1; int x; int menu_active = 0; int using_pseudo = 0; struct ast_app *app; char *agifile; char *agifiledefault = "conf-background.agi"; char meetmesecs[30] = ""; char exitcontext[AST_MAX_EXTENSION] = ""; int dtmf; ZT_BUFFERINFO bi; char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; char *buf = __buf + AST_FRIENDLY_OFFSET; if (!user) { ast_log(LOG_ERROR, "Out of memory\n"); return(ret); } memset(user, 0, sizeof(struct ast_conf_user)); user->user_no = 0; /* User number 0 means starting up user! (dead - not in the list!) */ time(&user->jointime); if (conf->locked) { /* Sorry, but this confernce is locked! */ if (!ast_streamfile(chan, "conf-locked", chan->language)) ast_waitstream(chan, ""); goto outrun; } conf->users++; if (confflags & CONFFLAG_MARKEDUSER) conf->markedusers++; ast_mutex_lock(&conflock); if (conf->firstuser == NULL) { /* Fill the first new User struct */ user->user_no = 1; user->nextuser = NULL; user->prevuser = NULL; conf->firstuser = user; conf->lastuser = user; } else { /* Fill the new user struct */ user->user_no = conf->lastuser->user_no + 1; user->prevuser = conf->lastuser; user->nextuser = NULL; if (conf->lastuser->nextuser != NULL) { ast_log(LOG_WARNING, "Error in User Management!\n"); ast_mutex_unlock(&conflock); goto outrun; } else { conf->lastuser->nextuser = user; conf->lastuser = user; } } user->chan = chan; user->userflags = confflags; user->adminflags = 0; ast_mutex_unlock(&conflock); origquiet = confflags & CONFFLAG_QUIET; if (confflags & CONFFLAG_EXIT_CONTEXT) { if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) strncpy(exitcontext, agifile, sizeof(exitcontext) - 1); else if (!ast_strlen_zero(chan->macrocontext)) strncpy(exitcontext, chan->macrocontext, sizeof(exitcontext) - 1); else strncpy(exitcontext, chan->context, sizeof(exitcontext) - 1); } while((confflags & CONFFLAG_WAITMARKED) && (conf->markedusers == 0)) { confflags &= ~CONFFLAG_QUIET; confflags |= origquiet; /* XXX Announce that we're waiting on the conference lead to join */ if (!(confflags & CONFFLAG_QUIET)) { res = ast_streamfile(chan, "vm-dialout", chan->language); if (!res) res = ast_waitstream(chan, ""); } else res = 0; /* If we're waiting with hold music, set to silent mode */ if (!res) { confflags |= CONFFLAG_QUIET; ast_moh_start(chan, NULL); res = ast_safe_sleep_conditional(chan, 60000, confnonzero, conf); ast_moh_stop(chan); } if (res < 0) { ast_log(LOG_DEBUG, "Got hangup on '%s' already\n", chan->name); goto outrun; } } if (!(confflags & CONFFLAG_QUIET) && conf->users == 1) { if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) { if (ast_waitstream(chan, "") < 0) goto outrun; } else goto outrun; } /* Set it into linear mode (write) */ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name); goto outrun; } /* Set it into linear mode (read) */ if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) { ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name); goto outrun; } ast_indicate(chan, -1); retryzap = strcasecmp(chan->type, "Zap"); zapretry: origfd = chan->fds[0]; if (retryzap) { fd = open("/dev/zap/pseudo", O_RDWR); if (fd < 0) { ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno)); goto outrun; } using_pseudo = 1; /* Make non-blocking */ flags = fcntl(fd, F_GETFL); if (flags < 0) { ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno)); close(fd); goto outrun; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno)); close(fd); goto outrun; } /* Setup buffering information */ memset(&bi, 0, sizeof(bi)); bi.bufsize = CONF_SIZE/2; bi.txbufpolicy = ZT_POLICY_IMMEDIATE; bi.rxbufpolicy = ZT_POLICY_IMMEDIATE; bi.numbufs = 4; if (ioctl(fd, ZT_SET_BUFINFO, &bi)) { ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno)); close(fd); goto outrun; } x = 1; if (ioctl(fd, ZT_SETLINEAR, &x)) { ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno)); close(fd); goto outrun; } nfds = 1; } else { /* XXX Make sure we're not running on a pseudo channel XXX */ fd = chan->fds[0]; nfds = 0; } memset(&ztc, 0, sizeof(ztc)); /* Check to see if we're in a conference... */ ztc.chan = 0; if (ioctl(fd, ZT_GETCONF, &ztc)) { ast_log(LOG_WARNING, "Error getting conference\n"); close(fd); goto outrun; } if (ztc.confmode) { /* Whoa, already in a conference... Retry... */ if (!retryzap) { ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n"); retryzap = 1; goto zapretry; } } memset(&ztc, 0, sizeof(ztc)); /* Add us to the conference */ ztc.chan = 0; ztc.confno = conf->zapconf; if (confflags & CONFFLAG_MONITOR) ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER; else if (confflags & CONFFLAG_TALKER) ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER; else ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference\n"); close(fd); goto outrun; } ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf); manager_event(EVENT_FLAG_CALL, "MeetmeJoin", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" "Usernum: %i\r\n", chan->name, chan->uniqueid, conf->confno, user->user_no); if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) { firstpass = 1; if (!(confflags & CONFFLAG_QUIET)) conf_play(conf, ENTER); } if (confflags & CONFFLAG_AGI) { /* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND) or use default filename of conf-background.agi */ agifile = pbx_builtin_getvar_helper(chan,"MEETME_AGI_BACKGROUND"); if (!agifile) agifile = agifiledefault; if (!strcasecmp(chan->type,"Zap")) { /* Set CONFMUTE mode on Zap channel to mute DTMF tones */ x = 1; ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); } /* Find a pointer to the agi app and execute the script */ app = pbx_findapp("agi"); if (app) { ret = pbx_exec(chan, app, agifile, 1); } else { ast_log(LOG_WARNING, "Could not find application (agi)\n"); ret = -2; } if (!strcasecmp(chan->type,"Zap")) { /* Remove CONFMUTE mode on Zap channel */ x = 0; ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); } } else { if (!strcasecmp(chan->type,"Zap") && (confflags & CONFFLAG_STARMENU)) { /* Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */ x = 1; ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0); } for(;;) { outfd = -1; ms = -1; c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); /* Update the struct with the actual confflags */ user->userflags = confflags; /* trying to add moh for single person conf */ if (confflags & CONFFLAG_MOH) { if (conf->users == 1) { if (musiconhold == 0) { ast_moh_start(chan, NULL); musiconhold = 1; } } else { if (musiconhold) { ast_moh_stop(chan); musiconhold = 0; } } } /* Leave if the last marked user left */ if (conf->markedusers == 0 && confflags & CONFFLAG_MARKEDEXIT) { ret = -1; break; } /* Check if the admin changed my modes */ if (user->adminflags) { /* Set the new modes */ if ((user->adminflags & ADMINFLAG_MUTED) && (ztc.confmode & ZT_CONF_TALKER)) { ztc.confmode ^= ZT_CONF_TALKER; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } } if (!(user->adminflags & ADMINFLAG_MUTED) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) { ztc.confmode |= ZT_CONF_TALKER; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } } if (user->adminflags & ADMINFLAG_KICKME) { //You have been kicked. if (!ast_streamfile(chan, "conf-kicked", chan->language)) ast_waitstream(chan, ""); ret = 0; break; } } else if (!(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) { ztc.confmode |= ZT_CONF_TALKER; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } } if (c) { if (c->fds[0] != origfd) { if (using_pseudo) { /* Kill old pseudo */ close(fd); } ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n"); retryzap = 0; using_pseudo = 0; goto zapretry; } f = ast_read(c); if (!f) break; if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) { char tmp[2]; tmp[0] = f->subclass; tmp[1] = '\0'; if (ast_exists_extension(chan, exitcontext, tmp, 1, chan->callerid)) { strncpy(chan->context, exitcontext, sizeof(chan->context) - 1); strncpy(chan->exten, tmp, sizeof(chan->exten) - 1); chan->priority = 0; ret = 0; break; } } else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) { ret = 0; break; } else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) { if (musiconhold) { ast_moh_stop(chan); } if ((confflags & CONFFLAG_ADMIN)) { /* Admin menu */ if (!menu_active) { menu_active = 1; /* Record this sound! */ if (!ast_streamfile(chan, "conf-adminmenu", chan->language)) dtmf = ast_waitstream(chan, AST_DIGIT_ANY); else dtmf = 0; } else dtmf = f->subclass; if (dtmf) { switch(dtmf) { case '1': /* Un/Mute */ menu_active = 0; if (ztc.confmode & ZT_CONF_TALKER) { ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER; } else { ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER; } if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } if (ztc.confmode & ZT_CONF_TALKER) { if (!ast_streamfile(chan, "conf-unmuted", chan->language)) ast_waitstream(chan, ""); } else { if (!ast_streamfile(chan, "conf-muted", chan->language)) ast_waitstream(chan, ""); } break; case '2': /* Un/Lock the Conference */ menu_active = 0; if (conf->locked) { conf->locked = 0; if (!ast_streamfile(chan, "conf-unlockednow", chan->language)) ast_waitstream(chan, ""); } else { conf->locked = 1; if (!ast_streamfile(chan, "conf-lockednow", chan->language)) ast_waitstream(chan, ""); } break; default: menu_active = 0; /* Play an error message! */ if (!ast_streamfile(chan, "conf-errormenu", chan->language)) ast_waitstream(chan, ""); break; } } } else { /* User menu */ if (!menu_active) { menu_active = 1; /* Record this sound! */ if (!ast_streamfile(chan, "conf-usermenu", chan->language)) dtmf = ast_waitstream(chan, AST_DIGIT_ANY); else dtmf = 0; } else dtmf = f->subclass; if (dtmf) { switch(dtmf) { case '1': /* Un/Mute */ menu_active = 0; if (ztc.confmode & ZT_CONF_TALKER) { ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER; confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER; } else if (!(user->adminflags & ADMINFLAG_MUTED)) { ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER; confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER; } if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n"); ret = -1; break; } if (ztc.confmode & ZT_CONF_TALKER) { if (!ast_streamfile(chan, "conf-unmuted", chan->language)) ast_waitstream(chan, ""); } else { if (!ast_streamfile(chan, "conf-muted", chan->language)) ast_waitstream(chan, ""); } break; default: menu_active = 0; /* Play an error message! */ if (!ast_streamfile(chan, "conf-errormenu", chan->language)) ast_waitstream(chan, ""); break; } } } if (musiconhold) { ast_moh_start(chan, NULL); } } else if (using_pseudo) { if (f->frametype == AST_FRAME_VOICE) { if (f->subclass == AST_FORMAT_SLINEAR) { /* Carefully write */ careful_write(fd, f->data, f->datalen); } else ast_log(LOG_WARNING, "Huh? Got a non-linear (%d) frame in the conference\n", f->subclass); } } ast_frfree(f); } else if (outfd > -1) { res = read(outfd, buf, CONF_SIZE); if (res > 0) { memset(&fr, 0, sizeof(fr)); fr.frametype = AST_FRAME_VOICE; fr.subclass = AST_FORMAT_SLINEAR; fr.datalen = res; fr.samples = res/2; fr.data = buf; fr.offset = AST_FRIENDLY_OFFSET; if (ast_write(chan, &fr) < 0) { ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno)); /* break; */ } } else ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); } } } if (using_pseudo) close(fd); else { /* Take out of conference */ /* Add us to the conference */ ztc.chan = 0; ztc.confno = 0; ztc.confmode = 0; if (ioctl(fd, ZT_SETCONF, &ztc)) { ast_log(LOG_WARNING, "Error setting conference\n"); } } if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) conf_play(conf, LEAVE); outrun: ast_mutex_lock(&conflock); if (user->user_no) { /* Only cleanup users who really joined! */ manager_event(EVENT_FLAG_CALL, "MeetmeLeave", "Channel: %s\r\n" "Uniqueid: %s\r\n" "Meetme: %s\r\n" "Usernum: %i\r\n", chan->name, chan->uniqueid, conf->confno, user->user_no); prev = NULL; conf->users--; if (confflags & CONFFLAG_MARKEDUSER) conf->markedusers--; cur = confs; if (!conf->users) { /* No more users -- close this one out */ while(cur) { if (cur == conf) { if (prev) prev->next = conf->next; else confs = conf->next; break; } prev = cur; cur = cur->next; } if (!cur) ast_log(LOG_WARNING, "Conference not found\n"); if (conf->chan) ast_hangup(conf->chan); else close(conf->fd); free(conf); } else { /* Remove the user struct */ if (user == conf->firstuser) { if (user->nextuser) { /* There is another entry */ user->nextuser->prevuser = NULL; } else { /* We are the only entry */ conf->lastuser = NULL; } /* In either case */ conf->firstuser = user->nextuser; } else if (user == conf->lastuser){ if (user->prevuser) user->prevuser->nextuser = NULL; else ast_log(LOG_ERROR, "Bad bad bad! We're the last, not the first, but nobody before us??\n"); conf->lastuser = user->prevuser; } else { if (user->nextuser) user->nextuser->prevuser = user->prevuser; else ast_log(LOG_ERROR, "Bad! Bad! Bad! user->nextuser is NULL but we're not the end!\n"); if (user->prevuser) user->prevuser->nextuser = user->nextuser; else ast_log(LOG_ERROR, "Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning!\n"); } } /* Return the number of seconds the user was in the conf */ snprintf(meetmesecs, sizeof(meetmesecs), "%i", (int) (time(NULL) - user->jointime)); pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs); } free(user); ast_mutex_unlock(&conflock); return ret; }
static int app_exec(struct ast_channel *chan, void *data) { int res = 0, argc = 0, max_digits = 0, timeout = 0, alreadyran = 0, old_writeformat = 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 myframe { struct ast_frame f; unsigned char offset[AST_FRIENDLY_OFFSET]; unsigned char frdata[framesize]; } myf; 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); old_writeformat = chan->writeformat; if (ast_set_write_format(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; myf.f.subclass = AST_FORMAT_ULAW; 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 originDTMF = f->subclass; 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", originDTMF, rc); } else { sprintf(results, "%c", originDTMF); } 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->cid.cid_num)) { 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 && old_writeformat) { ast_set_write_format(chan, old_writeformat); } ast_module_user_remove(u); return res; }
static int conf_run(struct ast_channel *chan, int confno, int confflags) { int fd; struct dahdi_confinfo dahdic; struct ast_frame *f; struct ast_channel *c; struct ast_frame fr; int outfd; int ms; int nfds; int res; int flags; int retrydahdi; int origfd; int ret = -1; char input[4]; int ic = 0; struct dahdi_bufferinfo bi; char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; char *buf = __buf + AST_FRIENDLY_OFFSET; /* Set it into U-law mode (write) */ if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) { ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name); goto outrun; } /* Set it into U-law mode (read) */ if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) { ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name); goto outrun; } ast_indicate(chan, -1); retrydahdi = strcasecmp(chan->tech->type, "DAHDI"); dahdiretry: origfd = chan->fds[0]; if (retrydahdi) { fd = open("/dev/dahdi/pseudo", O_RDWR); if (fd < 0) { ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno)); goto outrun; } /* Make non-blocking */ flags = fcntl(fd, F_GETFL); if (flags < 0) { ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno)); close(fd); goto outrun; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno)); close(fd); goto outrun; } /* Setup buffering information */ memset(&bi, 0, sizeof(bi)); bi.bufsize = CONF_SIZE; bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE; bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE; bi.numbufs = 4; if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) { ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno)); close(fd); goto outrun; } nfds = 1; } else { /* XXX Make sure we're not running on a pseudo channel XXX */ fd = chan->fds[0]; nfds = 0; } memset(&dahdic, 0, sizeof(dahdic)); /* Check to see if we're in a conference... */ dahdic.chan = 0; if (ioctl(fd, DAHDI_GETCONF, &dahdic)) { ast_log(LOG_WARNING, "Error getting conference\n"); close(fd); goto outrun; } if (dahdic.confmode) { /* Whoa, already in a conference... Retry... */ if (!retrydahdi) { ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n"); retrydahdi = 1; goto dahdiretry; } } memset(&dahdic, 0, sizeof(dahdic)); /* Add us to the conference */ dahdic.chan = 0; dahdic.confno = confno; dahdic.confmode = DAHDI_CONF_MONITORBOTH; if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { ast_log(LOG_WARNING, "Error setting conference\n"); close(fd); goto outrun; } ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", chan->name, confno); for (;;) { outfd = -1; ms = -1; c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); if (c) { if (c->fds[0] != origfd) { if (retrydahdi) { /* Kill old pseudo */ close(fd); } ast_debug(1, "Ooh, something swapped out under us, starting over\n"); retrydahdi = 0; goto dahdiretry; } f = ast_read(c); if (!f) { break; } if (f->frametype == AST_FRAME_DTMF) { if (f->subclass == '#') { ret = 0; break; } else if (f->subclass == '*') { ret = -1; break; } else { input[ic++] = f->subclass; } if (ic == 3) { input[ic++] = '\0'; ic = 0; ret = atoi(input); ast_verb(3, "DAHDIScan: change channel to %d\n", ret); break; } } if (fd != chan->fds[0]) { if (f->frametype == AST_FRAME_VOICE) { if (f->subclass == AST_FORMAT_ULAW) { /* Carefully write */ careful_write(fd, f->data.ptr, f->datalen); } else { ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass); } } } ast_frfree(f); } else if (outfd > -1) { res = read(outfd, buf, CONF_SIZE); if (res > 0) { memset(&fr, 0, sizeof(fr)); fr.frametype = AST_FRAME_VOICE; fr.subclass = AST_FORMAT_ULAW; fr.datalen = res; fr.samples = res; fr.data.ptr = buf; fr.offset = AST_FRIENDLY_OFFSET; if (ast_write(chan, &fr) < 0) { ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno)); /* break; */ } } else { ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); } } } if (f) { ast_frfree(f); } if (fd != chan->fds[0]) { close(fd); } else { /* Take out of conference */ /* Add us to the conference */ dahdic.chan = 0; dahdic.confno = 0; dahdic.confmode = 0; if (ioctl(fd, DAHDI_SETCONF, &dahdic)) { ast_log(LOG_WARNING, "Error setting conference\n"); } } outrun: return ret; }
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 mp3_exec(struct ast_channel *chan, const char *data) { int res=0; int fds[2]; int ms = -1; int pid = -1; RAII_VAR(struct ast_format *, owriteformat, NULL, ao2_cleanup); int timeout = 2000; struct timeval next; struct ast_frame *f; struct myframe { struct ast_frame f; char offset[AST_FRIENDLY_OFFSET]; short frdata[160]; } myf = { .f = { 0, }, }; struct ast_format * native_format; unsigned int sampling_rate; struct ast_format * write_format; if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n"); return -1; } if (pipe(fds)) { ast_log(LOG_WARNING, "Unable to create pipe\n"); return -1; } ast_stopstream(chan); native_format = ast_format_cap_get_format(ast_channel_nativeformats(chan), 0); sampling_rate = ast_format_get_sample_rate(native_format); write_format = ast_format_cache_get_slin_by_rate(sampling_rate); owriteformat = ao2_bump(ast_channel_writeformat(chan)); res = ast_set_write_format(chan, write_format); if (res < 0) { ast_log(LOG_WARNING, "Unable to set write format to signed linear\n"); return -1; } myf.f.frametype = AST_FRAME_VOICE; myf.f.subclass.format = write_format; 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; res = mp3play(data, sampling_rate, fds[1]); if (!strncasecmp(data, "http://", 7)) { timeout = 10000; } /* 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), timeout); if (res > 0) { myf.f.datalen = res; myf.f.samples = res / 2; 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, sampling_rate)); } 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) ast_set_write_format(chan, owriteformat); ast_frfree(&myf.f); return res; }
static int txfax_exec(struct ast_channel *chan, void *data) { int res = 0; char source_file[256]; char *x; char *s; char *t; char *v; int option; int len; t30_state_t fax; int calling_party; int verbose; int samples; struct localuser *u; struct ast_frame *inf = NULL; struct ast_frame outf; int original_read_fmt; int original_write_fmt; uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET]; uint8_t *buf = __buf + AST_FRIENDLY_OFFSET; if (chan == NULL) { ast_log(LOG_WARNING, "Fax transmit channel is NULL. Giving up.\n"); return -1; } span_set_message_handler(span_message); /* The next few lines of code parse out the filename and header from the input string */ if (data == NULL) { /* No data implies no filename or anything is present */ ast_log(LOG_WARNING, "Txfax requires an argument (filename)\n"); return -1; } calling_party = FALSE; verbose = FALSE; source_file[0] = '\0'; for (option = 0, v = s = data; v; option++, s++) { t = s; v = strchr(s, '|'); s = (v) ? v : s + strlen(s); strncpy((char *) buf, t, s - t); buf[s - t] = '\0'; if (option == 0) { /* The first option is always the file name */ len = s - t; if (len > 255) len = 255; strncpy(source_file, t, len); source_file[len] = '\0'; } else if (strncmp("caller", t, s - t) == 0) { calling_party = TRUE; } else if (strncmp("debug", t, s - t) == 0) { verbose = TRUE; } } /* Done parsing */ LOCAL_USER_ADD(u); if (chan->_state != AST_STATE_UP) { /* Shouldn't need this, but checking to see if channel is already answered * Theoretically asterisk should already have answered before running the app */ res = ast_answer(chan); } if (!res) { original_read_fmt = chan->readformat; if (original_read_fmt != AST_FORMAT_SLINEAR) { res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n"); return -1; } } original_write_fmt = chan->writeformat; if (original_write_fmt != AST_FORMAT_SLINEAR) { res = ast_set_write_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n"); res = ast_set_read_format(chan, original_read_fmt); if (res) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); return -1; } } fax_init(&fax, calling_party, NULL); if (verbose) fax.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"); if (x && x[0]) t30_set_local_ident(&fax, x); x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO"); if (x && x[0]) t30_set_header_info(&fax, x); t30_set_tx_file(&fax, source_file, -1, -1); //t30_set_phase_b_handler(&fax, phase_b_handler, chan); //t30_set_phase_d_handler(&fax, phase_d_handler, chan); t30_set_phase_e_handler(&fax, phase_e_handler, chan); while (ast_waitfor(chan, -1) > -1) { inf = ast_read(chan); if (inf == NULL) { res = -1; break; } if (inf->frametype == AST_FRAME_VOICE) { if (fax_rx(&fax, inf->data, inf->samples)) break; samples = (inf->samples <= MAX_BLOCK_SIZE) ? inf->samples : MAX_BLOCK_SIZE; len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples); if (len) { memset(&outf, 0, sizeof(outf)); outf.frametype = AST_FRAME_VOICE; outf.subclass = AST_FORMAT_SLINEAR; outf.datalen = len*sizeof(int16_t); outf.samples = len; outf.data = &buf[AST_FRIENDLY_OFFSET]; outf.offset = AST_FRIENDLY_OFFSET; if (ast_write(chan, &outf) < 0) { ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno)); break; } } } ast_frfree(inf); } if (inf == NULL) { ast_log(LOG_DEBUG, "Got hangup\n"); res = -1; } if (original_read_fmt && original_read_fmt != AST_FORMAT_SLINEAR) { res = ast_set_read_format(chan, original_read_fmt); if (res) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); } if (original_write_fmt && original_write_fmt != AST_FORMAT_SLINEAR) { res = ast_set_write_format(chan, original_write_fmt); if (res) ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name); } fax_release(&fax); } else { ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name); } LOCAL_USER_REMOVE(u); 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 ms = -1; int pid = -1; int needed = 0; int owriteformat; struct ast_frame *f; struct myframe { struct ast_frame f; char offset[AST_FRIENDLY_OFFSET]; char frdata[2048]; } myf; if (pipe(fds)) { ast_log(LOG_WARNING, "Unable to create pipe\n"); return -1; } /* Answer if it's not already going */ if (chan->_state != AST_STATE_UP) ast_answer(chan); ast_stopstream(chan); ast_indicate(chan, -1); owriteformat = chan->writeformat; res = ast_set_write_format(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) { pid = res; /* Order is important -- there's almost always going to be mp3... we want to prioritize the user */ for (;;) { ms = 1000; res = ast_waitfor(chan, ms); 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_log(LOG_DEBUG, "User pressed a key\n"); if (intkeys && strchr(intkeys, f->subclass)) { res = f->subclass; 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; myf.f.subclass = AST_FORMAT_SLINEAR; 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.data = myf.frdata; if (ast_write(chan, &myf.f) < 0) { res = -1; ast_frfree(f); break; } if (res < needed) { /* last frame */ ast_log(LOG_DEBUG, "Last frame\n"); res=0; ast_frfree(f); break; } } else { ast_log(LOG_DEBUG, "No more waveform\n"); res = 0; } } ast_frfree(f); } } close(fds[0]); close(fds[1]); /* if (pid > -1) */ /* kill(pid, SIGKILL); */ if (!res && owriteformat) ast_set_write_format(chan, owriteformat); return res; }