mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 12:36:58 +00:00
queue device state changes and handle them serially in a background thread
optimize device state related functions add ast_get_channel_by_name_prefix to allow searching for matching channels in O(1) operation git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6062 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
2
Makefile
2
Makefile
@@ -254,7 +254,7 @@ OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o \
|
||||
cdr.o tdd.o acl.o rtp.o manager.o asterisk.o \
|
||||
dsp.o chanvars.o indications.o autoservice.o db.o privacy.o \
|
||||
astmm.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \
|
||||
utils.o config_old.o plc.o jitterbuf.o dnsmgr.o
|
||||
utils.o config_old.o plc.o jitterbuf.o dnsmgr.o devicestate.o
|
||||
ifeq (${OSARCH},Darwin)
|
||||
OBJS+=poll.o dlfcn.o
|
||||
ASTLINK=-Wl,-dynamic
|
||||
|
@@ -31,6 +31,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/devicestate.h"
|
||||
|
||||
static char *tdesc = "Check if channel is available";
|
||||
|
||||
|
@@ -71,6 +71,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/causes.h"
|
||||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/devicestate.h"
|
||||
|
||||
#define QUEUE_STRATEGY_RINGALL 0
|
||||
#define QUEUE_STRATEGY_ROUNDROBIN 1
|
||||
|
@@ -65,6 +65,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/version.h"
|
||||
#include "asterisk/build.h"
|
||||
#include "asterisk/linkedlists.h"
|
||||
#include "asterisk/devicestate.h"
|
||||
|
||||
#include "defaults.h"
|
||||
|
||||
@@ -2095,6 +2096,10 @@ int main(int argc, char *argv[])
|
||||
printf(term_quit());
|
||||
exit(1);
|
||||
}
|
||||
if (ast_device_state_engine_init()) {
|
||||
printf(term_quit());
|
||||
exit(1);
|
||||
}
|
||||
ast_rtp_init();
|
||||
if (ast_image_init()) {
|
||||
printf(term_quit());
|
||||
|
170
channel.c
170
channel.c
@@ -57,6 +57,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/transcap.h"
|
||||
#include "asterisk/devicestate.h"
|
||||
|
||||
/* uncomment if you have problems with 'monitoring' synchronized files */
|
||||
#if 0
|
||||
@@ -295,6 +296,58 @@ int ast_channel_register(const struct ast_channel_tech *tech)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ast_channel_unregister(const struct ast_channel_tech *tech)
|
||||
{
|
||||
struct chanlist *chan, *last=NULL;
|
||||
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Unregistering channel type '%s'\n", tech->type);
|
||||
|
||||
ast_mutex_lock(&chlock);
|
||||
|
||||
chan = backends;
|
||||
while (chan) {
|
||||
if (chan->tech == tech) {
|
||||
if (last)
|
||||
last->next = chan->next;
|
||||
else
|
||||
backends = backends->next;
|
||||
free(chan);
|
||||
ast_mutex_unlock(&chlock);
|
||||
|
||||
if (option_verbose > 1)
|
||||
ast_verbose( VERBOSE_PREFIX_2 "Unregistered channel type '%s'\n", tech->type);
|
||||
|
||||
return;
|
||||
}
|
||||
last = chan;
|
||||
chan = chan->next;
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&chlock);
|
||||
}
|
||||
|
||||
const struct ast_channel_tech *ast_get_channel_tech(const char *name)
|
||||
{
|
||||
struct chanlist *chanls;
|
||||
|
||||
if (ast_mutex_lock(&chlock)) {
|
||||
ast_log(LOG_WARNING, "Unable to lock channel tech list\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (chanls = backends; chanls; chanls = chanls->next) {
|
||||
if (strcasecmp(name, chanls->tech->type))
|
||||
continue;
|
||||
|
||||
ast_mutex_unlock(&chlock);
|
||||
return chanls->tech;
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&chlock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*--- ast_cause2str: Gives the string form of a given hangup cause */
|
||||
const char *ast_cause2str(int cause)
|
||||
{
|
||||
@@ -605,7 +658,7 @@ void ast_channel_undefer_dtmf(struct ast_channel *chan)
|
||||
* We should definitely go for a better scheme that is deadlock-free.
|
||||
*/
|
||||
static struct ast_channel *channel_find_locked(const struct ast_channel *prev,
|
||||
const char *name)
|
||||
const char *name, const int namelen)
|
||||
{
|
||||
const char *msg = prev ? "deadlock" : "initial deadlock";
|
||||
int retries, done;
|
||||
@@ -615,8 +668,14 @@ static struct ast_channel *channel_find_locked(const struct ast_channel *prev,
|
||||
ast_mutex_lock(&chlock);
|
||||
for (c = channels; c; c = c->next) {
|
||||
if (prev == NULL) {
|
||||
/* want either head of list or match by name */
|
||||
if (name == NULL || !strcasecmp(name, c->name))
|
||||
/* want head of list */
|
||||
if (!name)
|
||||
break;
|
||||
/* want match by full name */
|
||||
if (!namelen && !strcasecmp(c->name, name))
|
||||
break;
|
||||
/* want match by name prefix */
|
||||
if (!strncasecmp(c->name, name, namelen))
|
||||
break;
|
||||
} else if (c == prev) { /* found, return c->next */
|
||||
c = c->next;
|
||||
@@ -646,13 +705,19 @@ static struct ast_channel *channel_find_locked(const struct ast_channel *prev,
|
||||
/*--- ast_channel_walk_locked: Browse channels in use */
|
||||
struct ast_channel *ast_channel_walk_locked(const struct ast_channel *prev)
|
||||
{
|
||||
return channel_find_locked(prev, NULL);
|
||||
return channel_find_locked(prev, NULL, 0);
|
||||
}
|
||||
|
||||
/*--- ast_get_channel_by_name_locked: Get channel by name and lock it */
|
||||
struct ast_channel *ast_get_channel_by_name_locked(const char *name)
|
||||
{
|
||||
return channel_find_locked(NULL, name);
|
||||
return channel_find_locked(NULL, name, 0);
|
||||
}
|
||||
|
||||
/*--- ast_get_channel_by_name_prefix_locked: Get channel by name prefix and lock it */
|
||||
struct ast_channel *ast_get_channel_by_name_prefix_locked(const char *name, const int namelen)
|
||||
{
|
||||
return channel_find_locked(NULL, name, namelen);
|
||||
}
|
||||
|
||||
/*--- ast_safe_sleep_conditional: Wait, look for hangups and condition arg */
|
||||
@@ -964,37 +1029,6 @@ int ast_hangup(struct ast_channel *chan)
|
||||
return res;
|
||||
}
|
||||
|
||||
void ast_channel_unregister(const struct ast_channel_tech *tech)
|
||||
{
|
||||
struct chanlist *chan, *last=NULL;
|
||||
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Unregistering channel type '%s'\n", tech->type);
|
||||
|
||||
ast_mutex_lock(&chlock);
|
||||
|
||||
chan = backends;
|
||||
while (chan) {
|
||||
if (chan->tech == tech) {
|
||||
if (last)
|
||||
last->next = chan->next;
|
||||
else
|
||||
backends = backends->next;
|
||||
free(chan);
|
||||
ast_mutex_unlock(&chlock);
|
||||
|
||||
if (option_verbose > 1)
|
||||
ast_verbose( VERBOSE_PREFIX_2 "Unregistered channel type '%s'\n", tech->type);
|
||||
|
||||
return;
|
||||
}
|
||||
last = chan;
|
||||
chan = chan->next;
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&chlock);
|
||||
}
|
||||
|
||||
int ast_answer(struct ast_channel *chan)
|
||||
{
|
||||
int res = 0;
|
||||
@@ -2167,70 +2201,6 @@ struct ast_channel *ast_request(const char *type, int format, void *data, int *c
|
||||
return c;
|
||||
}
|
||||
|
||||
int ast_parse_device_state(char *device)
|
||||
{
|
||||
char name[AST_CHANNEL_NAME] = "";
|
||||
char *cut;
|
||||
struct ast_channel *chan;
|
||||
|
||||
chan = ast_channel_walk_locked(NULL);
|
||||
while (chan) {
|
||||
ast_copy_string(name, chan->name, sizeof(name));
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
cut = strchr(name,'-');
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
if (!strcmp(name, device)) {
|
||||
if (chan->_state == AST_STATE_RINGING) {
|
||||
return AST_DEVICE_RINGING;
|
||||
} else {
|
||||
return AST_DEVICE_INUSE;
|
||||
}
|
||||
}
|
||||
chan = ast_channel_walk_locked(chan);
|
||||
}
|
||||
return AST_DEVICE_UNKNOWN;
|
||||
}
|
||||
|
||||
int ast_device_state(char *device)
|
||||
{
|
||||
char tech[AST_MAX_EXTENSION] = "";
|
||||
char *number;
|
||||
struct chanlist *chanls;
|
||||
int res = 0;
|
||||
|
||||
ast_copy_string(tech, device, sizeof(tech));
|
||||
number = strchr(tech, '/');
|
||||
if (!number) {
|
||||
return AST_DEVICE_INVALID;
|
||||
}
|
||||
*number = 0;
|
||||
number++;
|
||||
|
||||
if (ast_mutex_lock(&chlock)) {
|
||||
ast_log(LOG_WARNING, "Unable to lock channel list\n");
|
||||
return -1;
|
||||
}
|
||||
chanls = backends;
|
||||
while(chanls) {
|
||||
if (!strcasecmp(tech, chanls->tech->type)) {
|
||||
ast_mutex_unlock(&chlock);
|
||||
if (!chanls->tech->devicestate)
|
||||
return ast_parse_device_state(device);
|
||||
else {
|
||||
res = chanls->tech->devicestate(number);
|
||||
if (res == AST_DEVICE_UNKNOWN)
|
||||
return ast_parse_device_state(device);
|
||||
else
|
||||
return res;
|
||||
}
|
||||
}
|
||||
chanls = chanls->next;
|
||||
}
|
||||
ast_mutex_unlock(&chlock);
|
||||
return AST_DEVICE_INVALID;
|
||||
}
|
||||
|
||||
int ast_call(struct ast_channel *chan, char *addr, int timeout)
|
||||
{
|
||||
/* Place an outgoing call, but don't wait any longer than timeout ms before returning.
|
||||
|
@@ -49,6 +49,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/causes.h"
|
||||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/devicestate.h"
|
||||
|
||||
static const char desc[] = "Agent Proxy Channel";
|
||||
static const char channeltype[] = "Agent";
|
||||
|
@@ -42,6 +42,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/localtime.h"
|
||||
#include "asterisk/aes.h"
|
||||
#include "asterisk/dnsmgr.h"
|
||||
#include "asterisk/devicestate.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <dirent.h>
|
||||
@@ -73,7 +75,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "iax2.h"
|
||||
#include "iax2-parser.h"
|
||||
#include "iax2-provision.h"
|
||||
#include "asterisk.h"
|
||||
|
||||
/* Define NEWJB to use the new channel independent jitterbuffer,
|
||||
* otherwise, use the old jitterbuffer */
|
||||
|
@@ -62,6 +62,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/astobj.h"
|
||||
#include "asterisk/dnsmgr.h"
|
||||
#include "asterisk/devicestate.h"
|
||||
#ifdef OSP_SUPPORT
|
||||
#include "asterisk/astosp.h"
|
||||
#endif
|
||||
|
@@ -444,21 +444,6 @@ struct outgoing_helper {
|
||||
/*! Do not transmit voice data */
|
||||
#define AST_STATE_MUTE (1 << 16)
|
||||
|
||||
/*! Device is valid but channel didn't know state */
|
||||
#define AST_DEVICE_UNKNOWN 0
|
||||
/*! Device is not used */
|
||||
#define AST_DEVICE_NOT_INUSE 1
|
||||
/*! Device is in use */
|
||||
#define AST_DEVICE_INUSE 2
|
||||
/*! Device is busy */
|
||||
#define AST_DEVICE_BUSY 3
|
||||
/*! Device is invalid */
|
||||
#define AST_DEVICE_INVALID 4
|
||||
/*! Device is unavailable */
|
||||
#define AST_DEVICE_UNAVAILABLE 5
|
||||
/*! Device is ringing */
|
||||
#define AST_DEVICE_RINGING 6
|
||||
|
||||
/*! Create a channel structure */
|
||||
/*! Returns NULL on failure to allocate. New channels are
|
||||
by default set to the "default" context and
|
||||
@@ -494,27 +479,6 @@ void ast_channel_free(struct ast_channel *);
|
||||
*/
|
||||
struct ast_channel *ast_request(const char *type, int format, void *data, int *status);
|
||||
|
||||
/*! Search the Channels by Name */
|
||||
/*!
|
||||
* \param device like a dialstring
|
||||
* Search the Device in active channels by compare the channelname against
|
||||
* the devicename. Compared are only the first chars to the first '-' char.
|
||||
* Returns an AST_DEVICE_UNKNOWN if no channel found or
|
||||
* AST_DEVICE_INUSE if a channel is found
|
||||
*/
|
||||
int ast_parse_device_state(char *device);
|
||||
|
||||
/*! Asks a channel for device state */
|
||||
/*!
|
||||
* \param device like a dialstring
|
||||
* Asks a channel for device state, data is normaly a number from dialstring
|
||||
* used by the low level module
|
||||
* Trys the channel devicestate callback if not supported search in the
|
||||
* active channels list for the device.
|
||||
* Returns an AST_DEVICE_??? state -1 on failure
|
||||
*/
|
||||
int ast_device_state(char *device);
|
||||
|
||||
/*!
|
||||
* \param type type of channel to request
|
||||
* \param format requested channel format
|
||||
@@ -545,6 +509,12 @@ int ast_channel_register(const struct ast_channel_tech *tech);
|
||||
*/
|
||||
void ast_channel_unregister(const struct ast_channel_tech *tech);
|
||||
|
||||
/*! Get a channel technology structure by name
|
||||
* \param name name of technology to find
|
||||
* \return a pointer to the structure, or NULL if no matching technology found
|
||||
*/
|
||||
const struct ast_channel_tech *ast_get_channel_tech(const char *name);
|
||||
|
||||
/*! Hang up a channel */
|
||||
/*!
|
||||
* \param chan channel to hang up
|
||||
@@ -759,6 +729,9 @@ struct ast_channel *ast_channel_walk_locked(const struct ast_channel *prev);
|
||||
/*! Get channel by name (locks channel) */
|
||||
struct ast_channel *ast_get_channel_by_name_locked(const char *chan);
|
||||
|
||||
/*! Get channel by name prefix (locks channel) */
|
||||
struct ast_channel *ast_get_channel_by_name_prefix_locked(const char *name, const int namelen);
|
||||
|
||||
/*! Waits for a digit */
|
||||
/*!
|
||||
* \param c channel to wait for a digit on
|
||||
|
@@ -306,11 +306,13 @@ struct { \
|
||||
used to link entries of this list together.
|
||||
|
||||
Removes the head entry from the list, and returns a pointer to it. The
|
||||
forward-link pointer in the returned entry is \b not cleared.
|
||||
forward-link pointer in the returned entry is \b not cleared. This macro
|
||||
is safe to call on an empty list.
|
||||
*/
|
||||
#define AST_LIST_REMOVE_HEAD(head, field) ({ \
|
||||
typeof((head)->first) cur = (head)->first; \
|
||||
(head)->first = (head)->first->field.next; \
|
||||
if (cur) \
|
||||
(head)->first = cur->field.next; \
|
||||
cur; \
|
||||
})
|
||||
|
||||
|
@@ -51,8 +51,6 @@ struct ast_sw;
|
||||
|
||||
typedef int (*ast_state_cb_type)(char *context, char* id, int state, void *data);
|
||||
|
||||
typedef int (*ast_devstate_cb_type)(const char *dev, int state, void *data);
|
||||
|
||||
/*! Data structure associated with a custom function */
|
||||
struct ast_custom_function {
|
||||
char *name;
|
||||
@@ -253,16 +251,6 @@ int ast_unregister_application(const char *app);
|
||||
*/
|
||||
int ast_extension_state(struct ast_channel *c, char *context, char *exten);
|
||||
|
||||
/*! Tells Asterisk the State for Device is changed */
|
||||
/*!
|
||||
* \param fmt devicename like a dialstring with format parameters
|
||||
* Asterisk polls the new extensionstates and calls the registered
|
||||
* callbacks for the changed extensions
|
||||
* Returns 0 on success, -1 on failure
|
||||
*/
|
||||
int ast_device_state_changed(const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
/*! Registers a state change callback */
|
||||
/*!
|
||||
* \param context which context to look in
|
||||
@@ -275,15 +263,6 @@ int ast_device_state_changed(const char *fmt, ...)
|
||||
int ast_extension_state_add(const char *context, const char *exten,
|
||||
ast_state_cb_type callback, void *data);
|
||||
|
||||
/*! Registers a device state change callback */
|
||||
/*!
|
||||
* \param data to pass to callback
|
||||
* The callback is called if the state for extension is changed
|
||||
* Return -1 on failure, ID on success
|
||||
*/
|
||||
int ast_devstate_add(ast_devstate_cb_type callback, void *data);
|
||||
void ast_devstate_del(ast_devstate_cb_type callback, void *data);
|
||||
|
||||
/*! Deletes a registered state change callback by ID */
|
||||
/*!
|
||||
* \param id of the callback to delete
|
||||
@@ -629,6 +608,8 @@ char *ast_func_read(struct ast_channel *chan, const char *in, char *workspace, s
|
||||
*/
|
||||
void ast_func_write(struct ast_channel *chan, const char *in, const char *value);
|
||||
|
||||
void ast_hint_state_changed(const char *device);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
}
|
||||
#endif
|
||||
|
146
pbx.c
146
pbx.c
@@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/causes.h"
|
||||
#include "asterisk/musiconhold.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/devicestate.h"
|
||||
|
||||
/*
|
||||
* I M P O R T A N T :
|
||||
@@ -160,15 +161,6 @@ struct ast_state_cb {
|
||||
struct ast_state_cb *next;
|
||||
};
|
||||
|
||||
/* ast_devstate_cb: An extension state notify */
|
||||
struct ast_devstate_cb {
|
||||
void *data;
|
||||
ast_devstate_cb_type callback;
|
||||
struct ast_devstate_cb *next;
|
||||
};
|
||||
|
||||
static struct ast_devstate_cb *devcbs;
|
||||
|
||||
/* Hints are pointers from an extension in the dialplan to one or more devices (tech/name) */
|
||||
struct ast_hint {
|
||||
struct ast_exten *exten; /* Extension */
|
||||
@@ -1805,130 +1797,48 @@ int ast_extension_state(struct ast_channel *c, char *context, char *exten)
|
||||
return ast_extension_state2(e); /* Check all devices in the hint */
|
||||
}
|
||||
|
||||
/*--- ast_device_state_changed: If device state in cblist is changed - then notify callback function */
|
||||
int ast_device_state_changed(const char *fmt, ...)
|
||||
void ast_hint_state_changed(const char *device)
|
||||
{
|
||||
struct ast_hint *list;
|
||||
struct ast_hint *hint;
|
||||
struct ast_state_cb *cblist;
|
||||
struct ast_devstate_cb *devcb;
|
||||
char hint[AST_MAX_EXTENSION] = "";
|
||||
char device[AST_MAX_EXTENSION];
|
||||
|
||||
char *cur, *rest;
|
||||
char buf[AST_MAX_EXTENSION];
|
||||
char *parse;
|
||||
char *cur;
|
||||
int state;
|
||||
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(device, sizeof(device), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
rest = strchr(device, '-');
|
||||
if (rest) {
|
||||
*rest = 0;
|
||||
}
|
||||
|
||||
|
||||
state = ast_device_state(device);
|
||||
if (option_debug > 2)
|
||||
ast_log(LOG_DEBUG, "Changing state for %s - state %d\n", device, state);
|
||||
|
||||
ast_mutex_lock(&hintlock);
|
||||
|
||||
/* First check device callbacks */
|
||||
devcb = devcbs;
|
||||
while(devcb) {
|
||||
if (devcb->callback)
|
||||
devcb->callback(device, state, devcb->data);
|
||||
devcb = devcb->next;
|
||||
}
|
||||
for (hint = hints; hint; hint = hint->next) {
|
||||
ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
|
||||
parse = buf;
|
||||
for (cur = strsep(&parse, "&"); cur; cur = strsep(&parse, "&")) {
|
||||
if (strcmp(cur, device))
|
||||
continue;
|
||||
|
||||
/* Then check callbacks in hints */
|
||||
list = hints;
|
||||
|
||||
while (list) {
|
||||
|
||||
ast_copy_string(hint, ast_get_extension_app(list->exten), sizeof(hint));
|
||||
cur = hint;
|
||||
do {
|
||||
rest = strchr(cur, '&');
|
||||
if (rest) {
|
||||
*rest = 0;
|
||||
rest++;
|
||||
}
|
||||
/* Get device state for this hint */
|
||||
state = ast_extension_state2(hint->exten);
|
||||
|
||||
if (!strcmp(cur, device)) { /* Is this device referred to in this hint? */
|
||||
if ((state == -1) || (state == hint->laststate))
|
||||
continue;
|
||||
|
||||
/* Get device state for this hint */
|
||||
state = ast_extension_state2(list->exten);
|
||||
|
||||
if ((state != -1) && (state != list->laststate)) {
|
||||
/* Device state changed since last check - notify the watcher */
|
||||
|
||||
/* For general callbacks */
|
||||
cblist = statecbs;
|
||||
while (cblist) {
|
||||
cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
|
||||
cblist = cblist->next;
|
||||
}
|
||||
|
||||
/* For extension callbacks */
|
||||
cblist = list->callbacks;
|
||||
while (cblist) {
|
||||
cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
|
||||
cblist = cblist->next;
|
||||
}
|
||||
/* Device state changed since last check - notify the watchers */
|
||||
|
||||
list->laststate = state;
|
||||
}
|
||||
break;
|
||||
}
|
||||
cur = rest;
|
||||
} while (cur);
|
||||
list = list->next;
|
||||
}
|
||||
ast_mutex_unlock(&hintlock);
|
||||
return 1;
|
||||
}
|
||||
/* For general callbacks */
|
||||
for (cblist = statecbs; cblist; cblist = cblist->next)
|
||||
cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
|
||||
|
||||
/*--- ast_devstate_add: Add device state watcher */
|
||||
int ast_devstate_add(ast_devstate_cb_type callback, void *data)
|
||||
{
|
||||
struct ast_devstate_cb *devcb;
|
||||
devcb = malloc(sizeof(struct ast_devstate_cb));
|
||||
if (devcb) {
|
||||
memset(devcb, 0, sizeof(struct ast_devstate_cb));
|
||||
ast_mutex_lock(&hintlock);
|
||||
devcb->data = data;
|
||||
devcb->callback = callback;
|
||||
devcb->next = devcbs;
|
||||
devcbs = devcb;
|
||||
ast_mutex_unlock(&hintlock);
|
||||
/* For extension callbacks */
|
||||
for (cblist = hint->callbacks; cblist; cblist = cblist->next)
|
||||
cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
|
||||
|
||||
hint->laststate = state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*--- ast_devstate_del: Remove device state watcher */
|
||||
void ast_devstate_del(ast_devstate_cb_type callback, void *data)
|
||||
{
|
||||
struct ast_devstate_cb *devcb, *prev = NULL, *next;
|
||||
ast_mutex_lock(&hintlock);
|
||||
devcb = devcbs;
|
||||
while(devcb) {
|
||||
next = devcb->next;
|
||||
if ((devcb->data == data) && (devcb->callback == callback)) {
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
else
|
||||
devcbs = next;
|
||||
free(devcb);
|
||||
} else
|
||||
prev = devcb;
|
||||
devcb = next;
|
||||
}
|
||||
ast_mutex_unlock(&hintlock);
|
||||
}
|
||||
|
||||
|
||||
/*--- ast_extension_state_add: Add watcher for extension states */
|
||||
int ast_extension_state_add(const char *context, const char *exten,
|
||||
ast_state_cb_type callback, void *data)
|
||||
|
Reference in New Issue
Block a user