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 *
28 *
29 * mod_tone_stream.c -- Tone Generation Stream
30 *
31 */
32 #include <switch.h>
33
34 SWITCH_MODULE_LOAD_FUNCTION(mod_tone_stream_load);
35 SWITCH_MODULE_DEFINITION(mod_tone_stream, mod_tone_stream_load, NULL, NULL);
36 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_tone_stream_shutdown);
37
38 struct silence_handle {
39 int32_t samples;
40 int silence;
41 int forever;
42 };
43
silence_stream_file_open(switch_file_handle_t * handle,const char * path)44 static switch_status_t silence_stream_file_open(switch_file_handle_t *handle, const char *path)
45 {
46
47 struct silence_handle *sh;
48 int ms;
49 char *p;
50
51 ms = atoi(path);
52
53 if (ms == 0) {
54 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid Input [%s] Expect <msec>[,<silence_factor>]\n", path);
55 return SWITCH_STATUS_FALSE;
56 }
57
58 sh = switch_core_alloc(handle->memory_pool, sizeof(*sh));
59
60 if (ms > 0) {
61 sh->samples = (handle->samplerate / 1000) * ms;
62 } else {
63 sh->samples = 0;
64 sh->forever = 1;
65 }
66
67 if ((p = strchr(path, ','))) {
68 p++;
69 ms = atoi(p);
70 if (ms > 0) {
71 sh->silence = ms;
72 }
73 }
74
75 handle->channels = 1;
76 handle->private_info = sh;
77
78 return SWITCH_STATUS_SUCCESS;
79 }
80
silence_stream_file_close(switch_file_handle_t * handle)81 static switch_status_t silence_stream_file_close(switch_file_handle_t *handle)
82 {
83 return SWITCH_STATUS_SUCCESS;
84 }
85
silence_stream_file_read(switch_file_handle_t * handle,void * data,size_t * len)86 static switch_status_t silence_stream_file_read(switch_file_handle_t *handle, void *data, size_t *len)
87 {
88 struct silence_handle *sh = handle->private_info;
89
90 if (!sh->forever) {
91 if (sh->samples <= 0) {
92 return SWITCH_STATUS_FALSE;
93 }
94
95 if (*len > (size_t) sh->samples) {
96 *len = sh->samples;
97 }
98
99 sh->samples -= (int32_t)*len;
100 }
101
102 switch_generate_sln_silence((int16_t *) data, (uint32_t)*len, handle->channels,
103 sh->silence ? sh->silence : (uint32_t)-1);
104
105 return SWITCH_STATUS_SUCCESS;
106 }
107
108
teletone_handler(teletone_generation_session_t * ts,teletone_tone_map_t * map)109 static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
110 {
111 switch_buffer_t *audio_buffer = ts->user_data;
112 int wrote;
113
114 if (!audio_buffer) {
115 return -1;
116 }
117
118 wrote = teletone_mux_tones(ts, map);
119 switch_buffer_write(audio_buffer, ts->buffer, wrote * 2);
120
121 return 0;
122 }
123
tone_stream_file_open(switch_file_handle_t * handle,const char * path)124 static switch_status_t tone_stream_file_open(switch_file_handle_t *handle, const char *path)
125 {
126 switch_buffer_t *audio_buffer = NULL;
127 teletone_generation_session_t ts;
128 char *tonespec;
129 int loops = 0;
130 char *tmp;
131 int fd = -1;
132 char buf[1024] = "";
133 size_t len;
134
135 memset(&ts, 0, sizeof(ts));
136
137 tonespec = switch_core_strdup(handle->memory_pool, path);
138
139 switch_buffer_create_dynamic(&audio_buffer, 1024, 1024, 0);
140 switch_assert(audio_buffer);
141
142 if ((tmp = (char *)switch_stristr(";loops=", tonespec))) {
143 *tmp = '\0';
144 tmp += 7;
145 if (*tmp) {
146 loops = atoi(tmp);
147 switch_buffer_set_loops(audio_buffer, loops);
148 }
149 }
150
151 if (handle->params) {
152 if ((tmp = switch_event_get_header(handle->params, "loops"))) {
153 loops = atoi(tmp);
154 switch_buffer_set_loops(audio_buffer, loops);
155 }
156 }
157
158 if (!handle->samplerate) {
159 handle->samplerate = 8000;
160 }
161
162 handle->channels = 1;
163
164 teletone_init_session(&ts, 0, teletone_handler, audio_buffer);
165 ts.rate = handle->samplerate;
166 ts.channels = 1;
167
168 if (!strncasecmp(tonespec, "path=", 5)) {
169 tmp = tonespec + 5;
170 if ((fd = open(tmp, O_RDONLY)) < 0) {
171 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to open [%s]\n", tmp);
172 return SWITCH_STATUS_FALSE;
173 }
174
175 while ((len = switch_fd_read_line(fd, buf, sizeof(buf)))) {
176 teletone_run(&ts, buf);
177 }
178 close(fd);
179 } else {
180 teletone_run(&ts, tonespec);
181 }
182
183 teletone_destroy_session(&ts);
184
185 handle->private_info = audio_buffer;
186
187 return SWITCH_STATUS_SUCCESS;
188 }
189
tone_stream_file_close(switch_file_handle_t * handle)190 static switch_status_t tone_stream_file_close(switch_file_handle_t *handle)
191 {
192 switch_buffer_t *audio_buffer = handle->private_info;
193
194 switch_buffer_destroy(&audio_buffer);
195 return SWITCH_STATUS_SUCCESS;
196 }
197
tone_stream_file_read(switch_file_handle_t * handle,void * data,size_t * len)198 static switch_status_t tone_stream_file_read(switch_file_handle_t *handle, void *data, size_t *len)
199 {
200 switch_buffer_t *audio_buffer = handle->private_info;
201 switch_size_t bytes;
202
203 if ((bytes = switch_buffer_read_loop(audio_buffer, data, *len * 2)) <= 0) {
204 *len = 0;
205 return SWITCH_STATUS_FALSE;
206 }
207
208 *len = bytes / 2;
209 return SWITCH_STATUS_SUCCESS;
210 }
211
212 /* Registration */
213
214 static char *supported_formats[SWITCH_MAX_CODECS] = { 0 };
215 static char *silence_supported_formats[SWITCH_MAX_CODECS] = { 0 };
216
SWITCH_MODULE_LOAD_FUNCTION(mod_tone_stream_load)217 SWITCH_MODULE_LOAD_FUNCTION(mod_tone_stream_load)
218 {
219 switch_file_interface_t *file_interface;
220 supported_formats[0] = "tone_stream";
221 silence_supported_formats[0] = "silence_stream";
222
223 *module_interface = switch_loadable_module_create_module_interface(pool, modname);
224 file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
225 file_interface->interface_name = modname;
226 file_interface->extens = supported_formats;
227 file_interface->file_open = tone_stream_file_open;
228 file_interface->file_close = tone_stream_file_close;
229 file_interface->file_read = tone_stream_file_read;
230
231 file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
232 file_interface->interface_name = modname;
233 file_interface->extens = silence_supported_formats;
234 file_interface->file_open = silence_stream_file_open;
235 file_interface->file_close = silence_stream_file_close;
236 file_interface->file_read = silence_stream_file_read;
237
238 /* indicate that the module should continue to be loaded */
239 return SWITCH_STATUS_SUCCESS;
240 }
241
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_tone_stream_shutdown)242 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_tone_stream_shutdown)
243 {
244 return SWITCH_STATUS_SUCCESS;
245 }
246
247 /* For Emacs:
248 * Local Variables:
249 * mode:c
250 * indent-tabs-mode:t
251 * tab-width:4
252 * c-basic-offset:4
253 * End:
254 * For VIM:
255 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
256 */
257