freeswitch/src/mod/event_handlers/mod_rayo/rayo_prompt_component.c

674 lines
24 KiB
C

/*
* mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2013, 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 <chris.rienzo@grasshopper.com>
*
* rayo_prompt_component.c -- Rayo prompt component implementation
*
*/
#include "rayo_components.h"
#include "rayo_elements.h"
enum prompt_component_state {
/* initial state - no barge */
PCS_START_OUTPUT,
/* playing prompt */
PCS_OUTPUT,
/* start input - no barge */
PCS_START_INPUT,
/* input starting - start timers needed */
PCS_START_INPUT_TIMERS,
/* initial state - barge in */
PCS_START_OUTPUT_BARGE,
/* start input for barge-in */
PCS_START_INPUT_OUTPUT,
/* playing and detecting */
PCS_INPUT_OUTPUT,
/* barge in on output */
PCS_STOP_OUTPUT,
/* detecting */
PCS_INPUT,
/* finishing, stop output */
PCS_DONE_STOP_OUTPUT,
/* finished */
PCS_DONE
};
/**
* Prompt state
*/
struct prompt_component {
struct rayo_component base;
enum prompt_component_state state;
iks *iq;
iks *complete;
const char *input_jid;
const char *output_jid;
};
#define PROMPT_COMPONENT(x) ((struct prompt_component *)x)
static const char *prompt_component_state_to_string(enum prompt_component_state state)
{
switch(state) {
case PCS_START_OUTPUT_BARGE: return "START_OUTPUT_BARGE";
case PCS_START_OUTPUT: return "START_OUTPUT";
case PCS_START_INPUT_OUTPUT: return "START_INPUT_OUTPUT";
case PCS_START_INPUT: return "START_INPUT";
case PCS_START_INPUT_TIMERS: return "START_INPUT_TIMERS";
case PCS_INPUT_OUTPUT: return "INPUT_OUTPUT";
case PCS_STOP_OUTPUT: return "STOP_OUTPUT";
case PCS_INPUT: return "INPUT";
case PCS_OUTPUT: return "OUTPUT";
case PCS_DONE_STOP_OUTPUT: return "DONE_STOP_OUTPUT";
case PCS_DONE: return "DONE";
}
return "UNKNOWN";
}
/**
* Send stop to component
*/
static void rayo_component_send_stop(struct rayo_actor *from, const char *to)
{
iks *stop = iks_new("iq");
iks *x;
iks_insert_attrib(stop, "from", RAYO_JID(from));
iks_insert_attrib(stop, "to", to);
iks_insert_attrib(stop, "type", "set");
iks_insert_attrib_printf(stop, "id", "mod_rayo-prompt-%d", RAYO_SEQ_NEXT(from));
x = iks_insert(stop, "stop");
iks_insert_attrib(x, "xmlns", RAYO_EXT_NS);
RAYO_SEND_MESSAGE(from, to, stop);
}
/**
* Start input component
*/
static void start_input(struct prompt_component *prompt, int start_timers, int barge_event)
{
iks *iq = iks_new("iq");
iks *input = iks_find(PROMPT_COMPONENT(prompt)->iq, "prompt");
input = iks_find(input, "input");
iks_insert_attrib(iq, "from", RAYO_JID(prompt));
iks_insert_attrib(iq, "to", RAYO_JID(RAYO_COMPONENT(prompt)->parent));
iks_insert_attrib_printf(iq, "id", "mod_rayo-prompt-%d", RAYO_SEQ_NEXT(prompt));
iks_insert_attrib(iq, "type", "set");
input = iks_copy_within(input, iks_stack(iq));
iks_insert_attrib(input, "start-timers", start_timers ? "true" : "false");
iks_insert_attrib(input, "barge-event", barge_event ? "true" : "false");
iks_insert_node(iq, input);
RAYO_SEND_MESSAGE(prompt, RAYO_JID(RAYO_COMPONENT(prompt)->parent), iq);
}
/**
* Start input component timers
*/
static void start_input_timers(struct prompt_component *prompt)
{
iks *x;
iks *iq = iks_new("iq");
iks_insert_attrib(iq, "from", RAYO_JID(prompt));
iks_insert_attrib(iq, "to", prompt->input_jid);
iks_insert_attrib(iq, "type", "set");
iks_insert_attrib_printf(iq, "id", "mod_rayo-prompt-%d", RAYO_SEQ_NEXT(prompt));
x = iks_insert(iq, "start-timers");
iks_insert_attrib(x, "xmlns", RAYO_INPUT_NS);
RAYO_SEND_MESSAGE(prompt, prompt->input_jid, iq);
}
/**
* Handle start of output.
*/
static iks *prompt_component_handle_output_start(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) output start\n",
RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state));
switch (PROMPT_COMPONENT(prompt)->state) {
case PCS_START_OUTPUT:
PROMPT_COMPONENT(prompt)->output_jid = switch_core_strdup(RAYO_POOL(prompt), msg->from_jid);
PROMPT_COMPONENT(prompt)->state = PCS_OUTPUT;
/* send ref to client */
rayo_component_send_start(RAYO_COMPONENT(prompt), PROMPT_COMPONENT(prompt)->iq);
break;
case PCS_START_OUTPUT_BARGE:
PROMPT_COMPONENT(prompt)->output_jid = switch_core_strdup(RAYO_POOL(prompt), msg->from_jid);
PROMPT_COMPONENT(prompt)->state = PCS_START_INPUT_OUTPUT;
/* start input without timers and with barge events */
start_input(PROMPT_COMPONENT(prompt), 0, 1);
break;
case PCS_OUTPUT:
case PCS_START_INPUT_OUTPUT:
case PCS_START_INPUT:
case PCS_START_INPUT_TIMERS:
case PCS_INPUT_OUTPUT:
case PCS_STOP_OUTPUT:
case PCS_INPUT:
case PCS_DONE_STOP_OUTPUT:
case PCS_DONE:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, unexpected start output event\n", RAYO_JID(prompt));
break;
}
return NULL;
}
/**
* Handle start of input.
*/
static iks *prompt_component_handle_input_start(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) input start\n",
RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state));
switch (PROMPT_COMPONENT(prompt)->state) {
case PCS_START_INPUT:
PROMPT_COMPONENT(prompt)->input_jid = switch_core_strdup(RAYO_POOL(prompt), msg->from_jid);
PROMPT_COMPONENT(prompt)->state = PCS_INPUT;
break;
case PCS_START_INPUT_OUTPUT:
PROMPT_COMPONENT(prompt)->input_jid = switch_core_strdup(RAYO_POOL(prompt), msg->from_jid);
PROMPT_COMPONENT(prompt)->state = PCS_INPUT_OUTPUT;
/* send ref to client */
rayo_component_send_start(RAYO_COMPONENT(prompt), PROMPT_COMPONENT(prompt)->iq);
iks_delete(PROMPT_COMPONENT(prompt)->iq);
break;
case PCS_START_INPUT_TIMERS:
PROMPT_COMPONENT(prompt)->input_jid = switch_core_strdup(RAYO_POOL(prompt), msg->from_jid);
PROMPT_COMPONENT(prompt)->state = PCS_INPUT;
/* send ref to client */
rayo_component_send_start(RAYO_COMPONENT(prompt), PROMPT_COMPONENT(prompt)->iq);
iks_delete(PROMPT_COMPONENT(prompt)->iq);
start_input_timers(PROMPT_COMPONENT(prompt));
break;
case PCS_DONE:
/* stopped by client */
PROMPT_COMPONENT(prompt)->input_jid = switch_core_strdup(RAYO_POOL(prompt), msg->from_jid);
rayo_component_send_stop(prompt, msg->from_jid);
break;
case PCS_START_OUTPUT:
case PCS_START_OUTPUT_BARGE:
case PCS_INPUT_OUTPUT:
case PCS_INPUT:
case PCS_STOP_OUTPUT:
case PCS_OUTPUT:
case PCS_DONE_STOP_OUTPUT:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, unexpected start input event\n", RAYO_JID(prompt));
break;
}
return NULL;
}
/**
* Handle start of input/output.
*/
static iks *prompt_component_handle_io_start(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
iks *iq = msg->payload;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, got <ref> from %s: %s\n",
RAYO_JID(prompt), msg->from_jid, iks_string(iks_stack(iq), iq));
if (!strcmp("input", msg->from_subtype)) {
return prompt_component_handle_input_start(prompt, msg, data);
} else if (!strcmp("output", msg->from_subtype)) {
return prompt_component_handle_output_start(prompt, msg, data);
}
return NULL;
}
/**
* Handle barge event
*/
static iks *prompt_component_handle_input_start_timers_error(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
/* this is only expected if input component is gone */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) start timers error\n",
RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state));
return NULL;
}
/**
* Handle input failure.
*/
static iks *prompt_component_handle_input_error(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
iks *iq = msg->payload;
iks *error = iks_find(iq, "error");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) input error\n",
RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state));
switch (PROMPT_COMPONENT(prompt)->state) {
case PCS_START_INPUT_TIMERS:
case PCS_START_INPUT:
/* send error to client */
PROMPT_COMPONENT(prompt)-> state = PCS_DONE;
iks_delete(PROMPT_COMPONENT(prompt)->iq);
rayo_component_send_complete(RAYO_COMPONENT(prompt), COMPONENT_COMPLETE_ERROR);
break;
break;
case PCS_START_INPUT_OUTPUT:
PROMPT_COMPONENT(prompt)->state = PCS_DONE_STOP_OUTPUT;
/* forward error to client */
iq = PROMPT_COMPONENT(prompt)->iq;
iks_insert_attrib(iq, "from", RAYO_JID(RAYO_COMPONENT(prompt)->parent));
iks_insert_attrib(iq, "to", RAYO_COMPONENT(prompt)->client_jid);
iks_insert_node(iq, iks_copy_within(error, iks_stack(iq)));
PROMPT_COMPONENT(prompt)->complete = iq;
rayo_component_send_stop(prompt, PROMPT_COMPONENT(prompt)->output_jid);
break;
case PCS_START_OUTPUT:
case PCS_START_OUTPUT_BARGE:
case PCS_INPUT_OUTPUT:
case PCS_STOP_OUTPUT:
case PCS_INPUT:
case PCS_OUTPUT:
case PCS_DONE_STOP_OUTPUT:
case PCS_DONE:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, unexpected start input error event\n", RAYO_JID(prompt));
break;
}
return NULL;
}
/**
* Handle output failure.
*/
static iks *prompt_component_handle_output_error(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
iks *iq = msg->payload;
iks *error = iks_find(iq, "error");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) output error\n",
RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state));
switch (PROMPT_COMPONENT(prompt)->state) {
case PCS_START_OUTPUT:
case PCS_START_OUTPUT_BARGE:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, <output> error: %s\n", RAYO_JID(prompt), iks_string(iks_stack(iq), iq));
PROMPT_COMPONENT(prompt)->state = PCS_DONE;
/* forward error to client */
iq = PROMPT_COMPONENT(prompt)->iq;
iks_insert_attrib(iq, "from", RAYO_JID(RAYO_COMPONENT(prompt)->parent));
iks_insert_attrib(iq, "to", RAYO_COMPONENT(prompt)->client_jid);
iks_insert_node(iq, iks_copy_within(error, iks_stack(iq)));
RAYO_SEND_REPLY(prompt, RAYO_COMPONENT(prompt)->client_jid, iq);
/* done */
RAYO_UNLOCK(prompt);
RAYO_DESTROY(prompt);
break;
case PCS_START_INPUT_OUTPUT:
case PCS_START_INPUT_TIMERS:
case PCS_START_INPUT:
case PCS_INPUT_OUTPUT:
case PCS_STOP_OUTPUT:
case PCS_INPUT:
case PCS_OUTPUT:
case PCS_DONE_STOP_OUTPUT:
case PCS_DONE:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, unexpected start output error event\n", RAYO_JID(prompt));
break;
}
return NULL;
}
/**
* Handle barge event
*/
static iks *prompt_component_handle_input_barge(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
iks *presence = msg->payload;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) input barge\n",
RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state));
switch (PROMPT_COMPONENT(prompt)->state) {
case PCS_INPUT_OUTPUT:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, got <start-of-input> from %s: %s\n",
RAYO_JID(prompt), msg->from_jid, iks_string(iks_stack(presence), presence));
PROMPT_COMPONENT(prompt)->state = PCS_STOP_OUTPUT;
rayo_component_send_stop(prompt, PROMPT_COMPONENT(prompt)->output_jid);
break;
case PCS_STOP_OUTPUT:
case PCS_INPUT:
/* don't care */
break;
case PCS_OUTPUT:
case PCS_START_OUTPUT:
case PCS_START_OUTPUT_BARGE:
case PCS_START_INPUT:
case PCS_START_INPUT_OUTPUT:
case PCS_START_INPUT_TIMERS:
case PCS_DONE_STOP_OUTPUT:
case PCS_DONE:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, unexpected start output error event\n", RAYO_JID(prompt));
break;
}
return NULL;
}
/**
* Handle completion event
*/
static iks *prompt_component_handle_input_complete(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
iks *presence = msg->payload;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) input complete\n",
RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state));
switch (PROMPT_COMPONENT(prompt)->state) {
case PCS_INPUT_OUTPUT:
PROMPT_COMPONENT(prompt)->state = PCS_DONE_STOP_OUTPUT;
presence = iks_copy(presence);
iks_insert_attrib(presence, "from", RAYO_JID(prompt));
iks_insert_attrib(presence, "to", RAYO_COMPONENT(prompt)->client_jid);
PROMPT_COMPONENT(prompt)->complete = presence;
rayo_component_send_stop(prompt, PROMPT_COMPONENT(prompt)->output_jid);
break;
case PCS_STOP_OUTPUT:
PROMPT_COMPONENT(prompt)->state = PCS_DONE_STOP_OUTPUT;
presence = iks_copy(presence);
iks_insert_attrib(presence, "from", RAYO_JID(prompt));
iks_insert_attrib(presence, "to", RAYO_COMPONENT(prompt)->client_jid);
PROMPT_COMPONENT(prompt)->complete = presence;
break;
case PCS_INPUT:
PROMPT_COMPONENT(prompt)->state = PCS_DONE;
/* pass through */
case PCS_DONE:
presence = iks_copy(presence);
iks_insert_attrib(presence, "from", RAYO_JID(prompt));
iks_insert_attrib(presence, "to", RAYO_COMPONENT(prompt)->client_jid);
rayo_component_send_complete_event(RAYO_COMPONENT(prompt), presence);
break;
case PCS_OUTPUT:
case PCS_START_OUTPUT:
case PCS_START_OUTPUT_BARGE:
case PCS_START_INPUT:
case PCS_START_INPUT_OUTPUT:
case PCS_START_INPUT_TIMERS:
case PCS_DONE_STOP_OUTPUT:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, unexpected start output error event\n", RAYO_JID(prompt));
break;
}
return NULL;
}
/**
* Forward result
*/
static iks *prompt_component_handle_result(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
iks *iq = msg->payload;
/* forward all results, except for internal ones... */
if (strncmp("mod_rayo-prompt", iks_find_attrib_soft(iq, "id"), 15)) {
iks_insert_attrib(iq, "from", RAYO_JID(prompt));
iks_insert_attrib(iq, "to", RAYO_COMPONENT(prompt)->client_jid);
RAYO_SEND_REPLY_DUP(prompt, RAYO_COMPONENT(prompt)->client_jid, iq);
}
return NULL;
}
/**
* Handle completion event
*/
static iks *prompt_component_handle_output_complete(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) output complete\n",
RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state));
switch (PROMPT_COMPONENT(prompt)->state) {
case PCS_OUTPUT:
PROMPT_COMPONENT(prompt)->state = PCS_START_INPUT;
/* start input with timers enabled and barge events disabled */
start_input(PROMPT_COMPONENT(prompt), 1, 0);
iks_delete(PROMPT_COMPONENT(prompt)->iq);
break;
case PCS_START_INPUT_OUTPUT:
PROMPT_COMPONENT(prompt)->state = PCS_INPUT;
break;
case PCS_INPUT_OUTPUT:
PROMPT_COMPONENT(prompt)->state = PCS_INPUT;
start_input_timers(PROMPT_COMPONENT(prompt));
break;
case PCS_STOP_OUTPUT:
PROMPT_COMPONENT(prompt)->state = PCS_INPUT;
start_input_timers(PROMPT_COMPONENT(prompt));
break;
case PCS_DONE_STOP_OUTPUT:
if (PROMPT_COMPONENT(prompt)->complete) {
rayo_component_send_complete_event(RAYO_COMPONENT(prompt), PROMPT_COMPONENT(prompt)->complete);
}
break;
case PCS_INPUT:
case PCS_START_OUTPUT:
case PCS_START_OUTPUT_BARGE:
case PCS_START_INPUT:
case PCS_START_INPUT_TIMERS:
case PCS_DONE:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, unexpected start output error event\n", RAYO_JID(prompt));
break;
}
return NULL;
}
/**
* Start execution of prompt component
*/
static iks *start_call_prompt_component(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;
switch_memory_pool_t *pool;
struct prompt_component *prompt_component = NULL;
iks *prompt = iks_find(iq, "prompt");
iks *input;
iks *output;
iks *cmd;
if (!VALIDATE_RAYO_PROMPT(prompt)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Bad <prompt> attrib\n");
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Bad <prompt> attrib value");
}
output = iks_find(prompt, "output");
if (!output) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Missing <output>\n");
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Missing <output>");
}
input = iks_find(prompt, "input");
if (!input) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Missing <input>\n");
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Missing <input>");
}
/* create prompt component, linked to call */
switch_core_new_memory_pool(&pool);
prompt_component = switch_core_alloc(pool, sizeof(*prompt_component));
rayo_component_init(RAYO_COMPONENT(prompt_component), pool, RAT_CALL_COMPONENT, "prompt", NULL, call, iks_find_attrib(iq, "from"));
prompt_component->iq = iks_copy(iq);
/* start output */
if (iks_find_bool_attrib(prompt, "barge-in")) {
prompt_component->state = PCS_START_OUTPUT_BARGE;
} else {
prompt_component->state = PCS_START_OUTPUT;
}
cmd = iks_new("iq");
iks_insert_attrib(cmd, "from", RAYO_JID(prompt_component));
iks_insert_attrib(cmd, "to", RAYO_JID(call));
iks_insert_attrib(cmd, "id", iks_find_attrib(iq, "id"));
iks_insert_attrib(cmd, "type", "set");
output = iks_copy_within(output, iks_stack(cmd));
iks_insert_node(cmd, output);
RAYO_SEND_MESSAGE(prompt_component, RAYO_JID(call), cmd);
return NULL;
}
/**
* Stop execution of prompt component
*/
static iks *stop_call_prompt_component(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
iks *iq = msg->payload;
iks *reply = NULL;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) stop prompt\n",
RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state));
switch (PROMPT_COMPONENT(prompt)->state) {
case PCS_OUTPUT:
/* input hasn't started yet */
PROMPT_COMPONENT(prompt)->state = PCS_DONE_STOP_OUTPUT;
PROMPT_COMPONENT(prompt)->complete = rayo_component_create_complete_event(RAYO_COMPONENT(prompt), COMPONENT_COMPLETE_STOP);
rayo_component_send_stop(prompt, PROMPT_COMPONENT(prompt)->output_jid);
break;
case PCS_INPUT_OUTPUT:
case PCS_INPUT:
case PCS_STOP_OUTPUT:
/* stopping input will trigger completion */
rayo_component_send_stop(prompt, PROMPT_COMPONENT(prompt)->input_jid);
break;
case PCS_START_INPUT:
/* stop input as soon as it starts */
PROMPT_COMPONENT(prompt)->state = PCS_DONE;
break;
case PCS_DONE_STOP_OUTPUT:
case PCS_DONE:
/* already done */
break;
case PCS_START_OUTPUT:
case PCS_START_OUTPUT_BARGE:
case PCS_START_INPUT_OUTPUT:
case PCS_START_INPUT_TIMERS:
/* ref hasn't been sent yet */
reply = iks_new_error(iq, STANZA_ERROR_UNEXPECTED_REQUEST);
break;
}
if (!reply) {
reply = iks_new_iq_result(iq);
}
return reply;
}
/**
* Pass output component command
*/
static iks *forward_output_component_request(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
iks *iq = msg->payload;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s) %s prompt\n",
RAYO_JID(prompt), prompt_component_state_to_string(PROMPT_COMPONENT(prompt)->state), iks_name(iks_first_tag(iq)));
switch (PROMPT_COMPONENT(prompt)->state) {
case PCS_OUTPUT:
case PCS_START_INPUT_OUTPUT:
case PCS_INPUT_OUTPUT: {
/* forward request to output component */
iks_insert_attrib(iq, "from", RAYO_JID(prompt));
iks_insert_attrib(iq, "to", PROMPT_COMPONENT(prompt)->output_jid);
RAYO_SEND_MESSAGE_DUP(prompt, PROMPT_COMPONENT(prompt)->output_jid, iq);
return NULL;
}
case PCS_START_INPUT_TIMERS:
case PCS_START_OUTPUT:
case PCS_START_OUTPUT_BARGE:
/* ref hasn't been sent yet */
return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "too soon");
break;
case PCS_START_INPUT:
case PCS_STOP_OUTPUT:
case PCS_DONE_STOP_OUTPUT:
case PCS_INPUT:
case PCS_DONE:
return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "output is finished");
}
return NULL;
}
/**
* Initialize prompt component
* @param module_interface
* @param pool memory pool to allocate from
* @param config_file to use
* @return SWITCH_STATUS_SUCCESS if successful
*/
switch_status_t rayo_prompt_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file)
{
/* Prompt is a convenience component that wraps <input> and <output> */
rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_PROMPT_NS":prompt", start_call_prompt_component);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "prompt", "set:"RAYO_EXT_NS":stop", stop_call_prompt_component);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "prompt", "result:"RAYO_NS":ref", prompt_component_handle_io_start);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "prompt", "result::", prompt_component_handle_result);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "prompt", "error:"RAYO_OUTPUT_NS":output", prompt_component_handle_output_error);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "prompt", "error:"RAYO_INPUT_NS":input", prompt_component_handle_input_error);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "prompt", "error:"RAYO_INPUT_NS":start-timers", prompt_component_handle_input_start_timers_error);
rayo_actor_event_handler_add(RAT_CALL_COMPONENT, "input", RAT_CALL_COMPONENT, "prompt", ":"RAYO_INPUT_NS":start-of-input", prompt_component_handle_input_barge);
rayo_actor_event_handler_add(RAT_CALL_COMPONENT, "input", RAT_CALL_COMPONENT, "prompt", "unavailable:"RAYO_EXT_NS":complete", prompt_component_handle_input_complete);
rayo_actor_event_handler_add(RAT_CALL_COMPONENT, "output", RAT_CALL_COMPONENT, "prompt", "unavailable:"RAYO_EXT_NS":complete", prompt_component_handle_output_complete);
/* wrap output commands */
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "prompt", "set:"RAYO_OUTPUT_NS":pause", forward_output_component_request);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "prompt", "set:"RAYO_OUTPUT_NS":resume", forward_output_component_request);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "prompt", "set:"RAYO_OUTPUT_NS":speed-up", forward_output_component_request);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "prompt", "set:"RAYO_OUTPUT_NS":speed-down", forward_output_component_request);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "prompt", "set:"RAYO_OUTPUT_NS":volume-up", forward_output_component_request);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "prompt", "set:"RAYO_OUTPUT_NS":volume-down", forward_output_component_request);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "prompt", "set:"RAYO_OUTPUT_NS":seek", forward_output_component_request);
return SWITCH_STATUS_SUCCESS;
}
/**
* Shutdown prompt component
* @return SWITCH_STATUS_SUCCESS if successful
*/
switch_status_t rayo_prompt_component_shutdown(void)
{
return SWITCH_STATUS_SUCCESS;
}
/* 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
*/