[asterisk-dev] Running channels through dialplan on attended transfer

Nikša Baldun it at voxdiversa.hr
Tue Feb 21 07:42:31 CST 2023


Hello,

information available on channels involved in attended transfer is 
inadequate for my purposes, so I have created a function which sets some 
variables on these channels, and also runs transferee and transfer 
target through dialplan. It works, but I am unsure that I did it 
correctly. Two specific questions of note:

1. Do I have to lock channels before setting variables? I've seen it 
done in many places, but if I do, I get debug messages like: "Thread LWP 
822 is blocking 'PJSIP/444-0000004b', already blocked by thread LWP 6204 
in procedure ast_waitfor_nandfds".

2. Do I have to set autoservice_chan parameter in ast_app_exec_sub? I 
don't know what autoservice is.

The function follows (I call it from two_bridge_attended_transfer and 
ast_bridge_transfer_attended functions).

/*!
  * \internal
  * \brief Set variables on channels involved in attended transfer and 
run them through dialplan.
  *
  * \param to_transferee The channel that is bridged to the transferee
  * \param to_transfer_target The channel that dialed the transfer target(s)
  * \param transferee_channels A two-channel container containing the 
transferer and transferee
  * \param to_target_bridge The bridge between to_transfer_target and 
the transfer_target (NULL if transfer_target did not answer yet)
  *
  * \retval 0 on success.
  * \retval -1 on error.
  */
static int ast_bridge_transfer_attended_to_dialplan(struct ast_channel 
*to_transferee,
         struct ast_channel *to_transfer_target,
         struct ao2_container *transferee_channels, struct ast_bridge 
*to_target_bridge)
{
     RAII_VAR(struct ao2_container *, target_channels, NULL, ao2_cleanup);
     RAII_VAR(struct ast_channel *, transferee, NULL, ao2_cleanup);
     RAII_VAR(struct ast_channel *, transfer_target, NULL, ao2_cleanup);
     const char *to_transferee_name;
     const char *to_transfer_target_name;
     const char *transferee_name;
     const char *dialed_channels;

     transferee = get_transferee(transferee_channels, to_transferee);
     if (!transferee)
         return -1;
     if (to_target_bridge) {
         target_channels = ast_bridge_peers_nolock(to_target_bridge);
         if (!target_channels)
             return -1;
         transfer_target = get_transferee(target_channels, 
to_transfer_target);
     } else {
         transfer_target = NULL;
     }

     to_transferee_name = ast_strdupa(ast_channel_name(to_transferee));
     to_transfer_target_name = 
ast_strdupa(ast_channel_name(to_transfer_target));
     transferee_name = ast_strdupa(ast_channel_name(transferee));
     dialed_channels = pbx_builtin_getvar_helper(to_transfer_target, 
"DIALEDCHANNELS");

     pbx_builtin_setvar_helper(to_transferee, ATTENDEDTRANSFERER1, 
to_transferee_name);
     pbx_builtin_setvar_helper(to_transferee, ATTENDEDTRANSFERER2, 
to_transfer_target_name);
     pbx_builtin_setvar_helper(to_transfer_target, ATTENDEDTRANSFERER1, 
to_transferee_name);
     pbx_builtin_setvar_helper(to_transfer_target, ATTENDEDTRANSFERER2, 
to_transfer_target_name);
     pbx_builtin_setvar_helper(transferee, ATTENDEDTRANSFERER1, 
to_transferee_name);
     pbx_builtin_setvar_helper(transferee, ATTENDEDTRANSFERER2, 
to_transfer_target_name);

     ast_app_exec_sub(NULL, transferee, 
"attended_transferee_connect,s,1", 0);

     if (transfer_target) {
         pbx_builtin_setvar_helper(transfer_target, ATTENDEDTRANSFEREE, 
transferee_name);
         pbx_builtin_setvar_helper(transfer_target, ATTENDEDTRANSFERER1, 
to_transferee_name);
         pbx_builtin_setvar_helper(transfer_target, ATTENDEDTRANSFERER2, 
to_transfer_target_name);
         ast_app_exec_sub(NULL, transfer_target, 
"attended_target_connect,s,1", 0);
     } else {
         if (!ast_strlen_zero(dialed_channels)) {
             char *b_channel_names = ast_strdupa(dialed_channels);
             char *b_channel_name;
             while ((b_channel_name = strtok_r(b_channel_names, " ", 
&b_channel_names))) {
                 struct ast_channel *b_channel = 
ast_channel_get_by_name(b_channel_name);
                 if (b_channel) {
                     pbx_builtin_setvar_helper(b_channel, 
ATTENDEDTRANSFEREE, transferee_name);
                     pbx_builtin_setvar_helper(b_channel, 
ATTENDEDTRANSFERER1, to_transferee_name);
                     pbx_builtin_setvar_helper(b_channel, 
ATTENDEDTRANSFERER2, to_transfer_target_name);
                     ast_app_exec_sub(NULL, b_channel, 
"attended_target_connect,s,1", 0);
                     ast_channel_unref(b_channel);
                 }
             }
         }
     }

     return 0;
}

-- 
Nikša Baldun




More information about the asterisk-dev mailing list