aboutsummaryrefslogtreecommitdiffstats
path: root/main/devicestate.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/devicestate.c')
-rw-r--r--main/devicestate.c110
1 files changed, 92 insertions, 18 deletions
diff --git a/main/devicestate.c b/main/devicestate.c
index 05a775227..aef21f70a 100644
--- a/main/devicestate.c
+++ b/main/devicestate.c
@@ -25,6 +25,7 @@
*
* \arg \ref AstExtState
*/
+
/*! \page AstExtState Extension and device states in Asterisk
*
* Asterisk has an internal system that reports states
@@ -166,6 +167,17 @@ static pthread_t change_thread = AST_PTHREADT_NULL;
/*! \brief Flag for the queue */
static ast_cond_t change_pending;
+/*! \brief Whether or not to cache this device state value */
+enum devstate_cache {
+ /*! Cache this value as it is coming from a device state provider which is
+ * pushing up state change events to us as they happen */
+ CACHE_ON,
+ /*! Don't cache this result, since it was pulled from the device state provider.
+ * We only want to cache results from device state providers that are being nice
+ * and pushing state change events up to us as they happen. */
+ CACHE_OFF,
+};
+
/* Forward declarations */
static int getproviderstate(const char *provider, const char *address);
@@ -261,18 +273,42 @@ enum ast_device_state ast_parse_device_state(const char *device)
return res;
}
+static enum ast_device_state devstate_cached(const char *device)
+{
+ enum ast_device_state res = AST_DEVICE_UNKNOWN;
+ struct ast_event *event;
+
+ event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
+ AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
+ AST_EVENT_IE_END);
+
+ if (!event)
+ return res;
+
+ res = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
+
+ ast_event_destroy(event);
+
+ return res;
+}
+
/*! \brief Check device state through channel specific function or generic function */
enum ast_device_state ast_device_state(const char *device)
{
char *buf;
char *number;
const struct ast_channel_tech *chan_tech;
- enum ast_device_state res = AST_DEVICE_UNKNOWN;
+ enum ast_device_state res;
/*! \brief Channel driver that provides device state */
char *tech;
/*! \brief Another provider of device state */
char *provider = NULL;
-
+
+ /* If the last known state is cached, just return that */
+ res = devstate_cached(device);
+ if (res != AST_DEVICE_UNKNOWN)
+ return res;
+
buf = ast_strdupa(device);
tech = strsep(&buf, "/");
if (!(number = buf)) {
@@ -368,17 +404,10 @@ static int getproviderstate(const char *provider, const char *address)
return res;
}
-/*! \brief Notify callback watchers of change, and notify PBX core for hint updates
- Normally executed within a separate thread
-*/
-static void do_state_change(const char *device)
+static void devstate_event(const char *device, enum ast_device_state state, enum devstate_cache cache)
{
- enum ast_device_state state;
struct ast_event *event;
- state = ast_device_state(device);
- ast_debug(3, "Changing state for %s - state %d (%s)\n", device, state, devstate2str(state));
-
if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE,
AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
@@ -386,12 +415,31 @@ static void do_state_change(const char *device)
return;
}
- ast_event_queue_and_cache(event,
- AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR,
- AST_EVENT_IE_END);
+ if (cache == CACHE_ON) {
+ /* Cache this event, replacing an event in the cache with the same
+ * device name if it exists. */
+ ast_event_queue_and_cache(event,
+ AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR,
+ AST_EVENT_IE_END);
+ } else {
+ ast_event_queue(event);
+ }
}
-static int __ast_device_state_changed_literal(char *buf)
+/*! Called by the state change thread to find out what the state is, and then
+ * to queue up the state change event */
+static void do_state_change(const char *device)
+{
+ enum ast_device_state state;
+
+ state = ast_device_state(device);
+
+ ast_debug(3, "Changing state for %s - state %d (%s)\n", device, state, devstate2str(state));
+
+ devstate_event(device, state, CACHE_OFF);
+}
+
+static int __ast_devstate_changed_literal(enum ast_device_state state, char *buf)
{
char *device;
struct state_change *change;
@@ -404,8 +452,10 @@ static int __ast_device_state_changed_literal(char *buf)
tmp = strrchr(device, '-');
if (tmp)
*tmp = '\0';
-
- if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
+
+ if (state != AST_DEVICE_UNKNOWN) {
+ devstate_event(device, state, CACHE_ON);
+ } else if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
/* we could not allocate a change struct, or */
/* there is no background thread, so process the change now */
do_state_change(device);
@@ -421,11 +471,34 @@ static int __ast_device_state_changed_literal(char *buf)
return 1;
}
+int ast_devstate_changed_literal(enum ast_device_state state, const char *dev)
+{
+ char *buf;
+
+ buf = ast_strdupa(dev);
+
+ return __ast_devstate_changed_literal(state, buf);
+}
+
int ast_device_state_changed_literal(const char *dev)
{
char *buf;
+
buf = ast_strdupa(dev);
- return __ast_device_state_changed_literal(buf);
+
+ return __ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, buf);
+}
+
+int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...)
+{
+ char buf[AST_MAX_EXTENSION];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ return __ast_devstate_changed_literal(state, buf);
}
/*! \brief Accept change notification, add it to change queue */
@@ -437,7 +510,8 @@ int ast_device_state_changed(const char *fmt, ...)
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
- return __ast_device_state_changed_literal(buf);
+
+ return __ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, buf);
}
/*! \brief Go through the dev state change queue and update changes in the dev state thread */