diff --git a/conf/rayo/autoload_configs/rayo.conf.xml b/conf/rayo/autoload_configs/rayo.conf.xml index 45a8ab04bb..52a1a35977 100644 --- a/conf/rayo/autoload_configs/rayo.conf.xml +++ b/conf/rayo/autoload_configs/rayo.conf.xml @@ -109,6 +109,9 @@ + ]]> + ]]> + ]]> ]]> ]]> ]]> diff --git a/src/mod/event_handlers/mod_rayo/Makefile b/src/mod/event_handlers/mod_rayo/Makefile index 3b7e5dba3f..070f41f98c 100644 --- a/src/mod/event_handlers/mod_rayo/Makefile +++ b/src/mod/event_handlers/mod_rayo/Makefile @@ -10,6 +10,7 @@ LOCAL_OBJS= $(IKS_LA) \ iks_helpers.o \ nlsml.o \ rayo_components.o \ + rayo_cpa_component.o \ rayo_cpa_detector.o \ rayo_elements.o \ rayo_fax_components.o \ @@ -24,6 +25,7 @@ LOCAL_SOURCES= \ iks_helpers.c \ nlsml.c \ rayo_components.c \ + rayo_cpa_component.c \ rayo_cpa_detector.c \ rayo_elements.c \ rayo_fax_components.c \ diff --git a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml index 45a8ab04bb..52a1a35977 100644 --- a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml +++ b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml @@ -109,6 +109,9 @@ + ]]> + ]]> + ]]> ]]> ]]> ]]> diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.c b/src/mod/event_handlers/mod_rayo/mod_rayo.c index c650e66877..95162093c8 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.c +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.c @@ -1191,6 +1191,10 @@ static struct rayo_mixer *_rayo_mixer_create(const char *name, const char *file, */ static void rayo_component_cleanup(struct rayo_actor *actor) { + if (RAYO_COMPONENT(actor)->cleanup_fn) { + RAYO_COMPONENT(actor)->cleanup_fn(actor); + } + /* parent can now be destroyed */ RAYO_UNLOCK(RAYO_COMPONENT(actor)->parent); } @@ -1202,9 +1206,12 @@ static void rayo_component_cleanup(struct rayo_actor *actor) * @param id internal ID of this component * @param parent the parent that owns this component * @param client_jid the client that created this component + * @param cleanup optional cleanup function + * @param file file that called this function + * @param line line number that called this function * @return the component */ -struct rayo_component *_rayo_component_init(struct rayo_component *component, switch_memory_pool_t *pool, const char *type, const char *subtype, const char *id, struct rayo_actor *parent, const char *client_jid, const char *file, int line) +struct rayo_component *_rayo_component_init(struct rayo_component *component, switch_memory_pool_t *pool, const char *type, const char *subtype, const char *id, struct rayo_actor *parent, const char *client_jid, rayo_actor_cleanup_fn cleanup, const char *file, int line) { char *ref = switch_mprintf("%s-%d", subtype, rayo_actor_seq_next(parent)); char *jid = switch_mprintf("%s/%s", RAYO_JID(parent), ref); @@ -1218,6 +1225,7 @@ struct rayo_component *_rayo_component_init(struct rayo_component *component, sw component->client_jid = switch_core_strdup(pool, client_jid); component->ref = switch_core_strdup(pool, ref); component->parent = parent; + component->cleanup_fn = cleanup; switch_safe_free(ref); switch_safe_free(jid); @@ -2443,6 +2451,8 @@ static iks *on_iq_get_xmpp_disco(struct rayo_actor *server, struct rayo_message feature = iks_insert(x, "feature"); iks_insert_attrib(feature, "var", RAYO_NS); feature = iks_insert(x, "feature"); + iks_insert_attrib(feature, "var", RAYO_CPA_NS); + feature = iks_insert(x, "feature"); iks_insert_attrib(feature, "var", RAYO_FAX_NS); /* TODO The response MUST also include features for the application formats and transport methods supported by diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.h b/src/mod/event_handlers/mod_rayo/mod_rayo.h index b862802f31..9d0bf05490 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.h +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.h @@ -42,6 +42,9 @@ #define RAYO_CALL_NS RAYO_BASE "call:" RAYO_VERSION #define RAYO_MIXER_NS RAYO_BASE "mixer:" RAYO_VERSION +#define RAYO_CPA_BASE RAYO_BASE "cpa:" +#define RAYO_CPA_NS RAYO_CPA_BASE RAYO_VERSION + #define RAT_CALL "CALL" #define RAT_COMPONENT "COMPONENT" #define RAT_CALL_COMPONENT RAT_COMPONENT"_CALL" @@ -119,6 +122,8 @@ struct rayo_component { const char *client_jid; /** external ref */ const char *ref; + /** optional cleanup */ + rayo_actor_cleanup_fn cleanup_fn; }; #define RAYO_ACTOR(x) ((struct rayo_actor *)x) @@ -160,8 +165,9 @@ extern const char *rayo_call_get_dcp_jid(struct rayo_call *call); #define rayo_mixer_get_name(mixer) RAYO_ID(mixer) -#define rayo_component_init(component, pool, type, subtype, id, parent, client_jid) _rayo_component_init(component, pool, type, subtype, id, parent, client_jid, __FILE__, __LINE__) -extern struct rayo_component *_rayo_component_init(struct rayo_component *component, switch_memory_pool_t *pool, const char *type, const char *subtype, const char *id, struct rayo_actor *parent, const char *client_jid, const char *file, int line); +#define rayo_component_init(component, pool, type, subtype, id, parent, client_jid) _rayo_component_init(component, pool, type, subtype, id, parent, client_jid, NULL, __FILE__, __LINE__) +#define rayo_component_init_cleanup(component, pool, type, subtype, id, parent, client_jid, cleanup) _rayo_component_init(component, pool, type, subtype, id, parent, client_jid, cleanup, __FILE__, __LINE__) +extern struct rayo_component *_rayo_component_init(struct rayo_component *component, switch_memory_pool_t *pool, const char *type, const char *subtype, const char *id, struct rayo_actor *parent, const char *client_jid, rayo_actor_cleanup_fn cleanup, const char *file, int line); extern switch_bool_t is_component_actor(struct rayo_actor *); typedef iks *(*rayo_actor_xmpp_handler)(struct rayo_actor *, struct rayo_message *, void *); diff --git a/src/mod/event_handlers/mod_rayo/rayo_cpa_component.c b/src/mod/event_handlers/mod_rayo/rayo_cpa_component.c new file mode 100644 index 0000000000..8004347118 --- /dev/null +++ b/src/mod/event_handlers/mod_rayo/rayo_cpa_component.c @@ -0,0 +1,401 @@ +/* + * mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2014, Grasshopper + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is Grasshopper + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Rienzo + * + * rayo_cpa_component.c -- input component "cpa" mode implementation + */ +#include + +#include "rayo_cpa_component.h" +#include "mod_rayo.h" +#include "rayo_components.h" +#include "rayo_cpa_detector.h" + +/** + * Module globals + */ +struct { + /** signal subscribers */ + switch_hash_t *subscribers; + /** synchronizes access to subscribers */ + switch_mutex_t *subscribers_mutex; + /** module pool */ + switch_memory_pool_t *pool; +} globals; + +/** + * A CPA signal monitored by this component + */ +struct cpa_signal { + /** name of this signal */ + const char *name; + /** true if signal causes component termination */ + int terminate; +}; + +/** + * CPA component state + */ +struct cpa_component { + /** component base class */ + struct rayo_component base; + /** true if ready to forward detector events */ + int ready; + /** signals this component wants */ + switch_hash_t *signals; +}; + +#define CPA_COMPONENT(x) ((struct cpa_component *)x) + +typedef void (* subscriber_execute_fn)(const char *jid, void *user_data); + +/** + * Request signals + */ +static void subscribe(const char *uuid, const char *signal_type, const char *jid) +{ + char *key = switch_mprintf("%s:%s", uuid, signal_type); + switch_mutex_lock(globals.subscribers_mutex); + { + switch_hash_t *signal_subscribers = switch_core_hash_find(globals.subscribers, key); + switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Subscribe %s => %s\n", signal_type, jid); + if (!signal_subscribers) { + switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Create %s subscriber hash\n", signal_type); + switch_core_hash_init(&signal_subscribers, NULL); + switch_core_hash_insert(globals.subscribers, key, signal_subscribers); + } + switch_core_hash_insert(signal_subscribers, jid, "1"); + } + switch_mutex_unlock(globals.subscribers_mutex); + switch_safe_free(key); +} + +/** + * Stop receiving signals + */ +static void unsubscribe(const char *uuid, const char *signal_type, const char *jid) +{ + char *key = switch_mprintf("%s:%s", uuid, signal_type); + switch_mutex_lock(globals.subscribers_mutex); + { + switch_hash_t *signal_subscribers = switch_core_hash_find(globals.subscribers, key); + if (signal_subscribers) { + switch_core_hash_delete(signal_subscribers, jid); + switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Unsubscribe %s => %s\n", signal_type, jid); + + /* clean up hash if empty */ + if (!switch_core_hash_first(signal_subscribers)) { + switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Destroy %s subscriber hash\n", signal_type); + switch_core_hash_destroy(&signal_subscribers); + switch_core_hash_delete(globals.subscribers, key); + } + } + } + switch_mutex_unlock(globals.subscribers_mutex); + switch_safe_free(key); +} + +/** + * Execute function for each subscriber + */ +static void subscriber_execute(const char *uuid, const char *signal_type, subscriber_execute_fn callback, void *user_data) +{ + switch_event_t *subscriber_list = NULL; + switch_event_header_t *subscriber = NULL; + + /* fetch list of subscribers */ + char *key = switch_mprintf("%s:%s", uuid, signal_type); + switch_event_create_subclass(&subscriber_list, SWITCH_EVENT_CLONE, NULL); + switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Subscriber execute %s\n", signal_type); + switch_mutex_lock(globals.subscribers_mutex); + { + switch_hash_index_t *hi = NULL; + switch_hash_t *signal_subscribers = switch_core_hash_find(globals.subscribers, key); + if (signal_subscribers) { + for (hi = switch_core_hash_first(signal_subscribers); hi; hi = switch_core_hash_next(hi)) { + const void *jid; + void *dont_care; + switch_core_hash_this(hi, &jid, NULL, &dont_care); + switch_event_add_header_string(subscriber_list, SWITCH_STACK_BOTTOM, "execute", (const char *)jid); + } + } else { + switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "No subscribers for %s\n", signal_type); + } + } + switch_mutex_unlock(globals.subscribers_mutex); + switch_safe_free(key); + + /* execute function for each subscriber */ + for (subscriber = subscriber_list->headers; subscriber; subscriber = subscriber->next) { + callback(subscriber->value, user_data); + } + + switch_event_destroy(&subscriber_list); +} + +/** + * Stop all CPA detectors + */ +static void stop_cpa_detectors(struct cpa_component *cpa) +{ + if (cpa->signals) { + switch_hash_index_t *hi = NULL; + for (hi = switch_core_hash_first(cpa->signals); hi; hi = switch_core_hash_next(hi)) { + const char *signal_type; + struct cpa_signal *cpa_signal = NULL; + switch_core_hash_this(hi, (const void **)&signal_type, NULL, (void **)&cpa_signal); + if (cpa_signal) { + rayo_cpa_detector_stop(RAYO_COMPONENT(cpa)->parent->id, cpa_signal->name); + unsubscribe(RAYO_COMPONENT(cpa)->parent->id, cpa_signal->name, RAYO_JID(cpa)); + } + } + switch_core_hash_destroy(&cpa->signals); + cpa->signals = NULL; + } + unsubscribe(RAYO_COMPONENT(cpa)->parent->id, "hangup", RAYO_JID(cpa)); +} + +/** + * Stop execution of CPA component + */ +static iks *stop_cpa_component(struct rayo_actor *component, struct rayo_message *msg, void *data) +{ + stop_cpa_detectors(CPA_COMPONENT(component)); + rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_STOP); + return iks_new_iq_result(msg->payload); +} + +/** + * Forward CPA signal to client + */ +static void rayo_cpa_detector_event(const char *jid, void *user_data) +{ + struct rayo_actor *component = RAYO_LOCATE(jid); + if (component) { + if (CPA_COMPONENT(component)->ready) { + switch_event_t *event = (switch_event_t *)user_data; + const char *signal_type = switch_event_get_header(event, "signal-type"); + struct cpa_signal *cpa_signal = switch_core_hash_find(CPA_COMPONENT(component)->signals, signal_type); + switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_COMPONENT(component)->parent->id), SWITCH_LOG_DEBUG, "Handling CPA event\n"); + if (cpa_signal) { + const char *value = switch_event_get_header(event, "value"); + const char *duration = switch_event_get_header(event, "duration"); + if (cpa_signal->terminate) { + iks *complete_event; + iks *signal_xml; + + stop_cpa_detectors(CPA_COMPONENT(component)); + + /* send complete event to client */ + complete_event = rayo_component_create_complete_event(RAYO_COMPONENT(component), "signal", RAYO_CPA_NS); + signal_xml = iks_find(complete_event, "complete"); + signal_xml = iks_find(signal_xml, "signal"); + iks_insert_attrib(signal_xml, "type", signal_type); + if (!zstr(value)) { + iks_insert_attrib(signal_xml, "value", value); + } + if (!zstr(duration)) { + iks_insert_attrib(signal_xml, "duration", duration); + } + rayo_component_send_complete_event(RAYO_COMPONENT(component), complete_event); + } else { + /* send event to client */ + iks *signal_event = iks_new_presence("signal", RAYO_CPA_NS, RAYO_JID(component), RAYO_COMPONENT(component)->client_jid); + iks *signal_xml = iks_find(signal_event, "signal"); + iks_insert_attrib(signal_xml, "type", signal_type); + if (!zstr(value)) { + iks_insert_attrib(signal_xml, "value", value); + } + if (!zstr(duration)) { + iks_insert_attrib(signal_xml, "duration", duration); + } + RAYO_SEND_REPLY(component, RAYO_COMPONENT(component)->client_jid, signal_event); + } + } + } else { + switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_COMPONENT(component)->parent->id), SWITCH_LOG_DEBUG, "Skipping CPA event\n"); + } + RAYO_UNLOCK(component); + } +} + +/** + * Handle CPA signal-type event + */ +static void on_rayo_cpa_detector_event(switch_event_t *event) +{ + subscriber_execute(switch_event_get_header(event, "Unique-ID"), switch_event_get_header(event, "signal-type"), rayo_cpa_detector_event, event); +} + +/** + * Handle CPA completion because of hangup + */ +static void rayo_cpa_component_hangup(const char *jid, void *user_data) +{ + struct rayo_actor *component = RAYO_LOCATE(jid); + if (component) { + stop_cpa_detectors(CPA_COMPONENT(component)); + rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_HANGUP); + RAYO_UNLOCK(component); + } +} + +/** + * Handle hungup call event + */ +static void on_channel_hangup_complete_event(switch_event_t *event) +{ + subscriber_execute(switch_event_get_header(event, "Unique-ID"), "hangup", rayo_cpa_component_hangup, event); +} + +/** + * Start CPA + */ +iks *rayo_cpa_component_start(struct rayo_actor *call, struct rayo_message *msg, void *session_data) +{ + iks *iq = msg->payload; + switch_core_session_t *session = (switch_core_session_t *)session_data; + iks *input = iks_find(iq, "input"); + switch_memory_pool_t *pool = NULL; + struct cpa_component *component = NULL; + int have_grammar = 0; + iks *grammar = NULL; + + /* create CPA component */ + switch_core_new_memory_pool(&pool); + component = switch_core_alloc(pool, sizeof(*component)); + rayo_component_init((struct rayo_component *)component, pool, RAT_CALL_COMPONENT, "cpa", NULL, call, iks_find_attrib(iq, "from")); + + switch_core_hash_init(&component->signals, pool); + + /* start CPA detectors */ + for (grammar = iks_find(input, "grammar"); grammar; grammar = iks_next_tag(grammar)) { + if (!strcmp("grammar", iks_name(grammar))) { + const char *error_str = ""; + const char *url = iks_find_attrib_soft(grammar, "url"); + char *url_dup; + char *url_params; + + if (zstr(url)) { + stop_cpa_detectors(component); + RAYO_UNLOCK(component); + RAYO_DESTROY(component); + return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Missing grammar URL"); + } + have_grammar = 1; + + url_dup = strdup(url); + if ((url_params = strchr(url_dup, '?'))) { + *url_params = '\0'; + url_params++; + } + + if (switch_core_hash_find(component->signals, url)) { + free(url_dup); + stop_cpa_detectors(component); + RAYO_UNLOCK(component); + RAYO_DESTROY(component); + return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Duplicate URL"); + } + + /* start detector */ + /* TODO return better reasons... */ + if (rayo_cpa_detector_start(switch_core_session_get_uuid(session), url_dup, &error_str)) { + struct cpa_signal *cpa_signal = switch_core_alloc(pool, sizeof(*cpa_signal)); + cpa_signal->terminate = !zstr(url_params) && strstr(url_params, "terminate=true"); + cpa_signal->name = switch_core_strdup(pool, url_dup); + switch_core_hash_insert(component->signals, cpa_signal->name, cpa_signal); + subscribe(switch_core_session_get_uuid(session), cpa_signal->name, RAYO_JID(component)); + } else { + free(url_dup); + stop_cpa_detectors(component); + RAYO_UNLOCK(component); + RAYO_DESTROY(component); + return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, error_str); + } + + free(url_dup); + } + } + + if (!have_grammar) { + stop_cpa_detectors(component); + RAYO_UNLOCK(component); + RAYO_DESTROY(component); + return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "No grammar defined"); + } + + /* acknowledge command */ + rayo_component_send_start(RAYO_COMPONENT(component), iq); + + /* TODO hangup race condition */ + subscribe(switch_core_session_get_uuid(session), "hangup", RAYO_JID(component)); + + /* ready to forward detector events */ + component->ready = 1; + + return NULL; +} + +/** + * Load input CPA + * @param module_interface + * @param pool memory pool + * @param config_file + * @return SWITCH_STATUS_SUCCESS if successfully loaded + */ +switch_status_t rayo_cpa_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file) +{ + rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "cpa", "set:"RAYO_EXT_NS":stop", stop_cpa_component); + switch_event_bind("rayo_cpa_component", SWITCH_EVENT_CUSTOM, "rayo::cpa", on_rayo_cpa_detector_event, NULL); + switch_event_bind("rayo_cpa_component", SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE, NULL, on_channel_hangup_complete_event, NULL); + + globals.pool = pool; + switch_core_hash_init(&globals.subscribers, pool); + switch_mutex_init(&globals.subscribers_mutex, SWITCH_MUTEX_NESTED, pool); + + return rayo_cpa_detector_load(module_interface, pool, config_file); +} + +/** + * Stop input CPA + */ +void rayo_cpa_component_shutdown(void) +{ + switch_event_unbind_callback(on_rayo_cpa_detector_event); + switch_event_unbind_callback(on_channel_hangup_complete_event); + rayo_cpa_detector_shutdown(); + switch_core_hash_destroy(&globals.subscribers); +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet + */ diff --git a/src/mod/event_handlers/mod_rayo/rayo_cpa_component.h b/src/mod/event_handlers/mod_rayo/rayo_cpa_component.h new file mode 100644 index 0000000000..36354c9508 --- /dev/null +++ b/src/mod/event_handlers/mod_rayo/rayo_cpa_component.h @@ -0,0 +1,53 @@ +/* + * mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2014, Grasshopper + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is Grasshopper + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Rienzo + * + * rayo_cpa_component.h -- Rayo call progress analysis component + * + */ +#ifndef RAYO_CPA_COMPONENT_H +#define RAYO_CPA_COMPONENT_H + +#include +#include + +#include "mod_rayo.h" + +extern switch_status_t rayo_cpa_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file); +extern void rayo_cpa_component_shutdown(void); +extern iks *rayo_cpa_component_start(struct rayo_actor *call, struct rayo_message *msg, void *session_data); + +#endif + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet + */ diff --git a/src/mod/event_handlers/mod_rayo/rayo_cpa_detector.c b/src/mod/event_handlers/mod_rayo/rayo_cpa_detector.c index 9267e05456..27ce9a13be 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_cpa_detector.c +++ b/src/mod/event_handlers/mod_rayo/rayo_cpa_detector.c @@ -155,21 +155,27 @@ static void rayo_cpa_detector_event(switch_event_t *event) } if (!zstr(signal_type)) { switch_event_t *cpa_event; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Got Rayo CPA event %s\n", signal_type); + const char *uuid = switch_event_get_header(event, "Unique-ID"); + if (zstr(uuid)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Detector %s %s event is missing call UUID!\n", detector->name, signal_type); + return; + } + switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Got Rayo CPA event %s\n", signal_type); if (switch_event_create_subclass(&cpa_event, SWITCH_EVENT_CUSTOM, "rayo::cpa") == SWITCH_STATUS_SUCCESS) { - switch_event_add_header(cpa_event, SWITCH_STACK_BOTTOM, "detector-name", detector->name); - switch_event_add_header(cpa_event, SWITCH_STACK_BOTTOM, "detector-uuid", detector->uuid); - switch_event_add_header(cpa_event, SWITCH_STACK_BOTTOM, "signal-type", signal_type); + switch_event_add_header_string(cpa_event, SWITCH_STACK_BOTTOM, "Unique-ID", uuid); + switch_event_add_header_string(cpa_event, SWITCH_STACK_BOTTOM, "detector-name", detector->name); + switch_event_add_header_string(cpa_event, SWITCH_STACK_BOTTOM, "detector-uuid", detector->uuid); + switch_event_add_header(cpa_event, SWITCH_STACK_BOTTOM, "signal-type", "%s%s:%s", RAYO_CPA_BASE, signal_type, RAYO_VERSION); if (!zstr(detector->signal_value_header)) { const char *value = switch_event_get_header(event, detector->signal_value_header); if (!zstr(value)) { - switch_event_add_header(cpa_event, SWITCH_STACK_BOTTOM, "value", value); + switch_event_add_header_string(cpa_event, SWITCH_STACK_BOTTOM, "value", value); } } if (!zstr(detector->signal_duration_header)) { const char *duration = switch_event_get_header(event, detector->signal_duration_header); if (!zstr(duration)) { - switch_event_add_header(cpa_event, SWITCH_STACK_BOTTOM, "duration", duration); + switch_event_add_header_string(cpa_event, SWITCH_STACK_BOTTOM, "duration", duration); } } switch_event_fire(&cpa_event); diff --git a/src/mod/event_handlers/mod_rayo/rayo_cpa_detector.h b/src/mod/event_handlers/mod_rayo/rayo_cpa_detector.h index 335d1c3a1b..fcdc35f2f4 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_cpa_detector.h +++ b/src/mod/event_handlers/mod_rayo/rayo_cpa_detector.h @@ -33,21 +33,6 @@ #include "mod_rayo.h" -#define RAYO_CPA_BASE RAYO_BASE "cpa:" -#define RAYO_CPA_NS RAYO_CPA_BASE RAYO_VERSION - -#define RAYO_CPA_BEEP_NS RAYO_CPA_BASE "beep:" RAYO_VERSION -#define RAYO_CPA_DTMF_NS RAYO_CPA_BASE "dtmf:" RAYO_VERSION -#define RAYO_CPA_SPEECH_NS RAYO_CPA_BASE "speech:" RAYO_VERSION -#define RAYO_CPA_FAX_CED_NS RAYO_CPA_BASE "fax-ced:" RAYO_VERSION -#define RAYO_CPA_FAX_CNG_NS RAYO_CPA_BASE "fax-cng:" RAYO_VERSION -#define RAYO_CPA_RING_NS RAYO_CPA_BASE "ring:" RAYO_VERSION -#define RAYO_CPA_BUSY_NS RAYO_CPA_BASE "busy:" RAYO_VERSION -#define RAYO_CPA_CONGESTION_NS RAYO_CPA_BASE "congestion:" RAYO_VERSION -#define RAYO_CPA_SIT_NS RAYO_CPA_BASE "sit:" RAYO_VERSION -#define RAYO_CPA_MODEM_NS RAYO_CPA_BASE "modem:" RAYO_VERSION -#define RAYO_CPA_OFFHOOK_NS RAYO_CPA_BASE "offhook:" RAYO_VERSION - extern switch_status_t rayo_cpa_detector_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file); extern void rayo_cpa_detector_shutdown(void); extern int rayo_cpa_detector_start(const char *call_uuid, const char *signal_ns, const char **error_detail); diff --git a/src/mod/event_handlers/mod_rayo/rayo_elements.c b/src/mod/event_handlers/mod_rayo/rayo_elements.c index 78209c3bd6..1720471e31 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_elements.c +++ b/src/mod/event_handlers/mod_rayo/rayo_elements.c @@ -33,7 +33,7 @@ */ ELEMENT(RAYO_INPUT) ATTRIB(xmlns,, any) - STRING_ATTRIB(mode, any, "any,dtmf,voice") + STRING_ATTRIB(mode, any, "any,dtmf,voice,cpa") OPTIONAL_ATTRIB(terminator,, dtmf_digit) ATTRIB(recognizer,, any) ATTRIB(language, en-US, any) diff --git a/src/mod/event_handlers/mod_rayo/rayo_input_component.c b/src/mod/event_handlers/mod_rayo/rayo_input_component.c index 4ea0e5f600..41383a1d23 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_input_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_input_component.c @@ -27,7 +27,7 @@ * */ #include "rayo_components.h" -#include "rayo_cpa_detector.h" +#include "rayo_cpa_component.h" #include "rayo_elements.h" #include "srgs.h" #include "nlsml.h" @@ -360,10 +360,14 @@ static iks *start_call_input(struct input_component *component, switch_core_sess component->speech_mode = strcmp(iks_find_attrib_soft(input, "mode"), "dtmf"); if (component->speech_mode && handler->voice_component) { /* don't allow multi voice input */ + RAYO_UNLOCK(component); + RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_CONFLICT, "Multiple voice input is not allowed"); } if (!component->speech_mode && handler->dtmf_component) { /* don't allow multi dtmf input */ + RAYO_UNLOCK(component); + RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_CONFLICT, "Multiple dtmf input is not allowed"); } @@ -538,17 +542,20 @@ static iks *start_call_input_component(struct rayo_actor *call, struct rayo_mess struct input_component *input_component = NULL; const char *error = NULL; + /* Start CPA */ + if (!strcmp(iks_find_attrib_soft(input, "mode"), "cpa")) { + return rayo_cpa_component_start(call, msg, session_data); + } + + /* start input */ if (!validate_call_input(input, &error)) { return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, error); } - /* create component */ switch_core_new_memory_pool(&pool); input_component = switch_core_alloc(pool, sizeof(*input_component)); rayo_component_init(RAYO_COMPONENT(input_component), pool, RAT_CALL_COMPONENT, "input", component_id, call, iks_find_attrib(iq, "from")); - - /* start input */ - return start_call_input(input_component, session, iks_find(iq, "input"), iq, NULL, 0); + return start_call_input(input_component, session, input, iq, NULL, 0); } /** @@ -761,7 +768,7 @@ switch_status_t rayo_input_component_load(switch_loadable_module_interface_t **m rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "input", "set:"RAYO_INPUT_NS":start-timers", start_timers_call_input_component); switch_event_bind("rayo_input_component", SWITCH_EVENT_DETECTED_SPEECH, SWITCH_EVENT_SUBCLASS_ANY, on_detected_speech_event, NULL); - return rayo_cpa_detector_load(module_interface, pool, config_file); + return rayo_cpa_component_load(module_interface, pool, config_file); } /** @@ -773,7 +780,7 @@ switch_status_t rayo_input_component_shutdown(void) srgs_parser_destroy(globals.parser); switch_event_unbind_callback(on_detected_speech_event); - rayo_cpa_detector_shutdown(); + rayo_cpa_component_shutdown(); return SWITCH_STATUS_SUCCESS; }