Asterisk - The Open Source Telephony Project  18.5.0
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. More...
 
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. More...
 
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. More...
 
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(). More...
 

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.

Parameters
dataData to destroy.

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.

Returns
Nothing

Definition at line 62 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 65 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.

/brief Stasis dialplan application callback

Definition at line 1324 of file res_stasis.c.

References add_masquerade_store(), ao2_bump, ao2_cleanup, ao2_find, ao2_link, ao2_ref, app, app_is_active(), app_send(), app_send_end_msg(), app_subscribe_bridge(), app_unsubscribe_bridge(), 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_get_bridge(), and stasis_app_name().

Referenced by app_exec().

1326 {
1327  RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
1328  RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
1329  struct ast_bridge *bridge = NULL;
1330  int res = 0;
1331  int needs_depart;
1332 
1333  ast_assert(chan != NULL);
1334 
1335  /* Just in case there's a lingering indication that the channel has had a stasis
1336  * end published on it, remove that now.
1337  */
1339 
1340  if (!apps_registry) {
1341  return -1;
1342  }
1343 
1345  if (!app) {
1347  "Stasis app '%s' not registered\n", app_name);
1348  return -1;
1349  }
1350  if (!app_is_active(app)) {
1352  "Stasis app '%s' not active\n", app_name);
1353  return -1;
1354  }
1355 
1356  control = control_create(chan, app);
1357  if (!control) {
1358  ast_log(LOG_ERROR, "Control allocation failed or Stasis app '%s' not registered\n", app_name);
1359  return -1;
1360  }
1361 
1362  if (!control_app(control)) {
1363  ast_log(LOG_ERROR, "Stasis app '%s' not registered\n", app_name);
1364  return -1;
1365  }
1366 
1367  if (!app_is_active(control_app(control))) {
1368  ast_log(LOG_ERROR, "Stasis app '%s' not active\n", app_name);
1369  return -1;
1370  }
1371  ao2_link(app_controls, control);
1372 
1373  if (add_masquerade_store(chan)) {
1374  ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1375  return -1;
1376  }
1377 
1378  res = send_start_msg(control_app(control), chan, argc, argv);
1379  if (res != 0) {
1381  "Error sending start message to '%s'\n", app_name);
1383  return -1;
1384  }
1385 
1386  /* Pull queued prestart commands and execute */
1387  control_prestart_dispatch_all(control, chan);
1388 
1389  while (!control_is_done(control)) {
1390  RAII_VAR(struct ast_frame *, f, NULL, ast_frame_dtor);
1391  int r;
1392  int command_count;
1393  RAII_VAR(struct ast_bridge *, last_bridge, NULL, ao2_cleanup);
1394 
1395  /* Check to see if a bridge absorbed our hangup frame */
1396  if (ast_check_hangup_locked(chan)) {
1397  control_mark_done(control);
1398  break;
1399  }
1400 
1401  /* control->next_app is only modified within the control thread, so this is safe */
1402  if (control_next_app(control)) {
1403  struct stasis_app *next_app = ao2_find(apps_registry, control_next_app(control), OBJ_SEARCH_KEY);
1404 
1405  if (next_app && app_is_active(next_app)) {
1406  int idx;
1407  int next_argc;
1408  char **next_argv;
1409 
1410  /* If something goes wrong in this conditional, res will need to be non-zero
1411  * so that the code below the exec loop knows something went wrong during a move.
1412  */
1414  res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1415  if (res != 0) {
1417  "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1418  control_mark_done(control);
1419  ao2_ref(next_app, -1);
1420  break;
1421  }
1422  } else {
1424  }
1425 
1426  /* This will ao2_bump next_app, and unref the previous app by 1 */
1427  control_set_app(control, next_app);
1428 
1429  /* There's a chance that the previous application is ready for clean up, so go ahead
1430  * and do that now.
1431  */
1432  cleanup();
1433 
1434  /* We need to add another masquerade store, otherwise the leave message will
1435  * not show up for the correct application.
1436  */
1437  if (add_masquerade_store(chan)) {
1438  ast_log(LOG_ERROR, "Failed to attach masquerade detector\n");
1439  res = -1;
1440  control_mark_done(control);
1441  ao2_ref(next_app, -1);
1442  break;
1443  }
1444 
1445  /* We MUST get the size before the list, as control_next_app_args steals the elements
1446  * from the string vector.
1447  */
1448  next_argc = control_next_app_args_size(control);
1449  next_argv = control_next_app_args(control);
1450 
1451  res = send_start_msg(control_app(control), chan, next_argc, next_argv);
1452 
1453  /* Even if res != 0, we still need to free the memory we got from control_argv */
1454  if (next_argv) {
1455  for (idx = 0; idx < next_argc; idx++) {
1456  ast_free(next_argv[idx]);
1457  }
1458  ast_free(next_argv);
1459  }
1460 
1461  if (res != 0) {
1463  "Error sending start message to '%s'\n", stasis_app_name(control_app(control)));
1465  control_mark_done(control);
1466  ao2_ref(next_app, -1);
1467  break;
1468  }
1469 
1470  /* Done switching applications, free memory and clean up */
1471  control_move_cleanup(control);
1472  } else {
1473  /* If we can't switch applications, do nothing */
1474  struct ast_json *msg;
1475  RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
1476 
1477  if (!next_app) {
1478  ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not registered\n",
1479  control_next_app(control));
1480  } else {
1481  ast_log(LOG_ERROR, "Could not move to Stasis app '%s' - not active\n",
1482  control_next_app(control));
1483  }
1484 
1486  if (!snapshot) {
1487  ast_log(LOG_ERROR, "Could not get channel shapshot for '%s'\n",
1488  ast_channel_name(chan));
1489  } else {
1490  struct ast_json *json_args;
1491  int next_argc = control_next_app_args_size(control);
1492  char **next_argv = control_next_app_args(control);
1493 
1494  msg = ast_json_pack("{s: s, s: o, s: o, s: s, s: []}",
1495  "type", "ApplicationMoveFailed",
1496  "timestamp", ast_json_timeval(ast_tvnow(), NULL),
1497  "channel", ast_channel_snapshot_to_json(snapshot, NULL),
1498  "destination", control_next_app(control),
1499  "args");
1500  if (!msg) {
1501  ast_log(LOG_ERROR, "Failed to pack JSON for ApplicationMoveFailed message\n");
1502  } else {
1503  json_args = ast_json_object_get(msg, "args");
1504  if (!json_args) {
1505  ast_log(LOG_ERROR, "Could not get args json array");
1506  } else {
1507  int r = 0;
1508  int idx;
1509  for (idx = 0; idx < next_argc; ++idx) {
1510  r = ast_json_array_append(json_args,
1511  ast_json_string_create(next_argv[idx]));
1512  if (r != 0) {
1513  ast_log(LOG_ERROR, "Error appending to ApplicationMoveFailed message\n");
1514  break;
1515  }
1516  }
1517  if (r == 0) {
1518  app_send(control_app(control), msg);
1519  }
1520  }
1521  ast_json_unref(msg);
1522  }
1523  }
1524  }
1525  control_move_cleanup(control);
1526  ao2_cleanup(next_app);
1527  }
1528 
1529  last_bridge = bridge;
1530  bridge = ao2_bump(stasis_app_get_bridge(control));
1531 
1532  if (bridge != last_bridge) {
1533  if (last_bridge) {
1534  app_unsubscribe_bridge(control_app(control), last_bridge);
1535  }
1536  if (bridge) {
1537  app_subscribe_bridge(control_app(control), bridge);
1538  }
1539  }
1540 
1541  if (bridge) {
1542  /* Bridge/dial is handling channel frames */
1543  control_wait(control);
1544  control_dispatch_all(control, chan);
1545  continue;
1546  }
1547 
1548  r = ast_waitfor(chan, MAX_WAIT_MS);
1549 
1550  if (r < 0) {
1551  ast_debug(3, "%s: Poll error\n",
1552  ast_channel_uniqueid(chan));
1553  control_mark_done(control);
1554  break;
1555  }
1556 
1557  command_count = control_dispatch_all(control, chan);
1558 
1559  if (command_count > 0 && ast_channel_fdno(chan) == -1) {
1560  /* Command drained the channel; wait for next frame */
1561  continue;
1562  }
1563 
1564  if (r == 0) {
1565  /* Timeout */
1566  continue;
1567  }
1568 
1569  f = ast_read(chan);
1570  if (!f) {
1571  /* Continue on in the dialplan */
1572  ast_debug(3, "%s: Hangup (no more frames)\n",
1573  ast_channel_uniqueid(chan));
1574  control_mark_done(control);
1575  break;
1576  }
1577 
1578  if (f->frametype == AST_FRAME_CONTROL) {
1579  if (f->subclass.integer == AST_CONTROL_HANGUP) {
1580  /* Continue on in the dialplan */
1581  ast_debug(3, "%s: Hangup\n",
1582  ast_channel_uniqueid(chan));
1583  control_mark_done(control);
1584  break;
1585  }
1586  }
1587  }
1588 
1589  ast_channel_lock(chan);
1590  needs_depart = (ast_channel_internal_bridge_channel(chan) != NULL);
1591  ast_channel_unlock(chan);
1592  if (needs_depart) {
1593  ast_bridge_depart(chan);
1594  }
1595 
1596  if (stasis_app_get_bridge(control)) {
1598  }
1599  ao2_cleanup(bridge);
1600 
1601  /* Only publish a stasis_end event if it hasn't already been published */
1602  if (!res && !stasis_app_channel_is_stasis_end_published(chan)) {
1603  /* A masquerade has occurred and this message will be wrong so it
1604  * has already been sent elsewhere. */
1605  res = has_masquerade_store(chan) && app_send_end_msg(control_app(control), chan);
1606  if (res != 0) {
1608  "Error sending end message to %s\n", stasis_app_name(control_app(control)));
1609  return res;
1610  }
1611  } else {
1613  }
1614 
1615  control_flush_queue(control);
1616 
1617  /* Stop any lingering silence generator */
1618  control_silence_stop_now(control);
1619 
1620  /* There's an off chance that app is ready for cleanup. Go ahead
1621  * and clean up, just in case
1622  */
1623  cleanup();
1624 
1625  /* The control needs to be removed from the controls container in
1626  * case a new PBX is started and ends up coming back into Stasis.
1627  */
1628  control_unlink(control);
1629  control = NULL;
1630 
1631  if (!res && !ast_channel_pbx(chan)) {
1632  int chan_hungup;
1633 
1634  /* The ASYNCGOTO softhangup flag may have broken the channel out of
1635  * its bridge to run dialplan, so if there's no pbx on the channel
1636  * let it run dialplan here. Otherwise, it will run when this
1637  * application exits. */
1638  ast_channel_lock(chan);
1640  chan_hungup = ast_check_hangup(chan);
1641  ast_channel_unlock(chan);
1642 
1643  if (!chan_hungup) {
1644  struct ast_pbx_args pbx_args;
1645 
1646  memset(&pbx_args, 0, sizeof(pbx_args));
1647  pbx_args.no_hangup_chan = 1;
1648 
1649  res = ast_pbx_run_args(chan, &pbx_args);
1650  }
1651  }
1652 
1653  return res;
1654 }
struct ast_bridge * stasis_app_get_bridge(struct stasis_app_control *control)
Gets the bridge currently associated with a control object.
Definition: control.c:931
Options for ast_pbx_run()
Definition: pbx.h:391
#define ast_channel_lock(chan)
Definition: channel.h:2945
char * control_next_app(struct stasis_app_control *control)
Returns the name of the application we are moving to.
Definition: control.c:1697
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:1710
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
void control_mark_done(struct stasis_app_control *control)
Definition: control.c:354
int ast_check_hangup_locked(struct ast_channel *chan)
Definition: channel.c:459
void control_flush_queue(struct stasis_app_control *control)
Flush the control command queue.
Definition: control.c:1482
Structure representing a snapshot of channel state.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
static int has_masquerade_store(struct ast_channel *chan)
Definition: res_stasis.c:1211
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define ast_assert(a)
Definition: utils.h:695
static void remove_masquerade_store(struct ast_channel *chan)
Definition: res_stasis.c:1236
#define NULL
Definition: resample.c:96
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:1563
int app_is_active(struct stasis_app *app)
Checks whether an app is active.
int control_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all commands enqueued to this control.
Definition: control.c:1495
int app_subscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge)
Add a bridge subscription to an existing channel subscription.
void ast_frame_dtor(struct ast_frame *frame)
NULL-safe wrapper for ast_frfree, good for RAII_VAR.
Definition: main/frame.c:187
struct ao2_container * app_controls
Definition: res_stasis.c:102
int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
Send StasisEnd message to the listening app.
Definition: res_stasis.c:1083
#define ao2_bump(obj)
Definition: astobj2.h:491
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static void cleanup(void)
Clean up any old apps that we don&#39;t need any more.
Definition: res_stasis.c:327
int stasis_app_channel_is_stasis_end_published(struct ast_channel *chan)
Has this channel had a StasisEnd published on it?
Definition: res_stasis.c:1299
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:1702
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2437
#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_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:268
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
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:4739
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:1715
const char * stasis_app_name(const struct stasis_app *app)
Retrieve an application&#39;s name.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
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:445
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition: json.c:649
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition: json.c:368
int ast_channel_fdno(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
Structure that contains information about a bridge.
Definition: bridge.h:357
static int send_start_msg(struct stasis_app *app, struct ast_channel *chan, int argc, char *argv[])
Definition: res_stasis.c:1057
void app_send(struct stasis_app *app, struct ast_json *message)
Send a message to the given application.
#define LOG_ERROR
Definition: logger.h:285
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
Definition: bridge.c:1952
struct stasis_app_control * control_create(struct ast_channel *channel, struct stasis_app *app)
Create a control object.
Definition: control.c:123
const char * app_name(struct ast_app *app)
Definition: pbx_app.c:463
#define ast_channel_unlock(chan)
Definition: channel.h:2946
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.
#define ast_free(a)
Definition: astmm.h:182
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:785
#define MAX_WAIT_MS
Definition: res_stasis.c:77
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
void control_set_app(struct stasis_app_control *control, struct stasis_app *app)
Set the application the control object belongs to.
Definition: control.c:1691
void control_silence_stop_now(struct stasis_app_control *control)
Stop playing silence to a channel right now.
Definition: control.c:837
int control_is_done(struct stasis_app_control *control)
Returns true if control_continue() has been called on this control.
Definition: control.c:348
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3171
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
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:397
int app_unsubscribe_bridge(struct stasis_app *app, struct ast_bridge *bridge)
Cancel the bridge subscription for an application.
struct ao2_container * apps_registry
Stasis application container.
Definition: res_stasis.c:100
const char * ast_channel_name(const struct ast_channel *chan)
Data structure associated with a single frame of data.
Abstract JSON element (object, array, string, int, ...).
static int add_masquerade_store(struct ast_channel *chan)
Definition: res_stasis.c:1217
static const char app[]
Definition: app_mysql.c:62
static void remove_stasis_end_published(struct ast_channel *chan)
Definition: res_stasis.c:1310
int control_prestart_dispatch_all(struct stasis_app_control *control, struct ast_channel *chan)
Dispatch all queued prestart commands.
Definition: control.c:1535
void control_wait(struct stasis_app_control *control)
Blocks until control&#39;s command queue has a command available.
Definition: control.c:1515
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ 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 898 of file control.c.

References app_send_command_on_condition(), and NULL.

Referenced by ast_ari_bridges_set_video_source(), and stasis_app_control_answer().

900 {
901  return app_send_command_on_condition(control, command_fn, data, data_destructor, NULL);
902 }
#define NULL
Definition: resample.c:96
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:866

◆ 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 904 of file control.c.

References ao2_ref, stasis_app_command::data_destructor, exec_command(), 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_record(), stasis_app_control_redirect(), stasis_app_control_ring(), stasis_app_control_ring_stop(), stasis_app_control_set_channel_var(), stasis_app_control_silence_start(), stasis_app_control_silence_stop(), stasis_app_control_unhold(), and stasis_app_control_unmute().

907 {
908  struct stasis_app_command *command;
909 
910  if (control == NULL || control->is_done) {
911  /* If exec_command fails, it calls the data_destructor. In order to
912  * provide consistent behavior, we'll also call the data_destructor
913  * on this error path. This way, callers never have to call the
914  * data_destructor themselves.
915  */
916  if (data_destructor) {
918  }
919  return -1;
920  }
921 
922  command = exec_command(control, command_fn, data, data_destructor);
923  if (!command) {
924  return -1;
925  }
926  ao2_ref(command, -1);
927 
928  return 0;
929 }
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:301
#define NULL
Definition: resample.c:96
command_data_destructor_fn data_destructor
Definition: command.c:38
#define ao2_ref(o, delta)
Definition: astobj2.h:464