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 | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| 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_channel * | dial_transfer (const 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) |
Variables | |
| static struct ast_module_info __MODULE_INFO_SECTION | __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Built in bridging features" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
Built in bridging features.
Definition in file bridge_builtin_features.c.
| static void __reg_module | ( | void | ) | [static] |
Definition at line 257 of file bridge_builtin_features.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 257 of file bridge_builtin_features.c.
| 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 131 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, AST_LIST_LAST, and ast_bridge::channels.
Referenced by feature_attended_transfer().
{
struct ast_bridge_channel *called_bridge_channel = NULL;
/* 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 */
ao2_lock(bridge);
if (AST_LIST_FIRST(&bridge->channels) != bridge_channel) {
called_bridge_channel = AST_LIST_FIRST(&bridge->channels);
} else {
called_bridge_channel = AST_LIST_LAST(&bridge->channels);
}
/* 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. */
if (called_bridge_channel) {
ast_bridge_change_state(called_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
}
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
ao2_unlock(bridge);
return 0;
}
| 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 123 of file bridge_builtin_features.c.
References ast_bridge_change_state(), and AST_BRIDGE_CHANNEL_STATE_DEPART.
Referenced by feature_attended_transfer().
{
/* 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 */
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_DEPART);
return 0;
}
| static struct ast_channel* dial_transfer | ( | const 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 68 of file bridge_builtin_features.c.
References ast_call(), ast_channel_inherit_variables(), ast_hangup(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_request(), cause, chan, and ast_channel::nativeformats.
Referenced by feature_attended_transfer(), and feature_blind_transfer().
{
char destination[AST_MAX_EXTENSION+AST_MAX_CONTEXT+1] = "";
struct ast_channel *chan = NULL;
int cause;
/* Fill the variable with the extension and context we want to call */
snprintf(destination, sizeof(destination), "%s@%s", exten, context);
/* Now we request that chan_local prepare to call the destination */
if (!(chan = ast_request("Local", caller->nativeformats, destination, &cause))) {
return NULL;
}
/* Before we actually dial out let's inherit the appropriate dialplan variables */
ast_channel_inherit_variables(caller, chan);
/* Since the above worked fine now we actually call it and return the channel */
if (ast_call(chan, destination, 0)) {
ast_hangup(chan);
return NULL;
}
return chan;
}
| 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 157 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, 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().
{
char exten[AST_MAX_EXTENSION] = "";
struct ast_channel *chan = NULL;
struct ast_bridge *attended_bridge = NULL;
struct ast_bridge_features caller_features, called_features;
enum ast_bridge_channel_state attended_bridge_result;
struct ast_bridge_features_attended_transfer *attended_transfer = hook_pvt;
const char *context = (attended_transfer && !ast_strlen_zero(attended_transfer->context) ? attended_transfer->context : bridge_channel->chan->context);
/* Grab the extension to transfer to */
if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
return 0;
}
/* Get a channel that is the destination we wish to call */
if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
return 0;
}
/* Create a bridge to use to talk to the person we are calling */
if (!(attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX, 0))) {
ast_hangup(chan);
ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
return 0;
}
/* Setup our called features structure so that if they hang up we immediately get thrown out of the bridge */
ast_bridge_features_init(&called_features);
ast_bridge_features_set_flag(&called_features, AST_BRIDGE_FLAG_DISSOLVE);
/* This is how this is going down, we are imparting the channel we called above into this bridge first */
ast_bridge_impart(attended_bridge, chan, NULL, &called_features);
/* Before we join setup a features structure with the hangup option, just in case they want to use DTMF */
ast_bridge_features_init(&caller_features);
ast_bridge_features_enable(&caller_features, AST_BRIDGE_BUILTIN_HANGUP,
(attended_transfer && !ast_strlen_zero(attended_transfer->complete) ? attended_transfer->complete : "*1"), NULL);
ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->threeway) ? attended_transfer->threeway : "*2"),
attended_threeway_transfer, NULL);
ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->abort) ? attended_transfer->abort : "*3"),
attended_abort_transfer, NULL);
/* 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 */
attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features);
/* Since the above returned the caller features structure is of no more use */
ast_bridge_features_cleanup(&caller_features);
/* Drop the channel we are transferring to out of the above bridge since it has ended */
if ((attended_bridge_result != AST_BRIDGE_CHANNEL_STATE_HANGUP) && !ast_bridge_depart(attended_bridge, chan)) {
/* If the user wants to turn this into a threeway transfer then do so, otherwise they take our place */
if (attended_bridge_result == AST_BRIDGE_CHANNEL_STATE_DEPART) {
/* We want to impart them upon the bridge and just have us return to it as normal */
ast_bridge_impart(bridge, chan, NULL, NULL);
} else {
ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL);
}
} else {
ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
}
/* Now that all channels are out of it we can destroy the bridge and the called features structure */
ast_bridge_features_cleanup(&called_features);
ast_bridge_destroy(attended_bridge);
return 0;
}
| 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 95 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, chan, ast_channel::context, ast_bridge_features_blind_transfer::context, context, dial_transfer(), exten, and grab_transfer().
Referenced by load_module().
{
char exten[AST_MAX_EXTENSION] = "";
struct ast_channel *chan = NULL;
struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;
const char *context = (blind_transfer && !ast_strlen_zero(blind_transfer->context) ? blind_transfer->context : bridge_channel->chan->context);
/* Grab the extension to transfer to */
if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
return 0;
}
/* Get a channel that is the destination we wish to call */
if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
return 0;
}
/* This is sort of the fun part. We impart the above channel onto the bridge, and have it take our place. */
ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL);
return 0;
}
| 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 233 of file bridge_builtin_features.c.
References ast_bridge_change_state(), and AST_BRIDGE_CHANNEL_STATE_END.
Referenced by load_module().
{
/* This is very simple, we basically change the state on the bridge channel to end and the core takes care of the rest */
ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
return 0;
}
| 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 48 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().
{
int res;
/* Play the simple "transfer" prompt out and wait */
res = ast_stream_and_wait(chan, "pbx-transfer", AST_DIGIT_ANY);
ast_stopstream(chan);
/* If the person hit a DTMF digit while the above played back stick it into the buffer */
if (res) {
exten[0] = (char)res;
}
/* Drop to dialtone so they can enter the extension they want to transfer to */
res = ast_app_dtget(chan, context, exten, exten_len, 100, 1000);
return res;
}
| static int load_module | ( | void | ) | [static] |
Definition at line 245 of file bridge_builtin_features.c.
References AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, AST_BRIDGE_BUILTIN_BLINDTRANSFER, AST_BRIDGE_BUILTIN_HANGUP, ast_bridge_features_register(), AST_MODULE_LOAD_SUCCESS, ast_module_ref(), feature_attended_transfer(), feature_blind_transfer(), feature_hangup(), and ast_module_info::self.
{
ast_bridge_features_register(AST_BRIDGE_BUILTIN_BLINDTRANSFER, feature_blind_transfer, NULL);
ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, feature_attended_transfer, NULL);
ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL);
/* Bump up our reference count so we can't be unloaded */
ast_module_ref(ast_module_info->self);
return AST_MODULE_LOAD_SUCCESS;
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 240 of file bridge_builtin_features.c.
{
return 0;
}
struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Built in bridging features" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static] |
Definition at line 257 of file bridge_builtin_features.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 257 of file bridge_builtin_features.c.