Asterisk - The Open Source Telephony Project  18.5.0
parking_bridge.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Jonathan Rose <[email protected]>
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 Parking Bridge Class
22  *
23  * \author Jonathan Rose <[email protected]>
24  */
25 
26 #include "asterisk.h"
27 #include "res_parking.h"
28 #include "asterisk/astobj2.h"
29 #include "asterisk/logger.h"
30 #include "asterisk/say.h"
31 #include "asterisk/term.h"
32 #include "asterisk/features.h"
34 
36 {
37  struct ast_bridge base;
38 
39  /* private stuff for parking */
40  struct parking_lot *lot;
41 };
42 
43 /*!
44  * \internal
45  * \brief ast_bridge parking class destructor
46  * \since 12.0.0
47  *
48  * \param self Bridge to operate upon.
49  *
50  * \note XXX Stub... and it might go unused.
51  *
52  * \return Nothing
53  */
54 static void bridge_parking_destroy(struct ast_bridge_parking *self)
55 {
56  ast_bridge_base_v_table.destroy(&self->base);
57 }
58 
60 {
61  self->lot = NULL;
63 }
64 
65 static void destroy_parked_user(void *obj)
66 {
67  struct parked_user *pu = obj;
68 
69  ao2_cleanup(pu->lot);
72 }
73 
74 /* Only call this on a parked user that hasn't had its parker_dial_string set already */
75 static int parked_user_set_parker_dial_string(struct parked_user *pu, const char *parker_channel_name)
76 {
77  char *dial_string = ast_strdupa(parker_channel_name);
78 
80  pu->parker_dial_string = ast_strdup(dial_string);
81 
82  if (!pu->parker_dial_string) {
83  return -1;
84  }
85 
86  return 0;
87 }
88 
89 /*!
90  * \internal
91  * \since 12
92  * \brief Construct a parked_user struct assigned to the specified parking lot
93  *
94  * \param lot The parking lot we are assigning the user to
95  * \param parkee The channel being parked
96  * \param parker_channel_name The name of the parker of this channel
97  * \param parker_dial_string Takes priority over parker for setting the parker dial string if included
98  * \param use_random_space if true, prioritize using a random parking space instead
99  * of ${PARKINGEXTEN} and/or automatic assignment from the parking lot
100  * \param time_limit If using a custom timeout, this should be supplied so that the
101  * parked_user struct can provide this information for manager events. If <0,
102  * use the parking lot limit instead.
103  *
104  * \retval NULL on failure
105  * \retval reference to the parked user
106  *
107  * \note ao2_cleanup this reference when you are done using it or you'll cause leaks.
108  */
109 static struct parked_user *generate_parked_user(struct parking_lot *lot, struct ast_channel *chan, const char *parker_channel_name, const char *parker_dial_string, int use_random_space, int time_limit)
110 {
111  struct parked_user *new_parked_user;
112  int preferred_space = -1; /* Initialize to use parking lot defaults */
113  int parking_space;
114  const char *parkingexten;
115 
116  if (lot->mode == PARKINGLOT_DISABLED) {
117  ast_log(LOG_NOTICE, "Tried to park in a parking lot that is no longer able to be parked to.\n");
118  return NULL;
119  }
120 
121  new_parked_user = ao2_alloc(sizeof(*new_parked_user), destroy_parked_user);
122  if (!new_parked_user) {
123  return NULL;
124  }
125 
126  if (use_random_space) {
127  preferred_space = ast_random() % (lot->cfg->parking_stop - lot->cfg->parking_start + 1);
128  preferred_space += lot->cfg->parking_start;
129  } else {
130  ast_channel_lock(chan);
131  if ((parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"))) {
132  parkingexten = ast_strdupa(parkingexten);
133  }
134  ast_channel_unlock(chan);
135 
136  if (!ast_strlen_zero(parkingexten)) {
137  if (sscanf(parkingexten, "%30d", &preferred_space) != 1 || preferred_space <= 0) {
138  ast_log(LOG_WARNING, "PARKINGEXTEN='%s' is not a valid parking space.\n", parkingexten);
139  ao2_ref(new_parked_user, -1);
140  return NULL;
141  }
142  }
143  }
144 
145  /* We need to keep the lot locked between parking_lot_get_space and actually placing it in the lot. Or until we decide not to. */
146  ao2_lock(lot);
147 
148  parking_space = parking_lot_get_space(lot, preferred_space);
149  if (parking_space == -1) {
150  ast_log(LOG_NOTICE, "Failed to get parking space in lot '%s'. All full.\n", lot->name);
151  ao2_ref(new_parked_user, -1);
152  ao2_unlock(lot);
153  return NULL;
154  }
155 
156  lot->next_space = ((parking_space + 1) - lot->cfg->parking_start) % (lot->cfg->parking_stop - lot->cfg->parking_start + 1) + lot->cfg->parking_start;
157  new_parked_user->chan = chan;
158  new_parked_user->parking_space = parking_space;
159 
160  /* Have the parked user take a reference to the parking lot. This reference should be immutable and released at destruction */
161  new_parked_user->lot = lot;
162  ao2_ref(lot, +1);
163 
164  new_parked_user->start = ast_tvnow();
165  new_parked_user->time_limit = (time_limit >= 0) ? time_limit : lot->cfg->parkingtime;
166 
167  if (parker_dial_string) {
168  new_parked_user->parker_dial_string = ast_strdup(parker_dial_string);
169  } else {
170  if (ast_strlen_zero(parker_channel_name) || parked_user_set_parker_dial_string(new_parked_user, parker_channel_name)) {
171  ao2_ref(new_parked_user, -1);
172  ao2_unlock(lot);
173  return NULL;
174  }
175  }
176 
177  if (!new_parked_user->parker_dial_string) {
178  ao2_ref(new_parked_user, -1);
179  ao2_unlock(lot);
180  return NULL;
181  }
182 
183  /* Insert into the parking lot's parked user list. We can unlock the lot now. */
184  ao2_link(lot->parked_users, new_parked_user);
185  ao2_unlock(lot);
186 
187  return new_parked_user;
188 }
189 
190 /* TODO CEL events for parking */
191 
192 /*!
193  * \internal
194  * \brief ast_bridge parking push method.
195  * \since 12.0.0
196  *
197  * \param self Bridge to operate upon
198  * \param bridge_channel Bridge channel to push
199  * \param swap Bridge channel to swap places with if not NULL
200  *
201  * \note On entry, self is already locked
202  *
203  * \retval 0 on success
204  * \retval -1 on failure
205  */
206 static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
207 {
208  struct parked_user *pu;
209  const char *blind_transfer;
210  struct ast_channel_snapshot *parker = NULL;
211  const char *parker_channel_name = NULL;
213 
214  ast_bridge_base_v_table.push(&self->base, bridge_channel, swap);
215 
216  ast_assert(self->lot != NULL);
217 
218  /* Answer the channel if needed */
219  if (ast_channel_state(bridge_channel->chan) != AST_STATE_UP) {
220  ast_answer(bridge_channel->chan);
221  }
222 
223  if (swap) {
224  int use_ringing = 0;
225 
227  pu = swap->bridge_pvt;
228  if (!pu) {
229  /* This should be impossible since the only way a channel can enter in the first place
230  * is if it has a parked user associated with it */
231  publish_parked_call_failure(bridge_channel->chan);
233  return -1;
234  }
235 
236  /* Give the swap channel's parked user reference to the incoming channel */
237  pu->chan = bridge_channel->chan;
238  bridge_channel->bridge_pvt = pu;
239  swap->bridge_pvt = NULL;
240 
241  if (ast_bridge_channel_has_role(swap, "holding_participant")) {
242  const char *idle_mode = ast_bridge_channel_get_role_option(swap, "holding_participant", "idle_mode");
243 
244  if (!ast_strlen_zero(idle_mode) && !strcmp(idle_mode, "ringing")) {
245  use_ringing = 1;
246  }
247  }
248 
250 
251  parking_set_duration(bridge_channel->features, pu);
252 
253  if (parking_channel_set_roles(bridge_channel->chan, self->lot, use_ringing)) {
254  ast_log(LOG_WARNING, "Failed to apply holding bridge roles to %s while joining the parking lot.\n",
255  ast_channel_name(bridge_channel->chan));
256  }
257 
259 
260  return 0;
261  }
262 
263  if (!(park_datastore = get_park_common_datastore_copy(bridge_channel->chan))) {
264  /* There was either a failure to apply the datastore when performing park common setup or else we had alloc failures while cloning. Abort. */
265  return -1;
266  }
267  parker = ast_channel_snapshot_get_latest(park_datastore->parker_uuid);
268 
269  /* If the parker and the parkee are the same channel pointer, then the channel entered using
270  * the park application. It's possible that the channel that transferred it is still alive (particularly
271  * when a multichannel bridge is parked), so try to get the real parker if possible. */
272  ast_channel_lock(bridge_channel->chan);
273  blind_transfer = pbx_builtin_getvar_helper(bridge_channel->chan, "BLINDTRANSFER");
274  blind_transfer = ast_strdupa(S_OR(blind_transfer, ""));
275  ast_channel_unlock(bridge_channel->chan);
276  if (!parker || !strcmp(parker->base->name, ast_channel_name(bridge_channel->chan))) {
277  if (ast_strlen_zero(blind_transfer) && parker) {
278  /* If no BLINDTRANSFER exists but the parker does then use their channel name */
279  parker_channel_name = parker->base->name;
280  } else {
281  /* Even if there is no BLINDTRANSFER dialplan variable then blind_transfer will
282  * be an empty string.
283  */
284  parker_channel_name = blind_transfer;
285  }
286  } else {
287  parker_channel_name = parker->base->name;
288  }
289 
290  pu = generate_parked_user(self->lot, bridge_channel->chan, parker_channel_name,
291  park_datastore->parker_dial_string, park_datastore->randomize, park_datastore->time_limit);
292  ao2_cleanup(parker);
293  if (!pu) {
294  publish_parked_call_failure(bridge_channel->chan);
295  return -1;
296  }
297 
298  /* If a comeback_override was provided, set it for the parked user's comeback string. */
299  if (park_datastore->comeback_override) {
300  ast_copy_string(pu->comeback, park_datastore->comeback_override, sizeof(pu->comeback));
301  }
302 
303  /* Generate ParkedCall Stasis Message */
305 
306  /* If not a blind transfer and silence_announce isn't set, play the announcement to the parkee */
307  if (ast_strlen_zero(blind_transfer) && !park_datastore->silence_announce) {
308  char saynum_buf[16];
309 
310  snprintf(saynum_buf, sizeof(saynum_buf), "%d %d", 0, pu->parking_space);
311  ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
312  }
313 
314  /* Apply parking duration limits */
315  parking_set_duration(bridge_channel->features, pu);
316 
317  /* Set this to the bridge pvt so that we don't have to refind the parked user associated with this bridge channel again. */
318  bridge_channel->bridge_pvt = pu;
319 
320  ast_verb(3, "Parking '" COLORIZE_FMT "' in '" COLORIZE_FMT "' at space %d\n",
321  COLORIZE(COLOR_BRMAGENTA, 0, ast_channel_name(bridge_channel->chan)),
322  COLORIZE(COLOR_BRMAGENTA, 0, self->lot->name),
323  pu->parking_space);
324 
325  parking_notify_metermaids(pu->parking_space, self->lot->cfg->parking_con, AST_DEVICE_INUSE);
326 
327  return 0;
328 }
329 
330 /*!
331  * \internal
332  * \brief ast_bridge parking pull method.
333  * \since 12.0.0
334  *
335  * \param self Bridge to operate upon.
336  * \param bridge_channel Bridge channel to pull.
337  *
338  * \note On entry, self is already locked.
339  *
340  * \return Nothing
341  */
342 static void bridge_parking_pull(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
343 {
344  RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup);
345 
346  ast_bridge_base_v_table.pull(&self->base, bridge_channel);
347 
348  /* Take over the bridge channel's pu reference. It will be released when we are done. */
349  pu = bridge_channel->bridge_pvt;
350  bridge_channel->bridge_pvt = NULL;
351 
352  /* This should only happen if the exiting channel was swapped out */
353  if (!pu) {
354  return;
355  }
356 
357  /* If we got here without the resolution being set, that's because the call was hung up for some reason without
358  * timing out or being picked up. There may be some forcible park removals later, but the resolution should be
359  * handled in those cases */
360  ao2_lock(pu);
361  if (pu->resolution == PARK_UNSET) {
362  pu->resolution = PARK_ABANDON;
363  }
364  ao2_unlock(pu);
365 
366  /* Pull can still happen after the bridge starts dissolving, so make sure we still have a lot before trying to notify metermaids. */
367  if (self->lot) {
368  parking_notify_metermaids(pu->parking_space, self->lot->cfg->parking_con, AST_DEVICE_NOT_INUSE);
369  }
370 
371  switch (pu->resolution) {
372  case PARK_UNSET:
373  /* This should be impossible now since the resolution is forcibly set to abandon if it was unset at this point. Resolution
374  isn't allowed to be changed when it isn't currently PARK_UNSET. */
375  break;
376  case PARK_ABANDON:
377  /* Since the call was abandoned without additional handling, we need to issue the give up event and unpark the user. */
379  unpark_parked_user(pu);
380  break;
381  case PARK_FORCED:
382  /* PARK_FORCED is currently unused, but it is expected that it would be handled similar to PARK_ANSWERED.
383  * There is currently no event related to forced parked calls either */
384  break;
385  case PARK_ANSWERED:
386  /* If answered or forced, the channel should be pulled from the bridge as part of that process and unlinked from
387  * the parking lot afterwards. We do need to apply bridge features though and play the courtesy tone if set. */
390 
391  if (pu->lot->cfg->parkedplay & AST_FEATURE_FLAG_BYCALLEE) {
392  ast_bridge_channel_queue_playfile(bridge_channel, NULL, pu->lot->cfg->courtesytone, NULL);
393  }
394  break;
395  case PARK_TIMEOUT:
396  /* Timeout is similar to abandon because it simply sets the bridge state to end and doesn't
397  * actually pull the channel. Because of that, unpark should happen in here. */
400  unpark_parked_user(pu);
401  break;
402  }
403 }
404 
405 /*!
406  * \internal
407  * \brief ast_bridge parking notify_masquerade method.
408  * \since 12.0.0
409  *
410  * \param self Bridge to operate upon.
411  * \param bridge_channel Bridge channel that was masqueraded.
412  *
413  * \note On entry, self is already locked.
414  * \note XXX Stub... and it will probably go unused.
415  *
416  * \return Nothing
417  */
418 static void bridge_parking_notify_masquerade(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
419 {
420  ast_bridge_base_v_table.notify_masquerade(&self->base, bridge_channel);
421 }
422 
424 {
426 }
427 
429  .name = "parking",
436 };
437 
438 static struct ast_bridge *ast_bridge_parking_init(struct ast_bridge_parking *self, struct parking_lot *bridge_lot)
439 {
440  if (!self) {
441  return NULL;
442  }
443 
444  /* If no lot is defined for the bridge, then we aren't allowing the bridge to be initialized. */
445  if (!bridge_lot) {
446  ao2_ref(self, -1);
447  return NULL;
448  }
449 
450  /* It doesn't need to be a reference since the bridge only lives as long as the parking lot lives. */
451  self->lot = bridge_lot;
452 
453  return &self->base;
454 }
455 
456 struct ast_bridge *bridge_parking_new(struct parking_lot *bridge_lot)
457 {
458  void *bridge;
459 
460  bridge = bridge_alloc(sizeof(struct ast_bridge_parking), &ast_bridge_parking_v_table);
463  | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM, "Parking", bridge_lot->name, NULL);
464  bridge = ast_bridge_parking_init(bridge, bridge_lot);
465  bridge = bridge_register(bridge);
466  return bridge;
467 }
static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
int ast_bridge_channel_has_role(struct ast_bridge_channel *bridge_channel, const char *role_name)
Check to see if a bridge channel inherited a specific role from its channel.
Definition: bridge_roles.c:418
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
struct ast_channel_snapshot_base * base
int unpark_parked_user(struct parked_user *pu)
Pull a parked user out of its parking lot. Use this when you don&#39;t want to use the parked user afterw...
Asterisk main include file. File version handling, generic pbx functions.
struct ast_bridge_features * features
void park_common_datastore_free(struct park_common_datastore *datastore)
Free a park common datastore struct.
struct ast_bridge * bridge_register(struct ast_bridge *bridge)
Register the new bridge with the system.
Definition: bridge.c:709
void parking_notify_metermaids(int exten, const char *context, enum ast_device_state state)
Notify metermaids that we&#39;ve changed an extension.
int(* ast_bridge_push_channel_fn)(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
Push this channel into the bridge.
Definition: bridge.h:213
int parking_lot_get_space(struct parking_lot *lot, int target_override)
Get an available parking space within a parking lot.
const char * name
Definition: bridge.h:267
void(* ast_bridge_dissolving_fn)(struct ast_bridge *self)
The bridge is being dissolved.
Definition: bridge.h:193
#define LOG_WARNING
Definition: logger.h:274
struct ao2_container * parked_users
Definition: res_parking.h:95
unsigned int parkingtime
Definition: res_parking.h:69
struct ast_bridge base
Structure representing a snapshot of channel state.
unsigned int time_limit
Definition: res_parking.h:110
struct parking_lot * lot
void parked_call_retrieve_enable_features(struct ast_channel *chan, struct parking_lot *lot, int recipient_mode)
Apply features based on the parking lot feature options.
if(!yyg->yy_init)
Definition: ast_expr2f.c:868
ast_channel_state
ast_channel states
Definition: channelstate.h:35
ast_bridge_dissolving_fn dissolving
Definition: bridge.h:271
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define ast_assert(a)
Definition: utils.h:695
void parking_set_duration(struct ast_bridge_features *features, struct parked_user *user)
Setup timeout interval feature on an ast_bridge_features for parking.
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
struct parking_lot * lot
Definition: res_parking.h:111
struct timeval start
Definition: res_parking.h:106
#define ast_verb(level,...)
Definition: logger.h:463
void publish_parked_call(struct parked_user *pu, enum ast_parked_call_event_type event_type)
Publish a stasis parked call message for a given parked user.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define COLORIZE(fg, bg, str)
Definition: term.h:68
#define ast_strlen_zero(foo)
Definition: strings.h:52
void publish_parked_call_failure(struct ast_channel *parkee)
Publish a stasis parked call message for the channel indicating failure to park.
struct ast_bridge_methods ast_bridge_base_v_table
Bridge base class virtual method table.
Definition: bridge.c:949
int(* ast_bridge_merge_priority_fn)(struct ast_bridge *self)
Get the merge priority of this bridge.
Definition: bridge.h:257
int next_space
Definition: res_parking.h:93
#define ast_log
Definition: astobj2.c:42
int parking_channel_set_roles(struct ast_channel *chan, struct parking_lot *lot, int force_ringing)
Set necessary bridge roles on a channel that is about to enter a parking lot.
#define ast_bridge_channel_lock(bridge_channel)
Lock the bridge_channel.
static struct ast_bridge * ast_bridge_parking_init(struct ast_bridge_parking *self, struct parking_lot *bridge_lot)
ast_bridge_notify_masquerade_fn notify_masquerade
Definition: bridge.h:277
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
char * parker_dial_string
Definition: res_parking.h:109
int parking_space
Definition: res_parking.h:107
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define COLORIZE_FMT
Shortcut macros for coloring a set of text.
Definition: term.h:67
long int ast_random(void)
Definition: main/utils.c:2064
#define ao2_lock(a)
Definition: astobj2.h:718
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
struct ast_bridge * bridge_alloc(size_t size, const struct ast_bridge_methods *v_table)
Definition: bridge.c:724
struct ast_bridge * bridge_base_init(struct ast_bridge *self, uint32_t capabilities, unsigned int flags, const char *creator, const char *name, const char *id)
Initialize the base class of the bridge.
Definition: bridge.c:760
void(* ast_bridge_pull_channel_fn)(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
Pull this channel from the bridge.
Definition: bridge.h:230
#define COLOR_BRMAGENTA
Definition: term.h:58
#define ast_bridge_channel_unlock(bridge_channel)
Unlock the bridge_channel.
Structure that contains information about a bridge.
Definition: bridge.h:357
static int parked_user_set_parker_dial_string(struct parked_user *pu, const char *parker_channel_name)
void ast_channel_name_to_dial_string(char *channel_name)
Removes the trailing identifiers from a channel name string.
Definition: channel.c:6934
char comeback[80]
Definition: res_parking.h:108
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *payload)
custom callback function for ast_bridge_channel_queue_playfile which plays a parking space and option...
struct ast_bridge * bridge_parking_new(struct parking_lot *bridge_lot)
Create a new parking bridge.
#define LOG_NOTICE
Definition: logger.h:263
static void bridge_parking_pull(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
Bridge virtual methods table definition.
Definition: bridge.h:265
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define ast_free(a)
Definition: astmm.h:182
ast_bridge_merge_priority_fn get_merge_priority
Definition: bridge.h:279
void(* ast_bridge_destructor_fn)(struct ast_bridge *self)
Destroy the bridge.
Definition: bridge.h:178
const ast_string_field name
Definition: res_parking.h:100
Support for logging to various files, console and syslog Configuration in file logger.conf.
static void bridge_parking_get_merge_priority(struct ast_bridge_parking *self)
struct ast_channel * chan
Structure that contains information regarding a channel in a bridge.
void * bridge_pvt
Bridge class private channel data.
struct park_common_datastore * get_park_common_datastore_copy(struct ast_channel *parkee)
Get a copy of the park_common_datastore from a channel that is being parked.
enum parking_lot_modes mode
Definition: res_parking.h:97
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object...
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
int ast_bridge_channel_queue_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
Queue a bridge action play file frame onto the bridge channel.
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2814
static void destroy_parked_user(void *obj)
static void bridge_parking_destroy(struct ast_bridge_parking *self)
Handy terminal functions for vt* terms.
ast_bridge_pull_channel_fn pull
Definition: bridge.h:275
ast_bridge_destructor_fn destroy
Definition: bridge.h:269
ast_bridge_push_channel_fn push
Definition: bridge.h:273
Call Parking Resource Internal API.
Private Bridging API.
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
static void bridge_parking_dissolving(struct ast_bridge_parking *self)
Say numbers and dates (maybe words one day too)
struct ast_channel_snapshot * retriever
Definition: res_parking.h:105
const char * ast_bridge_channel_get_role_option(struct ast_bridge_channel *bridge_channel, const char *role_name, const char *option)
Retrieve the value of a requested role option from a bridge channel.
Definition: bridge_roles.c:427
struct ast_channel * chan
Definition: res_parking.h:104
static void bridge_parking_notify_masquerade(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel)
static struct parked_user * generate_parked_user(struct parking_lot *lot, struct ast_channel *chan, const char *parker_channel_name, const char *parker_dial_string, int use_random_space, int time_limit)
void(* ast_bridge_notify_masquerade_fn)(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
Notify the bridge that this channel was just masqueraded.
Definition: bridge.h:246
struct ast_bridge_methods ast_bridge_parking_v_table
const ast_string_field name
struct parking_lot_cfg * cfg
Definition: res_parking.h:96
#define ao2_link(container, obj)
Definition: astobj2.h:1549