Beispiel #1
0
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;
}
Beispiel #2
0
static void add_member( struct cw_conference *conf, struct cw_conf_member *member ) 
{
    char cnum[80];

    if ( conf == NULL ) 
    {
    	cw_log( LOG_ERROR, "unable to add member to NULL conference\n" ) ;
    	return ;
    }

    // acquire the conference lock
    cw_mutex_lock( &conf->lock ) ;

    member->next = conf->memberlist ; // next is now list
    conf->memberlist = member ; // member is now at head of list
    conf->membercount ++;


    // release the conference lock
    cw_mutex_unlock( &conf->lock ) ;	

    if ((member->cid.cid_num != NULL) )
	strncpy( cnum, member->cid.cid_num, sizeof(cnum) );
    else
	cnum[0] = '\0';
    queue_incoming_silent_frame(member,2);
    if(!member->beep_only_mode){
    	add_command_to_queue( conf, member, CONF_ACTION_QUEUE_NUMBER , 1, cnum );
    	add_command_to_queue( conf, member, CONF_ACTION_QUEUE_SOUND  , 1, "conf-hasjoin" );
    } else {
    	add_command_to_queue( conf, member, CONF_ACTION_QUEUE_SOUND  , 1, "beep" );
    }

    cw_log( CW_CONF_DEBUG, "member added to conference, name => %s\n", conf->name ) ;	

    manager_event(
	EVENT_FLAG_CALL, 
	APP_CONFERENCE_MANID"Join", 
	"Channel: %s\r\n",
	member->channel_name
    ) ;

    return ;
}
Beispiel #3
0
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;
}
Beispiel #4
0
/* *****************************************************************************
	MANAGER UTILS
   ****************************************************************************/
