示例#1
0
static int attach_barge(struct ast_autochan *spyee_autochan,
	struct ast_autochan **spyee_bridge_autochan, struct ast_audiohook *bridge_whisper_audiohook,
	const char *spyer_name, const char *name)
{
	int retval = 0;
	struct ast_autochan *internal_bridge_autochan;
	struct ast_channel *bridged = ast_bridged_channel(spyee_autochan->chan);

	if (!bridged) {
		return -1;
	}

	ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);

	internal_bridge_autochan = ast_autochan_setup(bridged);
	if (!internal_bridge_autochan) {
		return -1;
	}

	ast_channel_lock(internal_bridge_autochan->chan);
	if (start_spying(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook)) {
		ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
		retval = -1;
	}
	ast_channel_unlock(internal_bridge_autochan->chan);

	*spyee_bridge_autochan = internal_bridge_autochan;

	return retval;
}
示例#2
0
/*! \internal \brief Enable talk detection on the channel */
static int set_talk_detect(struct ast_channel *chan, int dsp_silence_threshold, int dsp_talking_threshold)
{
	struct ast_datastore *datastore = NULL;
	struct talk_detect_params *td_params;
	SCOPED_CHANNELLOCK(chan_lock, chan);

	datastore = ast_channel_datastore_find(chan, &talk_detect_datastore, NULL);
	if (!datastore) {
		datastore = ast_datastore_alloc(&talk_detect_datastore, NULL);
		if (!datastore) {
			return -1;
		}

		td_params = ast_calloc(1, sizeof(*td_params));
		if (!td_params) {
			ast_datastore_free(datastore);
			return -1;
		}

		ast_audiohook_init(&td_params->audiohook,
		                   AST_AUDIOHOOK_TYPE_MANIPULATE,
		                   "TALK_DETECT",
		                   AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
		td_params->audiohook.manipulate_callback = talk_detect_audiohook_cb;
		ast_set_flag(&td_params->audiohook, AST_AUDIOHOOK_TRIGGER_READ);

		td_params->dsp = ast_dsp_new_with_rate(ast_format_get_sample_rate(ast_channel_rawreadformat(chan)));
		if (!td_params->dsp) {
			ast_datastore_free(datastore);
			ast_free(td_params);
			return -1;
		}
		datastore->data = td_params;

		ast_channel_datastore_add(chan, datastore);
		ast_audiohook_attach(chan, &td_params->audiohook);
	} else {
		/* Talk detection already enabled; update existing settings */
		td_params = datastore->data;
	}

	td_params->dsp_talking_threshold = dsp_talking_threshold;
	td_params->dsp_silence_threshold = dsp_silence_threshold;

	ast_dsp_set_threshold(td_params->dsp, td_params->dsp_talking_threshold);

	return 0;
}
示例#3
0
/*! \brief Internal helper function which sets up and attaches a snoop audiohook */
static int snoop_setup_audiohook(struct ast_channel *chan, enum ast_audiohook_type type, enum stasis_app_snoop_direction requested_direction,
	enum ast_audiohook_direction *direction, struct ast_audiohook *audiohook)
{
	ast_audiohook_init(audiohook, type, "Snoop", 0);

	if (requested_direction == STASIS_SNOOP_DIRECTION_OUT) {
		*direction = AST_AUDIOHOOK_DIRECTION_WRITE;
	} else if (requested_direction == STASIS_SNOOP_DIRECTION_IN) {
		*direction = AST_AUDIOHOOK_DIRECTION_READ;
	} else if (requested_direction == STASIS_SNOOP_DIRECTION_BOTH) {
		*direction = AST_AUDIOHOOK_DIRECTION_BOTH;
	} else {
		return -1;
	}

	return ast_audiohook_attach(chan, audiohook);
}
示例#4
0
/*! \brief Initialize mute hook on channel, but don't activate it
	\pre Assumes that the channel is locked
*/
static struct ast_datastore *initialize_mutehook(struct ast_channel *chan)
{
	struct ast_datastore *datastore = NULL;
	struct mute_information *mute = NULL;

	ast_debug(2, "Initializing new Mute Audiohook \n");

	/* Allocate a new datastore to hold the reference to this mute_datastore and audiohook information */
	if (!(datastore = ast_datastore_alloc(&mute_datastore, NULL))) {
		return NULL;
	}

	if (!(mute = ast_calloc(1, sizeof(*mute)))) {
		ast_datastore_free(datastore);
		return NULL;
	}
	ast_audiohook_init(&mute->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Mute", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
	mute->audiohook.manipulate_callback = mute_callback;
	datastore->data = mute;
	return datastore;
}
示例#5
0
static int volume_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
{
	struct ast_datastore *datastore = NULL;
	struct volume_information *vi = NULL;
	int is_new = 0;

	if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL))) {
		/* Allocate a new datastore to hold the reference to this volume and audiohook information */
		if (!(datastore = ast_datastore_alloc(&volume_datastore, NULL)))
			return 0;
		if (!(vi = ast_calloc(1, sizeof(*vi)))) {
			ast_datastore_free(datastore);
			return 0;
		}
		ast_audiohook_init(&vi->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
		vi->audiohook.manipulate_callback = volume_callback;
		ast_set_flag(&vi->audiohook, AST_AUDIOHOOK_WANTS_DTMF);
		is_new = 1;
	} else {
		vi = datastore->data;
	}

	/* Adjust gain on volume information structure */
	if (!strcasecmp(data, "tx"))
		vi->tx_gain = atoi(value);
	else if (!strcasecmp(data, "rx"))
		vi->rx_gain = atoi(value);

	if (is_new) {
		datastore->data = vi;
		ast_channel_datastore_add(chan, datastore);
		ast_audiohook_attach(chan, &vi->audiohook);
	}

	return 0;
}
示例#6
0
static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
	int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
	char *exitcontext)
{
	struct chanspy_translation_helper csth;
	int running = 0, res, x = 0;
	char inp[24] = {0};
	char *name;
	struct ast_frame *f;
	struct ast_silence_generator *silgen = NULL;
	struct ast_autochan *spyee_bridge_autochan = NULL;
	const char *spyer_name;
	struct ast_channel *chans[] = { chan, spyee_autochan->chan };

	ast_channel_lock(chan);
	spyer_name = ast_strdupa(chan->name);
	ast_channel_unlock(chan);

	/* We now hold the channel lock on spyee */

	if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan)) {
		return 0;
	}

	ast_channel_lock(spyee_autochan->chan);
	name = ast_strdupa(spyee_autochan->chan->name);
	ast_channel_unlock(spyee_autochan->chan);

	ast_verb(2, "Spying on channel %s\n", name);
	ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans,
			"SpyerChannel: %s\r\n"
			"SpyeeChannel: %s\r\n",
			spyer_name, name);

	memset(&csth, 0, sizeof(csth));
	ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);

	ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");

	if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
		ast_audiohook_destroy(&csth.spy_audiohook);
		return 0;
	}

	ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
	ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
	if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
		ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
	}
	if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) {
		ast_channel_lock(spyee_bridge_autochan->chan);
		if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
			ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
		}
		ast_channel_unlock(spyee_bridge_autochan->chan);
	}

	ast_channel_lock(chan);
	ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
	ast_channel_unlock(chan);

	csth.volfactor = *volfactor;

	if (csth.volfactor) {
		csth.spy_audiohook.options.read_volume = csth.volfactor;
		csth.spy_audiohook.options.write_volume = csth.volfactor;
	}

	csth.fd = fd;

	if (ast_test_flag(flags, OPTION_PRIVATE))
		silgen = ast_channel_start_silence_generator(chan);
	else
		ast_activate_generator(chan, &spygen, &csth);

	/* We can no longer rely on 'spyee' being an actual channel;
	   it can be hung up and freed out from under us. However, the
	   channel destructor will put NULL into our csth.spy.chan
	   field when that happens, so that is our signal that the spyee
	   channel has gone away.
	*/

	/* Note: it is very important that the ast_waitfor() be the first
	   condition in this expression, so that if we wait for some period
	   of time before receiving a frame from our spying channel, we check
	   for hangup on the spied-on channel _after_ knowing that a frame
	   has arrived, since the spied-on channel could have gone away while
	   we were waiting
	*/
	while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
		if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
			running = -1;
			break;
		}

		if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
			ast_audiohook_lock(&csth.whisper_audiohook);
			ast_audiohook_lock(&csth.bridge_whisper_audiohook);
			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_unlock(&csth.whisper_audiohook);
			ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
			ast_frfree(f);
			continue;
		} else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
			ast_audiohook_lock(&csth.whisper_audiohook);
			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_unlock(&csth.whisper_audiohook);
			ast_frfree(f);
			continue;
		}
		
		res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
		ast_frfree(f);
		if (!res)
			continue;

		if (x == sizeof(inp))
			x = 0;

		if (res < 0) {
			running = -1;
			break;
		}

		if (ast_test_flag(flags, OPTION_EXIT)) {
			char tmp[2];
			tmp[0] = res;
			tmp[1] = '\0';
			if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
				ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
				pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
				running = -2;
				break;
			} else {
				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
			}
		} else if (res >= '0' && res <= '9') {
			if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) {
				change_spy_mode(res, flags);
			} else {
				inp[x++] = res;
			}
		}

		if (res == user_options->cycle) {
			running = 0;
			break;
		} else if (res == user_options->exit) {
			running = -2;
			break;
		} else if (res == user_options->volume) {
			if (!ast_strlen_zero(inp)) {
				running = atoi(inp);
				break;
			}

			(*volfactor)++;
			if (*volfactor > 4)
				*volfactor = -4;
			ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);

			csth.volfactor = *volfactor;
			csth.spy_audiohook.options.read_volume = csth.volfactor;
			csth.spy_audiohook.options.write_volume = csth.volfactor;
		}
	}

	if (ast_test_flag(flags, OPTION_PRIVATE))
		ast_channel_stop_silence_generator(chan, silgen);
	else
		ast_deactivate_generator(chan);

	ast_channel_lock(chan);
	ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
	ast_channel_unlock(chan);

	ast_audiohook_lock(&csth.whisper_audiohook);
	ast_audiohook_detach(&csth.whisper_audiohook);
	ast_audiohook_unlock(&csth.whisper_audiohook);
	ast_audiohook_destroy(&csth.whisper_audiohook);
	
	ast_audiohook_lock(&csth.bridge_whisper_audiohook);
	ast_audiohook_detach(&csth.bridge_whisper_audiohook);
	ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
	ast_audiohook_destroy(&csth.bridge_whisper_audiohook);

	ast_audiohook_lock(&csth.spy_audiohook);
	ast_audiohook_detach(&csth.spy_audiohook);
	ast_audiohook_unlock(&csth.spy_audiohook);
	ast_audiohook_destroy(&csth.spy_audiohook);

	if (spyee_bridge_autochan) {
		ast_autochan_destroy(spyee_bridge_autochan);
	}

	ast_verb(2, "Done Spying on channel %s\n", name);
	ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);

	return running;
}
示例#7
0
static void *hook_launch_thread(void *data)
{
	struct hook_thread_arg *arg = data;
	struct ast_variable hook_id = {
		.name = "HOOK_ID",
		.value = arg->hook_id,
	};
	struct ast_variable chan_name_var = {
		.name = "HOOK_CHANNEL",
		.value = arg->chan_name,
		.next = &hook_id,
	};

	ast_pbx_outgoing_exten("Local", NULL, full_exten_name, 60,
			arg->context, arg->exten, 1, NULL, AST_OUTGOING_NO_WAIT,
			NULL, NULL, &chan_name_var, NULL, NULL, 1, NULL);

	hook_thread_arg_destroy(arg);

	return NULL;
}

