Asterisk - The Open Source Telephony Project GIT-master-6144b6b
Loading...
Searching...
No Matches
Typedefs | Functions
stasis_app_impl.h File Reference

Backend API for implementing components of res_stasis. More...

#include "asterisk/stasis_app.h"
Include dependency graph for stasis_app_impl.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef void(* command_data_destructor_fn) (void *data)
 Typedef for data destructor for stasis app commands.
 
typedef int(* stasis_app_command_cb) (struct stasis_app_control *control, struct ast_channel *chan, void *data)
 

Functions

int stasis_app_exec (struct ast_channel *chan, const char *app_name, int argc, char *argv[])
 Control a channel using stasis_app.
 
int stasis_app_send_command (struct stasis_app_control *control, stasis_app_command_cb command, void *data, command_data_destructor_fn data_destructor)
 Invokes a command on a control's channel.
 
int stasis_app_send_command_async (struct stasis_app_control *control, stasis_app_command_cb command, void *data, command_data_destructor_fn data_destructor)
 Asynchronous version of stasis_app_send_command().
 

Detailed Description

Backend API for implementing components of res_stasis.

Author
David M. Lee, II dlee@.nosp@m.digi.nosp@m.um.co.nosp@m.m
Since
12

This file defines functions useful for defining new commands to execute on channels while they are in Stasis.

Definition in file stasis_app_impl.h.

Typedef Documentation

◆ command_data_destructor_fn

typedef void(* command_data_destructor_fn) (void *data)

Typedef for data destructor for stasis app commands.

This is called during destruction of the command or if we fail to schedule a command. It is passed a pointer to the user-defined data of the command.

Parameters
dataData to destroy.

Definition at line 59 of file stasis_app_impl.h.

◆ stasis_app_command_cb

typedef int(* stasis_app_command_cb) (struct stasis_app_control *control, struct ast_channel *chan, void *data)

Callback type for stasis app commands

Definition at line 62 of file stasis_app_impl.h.

Function Documentation

◆ stasis_app_exec()

int stasis_app_exec ( struct ast_channel chan,
const char *  app_name,
int  argc,
char *  argv[] 
)

Control a channel using stasis_app.

Since
12

This function blocks until the channel hangs up, or stasis_app_control_continue() is called on the channel's stasis_app_control struct.

Parameters
chanChannel to control with Stasis.
app_nameApplication controlling the channel.
argcNumber of arguments for the application.
argvArguments for the application.

Control a channel using stasis_app.

Definition at line 1396 of file res_stasis.c.

