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: 184342 $")
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 }
00258
00259 return res;
00260 }
00261
00262 enum ast_device_state ast_devstate_val(const char *val)
00263 {
00264 if (!strcasecmp(val, "NOT_INUSE"))
00265 return AST_DEVICE_NOT_INUSE;
00266 else if (!strcasecmp(val, "INUSE"))
00267 return AST_DEVICE_INUSE;
00268 else if (!strcasecmp(val, "BUSY"))
00269 return AST_DEVICE_BUSY;
00270 else if (!strcasecmp(val, "INVALID"))
00271 return AST_DEVICE_INVALID;
00272 else if (!strcasecmp(val, "UNAVAILABLE"))
00273 return AST_DEVICE_UNAVAILABLE;
00274 else if (!strcasecmp(val, "RINGING"))
00275 return AST_DEVICE_RINGING;
00276 else if (!strcasecmp(val, "RINGINUSE"))
00277 return AST_DEVICE_RINGINUSE;
00278 else if (!strcasecmp(val, "ONHOLD"))
00279 return AST_DEVICE_ONHOLD;
00280
00281 return AST_DEVICE_UNKNOWN;
00282 }
00283
00284
00285
00286
00287
00288
00289 enum ast_device_state ast_parse_device_state(const char *device)
00290 {
00291 struct ast_channel *chan;
00292 char match[AST_CHANNEL_NAME];
00293 enum ast_device_state res;
00294
00295 ast_copy_string(match, device, sizeof(match)-1);
00296 strcat(match, "-");
00297 chan = ast_get_channel_by_name_prefix_locked(match, strlen(match));
00298
00299 if (!chan)
00300 return AST_DEVICE_UNKNOWN;
00301
00302 if (chan->_state == AST_STATE_RINGING)
00303 res = AST_DEVICE_RINGING;
00304 else
00305 res = AST_DEVICE_INUSE;
00306
00307 ast_channel_unlock(chan);
00308
00309 return res;
00310 }
00311
00312 static enum ast_device_state devstate_cached(const char *device)
00313 {
00314 enum ast_device_state res = AST_DEVICE_UNKNOWN;
00315 struct ast_event *event;
00316
00317 event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
00318 AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00319 AST_EVENT_IE_END);
00320
00321 if (!event)
00322 return res;
00323
00324 res = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00325
00326 ast_event_destroy(event);
00327
00328 return res;
00329 }
00330
00331
00332 static enum ast_device_state _ast_device_state(const char *device, int check_cache)
00333 {
00334 char *buf;
00335 char *number;
00336 const struct ast_channel_tech *chan_tech;
00337 enum ast_device_state res;
00338
00339 char *tech;
00340
00341 char *provider = NULL;
00342
00343
00344 if (check_cache) {
00345 res = devstate_cached(device);
00346 if (res != AST_DEVICE_UNKNOWN) {
00347 return res;
00348 }
00349 }
00350
00351 buf = ast_strdupa(device);
00352 tech = strsep(&buf, "/");
00353 if (!(number = buf)) {
00354 if (!(provider = strsep(&tech, ":")))
00355 return AST_DEVICE_INVALID;
00356
00357 number = tech;
00358 tech = NULL;
00359 }
00360
00361 if (provider) {
00362 ast_debug(3, "Checking if I can find provider for \"%s\" - number: %s\n", provider, number);
00363 return getproviderstate(provider, number);
00364 }
00365
00366 ast_debug(4, "No provider found, checking channel drivers for %s - %s\n", tech, number);
00367
00368 if (!(chan_tech = ast_get_channel_tech(tech)))
00369 return AST_DEVICE_INVALID;
00370
00371 if (!(chan_tech->devicestate))
00372 return ast_parse_device_state(device);
00373
00374 res = chan_tech->devicestate(number);
00375
00376 if (res != AST_DEVICE_UNKNOWN)
00377 return res;
00378
00379 res = ast_parse_device_state(device);
00380
00381 if (res == AST_DEVICE_UNKNOWN)
00382 return AST_DEVICE_NOT_INUSE;
00383
00384 return res;
00385 }
00386
00387 enum ast_device_state ast_device_state(const char *device)
00388 {
00389
00390
00391
00392 return _ast_device_state(device, 1);
00393 }
00394
00395
00396 int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
00397 {
00398 struct devstate_prov *devprov;
00399
00400 if (!callback || !(devprov = ast_calloc(1, sizeof(*devprov))))
00401 return -1;
00402
00403 devprov->callback = callback;
00404 ast_copy_string(devprov->label, label, sizeof(devprov->label));
00405
00406 AST_RWLIST_WRLOCK(&devstate_provs);
00407 AST_RWLIST_INSERT_HEAD(&devstate_provs, devprov, list);
00408 AST_RWLIST_UNLOCK(&devstate_provs);
00409
00410 return 0;
00411 }
00412
00413
00414 int ast_devstate_prov_del(const char *label)
00415 {
00416 struct devstate_prov *devcb;
00417 int res = -1;
00418
00419 AST_RWLIST_WRLOCK(&devstate_provs);
00420 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&devstate_provs, devcb, list) {
00421 if (!strcasecmp(devcb->label, label)) {
00422 AST_RWLIST_REMOVE_CURRENT(list);
00423 ast_free(devcb);
00424 res = 0;
00425 break;
00426 }
00427 }
00428 AST_RWLIST_TRAVERSE_SAFE_END;
00429 AST_RWLIST_UNLOCK(&devstate_provs);
00430
00431 return res;
00432 }
00433
00434
00435 static int getproviderstate(const char *provider, const char *address)
00436 {
00437 struct devstate_prov *devprov;
00438 int res = AST_DEVICE_INVALID;
00439
00440 AST_RWLIST_RDLOCK(&devstate_provs);
00441 AST_RWLIST_TRAVERSE(&devstate_provs, devprov, list) {
00442 ast_debug(5, "Checking provider %s with %s\n", devprov->label, provider);
00443
00444 if (!strcasecmp(devprov->label, provider)) {
00445 res = devprov->callback(address);
00446 break;
00447 }
00448 }
00449 AST_RWLIST_UNLOCK(&devstate_provs);
00450
00451 return res;
00452 }
00453
00454 static void devstate_event(const char *device, enum ast_device_state state)
00455 {
00456 struct ast_event *event;
00457 enum ast_event_type event_type;
00458
00459 if (devstate_collector.enabled) {
00460
00461
00462 event_type = AST_EVENT_DEVICE_STATE_CHANGE;
00463 } else {
00464 event_type = AST_EVENT_DEVICE_STATE;
00465 }
00466
00467 ast_debug(3, "device '%s' state '%d'\n", device, state);
00468
00469 if (!(event = ast_event_new(event_type,
00470 AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00471 AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
00472 AST_EVENT_IE_END))) {
00473 return;
00474 }
00475
00476 ast_event_queue_and_cache(event);
00477 }
00478
00479
00480
00481 static void do_state_change(const char *device)
00482 {
00483 enum ast_device_state state;
00484
00485 state = _ast_device_state(device, 0);
00486
00487 ast_debug(3, "Changing state for %s - state %d (%s)\n", device, state, devstate2str(state));
00488
00489 devstate_event(device, state);
00490 }
00491
00492 int ast_devstate_changed_literal(enum ast_device_state state, const char *device)
00493 {
00494 struct state_change *change;
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512 if (state != AST_DEVICE_UNKNOWN) {
00513 devstate_event(device, state);
00514 } else if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) {
00515
00516
00517 do_state_change(device);
00518 } else {
00519
00520 strcpy(change->device, device);
00521 AST_LIST_LOCK(&state_changes);
00522 AST_LIST_INSERT_TAIL(&state_changes, change, list);
00523 ast_cond_signal(&change_pending);
00524 AST_LIST_UNLOCK(&state_changes);
00525 }
00526
00527 return 1;
00528 }
00529
00530 int ast_device_state_changed_literal(const char *dev)
00531 {
00532 return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, dev);
00533 }
00534
00535 int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...)
00536 {
00537 char buf[AST_MAX_EXTENSION];
00538 va_list ap;
00539
00540 va_start(ap, fmt);
00541 vsnprintf(buf, sizeof(buf), fmt, ap);
00542 va_end(ap);
00543
00544 return ast_devstate_changed_literal(state, buf);
00545 }
00546
00547 int ast_device_state_changed(const char *fmt, ...)
00548 {
00549 char buf[AST_MAX_EXTENSION];
00550 va_list ap;
00551
00552 va_start(ap, fmt);
00553 vsnprintf(buf, sizeof(buf), fmt, ap);
00554 va_end(ap);
00555
00556 return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, buf);
00557 }
00558
00559
00560 static void *do_devstate_changes(void *data)
00561 {
00562 struct state_change *next, *current;
00563
00564 for (;;) {
00565
00566 AST_LIST_LOCK(&state_changes);
00567 if (AST_LIST_EMPTY(&state_changes))
00568 ast_cond_wait(&change_pending, &state_changes.lock);
00569 next = AST_LIST_FIRST(&state_changes);
00570 AST_LIST_HEAD_INIT_NOLOCK(&state_changes);
00571 AST_LIST_UNLOCK(&state_changes);
00572
00573
00574 while ((current = next)) {
00575 next = AST_LIST_NEXT(current, list);
00576 do_state_change(current->device);
00577 ast_free(current);
00578 }
00579 }
00580
00581 return NULL;
00582 }
00583
00584 static void destroy_devstate_change(struct devstate_change *sc)
00585 {
00586 ast_free(sc);
00587 }
00588
00589 #define MAX_SERVERS 64
00590 struct change_collection {
00591 struct devstate_change states[MAX_SERVERS];
00592 size_t num_states;
00593 };
00594
00595 static void devstate_cache_cb(const struct ast_event *event, void *data)
00596 {
00597 struct change_collection *collection = data;
00598 int i;
00599 const struct ast_eid *eid;
00600
00601 if (collection->num_states == ARRAY_LEN(collection->states)) {
00602 ast_log(LOG_ERROR, "More per-server state values than we have room for (MAX_SERVERS is %d)\n",
00603 MAX_SERVERS);
00604 return;
00605 }
00606
00607 if (!(eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID))) {
00608 ast_log(LOG_ERROR, "Device state change event with no EID\n");
00609 return;
00610 }
00611
00612 i = collection->num_states;
00613
00614 collection->states[i].state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00615 collection->states[i].eid = *eid;
00616
00617 collection->num_states++;
00618 }
00619
00620 static void process_collection(const char *device, struct change_collection *collection)
00621 {
00622 int i;
00623 struct ast_devstate_aggregate agg;
00624 enum ast_device_state state;
00625 struct ast_event *event;
00626
00627 ast_devstate_aggregate_init(&agg);
00628
00629 for (i = 0; i < collection->num_states; i++) {
00630 ast_debug(1, "Adding per-server state of '%s' for '%s'\n",
00631 devstate2str(collection->states[i].state), device);
00632 ast_devstate_aggregate_add(&agg, collection->states[i].state);
00633 }
00634
00635 state = ast_devstate_aggregate_result(&agg);
00636
00637 ast_debug(1, "Aggregate devstate result is %d\n", state);
00638
00639 event = ast_event_get_cached(AST_EVENT_DEVICE_STATE,
00640 AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00641 AST_EVENT_IE_END);
00642
00643 if (event) {
00644 enum ast_device_state old_state;
00645
00646 old_state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00647
00648 ast_event_destroy(event);
00649
00650 if (state == old_state) {
00651
00652 ast_debug(1, "Aggregate state for device '%s' has not changed from '%s'\n",
00653 device, devstate2str(state));
00654 return;
00655 }
00656 }
00657
00658 ast_debug(1, "Aggregate state for device '%s' has changed to '%s'\n",
00659 device, devstate2str(state));
00660
00661 event = ast_event_new(AST_EVENT_DEVICE_STATE,
00662 AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device,
00663 AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state,
00664 AST_EVENT_IE_END);
00665
00666 if (!event) {
00667 return;
00668 }
00669
00670 ast_event_queue_and_cache(event);
00671 }
00672
00673 static void handle_devstate_change(struct devstate_change *sc)
00674 {
00675 struct ast_event_sub *tmp_sub;
00676 struct change_collection collection = {
00677 .num_states = 0,
00678 };
00679
00680 ast_debug(1, "Processing device state change for '%s'\n", sc->device);
00681
00682 if (!(tmp_sub = ast_event_subscribe_new(AST_EVENT_DEVICE_STATE_CHANGE, devstate_cache_cb, &collection))) {
00683 ast_log(LOG_ERROR, "Failed to create subscription\n");
00684 return;
00685 }
00686
00687 if (ast_event_sub_append_ie_str(tmp_sub, AST_EVENT_IE_DEVICE, sc->device)) {
00688 ast_log(LOG_ERROR, "Failed to append device IE\n");
00689 ast_event_sub_destroy(tmp_sub);
00690 return;
00691 }
00692
00693
00694 ast_event_dump_cache(tmp_sub);
00695
00696 process_collection(sc->device, &collection);
00697
00698 ast_event_sub_destroy(tmp_sub);
00699 }
00700
00701 static void *run_devstate_collector(void *data)
00702 {
00703 for (;;) {
00704 struct devstate_change *sc;
00705
00706 ast_mutex_lock(&devstate_collector.lock);
00707 while (!(sc = AST_LIST_REMOVE_HEAD(&devstate_collector.devstate_change_q, entry)))
00708 ast_cond_wait(&devstate_collector.cond, &devstate_collector.lock);
00709 ast_mutex_unlock(&devstate_collector.lock);
00710
00711 handle_devstate_change(sc);
00712
00713 destroy_devstate_change(sc);
00714 }
00715
00716 return NULL;
00717 }
00718
00719 static void devstate_change_collector_cb(const struct ast_event *event, void *data)
00720 {
00721 struct devstate_change *sc;
00722 const char *device;
00723 const struct ast_eid *eid;
00724 uint32_t state;
00725
00726 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
00727 eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID);
00728 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
00729
00730 if (ast_strlen_zero(device) || !eid) {
00731 ast_log(LOG_ERROR, "Invalid device state change event received\n");
00732 return;
00733 }
00734
00735 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device))))
00736 return;
00737
00738 strcpy(sc->device, device);
00739 sc->eid = *eid;
00740 sc->state = state;
00741
00742 ast_mutex_lock(&devstate_collector.lock);
00743 AST_LIST_INSERT_TAIL(&devstate_collector.devstate_change_q, sc, entry);
00744 ast_cond_signal(&devstate_collector.cond);
00745 ast_mutex_unlock(&devstate_collector.lock);
00746 }
00747
00748
00749 int ast_device_state_engine_init(void)
00750 {
00751 ast_cond_init(&change_pending, NULL);
00752 if (ast_pthread_create_background(&change_thread, NULL, do_devstate_changes, NULL) < 0) {
00753 ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
00754 return -1;
00755 }
00756
00757 return 0;
00758 }
00759
00760 void ast_devstate_aggregate_init(struct ast_devstate_aggregate *agg)
00761 {
00762 memset(agg, 0, sizeof(*agg));
00763
00764 agg->all_unavail = 1;
00765 agg->all_busy = 1;
00766 agg->all_free = 1;
00767 agg->all_on_hold = 1;
00768 }
00769
00770 void ast_devstate_aggregate_add(struct ast_devstate_aggregate *agg, enum ast_device_state state)
00771 {
00772 switch (state) {
00773 case AST_DEVICE_NOT_INUSE:
00774 agg->all_unavail = 0;
00775 agg->all_busy = 0;
00776 agg->all_on_hold = 0;
00777 break;
00778 case AST_DEVICE_INUSE:
00779 agg->in_use = 1;
00780 agg->all_busy = 0;
00781 agg->all_unavail = 0;
00782 agg->all_free = 0;
00783 agg->all_on_hold = 0;
00784 break;
00785 case AST_DEVICE_RINGING:
00786 agg->ring = 1;
00787 agg->all_busy = 0;
00788 agg->all_unavail = 0;
00789 agg->all_free = 0;
00790 agg->all_on_hold = 0;
00791 break;
00792 case AST_DEVICE_RINGINUSE:
00793 agg->in_use = 1;
00794 agg->ring = 1;
00795 agg->all_busy = 0;
00796 agg->all_unavail = 0;
00797 agg->all_free = 0;
00798 agg->all_on_hold = 0;
00799 break;
00800 case AST_DEVICE_ONHOLD:
00801 agg->all_unavail = 0;
00802 agg->all_free = 0;
00803 break;
00804 case AST_DEVICE_BUSY:
00805 agg->all_unavail = 0;
00806 agg->all_free = 0;
00807 agg->all_on_hold = 0;
00808 agg->busy = 1;
00809 break;
00810 case AST_DEVICE_UNAVAILABLE:
00811 case AST_DEVICE_INVALID:
00812 agg->all_busy = 0;
00813 agg->all_free = 0;
00814 agg->all_on_hold = 0;
00815 break;
00816 case AST_DEVICE_UNKNOWN:
00817 break;
00818 }
00819 }
00820
00821 enum ast_device_state ast_devstate_aggregate_result(struct ast_devstate_aggregate *agg)
00822 {
00823 if (agg->all_free)
00824 return AST_DEVICE_NOT_INUSE;
00825
00826 if (agg->all_on_hold)
00827 return AST_DEVICE_ONHOLD;
00828
00829 if (agg->all_busy)
00830 return AST_DEVICE_BUSY;
00831
00832 if (agg->all_unavail)
00833 return AST_DEVICE_UNAVAILABLE;
00834
00835 if (agg->ring)
00836 return agg->in_use ? AST_DEVICE_RINGINUSE : AST_DEVICE_RINGING;
00837
00838 if (agg->in_use)
00839 return AST_DEVICE_INUSE;
00840
00841 if (agg->busy)
00842 return AST_DEVICE_BUSY;
00843
00844 return AST_DEVICE_NOT_INUSE;
00845 }
00846
00847 int ast_enable_distributed_devstate(void)
00848 {
00849 if (devstate_collector.enabled) {
00850 return 0;
00851 }
00852
00853 devstate_collector.event_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE_CHANGE,
00854 devstate_change_collector_cb, NULL, AST_EVENT_IE_END);
00855
00856 if (!devstate_collector.event_sub) {
00857 ast_log(LOG_ERROR, "Failed to create subscription for the device state change collector\n");
00858 return -1;
00859 }
00860
00861 ast_mutex_init(&devstate_collector.lock);
00862 ast_cond_init(&devstate_collector.cond, NULL);
00863 if (ast_pthread_create_background(&devstate_collector.thread, NULL, run_devstate_collector, NULL) < 0) {
00864 ast_log(LOG_ERROR, "Unable to start device state collector thread.\n");
00865 return -1;
00866 }
00867
00868 devstate_collector.enabled = 1;
00869
00870 return 0;
00871 }