static int faxgen_generate(struct cw_channel *chan, void *data, int samples) { int len; fax_state_t *fax; struct cw_frame outf; uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*CW_FRIENDLY_OFFSET]; uint8_t *buf = __buf + CW_FRIENDLY_OFFSET; fax = (fax_state_t*) data; samples = (samples <= MAX_BLOCK_SIZE) ? samples : MAX_BLOCK_SIZE; if ((len = fax_tx(fax, (int16_t *) &buf[CW_FRIENDLY_OFFSET], samples)) > 0) { cw_fr_init_ex(&outf, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, "FAX"); outf.datalen = len*sizeof(int16_t); outf.samples = len; outf.data = &buf[CW_FRIENDLY_OFFSET]; outf.offset = CW_FRIENDLY_OFFSET; if (cw_write(chan, &outf) < 0) cw_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno)); } return 0; }
static struct cw_filestream *pcm_open(FILE *f) { /* We don't have any header to read or anything really, but if we did, it would go here. We also might want to check and be sure it's a valid file. */ struct cw_filestream *tmp; if ((tmp = malloc(sizeof(struct cw_filestream)))) { memset(tmp, 0, sizeof(struct cw_filestream)); if (cw_mutex_lock(&pcm_lock)) { cw_log(LOG_WARNING, "Unable to lock pcm list\n"); free(tmp); return NULL; } tmp->f = f; cw_fr_init_ex(&tmp->fr, CW_FRAME_VOICE, CW_FORMAT_ULAW, name); tmp->fr.data = tmp->buf; /* datalen will vary for each frame */ glistcnt++; cw_mutex_unlock(&pcm_lock); cw_update_use_count(); } return tmp; }
static struct cw_filestream *au_open(FILE *f) { struct cw_filestream *tmp; if (!(tmp = malloc(sizeof(struct cw_filestream)))) { cw_log(LOG_ERROR, "Out of memory\n"); return NULL; } memset(tmp, 0, sizeof(struct cw_filestream)); if (check_header(f) < 0) { free(tmp); return NULL; } if (cw_mutex_lock(&au_lock)) { cw_log(LOG_WARNING, "Unable to lock au count\n"); free(tmp); return NULL; } tmp->f = f; cw_fr_init_ex(&tmp->fr, CW_FRAME_VOICE, CW_FORMAT_ULAW, NULL); tmp->fr.data = tmp->buf; /* datalen will vary for each frame */ tmp->fr.src = name; localusecnt++; cw_mutex_unlock(&au_lock); cw_update_use_count(); return tmp; }
static int linear_generator(struct cw_channel *chan, void *data, int samples) { struct cw_frame f; short buf[2048 + CW_FRIENDLY_OFFSET / 2]; struct linear_state *ls = data; int res, len; len = samples*sizeof(int16_t); if (len > sizeof(buf) - CW_FRIENDLY_OFFSET) { cw_log(LOG_WARNING, "Can't generate %d bytes of data!\n" ,len); len = sizeof(buf) - CW_FRIENDLY_OFFSET; } memset(&f, 0, sizeof(f)); res = read(ls->fd, buf + CW_FRIENDLY_OFFSET/2, len); if (res > 0) { cw_fr_init_ex(&f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, NULL); f.data = buf + CW_FRIENDLY_OFFSET/sizeof(int16_t); f.datalen = res; f.samples = res/sizeof(int16_t); f.offset = CW_FRIENDLY_OFFSET; cw_write(chan, &f); if (res == len) return 0; } return -1; }
static struct cw_filestream *g726_16_open(FILE *f) { /* We don't have any header to read or anything really, but if we did, it would go here. We also might want to check and be sure it's a valid file. */ struct cw_filestream *tmp; if ((tmp = malloc(sizeof(struct cw_filestream)))) { memset(tmp, 0, sizeof(struct cw_filestream)); if (cw_mutex_lock(&g726_lock)) { cw_log(LOG_WARNING, "Unable to lock g726 list.\n"); free(tmp); return NULL; } tmp->f = f; cw_fr_init_ex(&tmp->fr, CW_FRAME_VOICE, CW_FORMAT_G726, name16); tmp->rate = RATE_16; tmp->fr.data = tmp->g726; /* datalen will vary for each frame */ glistcnt++; if (option_debug) cw_log(LOG_DEBUG, "Created filestream G.726-%dk.\n", 40 - tmp->rate * 8); cw_mutex_unlock(&g726_lock); cw_update_use_count(); } return tmp; }
static struct cw_filestream *h263_open(FILE *f) { /* We don't have any header to read or anything really, but if we did, it would go here. We also might want to check and be sure it's a valid file. */ struct cw_filestream *tmp; unsigned int ts; int res; if ((res = fread(&ts, 1, sizeof(ts), f)) < sizeof(ts)) { cw_log(LOG_WARNING, "Empty file!\n"); return NULL; } if ((tmp = malloc(sizeof(struct cw_filestream)))) { memset(tmp, 0, sizeof(struct cw_filestream)); if (cw_mutex_lock(&h263_lock)) { cw_log(LOG_WARNING, "Unable to lock h263 list\n"); free(tmp); return NULL; } tmp->f = f; cw_fr_init_ex(&tmp->fr, CW_FRAME_VIDEO, CW_FORMAT_H263, name); tmp->fr.data = tmp->h263; /* datalen will vary for each frame */ glistcnt++; cw_mutex_unlock(&h263_lock); cw_update_use_count(); } return tmp; }
static struct cw_frame *g722tolin_sample(void) { static struct cw_frame f; cw_fr_init_ex(&f, CW_FRAME_VOICE, CW_FORMAT_G722, __PRETTY_FUNCTION__); f.datalen = sizeof(g722_ex); f.samples = sizeof(g722_ex)*2; f.data = (uint8_t *) g722_ex; return &f; }
static struct cw_frame *lintog722_sample(void) { static struct cw_frame f; cw_fr_init_ex(&f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, __PRETTY_FUNCTION__); f.datalen = sizeof (slin_ex); /* Assume 8000 Hz */ f.samples = sizeof (slin_ex)/sizeof(int16_t); f.data = (int16_t *) slin_ex; return &f; }
static struct cw_frame *lpc10tolin_sample(void) { static struct cw_frame f; cw_fr_init_ex(&f, CW_FRAME_VOICE, CW_FORMAT_LPC10, __PRETTY_FUNCTION__); f.datalen = sizeof(lpc10_ex); /* All frames are 22 ms long (maybe a little more -- why did he choose LPC10_SAMPLES_PER_FRAME sample frames anyway?? */ f.samples = LPC10_SAMPLES_PER_FRAME; f.data = lpc10_ex; return &f; }
static int playtones_generator(struct cw_channel *chan, void *data, int samples) { struct playtones_state *ps = data; struct playtones_item *pi; int len; int x; /* * We need to prepare a frame with 16 * timelen samples as we're * generating SLIN audio */ len = samples + samples; if (len > sizeof(ps->data)/sizeof(int16_t) - 1) { cw_log(LOG_WARNING, "Can't generate that much data!\n"); return -1; } x = tone_gen(&ps->tone_state, ps->data, samples); pi = &ps->items[ps->npos]; /* Assemble frame */ cw_fr_init_ex(&ps->f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, NULL); ps->f.datalen = len; ps->f.samples = samples; ps->f.offset = CW_FRIENDLY_OFFSET; ps->f.data = ps->data; cw_write(chan, &ps->f); ps->pos += x; if (pi->duration && ps->pos >= pi->duration*8) { /* item finished? */ ps->pos = 0; /* start new item */ ps->npos++; if (ps->npos >= ps->nitems) { /* last item */ if (ps->reppos == -1) /* repeat set? */ return -1; ps->npos = ps->reppos; /* redo from top */ } /* Prepare the tone generator for more */ pi = &ps->items[ps->npos]; tone_setup(ps, pi); } return 0; }
static struct cw_frame *lintog722_frameout(struct cw_translator_pvt *pvt) { struct g722_encoder_pvt *tmp = (struct g722_encoder_pvt *) pvt; if (tmp->tail == 0) return NULL; cw_fr_init_ex(&tmp->f, CW_FRAME_VOICE, CW_FORMAT_G722, __PRETTY_FUNCTION__); tmp->f.samples = tmp->tail*2; tmp->f.offset = CW_FRIENDLY_OFFSET; tmp->f.data = tmp->outbuf; tmp->f.datalen = tmp->tail; tmp->tail = 0; return &tmp->f; }
static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) { struct cw_frame outf; struct cw_channel *chan; chan = (struct cw_channel *) user_data; cw_fr_init_ex(&outf, CW_FRAME_MODEM, CW_MODEM_T38, "FAX"); outf.datalen = len; outf.data = (char *) buf; outf.tx_copies = count; if (cw_write(chan, &outf) < 0) cw_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno)); return 0; }
static struct cw_frame *h263_read(struct cw_filestream *s, int *whennext) { int res; int mark=0; unsigned short len; unsigned int ts; /* Send a frame from the file to the appropriate channel */ cw_fr_init_ex(&s->fr, CW_FRAME_VIDEO, CW_FORMAT_H263, NULL); s->fr.offset = CW_FRIENDLY_OFFSET; s->fr.data = s->h263; if ((res = fread(&len, 1, sizeof(len), s->f)) < 1) return NULL; len = ntohs(len); if (len & 0x8000) { mark = 1; } len &= 0x7fff; if (len > sizeof(s->h263)) { cw_log(LOG_WARNING, "Length %d is too long\n", len); return NULL; } if ((res = fread(s->h263, 1, len, s->f)) != len) { if (res) cw_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); return NULL; } s->fr.samples = s->lastts; s->fr.datalen = len; s->fr.subclass |= mark; s->fr.delivery.tv_sec = 0; s->fr.delivery.tv_usec = 0; if ((res = fread(&ts, 1, sizeof(ts), s->f)) == sizeof(ts)) { s->lastts = ntohl(ts); *whennext = s->lastts * 4/45; } else { *whennext = 0; } return &s->fr; }
static struct cw_frame *lpc10tolin_frameout(struct cw_translator_pvt *tmp) { if (tmp->tail == 0) return NULL; /* Signed linear is no particular frame size, so just send whatever we have in the buffer in one lump sum */ cw_fr_init_ex(&tmp->f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, __PRETTY_FUNCTION__); tmp->f.datalen = tmp->tail*sizeof(int16_t); /* Assume 8000 Hz */ tmp->f.samples = tmp->tail; tmp->f.offset = CW_FRIENDLY_OFFSET; tmp->f.data = tmp->buf; /* Reset tail pointer */ tmp->tail = 0; return &tmp->f; }
int queue_incoming_silent_frame( struct cw_conf_member *member, int count) { struct cw_frame f; int t = 0; memset(member->framedata,0,sizeof(member->framedata)); cw_fr_init_ex(&f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, "Nconf"); f.data = member->framedata; f.datalen = member->samples * sizeof(int16_t); f.samples = member->samples; f.offset = 0; // Actually queue some frames for (t = 0; t < count; t++) queue_incoming_frame(member, &f); return 0; }
static struct cw_frame *gsm_read(struct cw_filestream *s, int *whennext) { int res; cw_fr_init_ex(&s->fr, CW_FRAME_VOICE, CW_FORMAT_GSM, NULL); s->fr.offset = CW_FRIENDLY_OFFSET; s->fr.samples = 160; s->fr.datalen = 33; s->fr.data = s->gsm; if ((res = fread(s->gsm, 1, 33, s->f)) != 33) { if (res) cw_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); return NULL; } *whennext = 160; return &s->fr; }
int cw_dtmf_stream(struct cw_channel *chan,struct cw_channel *peer,char *digits,int between) { char *ptr; int res = 0; struct cw_frame f; if (!between) between = 100; if (peer) res = cw_autoservice_start(peer); if (!res) { res = cw_waitfor(chan,100); if (res > -1) { for (ptr=digits; *ptr; ptr++) { if (*ptr == 'w') { res = cw_safe_sleep(chan, 500); if (res) break; continue; } cw_fr_init_ex(&f, CW_FRAME_DTMF, *ptr, NULL); f.src = "cw_dtmf_stream"; if (strchr("0123456789*#abcdABCD",*ptr) == NULL) { cw_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr); } else { res = cw_write(chan, &f); if (res) break; /* pause between digits */ res = cw_safe_sleep(chan,between); if (res) break; } } } if (peer) res = cw_autoservice_stop(peer); } return res; }
static struct cw_frame *g726_read(struct cw_filestream *s, int *whennext) { int res; /* Send a frame from the file to the appropriate channel */ cw_fr_init_ex(&s->fr, CW_FRAME_VOICE, CW_FORMAT_G726, NULL); s->fr.offset = CW_FRIENDLY_OFFSET; s->fr.samples = 8*FRAME_TIME; s->fr.datalen = frame_size[s->rate]; s->fr.data = s->g726; if ((res = fread(s->g726, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (res) cw_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); return NULL; } *whennext = s->fr.samples; return &s->fr; }
static struct cw_frame *pcm_read(struct cw_filestream *s, int *whennext) { int res; int delay; /* Send a frame from the file to the appropriate channel */ cw_fr_init_ex(&s->fr, CW_FRAME_VOICE, CW_FORMAT_ULAW, NULL); s->fr.offset = CW_FRIENDLY_OFFSET; s->fr.data = s->buf; if ((res = fread(s->buf, 1, BUF_SIZE, s->f)) < 1) { if (res) cw_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); return NULL; } s->fr.samples = res; s->fr.datalen = res; delay = s->fr.samples; *whennext = delay; return &s->fr; }
static struct cw_frame *lintolpc10_frameout(struct cw_translator_pvt *tmp) { int consumed = 0; /* We can't work on anything less than a frame in size */ if (tmp->tail < LPC10_SAMPLES_PER_FRAME) return NULL; /* Start with an empty frame */ cw_fr_init_ex(&tmp->f, CW_FRAME_VOICE, CW_FORMAT_LPC10, __PRETTY_FUNCTION__); while (tmp->tail >= LPC10_SAMPLES_PER_FRAME) { if (tmp->f.datalen + LPC10_BYTES_IN_COMPRESSED_FRAME > sizeof(tmp->outbuf)) { cw_log(LOG_WARNING, "Out of buffer space\n"); return NULL; } /* Encode a frame of data */ lpc10_encode(tmp->lpc10.enc, ((uint8_t *)tmp->outbuf) + tmp->f.datalen, &tmp->buf[consumed], 180); tmp->f.datalen += LPC10_BYTES_IN_COMPRESSED_FRAME; tmp->f.samples += LPC10_SAMPLES_PER_FRAME; /* Use one of the two left over bits to record if this is a 22 or 23 ms frame... important for IAX use */ tmp->longer = 1 - tmp->longer; #if 0 /* What the heck was this for? */ ((char *)(tmp->f.data))[consumed - 1] |= tmp->longer; #endif tmp->tail -= LPC10_SAMPLES_PER_FRAME; consumed += LPC10_SAMPLES_PER_FRAME; } tmp->f.mallocd = 0; tmp->f.offset = CW_FRIENDLY_OFFSET; tmp->f.src = __PRETTY_FUNCTION__; tmp->f.data = tmp->outbuf; /* Move the data at the end of the buffer to the front */ if (tmp->tail) memmove(tmp->buf, tmp->buf + consumed, tmp->tail*sizeof(int16_t)); return &tmp->f; }
/*! * \brief Read a frame full of audio data from the filestream. * \param s The filestream. * \param whennext Number of sample times to schedule the next call. * \return A pointer to a frame containing audio data or NULL ifthere is no more audio data. */ static struct cw_frame *ogg_vorbis_read(struct cw_filestream *s, int *whennext) { int clipflag = 0; int i; int j; float **pcm; float *mono; double accumulator[SAMPLES_MAX]; int val; int samples_in; int samples_out = 0; for (;;) { /* See if we have filled up an audio frame yet */ if (samples_out == SAMPLES_MAX) break; /* See ifVorbis decoder has some audio data for us ... */ samples_in = read_samples(s, &pcm); if (samples_in <= 0) break; /* Got some audio data from Vorbis... */ /* Convert the float audio data to 16-bit signed linear */ clipflag = 0; samples_in = samples_in < (SAMPLES_MAX - samples_out) ? samples_in : (SAMPLES_MAX - samples_out); for(j = 0; j < samples_in; j++) accumulator[j] = 0.0; for (i = 0; i < s->vi.channels; i++) { mono = pcm[i]; for (j = 0; j < samples_in; j++) accumulator[j] += mono[j]; } for (j = 0; j < samples_in; j++) { val = accumulator[j] * 32767.0 / s->vi.channels; if (val > 32767) { val = 32767; clipflag = 1; } if (val < -32768) { val = -32768; clipflag = 1; } s->buffer[samples_out + j] = val; } if (clipflag) cw_log(LOG_WARNING, "Clipping in frame %ld\n", (long)(s->vd.sequence)); /* Tell the Vorbis decoder how many samples we actually used. */ vorbis_synthesis_read(&s->vd, samples_in); samples_out += samples_in; } if (samples_out > 0) { cw_fr_init_ex(&s->fr, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, name); s->fr.offset = CW_FRIENDLY_OFFSET; s->fr.datalen = samples_out*sizeof(int16_t); s->fr.data = s->buffer; s->fr.samples = samples_out; *whennext = samples_out; return &s->fr; } return NULL; }
static int fax_audio(struct cw_channel *chan, fax_state_t *fax, const char *file, int calling_party, int verbose) { char *x; struct cw_frame *inf = NULL; struct cw_frame outf; int ready = 1; int samples = 0; int res = 0; int len = 0; int generator_mode = 0; uint64_t begin = 0; uint64_t received_frames = 0; uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*CW_FRIENDLY_OFFSET]; uint8_t *buf = __buf + CW_FRIENDLY_OFFSET; #if 0 struct cw_frame *dspf = NULL; struct cw_dsp *dsp = NULL; #endif uint64_t voice_frames; t30_state_t *t30; memset(fax, 0, sizeof(*fax)); if (fax_init(fax, calling_party) == NULL) { cw_log(LOG_WARNING, "Unable to start FAX\n"); return -1; } t30 = fax_get_t30_state(fax); fax_set_transmit_on_idle(fax, TRUE); span_log_set_message_handler(&fax->logging, span_message); span_log_set_message_handler(&t30->logging, span_message); if (verbose) { span_log_set_level(&fax->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); span_log_set_level(&t30->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); } fax_set_common(chan, t30, file, calling_party, verbose); fax_set_transmit_on_idle(fax, TRUE); if (calling_party) { voice_frames = 0; } else { #if 0 /* Initializing the DSP */ if ((dsp = cw_dsp_new()) == NULL) { cw_log(LOG_WARNING, "Unable to allocate DSP!\n"); } else { cw_dsp_set_threshold(dsp, 256); cw_dsp_set_features(dsp, DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_CNG_DETECT); cw_dsp_digitmode(dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF); } #endif voice_frames = 1; } /* This is the main loop */ begin = nowis(); while (ready && ready_to_talk(chan)) { if (chan->t38_status == T38_NEGOTIATED) break; if ((res = cw_waitfor(chan, 20)) < 0) { ready = 0; break; } if (!t30_call_active(t30)) break; if ((inf = cw_read(chan)) == NULL) { ready = 0; break; } /* We got a frame */ if (inf->frametype == CW_FRAME_VOICE) { #if 0 if (dsp) { if ((dspf = cw_frdup(inf))) dspf = cw_dsp_process(chan, dsp, dspf); if (dspf) { if (dspf->frametype == CW_FRAME_DTMF) { if (dspf->subclass == 'f') { cw_log(LOG_DEBUG, "Fax detected in RxFax !!!\n"); cw_app_request_t38(chan); /* Prevent any further attempts to negotiate T.38 */ cw_dsp_free(dsp); dsp = NULL; } } cw_fr_free(dspf); dspf = NULL; } } #else if (voice_frames) { /* Wait a little before trying to switch to T.38, as some things don't seem to like entirely missing the audio. */ if (++voice_frames == 100) { cw_log(LOG_DEBUG, "Requesting T.38 negotation in RxFax !!!\n"); cw_app_request_t38(chan); voice_frames = 0; } } #endif received_frames++; if (fax_rx(fax, inf->data, inf->samples)) break; samples = (inf->samples <= MAX_BLOCK_SIZE) ? inf->samples : MAX_BLOCK_SIZE; if ((len = fax_tx(fax, (int16_t *) &buf[CW_FRIENDLY_OFFSET], samples)) > 0) { cw_fr_init_ex(&outf, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, "FAX"); outf.datalen = len*sizeof(int16_t); outf.samples = len; outf.data = &buf[CW_FRIENDLY_OFFSET]; outf.offset = CW_FRIENDLY_OFFSET; if (cw_write(chan, &outf) < 0) { cw_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno)); break; } } } else { if ((nowis() - begin) > 1000000) { if (received_frames < 20) { /* Just to be sure we have had no frames ... */ cw_log(LOG_NOTICE, "Switching to generator mode\n"); generator_mode = 1; break; } } } cw_fr_free(inf); inf = NULL; } if (inf) { cw_fr_free(inf); inf = NULL; } if (generator_mode) { /* This is activated when we don't receive any frame for X seconds (see above)... */ cw_log(LOG_NOTICE, "Starting generator\n"); #if 0 if (dsp) cw_dsp_reset(dsp); #endif cw_generator_activate(chan, &faxgen, fax); while (ready && ready_to_talk(chan)) { if (chan->t38_status == T38_NEGOTIATED) break; if ((res = cw_waitfor(chan, 20)) < 0) { ready = 0; break; } if (!t30_call_active(t30)) break; if ((inf = cw_read(chan)) == NULL) { ready = 0; break; } /* We got a frame */ if (inf->frametype == CW_FRAME_VOICE) { #if 0 if (dsp) { if ((dspf = cw_frdup(inf))) dspf = cw_dsp_process(chan, dsp, dspf); if (dspf) { if (dspf->frametype == CW_FRAME_DTMF) { if (dspf->subclass == 'f') { cw_log(LOG_DEBUG, "Fax detected in RxFax !!!\n"); cw_app_request_t38(chan); /* Prevent any further attempts to negotiate T.38 */ cw_dsp_free(dsp); dsp = NULL; } } cw_fr_free(dspf); dspf = NULL; } } #else if (voice_frames) { if (++voice_frames == 100) { cw_log(LOG_DEBUG, "Requesting T.38 negotation in RxFax !!!\n"); cw_app_request_t38(chan); voice_frames = 0; } } #endif if (fax_rx(fax, inf->data, inf->samples)) { ready = 0; break; } } cw_fr_free(inf); inf = NULL; } if (inf) { cw_fr_free(inf); inf = NULL; } cw_log(LOG_NOTICE, "Stopping generator\n"); cw_generator_deactivate(chan); } #if 0 if (dsp) cw_dsp_free(dsp); #endif return ready; }
struct cw_frame* get_outgoing_frame( struct cw_conference *conf, struct cw_conf_member* member, int samples ) { // // sanity checks // // check on conf if ( conf == NULL ) { cw_log( LOG_ERROR, "unable to queue null conference\n" ) ; return NULL ; } if ( conf->memberlist == NULL ) { cw_log( LOG_ERROR, "unable to queue for a null memberlist\n" ) ; return NULL ; } // check on member if ( member == NULL ) { cw_log( LOG_ERROR, "unable to queue frame for null member\n" ) ; return NULL ; } // *********************************** // Mixing procedure // *********************************** int members =0; struct cw_frame *f = NULL; struct cw_conf_member *mixmember; int16_t *dst = member->framedata; int16_t *src = NULL; memset(member->framedata,0,sizeof(member->framedata)); mixmember=conf->memberlist; while ( mixmember ) { if ( mixmember!=member && mixmember->is_speaking && ( mixmember->type != MEMBERTYPE_CONSULTANT || ( mixmember->type == MEMBERTYPE_CONSULTANT && member->type == MEMBERTYPE_MASTER ) ) ) { members++; src = mixmember->cbuf->buffer8k; #if ( APP_NCONFERENCE_DEBUG == 1 ) if(vdebug) cw_log(CW_CONF_DEBUG, "Mixing memb %s Chan %s Ind %d Samples %d " " bufpos: %p with offset %p FOR MEMBER %s\n", mixmember->id, mixmember->chan->name, mixmember->cbuf->index8k, samples, member->framedata, member->framedata + CW_FRIENDLY_OFFSET/sizeof(int16_t), member->chan->name ); #endif mix_slinear_frames( dst, src, samples, mixmember->cbuf->index8k, sizeof(mixmember->cbuf->buffer8k)/sizeof(int16_t) ); } mixmember=mixmember->next; } //Building the frame f = calloc(1, sizeof(struct cw_frame)); if (f != NULL) { cw_fr_init_ex(f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, "Nconf"); f->data = member->framedata; f->datalen = samples*sizeof(int16_t); f->samples = samples; f->offset = 0; } else return NULL; #if ( APP_NCONFERENCE_DEBUG == 1 ) if (vdebug && members) { int count=0; int16_t *msrc; msrc = f->data + CW_FRIENDLY_OFFSET; if (vdebug) cw_log(CW_CONF_DEBUG, "Offset %d OFO: %d Data at %p SRC at %p memberdata at %p \n", f->offset, CW_FRIENDLY_OFFSET, f->data, &msrc, member->framedata ); for( count=0; count<f->samples; count++ ) { cw_log(CW_CONF_DEBUG, "DUMP POS %04d VALUE %08d at %p \n", count, msrc[count], &msrc[count] ); } } #endif return f ; }
static int pipe_exec(struct cw_channel *chan, int argc, char **argv) { int res=0; struct localuser *u; int fds[2]; int ms = -1; int pid = -1; int owriteformat; int oreadformat; int timeout = 2000; struct timeval last; struct cw_frame *f; struct myframe { struct cw_frame f; char offset[CW_FRIENDLY_OFFSET]; short frdata[160]; } myf; last.tv_usec = 0; last.tv_sec = 0; if (argc < 2 || argc > 3) { cw_log(LOG_ERROR, "Syntax: %s\n", pipe_syntax); return -1; } LOCAL_USER_ADD(u); if (pipe(fds)) { cw_log(LOG_WARNING, "Unable to create pipe\n"); LOCAL_USER_REMOVE(u); return -1; } // MOC: Setting non blocking doesn't seem to change anything // flags = fcntl(fds[1], F_GETFL); // fcntl(fds[1], F_SETFL, flags | O_NONBLOCK); // flags = fcntl(fds[0], F_GETFL); // fcntl(fds[0], F_SETFL, flags | O_NONBLOCK); cw_stopstream(chan); if (chan->_state != CW_STATE_UP) res = cw_answer(chan); if (res) { close(fds[0]); close(fds[1]); cw_log(LOG_WARNING, "Answer failed!\n"); LOCAL_USER_REMOVE(u); return -1; } oreadformat = chan->readformat; res = cw_set_read_format(chan, CW_FORMAT_SLINEAR); owriteformat = chan->writeformat; res += cw_set_write_format(chan, CW_FORMAT_SLINEAR); if (res < 0) { close(fds[0]); close(fds[1]); cw_log(LOG_WARNING, "Unable to set write format to signed linear\n"); LOCAL_USER_REMOVE(u); return -1; } res = pipeencode(argv[1], argv[2], fds[0], fds[1]); if (res >= 0) { last = cw_tvnow(); last.tv_sec += 1; pid = res; for (;;) { /* Wait for audio, and stream */ if (argv[0][0] == '0') { /* START WRITE TO FD */ ms = cw_waitfor(chan, 10); if (ms < 0) { cw_log(LOG_DEBUG, "Hangup detected\n"); res = -1; break; } else if (ms > 0) { f = cw_read(chan); if (!f) { cw_log(LOG_DEBUG, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == CW_FRAME_DTMF) { cw_log(LOG_DEBUG, "User pressed a key\n"); cw_fr_free(f); res = 0; break; } if (f->frametype == CW_FRAME_VOICE) { res = write(fds[1], f->data, f->datalen); if (res < 0) { if (errno != EAGAIN) { cw_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno)); cw_fr_free(f); res = -1; break; } } } cw_fr_free(f); } /* END WRITE TO FD */ } else { /* START WRITE CHANNEL */ ms = cw_tvdiff_ms(last, cw_tvnow()); if (ms <= 0) { res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout); if (res > 0) { cw_fr_init_ex(&myf.f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, __PRETTY_FUNCTION__); myf.f.datalen = res; myf.f.samples = res/sizeof(int16_t); myf.f.offset = CW_FRIENDLY_OFFSET; myf.f.data = myf.frdata; if (cw_write(chan, &myf.f) < 0) { res = -1; break; } } else { cw_log(LOG_DEBUG, "No more stream\n"); res = 0; break; } last = cw_tvadd(last, cw_samp2tv(myf.f.samples, 8000)); } else { ms = cw_waitfor(chan, ms); if (ms < 0) { cw_log(LOG_DEBUG, "Hangup detected\n"); res = -1; break; } if (ms) { f = cw_read(chan); if (!f) { cw_log(LOG_DEBUG, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == CW_FRAME_DTMF) { cw_log(LOG_DEBUG, "User pressed a key\n"); cw_fr_free(f); res = 0; break; } cw_fr_free(f); } } /* END WRITE CHANNEL */ } } } close(fds[0]); close(fds[1]); LOCAL_USER_REMOVE(u); if (pid > -1) kill(pid, SIGKILL); if (!res && oreadformat) cw_set_read_format(chan, oreadformat); if (!res && owriteformat) cw_set_write_format(chan, owriteformat); return res; }