static int create_parked_subscription_full(struct ast_channel *chan, const char *parkee_uuid, int hangup_after,
	struct transfer_channel_data *parked_channel_data)
{
	struct ast_datastore *datastore;
	struct parked_subscription_datastore *parked_datastore;
	struct parked_subscription_data *subscription_data;

	char *parker_uuid = ast_strdupa(ast_channel_uniqueid(chan));
	size_t parker_uuid_size = strlen(parker_uuid) + 1;

	/* If there is already a subscription, get rid of it. */
	wipe_subscription_datastore(chan);

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

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

	if (!(subscription_data = ast_calloc(1, sizeof(*subscription_data) + parker_uuid_size +
			strlen(parkee_uuid) + 1))) {
		ast_datastore_free(datastore);
		ast_free(parked_datastore);
		return -1;
	}

	if (parked_channel_data) {
		subscription_data->transfer_data = parked_channel_data;
		ao2_ref(parked_channel_data, +1);
	}

	subscription_data->hangup_after = hangup_after;
	subscription_data->parkee_uuid = subscription_data->parker_uuid + parker_uuid_size;
	strcpy(subscription_data->parkee_uuid, parkee_uuid);
	strcpy(subscription_data->parker_uuid, parker_uuid);

	if (!(parked_datastore->parked_subscription = stasis_subscribe_pool(ast_parking_topic(), parker_update_cb, subscription_data))) {
		return -1;
	}

	datastore->data = parked_datastore;

	ast_channel_lock(chan);
	ast_channel_datastore_add(chan, datastore);
	ast_channel_unlock(chan);

	return 0;
}
Exemple #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;
}
Exemple #3
0
/*!
 * \brief Dial timeout
 *
 * This is a bridge interval hook callback. The interval hook triggering
 * means that the dial timeout has been reached. If the channel has not
 * been answered by the time this callback is called, then the channel
 * is hung up
 *
 * \param bridge_channel Bridge channel on which interval hook has been called
 * \param ignore Ignored
 * \return -1 (i.e. remove the interval hook)
 */
static int bridge_timeout(struct ast_bridge_channel *bridge_channel, void *ignore)
{
	struct ast_datastore *datastore;
	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);

	control = stasis_app_control_find_by_channel(bridge_channel->chan);

	ast_channel_lock(bridge_channel->chan);
	if (ast_channel_state(bridge_channel->chan) != AST_STATE_UP) {
		/* Don't bother removing the datastore because it will happen when the channel is hung up */
		ast_channel_unlock(bridge_channel->chan);
		stasis_app_send_command_async(control, hangup_channel, NULL, NULL);
		return -1;
	}

	datastore = ast_channel_datastore_find(bridge_channel->chan, &timeout_datastore, NULL);
	if (!datastore) {
		ast_channel_unlock(bridge_channel->chan);
		return -1;
	}
	ast_channel_datastore_remove(bridge_channel->chan, datastore);
	ast_channel_unlock(bridge_channel->chan);
	ast_datastore_free(datastore);

	return -1;
}
Exemple #4
0
static int srv_query_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
	struct ast_datastore *datastore;

	if (!chan) {
		ast_log(LOG_WARNING, "%s cannot be used without a channel\n", cmd);
		return -1;
	}

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "%s requires a service as an argument\n", cmd);
		return -1;
	}
	
	/* If they already called SRVQUERY for this service once,
	 * we need to kill the old datastore.
	 */
	ast_channel_lock(chan);
	datastore = ast_channel_datastore_find(chan, &srv_result_datastore_info, data);
	ast_channel_unlock(chan);

	if (datastore) {
		ast_channel_datastore_remove(chan, datastore);
		ast_datastore_free(datastore);
	}
	
	if (!srv_datastore_setup(data, chan)) {
		return -1;
	}

	ast_copy_string(buf, data, len);

	return 0;
}
Exemple #5
0
/*!
 * \internal
 * \brief Set the features datastore if it doesn't exist.
 *
 * \param chan Channel to add features datastore
 * \param my_features The channel's feature flags
 * \param peer_features The channel's bridge peer feature flags
 *
 * \retval TRUE if features datastore already existed.
 */
