static void native_rtp_bridge_stop(struct ast_bridge *bridge, struct ast_channel *target)
{
	struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels);
	struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels);
	enum ast_rtp_glue_result native_type;
	struct ast_rtp_glue *glue0, *glue1 = NULL;
	RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup);

	if (bc0 == bc1) {
		return;
	}

	ast_channel_lock_both(bc0->chan, bc1->chan);
	native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1);

	switch (native_type) {
	case AST_RTP_GLUE_RESULT_LOCAL:
		if (ast_rtp_instance_get_engine(instance0)->local_bridge) {
			ast_rtp_instance_get_engine(instance0)->local_bridge(instance0, NULL);
		}
		if (instance1 && ast_rtp_instance_get_engine(instance1)->local_bridge) {
			ast_rtp_instance_get_engine(instance1)->local_bridge(instance1, NULL);
		}
		ast_rtp_instance_set_bridged(instance0, NULL);
		if (instance1) {
			ast_rtp_instance_set_bridged(instance1, NULL);
		}
		break;
	case AST_RTP_GLUE_RESULT_REMOTE:
		if (target) {
			/*
			 * If a target was provided, it is being put on hold and should expect to
			 * receive media from Asterisk instead of what it was previously connected to.
			 */
			if (bc0->chan == target) {
				glue0->update_peer(bc0->chan, NULL, NULL, NULL, NULL, 0);
			} else {
				glue1->update_peer(bc1->chan, NULL, NULL, NULL, NULL, 0);
			}
		}
		break;
	case AST_RTP_GLUE_RESULT_FORBID:
		break;
	}

	if (!target && native_type != AST_RTP_GLUE_RESULT_FORBID) {
		glue0->update_peer(bc0->chan, NULL, NULL, NULL, NULL, 0);
		glue1->update_peer(bc1->chan, NULL, NULL, NULL, NULL, 0);
	}

	ast_debug(2, "Discontinued RTP bridging of '%s' and '%s' - media will flow through Asterisk core\n",
		ast_channel_name(bc0->chan), ast_channel_name(bc1->chan));

	ast_channel_unlock(bc0->chan);
	ast_channel_unlock(bc1->chan);
}
/*! \brief Write function for writing frames into the bridge */
static enum ast_bridge_write_result multiplexed_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
{
	struct ast_bridge_channel *other;

	if (AST_LIST_FIRST(&bridge->channels) == AST_LIST_LAST(&bridge->channels)) {
		return AST_BRIDGE_WRITE_FAILED;
	}

	if (!(other = (AST_LIST_FIRST(&bridge->channels) == bridge_channel ? AST_LIST_LAST(&bridge->channels) : AST_LIST_FIRST(&bridge->channels)))) {
		return AST_BRIDGE_WRITE_FAILED;
	}

	if (other->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
		ast_write(other->chan, frame);
	}

