Mon Aug 31 12:30:20 2015

Asterisk developer's documentation


bridge_builtin_features.c File Reference

Built in bridging features. More...

#include "asterisk.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/bridging.h"
#include "asterisk/bridging_technology.h"
#include "asterisk/frame.h"
#include "asterisk/file.h"
#include "asterisk/app.h"
#include "asterisk/astobj2.h"

Go to the source code of this file.

Functions

 AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Built in bridging features")
static int attended_abort_transfer (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 Attended transfer abort feature.
static int attended_threeway_transfer (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 Attended transfer feature to turn it into a threeway call.
static struct ast_channeldial_transfer (struct ast_channel *caller, const char *exten, const char *context)
 Helper function that creates an outgoing channel and returns it immediately.
static int feature_attended_transfer (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 Internal built in feature for attended transfers.
static int feature_blind_transfer (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 Internal built in feature for blind transfers.
static int feature_hangup (struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 Internal built in feature for hangup.
static int grab_transfer (struct ast_channel *chan, char *exten, size_t exten_len, const char *context)
 Helper function that presents dialtone and grabs extension.
static int load_module (void)
static int unload_module (void)

Detailed Description

Built in bridging features.

Author:
Joshua Colp <jcolp@digium.com>

Definition in file bridge_builtin_features.c.


Function Documentation

AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY  ,
"Built in bridging features"   
)
static int attended_abort_transfer ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
void *  hook_pvt 
) [static]

Attended transfer abort feature.

Definition at line 140 of file bridge_builtin_features.c.

References ao2_lock, ao2_unlock, ast_bridge_change_state(), AST_BRIDGE_CHANNEL_STATE_END, AST_BRIDGE_CHANNEL_STATE_HANGUP, AST_LIST_FIRST, and AST_LIST_LAST.

Referenced by feature_attended_transfer().

00141 {
00142    struct ast_bridge_channel *called_bridge_channel = NULL;
00143 
00144    /* 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 */
00145    ao2_lock(bridge);
00146 
00147    if (AST_LIST_FIRST(&bridge->channels) != bridge_channel) {
00148       called_bridge_channel = AST_LIST_FIRST(&bridge->channels);
00149    } else {
00150       called_bridge_channel = AST_LIST_LAST(&bridge->channels);
00151    }
00152 
00153    /* 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. */
00154    if (called_bridge_channel) {
00155       ast_bridge_change_state(called_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
00156    }
00157 
00158    ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
00159 
00160    ao2_unlock(bridge);
00161 
00162    return 0;
00163 }

static int attended_threeway_transfer ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
void *  hook_pvt 
) [static]

Attended transfer feature to turn it into a threeway call.

Definition at line 132 of file bridge_builtin_features.c.

References ast_bridge_change_state(), and AST_BRIDGE_CHANNEL_STATE_DEPART.

Referenced by feature_attended_transfer().

00133 {
00134    /* This is sort of abusing the depart state but in this instance it is only going to be handled in the below function so it is okay */
00135    ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_DEPART);
00136    return 0;
00137 }

static struct ast_channel* dial_transfer ( struct ast_channel caller,
const char *  exten,
const char *  context 
) [static, read]

Helper function that creates an outgoing channel and returns it immediately.

Definition at line 72 of file bridge_builtin_features.c.

References ast_call(), ast_channel_datastore_inherit(), ast_channel_inherit_variables(), ast_channel_lock_both, ast_channel_unlock, ast_connected_line_copy_from_caller(), ast_hangup(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_request(), ast_channel::caller, ast_channel::connected, and ast_channel::nativeformats.

Referenced by feature_attended_transfer(), and feature_blind_transfer().

00073 {
00074    char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
00075    struct ast_channel *chan;
00076    int cause;
00077 
00078    /* Fill the variable with the extension and context we want to call */
00079    snprintf(destination, sizeof(destination), "%s@%s", exten, context);
00080 
00081    /* Now we request that chan_local prepare to call the destination */
00082    if (!(chan = ast_request("Local", caller->nativeformats, caller, destination, &cause))) {
00083       return NULL;
00084    }
00085 
00086    /* Before we actually dial out let's inherit appropriate information. */
00087    ast_channel_lock_both(caller, chan);
00088    ast_connected_line_copy_from_caller(&chan->connected, &caller->caller);
00089    ast_channel_inherit_variables(caller, chan);
00090    ast_channel_datastore_inherit(caller, chan);
00091    ast_channel_unlock(chan);
00092    ast_channel_unlock(caller);
00093 
00094    /* Since the above worked fine now we actually call it and return the channel */
00095    if (ast_call(chan, destination, 0)) {
00096       ast_hangup(chan);
00097       return NULL;
00098    }
00099 
00100    return chan;
00101 }

static int feature_attended_transfer ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
void *  hook_pvt 
) [static]

Internal built in feature for attended transfers.

Definition at line 166 of file bridge_builtin_features.c.

References ast_bridge_features_attended_transfer::abort, AST_BRIDGE_BUILTIN_HANGUP, AST_BRIDGE_CAPABILITY_1TO1MIX, ast_bridge_change_state(), AST_BRIDGE_CHANNEL_STATE_DEPART, AST_BRIDGE_CHANNEL_STATE_HANGUP, AST_BRIDGE_CHANNEL_STATE_WAIT, ast_bridge_depart(), ast_bridge_destroy(), ast_bridge_features_cleanup(), ast_bridge_features_enable(), ast_bridge_features_hook(), ast_bridge_features_init(), ast_bridge_features_set_flag(), AST_BRIDGE_FLAG_DISSOLVE, ast_bridge_impart(), ast_bridge_join(), ast_bridge_new(), AST_DIGIT_ANY, ast_hangup(), AST_MAX_EXTENSION, ast_stream_and_wait(), ast_strlen_zero(), attended_abort_transfer(), attended_threeway_transfer(), ast_bridge_channel::chan, ast_bridge_features_attended_transfer::complete, ast_channel::context, ast_bridge_features_attended_transfer::context, context, dial_transfer(), exten, grab_transfer(), and ast_bridge_features_attended_transfer::threeway.

Referenced by load_module().

00167 {
00168    char exten[AST_MAX_EXTENSION] = "";
00169    struct ast_channel *chan = NULL;
00170    struct ast_bridge *attended_bridge = NULL;
00171    struct ast_bridge_features caller_features, called_features;
00172    enum ast_bridge_channel_state attended_bridge_result;
00173    struct ast_bridge_features_attended_transfer *attended_transfer = hook_pvt;
00174    const char *context = (attended_transfer && !ast_strlen_zero(attended_transfer->context) ? attended_transfer->context : bridge_channel->chan->context);
00175 
00176    /* Grab the extension to transfer to */
00177    if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
00178       ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
00179       ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
00180       return 0;
00181    }
00182 
00183    /* Get a channel that is the destination we wish to call */
00184    if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
00185       ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
00186       ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
00187       return 0;
00188    }
00189 
00190    /* Create a bridge to use to talk to the person we are calling */
00191    if (!(attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX, 0))) {
00192       ast_hangup(chan);
00193       ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
00194       ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
00195       return 0;
00196    }
00197 
00198    /* Setup our called features structure so that if they hang up we immediately get thrown out of the bridge */
00199    ast_bridge_features_init(&called_features);
00200    ast_bridge_features_set_flag(&called_features, AST_BRIDGE_FLAG_DISSOLVE);
00201 
00202    /* This is how this is going down, we are imparting the channel we called above into this bridge first */
00203    ast_bridge_impart(attended_bridge, chan, NULL, &called_features);
00204 
00205    /* Before we join setup a features structure with the hangup option, just in case they want to use DTMF */
00206    ast_bridge_features_init(&caller_features);
00207    ast_bridge_features_enable(&caller_features, AST_BRIDGE_BUILTIN_HANGUP,
00208                (attended_transfer && !ast_strlen_zero(attended_transfer->complete) ? attended_transfer->complete : "*1"), NULL);
00209    ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->threeway) ? attended_transfer->threeway : "*2"),
00210              attended_threeway_transfer, NULL);
00211    ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->abort) ? attended_transfer->abort : "*3"),
00212              attended_abort_transfer, NULL);
00213 
00214    /* But for the caller we want to join the bridge in a blocking fashion so we don't spin around in this function doing nothing while waiting */
00215    attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features);
00216 
00217    /* Since the above returned the caller features structure is of no more use */
00218    ast_bridge_features_cleanup(&caller_features);
00219 
00220    /* Drop the channel we are transferring to out of the above bridge since it has ended */
00221    if ((attended_bridge_result != AST_BRIDGE_CHANNEL_STATE_HANGUP) && !ast_bridge_depart(attended_bridge, chan)) {
00222       /* If the user wants to turn this into a threeway transfer then do so, otherwise they take our place */
00223       if (attended_bridge_result == AST_BRIDGE_CHANNEL_STATE_DEPART) {
00224          /* We want to impart them upon the bridge and just have us return to it as normal */
00225          ast_bridge_impart(bridge, chan, NULL, NULL);
00226       } else {
00227          ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL);
00228       }
00229    } else {
00230       ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
00231       ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
00232    }
00233 
00234    /* Now that all channels are out of it we can destroy the bridge and the called features structure */
00235    ast_bridge_features_cleanup(&called_features);
00236    ast_bridge_destroy(attended_bridge);
00237 
00238    return 0;
00239 }

