00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 #include "asterisk.h"
00117
00118 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 205414 $")
00119
00120 #include "asterisk/_private.h"
00121 #include "asterisk/channel.h"
00122 #include "asterisk/utils.h"
00123 #include "asterisk/lock.h"
00124 #include "asterisk/linkedlists.h"
00125 #include "asterisk/devicestate.h"
00126 #include "asterisk/pbx.h"
00127 #include "asterisk/app.h"
00128 #include "asterisk/event.h"
00129
00130
00131 static const char *devstatestring[] = {
00132 "Unknown",
00133 "Not in use",
00134 "In use",
00135 "Busy",
00136 "Invalid",
00137 "Unavailable",
00138 "Ringing",
00139 "Ring+Inuse",
00140 "On Hold"
00141 };
00142
00143
00144 static const struct chan2dev {
00145 enum ast_channel_state chan;
00146 enum ast_device_state dev;
00147 } chan2dev[] = {
00148 { AST_STATE_DOWN, AST_DEVICE_NOT_INUSE },
00149 { AST_STATE_RESERVED, AST_DEVICE_INUSE },
00150 { AST_STATE_OFFHOOK, AST_DEVICE_INUSE },
00151 { AST_STATE_DIALING, AST_DEVICE_INUSE },
00152 { AST_STATE_RING, AST_DEVICE_INUSE },
00153 { AST_STATE_RINGING, AST_DEVICE_RINGING },
00154 { AST_STATE_UP, AST_DEVICE_INUSE },
00155 { AST_STATE_BUSY, AST_DEVICE_BUSY },
00156 { AST_STATE_DIALING_OFFHOOK, AST_DEVICE_INUSE },
00157 { AST_STATE_PRERING, AST_DEVICE_RINGING },
00158 { -100, -100 },
00159 };
00160
00161
00162 struct devstate_prov {
00163 char label[40];
00164 ast_devstate_prov_cb_type callback;
00165 AST_RWLIST_ENTRY(devstate_prov) list;
00166 };
00167
00168
00169 static AST_RWLIST_HEAD_STATIC(devstate_provs, devstate_prov);
00170
00171 struct state_change {
00172 AST_LIST_ENTRY(state_change) list;
00173 char device[1];
00174 };
00175
00176
00177
00178 static AST_LIST_HEAD_STATIC(state_changes, state_change);
00179
00180
00181 static pthread_t change_thread = AST_PTHREADT_NULL;
00182
00183
00184 static ast_cond_t change_pending;
00185
00186 struct devstate_change {
00187 AST_LIST_ENTRY(devstate_change) entry;
00188 uint32_t state;
00189 struct ast_eid eid;
00190 char device[1];
00191 };
00192
00193 struct {
00194 pthread_t thread;
00195 struct ast_event_sub *event_sub;
00196 ast_cond_t cond;
00197 ast_mutex_t lock;
00198 AST_LIST_HEAD_NOLOCK(, devstate_change) devstate_change_q;
00199 unsigned int enabled:1;
00200 } devstate_collector = {
00201 .thread = AST_PTHREADT_NULL,
00202 .enabled = 0,
00203 };
00204
00205
00206 static int getproviderstate(const char *provider, const char *address);
00207
00208
00209 const char *devstate2str(enum ast_device_state devstate)
00210 {
00211 return devstatestring[devstate];
00212 }
00213
00214 enum ast_device_state ast_state_chan2dev(enum ast_channel_state chanstate)
00215 {
00216 int i;
00217 chanstate &= 0xFFFF;
00218 for (i = 0; chan2dev[i].chan != -100; i++) {
00219 if (chan2dev[i].chan == chanstate) {
00220 return chan2dev[i].dev;
00221 }
00222 }
00223 return AST_DEVICE_UNKNOWN;
00224 }
00225
00226 const char *ast_devstate_str(enum ast_device_state state)
00227 {
00228 const char *res = "UNKNOWN";
00229
00230 switch (state) {
00231 case AST_DEVICE_UNKNOWN:
00232 break;
00233 case AST_DEVICE_NOT_INUSE:
00234 res = "NOT_INUSE";
00235 break;
00236 case AST_DEVICE_INUSE:
00237 res = "INUSE";
00238 break;
00239 case AST_DEVICE_BUSY:
00240 res = "BUSY";
00241 break;
00242 case AST_DEVICE_INVALID:
00243 res = "INVALID";
00244 break;
00245 case AST_DEVICE_UNAVAILABLE:
00246 res = "UNAVAILABLE";
00247 break;
00248 case AST_DEVICE_RINGING:
00249 res = "RINGING";
00250 break;
00251 case AST_DEVICE_RINGINUSE:
00252 res = "RINGINUSE";
00253 break;
00254 case AST_DEVICE_ONHOLD:
00255 res = "ONHOLD";
00256 break;
00257 case AST_DEVICE_TOTAL:
00258 break;
00259 }
00260
00261 return res;
00262 }
00263
00264 enum ast_device_state ast_devstate_val(const char *val)
00265 {
00266 if (!strcasecmp(val, "NOT_INUSE"))
00267 return AST_DEVICE_NOT_INUSE;
00268 else if (!strcasecmp(val, "INUSE"))
00269 return AST_DEVICE_INUSE;
00270 else if (!strcasecmp(val, "BUSY"))
00271 return AST_DEVICE_BUSY;
00272 else if (!strcasecmp(val, "INVALID"))
00273 return AST_DEVICE_INVALID;
00274 else if (!strcasecmp(val, "UNAVAILABLE"))
00275 return AST_DEVICE_UNAVAILABLE;
00276 else if (!strcasecmp(val, "RINGING"))
00277 return AST_DEVICE_RINGING;
00278 else if (!strcasecmp(val, "RINGINUSE"))
00279 return AST_DEVICE_RINGINUSE;
00280 else if (!strcasecmp(val, "ONHOLD"))
00281 return AST_DEVICE_ONHOLD;
00282
00283 return AST_DEVICE_UNKNOWN;
00284 }
00285
00286
00287
00288
00289
00290
00291 enum ast_device_state ast_parse_device_state(const char *device)
00292 {
00293 struct ast_channel *chan;
00294 char match[AST_CHANNEL_NAME];
00295 enum ast_device_state res;
00296
00297 ast_copy_string(match, device, sizeof(match)-1);
00298 strcat(match, "-");
00299 chan = ast_get_channel_by_name_prefix_locked(match, strlen(match));
00300
00301 if (!chan)
00302 return AST_DEVICE_UNKNOWN;
00303
00304 if (chan->_state == AST_STATE_RINGING)
00305 res = AST_DEVICE_RINGING;
00306 else
00307 res = AST_DEVICE_INUSE;
00308
00309 ast_channel_unlock(chan);
00310
00311 return res;
00312 }
00313
00314 static enum ast_device_state devstate_cached(const char *device)
00315 {
00316 enum ast_device_state res = AST_DEVICE_UNKNOWN;
00317 struct ast_event *event;
00318
00319 event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
00320 AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00321 AST_EVENT_IE_END);
00322
00323 if (!event)
00324 return res;
00325
00326 res = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00327
00328 ast_event_destroy(event);
00329
00330 return res;
00331 }
00332
00333
00334 static enum ast_device_state _ast_device_state(const char *device, int check_cache)
00335 {
00336 char *buf;
00337 char *number;
00338 const struct ast_channel_tech *chan_tech;
00339 enum ast_device_state res;
00340
00341 char *tech;
00342
00343 char *provider = NULL;
00344
00345
00346 if (check_cache) {
00347 res = devstate_cached(device);
00348 if (res != AST_DEVICE_UNKNOWN) {
00349 return res;
00350 }
00351 }
00352
00353 buf = ast_strdupa(device);
00354 tech = strsep(&buf, "/");
00355 if (!(number = buf)) {
00356 if (!(provider = strsep(&tech, ":")))
00357 return AST_DEVICE_INVALID;
00358
00359 number = tech;
00360 tech = NULL;
00361 }
00362
00363 if (provider) {
00364 ast_debug(3, "Checking if I can find provider for \"%s\" - number: %s\n", provider, number);
00365 return getproviderstate(provider, number);
00366 }
00367
00368 ast_debug(4, "No provider found, checking channel drivers for %s - %s\n", tech, number);
00369
00370 if (!(chan_tech = ast_get_channel_tech(tech)))
00371 return AST_DEVICE_INVALID;
00372
00373 if (!(chan_tech->devicestate))
00374 return ast_parse_device_state(device);
00375
00376 res = chan_tech->devicestate(number);
00377
00378 if (res != AST_DEVICE_UNKNOWN)
00379 return res;
00380
00381 res = ast_parse_device_state(device);
00382
00383 return res;
00384 }
00385
00386 enum ast_device_state ast_device_state(const char *device)
00387 {
00388
00389
00390
00391 return _ast_device_state(device, 1);
00392 }
00393
00394
00395 int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
00396 {
00397 struct devstate_prov *devprov;
00398
00399 if (!callback || !(devprov = ast_calloc(1, sizeof(*devprov))))
00400 return -1;
00401
00402 devprov->callback = callback;
00403 ast_copy_string(devprov->label, label, sizeof(devprov->label));
00404
00405 AST_RWLIST_WRLOCK(&devstate_provs);
00406 AST_RWLIST_INSERT_HEAD(&devstate_provs, devprov, list);
00407 AST_RWLIST_UNLOCK(&devstate_provs);
00408
00409 return 0;
00410 }
00411
00412
00413 int ast_devstate_prov_del(const char *label)
00414 {
00415 struct devstate_prov *devcb;
00416 int res = -1;
00417
00418 AST_RWLIST_WRLOCK(&devstate_provs);
00419 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&devstate_provs, devcb, list) {
00420 if (!strcasecmp(devcb->label, label)) {
00421 AST_RWLIST_REMOVE_CURRENT(list);
00422 ast_free(devcb);
00423 res = 0;
00424 break;
00425 }
00426 }
00427 AST_RWLIST_TRAVERSE_SAFE_END;
00428 AST_RWLIST_UNLOCK(&devstate_provs);
00429
00430 return res;
00431 }
00432
00433
00434 static int getproviderstate(const char *provider, const char *address)
00435 {
00436 struct devstate_prov *devprov;
00437 int res = AST_DEVICE_INVALID;
00438
00439 AST_RWLIST_RDLOCK(&devstate_provs);
00440 AST_RWLIST_TRAVERSE(&devstate_provs, devprov, list) {
00441 ast_debug(5, "Checking provider %s with %s\n", devprov->label, provider);
00442
00443 if (!strcasecmp(devprov->label, provider)) {
00444 res = devprov->callback(address);
00445 break;
00446 }
00447 }
00448 AST_RWLIST_UNLOCK(&devstate_provs);
00449
00450 return res;
00451 }
00452
00453 static void devstate_event(const char *device, enum ast_device_state state)
00454 {
00455 struct ast_event *event;
00456 enum ast_event_type event_type;
00457
00458 if (devstate_collector.enabled) {
00459
00460
00461 event_type = AST_EVENT_DEVICE_STATE_CHANGE;
00462 } else {
00463 event_type = AST_EVENT_DEVICE_STATE;
00464 }
00465
00466 ast_debug(3, "device '%s' state '%d'\n", device, state);
00467
00468 if (!(event = ast_event_new(event_type,
00469 AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00470 AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
00471 AST_EVENT_IE_END))) {
00472 return;
00473 }
00474
00475 ast_event_queue_and_cache(event);
00476 }
00477
00478
00479
00480 static void do_state_change(const char *device)
00481 {
00482 enum ast_device_state state;
00483
00484 state = _ast_device_state(device, 0);
00485
00486 ast_debug(3, "Changing state for %s - state %d (%s)\n", device, state, devstate2str(state));
00487
00488 devstate_event(device, state);
00489 }
00490
00491 int ast_devstate_changed_literal(enum ast_device_state state, const char *device)
00492 {
00493 struct state_change *change;
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511 if (state != AST_DEVICE_UNKNOWN) {
00512 devstate_event(device, state);
00513 } else if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
00514
00515
00516 do_state_change(device);
00517 } else {
00518
00519 strcpy(change->device, device);
00520 AST_LIST_LOCK(&state_changes);
00521 AST_LIST_INSERT_TAIL(&state_changes, change, list);
00522 ast_cond_signal(&change_pending);
00523 AST_LIST_UNLOCK(&state_changes);
00524 }
00525
00526 return 1;
00527 }
00528
00529 int ast_device_state_changed_literal(const char *dev)
00530 {
00531 return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, dev);
00532 }
00533
00534 int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...)
00535 {
00536 char buf[AST_MAX_EXTENSION];
00537 va_list ap;
00538
00539 va_start(ap, fmt);
00540 vsnprintf(buf, sizeof(buf), fmt, ap);
00541 va_end(ap);
00542
00543 return ast_devstate_changed_literal(state, buf);
00544 }
00545
00546 int ast_device_state_changed(const char *fmt, ...)
00547 {
00548 char buf[AST_MAX_EXTENSION];
00549 va_list ap;
00550
00551 va_start(ap, fmt);
00552 vsnprintf(buf, sizeof(buf), fmt, ap);
00553 va_end(ap);
00554
00555 return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, buf);
00556 }
00557
00558
00559 static void *do_devstate_changes(void *data)
00560 {
00561 struct state_change *next, *current;
00562
00563 for (;;) {
00564
00565 AST_LIST_LOCK(&state_changes);
00566 if (AST_LIST_EMPTY(&state_changes))
00567 ast_cond_wait(&change_pending, &state_changes.lock);
00568 next = AST_LIST_FIRST(&state_changes);
00569 AST_LIST_HEAD_INIT_NOLOCK(&state_changes);
00570 AST_LIST_UNLOCK(&state_changes);
00571
00572
00573 while ((current = next)) {
00574 next = AST_LIST_NEXT(current, list);
00575 do_state_change(current->device);
00576 ast_free(current);
00577 }
00578 }
00579
00580 return NULL;
00581 }
00582
00583 static void destroy_devstate_change(struct devstate_change *sc)
00584 {
00585 ast_free(sc);
00586 }
00587
00588 #define MAX_SERVERS 64
00589 struct change_collection {
00590 struct devstate_change states[MAX_SERVERS];
00591 size_t num_states;
00592 };
00593
00594 static void devstate_cache_cb(const struct ast_event *event, void *data)
00595 {
00596 struct change_collection *collection = data;
00597 int i;
00598 const struct ast_eid *eid;
00599
00600 if (collection->num_states == ARRAY_LEN(collection->states)) {
00601 ast_log(LOG_ERROR, "More per-server state values than we have room for (MAX_SERVERS is %d)\n",
00602 MAX_SERVERS);
00603 return;
00604 }
00605
00606 if (!(eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID))) {
00607 ast_log(LOG_ERROR, "Device state change event with no EID\n");
00608 return;
00609 }
00610
00611 i = collection->num_states;
00612
00613 collection->states[i].state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00614 collection->states[i].eid = *eid;
00615
00616 collection->num_states++;
00617 }
00618
00619 static void process_collection(const char *device, struct change_collection *collection)
00620 {
00621 int i;
00622 struct ast_devstate_aggregate agg;
00623 enum ast_device_state state;
00624 struct ast_event *event;
00625
00626 ast_devstate_aggregate_init(&agg);
00627
00628 for (i = 0; i < collection->num_states; i++) {
00629 ast_debug(1, "Adding per-server state of '%s' for '%s'\n",
00630 devstate2str(collection->states[i].state), device);
00631 ast_devstate_aggregate_add(&agg, collection->states[i].state);
00632 }
00633
00634 state = ast_devstate_aggregate_result(&agg);
00635
00636 ast_debug(1, "Aggregate devstate result is %d\n", state);
00637
00638 event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
00639 AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00640 AST_EVENT_IE_END);
00641
00642 if (event) {
00643 enum ast_device_state old_state;
00644
00645 old_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00646
00647 ast_event_destroy(event);
00648
00649 if (state == old_state) {
00650
00651 ast_debug(1, "Aggregate state for device '%s' has not changed from '%s'\n",
00652 device, devstate2str(state));
00653 return;
00654 }
00655 }
00656
00657 ast_debug(1, "Aggregate state for device '%s' has changed to '%s'\n",
00658 device, devstate2str(state));
00659
00660 event = ast_event_new(AST_EVENT_DEVICE_STATE,
00661 AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00662 AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
00663 AST_EVENT_IE_END);
00664
00665 if (!event) {
00666 return;
00667 }
00668
00669 ast_event_queue_and_cache(event);
00670 }
00671
00672 static void handle_devstate_change(struct devstate_change *sc)
00673 {
00674 struct ast_event_sub *tmp_sub;
00675 struct change_collection collection = {
00676 .num_states = 0,
00677 };
00678
00679 ast_debug(1, "Processing device state change for '%s'\n", sc->device);
00680
00681 if (!(tmp_sub = ast_event_subscribe_new(AST_EVENT_DEVICE_STATE_CHANGE, devstate_cache_cb, &collection))) {
00682 ast_log(LOG_ERROR, "Failed to create subscription\n");
00683 return;
00684 }
00685
00686 if (ast_event_sub_append_ie_str(tmp_sub, AST_EVENT_IE_DEVICE, sc->device)) {
00687 ast_log(LOG_ERROR, "Failed to append device IE\n");
00688 ast_event_sub_destroy(tmp_sub);
00689 return;
00690 }
00691
00692
00693 ast_event_dump_cache(tmp_sub);
00694
00695 process_collection(sc->device, &collection);
00696
00697 ast_event_sub_destroy(tmp_sub);
00698 }
00699
00700 static void *run_devstate_collector(void *data)
00701 {
00702 for (;;) {
00703 struct devstate_change *sc;
00704
00705 ast_mutex_lock(&devstate_collector.lock);
00706 while (!(sc = AST_LIST_REMOVE_HEAD(&devstate_collector.devstate_change_q, entry)))
00707 ast_cond_wait(&devstate_collector.cond, &devstate_collector.lock);
00708 ast_mutex_unlock(&devstate_collector.lock);
00709
00710 handle_devstate_change(sc);
00711
00712 destroy_devstate_change(sc);
00713 }
00714
00715 return NULL;
00716 }
00717
00718 static void devstate_change_collector_cb(const struct ast_event *event, void *data)
00719 {
00720 struct devstate_change *sc;
00721 const char *device;
00722 const struct ast_eid *eid;
00723 uint32_t state;
00724
00725 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
00726 eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
00727 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00728
00729 if (ast_strlen_zero(device) || !eid) {
00730 ast_log(LOG_ERROR, "Invalid device state change event received\n");
00731 return;
00732 }
00733
00734 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device))))
00735 return;
00736
00737 strcpy(sc->device, device);
00738 sc->eid = *eid;
00739 sc->state = state;
00740
00741 ast_mutex_lock(&devstate_collector.lock);
00742 AST_LIST_INSERT_TAIL(&devstate_collector.devstate_change_q, sc, entry);
00743 ast_cond_signal(&devstate_collector.cond);
00744 ast_mutex_unlock(&devstate_collector.lock);
00745 }
00746
00747
00748 int ast_device_state_engine_init(void)
00749 {
00750 ast_cond_init(&change_pending, NULL);
00751 if (ast_pthread_create_background(&change_thread, NULL, do_devstate_changes, NULL) < 0) {
00752 ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
00753 return -1;
00754 }
00755
00756 return 0;
00757 }
00758
00759 void ast_devstate_aggregate_init(struct ast_devstate_aggregate *agg)
00760 {
00761 memset(agg, 0, sizeof(*agg));
00762
00763 agg->all_unknown = 1;
00764 agg->all_unavail = 1;
00765 agg->all_busy = 1;
00766 agg->all_free = 1;
00767 }
00768
00769 void ast_devstate_aggregate_add(struct ast_devstate_aggregate *agg, enum ast_device_state state)
00770 {
00771 switch (state) {
00772 case AST_DEVICE_NOT_INUSE:
00773 agg->all_unknown = 0;
00774 agg->all_unavail = 0;
00775 agg->all_busy = 0;
00776 break;
00777 case AST_DEVICE_INUSE:
00778 agg->in_use = 1;
00779 agg->all_unavail = 0;
00780 agg->all_free = 0;
00781 agg->all_unknown = 0;
00782 break;
00783 case AST_DEVICE_RINGING:
00784 agg->ring = 1;
00785 agg->all_unavail = 0;
00786 agg->all_free = 0;
00787 agg->all_unknown = 0;
00788 break;
00789 case AST_DEVICE_RINGINUSE:
00790 agg->in_use = 1;
00791 agg->ring = 1;
00792 agg->all_unavail = 0;
00793 agg->all_free = 0;
00794 agg->all_unknown = 0;
00795 break;
00796 case AST_DEVICE_ONHOLD:
00797 agg->all_unknown = 0;
00798 agg->all_unavail = 0;
00799 agg->all_free = 0;
00800 agg->on_hold = 1;
00801 break;
00802 case AST_DEVICE_BUSY:
00803 agg->all_unknown = 0;
00804 agg->all_unavail = 0;
00805 agg->all_free = 0;
00806 agg->busy = 1;
00807 agg->in_use = 1;
00808 break;
00809 case AST_DEVICE_UNAVAILABLE:
00810 agg->all_unknown = 0;
00811 case AST_DEVICE_INVALID:
00812 agg->all_busy = 0;
00813 agg->all_free = 0;
00814 break;
00815 case AST_DEVICE_UNKNOWN:
00816 agg->all_busy = 0;
00817 agg->all_free = 0;
00818 break;
00819 case AST_DEVICE_TOTAL:
00820 break;
00821 }
00822 }
00823
00824
00825 enum ast_device_state ast_devstate_aggregate_result(struct ast_devstate_aggregate *agg)
00826 {
00827 if (agg->all_free)
00828 return AST_DEVICE_NOT_INUSE;
00829 if ((agg->in_use || agg->on_hold) && agg->ring)
00830 return AST_DEVICE_RINGINUSE;
00831 if (agg->ring)
00832 return AST_DEVICE_RINGING;
00833 if (agg->busy)
00834 return AST_DEVICE_BUSY;
00835 if (agg->in_use)
00836 return AST_DEVICE_INUSE;
00837 if (agg->on_hold)
00838 return AST_DEVICE_ONHOLD;
00839 if (agg->all_busy)
00840 return AST_DEVICE_BUSY;
00841 if (agg->all_unknown)
00842 return AST_DEVICE_UNKNOWN;
00843 if (agg->all_unavail)
00844 return AST_DEVICE_UNAVAILABLE;
00845
00846 return AST_DEVICE_NOT_INUSE;
00847 }
00848
00849 int ast_enable_distributed_devstate(void)
00850 {
00851 if (devstate_collector.enabled) {
00852 return 0;
00853 }
00854
00855 devstate_collector.event_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
00856 devstate_change_collector_cb, NULL, AST_EVENT_IE_END);
00857
00858 if (!devstate_collector.event_sub) {
00859 ast_log(LOG_ERROR, "Failed to create subscription for the device state change collector\n");
00860 return -1;
00861 }
00862
00863 ast_mutex_init(&devstate_collector.lock);
00864 ast_cond_init(&devstate_collector.cond, NULL);
00865 if (ast_pthread_create_background(&devstate_collector.thread, NULL, run_devstate_collector, NULL) < 0) {
00866 ast_log(LOG_ERROR, "Unable to start device state collector thread.\n");
00867 return -1;
00868 }
00869
00870 devstate_collector.enabled = 1;
00871
00872 return 0;
00873 }