static int start_monitor_action(struct mansession *s, struct message *m)
{
	struct ast_channel *c = NULL;
	char *name = astman_get_header(m, "Channel");
	char *fname = astman_get_header(m, "File");
	char *format = astman_get_header(m, "Format");
	char *mix = astman_get_header(m, "Mix");
	char *d;
	
	if (ast_strlen_zero(name)) {
		astman_send_error(s, m, "No channel specified");
		return 0;
	}
	c = ast_get_channel_by_name_locked(name);
	if (!c) {
		astman_send_error(s, m, "No such channel");
		return 0;
	}

	if (ast_strlen_zero(fname)) {
		/* No filename base specified, default to channel name as per CLI */
		fname = malloc (FILENAME_MAX);
		if (!fname) {
			astman_send_error(s, m, "Could not start monitoring channel");
			ast_mutex_unlock(&c->lock);
			return 0;
		}
		memset(fname, 0, FILENAME_MAX);
		ast_copy_string(fname, c->name, FILENAME_MAX);
		/* Channels have the format technology/channel_name - have to replace that /  */
		if ((d=strchr(fname, '/'))) *d='-';
	}
	
	if (ast_monitor_start(c, format, fname, 1)) {
		if (ast_monitor_change_fname(c, fname, 1)) {
			astman_send_error(s, m, "Could not start monitoring channel");
			ast_mutex_unlock(&c->lock);
			return 0;
		}
	}

	if (ast_true(mix)) {
		ast_monitor_setjoinfiles(c, 1);
	}

	ast_mutex_unlock(&c->lock);
	astman_send_ack(s, m, "Started monitoring channel");
	return 0;
}
예제 #2
0
static int start_monitor_exec(struct ast_channel *chan, void *data)
{
	char *arg = NULL;
	char *format = NULL;
	char *fname_base = NULL;
	char *options = NULL;
	char *delay = NULL;
	char *urlprefix = NULL;
	char tmp[256];
	int joinfiles = 0;
	int waitforbridge = 0;
	int res = 0;
	
	/* Parse arguments. */
	if (!ast_strlen_zero((char*)data)) {
		arg = ast_strdupa((char*)data);
		format = arg;
		fname_base = strchr(arg, '|');
		if (fname_base) {
			*fname_base = 0;
			fname_base++;
			if ((options = strchr(fname_base, '|'))) {
				*options = 0;
				options++;
				if (strchr(options, 'm'))
					joinfiles = 1;
				if (strchr(options, 'b'))
					waitforbridge = 1;
			}
		}
		arg = strchr(format,':');
		if (arg) {
			*arg++ = 0;
			urlprefix = arg;
		}
	}
	if (urlprefix) {
		snprintf(tmp,sizeof(tmp) - 1,"%s/%s.%s",urlprefix,fname_base,
			((strcmp(format,"gsm")) ? "wav" : "gsm"));
		if (!chan->cdr && !(chan->cdr = ast_cdr_alloc()))
			return -1;
		ast_cdr_setuserfield(chan, tmp);
	}
	if (waitforbridge) {
		/* We must remove the "b" option if listed.  In principle none of
		   the following could give NULL results, but we check just to
		   be pedantic. Reconstructing with checks for 'm' option does not
		   work if we end up adding more options than 'm' in the future. */
		delay = ast_strdupa(data);
		options = strrchr(delay, '|');
		if (options) {
			arg = strchr(options, 'b');
			if (arg) {
				*arg = 'X';
				pbx_builtin_setvar_helper(chan,"AUTO_MONITOR",delay);
			}
		}
		return 0;
	}

	res = ast_monitor_start(chan, format, fname_base, 1);
	if (res < 0)
		res = ast_monitor_change_fname(chan, fname_base, 1);
	ast_monitor_setjoinfiles(chan, joinfiles);

	return res;
}
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 ;
		
}