[asterisk-dev] Fwd: Help editing app_dial for extending L functionality

Matthew Jordan mjordan at digium.com
Sat Aug 9 10:44:37 CDT 2014


On Sat, Aug 9, 2014 at 7:42 AM, Manuel Camarg <sir.louen at gmail.com> wrote:
> I've recently introduced in the Asterisk code
> Now I would like to make some changes in the app_dial
> But I find one issue:
> Inside the argument L there is the possibility of streaming a file before
> timeout (LIMIT_TIMEOUT_FILE), but I cannot figure out in the code where this
> is being done
> Any idea about this?
> Kind regards
> Manuel

The answer to this question will vary greatly depending on your
version of Asterisk. I'm going to use trunk, because that's typically
where new features are developed.

If you are using a different version of Asterisk, your mileage will
definitely vary.

The various L options (including the file to play) are passed to
ast_bridge_timelimit, which is implemented in features.c. From
app_dial:

    if (ast_test_flag64(&opts, OPT_DURATION_LIMIT) &&
!ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
        if (ast_bridge_timelimit(chan, &config,
opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit))
            goto done;
    }

The purpose of ast_bridge_timelimit is to set up on the
ast_bridge_config pointer (config) the necessary information to play
back a warning periodically on the channel. It does the following:
 * Parses out the time limits/interval periods
 * Sets up which files to play based on the variables set on the
channel (or default values)

It does not actually play back the message itself, nor does it create
the structures that will be called to perform the playback. At this
point, we've merely configured the bridge configuration object based
on the parameters passed to app_dial so that the bridging framework
functions can understand what it is we want to do.

Eventually, app_dial will hand the calling channel (chan) and the
dialled channel (peer) to ast_bridge_call. Once upon a time, this
would go into the infamous triple loop of doom in
features.c/channel.c. In Asterisk 12+, this now leads our channels
into the bridging framework. Before that happens, however, we have to
do some work setting up the limits feature on the channel. While we've
parsed out the configuration information into a structure, we haven't
made that information usable. The end goal is to set an
ast_bridge_hook on the channel(s). A bridge hook tells the bridging
core to call a callback function when some criteria is met. In our
case, we want what is known as an interval hook - that is, call some
callback function using some particular time based information. The
act of creating this bridge hook is handled in features.c during the
pre_bridge_setup (called from ast_bridge_call_with_flags):

        bridge_config_set_limits(config, &call_duration_limits_chan,
&call_duration_limits_peer);

        if (ast_bridge_features_set_limits(chan_features,
&call_duration_limits_chan, 0)) {
            abandon_call = 1;
        }
        if (ast_bridge_features_set_limits(peer_features,
&call_duration_limits_peer, 0)) {
            abandon_call = 1;
        }

Those various function calls will result in the correct interval
ast_bridge_hook being placed on the channels. Internally, this will
call into the constructor callback function for the interval hook that
handles the L option, which is implemented in
bridge_builtin_interval_features.c. Specifically, see the
bridge_builtin_set_limits function, which calls
ast_bridge_interval_hook on the channel's bridge_channel structure.

Once the hooks are on the channel, ast_bridge_call_with_flags will
finish the process of actually putting the channels into the bridging
framework:

    /* Put peer into the bridge */
    if (ast_bridge_impart(bridge, peer, NULL, peer_features,
        AST_BRIDGE_IMPART_CHAN_INDEPENDENT |
AST_BRIDGE_IMPART_INHIBIT_JOIN_COLP)) {
        ast_bridge_destroy(bridge, 0);
        ast_bridge_features_cleanup(&chan_features);
        bridge_failed_peer_goto(chan, peer);
        return -1;
    }

    /* Join bridge */
    ast_bridge_join(bridge, chan, NULL, &chan_features, NULL,
        AST_BRIDGE_JOIN_PASS_REFERENCE | AST_BRIDGE_JOIN_INHIBIT_JOIN_COLP);

Without going into the details of the bridging framework, at this
point, you are guaranteed that your interval hook will be called
periodically by the framework.

It's important to note that the L/S options - in Asterisk 12+ - are
built on a system of frameworks. It is completely possible to
implement a different interval hook in a separate module, using the
same frameworks, that would require very few modifications to the rest
of Asterisk. While those frameworks are pretty complex (in fact, this
is probably some of the most complex code in Asterisk - bridging is
hard) - using consistent frameworks helps to improve the stability of
Asterisk tremendously. If you're interested in extending this
functionality, I'd highly recommend using Asterisk 12+.

Matt

-- 
Matthew Jordan
Digium, Inc. | Engineering Manager
445 Jan Davis Drive NW - Huntsville, AL 35806 - USA
Check us out at: http://digium.com & http://asterisk.org



More information about the asterisk-dev mailing list