Пример #1
0
static int app_control_remove_channel_from_bridge(
    struct stasis_app_control *control,
    struct ast_channel *chan, void *data)
{
    struct ast_bridge *bridge = data;

    if (!control) {
        return -1;
    }

    /* We should only depart from our own bridge */
    ast_debug(3, "%s: Departing bridge %s\n",
              stasis_app_control_get_channel_id(control),
              bridge->uniqueid);

    if (bridge != stasis_app_get_bridge(control)) {
        ast_log(LOG_WARNING, "%s: Not in bridge %s; not removing\n",
                stasis_app_control_get_channel_id(control),
                bridge->uniqueid);
        return -1;
    }

    ast_bridge_depart(chan);
    return 0;
}
Пример #2
0
void ast_ari_bridges_set_video_source(struct ast_variable *headers,
	struct ast_ari_bridges_set_video_source_args *args, struct ast_ari_response *response)
{
	struct ast_bridge *bridge;
	struct stasis_app_control *control;

	bridge = find_bridge(response, args->bridge_id);
	if (!bridge) {
		return;
	}

	control = find_channel_control(response, args->channel_id);
	if (!control) {
		ao2_ref(bridge, -1);
		return;
	}

	if (stasis_app_get_bridge(control) != bridge) {
		ast_ari_response_error(response, 422,
			"Unprocessable Entity",
			"Channel not in this bridge");
		ao2_ref(bridge, -1);
		ao2_ref(control, -1);
		return;
	}

	stasis_app_send_command(control, bridge_set_video_source_cb,
		ao2_bump(bridge), __ao2_cleanup);

	ao2_ref(bridge, -1);
	ao2_ref(control, -1);

	ast_ari_response_no_content(response);
}
Пример #3
0
static int app_control_continue(struct stasis_app_control *control,
                                struct ast_channel *chan, void *data)
{
    RAII_VAR(struct stasis_app_control_continue_data *, continue_data, data, ast_free);

    ast_assert(control->channel != NULL);

    /* If we're in a Stasis bridge, depart it before going back to the
     * dialplan */
    if (stasis_app_get_bridge(control)) {
        ast_bridge_depart(control->channel);
    }

    /* Called from stasis_app_exec thread; no lock needed */
    ast_explicit_goto(control->channel, continue_data->context, continue_data->extension, continue_data->priority);

    control->is_done = 1;

    return 0;
}
Пример #4
0
void ast_ari_bridges_remove_channel(struct ast_variable *headers,
	struct ast_ari_bridges_remove_channel_args *args,
	struct ast_ari_response *response)
{
	RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
	RAII_VAR(struct control_list *, list, NULL, ao2_cleanup);
	size_t i;

	if (!bridge) {
		/* Response filled in by find_bridge() */
		return;
	}

	list = control_list_create(response, args->channel_count, args->channel);
	if (!list) {
		/* Response filled in by control_list_create() */
		return;
	}

	/* Make sure all of the channels are in this bridge */
	for (i = 0; i < list->count; ++i) {
		if (stasis_app_get_bridge(list->controls[i]) != bridge) {
			ast_log(LOG_WARNING, "Channel %s not in bridge %s\n",
				args->channel[i], args->bridge_id);
			ast_ari_response_error(response, 422,
				"Unprocessable Entity",
				"Channel not in this bridge");
			return;
		}
	}

	/* Now actually remove it */
	for (i = 0; i < list->count; ++i) {
		stasis_app_control_remove_channel_from_bridge(list->controls[i],
			bridge);
	}

	ast_ari_response_no_content(response);
}
static int record_file(struct stasis_app_control *control,
	struct ast_channel *chan, void *data)
{
	struct stasis_app_recording *recording = data;
	char *acceptdtmf;
	int res;

	ast_assert(recording != NULL);

	if (stasis_app_get_bridge(control)) {
		ast_log(LOG_ERROR, "Cannot record channel while in bridge\n");
		recording_fail(control, recording, "Cannot record channel while in bridge");
		return -1;
	}

	switch (recording->options->terminate_on) {
	case STASIS_APP_RECORDING_TERMINATE_NONE:
	case STASIS_APP_RECORDING_TERMINATE_INVALID:
		acceptdtmf = "";
		break;
	case STASIS_APP_RECORDING_TERMINATE_ANY:
		acceptdtmf = "#*0123456789abcd";
		break;
	default:
		acceptdtmf = ast_alloca(2);
		acceptdtmf[0] = recording->options->terminate_on;
		acceptdtmf[1] = '\0';
	}

	res = ast_auto_answer(chan);
	if (res != 0) {
		ast_debug(3, "%s: Failed to answer\n",
			ast_channel_uniqueid(chan));
		recording_fail(control, recording, "Failed to answer channel");
		return -1;
	}

