/* * Asterisk -- A telephony toolkit for Linux. * * Trivial application to use cepstral theta tts * * Copyright (C) 2004, Andy Powell * Update to Swift (C) 2004, Josh Roberson * * Andy Powell * Josh Roberson * * This program is free software, distributed under the terms of * the GNU General Public License */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static char *tdesc = "Trivial Cepstral TTS Application"; static char *app = "Cepstral"; static char *synopsis = "TTS conversion and playback"; static char *descrip = "Cepstral(text[|options]): Converts text to speech using Cepstral Theta engine.\n" "Currently only allows the use of a single voice which is the default\n" "voice for your install. Options are as follows:\n\n" "b -- Use similar to Background()\n" "noanswer -- same as in Playback() or Background()\n\n" "Typical Usage example (like Playback()):\n\nexten=> 1,1,Cepstral(\"hello world\")\n"; STANDARD_LOCAL_USER; LOCAL_USER_DECL; static int mytheta_create_file(char *file, char *voicename, char* sfx, char *lex, char *text) { /*************************************************** * All code until next break are updates for Swift * * and (C) 2004, Josh Roberson * ***************************************************/ swift_engine *engine; swift_port *port; const swift_voice *voice, *chosen_voice; swift_params *params; swift_background_t tts_stream; params = swift_params_new(NULL); swift_params_set_string(params, "audio/output-file", file); swift_params_set_string(params, "audio/output-format", "riff"); swift_params_set_string(params, "audio/sampling-rate", "8000"); swift_params_dump(params); /* Init the Engine. */ if(option_verbose > 3) ast_verbose(VERBOSE_PREFIX_4 "Initializing Swift engine.\n"); if ( SWIFT_FAILED(engine = swift_engine_open(NULL)) ) { ast_log(LOG_WARNING, "Failed to open Swift engine.\n"); } /* Open a port... */ if (option_verbose > 3) ast_verbose(VERBOSE_PREFIX_4 "Opening port to Swift engine.\n"); if ( SWIFT_FAILED(port = swift_port_open(engine, params)) ) { ast_log(LOG_WARNING, "Failed to open Swift Port.\n"); } /* Select the first available voice. */ if(option_verbose > 3) ast_verbose(VERBOSE_PREFIX_4 "Checking for an available voices.\n"); if ( NULL == (voice = swift_port_find_first_voice(port, NULL, NULL)) ) { if(option_verbose > 3) ast_log(LOG_WARNING, "No voices were found. Are you sure Cepstral is properly installed?\n"); return 1; } chosen_voice = voice; if(voicename && strcasecmp(voicename,swift_voice_get_attribute(voice, "name"))) { for (; voice; voice = swift_port_find_next_voice(port)) { if(!strcasecmp(voicename,swift_voice_get_attribute(voice, "name"))) { chosen_voice = voice; break; } } } /* Load the found voice as the voice to use */ if (option_verbose > 3) ast_verbose(VERBOSE_PREFIX_4 "Using voice %s\n", swift_voice_get_attribute(chosen_voice, "name")); if ( SWIFT_FAILED(swift_port_set_voice(port, chosen_voice)) ) { ast_log(LOG_NOTICE,"Failed to load a voice.\n"); return 1; } /* Let's do this */ if (option_verbose > 3) ast_verbose(VERBOSE_PREFIX_4 "Speaking \"%s\" into file %s\n", text, file); if ( SWIFT_FAILED(swift_port_speak_text(port, text, 0, "us-ascii", &tts_stream, NULL))) { ast_log(LOG_WARNING,"Failed to speak text" ); return 1; } if(sfx) swift_port_load_sfx(port, sfx); if(lex) swift_port_load_lexicon(port, lex); if (NULL != port) swift_port_close(port); if (NULL != engine) swift_engine_close(engine); if (NULL != params) swift_params_delete(params); return 0; } /************************************************** * Code from here on down is old code, with the * * exception of selective Playback()/Background() * * modes, and thus (C) 2004, Andy Powell * **************************************************/ static int cepstral_exec(struct ast_channel *chan, void *data) { int res = 0; time_t thistime; struct tm brokentime; struct localuser *u; char *text = NULL; char options[20]; int noanswer = 0; int background = 0; char sfname[256]; char nsfname[256]; char *stack=NULL,*var=NULL,*val=NULL,*voice=NULL,*sfx=NULL,*lex=NULL; LOCAL_USER_ADD(u); if (!data || !strlen((char *)data)) { ast_log(LOG_WARNING, "Cepstral requires an argument (text)\n"); LOCAL_USER_REMOVE(u); return -1; } stack = (char *) data; val=stack; while(val) { val = strsep(&stack, "|"); if(!val) break; var = strsep(&val,"="); // back compat if(var && ! val) { if (!strcasecmp(var, "noanswer")) { noanswer = 1; } else if(!strcasecmp(var, "voice")) { var = strsep(&stack, "|"); voice = ast_strdupa(var); } else if(var) { text = ast_strdupa(var); } continue; } // else named args i.e. voice=frank if(!strcmp(var,"text") && val) { text = ast_strdupa(val); } else if(!strcmp(var,"noanswer") && val) noanswer = 1; else if(!strcmp(var,"voice") && val) voice=ast_strdupa(val); else if(!strcmp(var,"sfx") && val) sfx=ast_strdupa(val); else if(!strcmp(var,"lex") && val) lex=ast_strdupa(val); } /* noanswer = 1 we don't do this */ if (chan->_state != AST_STATE_UP && noanswer == 0) { res = ast_answer(chan); } thistime=time(NULL); localtime_r(&thistime, &brokentime); snprintf(options, strlen(options) - 1, "%04d%02d%02d-%02d%02d%02d", brokentime.tm_year+1900, brokentime.tm_mon+1, brokentime.tm_mday, brokentime.tm_hour, brokentime.tm_min, brokentime.tm_sec ); ast_stopstream(chan); //pbx_substitute_variables_helper(chan, "${UNIQUEID}", options, sizeof(options) - 1); snprintf(sfname, sizeof(sfname)-1, "/tmp/cepstral_%s.wav", options); snprintf(nsfname, sizeof(nsfname)-1, "/tmp/cepstral_%s", options); res = mytheta_create_file(sfname, voice, sfx, lex, text); if(res == 0) { res = ast_safe_sleep(chan, 1000); if (!res) { res = ast_streamfile(chan, nsfname, chan->language); } if (!res) { if (background) res = ast_waitstream(chan, AST_DIGIT_ANY); else res = ast_waitstream(chan, ""); } else { ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data); res = 0; } ast_stopstream(chan); } LOCAL_USER_REMOVE(u); ast_filedelete(nsfname,"wav"); return res; } int unload_module(void) { STANDARD_HANGUP_LOCALUSERS; return ast_unregister_application(app); } int load_module(void) { return ast_register_application(app, cepstral_exec, synopsis, descrip); } char *description(void) { return tdesc; } int usecount(void) { int res; STANDARD_USECOUNT(res); return res; } char *key() { return ASTERISK_GPL_KEY; }