void send_state_change_notifications( struct cw_conf_member* member )
{

#if  ( APP_NCONFERENCE_DEBUG == 1 )
    cw_log(CW_CONF_DEBUG,
	    "Member on channel %s. State changed to %s.\n",
	    member->chan->name,
	    ( ( member->is_speaking == 1 ) ? "speaking" : "silent" )
	);
#endif

    manager_event(
	EVENT_FLAG_CALL, 
	APP_CONFERENCE_MANID"State", 
	"Channel: %s\r\n"
	"State: %s\r\n",
	member->chan->name, 
	( ( member->is_speaking == 1 ) ? "speaking" : "silent" )
    ) ;

    if ( member->is_speaking == 0 ) 
	queue_incoming_silent_frame(member,2);

}
Beispiel #5
0
int conference_parse_admin_command(struct cw_conf_member *member) {
    char action;
    char *parameters;
    int res = 0;

    action=member->dtmf_buffer[0];
    parameters=member->dtmf_buffer+1;

    switch (action) {
	case '1':
	    queue_incoming_silent_frame( member, 2 );
	    res = conf_do_originate(member,parameters);
	    break;
	case '4':
	    if      ( parameters[0] == '0' )
	        add_command_to_queue( member->conf, member, CONF_ACTION_ENABLE_SOUNDS , 0, "" );
	    else if ( parameters[0] == '1' )
	        add_command_to_queue( member->conf, member, CONF_ACTION_ENABLE_SOUNDS , 1, "" );
	    else
		conference_queue_sound( member, "beeperr" );
	    break;
	case '5':
	    if      ( parameters[0] == '0' )
	        add_command_to_queue( member->conf, member, CONF_ACTION_MUTE_ALL , 0, "" );
	    else if ( parameters[0] == '1' )
	        add_command_to_queue( member->conf, member, CONF_ACTION_MUTE_ALL , 1, "" );
	    else
		conference_queue_sound( member, "beeperr" );
	    break;
	case '6':
	    if      ( parameters[0] == '0' )
	        add_command_to_queue( member->conf, member, CONF_ACTION_PLAYMOH , 0, "" );
	    else if ( parameters[0] == '1' )
	        add_command_to_queue( member->conf, member, CONF_ACTION_PLAYMOH , 1, "" );
	    else
		conference_queue_sound( member, "beeperr" );
	    break;
	case '7':
	    if      ( parameters[0] == '0' ) {
		member->conf->is_locked = 0;
		conference_queue_sound( member, "conf-unlockednow" );
	    }
	    else if ( parameters[0] == '1' ) {
		member->conf->is_locked = 1;
		conference_queue_sound( member, "conf-lockednow" );
	    }
	    else {
		conference_queue_sound( member, "beep" );
	    }
	    break;
	case '9':
	    res = conference_set_pin(member,parameters);
	    conference_queue_sound( member, "beep" );
	    break;
	case '0':
	    if      ( parameters[0] == '0' )
	        add_command_to_queue( member->conf, member, CONF_ACTION_HANGUP , 0, "" );
	    else if ( parameters[0] == '1' )
	        add_command_to_queue( member->conf, member, CONF_ACTION_HANGUP , 1, "" );
	    else if ( parameters[0] == '2' )
	        add_command_to_queue( member->conf, member, CONF_ACTION_HANGUP , 2, "" );
	    else
		conference_queue_sound( member, "beeperr" );
	    break;
	default:
	    cw_log(CW_CONF_DEBUG,"Admin mode: Action: %c parameters: %s. Invalid or unknown\n",
		action, parameters);
	    break;
    }

    return 1;
}
Beispiel #6
0
static void conference_exec( struct cw_conference *conf ) 
{

    struct cw_conf_member *member, *temp_member ;
    struct timeval empty_start = {0,0}, tv = {0,0} ;
	
    cw_log( CW_CONF_DEBUG, "Entered conference_exec, name => %s\n", conf->name ) ;
	
    //
    // main conference thread loop
    //

    while ( 1 )
    {

	//Acquire the mutex
	cw_mutex_lock( &conf->lock );
	
	// get list of conference members
	member = conf->memberlist ;

	// loop over member list to retrieve queued frames
	while ( member != NULL )
	{
	    cw_mutex_lock( &member->lock ) ;
	    // check for dead members
	    if ( member->remove_flag == 1 ) 
	    {
		char cnum[80];
	    	cw_log( CW_CONF_DEBUG, "found member slated for removal, channel => %s\n", member->channel_name ) ;
	    	temp_member = member->next ;
		if (member->cid.cid_num != NULL)
		    strncpy( cnum,member->cid.cid_num,sizeof(cnum) );
		else
		    cnum[0] = '\0';
		queue_incoming_silent_frame(member,2);
	    	remove_member( conf, member ) ;
	    	member = temp_member ;
    		if(member && member->beep_only_mode == 0){
	        add_command_to_queue( conf, NULL, CONF_ACTION_QUEUE_NUMBER , 1, cnum );
	        add_command_to_queue( conf, NULL, CONF_ACTION_QUEUE_SOUND , 1, "conf-hasleft" );
    		} else if (member && member->beep_only_mode == 1) {
    		add_command_to_queue( conf, NULL, CONF_ACTION_QUEUE_SOUND  , 1, "beeperr" );
    		}
	    	continue ;
	    }
	    cw_mutex_unlock( &member->lock ) ;
	    // adjust our pointer to the next inline
	    member = member->next ;
	} 
	//
	// break, if we have no more members
	//

	if ( conf->memberlist == NULL ) {
	    if ( empty_start.tv_sec == 0 ) 
 		gettimeofday( &empty_start, NULL );

	    if (conf->auto_destroy) {
		cw_log( CW_CONF_DEBUG, "removing conference, count => %d, name => %s\n", conf->membercount, conf->name ) ;
		remove_conf( conf ) ; // stop the conference
		break ; // break from main processing loop
	    } else {
		//cw_log( CW_CONF_DEBUG, "Delaying conference removal. Auto destroy is not set.\n" ) ;
 		gettimeofday( &tv, NULL ) ;
		if ( tv.tv_sec - empty_start.tv_sec > CW_CONF_DESTROY_TIME ) 
		    conf->auto_destroy=1;
	    }
	} else {
	    empty_start.tv_sec = 0;
	}


	//
	// Check for the commands to be executed by the conference
	//
	if (conf->command_queue) 
	    cw_conf_command_execute( conf );

	//---------//
	// CLEANUP //
	//---------//

	// release conference mutex
	cw_mutex_unlock( &conf->lock ) ;

	//Sleep for 1ms (relax)
	usleep(1000);
    } // end while ( 1 )

    //
    // exit the conference thread
    // 
	
    cw_log( CW_CONF_DEBUG, "exit conference_exec\n" ) ;

    // exit the thread
    pthread_exit( NULL ) ;
    return ;
}
Beispiel #7
0
static void cw_conf_command_execute( struct cw_conference *conf ) {
    struct cw_conf_command_queue 	*cq;
    struct cw_conf_member *member 	= NULL ;

    cq = get_command_from_queue(conf);

    if ( cq == NULL ) return;

    cw_log(CW_CONF_DEBUG,"Parsing Command Queue for conference %s\n",conf->name);

    switch (cq->command) {
	case CONF_ACTION_MUTE_ALL: 
	    // get list of conference members
	    member = conf->memberlist ;
	    // loop over member list to retrieve queued frames
	    while ( member != NULL )
	    {
		if (member != cq->issuedby) {
		    cw_mutex_lock( &member->lock ) ;
		    queue_incoming_silent_frame(member,2);
		    member->talk_mute = cq->param_number;
		    cw_log(CW_CONF_DEBUG,"(CQ) Member Talk MUTE set to %d\n",member->talk_mute);
		    if (cq->param_number)
			conference_queue_sound( member, "conf-muted" );
		    else
			conference_queue_sound( member, "conf-unmuted" );
		    cw_mutex_unlock( &member->lock ) ;
		}
		// adjust our pointer to the next inline
		member = member->next ;
	    } 
	    break;
	case CONF_ACTION_ENABLE_SOUNDS: 
	    // get list of conference members
	    member = conf->memberlist ;
	    // loop over member list to retrieve queued frames
	    while ( member != NULL )
	    {
		cw_mutex_lock( &member->lock ) ;
		queue_incoming_silent_frame(member,2);
		member->dont_play_any_sound =  cq->param_number;
		cw_log(CW_CONF_DEBUG,"(CQ) Member Talk Disable sounds set to %d\n",member->dont_play_any_sound);
		cw_mutex_unlock( &member->lock ) ;
		// adjust our pointer to the next inline
		member = member->next ;
	    } 
	    break;
	case CONF_ACTION_QUEUE_SOUND: 
	    // get list of conference members
	    member = conf->memberlist ;
	    // loop over member list to retrieve queued frames
	    while ( member != NULL )
	    {
		if (member != cq->issuedby) {
		    cw_mutex_lock( &member->lock ) ;
		    queue_incoming_silent_frame(member,2);
		    if ( !(member->quiet_mode == 1 && cq->param_number) )
			conference_queue_sound( member, cq->param_text );
		    cw_mutex_unlock( &member->lock ) ;
		    // adjust our pointer to the next inline
		}
		    member = member->next ;
	    } 
	    break;
	case CONF_ACTION_QUEUE_NUMBER: 
	    // get list of conference members
	    member = conf->memberlist ;
	    // loop over member list to retrieve queued frames
	    while ( member != NULL )
	    {
		if (member != cq->issuedby) {
		    cw_mutex_lock( &member->lock ) ;
		    queue_incoming_silent_frame(member,2);
		    if ( !(member->quiet_mode == 1 && cq->param_number) )
			conference_queue_number( member, cq->param_text );
		    cw_mutex_unlock( &member->lock ) ;
		    // adjust our pointer to the next inline
		}
		member = member->next ;
	    } 
	    break;
	case CONF_ACTION_PLAYMOH: 
	    // get list of conference members
	    member = conf->memberlist ;
	    // loop over member list to retrieve queued frames
	    while ( member != NULL )
	    {
		if (member != cq->issuedby) {;
		    cw_mutex_lock( &member->lock ) ;
		    if ( cq->param_number == 1) {
			member->force_on_hold =  1;
		    } 
		    else {
			member->force_on_hold = -1;
		    }
		    cw_mutex_unlock( &member->lock ) ;
		    cw_log(CW_CONF_DEBUG,"(CQ) Member: playing moh set to %d\n",cq->param_number);
		    // adjust our pointer to the next inline
		}
		member = member->next ;
	    } 
	    break;
	case CONF_ACTION_HANGUP: 
	    member = conf->memberlist ;
	    // Scan all the members
	    while ( member != NULL )
	    {
		// If it's not me and we don't have to kick all members
		if (member != cq->issuedby) {
		    cw_mutex_lock( &member->lock ) ;
		    queue_incoming_silent_frame(member,2);
		    if (cq->param_number == 0) 
			conference_queue_sound( member, "goodbye" );
		    else
			conference_queue_sound( member, "conf-kicked" );
		    member->force_remove_flag = 1;
		    cw_log(CW_CONF_DEBUG,"(CQ) Conf %s Member Kicked: %s\n",conf->name, member->channel_name);
		    cw_mutex_unlock( &member->lock ) ;
		    if (cq->param_number == 1) 
			break;
		}
		// adjust our pointer to the next inline
		member 	= member->next ;
	    } 
	    break;
	default:
	    cw_log( LOG_WARNING, "Conference %s : don't know how to execute command %d\n", conf->name, cq->command) ;	
	    break;
    }

    // Free the struct we got
    free(cq);
}
Beispiel #8
0
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 ;
		
}
Beispiel #9
0
static int process_incoming(struct cw_conf_member *member, struct cw_frame *f) 
{
    int res;

    // Play our sound queue, if not empty. 
    if (member->soundq) {
	// Free the frame.
	if ( f != NULL ) {
	    cw_fr_free( f ) ;
	}
	res = conf_play_soundqueue( member ); 
	if (res != 0) {
	    queue_incoming_silent_frame(member,2);
	    // send the DTMF event to the MGR interface..
	    manager_event(
		EVENT_FLAG_CALL,
		APP_CONFERENCE_MANID"DTMF",
		"Channel: %s\r\n"
		"Key: %c\r\n",
		member->channel_name,
		res
	    ) ;
	    parse_dtmf_option( member, res);
	}
	return res;
    }

    //
    // Moderator forces MOH management
    //

    if ( member->force_on_hold == 1 ) {
	cw_moh_start(member->chan,"");
	member->force_on_hold = 0 ;
    } 
    else if ( member->force_on_hold == -1 ) {
	cw_moh_stop(member->chan);
	cw_generator_activate(member->chan,&membergen,member);
	member->force_on_hold = 0 ;
    } 

    //
    // MOH When the user is alone in the conference
    //
    if ( member->conf->membercount == 1 && 
	 member->is_on_hold == 0 && 
	 member->skip_moh_when_alone == 0 
       ) {
	cw_moh_start(member->chan,"");
	member->is_on_hold = 1 ;
	return 0;
    }

    if ( member->conf->membercount > 1 && 
	 member->is_on_hold == 1 && 
	 member->skip_moh_when_alone == 0 
       ) {
	cw_moh_stop(member->chan);
	cw_generator_activate(member->chan,&membergen,member);
	member->is_on_hold = 0 ;
	return 0;
    }

    if ( member->force_remove_flag == 1 ) {
        return 0;
    }

    // If we don't have any frame to parse, then return
    if ( f == NULL ) {
	return 0;
    }

    // Actions based on the content of the frame
    if ( f->frametype == CW_FRAME_DTMF && member->manage_dtmf )
    {	
	queue_incoming_silent_frame(member,2);

	// send the DTMF event to the MGR interface..
	manager_event(
		EVENT_FLAG_CALL,
		APP_CONFERENCE_MANID"DTMF",
		"Channel: %s\r\n"
		"Key: %c\r\n",
		member->channel_name,
		f->subclass
	) ;

	parse_dtmf_option( member, f->subclass);

	cw_fr_free(f);
    }
    else if (  (member->type == MEMBERTYPE_LISTENER) || (member->talk_mute) )
    {
	// this is a listen-only user, or it's muted. 	
	// Ignore the frame
	cw_fr_free( f ) ;
    }
    else if ( f->frametype == CW_FRAME_VOICE ) 
    {			
	// ********************************************************************************** VOICE
	int old_speaking_state = member->is_speaking;

#if ENABLE_VAD
	if ( member->talk_mute == 1 ) member->is_speaking = 0;

	if ( member->enable_vad 
	     && f->subclass == CW_FORMAT_SLINEAR && f->samples > 0 
	   )
	{
	    // and if it's time to check what the member is doing
	    if ( member->skip_voice_detection <= 0 || member->is_speaking ) 
	    {
		int rees;
		rees = vad_is_talk( f->data, f->datalen, &member->silence_nr, 20);
		// send the frame to the preprocessor
		if ( rees != 0 )
		{
		    // voice detected, reset skip count
		    if ( member->framelen != 0 )
			member->skip_voice_detection = (CW_CONF_SKIP_MS_AFTER_VOICE_DETECTION / member->framelen);
		    else 
			// Let's suppose that 20ms as a framelen is not too different from the real situation
			member->skip_voice_detection = 20;
		    member->is_speaking=1;
		}
		else {
		    // member is silent
		    member->is_speaking=0;
		    if ( member->framelen != 0 )
			member->skip_voice_detection = ( CW_CONF_SKIP_MS_WHEN_SILENT / member->framelen );
		    else 
			member->skip_voice_detection = 5;
		}

	    }
	    --member->skip_voice_detection ;
	}

	if (old_speaking_state != member ->is_speaking)
	    send_state_change_notifications(member);
#endif

	// volume of the frame is modified after the VAD has been done
	if (member->talk_volume != 0) 
	    set_talk_volume(member, f, 1);


	if (  member->is_speaking && queue_incoming_frame( member, f ) != 0 )
	    cw_log( CW_CONF_DEBUG, "dropped incoming frame, channel => %s\n", member->channel_name ) ;

	// free the original frame
	cw_fr_free( f ) ;
    }
    else if ( f->frametype == CW_FRAME_CONTROL && f->subclass == CW_CONTROL_HANGUP ) 
    {
	// hangup received, queue silence && free the frame 
	queue_incoming_silent_frame(member,2);
	cw_fr_free( f ) ;
    }
    else
    {
	// Unmanaged frame
#if  ( APP_NCONFERENCE_DEBUG == 1 )
	cw_log(LOG_WARNING,"Freeing unknown frame: type %d  member %s \n", f->frametype, member->chan->name );
#endif
	cw_fr_free( f ) ;
    }

    return 0;
}
int member_exec( struct ast_channel* chan, void* data ) {
    int left = 0 ;
    int res;

    struct ast_conference  *conf   	= NULL;
    struct ast_conf_member *member	= NULL;
    struct ast_frame *f		= NULL;
    struct ast_app *app = NULL;

    ast_log( AST_CONF_DEBUG, "Launching NConference %s\n", "$Revision: 2325 $" ) ;

	// make sure we have a channel to process
	if ( chan == NULL )
	{
	    ast_log( LOG_NOTICE, "member channel has closed\n" ) ;
	    return -1 ;
	}

    if (chan->_state != AST_STATE_UP)
	if ( (res = ast_answer( chan )) )
	{
    	    ast_log( LOG_ERROR, "unable to answer call\n" ) ;
    	    return -1 ;
	}

    member = create_member( chan, (const char*)( data ) ) ;

    // unable to create member, return an error
    if ( member == NULL ) 
    {
	ast_log( LOG_ERROR, "unable to create member\n" ) ;
	return -1 ;
    }

    //
    // setup Openpbx read/write formats
    //
	
    //ast_log( AST_CONF_DEBUG, 
	//	"CHANNEL INFO, CHANNEL => %s, DNID => %s, CALLER_ID => %s, ANI => %s\n", 
	//	chan->name, chan->cid.cid_dnid, chan->cid.cid_num, chan->cid.cid_ani ) ;

    ast_log( AST_CONF_DEBUG, 
		"CHANNEL CODECS, CHANNEL => %s, NATIVE => %d, READ => %d, WRITE => %d\n", 
		chan->name, chan->nativeformats, member->read_format, member->write_format ) ;


    if ( ast_set_read_format( chan, member->read_format ) < 0 )
    {
    	ast_log( LOG_ERROR, "unable to set read format.\n" ) ;
    	delete_member( member ) ;
    	return -1 ;
    } 

    // for right now, we'll send everything as slinear
    if ( ast_set_write_format( chan, member->write_format ) < 0 )
    {
    	ast_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 )
    {
	ast_log( LOG_ERROR, "unable to setup member conference\n" ) ;
	delete_member( member) ;
	return -1 ;
    } else {
	if (conf->is_locked && (member->type != MEMBERTYPE_MASTER) ) {
	    if (strlen(conf->pin) == 0 || strncmp(conf->pin,member->pin,sizeof(conf->pin)) ) {
		/* Conference is Locked and an invalid PIN was entered */
		remove_member(conf, member);
		return -2 ;
	    }
	}  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));
	    ast_log( AST_CONF_DEBUG, "Conference pin set to => %s\n", conf->pin ) ;
	}
    }

    //
    // process loop for new member ( this runs in it's own thread
    //
	
    ast_log( AST_CONF_DEBUG, "begin member event loop, channel => %s\n", chan->name ) ;

    // Add user to monitor
    if (member->monitor) {
        const char * const monitorfilename = pbx_builtin_getvar_helper(chan, "MONITOR_FILENAME");
        if (monitorfilename) {
            ast_monitor_start(chan, NULL, monitorfilename, 1);
        } else if (chan->cdr) {
            ast_monitor_start(chan, NULL, chan->cdr->uniqueid, 1);
        } else {
            char tmpid[256];
            snprintf(tmpid, sizeof(tmpid), "chan-%x", rand());
            ast_monitor_start(chan, NULL, tmpid, 1);
        }
        if (member->monitor_join) {
            ast_monitor_setjoinfiles(chan, 1);
        }
    }

    // Run AGI script
    if (member->agi) {
        char * agi = pbx_builtin_getvar_helper(chan, "AGI_CONF_JOIN");
        if (agi) {
            app = pbx_findapp("agi");
            if (app) {
                pbx_exec(chan, app, agi, 1);
            }
        } else {
            ast_log(LOG_WARNING, "AGI requested, but AGI_CONF_JOIN missing.\n");
        }
        conf->agi = 1 ;
    }

    // Activate the generator for the channel.
    res = ast_conf_member_genactivate( member );
    if ( !res ) {
	member->force_remove_flag = 1;
	ast_log( AST_CONF_DEBUG, "member marked for removal => %s\n", chan->name ) ;
    }

    //Play the join info messages
    if (!member->force_remove_flag && !member->quiet_mode && !member->mute_incoming_sounds) {
		if (ast_strlen_zero(member->intro_sounds)) {
			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 )
    {
#ifdef SOLARIS
    struct timespec rqtp;
    rqtp.tv_sec = 0;
    rqtp.tv_nsec = 1000000;
    if (nanosleep(&rqtp, (struct timespec *) NULL) == -1) {
        ast_log(LOG_NOTICE, "Nanosleep timer errored.\n");
    }
#else
	usleep(1000);
#endif

	//-----------------//
	// 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 ) ? AST_CONF_WAITFOR_TIME : member->framelen;

	left = ast_waitfor( chan, waittime ) ;

	if ( left < 0 )
	{
	    // an error occured	
	    ast_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 = ast_read( chan ) ;
			
	    if ( f == NULL ) 
	    {
		ast_log( AST_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 {
/*
		ast_log( AST_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 0 == 1
		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
		    ast_log( AST_CONF_DEBUG, "MEMBER FRAME DATA: datalen %d  samples %d  len(ms) %ld, offset: %d \n", f->datalen, f->samples, f->len, f->offset );
		} 

		if ( 
			    ( (member->framelen != f->len      ) && ( f->len !=0     ) ) 
				|| 
			    ( (member->samples  != f->samples  ) && ( f->samples !=0 )  && ( f->len !=0     ) )
			) 
		{
		    ast_log( AST_CONF_DEBUG, "FRAME CHANGE  : samples %d  len(ms) %ld\n", f->samples, f->len );
		    ast_log( AST_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
		    }
		}
#endif
        member->framelen = f->datalen;

		// 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 ;

    }

	// Run AGI script
	if (member->agi) {
		char * agi = pbx_builtin_getvar_helper(chan, "AGI_CONF_LEAVE");
		if (agi) {
			app = pbx_findapp("agi");
			if (app) {
				pbx_exec(chan, app, agi, 1);
			}
		} else {
			ast_log(LOG_WARNING, "AGI requested, but AGI_CONF_LEAVE missing.\n");
		}
	}
	if (conf->agi) 
		handle_conf_agi_end(conf->name, member);        
	member->remove_flag = 1 ;

    ast_log( AST_CONF_DEBUG, "end member event loop, time_entered => %ld -  removal: %d\n", member->time_entered.tv_sec, member->remove_flag ) ;

    //ast_log( AST_CONF_DEBUG, "Deactivating generator - Channel => %s\n", member->chan->name ) ;
    ast_generator_deactivate(chan);

	if (member->hangup_go_on) {
		ast_log(AST_CONF_DEBUG, "Hangup go on!\n");
		return 0;
	}

    return -1 ;
		
}