/* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * Copyright (C) 2005/2006, Anthony Minessale II * * 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 FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * * The Initial Developer of the Original Code is * Anthony Minessale II * Portions created by the Initial Developer are Copyright (C) * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Anthony Minessale II * * * mod_cepstral.c -- Cepstral Interface * */ #ifdef __ICC #pragma warning (disable:188) #endif #include #include static const char modname[] = "mod_cepstral"; static swift_engine *engine; typedef struct { swift_background_t tts_stream; swift_port *port; swift_params *params; swift_voice *voice; switch_mutex_t *audio_lock; switch_buffer_t *audio_buffer; int done; int done_gen; } cepstral_t; /* This callback caches the audio in the buffer */ static swift_result_t write_audio(swift_event *event, swift_event_t type, void *udata) { cepstral_t *cepstral; swift_event_t rv = SWIFT_SUCCESS; void *buf = NULL; int len = 0; cepstral = udata; assert(cepstral != NULL); /* Only proceed when we have success */ if (!SWIFT_FAILED((rv = swift_event_get_audio(event, &buf, &len)))) { switch_mutex_lock(cepstral->audio_lock); if (switch_buffer_write(cepstral->audio_buffer, buf, len) <= 0) { rv = SWIFT_UNKNOWN_ERROR; } switch_mutex_unlock(cepstral->audio_lock); } else { cepstral->done = 1; } return rv; } static switch_status_t cepstral_speech_open(switch_speech_handle_t *sh, char *voice_name, int rate, switch_speech_flag_t *flags) { if (*flags & SWITCH_SPEECH_FLAG_ASR) { return SWITCH_STATUS_FALSE; } if (*flags & SWITCH_SPEECH_FLAG_TTS) { cepstral_t *cepstral = switch_core_alloc(sh->memory_pool, sizeof(*cepstral)); char srate[25]; if (!cepstral) { return SWITCH_STATUS_MEMERR; } if (switch_buffer_create(sh->memory_pool, &cepstral->audio_buffer, SWITCH_RECCOMMENDED_BUFFER_SIZE) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Write Buffer Failed!\n"); return SWITCH_STATUS_MEMERR; } switch_mutex_init(&cepstral->audio_lock, SWITCH_MUTEX_NESTED, sh->memory_pool); cepstral->params = swift_params_new(NULL); swift_params_set_string(cepstral->params, "audio/encoding", "pcm16"); snprintf(srate, sizeof(srate), "%d", rate); swift_params_set_string(cepstral->params, "audio/sampling-rate", srate); /* Open a Swift Port through which to make TTS calls */ if (SWIFT_FAILED(cepstral->port = swift_port_open(engine, cepstral->params))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open Swift Port."); goto all_done; } if (voice_name && SWIFT_FAILED(swift_port_set_voice_by_name(cepstral->port, voice_name))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid voice %s!\n", voice_name); voice_name = NULL; } if (!voice_name) { /* Find the first voice on the system */ if ((cepstral->voice = swift_port_find_first_voice(cepstral->port, NULL, NULL)) == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to find any voices!\n"); goto all_done; } /* Set the voice found by find_first_voice() as the port's current voice */ if ( SWIFT_FAILED(swift_port_set_voice(cepstral->port, cepstral->voice)) ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set voice.\n"); goto all_done; } } swift_port_set_callback(cepstral->port, &write_audio, SWIFT_EVENT_AUDIO, cepstral); sh->private_info = cepstral; return SWITCH_STATUS_SUCCESS; } all_done: return SWITCH_STATUS_FALSE; } static switch_status_t cepstral_speech_close(switch_speech_handle_t *sh, switch_speech_flag_t *flags) { cepstral_t *cepstral; assert(sh != NULL); cepstral = sh->private_info; assert(cepstral != NULL); /* Close the Swift Port and Engine */ if (NULL != cepstral->port) swift_port_close(cepstral->port); //if (NULL != cepstral->engine) swift_engine_close(cepstral->engine); cepstral->port = NULL; //cepstral->engine = NULL; return SWITCH_STATUS_SUCCESS; } static switch_status_t cepstral_speech_feed_tts(switch_speech_handle_t *sh, char *text, switch_speech_flag_t *flags) { cepstral_t *cepstral; assert(sh != NULL); cepstral = sh->private_info; assert(cepstral != NULL); swift_port_speak_text(cepstral->port, text, 0, NULL, &cepstral->tts_stream, NULL); //swift_port_speak_text(cepstral->port, text, 0, NULL, NULL, NULL); return SWITCH_STATUS_FALSE; } static switch_status_t cepstral_speech_read_tts(switch_speech_handle_t *sh, void *data, size_t *datalen, uint32_t *rate, switch_speech_flag_t *flags) { cepstral_t *cepstral; size_t desired = *datalen; switch_status_t status = SWITCH_STATUS_FALSE; size_t used, padding = 0; assert(sh != NULL); cepstral = sh->private_info; assert(cepstral != NULL); while(!cepstral->done) { if (!cepstral->done_gen) { int check = (SWIFT_STATUS_RUNNING == swift_port_status(cepstral->port, cepstral->tts_stream)); if (!check) { cepstral->done_gen = 1; } } used = switch_buffer_inuse(cepstral->audio_buffer); if (!used && cepstral->done_gen) { break; } /* wait for the right amount of data (unless there is no blocking flag) */ if (used < desired) { if (cepstral->done_gen) { padding = desired - used; desired = used; } if (!(*flags & SWITCH_SPEECH_FLAG_BLOCKING)) { *datalen = 0; status = SWITCH_STATUS_SUCCESS; break; } switch_yield(1000); continue; } /* There is enough, read it and return */ switch_mutex_lock(cepstral->audio_lock); *datalen = switch_buffer_read(cepstral->audio_buffer, data, desired); if (padding) { size_t x = 0; unsigned char *p = data; for(x = 0; x < padding; x++) { *(p + x) = 0; (*datalen)++; } } switch_mutex_unlock(cepstral->audio_lock); status = SWITCH_STATUS_SUCCESS; break; } return status; } static const switch_speech_interface_t cepstral_speech_interface = { /*.interface_name*/ "cepstral", /*.speech_open*/ cepstral_speech_open, /*.speech_close*/ cepstral_speech_close, /*.speech_feed_asr*/ NULL, /*.speech_interpret_asr*/ NULL, /*.speech_feed_tts*/ cepstral_speech_feed_tts, /*.speech_read_tts*/ cepstral_speech_read_tts }; static const switch_loadable_module_interface_t cepstral_module_interface = { /*.module_name */ modname, /*.endpoint_interface */ NULL, /*.timer_interface */ NULL, /*.dialplan_interface */ NULL, /*.codec_interface */ NULL, /*.application_interface */ NULL, /*.api_interface */ NULL, /*.file_interface */ NULL, /*.speech_interface */ &cepstral_speech_interface, /*.directory_interface */ NULL }; switch_status_t switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename) { /* Open the Swift TTS Engine */ if ( SWIFT_FAILED(engine = swift_engine_open(NULL)) ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open Swift Engine."); return SWITCH_STATUS_GENERR; } /* connect my internal structure to the blank pointer passed to me */ *module_interface = &cepstral_module_interface; /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; }