Esempio n. 1
0
int stasis_app_control_dial(struct stasis_app_control *control, const char *endpoint, const char *exten, const char *context,
                            int timeout)
{
    struct stasis_app_control_dial_data *dial_data;

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

    if (!ast_strlen_zero(endpoint)) {
        ast_copy_string(dial_data->endpoint, endpoint, sizeof(dial_data->endpoint));
    } else if (!ast_strlen_zero(exten) && !ast_strlen_zero(context)) {
        snprintf(dial_data->endpoint, sizeof(dial_data->endpoint), "Local/%s@%s", exten, context);
    } else {
        return -1;
    }

    if (timeout > 0) {
        dial_data->timeout = timeout * 1000;
    } else if (timeout == -1) {
        dial_data->timeout = -1;
    } else {
        dial_data->timeout = 30000;
    }

    stasis_app_send_command_async(control, app_control_dial, dial_data);

    return 0;
}
Esempio n. 2
0
int stasis_app_control_set_channel_var(struct stasis_app_control *control, const char *variable, const char *value)
{
	struct chanvar *var;

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

	var->name = ast_strdup(variable);
	if (!var->name) {
		free_chanvar(var);
		return -1;
	}

	/* It's kosher for value to be NULL. It means the variable is being unset */
	if (value) {
		var->value = ast_strdup(value);
		if (!var->value) {
			free_chanvar(var);
			return -1;
		}
	}

	stasis_app_send_command_async(control, app_control_set_channel_var, var, free_chanvar);

	return 0;
}
Esempio n. 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;
}
Esempio n. 4
0
static void bridge_after_cb(struct ast_channel *chan, void *data)
{
    struct stasis_app_control *control = data;
    SCOPED_AO2LOCK(lock, control);
    struct ast_bridge_channel *bridge_channel;

    ast_debug(3, "%s, %s: Channel leaving bridge\n",
              ast_channel_uniqueid(chan), control->bridge->uniqueid);

    ast_assert(chan == control->channel);

    /* Restore the channel's PBX */
    ast_channel_pbx_set(control->channel, control->pbx);
    control->pbx = NULL;

    /* No longer in the bridge */
    control->bridge = NULL;

    /* Get the bridge channel so we don't depart from the wrong bridge */
    ast_channel_lock(chan);
    bridge_channel = ast_channel_get_bridge_channel(chan);
    ast_channel_unlock(chan);

    /* Depart this channel from the bridge using the command queue if possible */
    if (stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel)) {
        ao2_cleanup(bridge_channel);
    }
}
Esempio n. 5
0
void stasis_app_control_moh_start(struct stasis_app_control *control, const char *moh_class)
{
    char *data = NULL;

    if (!ast_strlen_zero(moh_class)) {
        data = ast_strdup(moh_class);
    }

    stasis_app_send_command_async(control, app_control_moh_start, data);
}
Esempio n. 6
0
int stasis_app_control_redirect(struct stasis_app_control *control, const char *endpoint)
{
	char *endpoint_data = ast_strdup(endpoint);

	if (!endpoint_data) {
		return -1;
	}

	stasis_app_send_command_async(control, app_control_redirect, endpoint_data, ast_free_ptr);

	return 0;
}
Esempio n. 7
0
static void internal_bridge_after_cb(struct ast_channel *chan, void *data,
	enum ast_bridge_after_cb_reason reason)
{
	struct stasis_app_control *control = data;
	SCOPED_AO2LOCK(lock, control);
	struct ast_bridge_channel *bridge_channel;

	ast_debug(3, "%s, %s: %s\n",
		ast_channel_uniqueid(chan), control->bridge ? control->bridge->uniqueid : "unknown",
			ast_bridge_after_cb_reason_string(reason));

	if (reason == AST_BRIDGE_AFTER_CB_REASON_IMPART_FAILED) {
		/* The impart actually failed so control->bridge isn't valid. */
		control->bridge = NULL;
	}

	ast_assert(chan == control->channel);

	/* Restore the channel's PBX */
	ast_channel_pbx_set(control->channel, control->pbx);
	control->pbx = NULL;

