Asterisk - The Open Source Telephony Project  21.4.1
Functions
pickup.h File Reference

Call Pickup API. More...

Go to the source code of this file.

Functions

struct stasis_message_typeast_call_pickup_type (void)
 accessor for call pickup message type More...
 
int ast_can_pickup (struct ast_channel *chan)
 Test if a channel can be picked up. More...
 
int ast_do_pickup (struct ast_channel *chan, struct ast_channel *target)
 Pickup a call target. More...
 
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call. More...
 
struct ast_channelast_pickup_find_by_group (struct ast_channel *chan)
 Find a pickup channel target by group. More...
 
int ast_pickup_init (void)
 Initialize pickup. More...
 

Detailed Description

Call Pickup API.

Includes code and algorithms from the Zapata library.

Definition in file pickup.h.

Function Documentation

struct stasis_message_type* ast_call_pickup_type ( void  )

accessor for call pickup message type

Since
12.0.0
Returns
pointer to the stasis message type
Return values
NULLif not initialized

Referenced by ast_pickup_init(), and create_routes().

int ast_can_pickup ( struct ast_channel chan)

Test if a channel can be picked up.

Parameters
chanChannel to test if can be picked up.
Note
This function assumes that chan is locked.
Return values
TRUEif channel can be picked up.

Definition at line 77 of file pickup.c.

References ast_channel_datastore_find(), AST_FLAG_ZOMBIE, AST_STATE_DOWN, AST_STATE_RING, and AST_STATE_RINGING.

Referenced by ast_pickup_find_by_group(), find_by_mark(), find_by_name(), find_by_uniqueid(), find_channel_by_group(), and pickup_by_exten().

78 {
79  if (!ast_channel_pbx(chan) && !ast_channel_masq(chan) && !ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
82  /*
83  * Check the down state as well because some SIP devices do not
84  * give 180 ringing when they can just give 183 session progress
85  * instead. Issue 14005. (Some ISDN switches as well for that
86  * matter.)
87  */
89  && !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
90  return 1;
91  }
92  return 0;
93 }
ast_channel_state
ast_channel states
Definition: channelstate.h:35
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2399
static const struct ast_datastore_info pickup_active
Definition: pickup.c:73
int ast_do_pickup ( struct ast_channel chan,
struct ast_channel target 
)

Pickup a call target.

Parameters
chanchannel that initiated pickup.
targetchannel to be picked up.
Note
This function assumes that target is locked.
Return values
0on success.
-1on failure.

< A masquerade changes channel names.

< A masquerade changes channel names.

Definition at line 301 of file pickup.c.

References ast_answer(), ast_channel_connected_line_sub(), ast_channel_datastore_add(), ast_channel_datastore_remove(), ast_channel_move(), ast_channel_queue_connected_line_update(), ast_channel_snapshot_create(), ast_channel_snapshot_get_latest(), ast_channel_update_connected_line(), ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, ast_datastore_free(), ast_debug, ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_party_id_reset(), ast_queue_control(), ast_strdupa, ast_party_connected_line::priv, RAII_VAR, and ast_party_connected_line::source.

Referenced by ast_pickup_call(), pickup_by_channel(), pickup_by_exten(), pickup_by_group(), pickup_by_mark(), and pickup_by_part().

