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