static int add_features_datastore(struct ast_channel *chan, const struct ast_flags *my_features, const struct ast_flags *peer_features)
{
	struct ast_datastore *datastore;
	struct ast_dial_features *dialfeatures;

	ast_channel_lock(chan);
	datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL);
	ast_channel_unlock(chan);
	if (datastore) {
		/* Already exists. */
		return 1;
	}

	/* Create a new datastore with specified feature flags. */
	datastore = ast_datastore_alloc(&dial_features_info, NULL);
	if (!datastore) {
		ast_log(LOG_WARNING, "Unable to create channel features datastore.\n");
		return 0;
	}
	dialfeatures = ast_calloc(1, sizeof(*dialfeatures));
	if (!dialfeatures) {
		ast_log(LOG_WARNING, "Unable to allocate memory for feature flags.\n");
		ast_datastore_free(datastore);
		return 0;
	}
	ast_copy_flags(&dialfeatures->my_features, my_features, AST_FLAGS_ALL);
	ast_copy_flags(&dialfeatures->peer_features, peer_features, AST_FLAGS_ALL);
	datastore->inheritance = DATASTORE_INHERIT_FOREVER;
	datastore->data = dialfeatures;
	ast_channel_lock(chan);
	ast_channel_datastore_add(chan, datastore);
	ast_channel_unlock(chan);
	return 0;
}
Exemple #6
0
/*! \internal \brief Disable talk detection on the channel */
static int remove_talk_detect(struct ast_channel *chan)
{
	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) {
		ast_log(AST_LOG_WARNING, "Cannot remove TALK_DETECT from %s: TALK_DETECT not currently enabled\n",
		        ast_channel_name(chan));
		return -1;
	}
	td_params = datastore->data;

	if (ast_audiohook_remove(chan, &td_params->audiohook)) {
		ast_log(AST_LOG_WARNING, "Failed to remove TALK_DETECT audiohook from channel %s\n",
		        ast_channel_name(chan));
		return -1;
	}

	if (ast_channel_datastore_remove(chan, datastore)) {
		ast_log(AST_LOG_WARNING, "Failed to remove TALK_DETECT datastore from channel %s\n",
		        ast_channel_name(chan));
		return -1;
	}
	ast_datastore_free(datastore);

	return 0;
}
static int frame_trace_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
{
	struct frame_trace_data *framedata;
	struct ast_datastore *datastore = NULL;
	struct ast_framehook_interface interface = {
		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
		.event_cb = hook_event_cb,
		.destroy_cb = hook_destroy_cb,
	};
	int i = 0;

	if (!(framedata = ast_calloc(1, sizeof(*framedata)))) {
		return 0;
	}

	interface.data = framedata;

	if (!strcasecmp(data, "black")) {
		framedata->list_type = 1;
	}
	for (i = 0; i < ARRAY_LEN(frametype2str); i++) {
		if (strcasestr(value, frametype2str[i].str)) {
			framedata->values[i] = 1;
		}
	}

	ast_channel_lock(chan);
	i = ast_framehook_attach(chan, &interface);
	if (i >= 0) {
		int *id;
		if ((datastore = ast_channel_datastore_find(chan, &frame_trace_datastore, NULL))) {
			id = datastore->data;
			ast_framehook_detach(chan, *id);
			ast_channel_datastore_remove(chan, datastore);
		}

		if (!(datastore = ast_datastore_alloc(&frame_trace_datastore, NULL))) {
			ast_framehook_detach(chan, i);
			ast_channel_unlock(chan);
			return 0;
		}

		if (!(id = ast_calloc(1, sizeof(int)))) {
			ast_datastore_free(datastore);
			ast_framehook_detach(chan, i);
			ast_channel_unlock(chan);
			return 0;
		}

		*id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */
		datastore->data = id;
		ast_channel_datastore_add(chan, datastore);
	}
	ast_channel_unlock(chan);

	return 0;
}
static void wipe_subscription_datastore(struct ast_channel *chan)
{
	struct ast_datastore *datastore;

	ast_channel_lock(chan);

	datastore = ast_channel_datastore_find(chan, &parked_subscription_info, NULL);
	if (datastore) {
		ast_channel_datastore_remove(chan, datastore);
		ast_datastore_free(datastore);
	}
	ast_channel_unlock(chan);
}
/*! \brief Mute dialplan function */
static int func_mute_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
{
	struct ast_datastore *datastore = NULL;
	struct mute_information *mute = NULL;
	int is_new = 0;

	if (!chan) {
		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
		return -1;
	}

	ast_channel_lock(chan);
	if (!(datastore = ast_channel_datastore_find(chan, &mute_datastore, NULL))) {
		if (!(datastore = initialize_mutehook(chan))) {
			ast_channel_unlock(chan);
			return 0;
		}
		is_new = 1;
	}

	mute = datastore->data;

	if (!strcasecmp(data, "out")) {
		mute->mute_write = ast_true(value);
		ast_debug(1, "%s channel - outbound \n", ast_true(value) ? "Muting" : "Unmuting");
	} else if (!strcasecmp(data, "in")) {
		mute->mute_read = ast_true(value);
		ast_debug(1, "%s channel - inbound  \n", ast_true(value) ? "Muting" : "Unmuting");
	} else if (!strcasecmp(data,"all")) {
		mute->mute_write = mute->mute_read = ast_true(value);
	}

	if (is_new) {
		if (mute_add_audiohook(chan, mute, datastore)) {
			/* Can't add audiohook - already printed error message */
			ast_datastore_free(datastore);
			ast_free(mute);
		}
	}
	ast_channel_unlock(chan);

	return 0;
}
/*!
 * \internal
 * \brief Destroy the speech datastore on the given channel.
 *
 * \param chan Channel to destroy speech datastore.
 *
 * \retval 0 on success.
 * \retval -1 not found.
 */
