RTS API Documentation  1.10.11
fs_tts.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2019, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Seven Du <seven@signalwire.com>
27  *
28  * fs_tts.c -- Use TTS to generate a sound file
29  *
30  */
31 
32 #ifndef _XOPEN_SOURCE
33 #define _XOPEN_SOURCE 600
34 #endif
35 
36 #ifndef WIN32
37 #ifdef HAVE_SETRLIMIT
38 #include <sys/resource.h>
39 #endif
40 #endif
41 
42 #include <switch.h>
43 
44 /* Picky compiler */
45 #ifdef __ICC
46 #pragma warning (disable:167)
47 #endif
48 
49 static void fs_tts_cleanup(void)
50 {
54 }
55 
56 int main(int argc, char *argv[])
57 {
58  int r = 1;
59  switch_bool_t verbose = SWITCH_FALSE;
60  const char *err = NULL;
61  int i;
62  char *extra_modules[100] = { 0 };
63  int extra_modules_count = 0;
64  int cmd_fail = 0;
65  const char *tts_engine = "flite";
66  const char *tts_voice = "default";
67  const char *input = NULL;
68  const char *output = NULL;
69  const char *text = NULL;
70  int channels = 1;
71  int rate = 8000;
72  switch_file_handle_t fh_input = { 0 }, fh_output = { 0 };
73  char buf[2048];
74  char txtbuf[2048] = { 0 };
75  switch_size_t len = 0;
76  switch_memory_pool_t *pool = NULL;
77 
78  for (i = 1; i < argc; i++) {
79  if (argv[i][0] == '-') {
80  switch(argv[i][1]) {
81  case 'c':
82  i++;
83  if((SWITCH_GLOBAL_dirs.conf_dir = (char *) malloc(strlen(argv[i]) + 1)) == NULL) {
84  return 255;
85  }
86  strcpy(SWITCH_GLOBAL_dirs.conf_dir, argv[i]);
87  break;
88  case 'k':
89  i++;
90  if((SWITCH_GLOBAL_dirs.log_dir = (char *) malloc(strlen(argv[i]) + 1)) == NULL) {
91  return 255;
92  }
93  strcpy(SWITCH_GLOBAL_dirs.log_dir, argv[i]);
94  break;
95  case 'm':
96  i++;
97  if((SWITCH_GLOBAL_dirs.mod_dir = (char *) malloc(strlen(argv[i]) + 1)) == NULL) {
98  return 255;
99  }
100  strcpy(SWITCH_GLOBAL_dirs.mod_dir, argv[i]);
101  break;
102  case 'l':
103  i++;
104  /* Load extra modules */
105  if (strchr(argv[i], ',')) {
106  extra_modules_count = switch_split(argv[i], ',', extra_modules);
107  } else {
108  extra_modules_count = 1;
109  extra_modules[0] = argv[i];
110  }
111  break;
112  case 'i':
113  input = argv[++i];
114  break;
115  case 'e':
116  tts_engine = argv[++i];
117  break;
118  case 'V':
119  tts_voice = argv[++i];
120  break;
121  case 'r':
122  rate = atoi(argv[++i]);
123  break;
124  case 'v':
125  verbose = SWITCH_TRUE;
126  break;
127  default:
128  printf("Command line option not recognized: %s\n", argv[i]);
129  cmd_fail = 1;
130  }
131  } else {
132  break;
133  }
134  }
135 
136  if (argc - i < 1 || cmd_fail) {
137  goto usage;
138  }
139 
140  output = argv[i++];
141 
142  if (zstr(output)) {
143  goto usage;
144  }
145 
146  if (argc - i > 1) {
147  text = argv[i++];
148  }
149 
150  if (switch_core_init(SCF_MINIMAL, verbose, &err) != SWITCH_STATUS_SUCCESS) {
151  fprintf(stderr, "Cannot init core [%s]\n", err);
152  goto end;
153  }
154 
156  switch_loadable_module_load_module("", "CORE_PCM_MODULE", SWITCH_TRUE, &err);
157  switch_loadable_module_load_module("", "CORE_SPEEX_MODULE", SWITCH_TRUE, &err);
158  switch_loadable_module_load_module("", "CORE_SOFTTIMER_MODULE", SWITCH_TRUE, &err);
160 
161  for (i = 0; i < extra_modules_count; i++) {
163  fprintf(stderr, "Cannot init %s [%s]\n", extra_modules[i], err);
164  goto end;
165  }
166  }
167 
169  fprintf(stderr, "Cannot init mod_sndfile [%s]\n", err);
170  goto end;
171  }
172 
174  fprintf(stderr, "Cannot init mod_ssml [%s]\n", err);
175  goto end;
176  }
177 
178  if (!strcmp(tts_engine, "polly")) {
180  fprintf(stderr, "Cannot init mod_polly [%s]\n", err);
181  goto end;
182  }
183  }
184 
185  if (!strcmp(tts_engine, "gcloud")) {
187  fprintf(stderr, "Cannot init mod_polly [%s]\n", err);
188  goto end;
189  }
190  }
191 
192  if (!strcmp(tts_voice, "default") && !strcmp(tts_engine, "flite")) {
193  tts_voice = "kal";
194  }
195 
197 
198  if (zstr(text) || *text == '-') { // read from stdin
199  while(read(STDIN_FILENO, txtbuf + len, 1) == 1) {
200  if(++len == sizeof(txtbuf) - 1) break;
201  }
202  } else if (input) {
203  int fd = open(input, O_RDONLY);
204 
205  if (fd== -1) {
206  fprintf(stderr, "Error opening file %s\n", input);
207  goto end;
208  }
209 
210  len = read(fd, txtbuf, sizeof(txtbuf) - 1);
211  close(fd);
212  }
213 
214  if (len > 0) {
215  text = txtbuf;
216  }
217 
218  input = switch_core_sprintf(pool, "tts://%s|%s|%s", tts_engine, tts_voice, text);
219 
220  // input = "tts://polly|default|Hello";
221 
222  if (verbose) {
223  fprintf(stderr, "Speaking %s\n", input);
224  }
225 
226  if (switch_core_file_open(&fh_input, input, channels, rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
227  fprintf(stderr, "Couldn't open %s\n", input);
228  goto end;
229  }
230 
231  if (verbose) {
232  fprintf(stderr, "Opening file %s\n", output);
233  }
234 
235  if (switch_core_file_open(&fh_output, output, channels, rate, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
236  fprintf(stderr, "Couldn't open %s\n", output);
237  goto end;
238  }
239 
240  len = sizeof(buf) / 2;
241 
242  while (switch_core_file_read(&fh_input, buf, &len) == SWITCH_STATUS_SUCCESS) {
243  if (switch_core_file_write(&fh_output, buf, &len) != SWITCH_STATUS_SUCCESS) {
244  fprintf(stderr, "Write error\n");
245  goto end;
246  }
247 
248  len = sizeof(buf) / 2;
249  }
250 
251  r = 0;
252 
253 end:
254  if (switch_test_flag(&fh_input, SWITCH_FILE_OPEN)) {
255  switch_core_file_close(&fh_input);
256  }
257 
258  if (switch_test_flag(&fh_output, SWITCH_FILE_OPEN)) {
259  switch_core_file_close(&fh_output);
260  }
261 
262  if (pool) {
264  }
265 
266  fs_tts_cleanup();
267 
268  // switch_core_destroy();
269 
270  return r;
271 usage:
272  printf("Usage: %s [options] output [text]\n\n", argv[0]);
273  printf("The output must end in the format, e.g., myfile.wav myfile.mp3\n");
274  printf("\t\t -c path\t\t Path to the FS configurations.\n");
275  printf("\t\t -k path\t\t Path to the FS log directory\n");
276  printf("\t\t -l module[,module]\t Load additional modules (comma-separated)\n");
277  printf("\t\t -m path\t\t Path to the modules.\n");
278  printf("\t\t -r rate\t\t sampling rate\n");
279  printf("\t\t -v\t\t\t verbose\n");
280  printf("\t\t -e\t\t\t TTS engine\n");
281  printf("\t\t -V\t\t\t TTS voice\n");
282  fs_tts_cleanup();
283  return 1;
284 }
285 
286 /* For Emacs:
287  * Local Variables:
288  * mode:c
289  * indent-tabs-mode:t
290  * tab-width:4
291  * c-basic-offset:4
292  * End:
293  * For VIM:
294  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
295  */
#define switch_core_new_memory_pool(p)
Create a new sub memory pool from the core&#39;s master pool.
Definition: switch_core.h:633
#define switch_core_file_open(_fh, _file_path, _channels, _rate, _flags, _pool)
Open a media file using file format modules.
Definition: switch_core.h:1963
switch_status_t switch_core_init(_In_ switch_core_flag_t flags, _In_ switch_bool_t console, _Out_ const char **err)
Initilize the core.
switch_bool_t
Definition: switch_types.h:437
#define switch_split(_data, _delim, _array)
Definition: switch_utils.h:375
#define switch_core_destroy_memory_pool(p)
Returns a subpool back to the main pool.
Definition: switch_core.h:642
switch_memory_pool_t * pool
switch_status_t switch_core_file_close(_In_ switch_file_handle_t *fh)
Close an open file handle.
switch_status_t switch_core_file_read(_In_ switch_file_handle_t *fh, void *data, switch_size_t *len)
Read media from a file handle.
#define zstr(x)
Definition: switch_utils.h:314
static const char usage[]
Definition: switch.c:419
switch_byte_t switch_byte_t * buf
#define switch_safe_free(it)
Free a pointer and set it to NULL unless it already is NULL.
Definition: switch_utils.h:885
static void fs_tts_cleanup(void)
Definition: fs_tts.c:49
uintptr_t switch_size_t
switch_directories SWITCH_GLOBAL_dirs
Definition: switch_core.c:82
switch_status_t switch_loadable_module_load_module(const char *dir, const char *fname, switch_bool_t runtime, const char **err)
Load a module.
switch_status_t switch_core_file_write(_In_ switch_file_handle_t *fh, void *data, switch_size_t *len)
Write media to a file handle.
Main Library Header.
int main(int argc, char *argv[])
Definition: fs_tts.c:56
switch_status_t switch_loadable_module_init(switch_bool_t autoload)
Initilize the module backend and load all the modules.
#define switch_test_flag(obj, flag)
Test for the existance of a flag on an arbitary object.
Definition: switch_utils.h:693
struct fspr_pool_t switch_memory_pool_t
char * switch_core_sprintf(_In_ switch_memory_pool_t *pool, _In_z_ _Printf_format_string_ const char *fmt,...)
printf-style style printing routine. The data is output to a string allocated from the pool ...