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