static int speech_datastore_destroy(struct ast_channel *chan)
{
	struct ast_datastore *datastore;
	int res;

	ast_channel_lock(chan);
	datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
	if (datastore) {
		ast_channel_datastore_remove(chan, datastore);
	}
	ast_channel_unlock(chan);
	if (datastore) {
		ast_datastore_free(datastore);
		res = 0;
	} else {
		res = -1;
	}
	return res;
}
/*! \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;
}
Exemple #12
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;
}
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);
	);
static int manager_mutestream(struct mansession *s, const struct message *m)
{
	const char *channel = astman_get_header(m, "Channel");
	const char *id = astman_get_header(m,"ActionID");
	const char *state = astman_get_header(m,"State");
	const char *direction = astman_get_header(m,"Direction");
	char id_text[256];
	struct ast_channel *c = NULL;
	struct ast_datastore *datastore = NULL;
	struct mute_information *mute = NULL;
	int is_new = 0;
	int turnon;

	if (ast_strlen_zero(channel)) {
		astman_send_error(s, m, "Channel not specified");
		return 0;
	}
	if (ast_strlen_zero(state)) {
		astman_send_error(s, m, "State not specified");
		return 0;
	}
	if (ast_strlen_zero(direction)) {
		astman_send_error(s, m, "Direction not specified");
		return 0;
	}
	/* Ok, we have everything */

	c = ast_channel_get_by_name(channel);
	if (!c) {
		astman_send_error(s, m, "No such channel");
		return 0;
	}

	ast_channel_lock(c);

	if (!(datastore = ast_channel_datastore_find(c, &mute_datastore, NULL))) {
		if (!(datastore = initialize_mutehook(c))) {
			ast_channel_unlock(c);
			ast_channel_unref(c);
			astman_send_error(s, m, "Memory allocation failure");
			return 0;
		}
		is_new = 1;
	}
	mute = datastore->data;

	turnon = ast_true(state);
	if (!strcasecmp(direction, "in")) {
		mute->mute_read = turnon;
	} else if (!strcasecmp(direction, "out")) {
		mute->mute_write = turnon;
	} else if (!strcasecmp(direction, "all")) {
		mute->mute_read = mute->mute_write = turnon;
	}

	if (is_new) {
		if (mute_add_audiohook(c, mute, datastore)) {
			/* Can't add audiohook */
			ast_datastore_free(datastore);
			ast_free(mute);
			ast_channel_unlock(c);
			ast_channel_unref(c);
			astman_send_error(s, m, "Couldn't add mute audiohook");
			return 0;
		}
	}
	ast_channel_unlock(c);
	ast_channel_unref(c);

	if (!ast_strlen_zero(id)) {
		snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
	} else {
		id_text[0] = '\0';
	}
	astman_append(s, "Response: Success\r\n"
		"%s"
		"\r\n", id_text);
	return 0;
}
Exemple #15
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;
}
Exemple #16
0
void ast_jb_create_framehook(struct ast_channel *chan, struct ast_jb_conf *jb_conf, int prefer_existing)
{
	struct jb_framedata *framedata;
	struct ast_datastore *datastore = NULL;
	struct ast_framehook_interface interface = {
		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
		.event_cb = hook_event_cb,
		.destroy_cb = hook_destroy_cb,
	};
	int i = 0;

	/* If disabled, strip any existing jitterbuffer and don't replace it. */
	if (!strcasecmp(jb_conf->impl, "disabled")) {
		int *id;
		ast_channel_lock(chan);
		if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) {
			id = datastore->data;
			ast_framehook_detach(chan, *id);
			ast_channel_datastore_remove(chan, datastore);
			ast_datastore_free(datastore);
		}
		ast_channel_unlock(chan);
		return;
	}

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

	if (jb_framedata_init(framedata, jb_conf)) {
		jb_framedata_destroy(framedata);
		return;
	}

	interface.data = framedata;

	ast_channel_lock(chan);
	i = ast_framehook_attach(chan, &interface);
	if (i >= 0) {
		int *id;
		if ((datastore = ast_channel_datastore_find(chan, &jb_datastore, NULL))) {
			/* There is already a jitterbuffer on the channel. */
			if (prefer_existing) {
				/* We prefer the existing jitterbuffer, so remove the new one and keep the old one. */
				ast_framehook_detach(chan, i);
				ast_channel_unlock(chan);
				return;
			}
			/* We prefer the new jitterbuffer, so strip the old one. */
			id = datastore->data;
			ast_framehook_detach(chan, *id);
			ast_channel_datastore_remove(chan, datastore);
			ast_datastore_free(datastore);
		}

		if (!(datastore = ast_datastore_alloc(&jb_datastore, NULL))) {
			ast_framehook_detach(chan, i);
			ast_channel_unlock(chan);
			return;
		}

		if (!(id = ast_calloc(1, sizeof(int)))) {
			ast_datastore_free(datastore);
			ast_framehook_detach(chan, i);
			ast_channel_unlock(chan);
			return;
		}

		*id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */
		datastore->data = id;
		ast_channel_datastore_add(chan, datastore);

		ast_channel_set_fd(chan, AST_JITTERBUFFER_FD, framedata->timer_fd);
	} else {
		jb_framedata_destroy(framedata);
		framedata = NULL;
	}
	ast_channel_unlock(chan);
}
Exemple #17
0
int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target)
{
	struct ast_party_connected_line connected_caller;
	struct ast_datastore *ds_pickup;
	const char *chan_name;/*!< A masquerade changes channel names. */
	const char *target_name;/*!< A masquerade changes channel names. */
	int res = -1;

	RAII_VAR(struct ast_channel_snapshot *, chan_snapshot, NULL, ao2_cleanup);
	RAII_VAR(struct ast_channel_snapshot *, target_snapshot, NULL, ao2_cleanup);

	target_name = ast_strdupa(ast_channel_name(target));
	ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan));

	/* Mark the target to block any call pickup race. */
	ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
	if (!ds_pickup) {
		ast_log(LOG_WARNING,
			"Unable to create channel datastore on '%s' for call pickup\n", target_name);
		return -1;
	}
	ast_channel_datastore_add(target, ds_pickup);

	ast_party_connected_line_init(&connected_caller);
	ast_party_connected_line_copy(&connected_caller, ast_channel_connected(target));
	ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
	/* Reset any earlier private connected id representation */
	ast_party_id_reset(&connected_caller.priv);

	connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
	if (ast_channel_connected_line_sub(NULL, chan, &connected_caller, 0) &&
		ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
		ast_channel_update_connected_line(chan, &connected_caller, NULL);
	}
	ast_party_connected_line_free(&connected_caller);

	ast_channel_lock(chan);
	chan_name = ast_strdupa(ast_channel_name(chan));
	ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(chan));
	ast_channel_unlock(chan);
	connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;

	if (ast_answer(chan)) {
		ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
		goto pickup_failed;
	}

	if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
		ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
		goto pickup_failed;
	}

	ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);

	/* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */
	ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE);

	ast_channel_lock(chan);
	chan_snapshot = ast_channel_snapshot_create(chan);
	ast_channel_unlock(chan);
	if (!chan_snapshot) {
		goto pickup_failed;
	}

	target_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(target));
	if (!target_snapshot) {
		goto pickup_failed;
	}

	if (ast_channel_move(target, chan)) {
		ast_log(LOG_WARNING, "Unable to complete call pickup of '%s' with '%s'\n",
			chan_name, target_name);
		goto pickup_failed;
	}

	/* target points to the channel that did the pickup at this point, so use that channel's topic instead of chan */
	send_call_pickup_stasis_message(target, chan_snapshot, target_snapshot);

	res = 0;

