Asterisk - The Open Source Telephony Project  18.5.0
Functions | Variables
pickup.c File Reference

Routines implementing call pickup. More...

#include "asterisk.h"
#include "asterisk/pickup.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/callerid.h"
#include "asterisk/causes.h"
#include "asterisk/stasis.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/features_config.h"
Include dependency graph for pickup.c:

Go to the source code of this file.

Functions

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...
 
static struct ast_manager_event_blobcall_pickup_to_ami (struct stasis_message *message)
 
static int find_channel_by_group (void *obj, void *arg, void *data, int flags)
 
static void pickup_shutdown (void)
 
static int send_call_pickup_stasis_message (struct ast_channel *picking_up, struct ast_channel_snapshot *chan, struct ast_channel_snapshot *target)
 
 STASIS_MESSAGE_TYPE_DEFN (ast_call_pickup_type,.to_ami=call_pickup_to_ami)
 

Variables

static const struct ast_datastore_info pickup_active
 

Detailed Description

Routines implementing call pickup.

Author
Matt Jordan mjord.nosp@m.an@d.nosp@m.igium.nosp@m..com

Definition in file pickup.c.

Function Documentation

◆ ast_can_pickup()

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.
Returns
TRUE if channel can be picked up.

Definition at line 77 of file pickup.c.

References ast_channel_datastore_find(), ast_channel_flags(), ast_channel_masq(), ast_channel_pbx(), AST_FLAG_ZOMBIE, AST_STATE_DOWN, AST_STATE_RING, AST_STATE_RINGING, ast_test_flag, and NULL.

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

78 {
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  */
90  return 1;
91  }
92  return 0;
93 }
#define ast_test_flag(p, flag)
Definition: utils.h:63
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:2404
#define NULL
Definition: resample.c:96
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
struct ast_channel * ast_channel_masq(const struct ast_channel *chan)
static const struct ast_datastore_info pickup_active
Definition: pickup.c:73
struct ast_flags * ast_channel_flags(struct ast_channel *chan)

◆ ast_do_pickup()

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 302 of file pickup.c.

References ao2_cleanup, ast_answer(), AST_CAUSE_ANSWERED_ELSEWHERE, ast_channel_caller(), ast_channel_connected(), ast_channel_connected_line_macro(), ast_channel_connected_line_sub(), ast_channel_datastore_add(), ast_channel_datastore_remove(), ast_channel_hangupcause_set(), ast_channel_lock, ast_channel_move(), ast_channel_name(), ast_channel_queue_connected_line_update(), ast_channel_snapshot_create(), ast_channel_snapshot_get_latest(), ast_channel_uniqueid(), ast_channel_unlock, ast_channel_update_connected_line(), ast_connected_line_copy_from_caller(), AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, AST_CONTROL_ANSWER, ast_datastore_alloc, ast_datastore_free(), ast_debug, ast_log, ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_party_id_reset(), ast_queue_control(), ast_strdupa, LOG_WARNING, NULL, ast_party_connected_line::priv, RAII_VAR, send_call_pickup_stasis_message(), and ast_party_connected_line::source.

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