static int feature_blind_transfer ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
void *  hook_pvt 
) [static]

Internal built in feature for blind transfers.

Definition at line 104 of file bridge_builtin_features.c.

References ast_bridge_change_state(), AST_BRIDGE_CHANNEL_STATE_WAIT, ast_bridge_impart(), AST_DIGIT_ANY, AST_MAX_EXTENSION, ast_stream_and_wait(), ast_strlen_zero(), ast_bridge_channel::chan, ast_channel::context, ast_bridge_features_blind_transfer::context, context, dial_transfer(), exten, and grab_transfer().

Referenced by load_module().

00105 {
00106    char exten[AST_MAX_EXTENSION] = "";
00107    struct ast_channel *chan = NULL;
00108    struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;
00109    const char *context = (blind_transfer && !ast_strlen_zero(blind_transfer->context) ? blind_transfer->context : bridge_channel->chan->context);
00110 
00111    /* Grab the extension to transfer to */
00112    if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
00113       ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
00114       ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
00115       return 0;
00116    }
00117 
00118    /* Get a channel that is the destination we wish to call */
00119    if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
00120       ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
00121       ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
00122       return 0;
00123    }
00124 
00125    /* This is sort of the fun part. We impart the above channel onto the bridge, and have it take our place. */
00126    ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL);
00127 
00128    return 0;
00129 }