pickup_failed:
	ast_channel_lock(target);
	if (!ast_channel_datastore_remove(target, ds_pickup)) {
		ast_datastore_free(ds_pickup);
	}
	ast_party_connected_line_free(&connected_caller);

	return res;
}
Exemple #18
0
/*!
 * \brief Get the lua_State for this channel
 *
 * If no channel is passed then a new state is allocated.  States with no
 * channel assocatied with them should only be used for matching extensions.
 * If the channel does not yet have a lua state associated with it, one will be
 * created.
 *
 * \note If no channel was passed then the caller is expected to free the state
 * using lua_close().
 *
 * \return a lua_State
 */
static lua_State *lua_get_state(struct ast_channel *chan)
{
	struct ast_datastore *datastore = NULL;
	lua_State *L;

	if (!chan) {
		L = luaL_newstate();
		if (!L) {
			ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n");
			return NULL;
		}

		if (lua_load_extensions(L, NULL)) {
			const char *error = lua_tostring(L, -1);
			ast_log(LOG_ERROR, "Error loading extensions.lua: %s\n", error);
			lua_close(L);
			return NULL;
		}
		return L;
	} else {
		ast_channel_lock(chan);
		datastore = ast_channel_datastore_find(chan, &lua_datastore, NULL);
		ast_channel_unlock(chan);

		if (!datastore) {
			/* nothing found, allocate a new lua state */
			datastore = ast_datastore_alloc(&lua_datastore, NULL);
			if (!datastore) {
				ast_log(LOG_ERROR, "Error allocation channel datastore for lua_State\n");
				return NULL;
			}

			datastore->data = luaL_newstate();
			if (!datastore->data) {
				ast_datastore_free(datastore);
				ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n");
				return NULL;
			}

			ast_channel_lock(chan);
			ast_channel_datastore_add(chan, datastore);
			ast_channel_unlock(chan);

			L = datastore->data;

			if (lua_load_extensions(L, chan)) {
				const char *error = lua_tostring(L, -1);
				ast_log(LOG_ERROR, "Error loading extensions.lua for %s: %s\n", ast_channel_name(chan), error);

				ast_channel_lock(chan);
				ast_channel_datastore_remove(chan, datastore);
				ast_channel_unlock(chan);

				ast_datastore_free(datastore);
				return NULL;
			}
		}

		return datastore->data;
	}
}
Exemple #19
0
struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event *event)
{
	struct varshead *headp;
	struct ast_var_t *newvariable;
	const char *mixed_name;
	char timebuf[30];
	struct ast_channel *tchan;
	struct ast_cel_event_record record = {
		.version = AST_CEL_EVENT_RECORD_VERSION,
	};
	struct ast_datastore *datastore;
	char *app_data;

	/* do not call ast_channel_alloc because this is not really a real channel */
	if (!(tchan = ast_dummy_channel_alloc())) {
		return NULL;
	}

	headp = ast_channel_varshead(tchan);

	/* first, get the variables from the event */
	if (ast_cel_fill_record(event, &record)) {
		ast_channel_unref(tchan);
		return NULL;
	}

	/* next, fill the channel with their data */
	mixed_name = (record.event_type == AST_CEL_USER_DEFINED)
		? record.user_defined_name : record.event_name;
	if ((newvariable = ast_var_assign("eventtype", mixed_name))) {
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
	}

	if (ast_strlen_zero(cel_dateformat)) {
		snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
				(long) record.event_time.tv_usec);
	} else {
		struct ast_tm tm;
		ast_localtime(&record.event_time, &tm, NULL);
		ast_strftime(timebuf, sizeof(timebuf), cel_dateformat, &tm);
	}

	if ((newvariable = ast_var_assign("eventtime", timebuf))) {
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
	}

	if ((newvariable = ast_var_assign("eventenum", record.event_name))) {
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
	}
	if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
	}
	if ((newvariable = ast_var_assign("eventextra", record.extra))) {
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
	}

	ast_channel_caller(tchan)->id.name.valid = 1;
	ast_channel_caller(tchan)->id.name.str = ast_strdup(record.caller_id_name);
	ast_channel_caller(tchan)->id.number.valid = 1;
	ast_channel_caller(tchan)->id.number.str = ast_strdup(record.caller_id_num);
	ast_channel_caller(tchan)->ani.number.valid = 1;
	ast_channel_caller(tchan)->ani.number.str = ast_strdup(record.caller_id_ani);
	ast_channel_redirecting(tchan)->from.number.valid = 1;
	ast_channel_redirecting(tchan)->from.number.str = ast_strdup(record.caller_id_rdnis);
	ast_channel_dialed(tchan)->number.str = ast_strdup(record.caller_id_dnid);

	ast_channel_exten_set(tchan, record.extension);
	ast_channel_context_set(tchan, record.context);
	ast_channel_name_set(tchan, record.channel_name);
	ast_channel_uniqueid_set(tchan, record.unique_id);
	ast_channel_linkedid_set(tchan, record.linked_id);
	ast_channel_accountcode_set(tchan, record.account_code);
	ast_channel_peeraccount_set(tchan, record.peer_account);
	ast_channel_userfield_set(tchan, record.user_field);

	if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) {
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
	}

	ast_channel_amaflags_set(tchan, record.amaflag);

	/* We need to store an 'application name' and 'application
	 * data' on the channel for logging purposes, but the channel
	 * structure only provides a place to store pointers, and it
	 * expects these pointers to be pointing to data that does not
	 * need to be freed. This means that the channel's destructor
	 * does not attempt to free any storage that these pointers
	 * point to. However, we can't provide data in that form directly for
	 * these structure members. In order to ensure that these data
	 * elements have a lifetime that matches the channel's
	 * lifetime, we'll put them in a datastore attached to the
	 * channel, and set's the channel's pointers to point into the
	 * datastore.  The datastore will then be automatically destroyed
	 * when the channel is destroyed.
	 */

	if (!(datastore = ast_datastore_alloc(&fabricated_channel_datastore, NULL))) {
		ast_channel_unref(tchan);
		return NULL;
	}

	if (!(app_data = ast_malloc(strlen(record.application_name) + strlen(record.application_data) + 2))) {
		ast_datastore_free(datastore);
		ast_channel_unref(tchan);
		return NULL;
	}

	ast_channel_appl_set(tchan, strcpy(app_data, record.application_name));
	ast_channel_data_set(tchan, strcpy(app_data + strlen(record.application_name) + 1,
		record.application_data));

	datastore->data = app_data;
	ast_channel_datastore_add(tchan, datastore);

	return tchan;
}