File: | src/mod/applications/mod_spandsp/mod_spandsp_modem.c |
Location: | line 284, column 17 |
Description: | Null pointer passed as an argument to a 'nonnull' parameter |
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 mod_fax. | |||
18 | * | |||
19 | * The Initial Developer of the Original Code is | |||
20 | * Massimo Cetra <devel@navynet.it> | |||
21 | * | |||
22 | * Portions created by the Initial Developer are Copyright (C) | |||
23 | * the Initial Developer. All Rights Reserved. | |||
24 | * | |||
25 | * Contributor(s): | |||
26 | * | |||
27 | * Brian West <brian@freeswitch.org> | |||
28 | * Anthony Minessale II <anthm@freeswitch.org> | |||
29 | * Steve Underwood <steveu@coppice.org> | |||
30 | * mod_spandsp_modem.c -- t31 Soft Modem | |||
31 | * | |||
32 | */ | |||
33 | ||||
34 | #include "mod_spandsp.h" | |||
35 | #include "udptl.h" | |||
36 | #include "mod_spandsp_modem.h" | |||
37 | ||||
38 | #if defined(MODEM_SUPPORT1) | |||
39 | #ifndef WIN32 | |||
40 | #include <poll.h> | |||
41 | #endif | |||
42 | ||||
43 | #define LOCAL_FAX_MAX_DATAGRAM400 400 | |||
44 | #define MAX_FEC_ENTRIES4 4 | |||
45 | #define MAX_FEC_SPAN4 4 | |||
46 | #define DEFAULT_FEC_ENTRIES3 3 | |||
47 | #define DEFAULT_FEC_SPAN3 3 | |||
48 | ||||
49 | static struct { | |||
50 | int REF_COUNT; | |||
51 | int THREADCOUNT; | |||
52 | switch_memory_pool_t *pool; | |||
53 | switch_mutex_t *mutex; | |||
54 | modem_t MODEM_POOL[MAX_MODEMS1024]; | |||
55 | int SOFT_MAX_MODEMS; | |||
56 | } globals; | |||
57 | ||||
58 | struct modem_state { | |||
59 | int state; | |||
60 | char *name; | |||
61 | }; | |||
62 | ||||
63 | static struct modem_state MODEM_STATE[] = { | |||
64 | {MODEM_STATE_INIT, "INIT"}, | |||
65 | {MODEM_STATE_ONHOOK, "ONHOOK"}, | |||
66 | {MODEM_STATE_OFFHOOK, "OFFHOOK"}, | |||
67 | {MODEM_STATE_ACQUIRED, "ACQUIRED"}, | |||
68 | {MODEM_STATE_RINGING, "RINGING"}, | |||
69 | {MODEM_STATE_ANSWERED, "ANSWERED"}, | |||
70 | {MODEM_STATE_DIALING, "DIALING"}, | |||
71 | {MODEM_STATE_CONNECTED, "CONNECTED"}, | |||
72 | {MODEM_STATE_HANGUP, "HANGUP"}, | |||
73 | {MODEM_STATE_LAST, "UNKNOWN"} | |||
74 | }; | |||
75 | ||||
76 | ||||
77 | static modem_t *acquire_modem(int index); | |||
78 | ||||
79 | static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) | |||
80 | { | |||
81 | return 0; | |||
82 | } | |||
83 | ||||
84 | static int t31_at_tx_handler(void *user_data, const uint8_t *buf, size_t len) | |||
85 | { | |||
86 | modem_t *modem = user_data; | |||
87 | ||||
88 | #ifndef WIN32 | |||
89 | switch_size_t wrote; | |||
90 | wrote = write(modem->master, buf, len); | |||
91 | #else | |||
92 | DWORD wrote; | |||
93 | OVERLAPPED o; | |||
94 | o.hEvent = CreateEvent(NULL((void*)0), TRUE(!0), FALSE0, NULL((void*)0)); | |||
95 | ||||
96 | /* Initialize the rest of the OVERLAPPED structure to zero. */ | |||
97 | o.Internal = 0; | |||
98 | o.InternalHigh = 0; | |||
99 | o.Offset = 0; | |||
100 | o.OffsetHigh = 0; | |||
101 | assert(o.hEvent)((o.hEvent) ? (void) (0) : __assert_fail ("o.hEvent", "mod_spandsp_modem.c" , 101, __PRETTY_FUNCTION__)); | |||
102 | if (!WriteFile(modem->master, buf, (DWORD)len, &wrote, &o)) { | |||
103 | GetOverlappedResult(modem->master, &o, &wrote, TRUE(!0)); | |||
104 | } | |||
105 | CloseHandle (o.hEvent); | |||
106 | #endif | |||
107 | ||||
108 | if (wrote != len) { | |||
109 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 109, ((void*)0), SWITCH_LOG_ERROR, "Unable to pass the full buffer onto the device file. " | |||
110 | "%"SWITCH_SSIZE_T_FMT"ld" " bytes of " "%"SWITCH_SIZE_T_FMT"ld" " written: %s\n", wrote, len, strerror(errno(*__errno_location ()))); | |||
111 | ||||
112 | if (wrote == -1) wrote = 0; | |||
113 | ||||
114 | #ifndef WIN32 | |||
115 | if (tcflush(modem->master, TCOFLUSH1)) { | |||
116 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 116, ((void*)0), SWITCH_LOG_ERROR, "Unable to flush pty master buffer: %s\n", strerror(errno(*__errno_location ()))); | |||
117 | } else if (tcflush(modem->slave, TCOFLUSH1)) { | |||
118 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 118, ((void*)0), SWITCH_LOG_ERROR, "Unable to flush pty slave buffer: %s\n", strerror(errno(*__errno_location ()))); | |||
119 | } else { | |||
120 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 120, ((void*)0), SWITCH_LOG_DEBUG, "Successfully flushed pty buffer\n"); | |||
121 | } | |||
122 | #endif | |||
123 | } | |||
124 | return wrote; | |||
125 | } | |||
126 | ||||
127 | static int t31_call_control_handler(t31_state_t *s, void *user_data, int op, const char *num) | |||
128 | { | |||
129 | modem_t *modem = user_data; | |||
130 | int ret = 0; | |||
131 | ||||
132 | if (modem->control_handler) { | |||
133 | ret = modem->control_handler(modem, num, op); | |||
134 | } else { | |||
135 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 135, ((void*)0), SWITCH_LOG_ERROR, "DOH! NO CONTROL HANDLER INSTALLED\n"); | |||
136 | } | |||
137 | ||||
138 | return ret; | |||
139 | } | |||
140 | ||||
141 | static modem_state_t modem_get_state(modem_t *modem) | |||
142 | { | |||
143 | modem_state_t state; | |||
144 | ||||
145 | switch_mutex_lock(modem->mutex); | |||
146 | state = modem->state; | |||
147 | switch_mutex_unlock(modem->mutex); | |||
148 | ||||
149 | return state; | |||
150 | } | |||
151 | ||||
152 | static void _modem_set_state(modem_t *modem, modem_state_t state, const char *file, const char *func, int line) | |||
153 | { | |||
154 | ||||
155 | switch_mutex_lock(modem->mutex); | |||
156 | switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL((void*)0), SWITCH_LOG_DEBUG,"Modem %s [%s] - Changing state to %s\n", modem->devlink, | |||
157 | modem_state2name(modem->state), modem_state2name(state)); | |||
158 | modem->state = state; | |||
159 | switch_mutex_unlock(modem->mutex); | |||
160 | } | |||
161 | #define modem_set_state(_modem, _state)_modem_set_state(_modem, _state, "mod_spandsp_modem.c", (const char *)__func__, 161) _modem_set_state(_modem, _state, __FILE__"mod_spandsp_modem.c", __SWITCH_FUNC__(const char *)__func__, __LINE__161) | |||
162 | ||||
163 | char *modem_state2name(int state) | |||
164 | { | |||
165 | if (state > MODEM_STATE_LAST || state < 0) { | |||
166 | state = MODEM_STATE_LAST; | |||
167 | } | |||
168 | ||||
169 | return MODEM_STATE[state].name; | |||
170 | } | |||
171 | ||||
172 | int modem_close(modem_t *modem) | |||
173 | { | |||
174 | int r = 0; | |||
175 | switch_status_t was_running = switch_test_flag(modem, MODEM_FLAG_RUNNING)((modem)->flags & MODEM_FLAG_RUNNING); | |||
176 | ||||
177 | switch_clear_flag(modem, MODEM_FLAG_RUNNING)(modem)->flags &= ~(MODEM_FLAG_RUNNING); | |||
178 | ||||
179 | #ifndef WIN32 | |||
180 | if (modem->master > -1) { | |||
181 | shutdown(modem->master, 2); | |||
182 | close(modem->master); | |||
183 | modem->master = -1; | |||
184 | #else | |||
185 | if (modem->master) { | |||
186 | SetEvent(modem->threadAbort); | |||
187 | CloseHandle(modem->threadAbort); | |||
188 | CloseHandle(modem->master); | |||
189 | modem->master = 0; | |||
190 | #endif | |||
191 | r++; | |||
192 | } | |||
193 | ||||
194 | if (modem->slave > -1) { | |||
195 | shutdown(modem->slave, 2); | |||
196 | close(modem->slave); | |||
197 | modem->slave = -1; | |||
198 | r++; | |||
199 | } | |||
200 | ||||
201 | if (modem->t31_state) { | |||
202 | t31_free(modem->t31_state); | |||
203 | modem->t31_state = NULL((void*)0); | |||
204 | } | |||
205 | ||||
206 | unlink(modem->devlink); | |||
207 | ||||
208 | if (was_running) { | |||
209 | switch_mutex_lock(globals.mutex); | |||
210 | globals.REF_COUNT--; | |||
211 | switch_mutex_unlock(globals.mutex); | |||
212 | } | |||
213 | ||||
214 | return r; | |||
215 | } | |||
216 | ||||
217 | switch_status_t modem_init(modem_t *modem, modem_control_handler_t control_handler) | |||
218 | { | |||
219 | switch_status_t status = SWITCH_STATUS_SUCCESS; | |||
220 | #ifdef WIN32 | |||
221 | COMMTIMEOUTS timeouts = {0}; | |||
222 | #endif | |||
223 | logging_state_t *logging; | |||
224 | ||||
225 | modem->master = -1; | |||
226 | modem->slave = -1; | |||
227 | ||||
228 | /* windows will have to try something like: | |||
229 | http://com0com.cvs.sourceforge.net/viewvc/com0com/com0com/ReadMe.txt?revision=RELEASED | |||
230 | */ | |||
231 | ||||
232 | #if USE_OPENPTY | |||
233 | if (openpty(&modem->master, &modem->slave, NULL((void*)0), NULL((void*)0), NULL((void*)0))) { | |||
234 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 234, ((void*)0), SWITCH_LOG_ERROR, "Fatal error: failed to initialize pty\n"); | |||
235 | status = SWITCH_STATUS_FALSE; | |||
236 | goto end; | |||
237 | } | |||
238 | ||||
239 | modem->stty = ttyname(modem->slave); | |||
240 | #else | |||
241 | #ifdef WIN32 | |||
242 | snprintf(modem->devlink, sizeof(modem->devlink), "COM%d", modem->slot); | |||
243 | ||||
244 | modem->master = CreateFile(modem->devlink, | |||
245 | GENERIC_READ | GENERIC_WRITE, | |||
246 | 0, | |||
247 | 0, | |||
248 | OPEN_EXISTING, | |||
249 | FILE_FLAG_OVERLAPPED, | |||
250 | 0); | |||
251 | if (modem->master == INVALID_HANDLE_VALUE) { | |||
252 | status = SWITCH_STATUS_FALSE; | |||
253 | if (GetLastError() == ERROR_FILE_NOT_FOUND) { | |||
254 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 254, ((void*)0), SWITCH_LOG_ERROR, "Fatal error: Serial port does not exist\n"); | |||
255 | goto end; | |||
256 | } | |||
257 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 257, ((void*)0), SWITCH_LOG_ERROR, "Fatal error: Serial port open error\n"); | |||
258 | goto end; | |||
259 | } | |||
260 | #elif !defined(HAVE_POSIX_OPENPT1) | |||
261 | modem->master = open("/dev/ptmx", O_RDWR02); | |||
262 | #else | |||
263 | modem->master = posix_openpt(O_RDWR02 | O_NOCTTY0400); | |||
264 | #endif | |||
265 | ||||
266 | #ifndef WIN32 | |||
267 | if (modem->master < 0) { | |||
268 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 268, ((void*)0), SWITCH_LOG_ERROR, "Fatal error: failed to initialize UNIX98 master pty\n"); | |||
269 | } | |||
270 | ||||
271 | if (grantpt(modem->master) < 0) { | |||
272 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 272, ((void*)0), SWITCH_LOG_ERROR, "Fatal error: failed to grant access to slave pty\n"); | |||
273 | } | |||
274 | ||||
275 | if (unlockpt(modem->master) < 0) { | |||
276 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 276, ((void*)0), SWITCH_LOG_ERROR, "Fatal error: failed to unlock slave pty\n"); | |||
277 | } | |||
278 | ||||
279 | modem->stty = ptsname(modem->master); | |||
280 | if (modem->stty == NULL((void*)0)) { | |||
281 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 281, ((void*)0), SWITCH_LOG_ERROR, "Fatal error: failed to obtain slave pty filename\n"); | |||
282 | } | |||
283 | ||||
284 | modem->slave = open(modem->stty, O_RDWR02); | |||
| ||||
285 | if (modem->slave < 0) { | |||
286 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 286, ((void*)0), SWITCH_LOG_ERROR, "Fatal error: failed to open slave pty %s\n", modem->stty); | |||
287 | } | |||
288 | #endif | |||
289 | ||||
290 | #ifdef SOLARIS | |||
291 | ioctl(modem->slave, I_PUSH, "ptem"); /* push ptem */ | |||
292 | ioctl(modem->slave, I_PUSH, "ldterm"); /* push ldterm*/ | |||
293 | #endif | |||
294 | #endif | |||
295 | ||||
296 | #ifndef WIN32 | |||
297 | snprintf(modem->devlink, sizeof(modem->devlink), "%s/FS%d", spandsp_globals.modem_directory, modem->slot); | |||
298 | ||||
299 | unlink(modem->devlink); | |||
300 | ||||
301 | if (symlink(modem->stty, modem->devlink)) { | |||
302 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 302, ((void*)0), SWITCH_LOG_ERROR, "Fatal error: failed to create %s symbolic link\n", modem->devlink); | |||
303 | modem_close(modem); | |||
304 | status = SWITCH_STATUS_FALSE; | |||
305 | goto end; | |||
306 | } | |||
307 | ||||
308 | if (fcntl(modem->master, F_SETFL4, fcntl(modem->master, F_GETFL3, 0) | O_NONBLOCK04000)) { | |||
309 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 309, ((void*)0), SWITCH_LOG_ERROR, "Cannot set up non-blocking read on %s\n", ttyname(modem->master)); | |||
310 | modem_close(modem); | |||
311 | status = SWITCH_STATUS_FALSE; | |||
312 | goto end; | |||
313 | } | |||
314 | #else | |||
315 | timeouts.ReadIntervalTimeout = 50; | |||
316 | timeouts.ReadTotalTimeoutConstant = 50; | |||
317 | timeouts.ReadTotalTimeoutMultiplier = 10; | |||
318 | ||||
319 | timeouts.WriteTotalTimeoutConstant = 50; | |||
320 | timeouts.WriteTotalTimeoutMultiplier = 10; | |||
321 | ||||
322 | SetCommMask(modem->master, EV_RXCHAR); | |||
323 | ||||
324 | if (!SetCommTimeouts(modem->master, &timeouts)) { | |||
325 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 325, ((void*)0), SWITCH_LOG_ERROR, "Cannot set up non-blocking read on %s\n", modem->devlink); | |||
326 | modem_close(modem); | |||
327 | status = SWITCH_STATUS_FALSE; | |||
328 | goto end; | |||
329 | } | |||
330 | modem->threadAbort = CreateEvent(NULL((void*)0), TRUE(!0), FALSE0, NULL((void*)0)); | |||
331 | #endif | |||
332 | ||||
333 | if (!(modem->t31_state = t31_init(NULL((void*)0), t31_at_tx_handler, modem, t31_call_control_handler, modem, t38_tx_packet_handler, modem))) { | |||
334 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 334, ((void*)0), SWITCH_LOG_ERROR, "Cannot initialize the T.31 modem\n"); | |||
335 | modem_close(modem); | |||
336 | status = SWITCH_STATUS_FALSE; | |||
337 | goto end; | |||
338 | } | |||
339 | modem->t38_core = t31_get_t38_core_state(modem->t31_state); | |||
340 | ||||
341 | if (spandsp_globals.modem_verbose) { | |||
342 | logging = t31_get_logging_state(modem->t31_state); | |||
343 | span_log_set_message_handler(logging, mod_spandsp_log_message, NULL((void*)0)); | |||
344 | span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); | |||
345 | ||||
346 | logging = v17_rx_get_logging_state(&modem->t31_state->audio.modems.fast_modems.v17_rx); | |||
347 | span_log_set_message_handler(logging, mod_spandsp_log_message, NULL((void*)0)); | |||
348 | span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); | |||
349 | ||||
350 | logging = v29_rx_get_logging_state(&modem->t31_state->audio.modems.fast_modems.v29_rx); | |||
351 | span_log_set_message_handler(logging, mod_spandsp_log_message, NULL((void*)0)); | |||
352 | span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); | |||
353 | ||||
354 | logging = v27ter_rx_get_logging_state(&modem->t31_state->audio.modems.fast_modems.v27ter_rx); | |||
355 | span_log_set_message_handler(logging, mod_spandsp_log_message, NULL((void*)0)); | |||
356 | span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); | |||
357 | ||||
358 | logging = t38_core_get_logging_state(modem->t38_core); | |||
359 | span_log_set_message_handler(logging, mod_spandsp_log_message, NULL((void*)0)); | |||
360 | span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); | |||
361 | } | |||
362 | ||||
363 | modem->control_handler = control_handler; | |||
364 | modem->flags = 0; | |||
365 | switch_set_flag(modem, MODEM_FLAG_RUNNING)(modem)->flags |= (MODEM_FLAG_RUNNING); | |||
366 | ||||
367 | switch_mutex_init(&modem->mutex, SWITCH_MUTEX_NESTED0x1, globals.pool); | |||
368 | switch_mutex_init(&modem->cond_mutex, SWITCH_MUTEX_NESTED0x1, globals.pool); | |||
369 | switch_thread_cond_create(&modem->cond, globals.pool); | |||
370 | ||||
371 | modem_set_state(modem, MODEM_STATE_INIT)_modem_set_state(modem, MODEM_STATE_INIT, "mod_spandsp_modem.c" , (const char *)__func__, 371); | |||
372 | ||||
373 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 373, ((void*)0), SWITCH_LOG_INFO, "Modem [%s]->[%s] Ready\n", modem->devlink, modem->stty); | |||
374 | ||||
375 | switch_mutex_lock(globals.mutex); | |||
376 | globals.REF_COUNT++; | |||
377 | switch_mutex_unlock(globals.mutex); | |||
378 | ||||
379 | end: | |||
380 | return status; | |||
381 | } | |||
382 | ||||
383 | static switch_endpoint_interface_t *modem_endpoint_interface = NULL((void*)0); | |||
384 | ||||
385 | struct private_object { | |||
386 | switch_mutex_t *mutex; | |||
387 | switch_core_session_t *session; | |||
388 | switch_channel_t *channel; | |||
389 | switch_codec_t read_codec; | |||
390 | switch_codec_t write_codec; | |||
391 | switch_frame_t read_frame; | |||
392 | udptl_state_t udptl_state; | |||
393 | unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE8192]; | |||
394 | switch_timer_t timer; | |||
395 | modem_t *modem; | |||
396 | switch_caller_profile_t *caller_profile; | |||
397 | int dead; | |||
398 | }; | |||
399 | ||||
400 | typedef struct private_object private_t; | |||
401 | ||||
402 | static switch_status_t channel_on_init(switch_core_session_t *session); | |||
403 | static switch_status_t channel_on_hangup(switch_core_session_t *session); | |||
404 | static switch_status_t channel_on_destroy(switch_core_session_t *session); | |||
405 | static switch_status_t channel_on_routing(switch_core_session_t *session); | |||
406 | static switch_status_t channel_on_exchange_media(switch_core_session_t *session); | |||
407 | static switch_status_t channel_on_soft_execute(switch_core_session_t *session); | |||
408 | static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, | |||
409 | switch_caller_profile_t *outbound_profile, | |||
410 | switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, | |||
411 | switch_call_cause_t *cancel_cause); | |||
412 | static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); | |||
413 | static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); | |||
414 | static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig); | |||
415 | ||||
416 | ||||
417 | /* | |||
418 | State methods they get called when the state changes to the specific state | |||
419 | returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next | |||
420 | so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it. | |||
421 | */ | |||
422 | static switch_status_t channel_on_init(switch_core_session_t *session) | |||
423 | { | |||
424 | switch_channel_t *channel; | |||
425 | private_t *tech_pvt = NULL((void*)0); | |||
426 | int to_ticks = 60, ring_ticks = 10, rt = ring_ticks; | |||
427 | int rest = 500000; | |||
428 | at_state_t *at_state; | |||
429 | ||||
430 | tech_pvt = switch_core_session_get_private(session)switch_core_session_get_private_class(session, SWITCH_PVT_PRIMARY ); | |||
431 | switch_assert(tech_pvt != NULL)((tech_pvt != ((void*)0)) ? (void) (0) : __assert_fail ("tech_pvt != ((void*)0)" , "mod_spandsp_modem.c", 431, __PRETTY_FUNCTION__)); | |||
432 | ||||
433 | channel = switch_core_session_get_channel(session); | |||
434 | switch_assert(channel != NULL)((channel != ((void*)0)) ? (void) (0) : __assert_fail ("channel != ((void*)0)" , "mod_spandsp_modem.c", 434, __PRETTY_FUNCTION__)); | |||
435 | ||||
436 | if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { | |||
437 | #ifndef WIN32 | |||
438 | int tioflags; | |||
439 | #endif | |||
440 | char call_time[16]; | |||
441 | char call_date[16]; | |||
442 | switch_size_t retsize; | |||
443 | switch_time_exp_t tm; | |||
444 | ||||
445 | switch_time_exp_lt(&tm, switch_micro_time_now()); | |||
446 | switch_strftime(call_date, &retsize, sizeof(call_date), "%m%d", &tm); | |||
447 | switch_strftime(call_time, &retsize, sizeof(call_time), "%H%M", &tm); | |||
448 | ||||
449 | #ifndef WIN32 | |||
450 | ioctl(tech_pvt->modem->slave, TIOCMGET0x5415, &tioflags); | |||
451 | tioflags |= TIOCM_RI0x080; | |||
452 | ioctl(tech_pvt->modem->slave, TIOCMSET0x5418, &tioflags); | |||
453 | #endif | |||
454 | ||||
455 | at_state = t31_get_at_state(tech_pvt->modem->t31_state); | |||
456 | at_reset_call_info(at_state); | |||
457 | at_set_call_info(at_state, "DATE", call_date); | |||
458 | at_set_call_info(at_state, "TIME", call_time); | |||
459 | at_set_call_info(at_state, "NAME", tech_pvt->caller_profile->caller_id_name); | |||
460 | at_set_call_info(at_state, "NMBR", tech_pvt->caller_profile->caller_id_number); | |||
461 | at_set_call_info(at_state, "ANID", tech_pvt->caller_profile->ani); | |||
462 | at_set_call_info(at_state, "USER", tech_pvt->caller_profile->username); | |||
463 | at_set_call_info(at_state, "CDID", tech_pvt->caller_profile->context); | |||
464 | at_set_call_info(at_state, "NDID", tech_pvt->caller_profile->destination_number); | |||
465 | ||||
466 | modem_set_state(tech_pvt->modem, MODEM_STATE_RINGING)_modem_set_state(tech_pvt->modem, MODEM_STATE_RINGING, "mod_spandsp_modem.c" , (const char *)__func__, 466); | |||
467 | t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ALERTING); | |||
468 | ||||
469 | while (to_ticks > 0 && switch_channel_up(channel)(switch_channel_check_signal(channel, SWITCH_TRUE) || switch_channel_get_state (channel) < CS_HANGUP) && modem_get_state(tech_pvt->modem) == MODEM_STATE_RINGING) { | |||
470 | if (--rt <= 0) { | |||
471 | t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ALERTING); | |||
472 | rt = ring_ticks; | |||
473 | } | |||
474 | ||||
475 | switch_yield(rest)switch_sleep(rest);; | |||
476 | to_ticks--; | |||
477 | } | |||
478 | ||||
479 | if (to_ticks < 1 || modem_get_state(tech_pvt->modem) != MODEM_STATE_ANSWERED) { | |||
480 | t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_NO_ANSWER); | |||
481 | switch_channel_hangup(channel, SWITCH_CAUSE_NO_ANSWER)switch_channel_perform_hangup(channel, "mod_spandsp_modem.c", (const char *)__func__, 481, SWITCH_CAUSE_NO_ANSWER); | |||
482 | } else { | |||
483 | t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ANSWERED); | |||
484 | modem_set_state(tech_pvt->modem, MODEM_STATE_CONNECTED)_modem_set_state(tech_pvt->modem, MODEM_STATE_CONNECTED, "mod_spandsp_modem.c" , (const char *)__func__, 484); | |||
485 | switch_channel_mark_answered(channel)switch_channel_perform_mark_answered(channel, "mod_spandsp_modem.c" , (const char *)__func__, 485); | |||
486 | } | |||
487 | } | |||
488 | ||||
489 | switch_channel_set_state(channel, CS_ROUTING)switch_channel_perform_set_state(channel, "mod_spandsp_modem.c" , (const char *)__func__, 489, CS_ROUTING); | |||
490 | ||||
491 | return SWITCH_STATUS_SUCCESS; | |||
492 | } | |||
493 | ||||
494 | static switch_status_t channel_on_routing(switch_core_session_t *session) | |||
495 | { | |||
496 | switch_channel_t *channel = NULL((void*)0); | |||
497 | private_t *tech_pvt = NULL((void*)0); | |||
498 | ||||
499 | channel = switch_core_session_get_channel(session); | |||
500 | assert(channel != NULL)((channel != ((void*)0)) ? (void) (0) : __assert_fail ("channel != ((void*)0)" , "mod_spandsp_modem.c", 500, __PRETTY_FUNCTION__)); | |||
501 | ||||
502 | tech_pvt = switch_core_session_get_private(session)switch_core_session_get_private_class(session, SWITCH_PVT_PRIMARY ); | |||
503 | assert(tech_pvt != NULL)((tech_pvt != ((void*)0)) ? (void) (0) : __assert_fail ("tech_pvt != ((void*)0)" , "mod_spandsp_modem.c", 503, __PRETTY_FUNCTION__)); | |||
504 | ||||
505 | return SWITCH_STATUS_SUCCESS; | |||
506 | } | |||
507 | ||||
508 | static switch_status_t channel_on_execute(switch_core_session_t *session) | |||
509 | { | |||
510 | switch_channel_t *channel = NULL((void*)0); | |||
511 | private_t *tech_pvt = NULL((void*)0); | |||
512 | ||||
513 | channel = switch_core_session_get_channel(session); | |||
514 | assert(channel != NULL)((channel != ((void*)0)) ? (void) (0) : __assert_fail ("channel != ((void*)0)" , "mod_spandsp_modem.c", 514, __PRETTY_FUNCTION__)); | |||
515 | ||||
516 | tech_pvt = switch_core_session_get_private(session)switch_core_session_get_private_class(session, SWITCH_PVT_PRIMARY ); | |||
517 | assert(tech_pvt != NULL)((tech_pvt != ((void*)0)) ? (void) (0) : __assert_fail ("tech_pvt != ((void*)0)" , "mod_spandsp_modem.c", 517, __PRETTY_FUNCTION__)); | |||
518 | ||||
519 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 519, (const char*)(session), SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel)); | |||
520 | ||||
521 | return SWITCH_STATUS_SUCCESS; | |||
522 | } | |||
523 | ||||
524 | static switch_status_t channel_on_destroy(switch_core_session_t *session) | |||
525 | { | |||
526 | //switch_channel_t *channel = NULL; | |||
527 | private_t *tech_pvt = NULL((void*)0); | |||
528 | ||||
529 | //channel = switch_core_session_get_channel(session); | |||
530 | //switch_assert(channel != NULL); | |||
531 | ||||
532 | if ((tech_pvt = switch_core_session_get_private(session)switch_core_session_get_private_class(session, SWITCH_PVT_PRIMARY ))) { | |||
533 | ||||
534 | switch_core_timer_destroy(&tech_pvt->timer); | |||
535 | ||||
536 | if (tech_pvt->modem) { | |||
537 | *tech_pvt->modem->uuid_str = '\0'; | |||
538 | *tech_pvt->modem->digits = '\0'; | |||
539 | modem_set_state(tech_pvt->modem, MODEM_STATE_ONHOOK)_modem_set_state(tech_pvt->modem, MODEM_STATE_ONHOOK, "mod_spandsp_modem.c" , (const char *)__func__, 539); | |||
540 | tech_pvt->modem = NULL((void*)0); | |||
541 | } | |||
542 | } | |||
543 | ||||
544 | return SWITCH_STATUS_SUCCESS; | |||
545 | } | |||
546 | ||||
547 | static switch_status_t channel_on_hangup(switch_core_session_t *session) | |||
548 | { | |||
549 | switch_channel_t *channel = NULL((void*)0); | |||
550 | private_t *tech_pvt = NULL((void*)0); | |||
551 | ||||
552 | channel = switch_core_session_get_channel(session); | |||
553 | switch_assert(channel != NULL)((channel != ((void*)0)) ? (void) (0) : __assert_fail ("channel != ((void*)0)" , "mod_spandsp_modem.c", 553, __PRETTY_FUNCTION__)); | |||
554 | ||||
555 | tech_pvt = switch_core_session_get_private(session)switch_core_session_get_private_class(session, SWITCH_PVT_PRIMARY ); | |||
556 | switch_assert(tech_pvt != NULL)((tech_pvt != ((void*)0)) ? (void) (0) : __assert_fail ("tech_pvt != ((void*)0)" , "mod_spandsp_modem.c", 556, __PRETTY_FUNCTION__)); | |||
557 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 557, (const char*)(session), SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel)); | |||
558 | ||||
559 | t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_HANGUP); | |||
560 | ||||
561 | return SWITCH_STATUS_SUCCESS; | |||
562 | } | |||
563 | ||||
564 | static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig) | |||
565 | { | |||
566 | switch_channel_t *channel = NULL((void*)0); | |||
567 | private_t *tech_pvt = NULL((void*)0); | |||
568 | ||||
569 | channel = switch_core_session_get_channel(session); | |||
570 | switch_assert(channel != NULL)((channel != ((void*)0)) ? (void) (0) : __assert_fail ("channel != ((void*)0)" , "mod_spandsp_modem.c", 570, __PRETTY_FUNCTION__)); | |||
571 | ||||
572 | tech_pvt = switch_core_session_get_private(session)switch_core_session_get_private_class(session, SWITCH_PVT_PRIMARY ); | |||
573 | switch_assert(tech_pvt != NULL)((tech_pvt != ((void*)0)) ? (void) (0) : __assert_fail ("tech_pvt != ((void*)0)" , "mod_spandsp_modem.c", 573, __PRETTY_FUNCTION__)); | |||
574 | ||||
575 | switch (sig) { | |||
576 | case SWITCH_SIG_BREAK: | |||
577 | break; | |||
578 | case SWITCH_SIG_KILL: | |||
579 | tech_pvt->dead = 1; | |||
580 | break; | |||
581 | default: | |||
582 | break; | |||
583 | } | |||
584 | ||||
585 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 585, (const char*)(session), SWITCH_LOG_DEBUG, "%s CHANNEL KILL\n", switch_channel_get_name(channel)); | |||
586 | ||||
587 | return SWITCH_STATUS_SUCCESS; | |||
588 | } | |||
589 | ||||
590 | static switch_status_t channel_on_soft_execute(switch_core_session_t *session) | |||
591 | { | |||
592 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 592, (const char*)(session), SWITCH_LOG_DEBUG, "CHANNEL TRANSMIT\n"); | |||
593 | return SWITCH_STATUS_SUCCESS; | |||
594 | } | |||
595 | ||||
596 | static switch_status_t channel_on_exchange_media(switch_core_session_t *session) | |||
597 | { | |||
598 | switch_channel_t *channel = NULL((void*)0); | |||
599 | private_t *tech_pvt = NULL((void*)0); | |||
600 | ||||
601 | channel = switch_core_session_get_channel(session); | |||
602 | assert(channel != NULL)((channel != ((void*)0)) ? (void) (0) : __assert_fail ("channel != ((void*)0)" , "mod_spandsp_modem.c", 602, __PRETTY_FUNCTION__)); | |||
603 | ||||
604 | tech_pvt = switch_core_session_get_private(session)switch_core_session_get_private_class(session, SWITCH_PVT_PRIMARY ); | |||
605 | assert(tech_pvt != NULL)((tech_pvt != ((void*)0)) ? (void) (0) : __assert_fail ("tech_pvt != ((void*)0)" , "mod_spandsp_modem.c", 605, __PRETTY_FUNCTION__)); | |||
606 | ||||
607 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 607, (const char*)(session), SWITCH_LOG_DEBUG, "CHANNEL MODEM\n"); | |||
608 | ||||
609 | return SWITCH_STATUS_SUCCESS; | |||
610 | } | |||
611 | ||||
612 | static switch_status_t channel_on_reset(switch_core_session_t *session) | |||
613 | { | |||
614 | private_t *tech_pvt = (private_t *) switch_core_session_get_private(session)switch_core_session_get_private_class(session, SWITCH_PVT_PRIMARY ); | |||
615 | switch_assert(tech_pvt != NULL)((tech_pvt != ((void*)0)) ? (void) (0) : __assert_fail ("tech_pvt != ((void*)0)" , "mod_spandsp_modem.c", 615, __PRETTY_FUNCTION__)); | |||
616 | ||||
617 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 617, (const char*)(session), SWITCH_LOG_DEBUG, "%s RESET\n", | |||
618 | switch_channel_get_name(switch_core_session_get_channel(session))); | |||
619 | ||||
620 | return SWITCH_STATUS_SUCCESS; | |||
621 | } | |||
622 | ||||
623 | static switch_status_t channel_on_hibernate(switch_core_session_t *session) | |||
624 | { | |||
625 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 625, (const char*)(session), SWITCH_LOG_DEBUG, "%s HIBERNATE\n", | |||
626 | switch_channel_get_name(switch_core_session_get_channel(session))); | |||
627 | ||||
628 | return SWITCH_STATUS_SUCCESS; | |||
629 | } | |||
630 | ||||
631 | static switch_status_t channel_on_consume_media(switch_core_session_t *session) | |||
632 | { | |||
633 | switch_channel_t *channel = NULL((void*)0); | |||
634 | private_t *tech_pvt = NULL((void*)0); | |||
635 | ||||
636 | channel = switch_core_session_get_channel(session); | |||
637 | assert(channel != NULL)((channel != ((void*)0)) ? (void) (0) : __assert_fail ("channel != ((void*)0)" , "mod_spandsp_modem.c", 637, __PRETTY_FUNCTION__)); | |||
638 | ||||
639 | tech_pvt = switch_core_session_get_private(session)switch_core_session_get_private_class(session, SWITCH_PVT_PRIMARY ); | |||
640 | assert(tech_pvt != NULL)((tech_pvt != ((void*)0)) ? (void) (0) : __assert_fail ("tech_pvt != ((void*)0)" , "mod_spandsp_modem.c", 640, __PRETTY_FUNCTION__)); | |||
641 | ||||
642 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 642, (const char*)(session), SWITCH_LOG_DEBUG, "CHANNEL CONSUME_MEDIA\n"); | |||
643 | ||||
644 | return SWITCH_STATUS_SUCCESS; | |||
645 | } | |||
646 | ||||
647 | static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf) | |||
648 | { | |||
649 | private_t *tech_pvt = NULL((void*)0); | |||
650 | ||||
651 | tech_pvt = switch_core_session_get_private(session)switch_core_session_get_private_class(session, SWITCH_PVT_PRIMARY ); | |||
652 | switch_assert(tech_pvt != NULL)((tech_pvt != ((void*)0)) ? (void) (0) : __assert_fail ("tech_pvt != ((void*)0)" , "mod_spandsp_modem.c", 652, __PRETTY_FUNCTION__)); | |||
653 | ||||
654 | return SWITCH_STATUS_SUCCESS; | |||
655 | } | |||
656 | ||||
657 | static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) | |||
658 | { | |||
659 | switch_channel_t *channel = NULL((void*)0); | |||
660 | private_t *tech_pvt = NULL((void*)0); | |||
661 | switch_status_t status = SWITCH_STATUS_SUCCESS; | |||
662 | int r, samples_wanted, samples_read = 0; | |||
663 | int16_t *data; | |||
664 | ||||
665 | channel = switch_core_session_get_channel(session); | |||
666 | switch_assert(channel != NULL)((channel != ((void*)0)) ? (void) (0) : __assert_fail ("channel != ((void*)0)" , "mod_spandsp_modem.c", 666, __PRETTY_FUNCTION__)); | |||
667 | ||||
668 | tech_pvt = switch_core_session_get_private(session)switch_core_session_get_private_class(session, SWITCH_PVT_PRIMARY ); | |||
669 | switch_assert(tech_pvt != NULL)((tech_pvt != ((void*)0)) ? (void) (0) : __assert_fail ("tech_pvt != ((void*)0)" , "mod_spandsp_modem.c", 669, __PRETTY_FUNCTION__)); | |||
670 | ||||
671 | if (tech_pvt->dead) return SWITCH_STATUS_FALSE; | |||
672 | ||||
673 | data = tech_pvt->read_frame.data; | |||
674 | samples_wanted = tech_pvt->read_codec.implementation->samples_per_packet; | |||
675 | ||||
676 | tech_pvt->read_frame.flags = SFF_NONE; | |||
677 | switch_core_timer_next(&tech_pvt->timer); | |||
678 | ||||
679 | do { | |||
680 | r = t31_tx(tech_pvt->modem->t31_state, data + samples_read, samples_wanted - samples_read); | |||
681 | if (r < 0) break; | |||
682 | samples_read += r; | |||
683 | } while (samples_read < samples_wanted && r > 0); | |||
684 | ||||
685 | if (r < 0) { | |||
686 | return SWITCH_STATUS_FALSE; | |||
687 | } | |||
688 | if (samples_read < samples_wanted) { | |||
689 | memset(data + samples_read, 0, sizeof(int16_t)*(samples_wanted - samples_read)); | |||
690 | samples_read = samples_wanted; | |||
691 | } | |||
692 | ||||
693 | tech_pvt->read_frame.samples = samples_read; | |||
694 | tech_pvt->read_frame.datalen = samples_read * 2; | |||
695 | ||||
696 | *frame = &tech_pvt->read_frame; | |||
697 | ||||
698 | return status; | |||
699 | } | |||
700 | ||||
701 | static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) | |||
702 | { | |||
703 | switch_channel_t *channel = NULL((void*)0); | |||
704 | private_t *tech_pvt = NULL((void*)0); | |||
705 | switch_status_t status = SWITCH_STATUS_SUCCESS; | |||
706 | ||||
707 | channel = switch_core_session_get_channel(session); | |||
708 | switch_assert(channel != NULL)((channel != ((void*)0)) ? (void) (0) : __assert_fail ("channel != ((void*)0)" , "mod_spandsp_modem.c", 708, __PRETTY_FUNCTION__)); | |||
709 | ||||
710 | tech_pvt = switch_core_session_get_private(session)switch_core_session_get_private_class(session, SWITCH_PVT_PRIMARY ); | |||
711 | switch_assert(tech_pvt != NULL)((tech_pvt != ((void*)0)) ? (void) (0) : __assert_fail ("tech_pvt != ((void*)0)" , "mod_spandsp_modem.c", 711, __PRETTY_FUNCTION__)); | |||
712 | ||||
713 | if (tech_pvt->dead) return SWITCH_STATUS_FALSE; | |||
714 | ||||
715 | if (t31_rx(tech_pvt->modem->t31_state, frame->data, frame->datalen / 2)) { | |||
716 | status = SWITCH_STATUS_FALSE; | |||
717 | } | |||
718 | ||||
719 | return status; | |||
720 | } | |||
721 | ||||
722 | static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) | |||
723 | { | |||
724 | switch_channel_t *channel; | |||
725 | private_t *tech_pvt; | |||
726 | ||||
727 | channel = switch_core_session_get_channel(session); | |||
728 | switch_assert(channel != NULL)((channel != ((void*)0)) ? (void) (0) : __assert_fail ("channel != ((void*)0)" , "mod_spandsp_modem.c", 728, __PRETTY_FUNCTION__)); | |||
729 | ||||
730 | tech_pvt = switch_core_session_get_private(session)switch_core_session_get_private_class(session, SWITCH_PVT_PRIMARY ); | |||
731 | switch_assert(tech_pvt != NULL)((tech_pvt != ((void*)0)) ? (void) (0) : __assert_fail ("tech_pvt != ((void*)0)" , "mod_spandsp_modem.c", 731, __PRETTY_FUNCTION__)); | |||
732 | ||||
733 | switch (msg->message_id) { | |||
734 | case SWITCH_MESSAGE_INDICATE_ANSWER: | |||
735 | t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_CONNECTED); | |||
736 | modem_set_state(tech_pvt->modem, MODEM_STATE_CONNECTED)_modem_set_state(tech_pvt->modem, MODEM_STATE_CONNECTED, "mod_spandsp_modem.c" , (const char *)__func__, 736); | |||
737 | mod_spandsp_indicate_data(session, SWITCH_FALSE, SWITCH_TRUE); | |||
738 | break; | |||
739 | case SWITCH_MESSAGE_INDICATE_PROGRESS: | |||
740 | t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_CONNECTED); | |||
741 | modem_set_state(tech_pvt->modem, MODEM_STATE_CONNECTED)_modem_set_state(tech_pvt->modem, MODEM_STATE_CONNECTED, "mod_spandsp_modem.c" , (const char *)__func__, 741); | |||
742 | mod_spandsp_indicate_data(session, SWITCH_FALSE, SWITCH_TRUE); | |||
743 | break; | |||
744 | case SWITCH_MESSAGE_INDICATE_RINGING: | |||
745 | break; | |||
746 | case SWITCH_MESSAGE_INDICATE_BRIDGE: | |||
747 | mod_spandsp_indicate_data(session, SWITCH_FALSE, SWITCH_TRUE); | |||
748 | break; | |||
749 | case SWITCH_MESSAGE_INDICATE_UNBRIDGE: | |||
750 | mod_spandsp_indicate_data(session, SWITCH_FALSE, SWITCH_TRUE); | |||
751 | break; | |||
752 | default: | |||
753 | break; | |||
754 | } | |||
755 | ||||
756 | return SWITCH_STATUS_SUCCESS; | |||
757 | } | |||
758 | ||||
759 | static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *session) | |||
760 | { | |||
761 | const char *iananame = "L16"; | |||
762 | int rate = 8000; | |||
763 | int interval = 20; | |||
764 | switch_status_t status = SWITCH_STATUS_SUCCESS; | |||
765 | switch_channel_t *channel = switch_core_session_get_channel(session); | |||
766 | const switch_codec_implementation_t *read_impl; | |||
767 | ||||
768 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 768, (const char*)(session), SWITCH_LOG_DEBUG, "%s setup codec %s/%d/%d\n", switch_channel_get_name(channel), iananame, rate, | |||
769 | interval); | |||
770 | ||||
771 | status = switch_core_codec_init(&tech_pvt->read_codec,switch_core_codec_init_with_bitrate(&tech_pvt->read_codec , iananame, ((void*)0), rate, interval, 1, 0, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool (session)) | |||
772 | iananame,switch_core_codec_init_with_bitrate(&tech_pvt->read_codec , iananame, ((void*)0), rate, interval, 1, 0, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool (session)) | |||
773 | NULL,switch_core_codec_init_with_bitrate(&tech_pvt->read_codec , iananame, ((void*)0), rate, interval, 1, 0, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool (session)) | |||
774 | rate, interval, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, switch_core_session_get_pool(session))switch_core_codec_init_with_bitrate(&tech_pvt->read_codec , iananame, ((void*)0), rate, interval, 1, 0, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool (session)); | |||
775 | ||||
776 | if (status != SWITCH_STATUS_SUCCESS || !tech_pvt->read_codec.implementation || !switch_core_codec_ready(&tech_pvt->read_codec)) { | |||
777 | goto end; | |||
778 | } | |||
779 | ||||
780 | status = switch_core_codec_init(&tech_pvt->write_codec,switch_core_codec_init_with_bitrate(&tech_pvt->write_codec , iananame, ((void*)0), rate, interval, 1, 0, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool (session)) | |||
781 | iananame,switch_core_codec_init_with_bitrate(&tech_pvt->write_codec , iananame, ((void*)0), rate, interval, 1, 0, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool (session)) | |||
782 | NULL,switch_core_codec_init_with_bitrate(&tech_pvt->write_codec , iananame, ((void*)0), rate, interval, 1, 0, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool (session)) | |||
783 | rate, interval, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, switch_core_session_get_pool(session))switch_core_codec_init_with_bitrate(&tech_pvt->write_codec , iananame, ((void*)0), rate, interval, 1, 0, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, ((void*)0), switch_core_session_get_pool (session)); | |||
784 | ||||
785 | if (status != SWITCH_STATUS_SUCCESS) { | |||
786 | switch_core_codec_destroy(&tech_pvt->read_codec); | |||
787 | goto end; | |||
788 | } | |||
789 | ||||
790 | tech_pvt->read_frame.data = tech_pvt->databuf; | |||
791 | tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf); | |||
792 | tech_pvt->read_frame.codec = &tech_pvt->read_codec; | |||
793 | tech_pvt->read_frame.flags = SFF_NONE; | |||
794 | ||||
795 | switch_core_session_set_read_codec(session, &tech_pvt->read_codec); | |||
796 | switch_core_session_set_write_codec(session, &tech_pvt->write_codec); | |||
797 | ||||
798 | read_impl = tech_pvt->read_codec.implementation; | |||
799 | ||||
800 | switch_core_timer_init(&tech_pvt->timer, "soft", | |||
801 | read_impl->microseconds_per_packet / 1000, read_impl->samples_per_packet, switch_core_session_get_pool(session)); | |||
802 | ||||
803 | switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED0x1, switch_core_session_get_pool(session)); | |||
804 | switch_core_session_set_private(session, tech_pvt)switch_core_session_set_private_class(session, tech_pvt, SWITCH_PVT_PRIMARY ); | |||
805 | tech_pvt->session = session; | |||
806 | tech_pvt->channel = switch_core_session_get_channel(session); | |||
807 | ||||
808 | end: | |||
809 | ||||
810 | return status; | |||
811 | } | |||
812 | ||||
813 | static void tech_attach(private_t *tech_pvt, modem_t *modem) | |||
814 | { | |||
815 | tech_pvt->modem = modem; | |||
816 | switch_set_string(modem->uuid_str, switch_core_session_get_uuid(tech_pvt->session))switch_copy_string(modem->uuid_str, switch_core_session_get_uuid (tech_pvt->session), sizeof(modem->uuid_str)); | |||
817 | switch_channel_set_variable_printf(tech_pvt->channel, "modem_slot", "%d", modem->slot); | |||
818 | switch_channel_set_variable(tech_pvt->channel, "modem_devlink", modem->devlink)switch_channel_set_variable_var_check(tech_pvt->channel, "modem_devlink" , modem->devlink, SWITCH_TRUE); | |||
819 | switch_channel_set_variable(tech_pvt->channel, "modem_digits", modem->digits)switch_channel_set_variable_var_check(tech_pvt->channel, "modem_digits" , modem->digits, SWITCH_TRUE); | |||
820 | switch_channel_export_variable(tech_pvt->channel, "rtp_autoflush_during_bridge", "false", SWITCH_EXPORT_VARS_VARIABLE)switch_channel_export_variable_var_check(tech_pvt->channel , "rtp_autoflush_during_bridge", "false", "export_vars", SWITCH_TRUE ); | |||
821 | } | |||
822 | ||||
823 | ||||
824 | static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, | |||
825 | switch_caller_profile_t *outbound_profile, | |||
826 | switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, | |||
827 | switch_call_cause_t *cancel_cause) | |||
828 | { | |||
829 | char name[128]; | |||
830 | switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; | |||
831 | ||||
832 | if ((*new_session = switch_core_session_request(modem_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, flags, pool)switch_core_session_request_uuid(modem_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND , flags, pool, ((void*)0))) != 0) { | |||
833 | private_t *tech_pvt; | |||
834 | switch_channel_t *channel; | |||
835 | switch_caller_profile_t *caller_profile; | |||
836 | char *dest = switch_core_session_strdup(*new_session, outbound_profile->destination_number)switch_core_perform_session_strdup(*new_session, outbound_profile ->destination_number, "mod_spandsp_modem.c", (const char * )__func__, 836); | |||
837 | char *modem_id_string = NULL((void*)0); | |||
838 | char *number = NULL((void*)0); | |||
839 | int modem_id = 0; | |||
840 | modem_t *modem = NULL((void*)0); | |||
841 | ||||
842 | if ((modem_id_string = dest)) { | |||
843 | if ((number = strchr(modem_id_string, '/')(__extension__ (__builtin_constant_p ('/') && !__builtin_constant_p (modem_id_string) && ('/') == '\0' ? (char *) __rawmemchr (modem_id_string, '/') : __builtin_strchr (modem_id_string, '/' ))))) { | |||
844 | *number++ = '\0'; | |||
845 | } | |||
846 | } | |||
847 | ||||
848 | if (zstr(modem_id_string)_zstr(modem_id_string) || zstr(number)_zstr(number)) { | |||
849 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 849, (const char*)(*new_session), SWITCH_LOG_ERROR, "Invalid dial string.\n"); | |||
850 | cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT; goto fail; | |||
851 | } | |||
852 | ||||
853 | if (!strcasecmp(modem_id_string, "a")) { | |||
854 | modem_id = -1; | |||
855 | } else { | |||
856 | modem_id = atoi(modem_id_string); | |||
857 | } | |||
858 | ||||
859 | if (!(modem = acquire_modem(modem_id))) { | |||
860 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 860, (const char*)(*new_session), SWITCH_LOG_ERROR, "Cannot find a modem.\n"); | |||
861 | cause = SWITCH_CAUSE_USER_BUSY; goto fail; | |||
862 | } | |||
863 | ||||
864 | switch_core_session_add_stream(*new_session, NULL((void*)0)); | |||
865 | ||||
866 | if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))switch_core_perform_session_alloc(*new_session, sizeof(private_t ), "mod_spandsp_modem.c", (const char *)__func__, 866)) != 0) { | |||
867 | channel = switch_core_session_get_channel(*new_session); | |||
868 | switch_snprintf(name, sizeof(name), "modem/%d/%s", modem->slot, number); | |||
869 | switch_channel_set_name(channel, name); | |||
870 | ||||
871 | if (tech_init(tech_pvt, *new_session) != SWITCH_STATUS_SUCCESS) { | |||
872 | cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; goto fail; | |||
873 | } | |||
874 | ||||
875 | switch_set_string(modem->digits, number)switch_copy_string(modem->digits, number, sizeof(modem-> digits)); | |||
876 | tech_attach(tech_pvt, modem); | |||
877 | } else { | |||
878 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 878, (const char*)(*new_session), SWITCH_LOG_CRIT, "Hey where is my memory pool?\n"); | |||
879 | switch_core_session_destroy(new_session)switch_core_session_perform_destroy(new_session, "mod_spandsp_modem.c" , (const char *)__func__, 879); | |||
880 | cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; goto fail; | |||
881 | } | |||
882 | ||||
883 | if (outbound_profile) { | |||
884 | caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); | |||
885 | caller_profile->source = switch_core_strdup(caller_profile->pool, "mod_spandsp")switch_core_perform_strdup(caller_profile->pool, "mod_spandsp" , "mod_spandsp_modem.c", (const char *)__func__, 885); | |||
886 | caller_profile->destination_number = switch_core_strdup(caller_profile->pool, number)switch_core_perform_strdup(caller_profile->pool, number, "mod_spandsp_modem.c" , (const char *)__func__, 886); | |||
887 | switch_channel_set_caller_profile(channel, caller_profile); | |||
888 | tech_pvt->caller_profile = caller_profile; | |||
889 | } else { | |||
890 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 890, (const char*)(*new_session), SWITCH_LOG_ERROR, "Doh! no caller profile\n"); | |||
891 | cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; goto fail; | |||
892 | } | |||
893 | ||||
894 | switch_channel_set_state(channel, CS_INIT)switch_channel_perform_set_state(channel, "mod_spandsp_modem.c" , (const char *)__func__, 894, CS_INIT); | |||
895 | ||||
896 | return SWITCH_CAUSE_SUCCESS; | |||
897 | ||||
898 | fail: | |||
899 | ||||
900 | if (new_session) { | |||
901 | switch_core_session_destroy(new_session)switch_core_session_perform_destroy(new_session, "mod_spandsp_modem.c" , (const char *)__func__, 901); | |||
902 | } | |||
903 | ||||
904 | if (modem) { | |||
905 | modem_set_state(modem, MODEM_STATE_ONHOOK)_modem_set_state(modem, MODEM_STATE_ONHOOK, "mod_spandsp_modem.c" , (const char *)__func__, 905); | |||
906 | } | |||
907 | } | |||
908 | ||||
909 | return cause; | |||
910 | } | |||
911 | ||||
912 | static switch_state_handler_table_t channel_event_handlers = { | |||
913 | /*.on_init */ channel_on_init, | |||
914 | /*.on_routing */ channel_on_routing, | |||
915 | /*.on_execute */ channel_on_execute, | |||
916 | /*.on_hangup */ channel_on_hangup, | |||
917 | /*.on_exchange_media */ channel_on_exchange_media, | |||
918 | /*.on_soft_execute */ channel_on_soft_execute, | |||
919 | /*.on_consume_media */ channel_on_consume_media, | |||
920 | /*.on_hibernate */ channel_on_hibernate, | |||
921 | /*.on_reset */ channel_on_reset, | |||
922 | /*.on_park */ NULL((void*)0), | |||
923 | /*.on_reporting */ NULL((void*)0), | |||
924 | /*.on_destroy */ channel_on_destroy | |||
925 | }; | |||
926 | ||||
927 | static switch_io_routines_t channel_io_routines = { | |||
928 | /*.outgoing_channel */ channel_outgoing_channel, | |||
929 | /*.read_frame */ channel_read_frame, | |||
930 | /*.write_frame */ channel_write_frame, | |||
931 | /*.kill_channel */ channel_kill_channel, | |||
932 | /*.send_dtmf */ channel_send_dtmf, | |||
933 | /*.receive_message */ channel_receive_message | |||
934 | }; | |||
935 | ||||
936 | static switch_status_t create_session(switch_core_session_t **new_session, modem_t *modem) | |||
937 | { | |||
938 | switch_status_t status = SWITCH_STATUS_FALSE; | |||
939 | switch_core_session_t *session; | |||
940 | switch_channel_t *channel; | |||
941 | private_t *tech_pvt = NULL((void*)0); | |||
942 | char name[1024]; | |||
943 | switch_caller_profile_t *caller_profile; | |||
944 | char *ani = NULL((void*)0), *p, *digits = NULL((void*)0); | |||
945 | ||||
946 | if (!(session = switch_core_session_request(modem_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL)switch_core_session_request_uuid(modem_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND , SOF_NONE, ((void*)0), ((void*)0)))) { | |||
947 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 947, (const char*)(session), SWITCH_LOG_CRIT, "Failure.\n"); | |||
948 | goto end; | |||
949 | } | |||
950 | ||||
951 | switch_core_session_add_stream(session, NULL((void*)0)); | |||
952 | channel = switch_core_session_get_channel(session); | |||
953 | tech_pvt = (private_t *) switch_core_session_alloc(session, sizeof(*tech_pvt))switch_core_perform_session_alloc(session, sizeof(*tech_pvt), "mod_spandsp_modem.c", (const char *)__func__, 953); | |||
954 | ||||
955 | p = switch_core_session_strdup(session, modem->digits)switch_core_perform_session_strdup(session, modem->digits, "mod_spandsp_modem.c", (const char *)__func__, 955); | |||
956 | ||||
957 | if (*p == '*') { | |||
958 | ani = p + 1; | |||
959 | if ((digits = strchr(ani, '*')(__extension__ (__builtin_constant_p ('*') && !__builtin_constant_p (ani) && ('*') == '\0' ? (char *) __rawmemchr (ani, '*' ) : __builtin_strchr (ani, '*'))))) { | |||
960 | *digits++ = '\0'; | |||
961 | } else { | |||
962 | ani = NULL((void*)0); | |||
963 | } | |||
964 | } | |||
965 | ||||
966 | if (zstr(digits)_zstr(digits)) { | |||
967 | digits = p; | |||
968 | } | |||
969 | ||||
970 | if (zstr(ani)_zstr(ani)) { | |||
971 | ani = modem->devlink + 5; | |||
972 | } | |||
973 | ||||
974 | switch_snprintf(name, sizeof(name), "modem/%d/%s", modem->slot, digits); | |||
975 | switch_channel_set_name(channel, name); | |||
976 | ||||
977 | if (tech_init(tech_pvt, session) != SWITCH_STATUS_SUCCESS) { | |||
978 | switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER)switch_channel_perform_hangup(channel, "mod_spandsp_modem.c", (const char *)__func__, 978, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ); | |||
979 | switch_core_session_destroy(&session)switch_core_session_perform_destroy(&session, "mod_spandsp_modem.c" , (const char *)__func__, 979); | |||
980 | goto end; | |||
981 | } | |||
982 | ||||
983 | caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), | |||
984 | modem->devlink, | |||
985 | spandsp_globals.modem_dialplan, | |||
986 | "FSModem", | |||
987 | ani, | |||
988 | NULL((void*)0), | |||
989 | ani, | |||
990 | NULL((void*)0), | |||
991 | NULL((void*)0), | |||
992 | "mod_spandsp", | |||
993 | spandsp_globals.modem_context, | |||
994 | digits); | |||
995 | ||||
996 | caller_profile->source = switch_core_strdup(caller_profile->pool, "mod_spandsp")switch_core_perform_strdup(caller_profile->pool, "mod_spandsp" , "mod_spandsp_modem.c", (const char *)__func__, 996); | |||
997 | switch_channel_set_caller_profile(channel, caller_profile); | |||
998 | tech_pvt->caller_profile = caller_profile; | |||
999 | switch_channel_set_state(channel, CS_INIT)switch_channel_perform_set_state(channel, "mod_spandsp_modem.c" , (const char *)__func__, 999, CS_INIT); | |||
1000 | ||||
1001 | if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) { | |||
1002 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_spandsp_modem.c", (const char *)__func__, 1002, (const char*)(session), SWITCH_LOG_CRIT, "Error spawning thread\n"); | |||
1003 | switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER)switch_channel_perform_hangup(channel, "mod_spandsp_modem.c", (const char *)__func__, 1003, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ); | |||
1004 | goto end; | |||
1005 | } | |||
1006 | ||||
1007 | status = SWITCH_STATUS_SUCCESS; | |||
1008 | tech_attach(tech_pvt, modem); | |||
1009 | *new_session = session; | |||
1010 | ||||
1011 | end: | |||
1012 | ||||
1013 | return status; | |||
1014 | } | |||
1015 | ||||
1016 | static void wake_modem_thread(modem_t *modem) | |||
1017 | { | |||
1018 | if (switch_mutex_trylock(modem->cond_mutex) == SWITCH_STATUS_SUCCESS) { | |||
1019 | switch_thread_cond_signal(modem->cond); | |||
1020 | switch_mutex_unlock(modem->cond_mutex); | |||
1021 | } | |||
1022 | } | |||
1023 | ||||
1024 | static int control_handler(modem_t *modem, const char *num, int op) | |||
1025 | { | |||
1026 | switch_core_session_t *session = NULL((void*)0); | |||
1027 | ||||
1028 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1028, ((void*)0), SWITCH_LOG_DEBUG1, "Control Handler op:%d state:[%s] %s\n", | |||
1029 | op, modem_state2name(modem_get_state(modem)), modem->devlink); | |||
1030 | ||||
1031 | switch (op) { | |||
1032 | case AT_MODEM_CONTROL_ANSWER: | |||
1033 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1033, ((void*)0), SWITCH_LOG_DEBUG, | |||
1034 | "Modem %s [%s] - Answering\n", modem->devlink, modem_state2name(modem_get_state(modem))); | |||
1035 | modem_set_state(modem, MODEM_STATE_ANSWERED)_modem_set_state(modem, MODEM_STATE_ANSWERED, "mod_spandsp_modem.c" , (const char *)__func__, 1035); | |||
1036 | break; | |||
1037 | case AT_MODEM_CONTROL_CALL: | |||
1038 | { | |||
1039 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1039, ((void*)0), SWITCH_LOG_DEBUG, | |||
1040 | "Modem %s [%s] - Dialing '%s'\n", modem->devlink, modem_state2name(modem_get_state(modem)), num); | |||
1041 | modem_set_state(modem, MODEM_STATE_DIALING)_modem_set_state(modem, MODEM_STATE_DIALING, "mod_spandsp_modem.c" , (const char *)__func__, 1041); | |||
1042 | switch_clear_flag(modem, MODEM_FLAG_XOFF)(modem)->flags &= ~(MODEM_FLAG_XOFF); | |||
1043 | wake_modem_thread(modem); | |||
1044 | ||||
1045 | switch_set_string(modem->digits, num)switch_copy_string(modem->digits, num, sizeof(modem->digits )); | |||
1046 | ||||
1047 | if (create_session(&session, modem) != SWITCH_STATUS_SUCCESS) { | |||
1048 | t31_call_event(modem->t31_state, AT_CALL_EVENT_HANGUP); | |||
1049 | } else { | |||
1050 | switch_core_session_thread_launch(session); | |||
1051 | } | |||
1052 | } | |||
1053 | break; | |||
1054 | case AT_MODEM_CONTROL_OFFHOOK: | |||
1055 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1055, ((void*)0), SWITCH_LOG_DEBUG, | |||
1056 | "Modem %s [%s] - Going off hook\n", modem->devlink, modem_state2name(modem_get_state(modem))); | |||
1057 | modem_set_state(modem, MODEM_STATE_OFFHOOK)_modem_set_state(modem, MODEM_STATE_OFFHOOK, "mod_spandsp_modem.c" , (const char *)__func__, 1057); | |||
1058 | break; | |||
1059 | case AT_MODEM_CONTROL_ONHOOK: | |||
1060 | case AT_MODEM_CONTROL_HANGUP: | |||
1061 | { | |||
1062 | if (modem_get_state(modem) != MODEM_STATE_RINGING) { | |||
1063 | int set_state = 1; | |||
1064 | ||||
1065 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1065, ((void*)0), SWITCH_LOG_DEBUG, | |||
1066 | "Modem %s [%s] - Hanging up\n", modem->devlink, modem_state2name(modem_get_state(modem))); | |||
1067 | switch_clear_flag(modem, MODEM_FLAG_XOFF)(modem)->flags &= ~(MODEM_FLAG_XOFF); | |||
1068 | wake_modem_thread(modem); | |||
1069 | ||||
1070 | modem_set_state(modem, MODEM_STATE_HANGUP)_modem_set_state(modem, MODEM_STATE_HANGUP, "mod_spandsp_modem.c" , (const char *)__func__, 1070); | |||
1071 | ||||
1072 | if (!zstr(modem->uuid_str)_zstr(modem->uuid_str)) { | |||
1073 | switch_core_session_t *session; | |||
1074 | ||||
1075 | if ((session = switch_core_session_force_locate(modem->uuid_str)switch_core_session_perform_force_locate(modem->uuid_str, "mod_spandsp_modem.c" , (const char *)__func__, 1075))) { | |||
1076 | switch_channel_t *channel = switch_core_session_get_channel(session); | |||
1077 | ||||
1078 | if (switch_channel_up(channel)(switch_channel_check_signal(channel, SWITCH_TRUE) || switch_channel_get_state (channel) < CS_HANGUP)) { | |||
1079 | switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING)switch_channel_perform_hangup(channel, "mod_spandsp_modem.c", (const char *)__func__, 1079, SWITCH_CAUSE_NORMAL_CLEARING); | |||
1080 | set_state = 0; | |||
1081 | } | |||
1082 | switch_core_session_rwunlock(session); | |||
1083 | } | |||
1084 | } | |||
1085 | ||||
1086 | if (set_state) { | |||
1087 | modem_set_state(modem, MODEM_STATE_ONHOOK)_modem_set_state(modem, MODEM_STATE_ONHOOK, "mod_spandsp_modem.c" , (const char *)__func__, 1087); | |||
1088 | } | |||
1089 | } | |||
1090 | } | |||
1091 | break; | |||
1092 | case AT_MODEM_CONTROL_DTR: | |||
1093 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1093, ((void*)0), SWITCH_LOG_DEBUG, | |||
1094 | "Modem %s [%s] - DTR %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num); | |||
1095 | break; | |||
1096 | case AT_MODEM_CONTROL_RTS: | |||
1097 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1097, ((void*)0), SWITCH_LOG_DEBUG, | |||
1098 | "Modem %s [%s] - RTS %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num); | |||
1099 | break; | |||
1100 | case AT_MODEM_CONTROL_CTS: | |||
1101 | { | |||
1102 | u_char x[1]; | |||
1103 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1103, ((void*)0), SWITCH_LOG_DEBUG1, | |||
1104 | "Modem %s [%s] - CTS %s\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num ? "XON" : "XOFF"); | |||
1105 | if (num) { | |||
1106 | x[0] = 0x11; | |||
1107 | t31_at_tx_handler(modem, x, 1); | |||
1108 | switch_clear_flag(modem, MODEM_FLAG_XOFF)(modem)->flags &= ~(MODEM_FLAG_XOFF); | |||
1109 | wake_modem_thread(modem); | |||
1110 | } else { | |||
1111 | x[0] = 0x13; | |||
1112 | t31_at_tx_handler(modem, x, 1); | |||
1113 | switch_set_flag(modem, MODEM_FLAG_XOFF)(modem)->flags |= (MODEM_FLAG_XOFF); | |||
1114 | } | |||
1115 | } | |||
1116 | break; | |||
1117 | case AT_MODEM_CONTROL_CAR: | |||
1118 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1118, ((void*)0), SWITCH_LOG_DEBUG, | |||
1119 | "Modem %s [%s] - CAR %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num); | |||
1120 | break; | |||
1121 | case AT_MODEM_CONTROL_RNG: | |||
1122 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1122, ((void*)0), SWITCH_LOG_DEBUG, | |||
1123 | "Modem %s [%s] - RNG %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num); | |||
1124 | break; | |||
1125 | case AT_MODEM_CONTROL_DSR: | |||
1126 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1126, ((void*)0), SWITCH_LOG_DEBUG, | |||
1127 | "Modem %s [%s] - DSR %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), (int) (intptr_t) num); | |||
1128 | break; | |||
1129 | default: | |||
1130 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1130, ((void*)0), SWITCH_LOG_DEBUG, | |||
1131 | "Modem %s [%s] - operation %d\n", modem->devlink, modem_state2name(modem_get_state(modem)), op); | |||
1132 | break; | |||
1133 | } | |||
1134 | /*endswitch*/ | |||
1135 | return 0; | |||
1136 | } | |||
1137 | ||||
1138 | typedef enum { | |||
1139 | MODEM_POLL_READ = (1 << 0), | |||
1140 | MODEM_POLL_WRITE = (1 << 1), | |||
1141 | MODEM_POLL_ERROR = (1 << 2) | |||
1142 | } modem_poll_t; | |||
1143 | ||||
1144 | #ifndef WIN32 | |||
1145 | static int modem_wait_sock(int sock, uint32_t ms, modem_poll_t flags) | |||
1146 | { | |||
1147 | struct pollfd pfds[2] = { { 0 } }; | |||
1148 | int s = 0, r = 0; | |||
1149 | ||||
1150 | pfds[0].fd = sock; | |||
1151 | ||||
1152 | if ((flags & MODEM_POLL_READ)) { | |||
1153 | pfds[0].events |= POLLIN0x001; | |||
1154 | } | |||
1155 | ||||
1156 | if ((flags & MODEM_POLL_WRITE)) { | |||
1157 | pfds[0].events |= POLLOUT0x004; | |||
1158 | } | |||
1159 | ||||
1160 | if ((flags & MODEM_POLL_ERROR)) { | |||
1161 | pfds[0].events |= POLLERR0x008; | |||
1162 | } | |||
1163 | ||||
1164 | s = poll(pfds, 1, ms); | |||
1165 | ||||
1166 | if (s < 0) { | |||
1167 | r = s; | |||
1168 | } else if (s > 0) { | |||
1169 | if ((pfds[0].revents & POLLIN0x001)) { | |||
1170 | r |= MODEM_POLL_READ; | |||
1171 | } | |||
1172 | if ((pfds[0].revents & POLLOUT0x004)) { | |||
1173 | r |= MODEM_POLL_WRITE; | |||
1174 | } | |||
1175 | if ((pfds[0].revents & POLLERR0x008)) { | |||
1176 | r |= MODEM_POLL_ERROR; | |||
1177 | } | |||
1178 | } | |||
1179 | ||||
1180 | return r; | |||
1181 | } | |||
1182 | #else | |||
1183 | static int modem_wait_sock(modem_t *modem, int ms, modem_poll_t flags) | |||
1184 | { | |||
1185 | /* this method ignores ms and waits infinitely */ | |||
1186 | DWORD dwEvtMask, dwWait; | |||
1187 | OVERLAPPED o; | |||
1188 | BOOL result; | |||
1189 | int ret = MODEM_POLL_ERROR; | |||
1190 | HANDLE arHandles[2]; | |||
1191 | ||||
1192 | arHandles[0] = modem->threadAbort; | |||
1193 | ||||
1194 | o.hEvent = CreateEvent(NULL((void*)0), TRUE(!0), FALSE0, NULL((void*)0)); | |||
1195 | arHandles[1] = o.hEvent; | |||
1196 | ||||
1197 | /* Initialize the rest of the OVERLAPPED structure to zero. */ | |||
1198 | o.Internal = 0; | |||
1199 | o.InternalHigh = 0; | |||
1200 | o.Offset = 0; | |||
1201 | o.OffsetHigh = 0; | |||
1202 | assert(o.hEvent)((o.hEvent) ? (void) (0) : __assert_fail ("o.hEvent", "mod_spandsp_modem.c" , 1202, __PRETTY_FUNCTION__)); | |||
1203 | ||||
1204 | result = WaitCommEvent(modem->master, &dwEvtMask, &o); | |||
1205 | ||||
1206 | if (result == 0) | |||
1207 | { | |||
1208 | if (GetLastError() != ERROR_IO_PENDING) { | |||
1209 | /* something went horribly wrong with WaitCommEvent(), so | |||
1210 | clear all errors and try again */ | |||
1211 | DWORD comerrors; | |||
1212 | ClearCommError(modem->master, &comerrors, 0); | |||
1213 | } else { | |||
1214 | /* IO is pending, wait for it to finish */ | |||
1215 | dwWait = WaitForMultipleObjects(2, arHandles, FALSE0, INFINITE); | |||
1216 | if (dwWait == WAIT_OBJECT_0 + 1) { | |||
1217 | ret = MODEM_POLL_READ; | |||
1218 | } | |||
1219 | } | |||
1220 | } | |||
1221 | else { | |||
1222 | ret = MODEM_POLL_READ; | |||
1223 | } | |||
1224 | ||||
1225 | CloseHandle (o.hEvent); | |||
1226 | return ret; | |||
1227 | } | |||
1228 | #endif | |||
1229 | ||||
1230 | static void *SWITCH_THREAD_FUNC modem_thread(switch_thread_t *thread, void *obj) | |||
1231 | { | |||
1232 | modem_t *modem = obj; | |||
1233 | int r, avail; | |||
1234 | #ifdef WIN32 | |||
1235 | DWORD readBytes; | |||
1236 | OVERLAPPED o; | |||
1237 | #endif | |||
1238 | char buf[T31_TX_BUF_LEN(4096)]; | |||
1239 | ||||
1240 | switch_mutex_lock(globals.mutex); | |||
1241 | modem_init(modem, control_handler); | |||
| ||||
1242 | globals.THREADCOUNT++; | |||
1243 | switch_mutex_unlock(globals.mutex); | |||
1244 | ||||
1245 | if (switch_test_flag(modem, MODEM_FLAG_RUNNING)((modem)->flags & MODEM_FLAG_RUNNING)) { | |||
1246 | switch_mutex_lock(modem->cond_mutex); | |||
1247 | ||||
1248 | while (switch_test_flag(modem, MODEM_FLAG_RUNNING)((modem)->flags & MODEM_FLAG_RUNNING)) { | |||
1249 | ||||
1250 | #ifndef WIN32 | |||
1251 | r = modem_wait_sock(modem->master, -1, MODEM_POLL_READ | MODEM_POLL_ERROR); | |||
1252 | #else | |||
1253 | r = modem_wait_sock(modem, -1, MODEM_POLL_READ | MODEM_POLL_ERROR); | |||
1254 | #endif | |||
1255 | ||||
1256 | if (!switch_test_flag(modem, MODEM_FLAG_RUNNING)((modem)->flags & MODEM_FLAG_RUNNING)) { | |||
1257 | break; | |||
1258 | } | |||
1259 | ||||
1260 | if (r < 0 || !(r & MODEM_POLL_READ) || (r & MODEM_POLL_ERROR)) { | |||
1261 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1261, ((void*)0), SWITCH_LOG_WARNING, "Bad Read on master [%s] [%d]\n", modem->devlink, r); | |||
1262 | break; | |||
1263 | } | |||
1264 | ||||
1265 | modem->last_event = switch_time_now(); | |||
1266 | ||||
1267 | if (switch_test_flag(modem, MODEM_FLAG_XOFF)((modem)->flags & MODEM_FLAG_XOFF)) { | |||
1268 | switch_thread_cond_wait(modem->cond, modem->cond_mutex); | |||
1269 | modem->last_event = switch_time_now(); | |||
1270 | } | |||
1271 | ||||
1272 | avail = t31_at_rx_free_space(modem->t31_state); | |||
1273 | if (avail == 0) { | |||
1274 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1274, ((void*)0), SWITCH_LOG_WARNING, "Buffer Full, retrying....\n"); | |||
1275 | switch_yield(10000)switch_sleep(10000);; | |||
1276 | continue; | |||
1277 | } | |||
1278 | ||||
1279 | #ifndef WIN32 | |||
1280 | r = read(modem->master, buf, avail); | |||
1281 | #else | |||
1282 | o.hEvent = CreateEvent(NULL((void*)0), TRUE(!0), FALSE0, NULL((void*)0)); | |||
1283 | ||||
1284 | /* Initialize the rest of the OVERLAPPED structure to zero. */ | |||
1285 | o.Internal = 0; | |||
1286 | o.InternalHigh = 0; | |||
1287 | o.Offset = 0; | |||
1288 | o.OffsetHigh = 0; | |||
1289 | assert(o.hEvent)((o.hEvent) ? (void) (0) : __assert_fail ("o.hEvent", "mod_spandsp_modem.c" , 1289, __PRETTY_FUNCTION__)); | |||
1290 | if (!ReadFile(modem->master, buf, avail, &readBytes, &o)) { | |||
1291 | GetOverlappedResult(modem->master, &o, &readBytes,TRUE(!0)); | |||
1292 | } | |||
1293 | CloseHandle (o.hEvent); | |||
1294 | r = readBytes; | |||
1295 | #endif | |||
1296 | t31_at_rx(modem->t31_state, buf, r); | |||
1297 | ||||
1298 | if (!strncasecmp(buf, "AT", 2)) { | |||
1299 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1299, ((void*)0), SWITCH_LOG_DEBUG1, "Command on %s [%s]\n", modem->devlink, buf); | |||
1300 | } | |||
1301 | } | |||
1302 | ||||
1303 | switch_mutex_unlock(modem->cond_mutex); | |||
1304 | ||||
1305 | if (switch_test_flag(modem, MODEM_FLAG_RUNNING)((modem)->flags & MODEM_FLAG_RUNNING)) { | |||
1306 | modem_close(modem); | |||
1307 | } | |||
1308 | } | |||
1309 | ||||
1310 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1310, ((void*)0), SWITCH_LOG_INFO, "Thread ended for %s\n", modem->devlink); | |||
1311 | ||||
1312 | switch_mutex_lock(globals.mutex); | |||
1313 | globals.THREADCOUNT--; | |||
1314 | switch_mutex_unlock(globals.mutex); | |||
1315 | ||||
1316 | return NULL((void*)0); | |||
1317 | } | |||
1318 | ||||
1319 | static void launch_modem_thread(modem_t *modem) | |||
1320 | { | |||
1321 | switch_thread_t *thread; | |||
1322 | switch_threadattr_t *thd_attr = NULL((void*)0); | |||
1323 | ||||
1324 | switch_threadattr_create(&thd_attr, globals.pool); | |||
1325 | switch_threadattr_detach_set(thd_attr, 1); | |||
1326 | switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE240 * 1024); | |||
1327 | switch_thread_create(&thread, thd_attr, modem_thread, modem, globals.pool); | |||
1328 | } | |||
1329 | ||||
1330 | static void activate_modems(void) | |||
1331 | { | |||
1332 | int max = globals.SOFT_MAX_MODEMS; | |||
1333 | int x; | |||
1334 | ||||
1335 | switch_mutex_lock(globals.mutex); | |||
1336 | memset(globals.MODEM_POOL, 0, sizeof(globals.MODEM_POOL)); | |||
1337 | for (x = 0; x < max; x++) { | |||
1338 | ||||
1339 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1339, ((void*)0), SWITCH_LOG_INFO, "Starting Modem SLOT %d\n", x); | |||
1340 | ||||
1341 | globals.MODEM_POOL[x].slot = x; | |||
1342 | launch_modem_thread(&globals.MODEM_POOL[x]); | |||
1343 | } | |||
1344 | switch_mutex_unlock(globals.mutex); | |||
1345 | } | |||
1346 | ||||
1347 | static void deactivate_modems(void) | |||
1348 | { | |||
1349 | int max = globals.SOFT_MAX_MODEMS; | |||
1350 | int x; | |||
1351 | ||||
1352 | switch_mutex_lock(globals.mutex); | |||
1353 | ||||
1354 | for (x = 0; x < max; x++) { | |||
1355 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1355, ((void*)0), SWITCH_LOG_INFO, "Stopping Modem SLOT %d\n", x); | |||
1356 | modem_close(&globals.MODEM_POOL[x]); | |||
1357 | } | |||
1358 | ||||
1359 | switch_mutex_unlock(globals.mutex); | |||
1360 | ||||
1361 | /* Wait for Threads to die */ | |||
1362 | while (globals.THREADCOUNT) { | |||
1363 | switch_yield(100000)switch_sleep(100000);; | |||
1364 | } | |||
1365 | } | |||
1366 | ||||
1367 | static modem_t *acquire_modem(int index) | |||
1368 | { | |||
1369 | modem_t *modem = NULL((void*)0); | |||
1370 | switch_time_t now = switch_time_now(); | |||
1371 | int64_t idle_debounce = 2000000; | |||
1372 | ||||
1373 | switch_mutex_lock(globals.mutex); | |||
1374 | if (index > -1 && index < globals.SOFT_MAX_MODEMS) { | |||
1375 | modem = &globals.MODEM_POOL[index]; | |||
1376 | } else { | |||
1377 | int x; | |||
1378 | ||||
1379 | for (x = 0; x < globals.SOFT_MAX_MODEMS; x++) { | |||
1380 | if (globals.MODEM_POOL[x].state == MODEM_STATE_ONHOOK && (now - globals.MODEM_POOL[x].last_event) > idle_debounce) { | |||
1381 | modem = &globals.MODEM_POOL[x]; | |||
1382 | break; | |||
1383 | } | |||
1384 | } | |||
1385 | } | |||
1386 | ||||
1387 | if (modem && (modem->state != MODEM_STATE_ONHOOK || (now - modem->last_event) < idle_debounce)) { | |||
1388 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1388, ((void*)0), SWITCH_LOG_ERROR, "Modem %s In Use!\n", modem->devlink); | |||
1389 | modem = NULL((void*)0); | |||
1390 | } | |||
1391 | ||||
1392 | if (modem) { | |||
1393 | modem_set_state(modem, MODEM_STATE_ACQUIRED)_modem_set_state(modem, MODEM_STATE_ACQUIRED, "mod_spandsp_modem.c" , (const char *)__func__, 1393); | |||
1394 | modem->last_event = switch_time_now(); | |||
1395 | } else { | |||
1396 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1396, ((void*)0), SWITCH_LOG_ERROR, "No Modems Available!\n"); | |||
1397 | } | |||
1398 | ||||
1399 | switch_mutex_unlock(globals.mutex); | |||
1400 | ||||
1401 | return modem; | |||
1402 | } | |||
1403 | ||||
1404 | switch_status_t modem_global_init(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) | |||
1405 | { | |||
1406 | memset(&globals, 0, sizeof(globals)); | |||
1407 | globals.pool = pool; | |||
1408 | ||||
1409 | globals.SOFT_MAX_MODEMS = spandsp_globals.modem_count; | |||
1410 | ||||
1411 | switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED0x1, pool); | |||
1412 | ||||
1413 | modem_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE); | |||
1414 | modem_endpoint_interface->interface_name = "modem"; | |||
1415 | modem_endpoint_interface->io_routines = &channel_io_routines; | |||
1416 | modem_endpoint_interface->state_handler = &channel_event_handlers; | |||
1417 | ||||
1418 | activate_modems(); | |||
1419 | ||||
1420 | return SWITCH_STATUS_SUCCESS; | |||
1421 | } | |||
1422 | ||||
1423 | void modem_global_shutdown(void) | |||
1424 | { | |||
1425 | deactivate_modems(); | |||
1426 | } | |||
1427 | ||||
1428 | #else | |||
1429 | ||||
1430 | void modem_global_init(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) | |||
1431 | { | |||
1432 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1432, ((void*)0), SWITCH_LOG_INFO, "Modem support disabled\n"); | |||
1433 | } | |||
1434 | ||||
1435 | void modem_global_shutdown(void) | |||
1436 | { | |||
1437 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_spandsp_modem.c", (const char *)__func__ , 1437, ((void*)0), SWITCH_LOG_INFO, "Modem support disabled\n"); | |||
1438 | } | |||
1439 | ||||
1440 | #endif | |||
1441 | ||||
1442 | /* For Emacs: | |||
1443 | * Local Variables: | |||
1444 | * mode:c | |||
1445 | * indent-tabs-mode:nil | |||
1446 | * tab-width:4 | |||
1447 | * c-basic-offset:4 | |||
1448 | * End: | |||
1449 | * For VIM: | |||
1450 | * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: | |||
1451 | */ |