예제 #1
0
파일: control.c 프로젝트: vzar/asterisk
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);
    }
}
예제 #2
0
/*!
 * \brief Set a dial timeout interval hook on the channel.
 *
 * The absolute time that the timeout should occur is stored on
 * a datastore on the channel. This time is converted into a relative
 * number of milliseconds in the future. Then an interval hook is set
 * to trigger in that number of milliseconds.
 *
 * \pre chan is locked
 *
 * \param chan The channel on which to set the interval hook
 */
static void set_interval_hook(struct ast_channel *chan)
{
	struct ast_datastore *datastore;
	struct timeval *hangup_time;
	int64_t ms;
	struct ast_bridge_channel *bridge_channel;

	datastore = ast_channel_datastore_find(chan, &timeout_datastore, NULL);
	if (!datastore) {
		return;
	}

	hangup_time = datastore->data;

	ms = ast_tvdiff_ms(*hangup_time, ast_tvnow());
	bridge_channel = ast_channel_get_bridge_channel(chan);
	if (!bridge_channel) {
		return;
	}

	if (ast_bridge_interval_hook(bridge_channel->features, 0, ms > 0 ? ms : 1,
			bridge_timeout, NULL, NULL, 0)) {
		return;
	}

	ast_queue_frame(bridge_channel->chan, &ast_null_frame);
}
예제 #3
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);
	}
}
예제 #4
0
static void parker_parked_call_message_response(struct ast_parked_call_payload *message, struct parked_subscription_data *data,
	struct stasis_subscription *sub)
{
	const char *parkee_to_act_on = data->parkee_uuid;
	char saynum_buf[16];
	struct ast_channel_snapshot *parkee_snapshot = message->parkee;
	RAII_VAR(struct ast_channel *, parker, NULL, ast_channel_cleanup);
	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);

	if (strcmp(parkee_to_act_on, parkee_snapshot->uniqueid)) {
		return;
	}

	if (message->event_type != PARKED_CALL && message->event_type != PARKED_CALL_FAILED) {
		/* We only care about these two event types */
		return;
	}

	parker = ast_channel_get_by_name(data->parker_uuid);
	if (!parker) {
		return;
	}

	ast_channel_lock(parker);
	bridge_channel = ast_channel_get_bridge_channel(parker);
	ast_channel_unlock(parker);
	if (!bridge_channel) {
		return;
	}

	/* This subscription callback will block for the duration of the announcement if
	 * parked_subscription_data is tracking a transfer_channel_data struct. */
	if (message->event_type == PARKED_CALL) {
		/* queue the saynum on the bridge channel and hangup */
		snprintf(saynum_buf, sizeof(saynum_buf), "%d %u", data->hangup_after, message->parkingspace);
		if (!data->transfer_data) {
			ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
		} else {
			ast_bridge_channel_queue_playfile_sync(bridge_channel, say_parking_space, saynum_buf, NULL);
			data->transfer_data->completed = 1;
		}
		wipe_subscription_datastore(parker);
	} else if (message->event_type == PARKED_CALL_FAILED) {
		if (!data->transfer_data) {
			ast_bridge_channel_queue_playfile(bridge_channel, NULL, "pbx-parkingfailed", NULL);
		} else {
			ast_bridge_channel_queue_playfile_sync(bridge_channel, NULL, "pbx-parkingfailed", NULL);
			data->transfer_data->completed = 1;
		}
		wipe_subscription_datastore(parker);
	}
}
예제 #5
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;
}
예제 #6
0
static void manager_park_bridged(struct mansession *s, const struct message *m,
		struct ast_channel *chan, struct ast_channel *parker_chan,
		const char *parkinglot, int timeout_override)
{
	struct ast_bridge_channel *bridge_channel;
	char *app_data;

	if (timeout_override != -1) {
		if (ast_asprintf(&app_data, "%s,t(%d)", parkinglot, timeout_override) == -1) {
			astman_send_error(s, m, "Park action failed\n");
			return;
		}
	} else {
		if (ast_asprintf(&app_data, "%s", parkinglot) == -1) {
			astman_send_error(s, m, "Park action failed\n");
			return;
		}
	}

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

	if (!bridge_channel) {
		ast_free(app_data);
		astman_send_error(s, m, "Park action failed\n");
		return;
	}

	/* Subscribe to park messages for the channel being parked */
	if (create_parked_subscription(parker_chan, ast_channel_uniqueid(chan), 1)) {
		ast_free(app_data);
		astman_send_error(s, m, "Park action failed\n");
		ao2_cleanup(bridge_channel);
		return;
	}

	ast_bridge_channel_write_park(bridge_channel, ast_channel_uniqueid(chan),
			ast_channel_uniqueid(parker_chan), app_data);

	ast_free(app_data);

	astman_send_ack(s, m, "Park successful\n");
	ao2_cleanup(bridge_channel);
}