diff options
-rw-r--r-- | CHANGES | 20 | ||||
-rw-r--r-- | main/stasis_endpoints.c | 78 | ||||
-rw-r--r-- | res/ari/ari_model_validators.c | 359 | ||||
-rw-r--r-- | res/ari/ari_model_validators.h | 95 | ||||
-rw-r--r-- | rest-api-templates/ari_model_validators.c.mustache | 2 | ||||
-rw-r--r-- | rest-api/api-docs/events.json | 99 |
6 files changed, 641 insertions, 12 deletions
@@ -189,6 +189,26 @@ Dialplan Functions return the SIP Call-ID associated with the INVITE request that established the PJSIP channel. +ARI +------------------ + * Two new endpoint related events are now available: PeerStatusChange and + ContactStatusChange. In particular, these events are useful when subscribing + to all event sources, as they provide additional endpoint related + information beyond the addition/removal of channels from an endpoint. + + * Added the ability to subscribe to all ARI events in Asterisk, regardless + of whether the application 'controls' the resource. This is useful for + scenarios where an ARI application merely wants to observe the system, + as opposed to control it. There are two ways to accomplish this: + (1) Via the WebSocket connection URI. A new query paramter, 'subscribeAll', + has been added that, when present and True, will subscribe all + specified applications to all ARI event sources in Asterisk. + (2) Via the applications resource. An ARI client can, at any time, subscribe + to all resources in an event source merely by not providing an explicit + resource. For example, subscribing to an event source of 'channels:' + as opposed to 'channels:12345' will subscribe the application to all + channels. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.4.0 to Asterisk 13.5.0 ------------ ------------------------------------------------------------------------------ diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c index da6505355..f44ce4229 100644 --- a/main/stasis_endpoints.c +++ b/main/stasis_endpoints.c @@ -124,12 +124,7 @@ struct stasis_topic *ast_endpoint_topic_all_cached(void) return stasis_cp_all_topic_cached(endpoint_cache_all); } -static struct ast_manager_event_blob *peerstatus_to_ami(struct stasis_message *msg); - STASIS_MESSAGE_TYPE_DEFN(ast_endpoint_snapshot_type); -STASIS_MESSAGE_TYPE_DEFN(ast_endpoint_state_type, - .to_ami = peerstatus_to_ami, -); static struct ast_manager_event_blob *peerstatus_to_ami(struct stasis_message *msg) { @@ -166,10 +161,44 @@ static struct ast_manager_event_blob *peerstatus_to_ami(struct stasis_message *m ast_str_buffer(peerstatus_event_string)); } -static struct ast_manager_event_blob *contactstatus_to_ami(struct stasis_message *msg); +static struct ast_json *peerstatus_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize) +{ + struct ast_endpoint_blob *obj = stasis_message_data(msg); + struct ast_json *json_endpoint; + struct ast_json *json_peer; + struct ast_json *json_final; + const struct timeval *tv = stasis_message_timestamp(msg); -STASIS_MESSAGE_TYPE_DEFN(ast_endpoint_contact_state_type, - .to_ami = contactstatus_to_ami, + json_endpoint = ast_endpoint_snapshot_to_json(obj->snapshot, NULL); + if (!json_endpoint) { + return NULL; + } + + json_peer = ast_json_object_create(); + if (!json_peer) { + ast_json_unref(json_endpoint); + return NULL; + } + + /* Copy all fields from the blob */ + ast_json_object_update(json_peer, obj->blob); + + json_final = ast_json_pack("{s: s, s: o, s: o, s: o }", + "type", "PeerStatusChange", + "timestamp", ast_json_timeval(*tv, NULL), + "endpoint", json_endpoint, + "peer", json_peer); + if (!json_final) { + ast_json_unref(json_endpoint); + ast_json_unref(json_peer); + } + + return json_final; +} + +STASIS_MESSAGE_TYPE_DEFN(ast_endpoint_state_type, + .to_ami = peerstatus_to_ami, + .to_json = peerstatus_to_json, ); static struct ast_manager_event_blob *contactstatus_to_ami(struct stasis_message *msg) @@ -206,6 +235,39 @@ static struct ast_manager_event_blob *contactstatus_to_ami(struct stasis_message "%s", ast_str_buffer(contactstatus_event_string)); } +static struct ast_json *contactstatus_to_json(struct stasis_message *msg, const struct stasis_message_sanitizer *sanitize) +{ + struct ast_endpoint_blob *obj = stasis_message_data(msg); + struct ast_json *json_endpoint; + struct ast_json *json_final; + const struct timeval *tv = stasis_message_timestamp(msg); + + json_endpoint = ast_endpoint_snapshot_to_json(obj->snapshot, NULL); + if (!json_endpoint) { + return NULL; + } + + json_final = ast_json_pack("{s: s, s: o, s: o, s: { s: s, s: s, s: s } } ", + "type", "ContactStatusChange", + "timestamp", ast_json_timeval(*tv, NULL), + "endpoint", json_endpoint, + "contact_info", + "uri", ast_json_string_get(ast_json_object_get(obj->blob, "uri")), + "contact_status", ast_json_string_get(ast_json_object_get(obj->blob, "contact_status")), + "aor", ast_json_string_get(ast_json_object_get(obj->blob, "aor")), + "roundtrip_usec", ast_json_string_get(ast_json_object_get(obj->blob, "roundtrip_usec"))); + if (!json_final) { + ast_json_unref(json_endpoint); + } + + return json_final; +} + +STASIS_MESSAGE_TYPE_DEFN(ast_endpoint_contact_state_type, + .to_ami = contactstatus_to_ami, + .to_json = contactstatus_to_json +); + static void endpoint_blob_dtor(void *obj) { struct ast_endpoint_blob *event = obj; diff --git a/res/ari/ari_model_validators.c b/res/ari/ari_model_validators.c index 0a5c7606f..623d5b541 100644 --- a/res/ari/ari_model_validators.c +++ b/res/ari/ari_model_validators.c @@ -4180,6 +4180,180 @@ ari_validator ast_ari_validate_channel_varset_fn(void) return ast_ari_validate_channel_varset; } +int ast_ari_validate_contact_info(struct ast_json *json) +{ + int res = 1; + struct ast_json_iter *iter; + int has_aor = 0; + int has_contact_status = 0; + int has_uri = 0; + + for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) { + if (strcmp("aor", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_aor = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ContactInfo field aor failed validation\n"); + res = 0; + } + } else + if (strcmp("contact_status", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_contact_status = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ContactInfo field contact_status failed validation\n"); + res = 0; + } + } else + if (strcmp("roundtrip_usec", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ContactInfo field roundtrip_usec failed validation\n"); + res = 0; + } + } else + if (strcmp("uri", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_uri = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ContactInfo field uri failed validation\n"); + res = 0; + } + } else + { + ast_log(LOG_ERROR, + "ARI ContactInfo has undocumented field %s\n", + ast_json_object_iter_key(iter)); + res = 0; + } + } + + if (!has_aor) { + ast_log(LOG_ERROR, "ARI ContactInfo missing required field aor\n"); + res = 0; + } + + if (!has_contact_status) { + ast_log(LOG_ERROR, "ARI ContactInfo missing required field contact_status\n"); + res = 0; + } + + if (!has_uri) { + ast_log(LOG_ERROR, "ARI ContactInfo missing required field uri\n"); + res = 0; + } + + return res; +} + +ari_validator ast_ari_validate_contact_info_fn(void) +{ + return ast_ari_validate_contact_info; +} + +int ast_ari_validate_contact_status_change(struct ast_json *json) +{ + int res = 1; + struct ast_json_iter *iter; + int has_type = 0; + int has_application = 0; + int has_contact_info = 0; + int has_endpoint = 0; + + for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) { + if (strcmp("type", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_type = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ContactStatusChange field type failed validation\n"); + res = 0; + } + } else + if (strcmp("application", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_application = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ContactStatusChange field application failed validation\n"); + res = 0; + } + } else + if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_date( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ContactStatusChange field timestamp failed validation\n"); + res = 0; + } + } else + if (strcmp("contact_info", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_contact_info = 1; + prop_is_valid = ast_ari_validate_contact_info( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ContactStatusChange field contact_info failed validation\n"); + res = 0; + } + } else + if (strcmp("endpoint", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_endpoint = 1; + prop_is_valid = ast_ari_validate_endpoint( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI ContactStatusChange field endpoint failed validation\n"); + res = 0; + } + } else + { + ast_log(LOG_ERROR, + "ARI ContactStatusChange has undocumented field %s\n", + ast_json_object_iter_key(iter)); + res = 0; + } + } + + if (!has_type) { + ast_log(LOG_ERROR, "ARI ContactStatusChange missing required field type\n"); + res = 0; + } + + if (!has_application) { + ast_log(LOG_ERROR, "ARI ContactStatusChange missing required field application\n"); + res = 0; + } + + if (!has_contact_info) { + ast_log(LOG_ERROR, "ARI ContactStatusChange missing required field contact_info\n"); + res = 0; + } + + if (!has_endpoint) { + ast_log(LOG_ERROR, "ARI ContactStatusChange missing required field endpoint\n"); + res = 0; + } + + return res; +} + +ari_validator ast_ari_validate_contact_status_change_fn(void) +{ + return ast_ari_validate_contact_status_change; +} + int ast_ari_validate_device_state_changed(struct ast_json *json) { int res = 1; @@ -4479,7 +4653,7 @@ int ast_ari_validate_event(struct ast_json *json) discriminator = ast_json_string_get(ast_json_object_get(json, "type")); if (!discriminator) { - ast_log(LOG_ERROR, "ARI Event missing required field type"); + ast_log(LOG_ERROR, "ARI Event missing required field type\n"); return 0; } @@ -4552,6 +4726,9 @@ int ast_ari_validate_event(struct ast_json *json) if (strcmp("ChannelVarset", discriminator) == 0) { return ast_ari_validate_channel_varset(json); } else + if (strcmp("ContactStatusChange", discriminator) == 0) { + return ast_ari_validate_contact_status_change(json); + } else if (strcmp("DeviceStateChanged", discriminator) == 0) { return ast_ari_validate_device_state_changed(json); } else @@ -4561,6 +4738,9 @@ int ast_ari_validate_event(struct ast_json *json) if (strcmp("EndpointStateChange", discriminator) == 0) { return ast_ari_validate_endpoint_state_change(json); } else + if (strcmp("PeerStatusChange", discriminator) == 0) { + return ast_ari_validate_peer_status_change(json); + } else if (strcmp("PlaybackFinished", discriminator) == 0) { return ast_ari_validate_playback_finished(json); } else @@ -4656,7 +4836,7 @@ int ast_ari_validate_message(struct ast_json *json) discriminator = ast_json_string_get(ast_json_object_get(json, "type")); if (!discriminator) { - ast_log(LOG_ERROR, "ARI Message missing required field type"); + ast_log(LOG_ERROR, "ARI Message missing required field type\n"); return 0; } @@ -4729,6 +4909,9 @@ int ast_ari_validate_message(struct ast_json *json) if (strcmp("ChannelVarset", discriminator) == 0) { return ast_ari_validate_channel_varset(json); } else + if (strcmp("ContactStatusChange", discriminator) == 0) { + return ast_ari_validate_contact_status_change(json); + } else if (strcmp("DeviceStateChanged", discriminator) == 0) { return ast_ari_validate_device_state_changed(json); } else @@ -4744,6 +4927,9 @@ int ast_ari_validate_message(struct ast_json *json) if (strcmp("MissingParams", discriminator) == 0) { return ast_ari_validate_missing_params(json); } else + if (strcmp("PeerStatusChange", discriminator) == 0) { + return ast_ari_validate_peer_status_change(json); + } else if (strcmp("PlaybackFinished", discriminator) == 0) { return ast_ari_validate_playback_finished(json); } else @@ -4861,6 +5047,175 @@ ari_validator ast_ari_validate_missing_params_fn(void) return ast_ari_validate_missing_params; } +int ast_ari_validate_peer(struct ast_json *json) +{ + int res = 1; + struct ast_json_iter *iter; + int has_peer_status = 0; + + for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) { + if (strcmp("address", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI Peer field address failed validation\n"); + res = 0; + } + } else + if (strcmp("cause", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI Peer field cause failed validation\n"); + res = 0; + } + } else + if (strcmp("peer_status", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_peer_status = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI Peer field peer_status failed validation\n"); + res = 0; + } + } else + if (strcmp("port", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI Peer field port failed validation\n"); + res = 0; + } + } else + if (strcmp("time", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI Peer field time failed validation\n"); + res = 0; + } + } else + { + ast_log(LOG_ERROR, + "ARI Peer has undocumented field %s\n", + ast_json_object_iter_key(iter)); + res = 0; + } + } + + if (!has_peer_status) { + ast_log(LOG_ERROR, "ARI Peer missing required field peer_status\n"); + res = 0; + } + + return res; +} + +ari_validator ast_ari_validate_peer_fn(void) +{ + return ast_ari_validate_peer; +} + +int ast_ari_validate_peer_status_change(struct ast_json *json) +{ + int res = 1; + struct ast_json_iter *iter; + int has_type = 0; + int has_application = 0; + int has_endpoint = 0; + int has_peer = 0; + + for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) { + if (strcmp("type", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_type = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI PeerStatusChange field type failed validation\n"); + res = 0; + } + } else + if (strcmp("application", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_application = 1; + prop_is_valid = ast_ari_validate_string( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI PeerStatusChange field application failed validation\n"); + res = 0; + } + } else + if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + prop_is_valid = ast_ari_validate_date( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI PeerStatusChange field timestamp failed validation\n"); + res = 0; + } + } else + if (strcmp("endpoint", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_endpoint = 1; + prop_is_valid = ast_ari_validate_endpoint( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI PeerStatusChange field endpoint failed validation\n"); + res = 0; + } + } else + if (strcmp("peer", ast_json_object_iter_key(iter)) == 0) { + int prop_is_valid; + has_peer = 1; + prop_is_valid = ast_ari_validate_peer( + ast_json_object_iter_value(iter)); + if (!prop_is_valid) { + ast_log(LOG_ERROR, "ARI PeerStatusChange field peer failed validation\n"); + res = 0; + } + } else + { + ast_log(LOG_ERROR, + "ARI PeerStatusChange has undocumented field %s\n", + ast_json_object_iter_key(iter)); + res = 0; + } + } + + if (!has_type) { + ast_log(LOG_ERROR, "ARI PeerStatusChange missing required field type\n"); + res = 0; + } + + if (!has_application) { + ast_log(LOG_ERROR, "ARI PeerStatusChange missing required field application\n"); + res = 0; + } + + if (!has_endpoint) { + ast_log(LOG_ERROR, "ARI PeerStatusChange missing required field endpoint\n"); + res = 0; + } + + if (!has_peer) { + ast_log(LOG_ERROR, "ARI PeerStatusChange missing required field peer\n"); + res = 0; + } + + return res; +} + +ari_validator ast_ari_validate_peer_status_change_fn(void) +{ + return ast_ari_validate_peer_status_change; +} + int ast_ari_validate_playback_finished(struct ast_json *json) { int res = 1; diff --git a/res/ari/ari_model_validators.h b/res/ari/ari_model_validators.h index 1803f57c9..0bcdb0fa2 100644 --- a/res/ari/ari_model_validators.h +++ b/res/ari/ari_model_validators.h @@ -1007,6 +1007,42 @@ int ast_ari_validate_channel_varset(struct ast_json *json); ari_validator ast_ari_validate_channel_varset_fn(void); /*! + * \brief Validator for ContactInfo. + * + * Detailed information about a contact on an endpoint. + * + * \param json JSON object to validate. + * \returns True (non-zero) if valid. + * \returns False (zero) if invalid. + */ +int ast_ari_validate_contact_info(struct ast_json *json); + +/*! + * \brief Function pointer to ast_ari_validate_contact_info(). + * + * See \ref ast_ari_model_validators.h for more details. + */ +ari_validator ast_ari_validate_contact_info_fn(void); + +/*! + * \brief Validator for ContactStatusChange. + * + * The state of a contact on an endpoint has changed. + * + * \param json JSON object to validate. + * \returns True (non-zero) if valid. + * \returns False (zero) if invalid. + */ +int ast_ari_validate_contact_status_change(struct ast_json *json); + +/*! + * \brief Function pointer to ast_ari_validate_contact_status_change(). + * + * See \ref ast_ari_model_validators.h for more details. + */ +ari_validator ast_ari_validate_contact_status_change_fn(void); + +/*! * \brief Validator for DeviceStateChanged. * * Notification that a device state has changed. @@ -1115,6 +1151,42 @@ int ast_ari_validate_missing_params(struct ast_json *json); ari_validator ast_ari_validate_missing_params_fn(void); /*! + * \brief Validator for Peer. + * + * Detailed information about a remote peer that communicates with Asterisk. + * + * \param json JSON object to validate. + * \returns True (non-zero) if valid. + * \returns False (zero) if invalid. + */ +int ast_ari_validate_peer(struct ast_json *json); + +/*! + * \brief Function pointer to ast_ari_validate_peer(). + * + * See \ref ast_ari_model_validators.h for more details. + */ +ari_validator ast_ari_validate_peer_fn(void); + +/*! + * \brief Validator for PeerStatusChange. + * + * The state of a peer associated with an endpoint has changed. + * + * \param json JSON object to validate. + * \returns True (non-zero) if valid. + * \returns False (zero) if invalid. + */ +int ast_ari_validate_peer_status_change(struct ast_json *json); + +/*! + * \brief Function pointer to ast_ari_validate_peer_status_change(). + * + * See \ref ast_ari_model_validators.h for more details. + */ +ari_validator ast_ari_validate_peer_status_change_fn(void); + +/*! * \brief Validator for PlaybackFinished. * * Event showing the completion of a media playback operation. @@ -1546,6 +1618,17 @@ ari_validator ast_ari_validate_application_fn(void); * - channel: Channel * - value: string (required) * - variable: string (required) + * ContactInfo + * - aor: string (required) + * - contact_status: string (required) + * - roundtrip_usec: string + * - uri: string (required) + * ContactStatusChange + * - type: string (required) + * - application: string (required) + * - timestamp: Date + * - contact_info: ContactInfo (required) + * - endpoint: Endpoint (required) * DeviceStateChanged * - type: string (required) * - application: string (required) @@ -1575,6 +1658,18 @@ ari_validator ast_ari_validate_application_fn(void); * MissingParams * - type: string (required) * - params: List[string] (required) + * Peer + * - address: string + * - cause: string + * - peer_status: string (required) + * - port: string + * - time: string + * PeerStatusChange + * - type: string (required) + * - application: string (required) + * - timestamp: Date + * - endpoint: Endpoint (required) + * - peer: Peer (required) * PlaybackFinished * - type: string (required) * - application: string (required) diff --git a/rest-api-templates/ari_model_validators.c.mustache b/rest-api-templates/ari_model_validators.c.mustache index 0ca3d26ca..78f19bf66 100644 --- a/rest-api-templates/ari_model_validators.c.mustache +++ b/rest-api-templates/ari_model_validators.c.mustache @@ -50,7 +50,7 @@ int ast_ari_validate_{{c_id}}(struct ast_json *json) discriminator = ast_json_string_get(ast_json_object_get(json, "{{discriminator.name}}")); if (!discriminator) { - ast_log(LOG_ERROR, "ARI {{id}} missing required field {{discriminator.name}}"); + ast_log(LOG_ERROR, "ARI {{id}} missing required field {{discriminator.name}}\n"); return 0; } diff --git a/rest-api/api-docs/events.json b/rest-api/api-docs/events.json index 392b0ac70..54269a407 100644 --- a/rest-api/api-docs/events.json +++ b/rest-api/api-docs/events.json @@ -163,14 +163,83 @@ "ChannelTalkingFinished", "ChannelHold", "ChannelUnhold", + "ContactStatusChange", "EndpointStateChange", "Dial", "StasisEnd", "StasisStart", "TextMessageReceived", - "ChannelConnectedLine" + "ChannelConnectedLine", + "PeerStatusChange" ] }, + "ContactInfo": { + "id": "ContactInfo", + "description": "Detailed information about a contact on an endpoint.", + "properties": { + "uri": { + "type": "string", + "description": "The location of the contact.", + "required": true + }, + "contact_status": { + "type": "string", + "description": "The current status of the contact.", + "required": true, + "allowableValues": { + "valueType": "LIST", + "values": [ + "Unreachable", + "Reachable", + "Unknown", + "Created", + "Removed" + ] + } + }, + "aor": { + "type": "string", + "description": "The Address of Record this contact belongs to.", + "required": true + }, + "roundtrip_usec": { + "type": "string", + "description": "Current round trip time, in microseconds, for the contact.", + "required": false + } + } + }, + "Peer": { + "id": "Peer", + "description": "Detailed information about a remote peer that communicates with Asterisk.", + "properties": { + "peer_status": { + "type": "string", + "description": "The current state of the peer. Note that the values of the status are dependent on the underlying peer technology.", + "required": true + }, + "cause": { + "type": "string", + "description": "An optional reason associated with the change in peer_status.", + "required": false + }, + "address": { + "type": "string", + "description": "The IP address of the peer.", + "required": false + }, + "port": { + "type": "string", + "description": "The port of the peer.", + "required": false + }, + "time": { + "type": "string", + "description": "The last known time the peer was contacted.", + "required": false + } + } + }, "DeviceStateChanged": { "id": "DeviceStateChanged", "description": "Notification that a device state has changed.", @@ -654,6 +723,34 @@ } } }, + "ContactStatusChange": { + "id": "ContactStatusChange", + "description": "The state of a contact on an endpoint has changed.", + "properties": { + "endpoint": { + "required": true, + "type": "Endpoint" + }, + "contact_info": { + "required": true, + "type": "ContactInfo" + } + } + }, + "PeerStatusChange": { + "id": "PeerStatusChange", + "description": "The state of a peer associated with an endpoint has changed.", + "properties": { + "endpoint": { + "required": true, + "type": "Endpoint" + }, + "peer": { + "required": true, + "type": "Peer" + } + } + }, "EndpointStateChange": { "id": "EndpointStateChange", "description": "Endpoint state changed.", |