diff --git a/include/asterisk/pickup.h b/include/asterisk/pickup.h index fe7534e74f..d9fc2b3ba8 100644 --- a/include/asterisk/pickup.h +++ b/include/asterisk/pickup.h @@ -58,6 +58,9 @@ struct ast_channel *ast_pickup_find_by_group(struct ast_channel *chan); */ int ast_pickup_call(struct ast_channel *chan); +struct ast_channel_snapshot; +int ast_send_call_pickup_stasis_message(struct ast_channel *picking_up, struct ast_channel_snapshot *chan, struct ast_channel_snapshot *target); + /*! * \brief Pickup a call target. * diff --git a/main/pickup.c b/main/pickup.c index 1db3672a3c..5c551e9f41 100644 --- a/main/pickup.c +++ b/main/pickup.c @@ -274,7 +274,7 @@ static struct ast_manager_event_blob *call_pickup_to_ami(struct stasis_message * return res; } -static int send_call_pickup_stasis_message(struct ast_channel *picking_up, struct ast_channel_snapshot *chan, struct ast_channel_snapshot *target) +int ast_send_call_pickup_stasis_message(struct ast_channel *picking_up, struct ast_channel_snapshot *chan, struct ast_channel_snapshot *target) { RAII_VAR(struct ast_multi_channel_blob *, pickup_payload, NULL, ao2_cleanup); RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); @@ -374,7 +374,7 @@ int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target) } /* target points to the channel that did the pickup at this point, so use that channel's topic instead of chan */ - send_call_pickup_stasis_message(target, chan_snapshot, target_snapshot); + ast_send_call_pickup_stasis_message(target, chan_snapshot, target_snapshot); res = 0; diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index 8890d235b5..5e8b1268d3 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -972,6 +972,8 @@ static int refer_incoming_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *packet; int response = 0; RAII_VAR(struct ast_sip_session *, other_session, NULL, ao2_cleanup); + RAII_VAR(struct ast_channel_snapshot *, chan_snapshot, NULL, ao2_cleanup); + RAII_VAR(struct ast_channel_snapshot *, target_snapshot, NULL, ao2_cleanup); struct invite_replaces invite; /* If a Replaces header is present make sure it is valid */ @@ -1022,17 +1024,47 @@ static int refer_incoming_invite_request(struct ast_sip_session *session, struct if (!invite.bridge) { struct ast_channel *chan = session->channel; + ast_debug(3, "Setting hangupcause on '%s'\n", ast_channel_name(chan)); + + /* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */ + ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE); + + ast_debug(3, "Taking snapshot of chan '%s'\n", ast_channel_name(chan)); + ast_channel_lock(chan); + chan_snapshot = ast_channel_snapshot_create(chan); + ast_channel_unlock(chan); + if (!chan_snapshot) { + ast_debug(3, "Taking snapshot of chan '%s' failed.\n", ast_channel_name(chan)); + response = AST_CAUSE_FAILURE; + goto pickup_failed; + } + + ast_debug(3, "Taking snapshot of target '%s'\n", ast_channel_name(invite.channel)); + target_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(invite.channel)); + if (!target_snapshot) { + ast_debug(3, "Taking snapshot of target '%s' failed.\n", ast_channel_name(invite.channel)); + response = AST_CAUSE_FAILURE; + goto pickup_failed; + } + /* * This will use a synchronous task but we aren't operating in * the serializer at this point in time, so it won't deadlock. */ if (!ast_channel_move(invite.channel, chan)) { + ast_debug(3, "Move worked '%s'-> '%s'\n", ast_channel_name(invite.channel), ast_channel_name(chan)); + + ast_debug(3, "Sending stasis message to '%s'\n", ast_channel_name(invite.channel)); + /* target points to the channel that did the pickup at this point, so use that channel's topic instead of chan */ + ast_send_call_pickup_stasis_message(invite.channel, chan_snapshot, target_snapshot); + /* * We can't directly use session->channel because ast_channel_move() * does a masquerade which changes session->channel to a different * channel. To ensure we work on the right channel we store a * pointer locally before we begin so it remains valid. */ + ast_debug(3, "Haning up chan '%s'\n", ast_channel_name(chan)); ast_hangup(chan); } else { response = AST_CAUSE_FAILURE; @@ -1047,6 +1079,8 @@ static int refer_incoming_invite_request(struct ast_sip_session *session, struct ast_channel_unref(invite.channel); ao2_cleanup(invite.bridge);diff --git a/include/asterisk/pickup.h b/include/asterisk/pickup.h index fe7534e74f..d9fc2b3ba8 100644 --- a/include/asterisk/pickup.h +++ b/include/asterisk/pickup.h @@ -58,6 +58,9 @@ struct ast_channel *ast_pickup_find_by_group(struct ast_channel *chan); */ int ast_pickup_call(struct ast_channel *chan); +struct ast_channel_snapshot; +int ast_send_call_pickup_stasis_message(struct ast_channel *picking_up, struct ast_channel_snapshot *chan, struct ast_channel_snapshot *target); + /*! * \brief Pickup a call target. * diff --git a/main/pickup.c b/main/pickup.c index 1db3672a3c..5c551e9f41 100644 --- a/main/pickup.c +++ b/main/pickup.c @@ -274,7 +274,7 @@ static struct ast_manager_event_blob *call_pickup_to_ami(struct stasis_message * return res; } -static int send_call_pickup_stasis_message(struct ast_channel *picking_up, struct ast_channel_snapshot *chan, struct ast_channel_snapshot *target) +int ast_send_call_pickup_stasis_message(struct ast_channel *picking_up, struct ast_channel_snapshot *chan, struct ast_channel_snapshot *target) { RAII_VAR(struct ast_multi_channel_blob *, pickup_payload, NULL, ao2_cleanup); RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); @@ -374,7 +374,7 @@ int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target) } /* target points to the channel that did the pickup at this point, so use that channel's topic instead of chan */ - send_call_pickup_stasis_message(target, chan_snapshot, target_snapshot); + ast_send_call_pickup_stasis_message(target, chan_snapshot, target_snapshot); res = 0; diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index 8890d235b5..f439605569 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -972,6 +972,8 @@ static int refer_incoming_invite_request(struct ast_sip_session *session, struct pjsip_tx_data *packet; int response = 0; RAII_VAR(struct ast_sip_session *, other_session, NULL, ao2_cleanup); + RAII_VAR(struct ast_channel_snapshot *, chan_snapshot, NULL, ao2_cleanup); + RAII_VAR(struct ast_channel_snapshot *, target_snapshot, NULL, ao2_cleanup); struct invite_replaces invite; /* If a Replaces header is present make sure it is valid */ @@ -1022,11 +1024,31 @@ static int refer_incoming_invite_request(struct ast_sip_session *session, struct if (!invite.bridge) { struct ast_channel *chan = session->channel; + /* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */ + ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE); + + ast_channel_lock(chan); + chan_snapshot = ast_channel_snapshot_create(chan); + ast_channel_unlock(chan); + if (!chan_snapshot) { + response = AST_CAUSE_FAILURE; + goto pickup_failed; + } + + target_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(invite.channel)); + if (!target_snapshot) { + response = AST_CAUSE_FAILURE; + goto pickup_failed; + } + /* * This will use a synchronous task but we aren't operating in * the serializer at this point in time, so it won't deadlock. */ if (!ast_channel_move(invite.channel, chan)) { + /* target points to the channel that did the pickup at this point, so use that channel's topic instead of chan */ + ast_send_call_pickup_stasis_message(invite.channel, chan_snapshot, target_snapshot); + /* * We can't directly use session->channel because ast_channel_move() * does a masquerade which changes session->channel to a different @@ -1047,6 +1069,8 @@ static int refer_incoming_invite_request(struct ast_sip_session *session, struct ast_channel_unref(invite.channel); ao2_cleanup(invite.bridge); +pickup_failed: + if (!response) { /* * On success we cannot use session->channel in the debug message. +pickup_failed: + if (!response) { /* * On success we cannot use session->channel in the debug message.