static int feature_hangup ( struct ast_bridge bridge,
struct ast_bridge_channel bridge_channel,
void *  hook_pvt 
) [static]

Internal built in feature for hangup.

Definition at line 242 of file bridge_builtin_features.c.

References ast_bridge_change_state(), and AST_BRIDGE_CHANNEL_STATE_END.

Referenced by load_module().

00243 {
00244    /* This is very simple, we basically change the state on the bridge channel to end and the core takes care of the rest */
00245    ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
00246    return 0;
00247 }

static int grab_transfer ( struct ast_channel chan,
char *  exten,
size_t  exten_len,
const char *  context 
) [static]

Helper function that presents dialtone and grabs extension.

Definition at line 52 of file bridge_builtin_features.c.

References ast_app_dtget(), AST_DIGIT_ANY, ast_stopstream(), and ast_stream_and_wait().

Referenced by feature_attended_transfer(), and feature_blind_transfer().

00053 {
00054    int res;
00055 
00056    /* Play the simple "transfer" prompt out and wait */
00057    res = ast_stream_and_wait(chan, "pbx-transfer", AST_DIGIT_ANY);
00058    ast_stopstream(chan);
00059 
00060    /* If the person hit a DTMF digit while the above played back stick it into the buffer */
00061    if (res) {
00062       exten[0] = (char)res;
00063    }
00064 
00065    /* Drop to dialtone so they can enter the extension they want to transfer to */
00066    res = ast_app_dtget(chan, context, exten, exten_len, 100, 1000);
00067 
00068    return res;
00069 }

static int load_module ( void   )  [static]
static int unload_module ( void   )  [static]

Definition at line 249 of file bridge_builtin_features.c.

00250 {
00251    return 0;
00252 }


Generated on 31 Aug 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1