302 {
303  struct ast_party_connected_line connected_caller;
304  struct ast_datastore *ds_pickup;
305  const char *chan_name;/*!< A masquerade changes channel names. */
306  const char *target_name;/*!< A masquerade changes channel names. */
307  int res = -1;
308 
309  RAII_VAR(struct ast_channel_snapshot *, chan_snapshot, NULL, ao2_cleanup);
310  RAII_VAR(struct ast_channel_snapshot *, target_snapshot, NULL, ao2_cleanup);
311 
312  target_name = ast_strdupa(ast_channel_name(target));
313  ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan));
314 
315  /* Mark the target to block any call pickup race. */
316  ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
317  if (!ds_pickup) {
318  ast_log(LOG_WARNING,
319  "Unable to create channel datastore on '%s' for call pickup\n", target_name);
320  return -1;
321  }
322  ast_channel_datastore_add(target, ds_pickup);
323 
324  ast_party_connected_line_init(&connected_caller);
325  ast_party_connected_line_copy(&connected_caller, ast_channel_connected(target));
326  ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
327  /* Reset any earlier private connected id representation */
328  ast_party_id_reset(&connected_caller.priv);
329 
330  connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
331  if (ast_channel_connected_line_sub(NULL, chan, &connected_caller, 0)) {
332  ast_channel_update_connected_line(chan, &connected_caller, NULL);
333  }
334  ast_party_connected_line_free(&connected_caller);
335 
336  ast_channel_lock(chan);
337  chan_name = ast_strdupa(ast_channel_name(chan));
338  ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(chan));
339  ast_channel_unlock(chan);
340  connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
341 
342  if (ast_answer(chan)) {
343  ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
344  goto pickup_failed;
345  }
346 
348  ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
349  goto pickup_failed;
350  }
351 
352  ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
353 
354  /* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */
355  ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE);
356 
357  ast_channel_lock(chan);
358  chan_snapshot = ast_channel_snapshot_create(chan);
359  ast_channel_unlock(chan);
360  if (!chan_snapshot) {
361  goto pickup_failed;
362  }
363 
364  target_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(target));
365  if (!target_snapshot) {
366  goto pickup_failed;
367  }
368 
369  if (ast_channel_move(target, chan)) {
370  ast_log(LOG_WARNING, "Unable to complete call pickup of '%s' with '%s'\n",
371  chan_name, target_name);
372  goto pickup_failed;
373  }
374 
375  /* target points to the channel that did the pickup at this point, so use that channel's topic instead of chan */
376  send_call_pickup_stasis_message(target, chan_snapshot, target_snapshot);
377 
378  res = 0;
379 
380 pickup_failed:
381  ast_channel_lock(target);
382  if (!ast_channel_datastore_remove(target, ds_pickup)) {
383  ast_datastore_free(ds_pickup);
384  }
385  ast_party_connected_line_free(&connected_caller);
386 
387  return res;
388 }
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition: channel.c:2022
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition: channel.c:1231
void ast_party_id_reset(struct ast_party_id *id)
Destroy and initialize the given party id structure.
Definition: channel.c:1896
void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Indicate that the connected line information has changed.
Definition: channel.c:9093
Structure representing a snapshot of channel state.
Structure for a data store object.
Definition: datastore.h:64
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2072
int ast_channel_move(struct ast_channel *dest, struct ast_channel *source)
Move a channel from its current location to a new location.
Definition: channel.c:10666
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate...
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
void ast_channel_queue_connected_line_update(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Queue a connected line update frame on a channel.
Definition: channel.c:9106
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_debug(level,...)
Log a DEBUG message.
int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *connected_info, int frame)
Run a connected line interception subroutine and update a channel's connected line information...
Definition: channel.c:10338
Connected Line/Party information.
Definition: channel.h:456
static const struct ast_datastore_info pickup_active
Definition: pickup.c:73
void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
Copy the source connected line information to the destination connected line.
Definition: channel.c:2031
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_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:8293
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2805
#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
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2394
int ast_pickup_call ( struct ast_channel chan)

Pickup a call.

Parameters
chanThe channel that initiated the pickup
Return values
0on success
-1on failure

Walk list of channels, checking it is not itself, channel is pbx one, check that the callgroup for both channels are the same and the channel is ringing. Answer calling channel, flag channel as answered on queue, masq channels together.

< Potential pickup target

Definition at line 199 of file pickup.c.

References ast_answer(), ast_channel_unref, ast_debug, ast_do_pickup(), ast_pickup_find_by_group(), ast_strdupa, ast_stream_and_wait(), pbx_builtin_setvar_helper(), and RAII_VAR.