1398{
1399 RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1400 RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
1401 struct ast_bridge *bridge = NULL;
1402 int res = 0;
1403 int needs_depart;
1404
1405 ast_assert(chan != NULL);
1406
1407 /* Just in case there's a lingering indication that the channel has had a stasis
1408 * end published on it, remove that now.
1409 */
1411
1412 if (!apps_registry) {
1413 return -1;
1414 }
1415
1417 if (!app) {
1419 "Stasis app '%s' not registered\n", app_name);
1420 return -1;
1421 }
1422 if (!app_is_active(app)) {
1424 "Stasis app '%s' not active\n", app_name);
1425 return -1;
1426 }
1427
1428 control = control_create(chan, app);
1429 if (!control) {
1430 ast_log(LOG_ERROR, "Control allocation failed or Stasis app '%s' not registered\n", app_name);
1431 return -1;
1432 }
1433
1434 if (!control_app(control)) {
1435 ast_log(LOG_ERROR, "Stasis app '%s' not registered\n", app_name);
1436 return -1;
1437 }
1438
1439 if (!app_is_active(control_app(control))) {
1440 ast_log(LOG_ERROR, "Stasis app '%s' not active\n", app_name);
1441 return -1;
1442 }
1443 ao2_link(app_controls, control);
1444
1445 if (add_masquerade_store(chan)) {
1446 ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1447 return -1;
1448 }
1449
1450 res = send_start_msg(control_app(control), chan, argc, argv);
1451 if (res != 0) {
1453 "Error sending start message to '%s'\n", app_name);
1455 return -1;
1456 }
1457
1458 /* Pull queued prestart commands and execute */
1459 control_prestart_dispatch_all(control, chan);
1460
1461 while (!control_is_done(control)) {
1462 RAII_VAR(struct ast_frame *, f, NULL, ast_frame_dtor);
1463 int r;
1464 int command_count;
1465 RAII_VAR(struct ast_bridge *, last_bridge, NULL, ao2_cleanup);
1466
1467 /* Check to see if a bridge absorbed our hangup frame */
1468 if (ast_check_hangup_locked(chan)) {
1469 control_mark_done(control);
1470 break;
1471 }
1472
1473 /* control->next_app is only modified within the control thread, so this is safe */
1474 if (control_next_app(control)) {
1475 struct stasis_app *next_app = ao2_find(apps_registry, control_next_app(control), OBJ_SEARCH_KEY);
1476
1477 if (next_app && app_is_active(next_app)) {
1478 int idx;
1479 int next_argc;
1480 char **next_argv;
1481
1482 /* If something goes wrong in this conditional, res will need to be non-zero
1483 * so that the code below the exec loop knows something went wrong during a move.
1484 */
1486 res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1487 if (res != 0) {
1489 "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1490 control_mark_done(control);
1491 ao2_ref(next_app, -1);
1492 break;
1493 }
1494 } else {
1496 }
1497
1498 /* This will ao2_bump next_app, and unref the previous app by 1 */
1499 control_set_app(control, next_app);
1500
1501 /* There's a chance that the previous application is ready for clean up, so go ahead
1502 * and do that now.
1503 */
1504 cleanup();
1505
1506 /* We need to add another masquerade store, otherwise the leave message will
1507 * not show up for the correct application.
1508 */
1509 if (add_masquerade_store(chan)) {
1510 ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1511 res = -1;
1512 control_mark_done(control);
1513 ao2_ref(next_app, -1);
1514 break;
1515 }
1516
1517 /* We MUST get the size before the list, as control_next_app_args steals the elements
1518 * from the string vector.
1519 */
1520 next_argc = control_next_app_args_size(control);
1521 next_argv = control_next_app_args(control);
1522
1523 res = send_start_msg(control_app(control), chan, next_argc, next_argv);
1524
1525 /* Even if res != 0, we still need to free the memory we got from control_argv */
1526 if (next_argv) {
1527 for (idx = 0; idx < next_argc; idx++) {
1528 ast_free(next_argv[idx]);
1529 }
1530 ast_free(next_argv);
1531 }
1532
1533 if (res != 0) {
1535 "Error sending start message to '%s'\n", stasis_app_name(control_app(control)));
1537 control_mark_done(control);
1538 ao2_ref(next_app, -1);
1539 break;
1540 }
1541
1542 /* Done switching applications, free memory and clean up */
1543 control_move_cleanup(control);
1544 } else {
1545 /* If we can't switch applications, do nothing */
1546 struct ast_json *msg;
1547 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
1548
1549 if (!next_app) {
1550 ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not registered\n",
1551 control_next_app(control));
1552 } else {
1553 ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not active\n",
1554 control_next_app(control));
1555 }
1556
1558 if (!snapshot) {
1559 ast_log(LOG_ERROR, "Could not get channel shapshot for '%s'\n",
1560 ast_channel_name(chan));
1561 } else {
1562 struct ast_json *json_args;
1563 int next_argc = control_next_app_args_size(control);
1564 char **next_argv = control_next_app_args(control);
1565
1566 msg = ast_json_pack("{s: s, s: o, s: o, s: s, s: []}",
1567 "type", "ApplicationMoveFailed",
1568 "timestamp", ast_json_timeval(ast_tvnow(), NULL),
1569 "channel", ast_channel_snapshot_to_json(snapshot, NULL),
1570 "destination", control_next_app(control),
1571 "args");
1572 if (!msg) {
1573 ast_log(LOG_ERROR, "Failed to pack JSON for ApplicationMoveFailed message\n");
1574 } else {
1575 json_args = ast_json_object_get(msg, "args");
1576 if (!json_args) {
1577 ast_log(LOG_ERROR, "Could not get args json array");
1578 } else {
1579 int r = 0;
1580 int idx;
1581 for (idx = 0; idx < next_argc; ++idx) {
1582 r = ast_json_array_append(json_args,
1583 ast_json_string_create(next_argv[idx]));
1584 if (r != 0) {
1585 ast_log(LOG_ERROR, "Error appending to ApplicationMoveFailed message\n");
1586 break;
1587 }
1588 }
1589 if (r == 0) {
1590 app_send(control_app(control), msg);
1591 }
1592 }
1593 ast_json_unref(msg);
1594 }
1595 }
1596 }
1597 control_move_cleanup(control);
1598 ao2_cleanup(next_app);
1599 }
1600
1601 last_bridge = bridge;
1602 bridge = ao2_bump(stasis_app_get_bridge(control));
1603
1604 if (bridge != last_bridge) {
1605 if (last_bridge) {
1606 app_unsubscribe_bridge(control_app(control), last_bridge);
1607 }
1608 if (bridge) {
1609 app_subscribe_bridge(control_app(control), bridge);
1610 }
1611 }
1612
1613 if (bridge) {
1614 /* Bridge/dial is handling channel frames */
1615 control_wait(control);
1616 control_dispatch_all(control, chan);
1617 continue;
1618 }
1619
1620 r = ast_waitfor(chan, MAX_WAIT_MS);
1621
1622 if (r < 0) {
1623 ast_debug(3, "%s: Poll error\n",
1624 ast_channel_uniqueid(chan));
1625 control_mark_done(control);
1626 break;
1627 }
1628
1629 command_count = control_dispatch_all(control, chan);
1630
1631 if (command_count > 0 && ast_channel_fdno(chan) == -1) {
1632 /* Command drained the channel; wait for next frame */
1633 continue;
1634 }
1635
1636 if (r == 0) {
1637 /* Timeout */
1638 continue;
1639 }
1640
1641 f = ast_read(chan);
1642 if (!f) {
1643 /* Continue on in the dialplan */
1644 ast_debug(3, "%s: Hangup (no more frames)\n",
1645 ast_channel_uniqueid(chan));
1646 control_mark_done(control);
1647 break;
1648 }
1649
1650 if (f->frametype == AST_FRAME_CONTROL) {
1651 if (f->subclass.integer == AST_CONTROL_HANGUP) {
1652 /* Continue on in the dialplan */
1653 ast_debug(3, "%s: Hangup\n",
1654 ast_channel_uniqueid(chan));
1655 control_mark_done(control);
1656 break;
1657 }
1658 }
1659 }
1660
1661 ast_channel_lock(chan);
1662 needs_depart = (ast_channel_internal_bridge_channel(chan) != NULL);
1663 ast_channel_unlock(chan);
1664 if (needs_depart) {
1665 ast_bridge_depart(chan);
1666 }
1667
1668 if (stasis_app_get_bridge(control)) {
1670 }
1671 ao2_cleanup(bridge);
1672
1673 /* Only publish a stasis_end event if it hasn't already been published */
1674 if (!res && !stasis_app_channel_is_stasis_end_published(chan)) {
1675 /* A masquerade has occurred and this message will be wrong so it
1676 * has already been sent elsewhere. */
1677 res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1678 if (res != 0) {
1680 "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1681 return res;
1682 }
1683 } else {
1685 }
1686
1687 control_flush_queue(control);
1688
1689 /* Stop any lingering silence generator */
1690 control_silence_stop_now(control);
1691
1692 /* There's an off chance that app is ready for cleanup. Go ahead
1693 * and clean up, just in case
1694 */
1695 cleanup();
1696
1697 if (stasis_app_control_is_failed(control)) {
1698 res = -1;
1699 }
1700 /* The control needs to be removed from the controls container in
1701 * case a new PBX is started and ends up coming back into Stasis.
1702 */
1703 control_unlink(control);
1704 control = NULL;
1705
1706 if (!res && !ast_channel_pbx(chan)) {
1707 int chan_hungup;
1708
1709 /* The ASYNCGOTO softhangup flag may have broken the channel out of
1710 * its bridge to run dialplan, so if there's no pbx on the channel
1711 * let it run dialplan here. Otherwise, it will run when this
1712 * application exits. */
1713 ast_channel_lock(chan);
1715 chan_hungup = ast_check_hangup(chan);
1716 ast_channel_unlock(chan);
1717
1718 if (!chan_hungup) {
1719 struct ast_pbx_args pbx_args;
1720
1721 memset(&pbx_args, 0, sizeof(pbx_args));
1722 pbx_args.no_hangup_chan = 1;
1723
1724 res = ast_pbx_run_args(chan, &pbx_args);
1725 }
1726 }
1727
1728 return res;
1729}
static const char app[]
#define ast_free(a)
Definition astmm.h:180
#define ast_log
Definition astobj2.c:42
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition astobj2.h:1101
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
Definition bridge.c:2105
const char * ast_channel_name(const struct ast_channel *chan)
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition channel.c:2423
int ast_channel_fdno(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition channel.h:2983
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition channel.c:3166
const char * ast_channel_uniqueid(const struct ast_channel *chan)
int ast_check_hangup_locked(struct ast_channel *chan)
Definition channel.c:460
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4278
struct ast_bridge_channel * ast_channel_internal_bridge_channel(const struct ast_channel *chan)
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition channel.c:446
@ AST_SOFTHANGUP_ASYNCGOTO
Definition channel.h:1146
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition channel.h:2984
struct stasis_app_control * control_create(struct ast_channel *channel, struct stasis_app *app)
Create a control object.
Definition control.c:131
int control_prestart_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all queued prestart commands.
Definition control.c:1598
void control_wait(struct stasis_app_control *control)
Blocks until control's command queue has a command available.
Definition control.c:1578
char ** control_next_app_args(struct stasis_app_control *control)
Returns the list of arguments to pass to the application we are moving to.
Definition control.c:1773
int control_is_done(struct stasis_app_control *control)
Returns true if control_continue() has been called on this control.
Definition control.c:363
void control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
Definition control.c:1545
int control_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all commands enqueued to this control.
Definition control.c:1558
int control_next_app_args_size(struct stasis_app_control *control)
Returns the number of arguments to be passed to the application we are moving to.
Definition control.c:1778
void control_set_app(struct stasis_app_control *control, struct stasis_app *app)
Set the application the control object belongs to.
Definition control.c:1754
void control_silence_stop_now(struct stasis_app_control *control)
Stop playing silence to a channel right now.
Definition control.c:889
char * control_next_app(struct stasis_app_control *control)
Returns the name of the application we are moving to.
Definition control.c:1760
struct stasis_app * control_app(struct stasis_app_control *control)
Returns the pointer (non-reffed) to the app associated with this control.
Definition control.c:1626
void control_move_cleanup(struct stasis_app_control *control)
Free any memory that was allocated for switching applications via /channels/{channelId}/move.
Definition control.c:1765
void control_mark_done(struct stasis_app_control *control)
Definition control.c:369
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_frame_dtor(struct ast_frame *frame)
NULL-safe wrapper for ast_frfree, good for RAII_VAR.
Definition main/frame.c:187
@ AST_FRAME_CONTROL
@ AST_CONTROL_HANGUP
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition json.c:278
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition json.c:378
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition json.c:612
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition json.c:670
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition json.c:407
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
Execute the PBX in the current thread.
Definition pbx.c:3295
const char * app_name(struct ast_app *app)
Definition pbx_app.c:475
int app_subscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge)
Add a bridge subscription to an existing channel subscription.
int app_unsubscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge)
Cancel the bridge subscription for an application.
int app_is_active(struct stasis_app *app)
Checks whether an app is active.
void app_send(struct stasis_app *app, struct ast_json *message)
Send a message to an application.
static int send_start_msg(struct stasis_app *app, struct ast_channel *chan, int argc, char *argv[])
struct ao2_container * app_controls
Definition res_stasis.c:102
static void remove_stasis_end_published(struct ast_channel *chan)
static void cleanup(void)
Clean up any old apps that we don't need any more.
Definition res_stasis.c:327
static int add_masquerade_store(struct ast_channel *chan)
static int has_masquerade_store(struct ast_channel *chan)
int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
Send StasisEnd message to the listening app.
#define MAX_WAIT_MS
Definition res_stasis.c:77
static void remove_masquerade_store(struct ast_channel *chan)
struct ao2_container * apps_registry
Stasis application container.
Definition res_stasis.c:100
static void control_unlink(struct stasis_app_control *control)
In addition to running ao2_cleanup(), this function also removes the object from the app_controls con...
Definition res_stasis.c:818
int stasis_app_channel_is_stasis_end_published(struct ast_channel *chan)
Has this channel had a StasisEnd published on it?
#define NULL
Definition resample.c:96
int stasis_app_control_is_failed(const struct stasis_app_control *control)
Check if a control object is marked as "failed".
Definition control.c:382
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
Definition control.c:983
const char * stasis_app_name(const struct stasis_app *app)
Retrieve an application's name.
struct ast_json * ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_channel_snapshot.
Structure that contains information about a bridge.
Definition bridge.h:355
Structure representing a snapshot of channel state.
Data structure associated with a single frame of data.
Abstract JSON element (object, array, string, int, ...).
Options for ast_pbx_run()
Definition pbx.h:409
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
#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:981
#define ast_assert(a)
Definition utils.h:779

