static int conf_play_soundfile( struct cw_conf_member *member, char * file ) { int res = 0; if ( member->dont_play_any_sound ) return 0; if ( !member->chan ) return 0; cw_stopstream(member->chan); queue_incoming_silent_frame(member,3); if ( ( strrchr(file,'/')!=NULL ) || (cw_fileexists(file, NULL, member->chan->language) > 0) ) { res = cw_streamfile(member->chan, file, member->chan->language); if (!res) { res = cw_waitstream(member->chan, CW_DIGIT_ANY); cw_stopstream(member->chan); } //cw_log(LOG_DEBUG, "Soundfile found %s - %d\n", file, cw_fileexists(file, NULL, member->chan->language) ); } else cw_log(LOG_DEBUG, "Soundfile not found %s - lang: %s\n", file, member->chan->language ); cw_set_write_format( member->chan, CW_FORMAT_SLINEAR ); return res; }
static void *playtones_alloc(struct cw_channel *chan, void *params) { struct playtones_def *pd = params; struct playtones_state *ps; if ((ps = malloc(sizeof(*ps))) == NULL) return NULL; memset(ps, 0, sizeof(*ps)); ps->origwfmt = chan->writeformat; if (cw_set_write_format(chan, CW_FORMAT_SLINEAR)) { cw_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name); playtones_release(NULL, ps); ps = NULL; } else { struct playtones_item *pi; ps->vol = pd->vol; ps->reppos = pd->reppos; ps->nitems = pd->nitems; ps->items = pd->items; /* Initialize the tone generator */ pi = &pd->items[0]; tone_setup(ps, pi); } /* Let interrupts interrupt :) */ if (pd->interruptible) cw_set_flag(chan, CW_FLAG_WRITE_INT); else cw_clear_flag(chan, CW_FLAG_WRITE_INT); return ps; }
static void playtones_release(struct cw_channel *chan, void *params) { struct playtones_state *ps = params; if (chan) cw_set_write_format(chan, ps->origwfmt); if (ps->items) free(ps->items); free(ps); }
static void linear_release(struct cw_channel *chan, void *params) { struct linear_state *ls = params; if (ls->origwfmt && cw_set_write_format(chan, ls->origwfmt)) { cw_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt); } if (ls->autoclose) close(ls->fd); free(params); }
static void *linear_alloc(struct cw_channel *chan, void *params) { struct linear_state *ls; /* In this case, params is already malloc'd */ if (params) { ls = params; if (ls->allowoverride) cw_set_flag(chan, CW_FLAG_WRITE_INT); else cw_clear_flag(chan, CW_FLAG_WRITE_INT); ls->origwfmt = chan->writeformat; if (cw_set_write_format(chan, CW_FORMAT_SLINEAR)) { cw_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name); free(ls); ls = params = NULL; } } return params; }
static struct cw_frame * sccp_rtp_read(sccp_channel_t * c) { /* Retrieve audio/etc from channel. Assumes c->lock is already held. */ struct cw_frame * f; /* if c->rtp not null */ if (!c->rtp) return NULL; f = cw_rtp_read(c->rtp); if (c->owner) { /* We already hold the channel lock */ if (f->frametype == CW_FRAME_VOICE) { if (f->subclass != c->owner->nativeformats) { sccp_log(10)(VERBOSE_PREFIX_3 "%s: Oooh, format changed to %d from %d on channel %d\n", c->device->id, f->subclass, c->owner->nativeformats, c->callid); c->owner->nativeformats = f->subclass; cw_set_read_format(c->owner, c->owner->readformat); cw_set_write_format(c->owner, c->owner->writeformat); } } } return f; }
int member_exec( struct cw_channel* chan, int argc, char **argv ) { int left = 0 ; int res; struct cw_conference *conf = NULL; struct cw_conf_member *member = NULL; struct cw_frame *f = NULL; cw_log( CW_CONF_DEBUG, "Launching NConference %s\n", "$Revision: 5349 $" ) ; if (chan->_state != CW_STATE_UP) if ( (res = cw_answer( chan )) ) { cw_log( LOG_ERROR, "unable to answer call\n" ) ; return -1 ; } member = create_member( chan, argc, argv ) ; // unable to create member, return an error if ( member == NULL ) { cw_log( LOG_ERROR, "unable to create member\n" ) ; return -1 ; } // // setup CallWeaver read/write formats // cw_log(CW_CONF_DEBUG, "CHANNEL INFO, CHANNEL => %s, DNID => %s, CALLER_ID => %s, ANI => %s\n", chan->name ? chan->name : "----", chan->cid.cid_dnid ? chan->cid.cid_dnid : "----", chan->cid.cid_num ? chan->cid.cid_num : "----", chan->cid.cid_ani ? chan->cid.cid_ani : "----"); cw_log(CW_CONF_DEBUG, "CHANNEL CODECS, CHANNEL => %s, NATIVE => %d, READ => %d, WRITE => %d\n", chan->name, chan->nativeformats, member->read_format, member->write_format); if ( cw_set_read_format( chan, member->read_format ) < 0 ) { cw_log( LOG_ERROR, "unable to set read format.\n" ) ; delete_member( member ) ; return -1 ; } // for right now, we'll send everything as slinear if ( cw_set_write_format( chan, member->write_format ) < 0 ) { cw_log( LOG_ERROR, "unable to set write format.\n" ) ; delete_member( member ) ; return -1 ; } // // setup a conference for the new member // conf = start_conference( member ) ; if ( conf == NULL ) { cw_log( LOG_ERROR, "unable to setup member conference\n" ) ; delete_member( member) ; return -1 ; } else { if (conf->is_locked && (member->type != MEMBERTYPE_MASTER) ) { if ( strcmp(conf->pin,member->pin) ) { conference_queue_sound(member,"conf-locked"); conf_play_soundqueue( member ); member->force_remove_flag = 1 ; } } else { member->conf = conf; if ( member->type == MEMBERTYPE_MASTER ) conf->auto_destroy = member->auto_destroy; } } if ( member->type == MEMBERTYPE_MASTER ) { conf->auto_destroy = member->auto_destroy; if ( strlen( member->pin ) > 0 ) { strncpy(conf->pin,member->pin,sizeof(conf->pin)); cw_log( CW_CONF_DEBUG, "Conference pin set to => %s\n", conf->pin ) ; } } // // process loop for new member ( this runs in it's own thread // cw_log( CW_CONF_DEBUG, "begin member event loop, channel => %s\n", chan->name ) ; // Activate the generator for the channel. res = cw_conf_member_genactivate( member ); if ( !res ) { member->force_remove_flag = 1; cw_log( CW_CONF_DEBUG, "member marked for removal => %s\n", chan->name ) ; } //Play the join info messages if (!member->force_remove_flag && !member->quiet_mode) { conference_queue_sound( member, "conf-youareinconfnum" ); conference_queue_number( member, member->id ); } // The member at the very beginningis speaking member->is_speaking = 1 ; // tell conference_exec we're ready for frames member->active_flag = 1 ; //Main loop. while ( !member->force_remove_flag || member->soundq != NULL ) { usleep(1000); // make sure we have a channel to process if ( chan == NULL ) { cw_log( LOG_NOTICE, "member channel has closed\n" ) ; break ; } //-----------------// // INCOMING FRAMES // //-----------------// if ( member->force_remove_flag == 1 ) { // break to the loop break; } // wait for an event on this channel int waittime = ( member->framelen == 0 ) ? CW_CONF_WAITFOR_TIME : member->framelen; left = cw_waitfor( chan, waittime ) ; f = NULL; if ( left < 0 ) { // an error occured cw_log( LOG_NOTICE, "an error occured waiting for a frame, channel => %s, error => %d\n", chan->name, left ) ; } else if ( left == 0 ) { // No frame avalaible member->lostframecount ++; // We have lost a frame. // In this case, we queue some silence // Sothat if we keep loosing frames, // there will be no glitching in the conference. // Set the speaking state to 0. if ( member->lostframecount == 1 ) { queue_incoming_silent_frame(member,1); } member->is_speaking = 0; } else if ( left > 0 ) { // a frame has come in before the latency timeout // was reached, so we process the frame // let's reset the lost frame count if ( member->lostframecount ) { member->lostframecount = 0; // If vad is not enabled, then set the speaking state back to 1 if ( !member->enable_vad ) member->is_speaking = 1; } f = cw_read( chan ) ; if ( f == NULL ) { cw_log( CW_CONF_DEBUG, "unable to read from channel, channel => %s. Got Hangup.\n", chan->name ) ; queue_incoming_silent_frame(member,5); member->is_speaking = 0; break ; } else { /* cw_log( CW_CONF_DEBUG, "Read (PRE dsp), channel => %s, datalen: %d samplefreq: %ld len: %ld samples %d class: %d\n", chan->name, f->datalen, member->samplefreq, f->len, f->samples, f->subclass) ; */ if ( member->samplefreq == 0 && f->samples != 0 ) { if ( ( f->len == 0 ) && ( f->datalen == 320 ) && ( f->samples == 160 ) ) member->framelen = 20; // This is probably chan_zap not setting the correct len. else member->framelen = f->len; // frame length in milliseconds member->datalen = f->datalen; // frame length in milliseconds member->samples = f->samples; // number of samples in framelen member->samplefreq = (int)(member->samples/member->framelen)*1000; // calculated sample frequency cw_log( CW_CONF_DEBUG, "MEMBER FRAME DATA: datalen %d samples %d len(ms) %ld, offset: %d \n", f->datalen, f->samples, f->len, f->offset ); /* // Try to initialize the smoother, only once queue_incoming_silent_frame(member); if ( member->smooth_size_in < 0 ) { member->smooth_size_in = f->samples ; cw_log( CW_CONF_DEBUG, "Initializing Smooother.\n"); member->inSmoother = cw_smoother_new(member->smooth_size_in); if ( member->inSmoother == NULL ) cw_log( CW_CONF_DEBUG, "Smoother initialization failed\n"); } */ } if ( ( (member->framelen != f->len ) && ( f->len !=0 ) ) || ( (member->samples != f->samples ) && ( f->samples !=0 ) && ( f->len !=0 ) ) ) { cw_log( CW_CONF_DEBUG, "FRAME CHANGE : samples %d len(ms) %ld\n", f->samples, f->len ); cw_log( CW_CONF_DEBUG, "FRAME SHOULDBE: samples %d len(ms) %ld\n", member->samples, member->framelen ); if (member->samples == 0 ) { member->framelen = f->len; // frame length in milliseconds member->datalen = f->datalen; // frame length in milliseconds member->samples = f->samples; // number of samples in framelen member->samplefreq = (int) ( f->samples/f->len)*1000; // calculated sample frequency } } // This fix is for chan_zap // Chan_zap NEVER sets framelen value. // Probably when adding support to 16Khz we should add a check for this. if ( ( member->framelen == 0 ) && ( member->datalen == 320 ) && ( member->samples == 160 ) ) member->framelen = 20; } } // actually process the frame. res = process_incoming(member, f); if (member->force_remove_flag) member->remove_flag = 1 ; } // // clean up // if ( member != NULL ) member->remove_flag = 1 ; cw_log( CW_CONF_DEBUG, "end member event loop, time_entered => %ld - removal: %d\n", member->time_entered.tv_sec, member->remove_flag ) ; //cw_log( CW_CONF_DEBUG, "Deactivating generator - Channel => %s\n", member->chan->name ) ; cw_generator_deactivate(chan); return -1 ; }
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; }
static int fax_exec(struct cw_channel *chan, int argc, char **argv) { fax_state_t fax; t38_terminal_state_t t38; t30_state_t *t30; const char *file_name; int res = 0; int ready; int calling_party; int verbose; struct localuser *u; int original_read_fmt; int original_write_fmt; /* Basic initial checkings */ if (chan == NULL) { cw_log(LOG_WARNING, "Fax transmit channel is NULL. Giving up.\n"); return -1; } /* Make sure they are initialized to zero */ memset(&fax, 0, sizeof(fax)); memset(&t38, 0, sizeof(t38)); if (argc < 1 || argc > 4) { cw_log(LOG_ERROR, "Syntax: %s\n", fax_syntax); return -1; } /* Resetting channel variables related to T38 */ pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", ""); pbx_builtin_setvar_helper(chan, "FAXPAGES", ""); pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", ""); pbx_builtin_setvar_helper(chan, "FAXBITRATE", ""); pbx_builtin_setvar_helper(chan, "PHASEESTATUS", ""); pbx_builtin_setvar_helper(chan, "PHASEESTRING", ""); /* Parsing parameters */ calling_party = FALSE; verbose = FALSE; file_name = argv[0]; while (argv++, --argc) { if (strcmp(argv[0], "caller") == 0) { calling_party = TRUE; } else if (strcmp(argv[0], "debug") == 0) { verbose = TRUE; } } /* Done parsing */ LOCAL_USER_ADD(u); if (chan->_state != CW_STATE_UP) { /* Shouldn't need this, but checking to see if channel is already answered * Theoretically the PBX should already have answered before running the app */ res = cw_answer(chan); if (!res) { cw_log(LOG_DEBUG, "Could not answer channel '%s'\n", chan->name); //LOCAL_USER_REMOVE(u); //return res; } } /* Setting read and write formats */ original_read_fmt = chan->readformat; if (original_read_fmt != CW_FORMAT_SLINEAR) { res = cw_set_read_format(chan, CW_FORMAT_SLINEAR); if (res < 0) { cw_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n"); LOCAL_USER_REMOVE(u); return -1; } } original_write_fmt = chan->writeformat; if (original_write_fmt != CW_FORMAT_SLINEAR) { res = cw_set_write_format(chan, CW_FORMAT_SLINEAR); if (res < 0) { cw_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n"); res = cw_set_read_format(chan, original_read_fmt); if (res) cw_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); LOCAL_USER_REMOVE(u); return -1; } } /* This is the main loop */ ready = TRUE; if (chan->t38_status == T38_NEGOTIATED) t30 = t38_terminal_get_t30_state(&t38); else t30 = fax_get_t30_state(&fax); while (ready && ready_to_talk(chan)) { if (ready && chan->t38_status != T38_NEGOTIATED) { t30 = fax_get_t30_state(&fax); ready = fax_audio(chan, &fax, file_name, calling_party, verbose); } if (ready && chan->t38_status == T38_NEGOTIATED) { t30 = t38_terminal_get_t30_state(&t38); ready = fax_t38(chan, &t38, file_name, calling_party, verbose); } if (chan->t38_status != T38_NEGOTIATING) ready = FALSE; // 1 loop is enough. This could be useful if we want to turn from udptl to RTP later. } t30_terminate(t30); fax_release(&fax); t38_terminal_release(&t38); /* Restoring initial channel formats. */ if (original_read_fmt != CW_FORMAT_SLINEAR) { if ((res = cw_set_read_format(chan, original_read_fmt))) cw_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); } if (original_write_fmt != CW_FORMAT_SLINEAR) { if ((res = cw_set_write_format(chan, original_write_fmt))) cw_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name); } return ready; }