32 #define DEVICE_STATE_SIZE 64
34 #define DEVICE_STATE_FAMILY "StasisDeviceState"
36 #define DEVICE_STATE_PROVIDER_STASIS "Stasis"
38 #define DEVICE_STATE_SCHEME_STASIS "Stasis:"
40 #define DEVICE_STATE_SCHEME_SUB "deviceState:"
43 #define DEVICE_STATE_BUCKETS 37
46 #define DEVICE_STATE_ALL "__AST_DEVICE_STATE_ALL_TOPIC"
63 static int device_state_subscriptions_hash(
const void *obj,
const int flags)
79 static int device_state_subscriptions_cmp(
void *obj,
void *arg,
int flags)
88 if (strcmp(object_left->device_name,
89 object_right->device_name)) {
92 cmp = strcmp(object_left->app_name, object_right->app_name);
106 static void device_state_subscription_destroy(
void *obj)
113 const struct stasis_app *app,
const char *device_name)
119 if (ast_strlen_zero(device_name)) {
120 device_name = DEVICE_STATE_ALL;
123 size = strlen(device_name) + strlen(app_name) + 2;
125 sub = ao2_alloc(
sizeof(*sub), device_state_subscription_destroy);
151 static void remove_device_state_subscription(
175 for (entry = tree; entry; entry = entry->next) {
176 const char *name = strrchr(entry->key,
'/');
178 if (!ast_strlen_zero(name)) {
179 char device[DEVICE_STATE_SIZE];
181 snprintf(device,
sizeof(device),
"%s%s", DEVICE_STATE_SCHEME_STASIS, ++name);
197 "type",
"DeviceStateChanged",
198 "application", sub->app_name,
204 ast_log(LOG_ERROR,
"Unable to create device state json object\n");
212 const char *name,
const char *value)
214 size_t size = strlen(DEVICE_STATE_SCHEME_STASIS);
217 ast_debug(3,
"Updating device name = %s, value = %s", name, value);
219 if (strncasecmp(name, DEVICE_STATE_SCHEME_STASIS, size)) {
220 ast_log(LOG_ERROR,
"Update can only be used to set "
221 "'%s' device state!\n", DEVICE_STATE_SCHEME_STASIS);
226 if (ast_strlen_zero(name)) {
227 ast_log(LOG_ERROR,
"Update requires custom device name!\n");
232 ast_log(LOG_ERROR,
"Unknown device state "
233 "value '%s'\n", value);
239 DEVICE_STATE_SCHEME_STASIS, name);
246 const char *full_name = name;
247 size_t size = strlen(DEVICE_STATE_SCHEME_STASIS);
249 if (strncasecmp(name, DEVICE_STATE_SCHEME_STASIS, size)) {
250 ast_log(LOG_ERROR,
"Can only delete '%s' device states!\n",
251 DEVICE_STATE_SCHEME_STASIS);
256 if (ast_strlen_zero(name)) {
257 ast_log(LOG_ERROR,
"Delete requires a device name!\n");
270 DEVICE_STATE_SCHEME_STASIS, name);
275 static void populate_cache(
void)
281 for (entry = tree; entry; entry = entry->next) {
282 const char *name = strrchr(entry->key,
'/');
283 if (!ast_strlen_zero(name)) {
287 DEVICE_STATE_SCHEME_STASIS, name + 1);
294 char buf[DEVICE_STATE_SIZE];
296 ast_db_get(DEVICE_STATE_FAMILY, data, buf,
sizeof(buf));
317 if (device_state->
eid) {
322 send_device_state(data, device_state->
device, device_state->
state);
325 static void *find_device_state(
const struct stasis_app *app,
const char *name)
327 return device_state_subscription_create(app, name);
330 static int is_subscribed_device_state(
struct stasis_app *app,
const char *name)
334 sub = find_device_state_subscription(app, DEVICE_STATE_ALL);
340 sub = find_device_state_subscription(app, name);
349 static int is_subscribed_device_state_lock(
struct stasis_app *app,
const char *name)
353 ao2_lock(device_state_subscriptions);
354 is_subscribed = is_subscribed_device_state(app, name);
355 ao2_unlock(device_state_subscriptions);
357 return is_subscribed;
360 static int subscribe_device_state(
struct stasis_app *app,
void *obj)
366 sub = device_state_subscription_create(app, NULL);
372 if (strcmp(sub->device_name, DEVICE_STATE_ALL)) {
378 ao2_lock(device_state_subscriptions);
380 if (is_subscribed_device_state(app, sub->device_name)) {
381 ao2_unlock(device_state_subscriptions);
386 ast_debug(3,
"Subscribing to device %s\n", sub->device_name);
390 ao2_unlock(device_state_subscriptions);
391 ast_log(LOG_ERROR,
"Unable to subscribe to device %s\n",
402 ao2_unlock(device_state_subscriptions);
407 static int unsubscribe_device_state(
struct stasis_app *app,
const char *name)
411 ao2_lock(device_state_subscriptions);
412 sub = find_device_state_subscription(app, name);
414 remove_device_state_subscription(sub);
416 ao2_unlock(device_state_subscriptions);
423 static int device_to_json_cb(
void *obj,
void *arg,
void *data,
int flags)
426 const char *app_name = arg;
429 if (strcmp(sub->app_name, app_name)) {
442 ao2_callback_data(device_state_subscriptions,
OBJ_NODATA,
448 .
scheme = DEVICE_STATE_SCHEME_SUB,
449 .find = find_device_state,
450 .subscribe = subscribe_device_state,
451 .unsubscribe = unsubscribe_device_state,
452 .is_subscribed = is_subscribed_device_state_lock,
453 .to_json = devices_to_json
456 static int load_module(
void)
460 stasis_device_state_cb)) {
465 DEVICE_STATE_BUCKETS, device_state_subscriptions_hash, NULL,
466 device_state_subscriptions_cmp);
467 if (!device_state_subscriptions) {
476 static int unload_module(
void)
480 ao2_cleanup(device_state_subscriptions);
481 device_state_subscriptions = NULL;
485 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,
"Stasis application device state support",
486 .support_level = AST_MODULE_SUPPORT_CORE,
488 .unload = unload_module,
489 .requires =
"res_stasis",
struct stasis_topic * ast_device_state_topic(const char *device)
Get the Stasis topic for device state messages for a specific device.
Stasis Application Device State API. See StasisApplication API" for detailed documentation.
ast_device_state
Device States.
Asterisk main include file. File version handling, generic pbx functions.
enum stasis_device_state_result stasis_app_device_state_delete(const char *name)
Delete a device controlled by ARI.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
The arg parameter is a search key, but is not an object.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
const char * scheme
The scheme to match against on [un]subscribes.
Device state subscription object.
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
stasis_device_state_result
enum ast_device_state state
int ast_devstate_prov_del(const char *label)
Remove device state provider.
Assume that the ao2_container is already locked.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
Add device state provider.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
int ast_device_state_clear_cache(const char *device)
Clear the device from the stasis cache.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
enum ast_device_state ast_devstate_val(const char *val)
Convert device state from text to integer value.
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
const struct ast_eid * eid
The EID of the server where this message originated.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Event source information and callbacks.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define AST_STRING_FIELD(name)
Declare a string field.
const char * stasis_app_name(const struct stasis_app *app)
Retrieve an application's name.
#define ast_debug(level,...)
Log a DEBUG message.
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
void stasis_app_unregister_event_source(struct stasis_app_event_source *obj)
Unregister an application event source.
const char * ast_devstate_str(enum ast_device_state devstate) attribute_pure
Convert device state to text string that is easier to parse.
Backend API for implementing components of res_stasis.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
enum stasis_device_state_result stasis_app_device_state_update(const char *name, const char *value)
Changes the state of a device controlled by ARI.
const char * app_name(struct ast_app *app)
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
set a member's status based on device state of that member's interface
int stasis_app_send(const char *app_name, struct ast_json *message)
Send a message to the given Stasis application.
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Module has failed to load, may be in an inconsistent state.
int ast_db_get(const char *family, const char *key, char *value, int valuelen)
Get key value specified by family/key.
struct ast_json * stasis_app_device_states_to_json(void)
Convert device states to json array.
struct stasis_subscription * sub
The arg parameter is an object of the same type.
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Abstract JSON element (object, array, string, int, ...).
The structure that contains device state.
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
Search option field mask.
#define ASTERISK_GPL_KEY
The text the key() function should return.
struct ast_json * stasis_app_device_state_to_json(const char *name, enum ast_device_state state)
Convert device state to json.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Persistent data storage (akin to *doze registry)
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
void stasis_app_register_event_source(struct stasis_app_event_source *obj)
Register an application event source.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.