References add_masquerade_store(), ao2_bump, ao2_cleanup, ao2_find, ao2_link, ao2_ref, app, app_controls, app_is_active(), app_name(), app_send(), app_send_end_msg(), app_subscribe_bridge(), app_unsubscribe_bridge(), apps_registry, ast_assert, ast_bridge_depart(), ast_channel_clear_softhangup(), ast_channel_fdno(), ast_channel_internal_bridge_channel(), ast_channel_lock, ast_channel_name(), ast_channel_pbx(), ast_channel_snapshot_get_latest(), ast_channel_snapshot_to_json(), ast_channel_uniqueid(), ast_channel_unlock, ast_check_hangup(), ast_check_hangup_locked(), AST_CONTROL_HANGUP, ast_debug, AST_FRAME_CONTROL, ast_frame_dtor(), ast_free, ast_json_array_append(), ast_json_object_get(), ast_json_pack(), ast_json_string_create(), ast_json_timeval(), ast_json_unref(), ast_log, ast_pbx_run_args(), ast_read(), AST_SOFTHANGUP_ASYNCGOTO, ast_tvnow(), ast_waitfor(), cleanup(), control_app(), control_create(), control_dispatch_all(), control_flush_queue(), control_is_done(), control_mark_done(), control_move_cleanup(), control_next_app(), control_next_app_args(), control_next_app_args_size(), control_prestart_dispatch_all(), control_set_app(), control_silence_stop_now(), control_unlink(), control_wait(), has_masquerade_store(), LOG_ERROR, MAX_WAIT_MS, ast_pbx_args::no_hangup_chan, NULL, OBJ_SEARCH_KEY, RAII_VAR, remove_masquerade_store(), remove_stasis_end_published(), send_start_msg(), stasis_app_channel_is_stasis_end_published(), stasis_app_control_is_failed(), stasis_app_get_bridge(), and stasis_app_name().