static struct hook_thread_arg *hook_thread_arg_alloc(struct ast_channel *chan,
		struct hook_state *state)
{
	struct hook_thread_arg *arg;

	if (!(arg = ast_calloc(1, sizeof(*arg)))) {
		return NULL;
	}

	ast_channel_lock(chan);
	arg->chan_name = ast_strdup(ast_channel_name(chan));
	ast_channel_unlock(chan);
	if (!arg->chan_name) {
		hook_thread_arg_destroy(arg);
		return NULL;
	}

	if (ast_asprintf(&arg->hook_id, "%u", state->hook_id) == -1) {
		hook_thread_arg_destroy(arg);
		return NULL;
	}

	if (!(arg->context = ast_strdup(state->context))) {
		hook_thread_arg_destroy(arg);
		return NULL;
	}

	if (!(arg->exten = ast_strdup(state->exten))) {
		hook_thread_arg_destroy(arg);
		return NULL;
	}

	return arg;
}

static int do_hook(struct ast_channel *chan, struct hook_state *state)
{
	pthread_t t;
	struct hook_thread_arg *arg;
	int res;

	if (!(arg = hook_thread_arg_alloc(chan, state))) {
		return -1;
	}

	/*
	 * We don't want to block normal frame processing *at all* while we kick
	 * this off, so do it in a new thread.
	 */
	res = ast_pthread_create_detached_background(&t, NULL, hook_launch_thread, arg);
	if (res != 0) {
		hook_thread_arg_destroy(arg);
	}

	return res;
}