	if (control->bridge) {
		app_unsubscribe_bridge(control->app, control->bridge);

		/* No longer in the bridge */
		control->bridge = NULL;

		/* Get the bridge channel so we don't depart from the wrong bridge */
		ast_channel_lock(chan);
		bridge_channel = ast_channel_get_bridge_channel(chan);
		ast_channel_unlock(chan);

		/* Depart this channel from the bridge using the command queue if possible */
		stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel, __ao2_cleanup);
	}

	if (stasis_app_channel_is_stasis_end_published(chan)) {
		/* The channel has had a StasisEnd published on it, but until now had remained in
		 * the bridging system. This means that the channel moved from a Stasis bridge to a
		 * non-Stasis bridge and is now exiting the bridging system. Because of this, the
		 * channel needs to exit the Stasis application and go to wherever the non-Stasis
		 * bridge has directed it to go. If the non-Stasis bridge has not set up an after
		 * bridge destination, then the channel should be hung up.
		 */
		int hangup_flag;

		hangup_flag = ast_bridge_setup_after_goto(chan) ? AST_SOFTHANGUP_DEV : AST_SOFTHANGUP_ASYNCGOTO;
		ast_channel_lock(chan);
		ast_softhangup_nolock(chan, hangup_flag);
		ast_channel_unlock(chan);
	}
}
Esempio n. 8
0
int stasis_app_control_add_role(struct stasis_app_control *control, const char *role)
{
	char *role_dup;

	role_dup = ast_strdup(role);
	if (!role_dup) {
		return -1;
	}

	stasis_app_send_command_async(control, app_control_add_role, role_dup, ast_free_ptr);

	return 0;
}
Esempio n. 9
0
int stasis_app_control_dial(struct stasis_app_control *control,
		const char *dialstring, unsigned int timeout)
{
	struct control_dial_args *args;

	args = control_dial_args_alloc(dialstring, timeout);
	if (!args) {
		return -1;
	}

	return stasis_app_send_command_async(control, app_control_dial,
		args, control_dial_args_destroy);
}
Esempio n. 10
0
/*!
 * \brief after bridge callback for the dial bridge
 *
 * The only purpose of this callback is to ensure that the control structure's
 * bridge pointer is NULLed
 */
static void dial_bridge_after_cb(struct ast_channel *chan, void *data)
{
	struct stasis_app_control *control = data;
	struct ast_bridge_channel *bridge_channel;

	ast_channel_lock(chan);
	bridge_channel = ast_channel_get_bridge_channel(chan);
	ast_channel_unlock(chan);

	ast_debug(3, "Channel: <%s>  Reason: %d\n", ast_channel_name(control->channel), ast_channel_hangupcause(chan));

	stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel, __ao2_cleanup);

	control->bridge = NULL;
}
Esempio n. 11
0
int stasis_app_control_unmute(struct stasis_app_control *control, unsigned int direction, enum ast_frame_type frametype)
{
    struct stasis_app_control_mute_data *mute_data;

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

    mute_data->direction = direction;
    mute_data->frametype = frametype;

    stasis_app_send_command_async(control, app_control_unmute, mute_data);

    return 0;
}
Esempio n. 12
0
int stasis_app_control_dtmf(struct stasis_app_control *control, const char *dtmf, int before, int between, unsigned int duration, int after)
{
    struct stasis_app_control_dtmf_data *dtmf_data;

    if (!(dtmf_data = ast_calloc(1, sizeof(*dtmf_data) + strlen(dtmf) + 1))) {
        return -1;
    }

    dtmf_data->before = before;
    dtmf_data->between = between;
    dtmf_data->duration = duration;
    dtmf_data->after = after;
    strcpy(dtmf_data->dtmf, dtmf);

    stasis_app_send_command_async(control, app_control_dtmf, dtmf_data);

    return 0;
}
Esempio n. 13
0
int stasis_app_control_continue(struct stasis_app_control *control, const char *context, const char *extension, int priority)
{
    struct stasis_app_control_continue_data *continue_data;

    if (!(continue_data = ast_calloc(1, sizeof(*continue_data)))) {
        return -1;
    }
    ast_copy_string(continue_data->context, S_OR(context, ""), sizeof(continue_data->context));
    ast_copy_string(continue_data->extension, S_OR(extension, ""), sizeof(continue_data->extension));
    if (priority > 0) {
        continue_data->priority = priority;
    } else {
        continue_data->priority = -1;
    }

    stasis_app_send_command_async(control, app_control_continue, continue_data);

    return 0;
}
Esempio n. 14
0
int stasis_app_control_dial(struct stasis_app_control *control, const char *endpoint, int timeout)
{
	struct stasis_app_control_dial_data *dial_data;

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

	ast_copy_string(dial_data->endpoint, endpoint, sizeof(dial_data->endpoint));

	if (timeout > 0) {
		dial_data->timeout = timeout * 1000;
	} else if (timeout == -1) {
		dial_data->timeout = -1;
	} else {
		dial_data->timeout = 30000;
	}

	stasis_app_send_command_async(control, app_control_dial, dial_data);

	return 0;
}
struct stasis_app_recording *stasis_app_control_record(
	struct stasis_app_control *control,
	struct stasis_app_recording_options *options)
{
	struct stasis_app_recording *recording;
	char *last_slash;

	errno = 0;

	if (options == NULL ||
		ast_strlen_zero(options->name) ||
		ast_strlen_zero(options->format) ||
		options->max_silence_seconds < 0 ||
		options->max_duration_seconds < 0) {
		errno = EINVAL;
		return NULL;
	}

	ast_debug(3, "%s: Sending record(%s.%s) command\n",
		stasis_app_control_get_channel_id(control), options->name,
		options->format);

	recording = ao2_alloc(sizeof(*recording), recording_dtor);
	if (!recording) {
		errno = ENOMEM;
		return NULL;
	}
	recording->duration.total = -1;
	recording->duration.energy_only = -1;