	recording_set_state(
		recording, STASIS_APP_RECORDING_STATE_RECORDING, NULL);
	ast_play_and_record_full(chan,
		NULL, /* playfile */
		recording->absolute_name,
		recording->options->max_duration_seconds,
		recording->options->format,
		&recording->duration.total,
		recording->options->max_silence_seconds ? &recording->duration.energy_only : NULL,
		recording->options->beep,
		-1, /* silencethreshold */
		recording->options->max_silence_seconds * 1000,
		NULL, /* path */
		acceptdtmf,
		NULL, /* canceldtmf */
		1, /* skip_confirmation_sound */
		recording->options->if_exists);

	ast_debug(3, "%s: Recording complete\n", ast_channel_uniqueid(chan));

	recording_set_state(
		recording, STASIS_APP_RECORDING_STATE_COMPLETE, NULL);

	stasis_app_control_unregister_add_rule(control, &rule_recording);

	return 0;
}
Пример #6
0
static void *record_file(struct stasis_app_control *control,
	struct ast_channel *chan, void *data)
{
	RAII_VAR(struct stasis_app_recording *, recording,
		NULL, recording_cleanup);
	char *acceptdtmf;
	int res;
	int duration = 0;

	recording = data;
	ast_assert(recording != NULL);

	if (stasis_app_get_bridge(control)) {
		ast_log(LOG_ERROR, "Cannot record channel while in bridge\n");
		recording_fail(recording);
		return NULL;
	}

	switch (recording->options->terminate_on) {
	case STASIS_APP_RECORDING_TERMINATE_NONE:
	case STASIS_APP_RECORDING_TERMINATE_INVALID:
		acceptdtmf = "";
		break;
	case STASIS_APP_RECORDING_TERMINATE_ANY:
		acceptdtmf = "#*0123456789abcd";
		break;
	default:
		acceptdtmf = ast_alloca(2);
		acceptdtmf[0] = recording->options->terminate_on;
		acceptdtmf[1] = '\0';
	}

	res = ast_auto_answer(chan);
	if (res != 0) {
		ast_debug(3, "%s: Failed to answer\n",
			ast_channel_uniqueid(chan));
		recording_fail(recording);
		return NULL;
	}

	ao2_lock(recording);
	recording->state = STASIS_APP_RECORDING_STATE_RECORDING;
	recording_publish(recording);
	ao2_unlock(recording);

	ast_play_and_record_full(chan,
		NULL, /* playfile */
		recording->absolute_name,
		recording->options->max_duration_seconds,
		recording->options->format,
		&duration,
		NULL, /* sound_duration */
		recording->options->beep,
		-1, /* silencethreshold */
		recording->options->max_silence_seconds * 1000,
		NULL, /* path */
		acceptdtmf,
		NULL, /* canceldtmf */
		1, /* skip_confirmation_sound */
		recording->options->if_exists);

	ast_debug(3, "%s: Recording complete\n", ast_channel_uniqueid(chan));

	ao2_lock(recording);
	recording->state = STASIS_APP_RECORDING_STATE_COMPLETE;
	recording_publish(recording);
	ao2_unlock(recording);

	return NULL;
}
Пример #7
0
static int app_control_add_channel_to_bridge(
    struct stasis_app_control *control,
    struct ast_channel *chan, void *data)
{
    struct ast_bridge *bridge = data;
    int res;

    if (!control || !bridge) {
        return -1;
    }

    ast_debug(3, "%s: Adding to bridge %s\n",
              stasis_app_control_get_channel_id(control),
              bridge->uniqueid);

    ast_assert(chan != NULL);

    /* Depart whatever Stasis bridge we're currently in. */
    if (stasis_app_get_bridge(control)) {
        /* Note that it looks like there's a race condition here, since
         * we don't have control locked. But this happens from the
         * control callback thread, so there won't be any other
         * concurrent attempts to bridge.
         */
        ast_bridge_depart(chan);
    }


    res = ast_bridge_set_after_callback(chan, bridge_after_cb,
                                        bridge_after_cb_failed, control);
    if (res != 0) {
        ast_log(LOG_ERROR, "Error setting after-bridge callback\n");
        return -1;
    }