303 {
304  struct ast_party_connected_line connected_caller;
305  struct ast_datastore *ds_pickup;
306  const char *chan_name;/*!< A masquerade changes channel names. */
307  const char *target_name;/*!< A masquerade changes channel names. */
308  int res = -1;
309 
310  RAII_VAR(struct ast_channel_snapshot *, chan_snapshot, NULL, ao2_cleanup);
311  RAII_VAR(struct ast_channel_snapshot *, target_snapshot, NULL, ao2_cleanup);
312 
313  target_name = ast_strdupa(ast_channel_name(target));
314  ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan));
315 
316  /* Mark the target to block any call pickup race. */
317  ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
318  if (!ds_pickup) {
320  "Unable to create channel datastore on '%s' for call pickup\n", target_name);
321  return -1;
322  }
323  ast_channel_datastore_add(target, ds_pickup);
324 
325  ast_party_connected_line_init(&connected_caller);
326  ast_party_connected_line_copy(&connected_caller, ast_channel_connected(target));
327  ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
328  /* Reset any earlier private connected id representation */
329  ast_party_id_reset(&connected_caller.priv);
330 
331  connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
332  if (ast_channel_connected_line_sub(NULL, chan, &connected_caller, 0) &&
333  ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
334  ast_channel_update_connected_line(chan, &connected_caller, NULL);
335  }
336  ast_party_connected_line_free(&connected_caller);
337 
338  ast_channel_lock(chan);
339  chan_name = ast_strdupa(ast_channel_name(chan));
341  ast_channel_unlock(chan);
342  connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
343 
344  if (ast_answer(chan)) {
345  ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
346  goto pickup_failed;
347  }
348 
350  ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
351  goto pickup_failed;
352  }
353 
354  ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
355 
356  /* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */
358 
359  ast_channel_lock(chan);
360  chan_snapshot = ast_channel_snapshot_create(chan);
361  ast_channel_unlock(chan);
362  if (!chan_snapshot) {
363  goto pickup_failed;
364  }
365 
366  target_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(target));
367  if (!target_snapshot) {
368  goto pickup_failed;
369  }
370 
371  if (ast_channel_move(target, chan)) {
372  ast_log(LOG_WARNING, "Unable to complete call pickup of '%s' with '%s'\n",
373  chan_name, target_name);
374  goto pickup_failed;
375  }
376 
377  /* target points to the channel that did the pickup at this point, so use that channel's topic instead of chan */
378  send_call_pickup_stasis_message(target, chan_snapshot, target_snapshot);
379 
380  res = 0;
381 
382 pickup_failed:
383  ast_channel_lock(target);
384  if (!ast_channel_datastore_remove(target, ds_pickup)) {
385  ast_datastore_free(ds_pickup);
386  }
387  ast_party_connected_line_free(&connected_caller);
388 
389  return res;
390 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition: channel.c:2022
#define ast_channel_lock(chan)
Definition: channel.h:2945
int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int is_caller, int frame)
Run a connected line interception macro and update a channel&#39;s connected line information.
Definition: channel.c:10435
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_hangupcause_set(struct ast_channel *chan, int value)
#define LOG_WARNING
Definition: logger.h:274
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:9189
Structure representing a snapshot of channel state.
static int send_call_pickup_stasis_message(struct ast_channel *picking_up, struct ast_channel_snapshot *chan, struct ast_channel_snapshot *target)
Definition: pickup.c:278
Structure for a data store object.
Definition: datastore.h:68
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2072
#define NULL
Definition: resample.c:96
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:10867
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
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
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:9202
#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
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition: causes.h:113
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char * ast_channel_uniqueid(const struct ast_channel *chan)
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&#39;s connected line information...
Definition: channel.c:10539
Connected Line/Party information.
Definition: channel.h:457
#define ast_channel_unlock(chan)
Definition: channel.h:2946
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...
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
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:8389
const char * ast_channel_name(const struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2814
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2399

◆ ast_pickup_call()

int ast_pickup_call ( struct ast_channel chan)

Pickup a call.

Parameters
chanchannel that initiated pickup.

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 200 of file pickup.c.

References ao2_cleanup, ast_answer(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_channel_unref, ast_debug, ast_do_pickup(), ast_get_chan_features_pickup_config(), ast_log, ast_pickup_find_by_group(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero, LOG_ERROR, LOG_NOTICE, LOG_WARNING, NULL, pbx_builtin_setvar_helper(), and RAII_VAR.

Referenced by __analog_ss_thread(), analog_ss_thread(), call_pickup_incoming_request(), cb_events(), handle_call_outgoing(), handle_soft_key_event_message(), mgcp_ss(), and sip_pickup_thread().

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

◆ ast_pickup_find_by_group()

struct ast_channel* ast_pickup_find_by_group ( struct ast_channel chan)

Find a pickup channel target by group.

Parameters
chanchannel that initiated pickup.
Return values
targeton success. The returned channel is locked and reffed.
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_iterator_next, ao2_ref, ao2_unlink, ast_can_pickup(), ast_channel_callback(), ast_channel_creationtime(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_tvcmp(), find_channel_by_group(), and NULL.

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 
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 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define NULL
Definition: resample.c:96
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
Definition: pickup.c:95
#define ao2_ref(o, delta)
Definition: astobj2.h:464
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)
Compres two struct timeval instances returning -1, 0, 1 if the first arg is smaller, equal or greater to the second.
Definition: time.h:128
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
struct timeval ast_channel_creationtime(struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2946
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:1841
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.

◆ ast_pickup_init()

int ast_pickup_init ( void  )

Initialize pickup.

Return values
0on success
non-zeroon failure

Definition at line 401 of file pickup.c.

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

Referenced by asterisk_daemon().

402 {
405 
406  return 0;
407 }
static void pickup_shutdown(void)
Definition: pickup.c:396
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1501
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

◆ call_pickup_to_ami()

static struct ast_manager_event_blob * call_pickup_to_ami ( struct stasis_message message)
static

Definition at line 246 of file pickup.c.

References ast_assert, ast_free, ast_manager_build_channel_state_string(), ast_manager_build_channel_state_string_prefix(), ast_manager_event_blob_create(), ast_multi_channel_blob_get_channel(), ast_str_buffer(), contents, EVENT_FLAG_CALL, NULL, RAII_VAR, and stasis_message_data().

247 {
249  struct ast_channel_snapshot *chan;
250  struct ast_channel_snapshot *target;
251  struct ast_manager_event_blob *res;
252 
253  RAII_VAR(struct ast_str *, channel_str, NULL, ast_free);
254  RAII_VAR(struct ast_str *, target_str, NULL, ast_free);
255 
256  chan = ast_multi_channel_blob_get_channel(contents, "channel");
257  target = ast_multi_channel_blob_get_channel(contents, "target");
258 
259  ast_assert(chan != NULL && target != NULL);
260 
261  if (!(channel_str = ast_manager_build_channel_state_string(chan))) {
262  return NULL;
263  }
264 
265  if (!(target_str = ast_manager_build_channel_state_string_prefix(target, "Target"))) {
266  return NULL;
267  }
268 
270  "%s"
271  "%s",
272  ast_str_buffer(channel_str),
273  ast_str_buffer(target_str));
274 
275  return res;
276 }
Struct containing info for an AMI event to send out.
Definition: manager.h:491
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
Structure representing a snapshot of channel state.
struct ast_str * ast_manager_build_channel_state_string_prefix(const struct ast_channel_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a channel snapshot.
#define EVENT_FLAG_CALL
Definition: manager.h:72
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:9727
#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
const char * contents
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define ast_free(a)
Definition: astmm.h:182
struct ast_channel_snapshot * ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
Retrieve a channel snapshot associated with a specific role from a ast_multi_channel_blob.
A multi channel blob data structure for multi_channel_blob stasis messages.

◆ find_channel_by_group()

static int find_channel_by_group ( void *  obj,
void *  arg,
void *  data,
int  flags 
)
static

< Potential pickup target

< Channel wanting to pickup call

< Candidate channels found.

Definition at line 95 of file pickup.c.

References ao2_link, ast_can_pickup(), ast_channel_callgroup(), ast_channel_lock, ast_channel_named_callgroups(), ast_channel_named_pickupgroups(), ast_channel_pickupgroup(), ast_channel_trylock, ast_channel_unlock, and ast_namedgroups_intersect().

Referenced by ast_pickup_find_by_group().

96 {
97  struct ast_channel *target = obj; /*!< Potential pickup target */
98  struct ast_channel *chan = arg; /*!< Channel wanting to pickup call */
99 
100  if (chan == target) {
101  return 0;
102  }
103 
104  ast_channel_lock(target);
105  if (ast_can_pickup(target)) {
106  /* Lock both channels. */
107  while (ast_channel_trylock(chan)) {
108  ast_channel_unlock(target);
109  sched_yield();
110  ast_channel_lock(target);
111  }
112 
113  /*
114  * Both callgroup and namedcallgroup pickup variants are
115  * matched independently. Checking for named group match is
116  * done last since it's a more expensive operation.
117  */
118  if ((ast_channel_pickupgroup(chan) & ast_channel_callgroup(target))
120  ast_channel_named_callgroups(target)))) {
121  struct ao2_container *candidates = data;/*!< Candidate channels found. */
122 
123  /* This is a candidate to pickup */
124  ao2_link(candidates, target);
125  }
126  ast_channel_unlock(chan);
127  }
128  ast_channel_unlock(target);
129 
130  return 0;
131 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
struct ast_namedgroups * ast_channel_named_callgroups(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2946
int ast_can_pickup(struct ast_channel *chan)
Test if a channel can be picked up.
Definition: pickup.c:77
int ast_namedgroups_intersect(struct ast_namedgroups *a, struct ast_namedgroups *b)
Return TRUE if group a and b contain at least one common groupname.
Definition: channel.c:8192
struct ast_namedgroups * ast_channel_named_pickupgroups(const struct ast_channel *chan)
ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan)
Generic container type.
#define ast_channel_trylock(chan)
Definition: channel.h:2947
ast_group_t ast_channel_callgroup(const struct ast_channel *chan)
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ pickup_shutdown()

static void pickup_shutdown ( void  )
static

Definition at line 396 of file pickup.c.

References ast_call_pickup_type(), and STASIS_MESSAGE_TYPE_CLEANUP.

Referenced by ast_pickup_init().

397 {
399 }
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1523
struct stasis_message_type * ast_call_pickup_type(void)
accessor for call pickup message type

◆ send_call_pickup_stasis_message()

static int send_call_pickup_stasis_message ( struct ast_channel picking_up,
struct ast_channel_snapshot chan,
struct ast_channel_snapshot target 
)
static

Definition at line 278 of file pickup.c.

References ao2_cleanup, ast_call_pickup_type(), ast_channel_topic(), ast_json_null(), ast_multi_channel_blob_add_channel(), ast_multi_channel_blob_create(), NULL, RAII_VAR, stasis_message_create(), and stasis_publish().

Referenced by ast_do_pickup().

279 {
280  RAII_VAR(struct ast_multi_channel_blob *, pickup_payload, NULL, ao2_cleanup);
281  RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
282 
283  if (!ast_call_pickup_type()) {
284  return -1;
285  }
286 
287  if (!(pickup_payload = ast_multi_channel_blob_create(ast_json_null()))) {
288  return -1;
289  }
290 
291  ast_multi_channel_blob_add_channel(pickup_payload, "channel", chan);
292  ast_multi_channel_blob_add_channel(pickup_payload, "target", target);
293 
294  if (!(msg = stasis_message_create(ast_call_pickup_type(), pickup_payload))) {
295  return -1;
296  }
297 
298  stasis_publish(ast_channel_topic(picking_up), msg);
299  return 0;
300 }
#define NULL
Definition: resample.c:96
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
#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
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
struct stasis_message_type * ast_call_pickup_type(void)
accessor for call pickup message type
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
A multi channel blob data structure for multi_channel_blob stasis messages.
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.

◆ STASIS_MESSAGE_TYPE_DEFN()

STASIS_MESSAGE_TYPE_DEFN ( ast_call_pickup_type  ,
to_ami = call_pickup_to_ami 
)

Variable Documentation

◆ pickup_active

const struct ast_datastore_info pickup_active
static
Initial value:
= {
.type = "pickup-active",
}

The presence of this datastore on the channel indicates that someone is attemting to pickup or has picked up the channel. The purpose is to prevent a race between two channels attempting to pickup the same channel.

Definition at line 73 of file pickup.c.