Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Functions
pickup.h File Reference

Call Pickup API. More...

This graph shows which files directly or indirectly include this file:

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

◆ ast_call_pickup_type()

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(), create_routes(), pickup_shutdown(), and send_call_pickup_stasis_message().

◆ 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.
Return values
TRUEif channel can be picked up.

Definition at line 80 of file pickup.c.

81{
85 /*
86 * Check the down state as well because some SIP devices do not
87 * give 180 ringing when they can just give 183 session progress
88 * instead. Issue 14005. (Some ISDN switches as well for that
89 * matter.)
90 */
93 return 1;
94 }
95 return 0;
96}
struct ast_channel * ast_channel_masq(const struct ast_channel *chan)
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
@ AST_FLAG_ZOMBIE
Definition: channel.h:1007
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
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:2428
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_RING
Definition: channelstate.h:40
@ AST_STATE_RINGING
Definition: channelstate.h:41
@ AST_STATE_DOWN
Definition: channelstate.h:36
static const struct ast_datastore_info pickup_active
Definition: pickup.c:76
#define NULL
Definition: resample.c:96
#define ast_test_flag(p, flag)
Definition: utils.h:63

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, NULL, and pickup_active.

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

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

305{
306 struct ast_party_connected_line connected_caller;
307 struct ast_datastore *ds_pickup;
308 const char *chan_name;/*!< A masquerade changes channel names. */
309 const char *target_name;/*!< A masquerade changes channel names. */
310 int res = -1;
311
312 RAII_VAR(struct ast_channel_snapshot *, chan_snapshot, NULL, ao2_cleanup);
313 RAII_VAR(struct ast_channel_snapshot *, target_snapshot, NULL, ao2_cleanup);
314
315 target_name = ast_strdupa(ast_channel_name(target));
316 ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan));
317
318 /* Mark the target to block any call pickup race. */
320 if (!ds_pickup) {
322 "Unable to create channel datastore on '%s' for call pickup\n", target_name);
323 return -1;
324 }
325 ast_channel_datastore_add(target, ds_pickup);
326
327 ast_party_connected_line_init(&connected_caller);
328 ast_party_connected_line_copy(&connected_caller, ast_channel_connected(target));
329 ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
330 /* Reset any earlier private connected id representation */
331 ast_party_id_reset(&connected_caller.priv);
332
333 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
334 if (ast_channel_connected_line_sub(NULL, chan, &connected_caller, 0)) {
335 ast_channel_update_connected_line(chan, &connected_caller, NULL);
336 }
337 ast_party_connected_line_free(&connected_caller);
338
339 ast_channel_lock(chan);
340 chan_name = ast_strdupa(ast_channel_name(chan));
342 ast_channel_unlock(chan);
343 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
344
345 if (ast_answer(chan)) {
346 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
347 goto pickup_failed;
348 }
349
351 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
352 goto pickup_failed;
353 }
354
355 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
356
357 /* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */
359
360 ast_channel_lock(chan);
361 chan_snapshot = ast_channel_snapshot_create(chan);
362 ast_channel_unlock(chan);
363 if (!chan_snapshot) {
364 goto pickup_failed;
365 }
366
367 target_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(target));
368 if (!target_snapshot) {
369 goto pickup_failed;
370 }
371
372 if (ast_channel_move(target, chan)) {
373 ast_log(LOG_WARNING, "Unable to complete call pickup of '%s' with '%s'\n",
374 chan_name, target_name);
375 goto pickup_failed;
376 }
377
378 /* target points to the channel that did the pickup at this point, so use that channel's topic instead of chan */
379 send_call_pickup_stasis_message(target, chan_snapshot, target_snapshot);
380
381 res = 0;
382
383pickup_failed:
384 ast_channel_lock(target);
385 if (!ast_channel_datastore_remove(target, ds_pickup)) {
386 ast_datastore_free(ds_pickup);
387 }
388 ast_party_connected_line_free(&connected_caller);
389
390 return res;
391}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
@ AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER
Definition: callerid.h:554
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition: causes.h:114
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2414
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2423
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:10364
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2099
#define ast_channel_lock(chan)
Definition: channel.h:2970
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:2058
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition: channel.c:1258
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
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:9119
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:10692
void ast_party_id_reset(struct ast_party_id *id)
Destroy and initialize the given party id structure.
Definition: channel.c:1923
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition: channel.c:2049
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:8319
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
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:9132
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2834
#define ast_channel_unlock(chan)
Definition: channel.h:2971
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
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,...
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.
@ AST_CONTROL_ANSWER
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_WARNING
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:280
Structure representing a snapshot of channel state.
Structure for a data store object.
Definition: datastore.h:64
Connected Line/Party information.
Definition: channel.h:458
#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

References ao2_cleanup, ast_answer(), AST_CAUSE_ANSWERED_ELSEWHERE, ast_channel_caller(), ast_channel_connected(), 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, pickup_active, 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(), pickup_by_channel(), pickup_by_exten(), pickup_by_group(), pickup_by_mark(), and pickup_by_part().

◆ ast_pickup_call()

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

203{
204 struct ast_channel *target;/*!< Potential pickup target */
205 int res = -1;
206 RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
207 const char *pickup_sound;
208 const char *fail_sound;
209
210 ast_debug(1, "Pickup attempt by %s\n", ast_channel_name(chan));
211 ast_channel_lock(chan);
212 pickup_cfg = ast_get_chan_features_pickup_config(chan);
213 if (!pickup_cfg) {
214 ast_log(LOG_ERROR, "Unable to retrieve pickup configuration. Unable to play pickup sounds\n");
215 }
216 pickup_sound = ast_strdupa(pickup_cfg ? pickup_cfg->pickupsound : "");
217 fail_sound = ast_strdupa(pickup_cfg ? pickup_cfg->pickupfailsound : "");
218 ast_channel_unlock(chan);
219
220 /* The found channel is already locked. */
221 target = ast_pickup_find_by_group(chan);
222 if (target) {
223 ast_log(LOG_NOTICE, "Pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan));
224
225 res = ast_do_pickup(chan, target);
226 ast_channel_unlock(target);
227 if (!res) {
228 if (!ast_strlen_zero(pickup_sound)) {
229 pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickup_sound);
230 }
231 } else {
232 ast_log(LOG_WARNING, "Pickup %s failed by %s\n", ast_channel_name(target), ast_channel_name(chan));
233 }
234 target = ast_channel_unref(target);
235 }
236
237 if (res < 0) {
238 ast_debug(1, "No call pickup possible... for %s\n", ast_channel_name(chan));
239 if (!ast_strlen_zero(fail_sound)) {
240 ast_answer(chan);
241 ast_stream_and_wait(chan, fail_sound, "");
242 }
243 }
244
245 return res;
246}
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3006
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:1886
struct ast_features_pickup_config * ast_get_chan_features_pickup_config(struct ast_channel *chan)
Get the pickup configuration options for a channel.
#define LOG_ERROR
#define LOG_NOTICE
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_do_pickup(struct ast_channel *chan, struct ast_channel *target)
Pickup a call target.
Definition: pickup.c:304
struct ast_channel * ast_pickup_find_by_group(struct ast_channel *chan)
Find a pickup channel target by group.
Definition: pickup.c:136
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Main Channel structure associated with a channel.
Configuration relating to call pickup.

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(), and handle_call_outgoing().

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

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

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().

◆ ast_pickup_init()

int ast_pickup_init ( void  )

Initialize pickup.

Return values
0on success
non-zeroon failure

Definition at line 402 of file pickup.c.

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

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

Referenced by asterisk_daemon().