FreeSWITCH API Documentation  1.7.0
switch_core_speech.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, 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  * Anthony Minessale II <anthm@freeswitch.org>
27  * Michael Jerris <mike@jerris.com>
28  * Paul D. Tinsley <pdt at jackhammer.org>
29  * Christopher M. Rienzo <chris@rienzo.com>
30  *
31  *
32  * switch_core_speech.c -- Main Core Library (speech functions)
33  *
34  */
35 
36 #include <switch.h>
38 
40  const char *module_name,
41  const char *voice_name,
42  unsigned int rate, unsigned int interval, unsigned int channels,
44 {
45  switch_status_t status;
46  char buf[256] = "";
47  char *param = NULL;
48 
49  if (!sh || !flags || zstr(module_name)) {
50  return SWITCH_STATUS_FALSE;
51  }
52 
53  if (strchr(module_name, ':')) {
54  switch_set_string(buf, module_name);
55  if ((param = strchr(buf, ':'))) {
56  *param++ = '\0';
57  module_name = buf;
58  }
59  }
60 
61  if ((sh->speech_interface = switch_loadable_module_get_speech_interface(module_name)) == 0) {
62  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid speech module [%s]!\n", module_name);
63  return SWITCH_STATUS_GENERR;
64  }
65 
66  sh->flags = *flags;
67  if (pool) {
68  sh->memory_pool = pool;
69  } else {
70  if ((status = switch_core_new_memory_pool(&sh->memory_pool)) != SWITCH_STATUS_SUCCESS) {
71  UNPROTECT_INTERFACE(sh->speech_interface);
72  return status;
73  }
75  }
76 
77  sh->engine = switch_core_strdup(sh->memory_pool, module_name);
78  if (param) {
79  sh->param = switch_core_strdup(sh->memory_pool, param);
80  }
81 
82  sh->rate = rate;
83  sh->name = switch_core_strdup(sh->memory_pool, module_name);
84  sh->samples = switch_samples_per_packet(rate, interval);
85  sh->samplerate = rate;
86  sh->native_rate = rate;
87  sh->channels = channels;
88  sh->real_channels = 1;
89 
90  if ((status = sh->speech_interface->speech_open(sh, voice_name, rate, channels, flags)) == SWITCH_STATUS_SUCCESS) {
92  } else {
93  UNPROTECT_INTERFACE(sh->speech_interface);
94  }
95 
96  return status;
97 }
98 
100 {
102  char *param_string = NULL;
103  char *data = NULL;
104  char *ltext = NULL;
105 
106  switch_assert(sh != NULL);
107 
108  if (zstr(text)) {
109  status = SWITCH_STATUS_FALSE;
110  goto done;
111  }
112 
113  /* Set TTS parameters from params in the text string
114  * Params are defined as follows {name1=val1,name2=val2,name3=val3}text to speak
115  */
116  ltext = strdup(text);
117  data = ltext;
118 
119  /* strip leading spaces */
120  while (data && *data == ' ') {
121  data++;
122  }
123  if (zstr(data)) {
124  status = SWITCH_STATUS_FALSE;
125  goto done;
126  }
127 
128  /* extract params */
129  if (*data == '{') {
130  param_string = data + 1;
131  data = switch_find_end_paren(data, '{', '}');
132  if (zstr(data)) {
133  status = SWITCH_STATUS_FALSE;
134  goto done;
135  } else {
136  *data = '\0';
137  data++;
138  }
139  }
140 
141  /* set TTS params */
142  if (!zstr(param_string)) {
143  char *param[256] = { 0 };
144  int i;
145  int argc = switch_separate_string(param_string, ',', param, (sizeof(param) / sizeof(param[0])));
146  for (i = 0; i < argc && param[i]; ++i) {
147  char *param_pair[2] = { 0 };
148  if (switch_separate_string(param[i], '=', param_pair, (sizeof(param_pair) / sizeof(param_pair[0]))) == 2) {
149  switch_core_speech_text_param_tts(sh, param_pair[0], param_pair[1]);
150  }
151  }
152  }
153 
154  status = sh->speech_interface->speech_feed_tts(sh, data, flags);
155 
156  done:
157 
158  switch_safe_free(ltext);
159  return status;
160 }
161 
163 {
164  switch_assert(sh != NULL);
165 
166  if (sh->speech_interface->speech_flush_tts) {
167  sh->speech_interface->speech_flush_tts(sh);
168  }
169 }
170 
172 {
173  switch_assert(sh != NULL);
174 
175  if (sh->speech_interface->speech_text_param_tts) {
176  sh->speech_interface->speech_text_param_tts(sh, param, val);
177  }
178 }
179 
181 {
182  switch_assert(sh != NULL);
183 
184  if (sh->speech_interface->speech_numeric_param_tts) {
185  sh->speech_interface->speech_numeric_param_tts(sh, param, val);
186  }
187 }
188 
190 {
191  switch_assert(sh != NULL);
192 
193  if (sh->speech_interface->speech_float_param_tts) {
194  sh->speech_interface->speech_float_param_tts(sh, param, val);
195  }
196 }
197 
199 {
200  switch_status_t status;
201  switch_size_t want, orig_len = *datalen;
202 
203  switch_assert(sh != NULL);
204 
205  want = *datalen;
206 
207  top:
208 
209  if (sh->buffer && (switch_buffer_inuse(sh->buffer) >= orig_len || switch_test_flag(sh, SWITCH_SPEECH_FLAG_DONE))) {
210  if ((*datalen = switch_buffer_read(sh->buffer, data, orig_len))) {
211  status = SWITCH_STATUS_SUCCESS;
212  goto done;
213  }
214  }
215 
218  *datalen = 0;
219  return SWITCH_STATUS_BREAK;
220  }
221 
222  more:
223 
224  *datalen = orig_len / sh->channels;
225 
226  if ((status = sh->speech_interface->speech_read_tts(sh, data, datalen, flags)) != SWITCH_STATUS_SUCCESS) {
228  goto top;
229  }
230 
231  if (sh->native_rate && sh->samplerate && sh->native_rate != sh->samplerate) {
232  if (!sh->resampler) {
233  if (switch_resample_create(&sh->resampler,
234  sh->native_rate, sh->samplerate, (uint32_t) orig_len / sh->channels, SWITCH_RESAMPLE_QUALITY, 1) != SWITCH_STATUS_SUCCESS) {
235  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n");
236  return SWITCH_STATUS_GENERR;
237  }
238  }
239 
240  switch_resample_process(sh->resampler, data, (uint32_t)(*datalen / 2));
241  if (sh->resampler->to_len < want / 2 || sh->resampler->to_len > orig_len / 2) {
242  if (!sh->buffer) {
243  int factor = sh->resampler->to_len * sh->samplerate / 1000;
244  switch_buffer_create_dynamic(&sh->buffer, factor, factor, 0);
245  switch_assert(sh->buffer);
246  }
247  if (!sh->dbuf || sh->dbuflen < sh->resampler->to_len * 2) {
248  sh->dbuflen = sh->resampler->to_len * 2;
249  sh->dbuf = switch_core_alloc(sh->memory_pool, sh->dbuflen);
250  }
251  switch_assert(sh->resampler->to_len <= sh->dbuflen);
252 
253  memcpy((int16_t *) sh->dbuf, sh->resampler->to, sh->resampler->to_len * 2);
254  switch_buffer_write(sh->buffer, sh->dbuf, sh->resampler->to_len * 2);
255 
256  if (switch_buffer_inuse(sh->buffer) < want) {
257  *datalen = want;
258  goto more;
259  }
260  *datalen = switch_buffer_read(sh->buffer, data, orig_len);
261  status = SWITCH_STATUS_SUCCESS;
262  } else {
263  memcpy(data, sh->resampler->to, sh->resampler->to_len * 2);
264  *datalen = sh->resampler->to_len * 2;
265  status = SWITCH_STATUS_SUCCESS;
266  }
267  }
268 
269 
270  done:
271 
272  if (sh->channels != sh->real_channels) {
273  uint32_t rlen = *datalen / 2;
274  switch_mux_channels((int16_t *) data, rlen, 1, sh->channels);
275  *datalen = rlen * 2 * sh->channels;
276  }
277 
278  return status;
279 
280 }
281 
282 
284 {
285  switch_status_t status = sh->speech_interface->speech_close(sh, flags);
286 
288  return SWITCH_STATUS_FALSE;
289  }
290 
291  if (sh->buffer) {
292  switch_buffer_destroy(&sh->buffer);
293  }
294 
295  switch_resample_destroy(&sh->resampler);
296 
297  UNPROTECT_INTERFACE(sh->speech_interface);
298 
300  switch_core_destroy_memory_pool(&sh->memory_pool);
301  }
302 
304 
305  return status;
306 }
307 
308 /* For Emacs:
309  * Local Variables:
310  * mode:c
311  * indent-tabs-mode:t
312  * tab-width:4
313  * c-basic-offset:4
314  * End:
315  * For VIM:
316  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
317  */
switch_status_t switch_core_speech_read_tts(switch_speech_handle_t *sh, void *data, switch_size_t *datalen, switch_speech_flag_t *flags)
Read rendered audio from the TTS module.
#define switch_core_new_memory_pool(p)
Create a new sub memory pool from the core's master pool.
Definition: switch_core.h:631
#define switch_set_flag(obj, flag)
Set a flag on an arbitrary object.
Definition: switch_utils.h:631
#define SWITCH_CHANNEL_LOG
switch_size_t switch_buffer_read(_In_ switch_buffer_t *buffer, _In_ void *data, _In_ switch_size_t datalen)
Read data from a switch_buffer_t up to the ammount of datalen if it is available. Remove read data fr...
char * switch_find_end_paren(const char *s, char open, char close)
Definition: switch_utils.c:661
switch_status_t switch_buffer_create_dynamic(_Out_ switch_buffer_t **buffer, _In_ switch_size_t blocksize, _In_ switch_size_t start_len, _In_ switch_size_t max_len)
Allocate a new dynamic switch_buffer.
uint32_t switch_speech_flag_t
#define switch_core_strdup(_pool, _todup)
Copy a string using memory allocation from a given pool.
Definition: switch_core.h:729
#define switch_core_destroy_memory_pool(p)
Returns a subpool back to the main pool.
Definition: switch_core.h:640
switch_memory_pool_t * pool
void switch_core_speech_float_param_tts(switch_speech_handle_t *sh, char *param, double val)
Set a float parameter on a TTS handle.
switch_status_t switch_core_speech_feed_tts(switch_speech_handle_t *sh, char *text, switch_speech_flag_t *flags)
Feed text to the TTS module.
#define SWITCH_RESAMPLE_QUALITY
void switch_core_speech_numeric_param_tts(switch_speech_handle_t *sh, char *param, int val)
Set a numeric parameter on a TTS handle.
void switch_core_speech_text_param_tts(switch_speech_handle_t *sh, char *param, const char *val)
Set a text parameter on a TTS handle.
void switch_resample_destroy(switch_audio_resampler_t **resampler)
Destroy an existing resampler handle.
switch_size_t switch_buffer_write(_In_ switch_buffer_t *buffer, _In_bytecount_(datalen) const void *data, _In_ switch_size_t datalen)
Write data into a switch_buffer_t up to the length of datalen.
#define zstr(x)
Definition: switch_utils.h:281
#define UNPROTECT_INTERFACE(_it)
#define switch_clear_flag(obj, flag)
Clear a flag on an arbitrary object while locked.
Definition: switch_utils.h:655
switch_status_t switch_core_speech_close(switch_speech_handle_t *sh, switch_speech_flag_t *flags)
Close an open speech handle.
switch_byte_t switch_byte_t * buf
unsigned int switch_separate_string(_In_ char *buf, char delim, _Post_count_(return) char **array, unsigned int arraylen)
Separate a string into an array based on a character delimiter.
#define switch_core_alloc(_pool, _mem)
Allocate memory directly from a memory pool.
Definition: switch_core.h:682
#define switch_safe_free(it)
Free a pointer and set it to NULL unless it already is NULL.
Definition: switch_utils.h:789
uintptr_t switch_size_t
#define switch_samples_per_packet(rate, interval)
Definition: switch_utils.h:258
void switch_core_speech_flush_tts(switch_speech_handle_t *sh)
Flush TTS audio on a given handle.
void switch_mux_channels(int16_t *data, switch_size_t samples, uint32_t orig_channels, uint32_t channels)
switch_status_t
Common return values.
Main Library Header.
switch_status_t switch_core_speech_open(switch_speech_handle_t *sh, const char *module_name, const char *voice_name, unsigned int rate, unsigned int interval, unsigned int channels, switch_speech_flag_t *flags, switch_memory_pool_t *pool)
#define SWITCH_DECLARE(type)
#define switch_set_string(_dst, _src)
Definition: switch_utils.h:665
struct apr_pool_t switch_memory_pool_t
#define switch_test_flag(obj, flag)
Test for the existance of a flag on an arbitary object.
Definition: switch_utils.h:624
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
#define switch_assert(expr)
switch_size_t switch_buffer_inuse(_In_ switch_buffer_t *buffer)
Get the in use amount of a switch_buffer_t.
void switch_buffer_destroy(switch_buffer_t **buffer)
Destroy the buffer.
#define switch_resample_create(_n, _fr, _tr, _ts, _q, _c)
uint32_t switch_resample_process(switch_audio_resampler_t *resampler, int16_t *src, uint32_t srclen)
Resample one float buffer into another using specifications of a given handle.
switch_speech_interface_t * switch_loadable_module_get_speech_interface(const char *name)
Retrieve the speech interface by it's registered name.