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