/** * 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; }
/** * Create new output component */ static struct rayo_component *create_output_component(struct rayo_actor *actor, const char *type, iks *output, const char *client_jid) { switch_memory_pool_t *pool; struct output_component *output_component = NULL; switch_core_new_memory_pool(&pool); output_component = switch_core_alloc(pool, sizeof(*output_component)); output_component = OUTPUT_COMPONENT(rayo_component_init((struct rayo_component *)output_component, pool, type, "output", NULL, actor, client_jid)); if (output_component) { output_component->document = iks_copy(output); output_component->start_offset_ms = iks_find_int_attrib(output, "start-offset"); output_component->repeat_interval_ms = iks_find_int_attrib(output, "repeat-interval"); output_component->repeat_times = iks_find_int_attrib(output, "repeat-times"); output_component->max_time_ms = iks_find_int_attrib(output, "max-time"); output_component->start_paused = iks_find_bool_attrib(output, "start-paused"); output_component->renderer = switch_core_strdup(RAYO_POOL(output_component), iks_find_attrib_soft(output, "renderer")); /* get custom headers */ { switch_stream_handle_t headers = { 0 }; iks *header = NULL; int first = 1; SWITCH_STANDARD_STREAM(headers); for (header = iks_find(output, "header"); header; header = iks_next_tag(header)) { if (!strcmp("header", iks_name(header))) { const char *name = iks_find_attrib_soft(header, "name"); const char *value = iks_find_attrib_soft(header, "value"); if (!zstr(name) && !zstr(value)) { headers.write_function(&headers, "%s%s=%s", first ? "{" : ",", name, value); first = 0; } } } if (headers.data) { headers.write_function(&headers, "}"); output_component->headers = switch_core_strdup(RAYO_POOL(output_component), (char *)headers.data); free(headers.data); } } } else { switch_core_destroy_memory_pool(&pool); } return RAYO_COMPONENT(output_component); }
/** * Create a record component */ static struct rayo_component *record_component_create(struct rayo_actor *actor, const char *client_jid, iks *record) { switch_memory_pool_t *pool; struct record_component *record_component = NULL; char *local_file_path; char *fs_file_path; switch_bool_t start_paused; /* validate record attributes */ if (!VALIDATE_RAYO_RECORD(record)) { return NULL; } start_paused = iks_find_bool_attrib(record, "start-paused"); /* create record filename from session UUID and ref */ /* for example: prefix/1234-1234-1234-1234-30.wav */ local_file_path = switch_mprintf("%s%s-%i.%s", globals.record_file_prefix, actor->id, rayo_actor_seq_next(actor), iks_find_attrib(record, "format")); fs_file_path = switch_mprintf("{pause=%s}fileman://%s", start_paused ? "true" : "false", local_file_path); switch_core_new_memory_pool(&pool); record_component = switch_core_alloc(pool, sizeof(*record_component)); rayo_component_init(RAYO_COMPONENT(record_component), pool, "record", fs_file_path, actor, client_jid); record_component->max_duration = iks_find_int_attrib(record, "max-duration"); record_component->initial_timeout = iks_find_int_attrib(record, "initial-timeout"); record_component->final_timeout = iks_find_int_attrib(record, "final-timeout"); record_component->direction = switch_core_strdup(RAYO_POOL(record_component), iks_find_attrib_soft(record, "direction")); record_component->mix = iks_find_bool_attrib(record, "mix"); record_component->start_beep = iks_find_bool_attrib(record, "start-beep"); record_component->stop_beep = iks_find_bool_attrib(record, "stop-beep"); record_component->start_time = start_paused ? 0 : switch_micro_time_now(); record_component->local_file_path = switch_core_strdup(RAYO_POOL(record_component), local_file_path); switch_safe_free(local_file_path); switch_safe_free(fs_file_path); return RAYO_COMPONENT(record_component); }
/** * 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"); prompt->start_timers_request_id = switch_core_sprintf(RAYO_POOL(prompt), "mod_rayo-prompt-%d", RAYO_SEQ_NEXT(prompt)); iks_insert_attrib(iq, "id", prompt->start_timers_request_id); x = iks_insert(iq, "start-timers"); iks_insert_attrib(x, "xmlns", RAYO_INPUT_NS); RAYO_SEND_MESSAGE(prompt, prompt->input_jid, iq); }
/** * Notify completion of record component */ static void complete_record(struct rayo_component *component, const char *reason, const char *reason_namespace) { switch_core_session_t *session = NULL; const char *uuid = component->parent->id; char *uri = switch_mprintf("file://%s", RECORD_COMPONENT(component)->local_file_path); iks *recording; switch_size_t file_size = 0; /* TODO this doesn't work with HTTP */ #if 0 switch_file_t *file; if (switch_file_open(&file, RECORD_COMPONENT(component)->local_file_path, SWITCH_FOPEN_READ, SWITCH_FPROT_UREAD, RAYO_POOL(component)) == SWITCH_STATUS_SUCCESS) { file_size = switch_file_get_size(file); switch_file_close(file); } else { switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_INFO, "Failed to open %s.\n", RECORD_COMPONENT(component)->local_file_path); } #endif switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Recording %s done.\n", RECORD_COMPONENT(component)->local_file_path); if (RECORD_COMPONENT(component)->stop_beep && (session = switch_core_session_locate(uuid))) { switch_ivr_displace_session(session, RECORD_BEEP, 0, ""); switch_core_session_rwunlock(session); } /* send complete event to client */ recording = iks_new("recording"); iks_insert_attrib(recording, "xmlns", RAYO_RECORD_COMPLETE_NS); iks_insert_attrib(recording, "uri", uri); iks_insert_attrib_printf(recording, "duration", "%i", RECORD_COMPONENT(component)->duration_ms); iks_insert_attrib_printf(recording, "size", "%"SWITCH_SIZE_T_FMT, file_size); rayo_component_send_complete_with_metadata(component, reason, reason_namespace, recording, 1); iks_delete(recording); RAYO_UNLOCK(component); switch_safe_free(uri); }
/** * Handle fax completion event from FreeSWITCH core * @param event received from FreeSWITCH core. It will be destroyed by the core after this function returns. */ static void on_execute_complete_event(switch_event_t *event) { const char *application = switch_event_get_header(event, "Application"); if (!zstr(application) && (!strcmp(application, "rxfax") || !strcmp(application, "txfax"))) { int is_rxfax = !strcmp(application, "rxfax"); const char *uuid = switch_event_get_header(event, "Unique-ID"); const char *fax_jid = switch_event_get_header(event, "variable_rayo_fax_jid"); struct rayo_actor *component; if (!zstr(fax_jid) && (component = RAYO_LOCATE(fax_jid))) { iks *result; iks *complete; iks *fax; int have_fax_document = 1; switch_core_session_t *session; switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Got result for %s\n", fax_jid); /* clean up channel */ session = switch_core_session_locate(uuid); if (session) { switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_read_frame_interrupt", NULL); switch_core_session_rwunlock(session); } /* RX only: transfer HTTP document and delete local copy */ if (is_rxfax && RECEIVEFAX_COMPONENT(component)->http_put_after_receive && switch_file_exists(RECEIVEFAX_COMPONENT(component)->local_filename, RAYO_POOL(component)) == SWITCH_STATUS_SUCCESS) { switch_stream_handle_t stream = { 0 }; SWITCH_STANDARD_STREAM(stream); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s PUT fax to %s\n", RAYO_JID(component), RECEIVEFAX_COMPONENT(component)->filename); switch_api_execute("http_put", RECEIVEFAX_COMPONENT(component)->filename, NULL, &stream); /* check if successful */ if (!zstr(stream.data) && strncmp(stream.data, "+OK", 3)) { /* PUT failed */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s PUT fax to %s failed: %s\n", RAYO_JID(component), RECEIVEFAX_COMPONENT(component)->filename, (char *)stream.data); have_fax_document = 0; } switch_safe_free(stream.data) switch_file_remove(RECEIVEFAX_COMPONENT(component)->local_filename, RAYO_POOL(component)); } /* successful fax? */ if (have_fax_document && switch_true(switch_event_get_header(event, "variable_fax_success"))) { result = rayo_component_create_complete_event(RAYO_COMPONENT(component), FAX_FINISH); } else if (have_fax_document && FAX_COMPONENT(component)->stop) { result = rayo_component_create_complete_event(RAYO_COMPONENT(component), COMPONENT_COMPLETE_STOP); } else { result = rayo_component_create_complete_event(RAYO_COMPONENT(component), COMPONENT_COMPLETE_ERROR); } complete = iks_find(result, "complete"); /* RX only: add fax document information */ if (is_rxfax && have_fax_document) { const char *pages = switch_event_get_header(event, "variable_fax_document_transferred_pages"); if (!zstr(pages) && switch_is_number(pages) && atoi(pages) > 0) { const char *resolution = switch_event_get_header(event, "variable_fax_file_image_resolution"); const char *size = switch_event_get_header(event, "variable_fax_image_size"); fax = iks_insert(complete, "fax"); iks_insert_attrib(fax, "xmlns", RAYO_FAX_COMPLETE_NS); if (RECEIVEFAX_COMPONENT(component)->http_put_after_receive) { iks_insert_attrib(fax, "url", RECEIVEFAX_COMPONENT(component)->filename); } else { /* convert absolute path to file:// URI */ iks_insert_attrib_printf(fax, "url", "file://%s", RECEIVEFAX_COMPONENT(component)->filename); } if (!zstr(resolution)) { iks_insert_attrib(fax, "resolution", resolution); } if (!zstr(size)) { iks_insert_attrib(fax, "size", size); } iks_insert_attrib(fax, "pages", pages); } } /* add metadata from event */ insert_fax_metadata(event, "fax_success", complete); insert_fax_metadata(event, "fax_result_code", complete); insert_fax_metadata(event, "fax_result_text", complete); insert_fax_metadata(event, "fax_document_transferred_pages", complete); insert_fax_metadata(event, "fax_document_total_pages", complete); insert_fax_metadata(event, "fax_image_resolution", complete); insert_fax_metadata(event, "fax_image_size", complete); insert_fax_metadata(event, "fax_bad_rows", complete); insert_fax_metadata(event, "fax_transfer_rate", complete); insert_fax_metadata(event, "fax_ecm_used", complete); insert_fax_metadata(event, "fax_local_station_id", complete); insert_fax_metadata(event, "fax_remote_station_id", complete); /* flag faxing as done */ rayo_call_set_faxing(RAYO_CALL(RAYO_COMPONENT(component)->parent), 0); rayo_component_send_complete_event(RAYO_COMPONENT(component), result); RAYO_UNLOCK(component); } } }