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