Wed Jan 8 2020 09:49:42

Asterisk developer's documentation


bridge_builtin_features.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief Built in bridging features
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  *
25  * \ingroup bridges
26  */
27 
28 /*** MODULEINFO
29  <support_level>core</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 361403 $")
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 
42 #include "asterisk/module.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/bridging.h"
46 #include "asterisk/frame.h"
47 #include "asterisk/file.h"
48 #include "asterisk/app.h"
49 #include "asterisk/astobj2.h"
50 
51 /*! \brief Helper function that presents dialtone and grabs extension */
52 static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len, const char *context)
53 {
54  int res;
55 
56  /* Play the simple "transfer" prompt out and wait */
57  res = ast_stream_and_wait(chan, "pbx-transfer", AST_DIGIT_ANY);
58  ast_stopstream(chan);
59 
60  /* If the person hit a DTMF digit while the above played back stick it into the buffer */
61  if (res) {
62  exten[0] = (char)res;
63  }
64 
65  /* Drop to dialtone so they can enter the extension they want to transfer to */
66  res = ast_app_dtget(chan, context, exten, exten_len, 100, 1000);
67 
68  return res;
69 }
70 
71 /*! \brief Helper function that creates an outgoing channel and returns it immediately */
72 static struct ast_channel *dial_transfer(struct ast_channel *caller, const char *exten, const char *context)
73 {
74  char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
75  struct ast_channel *chan;
76  int cause;
77 
78  /* Fill the variable with the extension and context we want to call */
79  snprintf(destination, sizeof(destination), "%s@%s", exten, context);
80 
81  /* Now we request that chan_local prepare to call the destination */
82  if (!(chan = ast_request("Local", caller->nativeformats, caller, destination, &cause))) {
83  return NULL;
84  }
85 
86  /* Before we actually dial out let's inherit appropriate information. */
87  ast_channel_lock_both(caller, chan);
89  ast_channel_inherit_variables(caller, chan);
90  ast_channel_datastore_inherit(caller, chan);
91  ast_channel_unlock(chan);
92  ast_channel_unlock(caller);
93 
94  /* Since the above worked fine now we actually call it and return the channel */
95  if (ast_call(chan, destination, 0)) {
96  ast_hangup(chan);
97  return NULL;
98  }
99 
100  return chan;
101 }
102 
103 /*! \brief Internal built in feature for blind transfers */
104 static int feature_blind_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
105 {
106  char exten[AST_MAX_EXTENSION] = "";
107  struct ast_channel *chan = NULL;
108  struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;
109  const char *context = (blind_transfer && !ast_strlen_zero(blind_transfer->context) ? blind_transfer->context : bridge_channel->chan->context);
110 
111  /* Grab the extension to transfer to */
112  if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
113  ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
115  return 0;
116  }
117 
118  /* Get a channel that is the destination we wish to call */
119  if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
120  ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
122  return 0;
123  }
124 
125  /* This is sort of the fun part. We impart the above channel onto the bridge, and have it take our place. */
126  ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL);
127 
128  return 0;
129 }
130 
131 /*! \brief Attended transfer feature to turn it into a threeway call */
132 static int attended_threeway_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
133 {
134  /* 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 */
136  return 0;
137 }
138 
139 /*! \brief Attended transfer abort feature */
140 static int attended_abort_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
141 {
142  struct ast_bridge_channel *called_bridge_channel = NULL;
143 
144  /* 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 */
145  ao2_lock(bridge);
146 
147  if (AST_LIST_FIRST(&bridge->channels) != bridge_channel) {
148  called_bridge_channel = AST_LIST_FIRST(&bridge->channels);
149  } else {
150  called_bridge_channel = AST_LIST_LAST(&bridge->channels);
151  }
152 
153  /* 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. */
154  if (called_bridge_channel) {
156  }
157 
159 
160  ao2_unlock(bridge);
161 
162  return 0;
163 }
164 
165 /*! \brief Internal built in feature for attended transfers */
166 static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
167 {
168  char exten[AST_MAX_EXTENSION] = "";
169  struct ast_channel *chan = NULL;
170  struct ast_bridge *attended_bridge = NULL;
171  struct ast_bridge_features caller_features, called_features;
172  enum ast_bridge_channel_state attended_bridge_result;
173  struct ast_bridge_features_attended_transfer *attended_transfer = hook_pvt;
174  const char *context = (attended_transfer && !ast_strlen_zero(attended_transfer->context) ? attended_transfer->context : bridge_channel->chan->context);
175 
176  /* Grab the extension to transfer to */
177  if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
178  ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
180  return 0;
181  }
182 
183  /* Get a channel that is the destination we wish to call */
184  if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
185  ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
187  return 0;
188  }
189 
190  /* Create a bridge to use to talk to the person we are calling */
191  if (!(attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX, 0))) {
192  ast_hangup(chan);
193  ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
195  return 0;
196  }
197 
198  /* Setup our called features structure so that if they hang up we immediately get thrown out of the bridge */
199  ast_bridge_features_init(&called_features);
201 
202  /* This is how this is going down, we are imparting the channel we called above into this bridge first */
203  ast_bridge_impart(attended_bridge, chan, NULL, &called_features);
204 
205  /* Before we join setup a features structure with the hangup option, just in case they want to use DTMF */
206  ast_bridge_features_init(&caller_features);
208  (attended_transfer && !ast_strlen_zero(attended_transfer->complete) ? attended_transfer->complete : "*1"), NULL);
209  ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->threeway) ? attended_transfer->threeway : "*2"),
211  ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->abort) ? attended_transfer->abort : "*3"),
213 
214  /* 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 */
215  attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features);
216 
217  /* Since the above returned the caller features structure is of no more use */
218  ast_bridge_features_cleanup(&caller_features);
219 
220  /* Drop the channel we are transferring to out of the above bridge since it has ended */
221  if ((attended_bridge_result != AST_BRIDGE_CHANNEL_STATE_HANGUP) && !ast_bridge_depart(attended_bridge, chan)) {
222  /* If the user wants to turn this into a threeway transfer then do so, otherwise they take our place */
223  if (attended_bridge_result == AST_BRIDGE_CHANNEL_STATE_DEPART) {
224  /* We want to impart them upon the bridge and just have us return to it as normal */
225  ast_bridge_impart(bridge, chan, NULL, NULL);
226  } else {
227  ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL);
228  }
229  } else {
230  ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
232  }
233 
234  /* Now that all channels are out of it we can destroy the bridge and the called features structure */
235  ast_bridge_features_cleanup(&called_features);
236  ast_bridge_destroy(attended_bridge);
237 
238  return 0;
239 }
240 
241 /*! \brief Internal built in feature for hangup */
242 static int feature_hangup(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
243 {
244  /* This is very simple, we basically change the state on the bridge channel to end and the core takes care of the rest */
246  return 0;
247 }
248 
249 static int unload_module(void)
250 {
251  return 0;
252 }
253 
254 static int load_module(void)
255 {
259 
260  /* Bump up our reference count so we can't be unloaded */
262 
264 }
265 
266 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Built in bridging features");
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.
int ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2804
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
Main Channel structure associated with a channel.
Definition: channel.h:742
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
struct ast_party_connected_line connected
Channel Connected Line ID information.
Definition: channel.h:811
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout)
Present a dialtone and collect a certain length extension.
Definition: app.c:120
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
char complete[MAXIMUM_DTMF_FEATURE_STRING]
enum ast_bridge_channel_state ast_bridge_join(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features)
Join (blocking) a channel to a bridge.
Definition: bridging.c:993
#define AST_DIGIT_ANY
Definition: file.h:47
Structure that contains features information.
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
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.
struct ast_bridge * ast_bridge_new(enum ast_bridge_capability capabilities, int flags)
Create a new bridge.
Definition: bridging.c:449
int ast_bridge_features_enable(struct ast_bridge_features *features, enum ast_bridge_builtin_feature feature, const char *dtmf, void *config)
Enable a built in feature on a bridge features structure.
Definition: bridging.c:1295
int ast_bridge_depart(struct ast_bridge *bridge, struct ast_channel *chan)
Depart a channel from a bridge.
Definition: bridging.c:1077
int ast_bridge_features_init(struct ast_bridge_features *features)
Initialize bridge features structure.
Definition: bridging.c:1322
static int attended_abort_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
Attended transfer abort feature.
int ast_bridge_destroy(struct ast_bridge *bridge)
Destroy a bridge.
Definition: bridging.c:515
#define ao2_unlock(a)
Definition: astobj2.h:497
format_t nativeformats
Definition: channel.h:852
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
static int load_module(void)
struct ast_bridge * bridge
Definition: bridging.h:129
int ast_bridge_features_hook(struct ast_bridge_features *features, const char *dtmf, ast_bridge_features_hook_callback callback, void *hook_pvt)
Attach a custom hook to a bridge features structure.
Definition: bridging.c:1274
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2573
void ast_bridge_change_state(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_state new_state)
Change the state of a bridged channel.
Definition: bridging.c:122
struct ast_module * self
Definition: module.h:227
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features)
Impart (non-blocking) a channel on a bridge.
Definition: bridging.c:1043
General Asterisk PBX channel definitions.
struct ast_channel * chan
Definition: autoservice.c:57
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
Asterisk internal frame definitions.
Channel Bridging API.
#define AST_MAX_EXTENSION
Definition: channel.h:135
Channel Bridging API.
#define ao2_lock(a)
Definition: astobj2.h:488
Structure that contains information about a bridge.
Definition: bridging.h:149
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.
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
Definition: linkedlists.h:428
struct ast_bridge * bridge
Definition: channel.h:865
char threeway[MAXIMUM_DTMF_FEATURE_STRING]
#define ast_channel_unlock(chan)
Definition: channel.h:2467
#define AST_MAX_CONTEXT
Definition: channel.h:136
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
Inherits channel variable from parent to child channel.
Definition: channel.c:6241
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1370
int ast_call(struct ast_channel *chan, char *addr, int timeout)
Make a call.
Definition: channel.c:5761
Structure that contains configuration information for the attended transfer built in feature...
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2473
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 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.
struct ast_channel * chan
Definition: bridging.h:125
Structure that contains information regarding a channel in a bridge.
Definition: bridging.h:117
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition: channel.c:8443
static int feature_hangup(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
Internal built in feature for hangup.
char abort[MAXIMUM_DTMF_FEATURE_STRING]
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
ast_bridge_channel_state
State information about a bridged channel.
Definition: bridging.h:86
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
static int unload_module(void)
int ast_bridge_features_register(enum ast_bridge_builtin_feature feature, ast_bridge_features_hook_callback callback, const char *dtmf)
Register a handler for a built in feature.
Definition: bridging.c:1248
Structure that contains configuration information for the blind transfer built in feature...
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
Asterisk module definitions.
struct ast_channel * ast_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *status)
Requests a channel.
Definition: channel.c:5695
int ast_bridge_features_cleanup(struct ast_bridge_features *features)
Clean up the contents of a bridge features structure.
Definition: bridging.c:1333
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:128
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
int ast_bridge_features_set_flag(struct ast_bridge_features *features, enum ast_bridge_feature_flags flag)
Set a flag on a bridge features structure.
Definition: bridging.c:1315
struct ast_module * ast_module_ref(struct ast_module *)
Definition: loader.c:1300