Bug Summary

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

Annotated Source Code

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
49static 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
58struct modem_state {
59 int state;
60 char *name;
61};
62
63static 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
77static modem_t *acquire_modem(int index);
78
79static 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
84static 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
127static 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
141static 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
152static 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
163char *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
172int 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
217switch_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) {
2
Taking false branch
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) {
3
Taking false branch
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) {
4
Taking false branch
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);
5
Value assigned to field 'stty'
280 if (modem->stty == NULL((void*)0)) {
6
Assuming pointer value is null
7
Taking true branch
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);
8
Null pointer passed as an argument to a 'nonnull' parameter
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
379end:
380 return status;
381}
382
383static switch_endpoint_interface_t *modem_endpoint_interface = NULL((void*)0);
384
385struct 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
400typedef struct private_object private_t;
401
402static switch_status_t channel_on_init(switch_core_session_t *session);
403static switch_status_t channel_on_hangup(switch_core_session_t *session);
404static switch_status_t channel_on_destroy(switch_core_session_t *session);
405static switch_status_t channel_on_routing(switch_core_session_t *session);
406static switch_status_t channel_on_exchange_media(switch_core_session_t *session);
407static switch_status_t channel_on_soft_execute(switch_core_session_t *session);
408static 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);
412static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
413static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
414static 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*/
422static 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
494static 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
508static 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
524static 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
547static 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
564static 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
590static 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
596static 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
612static 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
623static 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
631static 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
647static 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
657static 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
701static 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
722static 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
759static 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
808end:
809
810 return status;
811}
812
813static 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
824static 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
912static 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
927static 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
936static 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
1016static 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
1024static 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
1138typedef 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
1145static 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
1183static 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
1230static 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);
1
Calling 'modem_init'
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
1319static 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
1330static 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
1347static 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
1367static 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
1404switch_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
1423void modem_global_shutdown(void)
1424{
1425 deactivate_modems();
1426}
1427
1428#else
1429
1430void 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
1435void 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 */