static int hook_callback(struct ast_audiohook *audiohook, struct ast_channel *chan,
		struct ast_frame *frame, enum ast_audiohook_direction direction)
{
	struct hook_state *state = (struct hook_state *) audiohook; /* trust me. */
	struct timeval now;
	int res = 0;

	if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || state->disabled) {
		return 0;
	}

	now = ast_tvnow();
	if (ast_tvdiff_ms(now, state->last_hook) > state->interval * 1000) {
		if ((res = do_hook(chan, state))) {
			const char *name;
			ast_channel_lock(chan);
			name = ast_strdupa(ast_channel_name(chan));
			ast_channel_unlock(chan);
			ast_log(LOG_WARNING, "Failed to run hook on '%s'\n", name);
		}
		state->last_hook = now;
	}

	return res;
}

static struct hook_state *hook_state_alloc(const char *context, const char *exten,
		unsigned int interval, unsigned int hook_id)
{
	struct hook_state *state;

	if (!(state = ast_calloc(1, sizeof(*state)))) {
		return NULL;
	}

	state->context = ast_strdup(context);
	state->exten = ast_strdup(exten);
	state->interval = interval;
	state->hook_id = hook_id;

	ast_audiohook_init(&state->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE,
			AST_MODULE, AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
	state->audiohook.manipulate_callback = hook_callback;

	return state;
}

static int init_hook(struct ast_channel *chan, const char *context, const char *exten,
		unsigned int interval, unsigned int hook_id)
{
	struct hook_state *state;
	struct ast_datastore *datastore;
	char uid[32];

	snprintf(uid, sizeof(uid), "%u", hook_id);

	if (!(datastore = ast_datastore_alloc(&hook_datastore, uid))) {
		return -1;
	}
	ast_module_ref(ast_module_info->self);
	if (!(state = hook_state_alloc(context, exten, interval, hook_id))) {
		ast_datastore_free(datastore);
		return -1;
	}
	datastore->data = state;

	ast_channel_lock(chan);
	ast_channel_datastore_add(chan, datastore);
	ast_audiohook_attach(chan, &state->audiohook);
	ast_channel_unlock(chan);

	return 0;
}

static int hook_on(struct ast_channel *chan, const char *data, unsigned int hook_id)
{
	char *parse = ast_strdupa(S_OR(data, ""));
	AST_DECLARE_APP_ARGS(args,
		AST_APP_ARG(context);
		AST_APP_ARG(exten);
		AST_APP_ARG(interval);
	);
示例#8
0
static int speex_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
{
	struct ast_datastore *datastore = NULL;
	struct speex_info *si = NULL;
	struct speex_direction_info **sdi = NULL;
	int is_new = 0;

	ast_channel_lock(chan);
	if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
		ast_channel_unlock(chan);

		if (!(datastore = ast_datastore_alloc(&speex_datastore, NULL))) {
			return 0;
		}

		if (!(si = ast_calloc(1, sizeof(*si)))) {
			ast_datastore_free(datastore);
			return 0;
		}

		ast_audiohook_init(&si->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "speex", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
		si->audiohook.manipulate_callback = speex_callback;
		si->lastrate = 8000;
		is_new = 1;
	} else {
		ast_channel_unlock(chan);
		si = datastore->data;
	}

	if (!strcasecmp(data, "rx")) {
		sdi = &si->rx;
	} else if (!strcasecmp(data, "tx")) {
		sdi = &si->tx;
	} else {
		ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);

		if (is_new) {
			ast_datastore_free(datastore);
			return -1;
		}
	}

	if (!*sdi) {
		if (!(*sdi = ast_calloc(1, sizeof(**sdi)))) {
			return 0;
		}
		/* Right now, the audiohooks API will _only_ provide us 8 kHz slinear
		 * audio.  When it supports 16 kHz (or any other sample rates, we will
		 * have to take that into account here. */
		(*sdi)->samples = -1;
	}

	if (!strcasecmp(cmd, "agc")) {
		if (!sscanf(value, "%30f", &(*sdi)->agclevel))
			(*sdi)->agclevel = ast_true(value) ? DEFAULT_AGC_LEVEL : 0.0;
	
		if ((*sdi)->agclevel > 32768.0) {
			ast_log(LOG_WARNING, "AGC(%s)=%.01f is greater than 32768... setting to 32768 instead\n", 
					((*sdi == si->rx) ? "rx" : "tx"), (*sdi)->agclevel);
			(*sdi)->agclevel = 32768.0;
		}
	
		(*sdi)->agc = !!((*sdi)->agclevel);

		if ((*sdi)->state) {
			speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC, &(*sdi)->agc);
			if ((*sdi)->agc) {
				speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &(*sdi)->agclevel);
			}
		}
	} else if (!strcasecmp(cmd, "denoise")) {
		(*sdi)->denoise = (ast_true(value) != 0);

		if ((*sdi)->state) {
			speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_DENOISE, &(*sdi)->denoise);
		}
	}

	if (!(*sdi)->agc && !(*sdi)->denoise) {
		if ((*sdi)->state)
			speex_preprocess_state_destroy((*sdi)->state);

		ast_free(*sdi);
		*sdi = NULL;
	}

	if (!si->rx && !si->tx) {
		if (is_new) {
			is_new = 0;
		} else {
			ast_channel_lock(chan);
			ast_channel_datastore_remove(chan, datastore);
			ast_channel_unlock(chan);
			ast_audiohook_remove(chan, &si->audiohook);
			ast_audiohook_detach(&si->audiohook);
		}
		
		ast_datastore_free(datastore);
	}

	if (is_new) { 
		datastore->data = si;
		ast_channel_lock(chan);
		ast_channel_datastore_add(chan, datastore);
		ast_channel_unlock(chan);
		ast_audiohook_attach(chan, &si->audiohook);
	}

	return 0;
}
示例#9
0
static void launch_monitor_thread(struct ast_channel *chan, const char *filename,
				  unsigned int flags, int readvol, int writevol,
				  const char *post_process, const char *filename_write,
				  char *filename_read, const char *uid_channel_var)
{
	pthread_t thread;
	struct mixmonitor *mixmonitor;
	char postprocess2[1024] = "";
	char *datastore_id = NULL;

	postprocess2[0] = 0;
	/* If a post process system command is given attach it to the structure */
	if (!ast_strlen_zero(post_process)) {
		char *p1, *p2;

		p1 = ast_strdupa(post_process);
		for (p2 = p1; *p2; p2++) {
			if (*p2 == '^' && *(p2+1) == '{') {
				*p2 = '$';
			}
		}
		pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
	}

	/* Pre-allocate mixmonitor structure and spy */
	if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
		return;
	}

	/* Setup the actual spy before creating our thread */
	if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type, 0)) {
		mixmonitor_free(mixmonitor);
		return;
	}

	/* Copy over flags and channel name */
	mixmonitor->flags = flags;
	if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
		mixmonitor_free(mixmonitor);
		return;
	}

	if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id)) {
		ast_autochan_destroy(mixmonitor->autochan);
		mixmonitor_free(mixmonitor);
		ast_free(datastore_id);
		return;
	}

	if (!ast_strlen_zero(uid_channel_var)) {
		if (datastore_id) {
			pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
		}
	}
	ast_free(datastore_id);


	mixmonitor->name = ast_strdup(ast_channel_name(chan));

	if (!ast_strlen_zero(postprocess2)) {
		mixmonitor->post_process = ast_strdup(postprocess2);
	}

	if (!ast_strlen_zero(filename)) {
		mixmonitor->filename = ast_strdup(filename);
	}

	if (!ast_strlen_zero(filename_write)) {
		mixmonitor->filename_write = ast_strdup(filename_write);
	}

	if (!ast_strlen_zero(filename_read)) {
		mixmonitor->filename_read = ast_strdup(filename_read);
	}

	ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);

	if (readvol)
		mixmonitor->audiohook.options.read_volume = readvol;
	if (writevol)
		mixmonitor->audiohook.options.write_volume = writevol;

	if (startmon(chan, &mixmonitor->audiohook)) {
		ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
			mixmonitor_spy_type, ast_channel_name(chan));
		ast_audiohook_destroy(&mixmonitor->audiohook);
		mixmonitor_free(mixmonitor);
		return;
	}

	ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
}
示例#10
0
static void launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags,
				  int readvol, int writevol, const char *post_process) 
{
	pthread_attr_t attr;
	pthread_t thread;
	struct mixmonitor *mixmonitor;
	char postprocess2[1024] = "";
	size_t len;

	len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2;

	/* If a post process system command is given attach it to the structure */
	if (!ast_strlen_zero(post_process)) {
		char *p1, *p2;

		p1 = ast_strdupa(post_process);
		for (p2 = p1; *p2 ; p2++) {
			if (*p2 == '^' && *(p2+1) == '{') {
				*p2 = '$';
			}
		}

		pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
		if (!ast_strlen_zero(postprocess2))
			len += strlen(postprocess2) + 1;
	}

	/* Pre-allocate mixmonitor structure and spy */
	if (!(mixmonitor = calloc(1, len))) {
		return;
	}

	/* Copy over flags and channel name */
	mixmonitor->flags = flags;
	if (setup_mixmonitor_ds(mixmonitor, chan)) {
		return;
	}
	mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);
	strcpy(mixmonitor->name, chan->name);
	if (!ast_strlen_zero(postprocess2)) {
		mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2;
		strcpy(mixmonitor->post_process, postprocess2);
	}

	mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1;
	strcpy(mixmonitor->filename, filename);

	/* Setup the actual spy before creating our thread */
	if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) {
		free(mixmonitor);
		return;
	}
	
	ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
	
	if (readvol)
		mixmonitor->audiohook.options.read_volume = readvol;
	if (writevol)
		mixmonitor->audiohook.options.write_volume = writevol;

	if (startmon(chan, &mixmonitor->audiohook)) {
		ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
			mixmonitor_spy_type, chan->name);
		/* Since we couldn't add ourselves - bail out! */
		ast_audiohook_destroy(&mixmonitor->audiohook);
		free(mixmonitor);
		return;
	}

	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	ast_pthread_create_background(&thread, &attr, mixmonitor_thread, mixmonitor);
	pthread_attr_destroy(&attr);
}
示例#11
0
static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
	int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
	char *exitcontext)
{
	struct chanspy_translation_helper csth;
	int running = 0, res, x = 0;
	char inp[24] = {0};
	char *name;
	struct ast_frame *f;
	struct ast_silence_generator *silgen = NULL;
	struct ast_autochan *spyee_bridge_autochan = NULL;
	const char *spyer_name;

	if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan) ||
			ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
		return 0;
	}

	ast_channel_lock(chan);
	spyer_name = ast_strdupa(ast_channel_name(chan));
	ast_channel_unlock(chan);

	ast_channel_lock(spyee_autochan->chan);
	name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
	ast_channel_unlock(spyee_autochan->chan);

	ast_verb(2, "Spying on channel %s\n", name);
	publish_chanspy_message(chan, spyee_autochan->chan, 1);

	memset(&csth, 0, sizeof(csth));
	ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);

	/* This is the audiohook which gives us the audio off the channel we are
	   spying on.
	*/
	ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy", 0);

	if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
		ast_audiohook_destroy(&csth.spy_audiohook);
		return 0;
	}

	if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
		/* This audiohook will let us inject audio from our channel into the
		   channel we are currently spying on.
		*/
		ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy", 0);

		if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
			ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
		}
	}

	if (ast_test_flag(flags, OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
		RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(spyee_autochan->chan), ast_channel_cleanup);

		/* And this hook lets us inject audio into the channel that the spied on
		   channel is currently bridged with.
		*/
		ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);

		if ((spyee_bridge_autochan = ast_autochan_setup(bridged))) {
			ast_channel_lock(spyee_bridge_autochan->chan);
			if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
				ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
			}
			ast_channel_unlock(spyee_bridge_autochan->chan);
		}
	}
