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_channel * | dial_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) |
Built in bridging features.
Definition in file bridge_builtin_features.c.
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] |
Definition at line 254 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(), and feature_hangup().
00255 { 00256 ast_bridge_features_register(AST_BRIDGE_BUILTIN_BLINDTRANSFER, feature_blind_transfer, NULL); 00257 ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, feature_attended_transfer, NULL); 00258 ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL); 00259 00260 /* Bump up our reference count so we can't be unloaded */ 00261 ast_module_ref(ast_module_info->self); 00262 00263 return AST_MODULE_LOAD_SUCCESS; 00264 }
static int unload_module | ( | void | ) | [static] |
Definition at line 249 of file bridge_builtin_features.c.