200 {
201  struct ast_channel *target;/*!< Potential pickup target */
202  int res = -1;
203  RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
204  const char *pickup_sound;
205  const char *fail_sound;
206 
207  ast_debug(1, "Pickup attempt by %s\n", ast_channel_name(chan));
208  ast_channel_lock(chan);
209  pickup_cfg = ast_get_chan_features_pickup_config(chan);
210  if (!pickup_cfg) {
211  ast_log(LOG_ERROR, "Unable to retrieve pickup configuration. Unable to play pickup sounds\n");
212  }
213  pickup_sound = ast_strdupa(pickup_cfg ? pickup_cfg->pickupsound : "");
214  fail_sound = ast_strdupa(pickup_cfg ? pickup_cfg->pickupfailsound : "");
215  ast_channel_unlock(chan);
216 
217  /* The found channel is already locked. */
218  target = ast_pickup_find_by_group(chan);
219  if (target) {
220  ast_log(LOG_NOTICE, "Pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan));
221 
222  res = ast_do_pickup(chan, target);
223  ast_channel_unlock(target);
224  if (!res) {
225  if (!ast_strlen_zero(pickup_sound)) {
226  pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickup_sound);
227  }
228  } else {
229  ast_log(LOG_WARNING, "Pickup %s failed by %s\n", ast_channel_name(target), ast_channel_name(chan));
230  }
231  target = ast_channel_unref(target);
232  }
233 
234  if (res < 0) {
235  ast_debug(1, "No call pickup possible... for %s\n", ast_channel_name(chan));
236  if (!ast_strlen_zero(fail_sound)) {
237  ast_answer(chan);
238  ast_stream_and_wait(chan, fail_sound, "");
239  }
240  }
241 
242  return res;
243 }
Main Channel structure associated with a channel.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
struct ast_channel * ast_pickup_find_by_group(struct ast_channel *chan)
Find a pickup channel target by group.
Definition: pickup.c:133
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_debug(level,...)
Log a DEBUG message.
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:1878
int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target)
Pickup a call target.
Definition: pickup.c:301
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2805
#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
Configuration relating to call pickup.
struct ast_channel* ast_pickup_find_by_group ( struct ast_channel chan)

Find a pickup channel target by group.

Parameters
chanchannel that initiated pickup.
Returns
target on success. The returned channel is locked and reffed.
Return values
NULLon error.

< Candidate channels found to pickup.

< Potential pickup target

< Potential new older target

Definition at line 133 of file pickup.c.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_container_alloc_list, ao2_iterator_destroy(), ao2_iterator_init(), ao2_ref, ao2_unlink, ast_can_pickup(), ast_channel_callback(), ast_channel_unref, ast_tvcmp(), and find_channel_by_group().

Referenced by ast_pickup_call(), and pickup_by_group().

134 {
135  struct ao2_container *candidates;/*!< Candidate channels found to pickup. */
136  struct ast_channel *target;/*!< Potential pickup target */
137 
138  candidates = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL);
139  if (!candidates) {
140  return NULL;
141  }
142 
143  /* Find all candidate targets by group. */
144  ast_channel_callback(find_channel_by_group, chan, candidates, 0);
145 
146  /* Find the oldest pickup target candidate */
147  target = NULL;
148  for (;;) {
149  struct ast_channel *candidate;/*!< Potential new older target */
150  struct ao2_iterator iter;
151 
152  iter = ao2_iterator_init(candidates, 0);
153  while ((candidate = ao2_iterator_next(&iter))) {
154  if (!target) {
155  /* First target. */
156  target = candidate;
157  continue;
158  }
159  if (ast_tvcmp(ast_channel_creationtime(candidate), ast_channel_creationtime(target)) < 0) {
160  /* We have a new target. */
161  ast_channel_unref(target);
162  target = candidate;
163  continue;
164  }
165  ast_channel_unref(candidate);
166  }
167  ao2_iterator_destroy(&iter);
168  if (!target) {
169  /* No candidates found. */
170  break;
171  }
172 
173  /* The found channel must be locked and ref'd. */
174  ast_channel_lock(target);
175 
176  /* Recheck pickup ability */
177  if (ast_can_pickup(target)) {
178  /* This is the channel to pickup. */
179  break;
180  }
181 
182  /* Someone else picked it up or the call went away. */
183  ast_channel_unlock(target);
184  ao2_unlink(candidates, target);
185  target = ast_channel_unref(target);
186  }
187  ao2_ref(candidates, -1);
188 
189  return target;
190 }
Main Channel structure associated with a channel.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
Definition: pickup.c:95
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
struct ast_channel * ast_channel_callback(ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags)
Call a function with every active channel.
Definition: channel.c:1278
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller, equal or greater to the second.
Definition: time.h:137
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
int ast_can_pickup(struct ast_channel *chan)
Test if a channel can be picked up.
Definition: pickup.c:77
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Generic container type.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
int ast_pickup_init ( void  )

Initialize pickup.

Return values
0on success
non-zeroon failure

Definition at line 399 of file pickup.c.

References ast_call_pickup_type(), ast_register_cleanup(), and STASIS_MESSAGE_TYPE_INIT.

400 {
402  ast_register_cleanup(pickup_shutdown);
403 
404  return 0;
405 }
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
struct stasis_message_type * ast_call_pickup_type(void)
accessor for call pickup message type