implement TXTCIDNAME as a dialplan function and mark the application deprecated
[asterisk/asterisk.git] / devicestate.c
index 0474f5d..c85f9a8 100755 (executable)
@@ -1,12 +1,25 @@
 /*
- * Asterisk -- A telephony toolkit for Linux.
+ * Asterisk -- An open source telephony toolkit.
  *
- * Device state management
- * 
- * Copyright (C) 2005, Digium, Inc.
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
  *
  * This program is free software, distributed under the terms of
- * the GNU General Public License
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*
+ *
+ * Device state management
+ * 
  */
 
 #include <sys/types.h>
@@ -27,6 +40,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/pbx.h"
 #include "asterisk/options.h"
 
+static const char *devstatestring[] = {
+       /* 0 AST_DEVICE_UNKNOWN */      "Unknown",      /* Valid, but unknown state */
+       /* 1 AST_DEVICE_NOT_INUSE */    "Not in use",   /* Not used */
+       /* 2 AST_DEVICE IN USE */       "In use",       /* In use */
+       /* 3 AST_DEVICE_BUSY */         "Busy",         /* Busy */
+       /* 4 AST_DEVICE_INVALID */      "Invalid",      /* Invalid - not known to Asterisk */
+       /* 5 AST_DEVICE_UNAVAILABLE */  "Unavailable",  /* Unavailable (not registred) */
+       /* 6 AST_DEVICE_RINGING */      "Ringing"       /* Ring, ring, ring */
+};
+
 /* ast_devstate_cb: A device state watcher (callback) */
 struct devstate_cb {
        void *data;
@@ -46,6 +69,13 @@ static AST_LIST_HEAD_STATIC(state_changes, state_change);
 static pthread_t change_thread = AST_PTHREADT_NULL;
 static pthread_cond_t change_pending;
 
+/*--- devstate2str: Find devicestate as text message for output */
+const char *devstate2str(int devstate) 
+{
+       return devstatestring[devstate];
+}
+
+/*--- ast_parse_device_state: Find out if device is active in a call or not */
 int ast_parse_device_state(const char *device)
 {
        struct ast_channel *chan;
@@ -69,6 +99,7 @@ int ast_parse_device_state(const char *device)
        return res;
 }
 
+/*--- ast_device_state: Check device state through channel specific function or generic function */
 int ast_device_state(const char *device)
 {
        char *buf;
@@ -81,19 +112,26 @@ int ast_device_state(const char *device)
        tech = strsep(&buf, "/");
        number = buf;
        if (!number)
-           return AST_DEVICE_INVALID;
+               return AST_DEVICE_INVALID;
                
        chan_tech = ast_get_channel_tech(tech);
        if (!chan_tech)
                return AST_DEVICE_INVALID;
 
-       if (!chan_tech->devicestate) 
-               return ast_parse_device_state(device);
+       if (!chan_tech->devicestate)    /* Does the channel driver support device state notification? */
+               return ast_parse_device_state(device);  /* No, try the generic function */
        else {
-               res = chan_tech->devicestate(number);
-               if (res == AST_DEVICE_UNKNOWN)
-                       return ast_parse_device_state(device);
-               else
+               res = chan_tech->devicestate(number);   /* Ask the channel driver for device state */
+               if (res == AST_DEVICE_UNKNOWN) {
+                       res = ast_parse_device_state(device);
+                       /* at this point we know the device exists, but the channel driver
+                          could not give us a state; if there is no channel state available,
+                          it must be 'not in use'
+                       */
+                       if (res == AST_DEVICE_UNKNOWN)
+                               res = AST_DEVICE_NOT_INUSE;
+                       return res;
+               } else
                        return res;
        }
 }
@@ -145,7 +183,7 @@ static void do_state_change(const char *device)
 
        state = ast_device_state(device);
        if (option_debug > 2)
-               ast_log(LOG_DEBUG, "Changing state for %s - state %d\n", device, state);
+               ast_log(LOG_DEBUG, "Changing state for %s - state %d (%s)\n", device, state, devstate2str(state));
 
        AST_LIST_LOCK(&devstate_cbs);
        AST_LIST_TRAVERSE(&devstate_cbs, devcb, list)
@@ -155,21 +193,14 @@ static void do_state_change(const char *device)
        ast_hint_state_changed(device);
 }
 
-int ast_device_state_changed(const char *fmt, ...) 
+static int __ast_device_state_changed_literal(char *buf)
 {
-       char buf[AST_MAX_EXTENSION];
        char *device;
        char *parse;
        struct state_change *change = NULL;
-       va_list ap;
-
-       va_start(ap, fmt);
-       vsnprintf(buf, sizeof(buf), fmt, ap);
-       va_end(ap);
 
        parse = buf;
        device = strsep(&parse, "-");
-
        if (change_thread != AST_PTHREADT_NULL)
                change = calloc(1, sizeof(*change) + strlen(device));
 
@@ -191,7 +222,27 @@ int ast_device_state_changed(const char *fmt, ...)
        return 1;
 }
 
-static void *do_changes(void *data)
+int ast_device_state_changed_literal(const char *dev)
+{
+       char *buf;
+       buf = ast_strdupa(dev);
+       return __ast_device_state_changed_literal(buf);
+}
+
+/*--- ast_device_state_changed: Accept change notification, add it to change queue */
+int ast_device_state_changed(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_device_state_changed_literal(buf);
+}
+
+/*--- do_devstate_changes: Go through the dev state change queue and update changes in the dev state thread */
+static void *do_devstate_changes(void *data)
 {
        struct state_change *cur;
 
@@ -208,13 +259,14 @@ static void *do_changes(void *data)
                } else {
                        /* there was no entry, so atomically unlock the list and wait for
                           the condition to be signalled (returns with the lock held) */
-                       pthread_cond_wait(&change_pending, &state_changes.lock);
+                       ast_pthread_cond_wait(&change_pending, &state_changes.lock);
                }
        }
 
        return NULL;
 }
 
+/*--- ast_device_state_engine_init: Initialize the device state engine in separate thread */
 int ast_device_state_engine_init(void)
 {
        pthread_attr_t attr;
@@ -222,7 +274,7 @@ int ast_device_state_engine_init(void)
        pthread_cond_init(&change_pending, NULL);
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-       if (ast_pthread_create(&change_thread, &attr, do_changes, NULL) < 0) {
+       if (ast_pthread_create(&change_thread, &attr, do_devstate_changes, NULL) < 0) {
                ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
                return -1;
        }