int conf_play_soundqueue( struct cw_conf_member *member ) { int res = 0; cw_stopstream(member->chan); queue_incoming_silent_frame(member,3); struct cw_conf_soundq *toplay, *delitem; cw_generator_deactivate(member->chan); cw_mutex_lock(&member->lock); toplay = member->soundq; while ( ( toplay != NULL) && ( res == 0 ) ) { manager_event( EVENT_FLAG_CALL, APP_CONFERENCE_MANID"Sound", "Channel: %s\r\n" "Sound: %s\r\n", member->channel_name, toplay->name ); res = conf_play_soundfile( member, toplay->name ); if (res) break; delitem = toplay; toplay = toplay->next; member->soundq = toplay; free(delitem); } cw_generator_activate(member->chan,&membergen,member); cw_mutex_unlock(&member->lock); if (res != 0) conference_stop_sounds( 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 ; }
void cw_playtones_stop(struct cw_channel *chan) { cw_generator_deactivate(chan); }
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; }