    {
        /* pbx and bridge are modified by the bridging impart thread.
         * It shouldn't happen concurrently, but we still need to lock
         * for the memory fence.
         */
        SCOPED_AO2LOCK(lock, control);

        /* Save off the channel's PBX */
        ast_assert(control->pbx == NULL);
        if (!control->pbx) {
            control->pbx = ast_channel_pbx(chan);
            ast_channel_pbx_set(chan, NULL);
        }

        res = ast_bridge_impart(bridge,
                                chan,
                                NULL, /* swap channel */
                                NULL, /* features */
                                AST_BRIDGE_IMPART_CHAN_DEPARTABLE);
        if (res != 0) {
            ast_log(LOG_ERROR, "Error adding channel to bridge\n");
            ast_channel_pbx_set(chan, control->pbx);
            control->pbx = NULL;
            return -1;
        }

        ast_assert(stasis_app_get_bridge(control) == NULL);
        control->bridge = bridge;
    }
    return 0;
}
Пример #8
0
int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap)
{
	int res;

	if (!control || !bridge) {
		return -1;
	}

	ast_debug(3, "%s: Adding to bridge %s\n",
		stasis_app_control_get_channel_id(control),
		bridge->uniqueid);

	ast_assert(chan != NULL);

	/* Depart whatever Stasis bridge we're currently in. */
	if (stasis_app_get_bridge(control)) {
		/* Note that it looks like there's a race condition here, since
		 * we don't have control locked. But this happens from the
		 * control callback thread, so there won't be any other
		 * concurrent attempts to bridge.
		 */
		ast_bridge_depart(chan);
	}


	res = ast_bridge_set_after_callback(chan, bridge_after_cb,
		bridge_after_cb_failed, control);
	if (res != 0) {
		ast_log(LOG_ERROR, "Error setting after-bridge callback\n");
		return -1;
	}

	{
		/* pbx and bridge are modified by the bridging impart thread.
		 * It shouldn't happen concurrently, but we still need to lock
		 * for the memory fence.
		 */
		SCOPED_AO2LOCK(lock, control);

		/* Ensure the controlling application is subscribed early enough
		 * to receive the ChannelEnteredBridge message. This works in concert
		 * with the subscription handled in the Stasis application execution
		 * loop */
		app_subscribe_bridge(control->app, bridge);

		/* Save off the channel's PBX */
		ast_assert(control->pbx == NULL);
		if (!control->pbx) {
			control->pbx = ast_channel_pbx(chan);
			ast_channel_pbx_set(chan, NULL);
		}

		res = ast_bridge_impart(bridge,
			chan,
			swap,
			NULL, /* features */
			AST_BRIDGE_IMPART_CHAN_DEPARTABLE);
		if (res != 0) {
			ast_log(LOG_ERROR, "Error adding channel to bridge\n");
			ast_channel_pbx_set(chan, control->pbx);
			control->pbx = NULL;
			return -1;
		}

		ast_assert(stasis_app_get_bridge(control) == NULL);
		control->bridge = bridge;

		ast_channel_lock(chan);
		set_interval_hook(chan);
		ast_channel_unlock(chan);
	}
	return 0;
}
Пример #9
0
int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap)
{
	int res;
	struct ast_bridge_features *features;

	if (!control || !bridge) {
		return -1;
	}

	ast_debug(3, "%s: Adding to bridge %s\n",
		stasis_app_control_get_channel_id(control),
		bridge->uniqueid);

	ast_assert(chan != NULL);

	/* Depart whatever Stasis bridge we're currently in. */
	if (stasis_app_get_bridge(control)) {
		/* Note that it looks like there's a race condition here, since
		 * we don't have control locked. But this happens from the
		 * control callback thread, so there won't be any other
		 * concurrent attempts to bridge.
		 */
		ast_bridge_depart(chan);
	}


	res = ast_bridge_set_after_callback(chan, bridge_after_cb,
		bridge_after_cb_failed, control);
	if (res != 0) {
		ast_log(LOG_ERROR, "Error setting after-bridge callback\n");
		return -1;
	}

	ao2_lock(control);

	/* Ensure the controlling application is subscribed early enough
	 * to receive the ChannelEnteredBridge message. This works in concert
	 * with the subscription handled in the Stasis application execution
	 * loop */
	app_subscribe_bridge(control->app, bridge);

	/* Save off the channel's PBX */
	ast_assert(control->pbx == NULL);
	if (!control->pbx) {
		control->pbx = ast_channel_pbx(chan);
		ast_channel_pbx_set(chan, NULL);
	}

	/* Pull bridge features from the control */
	features = control->bridge_features;
	control->bridge_features = NULL;

	ast_assert(stasis_app_get_bridge(control) == NULL);
	/* We need to set control->bridge here since bridge_after_cb may be run
	 * before ast_bridge_impart returns.  bridge_after_cb gets a reason
	 * code so it can tell if the bridge is actually valid or not.
	 */
	control->bridge = bridge;

	/* We can't be holding the control lock while impart is running
	 * or we could create a deadlock with bridge_after_cb which also
	 * tries to lock control.
	 */
	ao2_unlock(control);
	res = ast_bridge_impart(bridge,
		chan,
		swap,
		features, /* features */
		AST_BRIDGE_IMPART_CHAN_DEPARTABLE);
	if (res != 0) {
		/* ast_bridge_impart failed before it could spawn the depart
		 * thread.  The callbacks aren't called in this case.
		 * The impart could still fail even if ast_bridge_impart returned
		 * ok but that's handled by bridge_after_cb.
		 */
		ast_log(LOG_ERROR, "Error adding channel to bridge\n");
		ao2_lock(control);
		ast_channel_pbx_set(chan, control->pbx);
		control->pbx = NULL;
		control->bridge = NULL;
		ao2_unlock(control);
	} else {
		ast_channel_lock(chan);
		set_interval_hook(chan);
		ast_channel_unlock(chan);
	}

	return res;
}