	return AST_BRIDGE_WRITE_SUCCESS;
}
Exemple #3
0
static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
{
	struct ast_channel *c0 = AST_LIST_FIRST(&bridge->channels)->chan;
	struct ast_channel *c1 = AST_LIST_LAST(&bridge->channels)->chan;

	/*
	 * If this is the first channel we can't make it compatible...
	 * unless we make it compatible with itself.  O.o
	 */
	if (c0 == c1) {
		return 0;
	}

	return ast_channel_make_compatible(c0, c1);
}
/*! \brief Join function which actually adds the channel into the array to be monitored */
static int multiplexed_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
{
	struct ast_channel *c0 = AST_LIST_FIRST(&bridge->channels)->chan, *c1 = AST_LIST_LAST(&bridge->channels)->chan;
	struct multiplexed_thread *multiplexed_thread = bridge->bridge_pvt;

	ast_debug(1, "Adding channel '%s' to multiplexed thread '%p' for monitoring\n", bridge_channel->chan->name, multiplexed_thread);

	multiplexed_add_or_remove(multiplexed_thread, bridge_channel->chan, 1);

	/* If the second channel has not yet joined do not make things compatible */
	if (c0 == c1) {
		return 0;
	}

	if (((c0->writeformat == c1->readformat) && (c0->readformat == c1->writeformat) && (c0->nativeformats == c1->nativeformats))) {
		return 0;
	}

	return ast_channel_make_compatible(c0, c1);
}
static int native_rtp_bridge_compatible(struct ast_bridge *bridge)
{
	struct ast_bridge_channel *bc0;
	struct ast_bridge_channel *bc1;
	int is_compatible;

	/* We require two channels before even considering native bridging */
	if (bridge->num_channels != 2) {
		ast_debug(1, "Bridge '%s' can not use native RTP bridge as two channels are required\n",
			bridge->uniqueid);
		return 0;
	}

	bc0 = AST_LIST_FIRST(&bridge->channels);
	bc1 = AST_LIST_LAST(&bridge->channels);

	ast_channel_lock_both(bc0->chan, bc1->chan);
	is_compatible = native_rtp_bridge_compatible_check(bridge, bc0, bc1);
	ast_channel_unlock(bc0->chan);
	ast_channel_unlock(bc1->chan);

	return is_compatible;
}
/*! \brief Attended transfer abort feature */
static int attended_abort_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
{
	struct ast_bridge_channel *called_bridge_channel = NULL;

	/* It is possible (albeit unlikely) that the bridge channels list may change, so we have to ensure we do all of our magic while locked */
	ao2_lock(bridge);

	if (AST_LIST_FIRST(&bridge->channels) != bridge_channel) {
		called_bridge_channel = AST_LIST_FIRST(&bridge->channels);
	} else {
		called_bridge_channel = AST_LIST_LAST(&bridge->channels);
	}

	/* Now we basically eject the other channel from the bridge. This will cause their thread to hang them up, and our own code to consider the transfer failed. */
	if (called_bridge_channel) {
		ast_bridge_change_state(called_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
	}

	ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);

	ao2_unlock(bridge);

	return 0;
}
/*!
 * \internal
 * \brief Start native RTP bridging of two channels
 *
 * \param bridge The bridge that had native RTP bridging happening on it
 * \param target If remote RTP bridging, the channel that is unheld.
 *
 * \note Bridge must be locked when calling this function.
 */
