mirror of
https://github.com/asterisk/asterisk.git
synced 2026-07-23 07:54:50 -07:00
Add support to the bridging core for performing COLP updates when channels join a 2 party bridge.
(closes issue ASTERISK-21829) Review: https://reviewboard.asterisk.org/r/2636/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@394249 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -2034,52 +2034,6 @@ int ast_channel_early_bridge(struct ast_channel *c0, struct ast_channel *c1);
|
||||
*/
|
||||
int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone);
|
||||
|
||||
/*!
|
||||
* \brief Setup a masquerade to transfer a call.
|
||||
* \since 1.8
|
||||
*
|
||||
* \param target_chan Target of the call transfer. (Masquerade original channel)
|
||||
* \param target_id New connected line information for the target channel.
|
||||
* \param target_held TRUE if the target call is on hold.
|
||||
* \param transferee_chan Transferee of the call transfer. (Masquerade clone channel)
|
||||
* \param transferee_id New connected line information for the transferee channel.
|
||||
* \param transferee_held TRUE if the transferee call is on hold.
|
||||
*
|
||||
* \details
|
||||
* Party A - Transferee
|
||||
* Party B - Transferer
|
||||
* Party C - Target of transfer
|
||||
*
|
||||
* Party B transfers A to C.
|
||||
*
|
||||
* Party A is connected to bridged channel B1.
|
||||
* Party B is connected to channels C1 and C2.
|
||||
* Party C is connected to bridged channel B2.
|
||||
*
|
||||
* Party B -- C1 == B1 -- Party A
|
||||
* __/
|
||||
* /
|
||||
* Party B -- C2 == B2 -- Party C
|
||||
*
|
||||
* Bridged channel B1 is masqueraded into channel C2. Where B1
|
||||
* is the masquerade clone channel and C2 is the masquerade
|
||||
* original channel.
|
||||
*
|
||||
* \see ast_channel_masquerade()
|
||||
*
|
||||
* \note Has the same locking requirements as ast_channel_masquerade().
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int ast_channel_transfer_masquerade(
|
||||
struct ast_channel *target_chan,
|
||||
const struct ast_party_connected_line *target_id,
|
||||
int target_held,
|
||||
struct ast_channel *transferee_chan,
|
||||
const struct ast_party_connected_line *transferee_id,
|
||||
int transferee_held);
|
||||
|
||||
/*!
|
||||
* \brief Gives the string form of a given cause code.
|
||||
*
|
||||
@@ -4023,6 +3977,7 @@ struct ast_frame *ast_channel_dtmff(struct ast_channel *chan);
|
||||
struct ast_jb *ast_channel_jb(struct ast_channel *chan);
|
||||
struct ast_party_caller *ast_channel_caller(struct ast_channel *chan);
|
||||
struct ast_party_connected_line *ast_channel_connected(struct ast_channel *chan);
|
||||
struct ast_party_connected_line *ast_channel_connected_indicated(struct ast_channel *chan);
|
||||
struct ast_party_id ast_channel_connected_effective_id(struct ast_channel *chan);
|
||||
struct ast_party_dialed *ast_channel_dialed(struct ast_channel *chan);
|
||||
struct ast_party_redirecting *ast_channel_redirecting(struct ast_channel *chan);
|
||||
|
||||
+99
-21
@@ -606,6 +606,52 @@ static void bridge_dissolve_check_stolen(struct ast_bridge *bridge, struct ast_b
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Update connected line information after a bridge has been reconfigured.
|
||||
*
|
||||
* \param bridge The bridge itself.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void bridge_reconfigured_connected_line_update(struct ast_bridge *bridge)
|
||||
{
|
||||
struct ast_party_connected_line connected;
|
||||
struct ast_bridge_channel *bridge_channel = AST_LIST_FIRST(&bridge->channels), *peer;
|
||||
unsigned char data[1024];
|
||||
size_t datalen;
|
||||
|
||||
if (!bridge_channel ||
|
||||
!(bridge->technology->capabilities & (AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE)) ||
|
||||
!(peer = ast_bridge_channel_peer(bridge_channel)) ||
|
||||
ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_ZOMBIE) ||
|
||||
ast_test_flag(ast_channel_flags(peer->chan), AST_FLAG_ZOMBIE) ||
|
||||
ast_check_hangup_locked(bridge_channel->chan) ||
|
||||
ast_check_hangup_locked(peer->chan)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ast_party_connected_line_init(&connected);
|
||||
|
||||
ast_channel_lock(bridge_channel->chan);
|
||||
ast_connected_line_copy_from_caller(&connected, ast_channel_caller(bridge_channel->chan));
|
||||
ast_channel_unlock(bridge_channel->chan);
|
||||
|
||||
if ((datalen = ast_connected_line_build_data(data, sizeof(data), &connected, NULL)) != (size_t) -1) {
|
||||
ast_bridge_channel_queue_control_data(peer, AST_CONTROL_CONNECTED_LINE, data, datalen);
|
||||
}
|
||||
|
||||
ast_channel_lock(peer->chan);
|
||||
ast_connected_line_copy_from_caller(&connected, ast_channel_caller(peer->chan));
|
||||
ast_channel_unlock(peer->chan);
|
||||
|
||||
if ((datalen = ast_connected_line_build_data(data, sizeof(data), &connected, NULL)) != (size_t) -1) {
|
||||
ast_bridge_channel_queue_control_data(bridge_channel, AST_CONTROL_CONNECTED_LINE, data, datalen);
|
||||
}
|
||||
|
||||
ast_party_connected_line_free(&connected);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Pull the bridge channel out of its current bridge.
|
||||
@@ -1240,8 +1286,6 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
|
||||
break;
|
||||
}
|
||||
|
||||
/* BUGBUG bridge join or impart needs to do CONNECTED_LINE updates if the channels are being swapped and it is a 1-1 bridge. */
|
||||
|
||||
/* Simply write the frame out to the bridge technology. */
|
||||
/* BUGBUG The tech is where AST_CONTROL_ANSWER hook should go. (early bridge) */
|
||||
/* BUGBUG The tech is where incoming BUSY/CONGESTION hangup should happen? (early bridge) */
|
||||
@@ -2241,6 +2285,7 @@ static void set_bridge_peer_vars(struct ast_bridge *bridge)
|
||||
* \since 12.0.0
|
||||
*
|
||||
* \param bridge Reconfigured bridge.
|
||||
* \param colp_update Whether to perform COLP updates.
|
||||
*
|
||||
* \details
|
||||
* After a series of bridge_channel_push and
|
||||
@@ -2252,7 +2297,7 @@ static void set_bridge_peer_vars(struct ast_bridge *bridge)
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void bridge_reconfigured(struct ast_bridge *bridge)
|
||||
static void bridge_reconfigured(struct ast_bridge *bridge, unsigned int colp_update)
|
||||
{
|
||||
if (!bridge->reconfigured) {
|
||||
return;
|
||||
@@ -2272,6 +2317,10 @@ static void bridge_reconfigured(struct ast_bridge *bridge)
|
||||
check_bridge_play_sounds(bridge);
|
||||
set_bridge_peer_vars(bridge);
|
||||
ast_bridge_publish_state(bridge);
|
||||
|
||||
if (colp_update) {
|
||||
bridge_reconfigured_connected_line_update(bridge);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -2562,10 +2611,37 @@ static void bridge_channel_blind_transfer(struct ast_bridge_channel *bridge_chan
|
||||
static void after_bridge_move_channel(struct ast_channel *chan_bridged, void *data)
|
||||
{
|
||||
RAII_VAR(struct ast_channel *, chan_target, data, ao2_cleanup);
|
||||
struct ast_party_connected_line connected_target;
|
||||
unsigned char connected_line_data[1024];
|
||||
int payload_size;
|
||||
|
||||
ast_party_connected_line_init(&connected_target);
|
||||
|
||||
ast_channel_lock(chan_target);
|
||||
ast_party_connected_line_copy(&connected_target, ast_channel_connected(chan_target));
|
||||
ast_channel_unlock(chan_target);
|
||||
ast_party_id_reset(&connected_target.priv);
|
||||
|
||||
if (ast_channel_move(chan_target, chan_bridged)) {
|
||||
ast_softhangup(chan_target, AST_SOFTHANGUP_DEV);
|
||||
ast_party_connected_line_free(&connected_target);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((payload_size = ast_connected_line_build_data(connected_line_data,
|
||||
sizeof(connected_line_data), &connected_target, NULL)) != -1) {
|
||||
struct ast_control_read_action_payload *frame_payload;
|
||||
int frame_size;
|
||||
|
||||
frame_size = payload_size + sizeof(*frame_payload);
|
||||
frame_payload = ast_alloca(frame_size);
|
||||
frame_payload->action = AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO;
|
||||
frame_payload->payload_size = payload_size;
|
||||
memcpy(frame_payload->payload, connected_line_data, payload_size);
|
||||
ast_queue_control_data(chan_target, AST_CONTROL_READ_ACTION, frame_payload, frame_size);
|
||||
}
|
||||
|
||||
ast_party_connected_line_free(&connected_target);
|
||||
}
|
||||
|
||||
static void after_bridge_move_channel_fail(enum ast_after_bridge_cb_reason reason, void *data)
|
||||
@@ -2891,7 +2967,7 @@ static void bridge_channel_wait(struct ast_bridge_channel *bridge_channel)
|
||||
ast_channel_clear_softhangup(bridge_channel->chan, AST_SOFTHANGUP_UNBRIDGE);
|
||||
ast_bridge_channel_lock_bridge(bridge_channel);
|
||||
bridge_channel->bridge->reconfigured = 1;
|
||||
bridge_reconfigured(bridge_channel->bridge);
|
||||
bridge_reconfigured(bridge_channel->bridge, 0);
|
||||
ast_bridge_unlock(bridge_channel->bridge);
|
||||
}
|
||||
ast_bridge_channel_lock(bridge_channel);
|
||||
@@ -3008,7 +3084,7 @@ static void bridge_channel_join(struct ast_bridge_channel *bridge_channel)
|
||||
if (bridge_channel_push(bridge_channel)) {
|
||||
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
|
||||
}
|
||||
bridge_reconfigured(bridge_channel->bridge);
|
||||
bridge_reconfigured(bridge_channel->bridge, 1);
|
||||
|
||||
if (bridge_channel->state == AST_BRIDGE_CHANNEL_STATE_WAIT) {
|
||||
/*
|
||||
@@ -3032,7 +3108,7 @@ static void bridge_channel_join(struct ast_bridge_channel *bridge_channel)
|
||||
}
|
||||
|
||||
bridge_channel_pull(bridge_channel);
|
||||
bridge_reconfigured(bridge_channel->bridge);
|
||||
bridge_reconfigured(bridge_channel->bridge, 1);
|
||||
|
||||
ast_bridge_unlock(bridge_channel->bridge);
|
||||
|
||||
@@ -3692,7 +3768,7 @@ void ast_bridge_notify_masquerade(struct ast_channel *chan)
|
||||
/* BUGBUG this needs more work. The channels need to be made compatible again if the formats change. The bridge_channel thread needs to monitor for this case. */
|
||||
/* The channel we want to notify is still in a bridge. */
|
||||
bridge->v_table->notify_masquerade(bridge, bridge_channel);
|
||||
bridge_reconfigured(bridge);
|
||||
bridge_reconfigured(bridge, 1);
|
||||
}
|
||||
ast_bridge_unlock(bridge);
|
||||
ao2_ref(bridge_channel, -1);
|
||||
@@ -3990,7 +4066,8 @@ static void bridge_channel_change_bridge(struct ast_bridge_channel *bridge_chann
|
||||
* This moves the channels in src_bridge into the bridge pointed
|
||||
* to by dst_bridge.
|
||||
*/
|
||||
static void bridge_merge_do(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_bridge_channel **kick_me, unsigned int num_kick)
|
||||
static void bridge_merge_do(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_bridge_channel **kick_me, unsigned int num_kick,
|
||||
unsigned int optimized)
|
||||
{
|
||||
struct ast_bridge_channel *bridge_channel;
|
||||
unsigned int idx;
|
||||
@@ -4061,8 +4138,8 @@ static void bridge_merge_do(struct ast_bridge *dst_bridge, struct ast_bridge *sr
|
||||
}
|
||||
}
|
||||
|
||||
bridge_reconfigured(dst_bridge);
|
||||
bridge_reconfigured(src_bridge);
|
||||
bridge_reconfigured(dst_bridge, !optimized);
|
||||
bridge_reconfigured(src_bridge, !optimized);
|
||||
|
||||
ast_debug(1, "Merged bridge %s into bridge %s\n",
|
||||
src_bridge->uniqueid, dst_bridge->uniqueid);
|
||||
@@ -4230,7 +4307,7 @@ static int bridge_merge_locked(struct ast_bridge *dst_bridge, struct ast_bridge
|
||||
}
|
||||
}
|
||||
|
||||
bridge_merge_do(merge.dest, merge.src, kick_them, num_kick);
|
||||
bridge_merge_do(merge.dest, merge.src, kick_them, num_kick, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4262,7 +4339,8 @@ int ast_bridge_merge(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridg
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on failure.
|
||||
*/
|
||||
static int bridge_move_do(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bridge_channel, int attempt_recovery)
|
||||
static int bridge_move_do(struct ast_bridge *dst_bridge, struct ast_bridge_channel *bridge_channel, int attempt_recovery,
|
||||
unsigned int optimized)
|
||||
{
|
||||
struct ast_bridge *orig_bridge;
|
||||
int was_in_bridge;
|
||||
@@ -4287,7 +4365,7 @@ static int bridge_move_do(struct ast_bridge *dst_bridge, struct ast_bridge_chann
|
||||
* The channel died as a result of being pulled. Leave it
|
||||
* pointing to the original bridge.
|
||||
*/
|
||||
bridge_reconfigured(orig_bridge);
|
||||
bridge_reconfigured(orig_bridge, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -4310,8 +4388,8 @@ static int bridge_move_do(struct ast_bridge *dst_bridge, struct ast_bridge_chann
|
||||
res = -1;
|
||||
}
|
||||
|
||||
bridge_reconfigured(dst_bridge);
|
||||
bridge_reconfigured(orig_bridge);
|
||||
bridge_reconfigured(dst_bridge, !optimized);
|
||||
bridge_reconfigured(orig_bridge, !optimized);
|
||||
ao2_ref(orig_bridge, -1);
|
||||
return res;
|
||||
}
|
||||
@@ -4390,7 +4468,7 @@ static int bridge_move_locked(struct ast_bridge *dst_bridge, struct ast_bridge *
|
||||
}
|
||||
|
||||
bridge_channel->swap = swap;
|
||||
return bridge_move_do(dst_bridge, bridge_channel, attempt_recovery);
|
||||
return bridge_move_do(dst_bridge, bridge_channel, attempt_recovery, 0);
|
||||
}
|
||||
|
||||
int ast_bridge_move(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_channel *chan, struct ast_channel *swap, int attempt_recovery)
|
||||
@@ -4724,7 +4802,7 @@ static int try_swap_optimize_out(struct ast_bridge *chan_bridge,
|
||||
ast_set_flag(pvt, AST_UNREAL_OPTIMIZE_BEGUN);
|
||||
}
|
||||
other->swap = dst_bridge_channel->chan;
|
||||
if (!bridge_move_do(dst_bridge, other, 1)) {
|
||||
if (!bridge_move_do(dst_bridge, other, 1, 1)) {
|
||||
ast_bridge_change_state(src_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
|
||||
res = -1;
|
||||
if (pvt && pvt->callbacks && pvt->callbacks->optimization_finished) {
|
||||
@@ -4836,7 +4914,7 @@ static int try_merge_optimize_out(struct ast_bridge *chan_bridge,
|
||||
pvt->callbacks->optimization_started(pvt);
|
||||
ast_set_flag(pvt, AST_UNREAL_OPTIMIZE_BEGUN);
|
||||
}
|
||||
bridge_merge_do(merge.dest, merge.src, kick_me, ARRAY_LEN(kick_me));
|
||||
bridge_merge_do(merge.dest, merge.src, kick_me, ARRAY_LEN(kick_me), 1);
|
||||
if (pvt && pvt->callbacks && pvt->callbacks->optimization_finished) {
|
||||
pvt->callbacks->optimization_finished(pvt);
|
||||
}
|
||||
@@ -6481,7 +6559,7 @@ static enum ast_transfer_result bridge_swap_attended_transfer(struct ast_bridge
|
||||
&& !ast_test_flag(&bridged_to_source->features->feature_flags,
|
||||
AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE)) {
|
||||
bridged_to_source->swap = swap_channel;
|
||||
if (bridge_move_do(dest_bridge, bridged_to_source, 1)) {
|
||||
if (bridge_move_do(dest_bridge, bridged_to_source, 1, 0)) {
|
||||
return AST_BRIDGE_TRANSFER_FAIL;
|
||||
}
|
||||
/* Must kick the source channel out of its bridge. */
|
||||
@@ -6537,12 +6615,12 @@ static enum ast_transfer_result two_bridge_attended_transfer(struct ast_channel
|
||||
goto end;
|
||||
case AST_BRIDGE_OPTIMIZE_MERGE_TO_CHAN_BRIDGE:
|
||||
final_bridge = to_transferee_bridge;
|
||||
bridge_merge_do(to_transferee_bridge, to_target_bridge, kick_me, ARRAY_LEN(kick_me));
|
||||
bridge_merge_do(to_transferee_bridge, to_target_bridge, kick_me, ARRAY_LEN(kick_me), 0);
|
||||
res = AST_BRIDGE_TRANSFER_SUCCESS;
|
||||
goto end;
|
||||
case AST_BRIDGE_OPTIMIZE_MERGE_TO_PEER_BRIDGE:
|
||||
final_bridge = to_target_bridge;
|
||||
bridge_merge_do(to_target_bridge, to_transferee_bridge, kick_me, ARRAY_LEN(kick_me));
|
||||
bridge_merge_do(to_target_bridge, to_transferee_bridge, kick_me, ARRAY_LEN(kick_me), 0);
|
||||
res = AST_BRIDGE_TRANSFER_SUCCESS;
|
||||
goto end;
|
||||
case AST_BRIDGE_OPTIMIZE_PROHIBITED:
|
||||
|
||||
+24
-208
@@ -892,6 +892,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
|
||||
ast_party_dialed_init(ast_channel_dialed(tmp));
|
||||
ast_party_caller_init(ast_channel_caller(tmp));
|
||||
ast_party_connected_line_init(ast_channel_connected(tmp));
|
||||
ast_party_connected_line_init(ast_channel_connected_indicated(tmp));
|
||||
ast_party_redirecting_init(ast_channel_redirecting(tmp));
|
||||
|
||||
if (cid_name) {
|
||||
@@ -2284,6 +2285,7 @@ static void ast_channel_destructor(void *obj)
|
||||
ast_party_dialed_free(ast_channel_dialed(chan));
|
||||
ast_party_caller_free(ast_channel_caller(chan));
|
||||
ast_party_connected_line_free(ast_channel_connected(chan));
|
||||
ast_party_connected_line_free(ast_channel_connected_indicated(chan));
|
||||
ast_party_redirecting_free(ast_channel_redirecting(chan));
|
||||
|
||||
/* Close pipes if appropriate */
|
||||
@@ -2366,6 +2368,7 @@ static void ast_dummy_channel_destructor(void *obj)
|
||||
ast_party_dialed_free(ast_channel_dialed(chan));
|
||||
ast_party_caller_free(ast_channel_caller(chan));
|
||||
ast_party_connected_line_free(ast_channel_connected(chan));
|
||||
ast_party_connected_line_free(ast_channel_connected_indicated(chan));
|
||||
ast_party_redirecting_free(ast_channel_redirecting(chan));
|
||||
|
||||
/* loop over the variables list, freeing all data and deleting list items */
|
||||
@@ -2648,7 +2651,7 @@ int ast_hangup(struct ast_channel *chan)
|
||||
*
|
||||
* NOTE: We must hold the channel lock after testing for a
|
||||
* pending masquerade and setting the channel as a zombie to
|
||||
* prevent __ast_channel_masquerade() from setting up a
|
||||
* prevent ast_channel_masquerade() from setting up a
|
||||
* masquerade with a dead channel.
|
||||
*/
|
||||
while (ast_channel_masq(chan)) {
|
||||
@@ -4404,6 +4407,8 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
|
||||
case AST_CONTROL_CONNECTED_LINE:
|
||||
{
|
||||
struct ast_party_connected_line connected;
|
||||
unsigned char current[1024], proposed[1024];
|
||||
int current_size, proposed_size;
|
||||
|
||||
ast_party_connected_line_set_init(&connected, ast_channel_connected(chan));
|
||||
res = ast_connected_line_parse_data(data, datalen, &connected);
|
||||
@@ -4411,6 +4416,23 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
|
||||
ast_channel_set_connected_line(chan, &connected, NULL);
|
||||
}
|
||||
ast_party_connected_line_free(&connected);
|
||||
|
||||
current_size = ast_connected_line_build_data(current, sizeof(current),
|
||||
ast_channel_connected_indicated(chan), NULL);
|
||||
proposed_size = ast_connected_line_build_data(proposed, sizeof(proposed),
|
||||
ast_channel_connected(chan), NULL);
|
||||
|
||||
if (current_size == -1 || proposed_size == -1) {
|
||||
goto indicate_cleanup;
|
||||
}
|
||||
|
||||
if (!res && current_size == proposed_size &&
|
||||
!memcmp(current, proposed, current_size)) {
|
||||
goto indicate_cleanup;
|
||||
}
|
||||
|
||||
ast_party_connected_line_copy(ast_channel_connected_indicated(chan),
|
||||
ast_channel_connected(chan));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -6114,7 +6136,7 @@ int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *pe
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clonechan, struct ast_datastore *xfer_ds)
|
||||
int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clonechan)
|
||||
{
|
||||
int res = -1;
|
||||
|
||||
@@ -6143,9 +6165,6 @@ static int __ast_channel_masquerade(struct ast_channel *original, struct ast_cha
|
||||
if (!ast_channel_masqr(original) && !ast_channel_masq(original) && !ast_channel_masq(clonechan) && !ast_channel_masqr(clonechan)) {
|
||||
ast_channel_masq_set(original, clonechan);
|
||||
ast_channel_masqr_set(clonechan, original);
|
||||
if (xfer_ds) {
|
||||
ast_channel_datastore_add(original, xfer_ds);
|
||||
}
|
||||
ast_queue_frame(original, &ast_null_frame);
|
||||
ast_queue_frame(clonechan, &ast_null_frame);
|
||||
ast_debug(1, "Done planning to masquerade channel %s into the structure of %s\n", ast_channel_name(clonechan), ast_channel_name(original));
|
||||
@@ -6171,121 +6190,6 @@ static int __ast_channel_masquerade(struct ast_channel *original, struct ast_cha
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone)
|
||||
{
|
||||
return __ast_channel_masquerade(original, clone, NULL);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Copy the source connected line information to the destination for a transfer.
|
||||
* \since 1.8
|
||||
*
|
||||
* \param dest Destination connected line
|
||||
* \param src Source connected line
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void party_connected_line_copy_transfer(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
|
||||
{
|
||||
struct ast_party_connected_line connected;
|
||||
|
||||
connected = *((struct ast_party_connected_line *) src);
|
||||
connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
|
||||
|
||||
/* Make sure empty strings will be erased. */
|
||||
if (!connected.id.name.str) {
|
||||
connected.id.name.str = "";
|
||||
}
|
||||
if (!connected.id.number.str) {
|
||||
connected.id.number.str = "";
|
||||
}
|
||||
if (!connected.id.subaddress.str) {
|
||||
connected.id.subaddress.str = "";
|
||||
}
|
||||
if (!connected.id.tag) {
|
||||
connected.id.tag = "";
|
||||
}
|
||||
|
||||
ast_party_connected_line_copy(dest, &connected);
|
||||
}
|
||||
|
||||
/*! Transfer masquerade connected line exchange data. */
|
||||
struct xfer_masquerade_ds {
|
||||
/*! New ID for the target of the transfer (Masquerade original channel) */
|
||||
struct ast_party_connected_line target_id;
|
||||
/*! New ID for the transferee of the transfer (Masquerade clone channel) */
|
||||
struct ast_party_connected_line transferee_id;
|
||||
/*! TRUE if the target call is held. (Masquerade original channel) */
|
||||
int target_held;
|
||||
/*! TRUE if the transferee call is held. (Masquerade clone channel) */
|
||||
int transferee_held;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Destroy the transfer connected line exchange datastore information.
|
||||
* \since 1.8
|
||||
*
|
||||
* \param data The datastore payload to destroy.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void xfer_ds_destroy(void *data)
|
||||
{
|
||||
struct xfer_masquerade_ds *ds = data;
|
||||
|
||||
ast_party_connected_line_free(&ds->target_id);
|
||||
ast_party_connected_line_free(&ds->transferee_id);
|
||||
ast_free(ds);
|
||||
}
|
||||
|
||||
static const struct ast_datastore_info xfer_ds_info = {
|
||||
.type = "xfer_colp",
|
||||
.destroy = xfer_ds_destroy,
|
||||
};
|
||||
|
||||
/*
|
||||
* BUGBUG ast_channel_transfer_masquerade() can be deleted when bridging COLP has been reimplemented.
|
||||
*
|
||||
* ast_bridge_transfer_attended() will need to do something like
|
||||
* this when it has to do a masquerade into an application.
|
||||
*/
|
||||
int ast_channel_transfer_masquerade(
|
||||
struct ast_channel *target_chan,
|
||||
const struct ast_party_connected_line *target_id,
|
||||
int target_held,
|
||||
struct ast_channel *transferee_chan,
|
||||
const struct ast_party_connected_line *transferee_id,
|
||||
int transferee_held)
|
||||
{
|
||||
struct ast_datastore *xfer_ds;
|
||||
struct xfer_masquerade_ds *xfer_colp;
|
||||
int res;
|
||||
|
||||
xfer_ds = ast_datastore_alloc(&xfer_ds_info, NULL);
|
||||
if (!xfer_ds) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
xfer_colp = ast_calloc(1, sizeof(*xfer_colp));
|
||||
if (!xfer_colp) {
|
||||
ast_datastore_free(xfer_ds);
|
||||
return -1;
|
||||
}
|
||||
party_connected_line_copy_transfer(&xfer_colp->target_id, target_id);
|
||||
xfer_colp->target_held = target_held;
|
||||
party_connected_line_copy_transfer(&xfer_colp->transferee_id, transferee_id);
|
||||
xfer_colp->transferee_held = transferee_held;
|
||||
xfer_ds->data = xfer_colp;
|
||||
|
||||
res = __ast_channel_masquerade(target_chan, transferee_chan, xfer_ds);
|
||||
if (res) {
|
||||
ast_datastore_free(xfer_ds);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief this function simply changes the name of the channel and issues a manager_event
|
||||
* with out unlinking and linking the channel from the ao2_container. This should
|
||||
* only be used when the channel has already been unlinked from the ao2_container.
|
||||
@@ -6443,62 +6347,6 @@ void ast_channel_name_to_dial_string(char *channel_name)
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Transfer COLP between target and transferee channels.
|
||||
* \since 1.8
|
||||
*
|
||||
* \param transferee Transferee channel to exchange connected line information.
|
||||
* \param colp Connected line information to exchange.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void masquerade_colp_transfer(struct ast_channel *transferee, struct xfer_masquerade_ds *colp)
|
||||
{
|
||||
struct ast_control_read_action_payload *frame_payload;
|
||||
int payload_size;
|
||||
int frame_size;
|
||||
unsigned char connected_line_data[1024];
|
||||
|
||||
/* Release any hold on the target. */
|
||||
if (colp->target_held) {
|
||||
ast_queue_unhold(transferee);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since transferee may not actually be bridged to another channel,
|
||||
* there is no way for us to queue a frame so that its connected
|
||||
* line status will be updated. Instead, we use the somewhat
|
||||
* hackish approach of using a special control frame type that
|
||||
* instructs ast_read() to perform a specific action. In this
|
||||
* case, the frame we queue tells ast_read() to call the
|
||||
* connected line interception macro configured for transferee.
|
||||
*/
|
||||
|
||||
/* Reset any earlier private connected id representation */
|
||||
ast_party_id_reset(&colp->target_id.priv);
|
||||
ast_party_id_reset(&colp->transferee_id.priv);
|
||||
|
||||
payload_size = ast_connected_line_build_data(connected_line_data,
|
||||
sizeof(connected_line_data), &colp->target_id, NULL);
|
||||
if (payload_size != -1) {
|
||||
frame_size = payload_size + sizeof(*frame_payload);
|
||||
frame_payload = ast_alloca(frame_size);
|
||||
frame_payload->action = AST_FRAME_READ_ACTION_CONNECTED_LINE_MACRO;
|
||||
frame_payload->payload_size = payload_size;
|
||||
memcpy(frame_payload->payload, connected_line_data, payload_size);
|
||||
ast_queue_control_data(transferee, AST_CONTROL_READ_ACTION, frame_payload,
|
||||
frame_size);
|
||||
}
|
||||
/*
|
||||
* In addition to queueing the read action frame so that the
|
||||
* connected line info on transferee will be updated, we also are
|
||||
* going to queue a plain old connected line update on transferee to
|
||||
* update the target.
|
||||
*/
|
||||
ast_channel_queue_connected_line_update(transferee, &colp->transferee_id, NULL);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Masquerade a channel
|
||||
*
|
||||
@@ -6524,8 +6372,6 @@ void ast_do_masquerade(struct ast_channel *original)
|
||||
} exchange;
|
||||
struct ast_channel *clonechan, *chans[2];
|
||||
struct ast_channel *bridged;
|
||||
struct ast_datastore *xfer_ds;
|
||||
struct xfer_masquerade_ds *xfer_colp;
|
||||
struct ast_format rformat;
|
||||
struct ast_format wformat;
|
||||
struct ast_format tmp_format;
|
||||
@@ -6593,15 +6439,6 @@ void ast_do_masquerade(struct ast_channel *original)
|
||||
ao2_unlink(channels, original);
|
||||
ao2_unlink(channels, clonechan);
|
||||
|
||||
/* Get any transfer masquerade connected line exchange data. */
|
||||
xfer_ds = ast_channel_datastore_find(original, &xfer_ds_info, NULL);
|
||||
if (xfer_ds) {
|
||||
ast_channel_datastore_remove(original, xfer_ds);
|
||||
xfer_colp = xfer_ds->data;
|
||||
} else {
|
||||
xfer_colp = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop any visible indication on the original channel so we can
|
||||
* transfer it to the clonechan taking the original's place.
|
||||
@@ -6610,14 +6447,6 @@ void ast_do_masquerade(struct ast_channel *original)
|
||||
ast_channel_unlock(original);
|
||||
ast_indicate(original, -1);
|
||||
|
||||
/*
|
||||
* Release any hold on the transferee channel before going any
|
||||
* further with the masquerade.
|
||||
*/
|
||||
if (xfer_colp && xfer_colp->transferee_held) {
|
||||
ast_indicate(clonechan, AST_CONTROL_UNHOLD);
|
||||
}
|
||||
|
||||
/* Start the masquerade channel contents rearangement. */
|
||||
ast_channel_lock_both(original, clonechan);
|
||||
|
||||
@@ -6948,19 +6777,6 @@ void ast_do_masquerade(struct ast_channel *original)
|
||||
}
|
||||
ast_indicate(original, AST_CONTROL_SRCCHANGE);
|
||||
|
||||
if (xfer_colp) {
|
||||
/*
|
||||
* After the masquerade, the original channel pointer actually
|
||||
* points to the new transferee channel and the bridged channel
|
||||
* is still the intended transfer target party.
|
||||
*/
|
||||
masquerade_colp_transfer(original, xfer_colp);
|
||||
}
|
||||
|
||||
if (xfer_ds) {
|
||||
ast_datastore_free(xfer_ds);
|
||||
}
|
||||
|
||||
if (!clone_was_zombie) {
|
||||
ao2_link(channels, clonechan);
|
||||
}
|
||||
|
||||
@@ -134,6 +134,11 @@ struct ast_channel {
|
||||
*/
|
||||
struct ast_party_connected_line connected;
|
||||
|
||||
/*!
|
||||
* \brief Channel Connected Line ID information that was last indicated.
|
||||
*/
|
||||
struct ast_party_connected_line connected_indicated;
|
||||
|
||||
/*! \brief Redirecting/Diversion information */
|
||||
struct ast_party_redirecting redirecting;
|
||||
|
||||
@@ -972,6 +977,10 @@ struct ast_party_connected_line *ast_channel_connected(struct ast_channel *chan)
|
||||
{
|
||||
return &chan->connected;
|
||||
}
|
||||
struct ast_party_connected_line *ast_channel_connected_indicated(struct ast_channel *chan)
|
||||
{
|
||||
return &chan->connected_indicated;
|
||||
}
|
||||
struct ast_party_id ast_channel_connected_effective_id(struct ast_channel *chan)
|
||||
{
|
||||
return ast_party_id_merge(&chan->connected.id, &chan->connected.priv);
|
||||
|
||||
Reference in New Issue
Block a user