Referenced by app_exec(), and stasis_broadcast_exec().

◆ stasis_app_send_command()

int stasis_app_send_command ( struct stasis_app_control control,
stasis_app_command_cb  command,
void *  data,
command_data_destructor_fn  data_destructor 
)

Invokes a command on a control's channel.

Since
12

This function dispatches the command to be executed in the context of stasis_app_exec(), so this command will block waiting for the results of the command.

Parameters
controlControl object for the channel to send the command to.
commandCommand function to execute.
dataOptional data to pass along with the control function.
data_destructorOptional function which will be called on the data in either the event of command completion or failure to schedule or complete the command
Returns
zero on success.
error code otherwise.

Definition at line 950 of file control.c.

952{
953 return app_send_command_on_condition(control, command_fn, data, data_destructor, NULL);
954}
static int app_send_command_on_condition(struct stasis_app_control *control, stasis_app_command_cb command_fn, void *data, command_data_destructor_fn data_destructor, app_command_can_exec_cb can_exec_fn)
Definition control.c:918

References app_send_command_on_condition(), stasis_app_command::data, stasis_app_command::data_destructor, and NULL.

Referenced by ast_ari_bridges_set_video_source(), stasis_app_control_answer(), and stasis_app_control_set_channel_var_reportable().

◆ stasis_app_send_command_async()

