static int conf_do_originate(struct cw_conf_member *member, char *ext) { int res; pthread_t th; pthread_attr_t attr; struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper)); char dst[80]=""; char appdata[80]=""; char *var; if (!fast) { res = -1; } else { memset(fast, 0, sizeof(struct fast_originate_helper)); if ( (var = pbx_builtin_getvar_helper(member->chan, "NCONF_OUTBOUND_TIMEOUT")) ) { fast->timeout = atoi(var) * 1000; } else fast->timeout = 30000; strcat(dst,ext); strcat(dst,"@"); if ( (var = pbx_builtin_getvar_helper(member->chan, "NCONF_OUTBOUND_CONTEXT")) ) strcat(dst,var); else strcat(dst,member->chan->context); strcat(appdata,member->id); strcat(appdata,"/"); if ( (var = pbx_builtin_getvar_helper(member->chan, "NCONF_OUTBOUND_PARAMS")) ) strcat(appdata,var); else { strcat(appdata,"Sdq"); #if ENABLE_VAD strcat(appdata,"V"); #endif } cw_copy_string( fast->tech, "Local", sizeof(fast->tech) ); cw_copy_string( fast->data, dst, sizeof(fast->data) ); cw_copy_string( fast->app, APP_CONFERENCE_NAME, sizeof(fast->app) ); cw_copy_string( fast->appdata, appdata, sizeof(fast->appdata) ); if ( (var = pbx_builtin_getvar_helper(member->chan, "NCONF_OUTBOUND_CID_NAME")) ) cw_copy_string( fast->cid_name, var, sizeof(fast->cid_name) ); else cw_copy_string( fast->cid_name,"NavyConference",sizeof(fast->cid_name) ); if ( (var = pbx_builtin_getvar_helper(member->chan, "NCONF_OUTBOUND_CID_NUM")) ) cw_copy_string( fast->cid_num, var,sizeof(fast->cid_num) ); else cw_copy_string( fast->cid_num, member->id,sizeof(fast->cid_num) ); cw_copy_string( fast->context, "internal", sizeof(fast->context) ); cw_copy_string( fast->exten, ext, sizeof(fast->exten) ); fast->priority = 1; fast->vars=NULL; /**/ fast->frommember=member; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (cw_pthread_create(&th, &attr, fast_originate, fast)) { free(fast); res = -1; } else { res = 0; } } cw_mutex_unlock(&member->chan->lock); cw_conf_member_genactivate( member ) ; return res; }
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 ; }