static void native_rtp_bridge_start(struct ast_bridge *bridge, struct ast_channel *target)
{
	struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels);
	struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels);
	enum ast_rtp_glue_result native_type = AST_RTP_GLUE_RESULT_FORBID;
	struct ast_rtp_glue *glue0, *glue1;
	RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, tinstance0, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, tinstance1, NULL, ao2_cleanup);
	RAII_VAR(struct ast_format_cap *, cap0, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
	RAII_VAR(struct ast_format_cap *, cap1, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);

	if (bc0 == bc1) {
		return;
	}

	ast_channel_lock_both(bc0->chan, bc1->chan);
	if (!bc0->suspended && !bc1->suspended) {
		native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1);
	}

	switch (native_type) {
	case AST_RTP_GLUE_RESULT_LOCAL:
		if (ast_rtp_instance_get_engine(instance0)->local_bridge) {
			ast_rtp_instance_get_engine(instance0)->local_bridge(instance0, instance1);
		}
		if (ast_rtp_instance_get_engine(instance1)->local_bridge) {
			ast_rtp_instance_get_engine(instance1)->local_bridge(instance1, instance0);
		}
		ast_rtp_instance_set_bridged(instance0, instance1);
		ast_rtp_instance_set_bridged(instance1, instance0);
		ast_verb(4, "Locally RTP bridged '%s' and '%s' in stack\n",
			ast_channel_name(bc0->chan), ast_channel_name(bc1->chan));
		break;

	case AST_RTP_GLUE_RESULT_REMOTE:
		if (glue0->get_codec) {
			glue0->get_codec(bc0->chan, cap0);
		}
		if (glue1->get_codec) {
			glue1->get_codec(bc1->chan, cap1);
		}

		/* If we have a target, it's the channel that received the UNHOLD or UPDATE_RTP_PEER frame and was told to resume */
		if (!target) {
			glue0->update_peer(bc0->chan, instance1, vinstance1, tinstance1, cap1, 0);
			glue1->update_peer(bc1->chan, instance0, vinstance0, tinstance0, cap0, 0);
			ast_verb(4, "Remotely bridged '%s' and '%s' - media will flow directly between them\n",
				ast_channel_name(bc0->chan), ast_channel_name(bc1->chan));
		} else {
			/*
			 * If a target was provided, it is the recipient of an unhold or an update and needs to have
			 * its media redirected to fit the current remote bridging needs. The other channel is either
			 * already set up to handle the new media path or will have its own set of updates independent
			 * of this pass.
			 */
			if (bc0->chan == target) {
				glue0->update_peer(bc0->chan, instance1, vinstance1, tinstance1, cap1, 0);
			} else {
				glue1->update_peer(bc1->chan, instance0, vinstance0, tinstance0, cap0, 0);
			}
		}
		break;
	case AST_RTP_GLUE_RESULT_FORBID:
		break;
	}

	ast_channel_unlock(bc0->chan);
	ast_channel_unlock(bc1->chan);
}
Exemple #8
0
static int native_rtp_bridge_compatible(struct ast_bridge *bridge)
{
	struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels);
	struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels);
	enum ast_rtp_glue_result native_type;
	struct ast_rtp_glue *glue0, *glue1;
	RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup);
	RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup);
	RAII_VAR(struct ast_format_cap *, cap0, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
	RAII_VAR(struct ast_format_cap *, cap1, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
	int read_ptime0, read_ptime1, write_ptime0, write_ptime1;

	/* We require two channels before even considering native bridging */
	if (bridge->num_channels != 2) {
		ast_debug(1, "Bridge '%s' can not use native RTP bridge as two channels are required\n",
			bridge->uniqueid);
		return 0;
	}

	if (!native_rtp_bridge_capable(bc0->chan)) {
		ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n",
			bridge->uniqueid, ast_channel_name(bc0->chan));
		return 0;
	}

	if (!native_rtp_bridge_capable(bc1->chan)) {
		ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n",
			bridge->uniqueid, ast_channel_name(bc1->chan));
		return 0;
	}

	if ((native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1))
		== AST_RTP_GLUE_RESULT_FORBID) {
		ast_debug(1, "Bridge '%s' can not use native RTP bridge as it was forbidden while getting details\n",
			bridge->uniqueid);
		return 0;
	}

	if (ao2_container_count(bc0->features->dtmf_hooks) && ast_rtp_instance_dtmf_mode_get(instance0)) {
		ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n",
			bridge->uniqueid, ast_channel_name(bc0->chan));
		return 0;
	}

	if (ao2_container_count(bc1->features->dtmf_hooks) && ast_rtp_instance_dtmf_mode_get(instance1)) {
		ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n",
			bridge->uniqueid, ast_channel_name(bc1->chan));
		return 0;
	}

	if ((native_type == AST_RTP_GLUE_RESULT_LOCAL) && ((ast_rtp_instance_get_engine(instance0)->local_bridge !=
		ast_rtp_instance_get_engine(instance1)->local_bridge) ||
		(ast_rtp_instance_get_engine(instance0)->dtmf_compatible &&
			!ast_rtp_instance_get_engine(instance0)->dtmf_compatible(bc0->chan, instance0, bc1->chan, instance1)))) {
		ast_debug(1, "Bridge '%s' can not use local native RTP bridge as local bridge or DTMF is not compatible\n",
			bridge->uniqueid);
		return 0;
	}

	/* Make sure that codecs match */
	if (glue0->get_codec) {
		glue0->get_codec(bc0->chan, cap0);
	}
	if (glue1->get_codec) {
		glue1->get_codec(bc1->chan, cap1);
	}
	if (ast_format_cap_count(cap0) != 0 && ast_format_cap_count(cap1) != 0 && !ast_format_cap_iscompatible(cap0, cap1)) {
		struct ast_str *codec_buf0 = ast_str_alloca(64);
		struct ast_str *codec_buf1 = ast_str_alloca(64);
		ast_debug(1, "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n",
			ast_format_cap_get_names(cap0, &codec_buf0), ast_format_cap_get_names(cap1, &codec_buf1));
		return 0;
	}

	read_ptime0 = ast_format_cap_get_format_framing(cap0, ast_channel_rawreadformat(bc0->chan));
	read_ptime1 = ast_format_cap_get_format_framing(cap1, ast_channel_rawreadformat(bc1->chan));
	write_ptime0 = ast_format_cap_get_format_framing(cap0, ast_channel_rawwriteformat(bc0->chan));
	write_ptime1 = ast_format_cap_get_format_framing(cap1, ast_channel_rawwriteformat(bc1->chan));

	if (read_ptime0 != write_ptime1 || read_ptime1 != write_ptime0) {
		ast_debug(1, "Packetization differs between RTP streams (%d != %d or %d != %d). Cannot native bridge in RTP\n",
				read_ptime0, write_ptime1, read_ptime1, write_ptime0);
		return 0;
	}

	return 1;
}