int stasis_app_send_command_async ( struct stasis_app_control control,
stasis_app_command_cb  command,
void *  data,
command_data_destructor_fn  data_destructor 
)

Asynchronous version of stasis_app_send_command().

Since
12

This function enqueues a command for execution, but returns immediately without waiting for the response.

Parameters
controlControl object for the channel to send the command to.
commandCommand function to execute.
dataOptional data to pass along with the control function.
data_destructorOptional function which will be called on the data in either the event of command completion or failure to schedule or complete the command
Returns
0 on success.
Non-zero on error.

Definition at line 956 of file control.c.

959{
960 struct stasis_app_command *command;
961
962 if (control == NULL || control->is_done) {
963 /* If exec_command fails, it calls the data_destructor. In order to
964 * provide consistent behavior, we'll also call the data_destructor
965 * on this error path. This way, callers never have to call the
966 * data_destructor themselves.
967 */
968 if (data_destructor) {
970 }
971 return -1;
972 }
973
974 command = exec_command(control, command_fn, data, data_destructor);
975 if (!command) {
976 return -1;
977 }
978 ao2_ref(command, -1);
979
980 return 0;
981}
static struct stasis_app_command * exec_command(struct stasis_app_control *control, stasis_app_command_cb command_fn, void *data, command_data_destructor_fn data_destructor)
Definition control.c:316
command_data_destructor_fn data_destructor
Definition command.c:38
unsigned int is_done
Definition control.c:105

References ao2_ref, stasis_app_command::data, stasis_app_command::data_destructor, exec_command(), stasis_app_control::is_done, and NULL.

Referenced by bridge_timeout(), dial_bridge_after_cb(), internal_bridge_after_cb(), stasis_app_control_add_role(), stasis_app_control_clear_roles(), stasis_app_control_continue(), stasis_app_control_dial(), stasis_app_control_dtmf(), stasis_app_control_hold(), stasis_app_control_moh_start(), stasis_app_control_moh_stop(), stasis_app_control_move(), stasis_app_control_mute(), stasis_app_control_play_uri(), stasis_app_control_progress(), stasis_app_control_record(), stasis_app_control_redirect(), stasis_app_control_ring(), stasis_app_control_ring_stop(), stasis_app_control_silence_start(), stasis_app_control_silence_stop(), stasis_app_control_unhold(), and stasis_app_control_unmute().