示例#12
0
static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds, 
	int *volfactor, int fd, const struct ast_flags *flags) 
{
	struct chanspy_translation_helper csth;
	int running = 0, res, x = 0;
	char inp[24] = {0};
	char *name;
	struct ast_frame *f;
	struct ast_silence_generator *silgen = NULL;
	struct ast_channel *spyee = NULL;
	const char *spyer_name;

	ast_channel_lock(chan);
	spyer_name = ast_strdupa(chan->name);
	ast_channel_unlock(chan);

	ast_mutex_lock(&spyee_chanspy_ds->lock);
	while ((spyee = spyee_chanspy_ds->chan) && ast_channel_trylock(spyee)) {
		/* avoid a deadlock here, just in case spyee is masqueraded and
		 * chanspy_ds_chan_fixup() is called with the channel locked */
		DEADLOCK_AVOIDANCE(&spyee_chanspy_ds->lock);
	}
	ast_mutex_unlock(&spyee_chanspy_ds->lock);

	if (!spyee)
		return 0;

	/* We now hold the channel lock on spyee */

	if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
		ast_channel_unlock(spyee);
		return 0;
	}

	name = ast_strdupa(spyee->name);
	if (option_verbose >= 2)
		ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);

	memset(&csth, 0, sizeof(csth));
	
	ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");

	if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
		ast_audiohook_destroy(&csth.spy_audiohook);
		ast_channel_unlock(spyee);
		return 0;
	}
	
	if (ast_test_flag(flags, OPTION_WHISPER)) {
		ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
		start_spying(spyee, spyer_name, &csth.whisper_audiohook);
	}

	ast_channel_unlock(spyee);
	spyee = NULL;

	csth.volfactor = *volfactor;
	
	if (csth.volfactor) {
		csth.spy_audiohook.options.read_volume = csth.volfactor;
		csth.spy_audiohook.options.write_volume = csth.volfactor;
	}
	
	csth.fd = fd;

	if (ast_test_flag(flags, OPTION_PRIVATE))
		silgen = ast_channel_start_silence_generator(chan);
	else
		ast_activate_generator(chan, &spygen, &csth);

	/* We can no longer rely on 'spyee' being an actual channel;
	   it can be hung up and freed out from under us. However, the
	   channel destructor will put NULL into our csth.spy.chan
	   field when that happens, so that is our signal that the spyee
	   channel has gone away.
	*/

	/* Note: it is very important that the ast_waitfor() be the first
	   condition in this expression, so that if we wait for some period
	   of time before receiving a frame from our spying channel, we check
	   for hangup on the spied-on channel _after_ knowing that a frame
	   has arrived, since the spied-on channel could have gone away while
	   we were waiting
	*/
	while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
		if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
			running = -1;
			break;
		}

		if (ast_test_flag(flags, OPTION_WHISPER) && (f->frametype == AST_FRAME_VOICE)) {
			ast_audiohook_lock(&csth.whisper_audiohook);
			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_unlock(&csth.whisper_audiohook);
			ast_frfree(f);
			continue;
		}

		res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
		ast_frfree(f);
		if (!res)
			continue;

		if (x == sizeof(inp))
			x = 0;

		if (res < 0) {
			running = -1;
			break;
		}

		if (res == '*') {
			running = 0;
			break;
		} else if (res == '#') {
			if (!ast_strlen_zero(inp)) {
				running = atoi(inp);
				break;
			}

			(*volfactor)++;
			if (*volfactor > 4)
				*volfactor = -4;
			if (option_verbose > 2)
				ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
			csth.volfactor = *volfactor;
			csth.spy_audiohook.options.read_volume = csth.volfactor;
			csth.spy_audiohook.options.write_volume = csth.volfactor;
		} else if (res >= '0' && res <= '9') {
			inp[x++] = res;
		}
	}

	if (ast_test_flag(flags, OPTION_PRIVATE))
		ast_channel_stop_silence_generator(chan, silgen);
	else
		ast_deactivate_generator(chan);

	if (ast_test_flag(flags, OPTION_WHISPER)) {
		ast_audiohook_lock(&csth.whisper_audiohook);
		ast_audiohook_detach(&csth.whisper_audiohook);
		ast_audiohook_unlock(&csth.whisper_audiohook);
		ast_audiohook_destroy(&csth.whisper_audiohook);
	}
	
	ast_audiohook_lock(&csth.spy_audiohook);
	ast_audiohook_detach(&csth.spy_audiohook);
	ast_audiohook_unlock(&csth.spy_audiohook);
	ast_audiohook_destroy(&csth.spy_audiohook);
	
	if (option_verbose >= 2)
		ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
	
	return running;
}