	ast_asprintf(&recording->absolute_name, "%s/%s",
		ast_config_AST_RECORDING_DIR, options->name);

	if (recording->absolute_name == NULL) {
		errno = ENOMEM;
		ao2_ref(recording, -1);
		return NULL;
	}

	if ((last_slash = strrchr(recording->absolute_name, '/'))) {
		*last_slash = '\0';
		if (ast_safe_mkdir(ast_config_AST_RECORDING_DIR,
				recording->absolute_name, 0777) != 0) {
			/* errno set by ast_mkdir */
			ao2_ref(recording, -1);
			return NULL;
		}
		*last_slash = '/';
	}

	ao2_ref(options, +1);
	recording->options = options;
	recording->control = control;
	recording->state = STASIS_APP_RECORDING_STATE_QUEUED;

	if ((recording->options->if_exists == AST_RECORD_IF_EXISTS_FAIL) &&
			(ast_fileexists(recording->absolute_name, NULL, NULL))) {
		ast_log(LOG_WARNING, "Recording file '%s' already exists and ifExists option is failure.\n",
			recording->absolute_name);
		errno = EEXIST;
		ao2_ref(recording, -1);
		return NULL;
	}

	{
		RAII_VAR(struct stasis_app_recording *, old_recording, NULL,
			ao2_cleanup);

		SCOPED_AO2LOCK(lock, recordings);

		old_recording = ao2_find(recordings, options->name,
			OBJ_KEY | OBJ_NOLOCK);
		if (old_recording) {
			ast_log(LOG_WARNING,
				"Recording %s already in progress\n",
				recording->options->name);
			errno = EEXIST;
			ao2_ref(recording, -1);
			return NULL;
		}
		ao2_link(recordings, recording);
	}

	stasis_app_control_register_add_rule(control, &rule_recording);

	stasis_app_send_command_async(control, record_file, ao2_bump(recording), recording_cleanup);

	return recording;
}
Esempio n. 16
0
struct stasis_app_recording *stasis_app_control_record(
	struct stasis_app_control *control,
	struct stasis_app_recording_options *options)
{
	RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
	char *last_slash;

	errno = 0;

	if (options == NULL ||
		ast_strlen_zero(options->name) ||
		ast_strlen_zero(options->format) ||
		options->max_silence_seconds < 0 ||
		options->max_duration_seconds < 0) {
		errno = EINVAL;
		return NULL;
	}

	ast_debug(3, "%s: Sending record(%s.%s) command\n",
		stasis_app_control_get_channel_id(control), options->name,
		options->format);

	recording = ao2_alloc(sizeof(*recording), recording_dtor);
	if (!recording) {
		errno = ENOMEM;
		return NULL;
	}

	ast_asprintf(&recording->absolute_name, "%s/%s",
		ast_config_AST_RECORDING_DIR, options->name);

	if (recording->absolute_name == NULL) {
		errno = ENOMEM;
		return NULL;
	}

	if ((last_slash = strrchr(recording->absolute_name, '/'))) {
		*last_slash = '\0';
		if (ast_safe_mkdir(ast_config_AST_RECORDING_DIR,
				recording->absolute_name, 0777) != 0) {
			/* errno set by ast_mkdir */
			return NULL;
		}
		*last_slash = '/';
	}

	ao2_ref(options, +1);
	recording->options = options;
	recording->control = control;
	recording->state = STASIS_APP_RECORDING_STATE_QUEUED;

	{
		RAII_VAR(struct stasis_app_recording *, old_recording, NULL,
			ao2_cleanup);

		SCOPED_AO2LOCK(lock, recordings);

		old_recording = ao2_find(recordings, options->name,
			OBJ_KEY | OBJ_NOLOCK);
		if (old_recording) {
			ast_log(LOG_WARNING,
				"Recording %s already in progress\n",
				recording->options->name);
			errno = EEXIST;
			return NULL;
		}
		ao2_link(recordings, recording);
	}

	/* A ref is kept in the recordings container; no need to bump */
	stasis_app_send_command_async(control, record_file, recording);

	/* Although this should be bumped for the caller */
	ao2_ref(recording, +1);
	return recording;
}
Esempio n. 17
0
void stasis_app_control_clear_roles(struct stasis_app_control *control)
{
	stasis_app_send_command_async(control, app_control_clear_roles, NULL, NULL);
}
Esempio n. 18
0
void stasis_app_control_silence_stop(struct stasis_app_control *control)
{
    stasis_app_send_command_async(control, app_control_silence_stop, NULL);
}
Esempio n. 19
0
int stasis_app_control_ring_stop(struct stasis_app_control *control)
{
    stasis_app_send_command_async(control, app_control_ring_stop, NULL);

    return 0;
}
Esempio n. 20
0
void stasis_app_control_unhold(struct stasis_app_control *control)
{
    stasis_app_send_command_async(control, app_control_unhold, NULL);
}