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