1 //indent -gnu -ts4 -br -brs -cdw -lp -ce -nbfda -npcs -nprs -npsl -nbbo -saf -sai -saw -cs -bbo -nhnl -nut -sob -l90
2 #include "celliax.h"
3
4 /* GLOBAL VARIABLES */
5 char celliax_console_active_array[50] = "";
6 char *celliax_console_active = celliax_console_active_array;
7 /*! \brief Count of active channels for this module */
8 int celliax_usecnt = 0;
9 int celliax_debug = 0;
10 /*! \brief This is the thread for the monitor which checks for input on the channels
11 * which are not currently in use. */
12 pthread_t celliax_monitor_thread = AST_PTHREADT_NULL;
13 pthread_t celliax_monitor_audio_thread = AST_PTHREADT_NULL;
14 int celliax_dir_entry_extension = 0;
15
16 /* CONSTANTS */
17 /*! \brief Name of configuration file for this module */
18 const char celliax_config[] = "celliax.conf";
19
20 /*! \brief Textual description for this module */
21 const char celliax_desc[] = "Celliax, Audio-Serial Driver";
22 /*! \brief Textual type for this module */
23 const char celliax_type[] = "Celliax";
24
25 /*! \brief Definition of this channel for PBX channel registration */
26 const struct ast_channel_tech celliax_tech = {
27 .type = celliax_type,
28 .description = celliax_desc,
29 .capabilities = AST_FORMAT_SLINEAR,
30 .requester = celliax_request,
31 .hangup = celliax_hangup,
32 .answer = celliax_answer,
33 .read = celliax_read,
34 .call = celliax_call,
35 .write = celliax_write,
36 .indicate = celliax_indicate,
37 .fixup = celliax_fixup,
38 .devicestate = celliax_devicestate,
39 #ifdef ASTERISK_VERSION_1_4
40 .send_digit_begin = celliax_senddigit_begin,
41 .send_digit_end = celliax_senddigit_end,
42 #else /* ASTERISK_VERSION_1_4 */
43 .send_digit = celliax_senddigit,
44 #endif /* ASTERISK_VERSION_1_4 */
45 };
46
47 #ifdef ASTERISK_VERSION_1_4
48 #include "asterisk/abstract_jb.h"
49 /*! Global jitterbuffer configuration - by default, jb is disabled */
50 static struct ast_jb_conf default_jbconf = {
51 .flags = 0,
52 .max_size = -1,
53 .resync_threshold = -1,
54 .impl = ""
55 };
56 static struct ast_jb_conf global_jbconf;
57 #endif /* ASTERISK_VERSION_1_4 */
58
59
60 #ifdef CELLIAX_ALSA
61 char celliax_console_alsa_period_usage[] =
62 "Usage: celliax_alsa_period [alsa_period_size, in bytes] [alsa_periods_in_buffer, how many]\n"
63 " Shows or set the values of the period and the buffer used by the ALSA subsistem. Standard values are 160 for alsa_period_size and 4 for alsa_periods_in_buffer. Without specifying a value, it just shows the current values. The values are for the \"current\" console (Celliax) channel.\n"
64 " Enter 'help console' on how to change the \"current\" console\n";
65 #endif /* CELLIAX_ALSA */
66
67 char mandescr_celliax_sendsms[] =
68 "Description: Send an SMS through the designated Celliax interface.\n" "Variables: \n"
69 " Interface: <name> The Celliax interface name you want to use.\n"
70 " Number: <number> The recipient number you want to send the SMS to.\n"
71 " Text: <text> The text of the SMS to be sent.\n"
72 " ActionID: <id> The Action ID for this AMI transaction.\n";
73
74 char celliax_console_celliax_usage[] =
75 " \n" "chan_celliax commands info\n" " \n"
76 " chan_celliax adds to Asterisk the following CLI commands and DIALPLAN applications:\n"
77 " \n" " CLI COMMANDS:\n" " celliax_hangup\n"
78 " celliax_dial\n" " celliax_console\n"
79 #ifdef CELLIAX_DIR
80 " celliax_dir_import\n" " celliax_dir_export\n"
81 #endif /* CELLIAX_DIR */
82 " celliax_playback_boost\n" " celliax_capture_boost\n"
83 " celliax_sendsms\n" " celliax_echo\n" " celliax_at\n"
84 " \n" " DIALPLAN APPLICATIONS:\n" " CelliaxSendsms\n" " \n"
85 " You can type 'help [command]' or 'show application [application]' to obtain more specific info on usage.\n"
86 " \n";
87 char celliax_console_hangup_usage[] =
88 "Usage: celliax_hangup\n"
89 " Hangs up any call currently placed on the \"current\" celliax_console (Celliax) channel.\n"
90 " Enter 'help celliax_console' on how to change the \"current\" celliax_console\n";
91 char celliax_console_playback_boost_usage[] =
92 "Usage: celliax_playback_boost [value]\n"
93 " Shows or set the value of boost applied to the outgoing sound (voice). Possible values are: 0 (no boost applied), -40 to 40 (negative to positive range, in db). Without specifying a value, it just shows the current value. The value is for the \"current\" celliax_console (Celliax) channel.\n"
94 " Enter 'help celliax_console' on how to change the \"current\" celliax_console\n";
95 char celliax_console_capture_boost_usage[] =
96 "Usage: celliax_capture_boost [value]\n"
97 " Shows or set the value of boost applied to the incoming sound (voice). Possible values are: 0 (no boost applied), -40 to 40 (negative to positive range, in db). Without specifying a value, it just shows the current value. The value is for the \"current\" celliax_console (Celliax) channel.\n"
98 " Enter 'help celliax_console' on how to change the \"current\" celliax_console\n";
99
100 #ifdef CELLIAX_DIR
101 char celliax_console_celliax_dir_import_usage[] =
102 "Usage: celliax_dir_import [add | replace] fromcell\n"
103 " Write in the celliax_dir.conf config file all the entries found in the phonebook of the cellphone connected on the \"current\" celliax_console (Celliax) channel or in the 'Contacts' list of the Skype client.\n"
104 " Enter 'help celliax_console' on how to change the \"current\" celliax_console\n";
105 char celliax_console_celliax_dir_export_usage[] =
106 #ifdef CELLIAX_LIBCSV
107 "Usage: celliax_dir_export tocell|tocsv celliax_cellphonenumber [csv_filename]\n"
108 #else /* CELLIAX_LIBCSV */
109 "Usage: celliax_dir_export tocell celliax_cellphonenumber\n"
110 #endif /* CELLIAX_LIBCSV */
111 " With 'tocell' modifier, write in the cellphone connected on the \"current\" celliax_console (Celliax) all the entries found in directoriax.conf, in the form: [celliax_cellphonenumber]wait_for_answer celliax_dir_prefix celliax_dir_entry. So, you can choose the new entry from the cellphone phonebook, dial it, and be directly connected to celliax_dir extension chosen, without having to pass through the voice menu.\n"
112 #ifdef CELLIAX_LIBCSV
113 " With 'tocsv' modifier, write in a file (Comma Separated Values, suitable to be imported by various software (eg Outlook) and smartphones) all the entries found in directoriax.conf, in the form: [celliax_cellphonenumber]wait_for_answer celliax_dir_prefix celliax_dir_entry. So, you can choose the new entry from the imported phonebook, dial it, and be directly connected to celliax_dir extension chosen, without having to pass through the voice menu.\n"
114 #endif /* CELLIAX_LIBCSV */
115 " Enter 'help celliax_console' on how to change the \"current\" celliax_console\n";
116
117 #endif /* CELLIAX_DIR */
118
119 char celliax_console_dial_usage[] =
120 "Usage: celliax_dial [DTMFs]\n"
121 " Dials a given DTMF string in the call currently placed on the\n"
122 " \"current\" celliax_console (Celliax) channel.\n"
123 " Enter 'help celliax_console' on how to change the \"current\" celliax_console\n";
124 char celliax_console_sendsms_usage[] =
125 "Usage: celliax_sendsms interfacename/number_to_send_sms_to SMS_TEXT\n"
126 " This CLI command will use the specified Celliax interface to send an SMS with content SMS_TEXT to the number_to_send_sms_to\n"
127 " Eg:\n" " celliax_sendsms nicephone/3472665618 \"ciao bello\"\n";
128
129 char celliax_console_celliax_console_usage[] =
130 "Usage: celliax_console [interface] | show\n"
131 " If used without a parameter, displays which interface is the \"current\"\n"
132 " celliax_console. If a device is specified, the \"current\" celliax_console is changed to\n"
133 " the interface specified.\n"
134 " If the parameter is \"show\", the available interfaces are listed\n";
135 char *celliax_sendsmsapp = "CelliaxSendsms";
136
137 char *celliax_sendsmssynopsis = "CelliaxSendsms sends an SMS through the cellphone";
138 char *celliax_sendsmsdescrip =
139 " CelliaxSendsms(interface_name / number_to_send_sms_to , SMS_TEXT):\n"
140 " This application will use the specified Celliax interface to send an SMS with content SMS_TEXT to the number_to_send_sms_to\n"
141 " Eg:\n" " CelliaxSendsms(nicephone/3472665618,\"ciao bello\")\n" " or\n"
142 " CelliaxSendsms(nicephone/3472665618,${DATETIME}\"ciao bello\")\n" "\n";
143 char celliax_console_echo_usage[] =
144 "Usage: celliax_echo [0|1] [0|1]\n"
145 " Shows or set the values (0 meaning OFF and 1 meaning ON) of the echo suppression options: speexecho and speexpreprocess. Without specifying a value, it just shows the current values. The values are for the \"current\" celliax_console (Celliax) channel.\n"
146 " Enter 'help celliax_console' on how to change the \"current\" celliax_console\n";
147 char celliax_console_at_usage[] =
148 "Usage: celliax_at [command string]\n"
149 " Send the 'command string' to the 'AT modem' (cellphone) connected to the \"current\" celliax_console (Celliax) channel.\n"
150 " Enter 'help celliax_console' on how to change the \"current\" celliax_console\n";
151 /*! \brief fake celliax_pvt structure values,
152 * just for logging purposes */
153 struct celliax_pvt celliax_log_struct = {
154 .name = "none",
155 };
156
157 /*! \brief Default celliax_pvt structure values,
158 * used by celliax_mkif to initialize the interfaces */
159 struct celliax_pvt celliax_default = {
160 .readpos = AST_FRIENDLY_OFFSET, /* start here on reads */
161 .oss_write_dst = 0, /* start here on reads */
162 .interface_state = AST_STATE_DOWN,
163 .phone_callflow = CALLFLOW_CALL_IDLE,
164 .dsp_silence_threshold = 512,
165 .context = "default",
166 .language = "en",
167 .exten = "s",
168 .controldevice_name = "none",
169 .controldevfd = 0,
170 .next = NULL,
171 .owner = NULL,
172 .dsp = NULL,
173 .fbus2_outgoing_list = NULL,
174 .seqnumfbus = FBUS2_SEQNUM_MAX,
175 .controldev_thread = AST_PTHREADT_NULL,
176 .arraycounter = 0,
177 #ifndef GIOVA48
178 .celliax_sound_rate = 8000,
179 #else // GIOVA48
180 .celliax_sound_rate = 48000,
181 #endif // GIOVA48
182 .celliax_sound_capt_fd = -1,
183 .need_acoustic_ring = 0,
184 .celliax_serial_synced_timestamp = 0,
185 .celliax_serial_sync_period = 300,
186 .audio_play_reset_timestamp = 0,
187 .audio_capture_reset_timestamp = 0,
188 .controldevice_speed = B38400,
189 .capture_boost = 0,
190 .playback_boost = 0,
191 .stripmsd = 0,
192 .controldev_dead = 0,
193 .dtmf_inited = 0,
194 .at_dial_pre_number = "AT+CKPD=\"",
195 //.at_dial_post_number = "S\"",
196 .at_dial_post_number = ";",
197 .at_dial_expect = "OK",
198 .at_early_audio = 0,
199 .at_hangup = "AT+CKPD=\"E\"",
200 .at_hangup_expect = "OK",
201 .at_answer = "ATA",
202 .at_answer_expect = "OK",
203 .at_send_dtmf = "AT+CKPD",
204 .at_initial_pause = 0,
205 .at_preinit_1 = "",
206 .at_preinit_1_expect = "",
207 .at_preinit_2 = "",
208 .at_preinit_2_expect = "",
209 .at_preinit_3 = "",
210 .at_preinit_3_expect = "",
211 .at_preinit_4 = "",
212 .at_preinit_4_expect = "",
213 .at_preinit_5 = "",
214 .at_preinit_5_expect = "",
215 .at_after_preinit_pause = 0,
216 .at_postinit_1 = "",
217 .at_postinit_1_expect = "",
218 .at_postinit_2 = "",
219 .at_postinit_2_expect = "",
220 .at_postinit_3 = "",
221 .at_postinit_3_expect = "",
222 .at_postinit_4 = "",
223 .at_postinit_4_expect = "",
224 .at_postinit_5 = "",
225 .at_postinit_5_expect = "",
226 .at_query_battchg = "",
227 .at_query_battchg_expect = "",
228 .at_query_signal = "",
229 .at_query_signal_expect = "",
230 .at_call_idle = "",
231 .at_call_incoming = "",
232 .at_call_active = "",
233 .at_call_failed = "",
234 .at_call_calling = "",
235 .at_indicator_noservice_string = "CIEV: 2,0",
236 .at_indicator_nosignal_string = "CIEV: 5,0",
237 .at_indicator_lowsignal_string = "CIEV: 5,1",
238 .at_indicator_lowbattchg_string = "CIEV: 0,1",
239 .at_indicator_nobattchg_string = "CIEV: 0,0",
240 .at_indicator_callactive_string = "CIEV: 3,1",
241 .at_indicator_nocallactive_string = "CIEV: 3,0",
242 .at_indicator_nocallsetup_string = "CIEV: 6,0",
243 .at_indicator_callsetupincoming_string = "CIEV: 6,1",
244 .at_indicator_callsetupoutgoing_string = "CIEV: 6,2",
245 .at_indicator_callsetupremoteringing_string = "CIEV: 6,3",
246 .at_has_clcc = 0,
247 .at_has_ecam = 0,
248
249 .skype = 0,
250 .celliax_dir_entry_extension_prefix = 5,
251
252 #ifdef CELLIAX_CVM
253 .cvm_subsc_1_pin = "0000",
254 .cvm_subsc_2_pin = "0000",
255 .cvm_subsc_no = 1,
256 .cvm_lock_state = CVM_UNKNOWN_LOCK_STATE,
257 .cvm_register_state = CVM_UNKNOWN_REGISTER_STATE,
258 .cvm_busmail_outgoing_list = NULL,
259 .busmail_rxseq_cvm_last = 0xFF, /*!< \brief sequential number of BUSMAIL messages, (0-7) */
260 .busmail_txseq_celliax_last = 0xFF, /*!< \brief sequential number of BUSMAIL messages, (0-7) */
261 .cvm_volume_level = 5,
262 .cvm_celliax_serial_delay = 200, /* 200ms delay after sending down the wire, fix for a bug ? */
263 .cvm_handset_no = 0,
264 .cvm_fp_is_cvm = 0,
265 .cvm_rssi = 0,
266
267 #endif /* CELLIAX_CVM */
268 #ifdef CELLIAX_LIBCSV
269 .csv_separator_is_semicolon = 0, //FIXME as option
270 .csv_complete_name_pos = 4, //FIXME as option was 4 for outlook express and some outlook, other outlook 2
271 .csv_email_pos = 6, //FIXME as option for outlook express
272 .csv_home_phone_pos = 32, //FIXME as option was 12 for outlook express
273 .csv_mobile_phone_pos = 33, //FIXME as option was 14 for outlook express
274 .csv_business_phone_pos = 41, //FIXME as option was 22 for outlook express
275 .csv_first_row_is_title = 1, //FIXME as option
276 #endif /* CELLIAX_LIBCSV */
277
278 .audio_play_reset_period = 0, //do not reset
279
280 .isInputInterleaved = 1,
281 .isOutputInterleaved = 1,
282 .numInputChannels = 1,
283 .numOutputChannels = 1,
284 #ifndef GIOVA48
285 .framesPerCallback = 160,
286 #else // GIOVA48
287 .framesPerCallback = 960,
288 #endif // GIOVA48
289 .speexecho = 1,
290 .speexpreprocess = 1,
291 .portaudiocindex = -1,
292 .portaudiopindex = -1,
293 #ifdef CELLIAX_ALSA
294 .alsa_period_size = 160,
295 .alsa_periods_in_buffer = 4,
296 .alsac = NULL,
297 .alsap = NULL,
298 .alsawrite_filled = 0,
299 #endif /* CELLIAX_ALSA */
300
301 };
302
303 /*!
304 * \brief PVT structure for a celliax interface (channel), created by celliax_mkif
305 */
306 struct celliax_pvt *celliax_iflist = NULL;
307
308 #ifdef ASTERISK_VERSION_1_6_0
309 struct ast_cli_entry myclis[] = {
310 AST_CLI_DEFINE(celliax_console_hangup, "Hangup a call on the console"),
311 //AST_CLI_DEFINE(celliax_console_dial, "Dial an extension on the console"),
312 //AST_CLI_DEFINE(celliax_console_playback_boost, "Sets/displays spk boost in dB"),
313 //AST_CLI_DEFINE(celliax_console_capture_boost, "Sets/displays mic boost in dB"),
314 //AST_CLI_DEFINE(celliax_console_set_active, "Sets/displays active console"),
315 //AST_CLI_DEFINE(celliax_console_at, "Sends an AT command"),
316 //AST_CLI_DEFINE(celliax_console_echo, "Echo suppression"),
317 #ifdef CELLIAX_DIR
318 //AST_CLI_DEFINE(celliax_console_celliax_dir_import, "imports entries from cellphone"),
319 //AST_CLI_DEFINE(celliax_console_celliax_dir_export, "exports entries to cellphone"),
320 #endif /* CELLIAX_DIR */
321 //AST_CLI_DEFINE(celliax_console_celliax, "all things celliax"),
322 //AST_CLI_DEFINE(celliax_console_sendsms, "Send an SMS from a Celliax interface"),
323 };
324 #else
325 struct ast_cli_entry myclis[] = {
326 {{"celliax_hangup", NULL}, celliax_console_hangup,
327 "Hangup a call on the celliax_console",
328 celliax_console_hangup_usage},
329 {{"celliax_playback_boost", NULL}, celliax_console_playback_boost, "playback boost",
330 celliax_console_playback_boost_usage},
331 {{"celliax_capture_boost", NULL}, celliax_console_capture_boost, "capture boost",
332 celliax_console_capture_boost_usage},
333 {{"celliax_usage", NULL}, celliax_console_celliax, "chan_celliax commands info",
334 celliax_console_celliax_usage},
335
336 {{"celliax_at", NULL}, celliax_console_at, "AT command",
337 celliax_console_at_usage},
338 {{"celliax_echo", NULL}, celliax_console_echo, "echo suppression",
339 celliax_console_echo_usage},
340 #ifdef CELLIAX_DIR
341 {{"celliax_dir_import", NULL}, celliax_console_celliax_dir_import,
342 "Write the celliax_dir.conf file, used by celliax_dir app",
343 celliax_console_celliax_dir_import_usage},
344 {{"celliax_dir_export", NULL}, celliax_console_celliax_dir_export,
345 "Write in the cellphone the contents of the celliax_dir.conf file, used by celliax_dir app",
346 celliax_console_celliax_dir_export_usage},
347 #endif /* CELLIAX_DIR */
348 #ifdef CELLIAX_ALSA
349 {{"celliax_alsa_period", NULL}, console_alsa_period, "alsa_period",
350 celliax_console_alsa_period_usage},
351 #endif /* CELLIAX_ALSA */
352
353 {{"celliax_dial", NULL}, celliax_console_dial,
354 "Dial an extension on the celliax_console",
355 celliax_console_dial_usage},
356 {{"celliax_sendsms", NULL}, celliax_console_sendsms,
357 "Send an SMS from a Celliax interface",
358 celliax_console_sendsms_usage},
359 {{"celliax_console", NULL}, celliax_console_set_active,
360 "Sets/displays active celliax_console",
361 celliax_console_celliax_console_usage},
362 };
363 #endif /* ASTERISK_VERSION_1_6_0 */
364
365 /* IMPLEMENTATION */
366
367 #ifdef CELLIAX_ALSA
console_alsa_period(int fd,int argc,char * argv[])368 int console_alsa_period(int fd, int argc, char *argv[])
369 {
370 struct celliax_pvt *p = celliax_console_find_desc(celliax_console_active);
371
372 if (argc > 3 || argc == 2)
373 return RESULT_SHOWUSAGE;
374 if (!p) {
375 ast_cli(fd,
376 "No \"current\" console for alsa_period_size, please enter 'help console'\n");
377 return RESULT_SUCCESS;
378 }
379
380 if (argc == 1) {
381 ast_cli(fd,
382 "On the active console, that is [%s], alsa_period_size and alsa_periods_in_buffer are: %d and %d\n",
383 celliax_console_active, p->alsa_period_size, p->alsa_periods_in_buffer);
384 } else if (argc == 3) {
385
386 if (p->owner) {
387 ast_cli(fd,
388 "CANNOT SET alsa_period_size and alsa_periods_in_buffer on the active console, that is [%s], because there is a call ongoing\n",
389 celliax_console_active);
390 return RESULT_SUCCESS;
391 }
392 sscanf(argv[1], "%d", &p->alsa_period_size);
393 sscanf(argv[2], "%d", &p->alsa_periods_in_buffer);
394 ast_cli(fd,
395 "alsa_period_size and alsa_periods_in_buffer on the active console, that is [%s], are now: %d and %d\n",
396 celliax_console_active, p->alsa_period_size, p->alsa_periods_in_buffer);
397
398 if (celliax_monitor_audio_thread
399 && (celliax_monitor_audio_thread != AST_PTHREADT_NULL)
400 && (celliax_monitor_audio_thread != AST_PTHREADT_STOP)) {
401
402 if (pthread_cancel(celliax_monitor_audio_thread)) {
403 ERRORA("pthread_cancel celliax_monitor_audio_thread failed, BAD\n",
404 CELLIAX_P_LOG);
405 }
406 if (pthread_kill(celliax_monitor_audio_thread, SIGURG)) {
407 DEBUGA_PBX("pthread_kill celliax_monitor_audio_thread failed, no problem\n", CELLIAX_P_LOG); //maybe it just died
408 }
409
410 if (pthread_join(celliax_monitor_audio_thread, NULL)) {
411 ERRORA("pthread_join failed, BAD\n", CELLIAX_P_LOG);
412 }
413 }
414
415 alsa_shutdown(p);
416 //sleep(5);
417 alsa_init(p);
418
419 if (ast_pthread_create
420 (&celliax_monitor_audio_thread, NULL, celliax_do_audio_monitor, NULL) < 0) {
421 ERRORA("Unable to start audio_monitor thread.\n", CELLIAX_P_LOG);
422 return -1;
423 }
424
425 ast_cli(fd,
426 "ACTIVATED alsa_period_size and alsa_periods_in_buffer on the active console\n");
427 }
428
429 return RESULT_SUCCESS;
430 }
431 #endif /* CELLIAX_ALSA */
432
celliax_unlocka_log(void * x)433 void celliax_unlocka_log(void *x)
434 {
435 ast_mutex_t *y;
436 y = x;
437 int i;
438
439 for (i = 0; i < 5; i++) { //let's be generous
440
441 ast_log(LOG_DEBUG,
442 CELLIAX_SVN_VERSION
443 "[%-7lx] I'm a dying thread, and I'm to go unlocking mutex %p for the %dth time\n",
444 (unsigned long int) pthread_self(), y, i);
445
446 ast_mutex_unlock(y);
447 }
448 ast_log(LOG_DEBUG,
449 CELLIAX_SVN_VERSION
450 "[%-7lx] I'm a dying thread, I've finished unlocking mutex %p\n",
451 (unsigned long int) pthread_self(), y);
452 }
453
celliax_queue_control(struct ast_channel * c,int control)454 int celliax_queue_control(struct ast_channel *c, int control)
455 {
456 struct celliax_pvt *p = c->tech_pvt;
457 int times;
458
459 /* queue the frame */
460 if (p)
461 p->control_to_send = control;
462 else
463 return 0;
464 DEBUGA_PBX("Queued CONTROL FRAME %d\n", CELLIAX_P_LOG, control);
465
466 /* wait for the frame to be sent */
467 while (p->control_to_send){
468 usleep(1000);
469 times++;
470 if(times == 1000){
471 ERRORA("Queued CONTROL FRAME %d FAILED to be sent\n", CELLIAX_P_LOG, control);
472 p->control_to_send = 0;
473 break;
474 }
475 }
476
477 return 0;
478 }
479
celliax_devicestate(void * data)480 int celliax_devicestate(void *data)
481 {
482 struct celliax_pvt *p = NULL;
483 char *name = data;
484 int res = AST_DEVICE_INVALID;
485
486 if (!data) {
487 ERRORA("Devicestate requested with no data\n", CELLIAX_P_LOG);
488 return res;
489 }
490
491 /* lock the interfaces' list */
492 LOKKA(&celliax_iflock);
493 /* make a pointer to the first interface in the interfaces list */
494 p = celliax_iflist;
495 /* Search for the requested interface and verify if is unowned */
496 while (p) {
497 size_t length = strlen(p->name);
498 /* is this the requested interface? */
499 if (strncmp(name, p->name, length) == 0) {
500 /* is this interface unowned? */
501 if (!p->owner) {
502 res = AST_DEVICE_NOT_INUSE;
503 DEBUGA_PBX("Interface is NOT OWNED by a channel\n", CELLIAX_P_LOG);
504 } else {
505 /* interface owned by a channel */
506 res = AST_DEVICE_INUSE;
507 DEBUGA_PBX("Interface is OWNED by a channel\n", CELLIAX_P_LOG);
508 }
509
510 /* we found the requested interface, bail out from the while loop */
511 break;
512 }
513 /* not yet found, next please */
514 p = p->next;
515 }
516 /* unlock the interfaces' list */
517 UNLOCKA(&celliax_iflock);
518
519 if (res == AST_DEVICE_INVALID) {
520 ERRORA("Checking device state for interface [%s] returning AST_DEVICE_INVALID\n",
521 CELLIAX_P_LOG, name);
522 }
523 return res;
524 }
525
526 #ifndef ASTERISK_VERSION_1_4
celliax_indicate(struct ast_channel * c,int cond)527 int celliax_indicate(struct ast_channel *c, int cond)
528 #else
529 int celliax_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen)
530 #endif
531 {
532 struct celliax_pvt *p = c->tech_pvt;
533 int res = 0;
534
535 switch (cond) {
536 case AST_CONTROL_BUSY:
537 case AST_CONTROL_CONGESTION:
538 case AST_CONTROL_RINGING:
539 case -1:
540 NOTICA("Let's INDICATE %d\n", CELLIAX_P_LOG, cond);
541 res = -1; /* Ask for inband indications */
542 break;
543 case AST_CONTROL_PROGRESS:
544 case AST_CONTROL_PROCEEDING:
545 case AST_CONTROL_VIDUPDATE:
546 case AST_CONTROL_HOLD:
547 case AST_CONTROL_UNHOLD:
548 #ifdef ASTERISK_VERSION_1_4
549 //FIXME case AST_CONTROL_SRCUPDATE:
550 #endif /* ASTERISK_VERSION_1_4 */
551 NOTICA("Let's NOT INDICATE %d\n", CELLIAX_P_LOG, cond);
552 break;
553 default:
554 WARNINGA("Don't know how to display condition %d on %s\n", CELLIAX_P_LOG, cond,
555 c->name);
556 /* The core will play inband indications for us if appropriate */
557 res = -1;
558 }
559
560 return res;
561 }
562
563 /*! \brief PBX interface function -build celliax pvt structure
564 * celliax calls initiated by the PBX arrive here */
celliax_request(const char * type,int format,void * data,int * cause)565 struct ast_channel *celliax_request(const char *type, int format, void *data, int *cause)
566 {
567 struct celliax_pvt *p = NULL;
568 struct ast_channel *tmp = NULL;
569 char *name = data;
570
571 if (option_debug) {
572 DEBUGA_PBX("ENTERING FUNC\n", CELLIAX_P_LOG);
573 }
574
575 DEBUGA_PBX("Try to request type: %s, name: %s, cause: %d," " format: %d\n",
576 CELLIAX_P_LOG, type, name, *cause, format);
577
578 if (!data) {
579 ERRORA("Channel requested with no data\n", CELLIAX_P_LOG);
580 if (option_debug) {
581 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
582 }
583 return NULL;
584 }
585
586 /* lock the interfaces' list */
587 LOKKA(&celliax_iflock);
588 /* make a pointer to the first interface in the interfaces list */
589 p = celliax_iflist;
590 /* Search for the requested interface and verify if is unowned and format compatible */
591 //TODO implement groups a la chan_zap
592 while (p) {
593 size_t length = strlen(p->name);
594 /* is this the requested interface? */
595 if (strncmp(name, p->name, length) == 0) {
596 /* is the requested format supported by this interface? */
597 if ((format & AST_FORMAT_SLINEAR) != 0) {
598 /* is this interface unowned? */
599 if (!p->owner) {
600 DEBUGA_PBX("Requesting: %s, name: %s, format: %d\n", CELLIAX_P_LOG, type, name,
601 format);
602 /* create a new channel owning this interface */
603 tmp = celliax_new(p, AST_STATE_DOWN, p->context);
604 if (!tmp) {
605 /* the channel was not created, probable memory allocation error */
606 *cause = AST_CAUSE_SWITCH_CONGESTION;
607 }
608 } else {
609 /* interface owned by another channel */
610 WARNINGA("owned by another channel\n", CELLIAX_P_LOG);
611 *cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
612 }
613 } else {
614 /* requested format not supported */
615 WARNINGA("format %d not supported\n", CELLIAX_P_LOG, format);
616 *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
617 }
618 /* we found the requested interface, bail out from the while loop */
619 break;
620 }
621 /* not yet found, next please */
622 p = p->next;
623 }
624 /* unlock the interfaces' list */
625 UNLOCKA(&celliax_iflock);
626 /* restart the monitor so it will watch only the remaining unowned interfaces */
627 celliax_restart_monitor();
628 if (tmp == NULL) {
629 /* new channel was not created */
630 WARNINGA("Unable to create new Celliax channel %s\n", CELLIAX_P_LOG, name);
631 }
632 if (option_debug) {
633 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
634 }
635 /* return the newly created channel */
636 return tmp;
637 }
638
639 /*! \brief Hangup celliax call
640 * Part of PBX interface, called from ast_hangup */
641
celliax_hangup(struct ast_channel * c)642 int celliax_hangup(struct ast_channel *c)
643 {
644 struct celliax_pvt *p;
645 int res;
646
647 /* get our celliax pvt interface from channel */
648 p = c->tech_pvt;
649 /* if there is not celliax pvt why we are here ? */
650 if (!p) {
651 ERRORA("Asked to hangup channel not connected\n", CELLIAX_P_LOG);
652 return 0;
653 }
654
655 if (option_debug) {
656 DEBUGA_PBX("ENTERING FUNC\n", CELLIAX_P_LOG);
657 }
658
659 p->phone_callflow = CALLFLOW_CALL_HANGUP_REQUESTED;
660 /* shutdown the serial monitoring thread */
661 if (p->controldev_thread && (p->controldev_thread != AST_PTHREADT_NULL)
662 && (p->controldev_thread != AST_PTHREADT_STOP)) {
663 if (pthread_cancel(p->controldev_thread)) {
664 ERRORA("controldev_thread pthread_cancel failed, maybe he killed himself?\n",
665 CELLIAX_P_LOG);
666 }
667 /* push it, maybe is stuck in a select or so */
668 if (pthread_kill(p->controldev_thread, SIGURG)) {
669 DEBUGA_SERIAL("controldev_thread pthread_kill failed, no problem\n", CELLIAX_P_LOG);
670 }
671 #ifndef __CYGWIN__ /* under cygwin, this seems to be not reliable, get stuck at times */
672 /* wait for it to die */
673 if (pthread_join(p->controldev_thread, NULL)) {
674 ERRORA("controldev_thread pthread_join failed, BAD\n", CELLIAX_P_LOG);
675 }
676 #else /* __CYGWIN__ */
677 /* allow the serial thread to die */
678 usleep(300000); //300msecs
679 #endif /* __CYGWIN__ */
680 }
681 p->controldev_thread = AST_PTHREADT_NULL;
682
683 if (p->controldevprotocol != PROTOCOL_NO_SERIAL) {
684 if (p->interface_state != AST_STATE_DOWN) {
685 /* actually hangup through the serial port */
686 if (p->controldevprotocol != PROTOCOL_NO_SERIAL) {
687 res = celliax_serial_hangup(p);
688 if (res) {
689 ERRORA("celliax_serial_hangup error: %d\n", CELLIAX_P_LOG, res);
690 if (option_debug) {
691 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
692 }
693 return -1;
694 }
695 }
696
697 while (p->interface_state != AST_STATE_DOWN) {
698 usleep(10000); //10msec
699 }
700 if (p->interface_state != AST_STATE_DOWN) {
701 ERRORA("call hangup failed\n", CELLIAX_P_LOG);
702 return -1;
703 } else {
704 DEBUGA_SERIAL("call hungup\n", CELLIAX_P_LOG);
705 }
706 }
707 } else {
708 p->interface_state = AST_STATE_DOWN;
709 p->phone_callflow = CALLFLOW_CALL_IDLE;
710 }
711 /* if there is a dsp struct alloced, free it */
712 if (p->dsp) {
713 ast_dsp_free(p->dsp);
714 p->dsp = NULL;
715 }
716 #ifndef __CYGWIN__
717 #ifdef CELLIAX_ALSA
718 /* restart alsa */
719 snd_pcm_drop(p->alsap);
720 snd_pcm_prepare(p->alsap);
721
722 snd_pcm_prepare(p->alsac);
723 snd_pcm_start(p->alsac);
724
725 /* shutdown the sound system, close sound fds, and if exist shutdown the sound managing threads */
726 DEBUGA_SOUND("shutting down sound\n", CELLIAX_P_LOG);
727 res = celliax_sound_shutdown(p);
728 if (res == -1) {
729 ERRORA("Failed to shutdown sound\n", CELLIAX_P_LOG);
730 }
731
732
733 #endif /* CELLIAX_ALSA */
734
735 #endif /* __CYGWIN__ */
736 #ifdef CELLIAX_PORTAUDIO
737 speex_echo_state_reset(p->stream->echo_state);
738 #endif // CELLIAX_PORTAUDIO
739
740 /* re-init the serial port, be paranoid */
741 if (p->controldevprotocol != PROTOCOL_NO_SERIAL) {
742 p->controldevfd = celliax_serial_init(p, p->controldevice_speed);
743 if (p->controldevfd < 1) {
744 ERRORA("bad, bad, bad\n", CELLIAX_P_LOG);
745 if (option_debug) {
746 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
747 }
748 return -1;
749 }
750 }
751 #ifndef ASTERISK_VERSION_1_4
752 /* subtract one to the usage count of Celliax-type channels */
753 LOKKA(&celliax_usecnt_lock);
754 celliax_usecnt--;
755 if (celliax_usecnt < 0)
756 ERRORA("Usecnt < 0???\n", CELLIAX_P_LOG);
757 UNLOCKA(&celliax_usecnt_lock);
758 ast_update_use_count();
759 #else /* ASTERISK_VERSION_1_4 */
760 ast_module_unref(ast_module_info->self);
761 #endif /* ASTERISK_VERSION_1_4 */
762
763 /* our celliax pvt interface is no more part of a channel */
764 p->owner = NULL;
765 /* our channel has no more this celliax pvt interface to manage */
766 c->tech_pvt = NULL;
767 /* set the channel state to DOWN, eg. available, not in active use */
768 if (ast_setstate(c, AST_STATE_DOWN)) {
769 ERRORA("ast_setstate failed, BAD\n", CELLIAX_P_LOG);
770 if (option_debug) {
771 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
772 }
773 return -1;
774 }
775
776 if (option_debug)
777 DEBUGA_PBX("Hanged Up\n", CELLIAX_P_LOG);
778 /* restart the monitor thread, so it can recheck which interfaces it have to watch during its loop (the interfaces that are not owned by channels) */
779 if (celliax_restart_monitor()) {
780 ERRORA("celliax_restart_monitor failed, BAD\n", CELLIAX_P_LOG);
781 if (option_debug) {
782 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
783 }
784 return -1;
785 }
786
787 if (option_debug) {
788 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
789 }
790 return 0;
791 }
792
793 /*! \brief Answer incoming call,
794 * Part of PBX interface */
celliax_answer(struct ast_channel * c)795 int celliax_answer(struct ast_channel *c)
796 {
797 struct celliax_pvt *p = c->tech_pvt;
798 int res;
799
800 if (option_debug) {
801 DEBUGA_PBX("ENTERING FUNC\n", CELLIAX_P_LOG);
802 }
803 /* do something to actually answer the call, if needed (eg. pick up the phone) */
804 if (p->controldevprotocol != PROTOCOL_NO_SERIAL) {
805 if (celliax_serial_answer(p)) {
806 ERRORA("celliax_answer FAILED\n", CELLIAX_P_LOG);
807 if (option_debug) {
808 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
809 }
810 return -1;
811 }
812 }
813 p->interface_state = AST_STATE_UP;
814 p->phone_callflow = CALLFLOW_CALL_ACTIVE;
815
816 while (p->interface_state == AST_STATE_RING) {
817 usleep(10000); //10msec
818 }
819 if (p->interface_state != AST_STATE_UP) {
820 ERRORA("call answering failed\n", CELLIAX_P_LOG);
821 res = -1;
822 } else {
823 if (option_debug)
824 DEBUGA_PBX("call answered\n", CELLIAX_P_LOG);
825 res = 0;
826 #ifdef CELLIAX_PORTAUDIO
827 speex_echo_state_reset(p->stream->echo_state);
828 #endif // CELLIAX_PORTAUDIO
829
830 if (p->owner) {
831 DEBUGA_PBX("going to send AST_STATE_UP\n", CELLIAX_P_LOG);
832 ast_setstate(p->owner, AST_STATE_UP);
833 //ast_queue_control(p->owner, AST_CONTROL_ANSWER);
834 //celliax_queue_control(p->owner, AST_CONTROL_ANSWER);
835 DEBUGA_PBX("just sent AST_STATE_UP\n", CELLIAX_P_LOG);
836 }
837 }
838 if (option_debug) {
839 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
840 }
841 return res;
842 }
843
844 #ifdef ASTERISK_VERSION_1_4
celliax_senddigit_begin(struct ast_channel * c,char digit)845 int celliax_senddigit_begin(struct ast_channel *c, char digit)
846 {
847 struct celliax_pvt *p = c->tech_pvt;
848
849 DEBUGA_PBX("DIGIT BEGIN received: %c\n", CELLIAX_P_LOG, digit);
850
851 return 0;
852 }
853
celliax_senddigit_end(struct ast_channel * c,char digit,unsigned int duration)854 int celliax_senddigit_end(struct ast_channel *c, char digit, unsigned int duration)
855 {
856 struct celliax_pvt *p = c->tech_pvt;
857
858 NOTICA("DIGIT END received: %c %d\n", CELLIAX_P_LOG, digit, duration);
859
860 if (p->controldevprotocol == PROTOCOL_AT && p->at_send_dtmf[0]) {
861 int res = 0;
862 char at_command[256];
863
864 memset(at_command, '\0', 256);
865 sprintf(at_command, "%s=\"%c\"", p->at_send_dtmf, digit);
866 res = celliax_serial_write_AT_ack(p, at_command);
867 if (res) {
868 ERRORA("senddigit command failed, command used: '%s=\"%c\"', giving up\n",
869 CELLIAX_P_LOG, p->at_send_dtmf, digit);
870 }
871 }
872 return 0;
873 }
874 #else /* ASTERISK_VERSION_1_4 */
celliax_senddigit(struct ast_channel * c,char digit)875 int celliax_senddigit(struct ast_channel *c, char digit)
876 {
877 struct celliax_pvt *p = c->tech_pvt;
878
879 NOTICA("DIGIT received: %c\n", CELLIAX_P_LOG, digit);
880
881 if (p->controldevprotocol == PROTOCOL_AT && p->at_send_dtmf[0]) {
882 int res = 0;
883 char at_command[256];
884
885 memset(at_command, '\0', 256);
886 sprintf(at_command, "%s=\"%c\"", p->at_send_dtmf, digit);
887 res = celliax_serial_write_AT_ack(p, at_command);
888 if (res) {
889 ERRORA("senddigit command failed, command used: '%s=\"%c\"', giving up\n",
890 CELLIAX_P_LOG, p->at_send_dtmf, digit);
891 }
892 }
893 return 0;
894 }
895
896 #endif /* ASTERISK_VERSION_1_4 */
897
898 /*! \brief Read audio frames from channel */
celliax_read(struct ast_channel * c)899 struct ast_frame *celliax_read(struct ast_channel *c)
900 {
901 struct ast_frame *f;
902 struct celliax_pvt *p = c->tech_pvt;
903 int actual;
904 char buf[128 + 1];
905
906 if (p->dtmf_inited == 0) {
907 dtmf_rx_init(&p->dtmf_state, NULL, NULL);
908 p->dtmf_inited = 1;
909 dtmf_rx_parms(&p->dtmf_state, 0, 10, 10);
910 p->dtmf_timestamp.tv_sec=0;
911 p->dtmf_timestamp.tv_usec=0;
912 DEBUGA_SOUND("DTMF recognition inited\n", CELLIAX_P_LOG);
913 }
914
915 /* if there are control frames queued to be sent by celliax_queue_control, send it the first */
916 //FIXME maybe better a real queue?
917 if (p && p->owner && p->control_to_send) {
918 ast_queue_control(p->owner, p->control_to_send);
919 DEBUGA_PBX("Sent CONTROL FRAME %d\n", CELLIAX_P_LOG, p->control_to_send);
920 p->control_to_send = 0;
921 }
922
923 #ifdef CELLIAX_PORTAUDIO
924 /* if the call is not active (ie: answered), do not send audio frames, they would pile up in a lag queue */
925 if (!p->owner || p->owner->_state != AST_STATE_UP)
926 #else /* CELLIAX_PORTAUDIO */
927 if (!p->owner )
928 #endif /* CELLIAX_PORTAUDIO */
929 {
930 static struct ast_frame f;
931 #ifdef CELLIAX_PORTAUDIO
932 char c;
933 #endif /* CELLIAX_PORTAUDIO */
934
935 f.frametype = AST_FRAME_NULL;
936 f.subclass = 0;
937 f.samples = 0;
938 f.datalen = 0;
939 #ifdef ASTERISK_VERSION_1_6_0_1
940 f.data.ptr = NULL;
941 #else
942 f.data = NULL;
943 #endif /* ASTERISK_VERSION_1_6_0_1 */
944 f.offset = 0;
945 f.src = celliax_type;
946 f.mallocd = 0;
947 f.delivery.tv_sec = 0;
948 f.delivery.tv_usec = 0;
949 /* read the char that was written by the audio thread in this pipe, this pipe is the fd monitored by asterisk, asterisk then has called the function we are inside) */
950 #ifdef CELLIAX_PORTAUDIO
951 read(p->audiopipe[0], &c, 1);
952 #endif /* CELLIAX_PORTAUDIO */
953
954 return &f;
955 }
956
957 /* read one asterisk frame of audio from sound interface */
958 f = celliax_sound_read(p);
959 if (f) {
960 struct timeval now_timestamp;
961 #ifndef __CYGWIN__
962 #ifdef CELLIAX_PORTAUDIO
963 char c[1000];
964 int letti = 2;
965
966 while (letti > 1) {
967 letti = read(p->audiopipe[0], &c, 1000);
968 if (letti > 0)
969 DEBUGA_SOUND("READ from audiopipe: %d\n", CELLIAX_P_LOG, letti);
970 //usleep(1);
971 }
972 //if(letti == -1)
973 //ERRORA("error: %s\n", CELLIAX_P_LOG, strerror(errno));
974 #endif /* CELLIAX_PORTAUDIO */
975 #endif /* __CYGWIN__ */
976
977 /* scale sound samples volume up or down */
978 celliax_sound_boost(f, p->capture_boost);
979
980 gettimeofday(&now_timestamp, NULL);
981
982 if( (((now_timestamp.tv_sec - p->dtmf_timestamp.tv_sec) * 1000000) < 0) || ( ((now_timestamp.tv_sec - p->dtmf_timestamp.tv_sec) * 1000000) + (now_timestamp.tv_usec - p->dtmf_timestamp.tv_usec) ) > 300000) { // if more than 0.3 seconds from last DTMF, or never got DTMFs before
983
984 #ifdef ASTERISK_VERSION_1_6_0_1
985 dtmf_rx(&p->dtmf_state, f->data.ptr, f->samples);
986 #else
987 dtmf_rx(&p->dtmf_state, f->data, f->samples);
988 #endif /* ASTERISK_VERSION_1_6_0_1 */
989 actual = dtmf_rx_get(&p->dtmf_state, buf, 128);
990 if (actual) {
991 //if (option_debug)
992 NOTICA("delta_usec=%ld, inband audio DTMF: %s\n", CELLIAX_P_LOG, ( (now_timestamp.tv_sec - p->dtmf_timestamp.tv_sec) * 1000000) + (now_timestamp.tv_usec - p->dtmf_timestamp.tv_usec), buf);
993 struct ast_frame f2 = { AST_FRAME_DTMF, buf[0], };
994 ast_queue_frame(p->owner, &f2);
995 gettimeofday(&p->dtmf_timestamp, NULL);
996 }
997 }
998 return f;
999 }
1000 return NULL;
1001 }
1002
1003 /*! \brief Initiate celliax call from PBX
1004 * used from the dial() application
1005 */
celliax_call(struct ast_channel * c,char * idest,int timeout)1006 int celliax_call(struct ast_channel *c, char *idest, int timeout)
1007 {
1008 struct celliax_pvt *p = NULL;
1009 p = c->tech_pvt;
1010 char rdest[80], *where, dstr[100] = "";
1011 char *stringp = NULL;
1012 int status;
1013
1014 if (option_debug) {
1015 DEBUGA_PBX("ENTERING FUNC\n", CELLIAX_P_LOG);
1016 }
1017 if ((c->_state != AST_STATE_DOWN)
1018 && (c->_state != AST_STATE_RESERVED)) {
1019 ERRORA("celliax_call called on %s, neither down nor reserved\n", CELLIAX_P_LOG,
1020 c->name);
1021 if (option_debug) {
1022 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1023 }
1024 return -1;
1025 }
1026
1027 if (option_debug > 1)
1028 DEBUGA_PBX("celliax_call to call idest: %s, timeout: %d!\n", CELLIAX_P_LOG, idest,
1029 timeout);
1030
1031 strncpy(rdest, idest, sizeof(rdest) - 1);
1032 // try '/' as separator
1033 stringp = rdest;
1034 strsep(&stringp, "/");
1035 where = strsep(&stringp, "/");
1036
1037 if (!where) {
1038 ERRORA
1039 ("Destination %s is not recognized. Chan_celliax requires a standard destination with slashes (Celliax/device/destination, eg: 'Celliax/nicephone/3472665618')\n",
1040 CELLIAX_P_LOG, idest);
1041 if (option_debug) {
1042 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1043 }
1044 return -1;
1045 }
1046
1047 strncpy(dstr, where + p->stripmsd, sizeof(dstr) - 1);
1048 if (option_debug > 1)
1049 DEBUGA_PBX("celliax_call dialing idest: %s, timeout: %d, dstr: %s!\n", CELLIAX_P_LOG,
1050 idest, timeout, dstr);
1051
1052 if (p->controldev_dead) {
1053 WARNINGA("celliax_call: device is dead, cannot call!\n", CELLIAX_P_LOG);
1054 status = -1;
1055 } else {
1056 ast_setstate(c, AST_STATE_DIALING);
1057 status = celliax_serial_call(p, dstr);
1058 }
1059
1060 if (status) {
1061 WARNINGA("celliax_call dialing failed: %d!\n", CELLIAX_P_LOG, status);
1062 if (option_debug) {
1063 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1064 }
1065 return -1;
1066 } else {
1067 if (option_debug)
1068 DEBUGA_PBX("call ongoing\n", CELLIAX_P_LOG);
1069 ast_queue_control(p->owner, AST_CONTROL_RINGING);
1070 }
1071
1072 if (option_debug > 1)
1073 DEBUGA_PBX("celliax_call dialed idest: %s, timeout: %d, dstr: %s!\n", CELLIAX_P_LOG,
1074 idest, timeout, dstr);
1075
1076 if (option_debug) {
1077 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1078 }
1079 #ifdef CELLIAX_PORTAUDIO
1080 speex_echo_state_reset(p->stream->echo_state);
1081 #endif // CELLIAX_PORTAUDIO
1082 return 0;
1083 }
1084
1085 /*! \brief Send audio frame to channel */
celliax_write(struct ast_channel * c,struct ast_frame * f)1086 int celliax_write(struct ast_channel *c, struct ast_frame *f)
1087 {
1088 struct celliax_pvt *p = c->tech_pvt;
1089 if (p->owner && p->owner->_state != AST_STATE_UP) {
1090 return 0;
1091 }
1092
1093 celliax_sound_boost(f, p->playback_boost);
1094
1095 return celliax_sound_write(p, f);
1096 }
1097
1098 /*! \brief Fix up a channel: If a channel is consumed, this is called.
1099 * Basically update any ->owner links */
celliax_fixup(struct ast_channel * oldchan,struct ast_channel * newchan)1100 int celliax_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1101 {
1102 struct celliax_pvt *p = newchan->tech_pvt;
1103
1104 if (!p) {
1105 ERRORA("No pvt after masquerade. Strange things may happen\n", CELLIAX_P_LOG);
1106 return -1;
1107 }
1108
1109 if (p->owner != oldchan) {
1110 ERRORA("old channel wasn't %p but was %p\n", CELLIAX_P_LOG, oldchan, p->owner);
1111 return -1;
1112 }
1113
1114 p->owner = newchan;
1115 return 0;
1116 }
1117
celliax_sound_boost(struct ast_frame * f,double boost)1118 int celliax_sound_boost(struct ast_frame *f, double boost)
1119 {
1120 /* LUIGI RIZZO's magic */
1121 if (boost != 0) { /* scale and clip values */
1122 int i, x;
1123
1124 #ifdef ASTERISK_VERSION_1_6_0_1
1125 int16_t *ptr = (int16_t *) f->data.ptr;
1126 #else
1127 int16_t *ptr = (int16_t *) f->data;
1128 #endif /* ASTERISK_VERSION_1_6_0_1 */
1129 for (i = 0; i < f->samples; i++) {
1130 x = (ptr[i] * boost) / BOOST_SCALE;
1131 if (x > 32767) {
1132 x = 32767;
1133 } else if (x < -32768) {
1134 x = -32768;
1135 }
1136 ptr[i] = x;
1137 }
1138 }
1139 return 0;
1140 }
1141
celliax_new(struct celliax_pvt * p,int state,char * context)1142 struct ast_channel *celliax_new(struct celliax_pvt *p, int state, char *context)
1143 {
1144 struct ast_channel *tmp;
1145
1146 if (option_debug) {
1147 DEBUGA_PBX("ENTERING FUNC\n", CELLIAX_P_LOG);
1148 }
1149 /* alloc a generic channel struct */
1150 #ifndef ASTERISK_VERSION_1_4
1151 tmp = ast_channel_alloc(1);
1152 #else
1153 //tmp = ast_channel_alloc(1, state, 0, 0, "", p->exten, p->context, 0, "");
1154 tmp =
1155 ast_channel_alloc(1, state, 0, 0, "", p->exten, p->context, 0, "Celliax/%s", p->name);
1156
1157 #endif /* ASTERISK_VERSION_1_4 */
1158 if (tmp) {
1159 int res;
1160
1161 /* initialize the soundcard channels (input and output) used by this interface (a multichannel soundcard can be used by multiple interfaces), optionally starting the sound managing threads */
1162 res = celliax_sound_init(p);
1163 if (res == -1) {
1164 ERRORA("Failed initializing sound device\n", CELLIAX_P_LOG);
1165 /* we failed, free the PVT */
1166 if (tmp)
1167 free(tmp);
1168 return NULL;
1169 }
1170
1171 /* give a name to the newly created channel */
1172 #ifndef ASTERISK_VERSION_1_4
1173 snprintf(tmp->name, sizeof(tmp->name), "Celliax/%s", p->name);
1174 tmp->type = celliax_type;
1175 #else /* ASTERISK_VERSION_1_4 */
1176 ast_string_field_build(tmp, name, "Celliax/%s", p->name);
1177 #endif /* ASTERISK_VERSION_1_4 */
1178
1179 DEBUGA_PBX("new channel: name=%s requested_state=%d\n", CELLIAX_P_LOG, tmp->name,
1180 state);
1181
1182 /* fd for the channel to poll for incoming audio */
1183 tmp->fds[0] = p->celliax_sound_capt_fd;
1184
1185 /* audio formats managed */
1186 tmp->nativeformats = AST_FORMAT_SLINEAR;
1187 tmp->readformat = AST_FORMAT_SLINEAR;
1188 tmp->writeformat = AST_FORMAT_SLINEAR;
1189 /* the technology description (eg. the interface type) of the newly created channel is the Celliax's one */
1190 tmp->tech = &celliax_tech;
1191 /* the technology pvt (eg. the interface) of the newly created channel is this interface pvt */
1192 tmp->tech_pvt = p;
1193
1194 /* copy this interface default context, extension, language to the newly created channel */
1195 if (strlen(p->context))
1196 strncpy(tmp->context, p->context, sizeof(tmp->context) - 1);
1197 if (strlen(p->exten))
1198 strncpy(tmp->exten, p->exten, sizeof(tmp->exten) - 1);
1199 #ifndef ASTERISK_VERSION_1_4
1200 if (strlen(p->language))
1201 strncpy(tmp->language, p->language, sizeof(tmp->language) - 1);
1202 #else
1203 if (strlen(p->language))
1204 ast_string_field_set(tmp, language, p->language);
1205 #endif /* ASTERISK_VERSION_1_4 */
1206 /* copy the requested context (not necessarily the interface default) to the newly created channel */
1207 if (strlen(context))
1208 strncpy(tmp->context, context, sizeof(tmp->context) - 1);
1209
1210 /* copy this interface default callerid in the newly created channel */
1211 ast_set_callerid(tmp, !ast_strlen_zero(p->callid_number) ? p->callid_number : NULL,
1212 !ast_strlen_zero(p->callid_name) ? p->callid_name : NULL,
1213 !ast_strlen_zero(p->callid_number) ? p->callid_number : NULL);
1214
1215 /* the owner of this interface pvt is the newly created channel */
1216 p->owner = tmp;
1217 /* if this interface pvt has an initialized dsp struct, free it */
1218 if (p->dsp) {
1219 DEBUGA_SOUND("freeing dsp\n", CELLIAX_P_LOG);
1220 ast_dsp_free(p->dsp);
1221 p->dsp = NULL;
1222 }
1223 #ifndef ASTERISK_VERSION_1_4
1224 /* set the newly created channel state to the requested state */
1225 if (ast_setstate(tmp, state)) {
1226 ERRORA("ast_setstate failed, BAD\n", CELLIAX_P_LOG);
1227 ast_dsp_free(p->dsp);
1228 ast_channel_free(tmp);
1229 if (option_debug) {
1230 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1231 }
1232 return NULL;
1233 }
1234 #endif /* ASTERISK_VERSION_1_4 */
1235
1236 #ifdef AST_VERION_1_4
1237 ast_module_ref(ast_module_info->self);
1238 ast_jb_configure(tmp, &global_jbconf);
1239 #endif /* AST_VERION_1_4 */
1240
1241 /* if the requested state is different from DOWN, let the pbx manage this interface (now part of the newly created channel) */
1242 if (state != AST_STATE_DOWN) {
1243 DEBUGA_PBX("Try to start PBX on %s, state=%d\n", CELLIAX_P_LOG, tmp->name, state);
1244 if (ast_pbx_start(tmp)) {
1245 ERRORA("Unable to start PBX on %s\n", CELLIAX_P_LOG, tmp->name);
1246 ast_dsp_free(p->dsp);
1247 ast_channel_free(tmp);
1248 if (option_debug) {
1249 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1250 }
1251 return NULL;
1252 }
1253 }
1254 /* let's start the serial monitoring thread too, so we can have serial signaling */
1255 if (ast_pthread_create(&p->controldev_thread, NULL, celliax_do_controldev_thread, p) <
1256 0) {
1257 ERRORA("Unable to start controldev thread.\n", CELLIAX_P_LOG);
1258 ast_dsp_free(p->dsp);
1259 ast_channel_free(tmp);
1260 tmp = NULL;
1261 }
1262 DEBUGA_SERIAL("STARTED controldev_thread=%lu STOP=%lu NULL=%lu\n", CELLIAX_P_LOG,
1263 (unsigned long) p->controldev_thread, (unsigned long) AST_PTHREADT_STOP,
1264 (unsigned long) AST_PTHREADT_NULL);
1265
1266 #ifndef ASTERISK_VERSION_1_4
1267 /* add one to the usage count of Celliax-type channels */
1268 LOKKA(&celliax_usecnt_lock);
1269 celliax_usecnt++;
1270 UNLOCKA(&celliax_usecnt_lock);
1271 ast_update_use_count();
1272 #endif /* ASTERISK_VERSION_1_4 */
1273
1274 /* return the newly created channel */
1275 if (option_debug) {
1276 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1277 }
1278 return tmp;
1279 }
1280 ERRORA("failed memory allocation for Celliax channel\n", CELLIAX_P_LOG);
1281 if (option_debug) {
1282 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1283 }
1284 return NULL;
1285 }
1286
1287 /*!
1288 * \brief Load the module into Asterisk and start its threads
1289 *
1290 * This function register the module into Asterisk,
1291 * create the interfaces for the channels,
1292 * start the auxiliary threads for the interfaces,
1293 * then start a monitor thread. The monitor thread
1294 * will signal Asterisk when an interface receive a call.
1295 *
1296 *
1297 * \return zero on success, -1 on error.
1298 */
load_module(void)1299 int load_module(void)
1300 {
1301 int i;
1302 struct ast_config *cfg;
1303 struct celliax_pvt *tmp;
1304 struct celliax_pvt *p = NULL;
1305 #ifdef ASTERISK_VERSION_1_6_0
1306 struct ast_flags config_flags = { 0 };
1307 #endif /* ASTERISK_VERSION_1_6_0 */
1308
1309
1310
1311 #ifdef ASTERISK_VERSION_1_4
1312 /* Copy the default jb config over global_jbconf */
1313 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
1314 #endif /* ASTERISK_VERSION_1_4 */
1315
1316 if (option_debug) {
1317 DEBUGA_PBX("ENTERING FUNC\n", CELLIAX_P_LOG);
1318 }
1319 ast_register_application(celliax_sendsmsapp, celliax_sendsms, celliax_sendsmssynopsis,
1320 celliax_sendsmsdescrip);
1321
1322 ast_manager_register2("CELLIAXsendsms", EVENT_FLAG_SYSTEM, celliax_manager_sendsms,
1323 "Send an SMS", mandescr_celliax_sendsms);
1324 /* make sure we can register our channel type with Asterisk */
1325 i = ast_channel_register(&celliax_tech);
1326 if (i < 0) {
1327 ERRORA("Unable to register channel type '%s'\n", CELLIAX_P_LOG, celliax_type);
1328 if (option_debug) {
1329 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1330 }
1331 return -1;
1332 }
1333 /* load celliax.conf config file */
1334 #ifdef ASTERISK_VERSION_1_6_0
1335 cfg = ast_config_load(celliax_config, config_flags);
1336 #else
1337 cfg = ast_config_load(celliax_config);
1338 #endif /* ASTERISK_VERSION_1_6_0 */
1339 if (cfg != NULL) {
1340 char *ctg = NULL;
1341 int is_first_category = 1;
1342 while ((ctg = ast_category_browse(cfg, ctg)) != NULL) {
1343 /* create one interface for each category in celliax.conf config file, first one set the defaults */
1344 tmp = celliax_mkif(cfg, ctg, is_first_category);
1345 if (tmp) {
1346 NOTICA("Created channel Celliax: celliax.conf category '[%s]', channel name '%s'"
1347 " control_device_name '%s'\n", CELLIAX_P_LOG, ctg, tmp->name,
1348 tmp->controldevice_name);
1349 /* add interface to celliax_iflist */
1350 tmp->next = celliax_iflist;
1351 celliax_iflist = tmp;
1352 /* next one will not be the first ;) */
1353 if (is_first_category == 1) {
1354 is_first_category = 0;
1355 celliax_console_active = tmp->name;
1356 }
1357 } else {
1358 ERRORA("Unable to create channel Celliax from celliax.conf category '[%s]'\n",
1359 CELLIAX_P_LOG, ctg);
1360 /* if error, unload config from memory and return */
1361 ast_config_destroy(cfg);
1362 ast_channel_unregister(&celliax_tech);
1363 if (option_debug) {
1364 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1365 }
1366 return -1;
1367 }
1368 /* do it for each category described in config */
1369 }
1370
1371 /* we finished, unload config from memory */
1372 ast_config_destroy(cfg);
1373 } else {
1374 ERRORA("Unable to load celliax_config celliax.conf\n", CELLIAX_P_LOG);
1375 ast_channel_unregister(&celliax_tech);
1376 if (option_debug) {
1377 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1378 }
1379 return -1;
1380 }
1381 #ifndef ASTERISK_VERSION_1_6_0
1382 ast_cli_register_multiple(myclis, sizeof(myclis) / sizeof(struct ast_cli_entry));
1383 #endif /* ASTERISK_VERSION_1_6_0 */
1384 /* start to monitor the interfaces (celliax_iflist) for the first time */
1385 if (celliax_restart_monitor()) {
1386 ERRORA("celliax_restart_monitor failed, BAD\n", CELLIAX_P_LOG);
1387 if (option_debug) {
1388 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1389 }
1390 return -1;
1391 }
1392 #ifdef CELLIAX_DIR
1393 //celliax_dir_create_extensions();
1394 #endif /* CELLIAX_DIR */
1395 if (option_debug) {
1396 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1397 }
1398 return 0;
1399 }
1400
1401 /*!
1402 * \brief Unload the module from Asterisk and shutdown its threads
1403 *
1404 * This function unregister the module from Asterisk,
1405 * destroy the interfaces for the channels,
1406 * shutdown the auxiliary threads for the interfaces,
1407 * then shutdown its monitor thread.
1408 *
1409 * \return zero on success, -1 on error.
1410 */
unload_module(void)1411 int unload_module(void)
1412 {
1413 struct celliax_pvt *p = NULL, *p2 = NULL;
1414 int res;
1415
1416 if (option_debug) {
1417 DEBUGA_PBX("ENTERING FUNC\n", CELLIAX_P_LOG);
1418 }
1419
1420 /* unregister our channel type with Asterisk */
1421 ast_channel_unregister(&celliax_tech);
1422 ast_cli_unregister_multiple(myclis, sizeof(myclis) / sizeof(struct ast_cli_entry));
1423
1424 ast_unregister_application(celliax_sendsmsapp);
1425
1426 /* lock the celliax_monlock, kill the monitor thread, unlock the celliax_monlock */
1427 LOKKA(&celliax_monlock);
1428 if (celliax_monitor_thread && (celliax_monitor_thread != AST_PTHREADT_NULL)
1429 && (celliax_monitor_thread != AST_PTHREADT_STOP)) {
1430 if (pthread_cancel(celliax_monitor_thread)) {
1431 ERRORA("pthread_cancel failed, BAD\n", CELLIAX_P_LOG);
1432 if (option_debug) {
1433 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1434 }
1435 return -1;
1436 }
1437 if (pthread_kill(celliax_monitor_thread, SIGURG)) {
1438 DEBUGA_PBX("pthread_kill failed\n", CELLIAX_P_LOG); //maybe it just died
1439 }
1440 #ifndef __CYGWIN__ /* under cygwin, this seems to be not reliable, get stuck at times */
1441 if (pthread_join(celliax_monitor_thread, NULL)) {
1442 ERRORA("pthread_join failed, BAD\n", CELLIAX_P_LOG);
1443 if (option_debug) {
1444 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1445 }
1446 return -1;
1447 }
1448 #endif /* __CYGWIN__ */
1449 }
1450 celliax_monitor_thread = AST_PTHREADT_STOP;
1451 UNLOCKA(&celliax_monlock);
1452
1453 if (celliax_monitor_audio_thread && (celliax_monitor_audio_thread != AST_PTHREADT_NULL)
1454 && (celliax_monitor_audio_thread != AST_PTHREADT_STOP)) {
1455
1456 if (pthread_cancel(celliax_monitor_audio_thread)) {
1457 ERRORA("pthread_cancel celliax_monitor_audio_thread failed, BAD\n", CELLIAX_P_LOG);
1458 }
1459 if (pthread_kill(celliax_monitor_audio_thread, SIGURG)) {
1460 DEBUGA_PBX("pthread_kill celliax_monitor_audio_thread failed, no problem\n", CELLIAX_P_LOG); //maybe it just died
1461 }
1462
1463 if (pthread_join(celliax_monitor_audio_thread, NULL)) {
1464 ERRORA("pthread_join failed, BAD\n", CELLIAX_P_LOG);
1465 }
1466 }
1467 /* lock the celliax_iflock, and go through the interfaces list (celliax_iflist) */
1468 LOKKA(&celliax_iflock);
1469 p = celliax_iflist;
1470 while (p) {
1471 /* for each interface in list */
1472 p2 = p->next;
1473 /* shutdown the sound system, close sound fds, and if exist shutdown the sound managing threads */
1474 DEBUGA_SOUND("shutting down sound\n", CELLIAX_P_LOG);
1475 res = celliax_sound_shutdown(p);
1476 if (res == -1) {
1477 ERRORA("Failed to shutdown sound\n", CELLIAX_P_LOG);
1478 }
1479
1480 /* if a serial port has been opened, close it */
1481 if (p->controldevprotocol != PROTOCOL_NO_SERIAL)
1482 if (p->controldevfd)
1483 close(p->controldevfd);
1484
1485 /* if a dsp struct has been allocated, free it */
1486 if (p->dsp) {
1487 ast_dsp_free(p->dsp);
1488 p->dsp = NULL;
1489 }
1490 DEBUGA_PBX("freeing PVT\n", CELLIAX_P_LOG);
1491 /* free the pvt allocated memory */
1492 free(p);
1493 /* next one, please */
1494 p = p2;
1495 }
1496 /* finished with the interfaces list, unlock the celliax_iflock */
1497 UNLOCKA(&celliax_iflock);
1498
1499 #ifdef __CYGWIN__
1500 NOTICA("Sleping 5 secs, please wait...\n", CELLIAX_P_LOG);
1501 sleep(5); /* without this pause, for some unknown (to me) reason it crashes on cygwin */
1502 #endif /* __CYGWIN__ */
1503 NOTICA("Unloaded Celliax Module\n", CELLIAX_P_LOG);
1504 if (option_debug) {
1505 DEBUGA_PBX("EXITING FUNC\n", CELLIAX_P_LOG);
1506 }
1507 return 0;
1508 }
1509
1510 /*!
1511 * \brief Return the count of active channels for this module
1512 *
1513 * \return the count of active channels for this module
1514 */
usecount()1515 int usecount()
1516 {
1517 int res;
1518 static struct celliax_pvt *p = &celliax_log_struct;
1519 /* lock the celliax_usecnt lock */
1520 LOKKA(&celliax_usecnt_lock);
1521 /* retrieve the celliax_usecnt */
1522 res = celliax_usecnt;
1523 /* unlock the celliax_usecnt lock */
1524 UNLOCKA(&celliax_usecnt_lock);
1525 /* return the celliax_usecnt */
1526 return res;
1527 }
1528
1529 /*!
1530 * \brief Return the textual description of the module
1531 *
1532 * \return the textual description of the module
1533 */
description()1534 char *description()
1535 {
1536 return (char *) celliax_desc;
1537 }
1538
1539 /*!
1540 * \brief Return the ASTERISK_GPL_KEY
1541 *
1542 * \return the ASTERISK_GPL_KEY
1543 */
key()1544 char *key()
1545 {
1546 struct celliax_pvt *p = NULL;
1547
1548 if (option_debug)
1549 NOTICA("Returning Key\n", CELLIAX_P_LOG);
1550
1551 return ASTERISK_GPL_KEY;
1552 }
1553
1554 /*!
1555 * \brief Create and initialize one interface for the module
1556 * \param cfg pointer to configuration data from celliax.conf
1557 * \param ctg pointer to a category name to be found in cfg
1558 * \param is_first_category is this the first category in cfg
1559 *
1560 * This function create and initialize one interface for the module
1561 *
1562 * \return a pointer to the PVT structure of interface on success, NULL on error.
1563 */
celliax_mkif(struct ast_config * cfg,char * ctg,int is_first_category)1564 struct celliax_pvt *celliax_mkif(struct ast_config *cfg, char *ctg, int is_first_category)
1565 {
1566 struct celliax_pvt *tmp;
1567 struct ast_variable *v;
1568 int res;
1569
1570 int debug_all = 0;
1571 int debug_at = 0;
1572 int debug_fbus2 = 0;
1573 int debug_serial = 0;
1574 int debug_sound = 0;
1575 int debug_pbx = 0;
1576 int debug_skype = 0;
1577 int debug_call = 0;
1578 int debug_locks = 0;
1579 int debug_monitorlocks = 0;
1580 #ifdef CELLIAX_CVM
1581 int debug_cvm = 0;
1582 #endif /* CELLIAX_CVM */
1583
1584 /* alloc memory for PVT */
1585 tmp = malloc(sizeof(struct celliax_pvt));
1586 if (tmp == NULL) /* fail */
1587 return NULL;
1588 /* clear memory for PVT */
1589 memset(tmp, 0, sizeof(struct celliax_pvt));
1590
1591 //NOTICA("malloced %d bytes\n", CELLIAX_TMP_LOG, sizeof(struct celliax_pvt));
1592
1593 /* if we are reading the "first" category of the config file, take SELECTED values as defaults, overriding the values in celliax_default */
1594 if (is_first_category == 1) {
1595 /* for each variable in category, copy it in the celliax_default struct */
1596 for (v = ast_variable_browse(cfg, ctg); v; v = v->next) {
1597 M_START(v->name, v->value);
1598
1599 M_STR("control_device_protocol", celliax_default.controldevprotocolname)
1600 M_STR("context", celliax_default.context)
1601 M_STR("language", celliax_default.language)
1602 M_STR("extension", celliax_default.exten)
1603 M_UINT("dsp_silence_threshold", celliax_default.dsp_silence_threshold)
1604 M_UINT("audio_play_reset_period", celliax_default.audio_play_reset_period)
1605 #ifdef CELLIAX_ALSA
1606 M_UINT("alsa_period_size", celliax_default.alsa_period_size)
1607 M_UINT("alsa_periods_in_buffer", celliax_default.alsa_periods_in_buffer)
1608 #endif /* CELLIAX_ALSA */
1609 M_F("playback_boost",
1610 celliax_store_boost(v->value, &celliax_default.playback_boost))
1611 M_F("capture_boost",
1612 celliax_store_boost(v->value, &celliax_default.capture_boost))
1613 M_UINT("celliax_dir_entry_extension_prefix",
1614 celliax_default.celliax_dir_entry_extension_prefix)
1615 M_UINT("celliax_dir_prefix", celliax_default.celliax_dir_prefix)
1616 M_STR("sms_receiving_program", tmp->sms_receiving_program)
1617 M_END(;
1618 );
1619 }
1620 }
1621
1622 /* initialize the newly created PVT from the celliax_default values */
1623 *tmp = celliax_default;
1624
1625 /* initialize the mutexes */
1626 ast_mutex_init(&tmp->controldev_lock);
1627 ast_mutex_init(&tmp->fbus2_outgoing_list_lock);
1628 #ifdef CELLIAX_CVM
1629 ast_mutex_init(&tmp->cvm_busmail_outgoing_list_lock);
1630 #endif /* CELLIAX_CVM */
1631
1632 /* the category name becomes the interface name */
1633 tmp->name = strdup(ctg);
1634
1635 /* for each category in config file, "first" included, read in ALL the values */
1636 for (v = ast_variable_browse(cfg, ctg); v; v = v->next) {
1637 M_START(v->name, v->value);
1638
1639 M_BOOL("debug_all", debug_all)
1640 M_BOOL("debug_at", debug_at)
1641 M_BOOL("debug_fbus2", debug_fbus2)
1642 M_BOOL("debug_serial", debug_serial)
1643 M_BOOL("debug_sound", debug_sound)
1644 M_BOOL("debug_pbx", debug_pbx)
1645 M_BOOL("debug_skype", debug_skype)
1646 M_BOOL("debug_call", debug_call)
1647 M_BOOL("debug_locks", debug_locks)
1648 M_BOOL("debug_monitorlocks", debug_monitorlocks)
1649 #ifdef CELLIAX_CVM
1650 M_BOOL("debug_cvm", debug_cvm)
1651 M_STR("cvm_subscription_1_pin", tmp->cvm_subsc_1_pin)
1652 M_STR("cvm_subscription_2_pin", tmp->cvm_subsc_2_pin)
1653 M_UINT("cvm_subscription_no", tmp->cvm_subsc_no)
1654 M_UINT("cvm_volume_level", tmp->cvm_volume_level)
1655 M_UINT("cvm_celliax_serial_delay", tmp->cvm_celliax_serial_delay)
1656 #endif /* CELLIAX_CVM */
1657 M_BOOL("skype", tmp->skype)
1658 M_BOOL("need_acoustic_ring", tmp->need_acoustic_ring)
1659 M_STR("control_device_name", tmp->controldevice_name)
1660 M_UINT("control_device_speed", tmp->controldevice_speed)
1661 M_STR("control_device_protocol", tmp->controldevprotocolname)
1662 M_STR("context", tmp->context)
1663 M_STR("language", tmp->language)
1664 M_STR("extension", tmp->exten)
1665 M_UINT("dsp_silence_threshold", tmp->dsp_silence_threshold)
1666 M_UINT("audio_play_reset_period", tmp->audio_play_reset_period)
1667 M_UINT("portaudio_capture_device_id", tmp->portaudiocindex)
1668 M_UINT("portaudio_playback_device_id", tmp->portaudiopindex)
1669 M_F("playback_boost", celliax_store_boost(v->value, &tmp->playback_boost))
1670 M_F("capture_boost", celliax_store_boost(v->value, &tmp->capture_boost))
1671 #ifdef CELLIAX_ALSA
1672 M_STR("alsa_capture_device_name", tmp->alsacname)
1673 M_STR("alsa_playback_device_name", tmp->alsapname)
1674 M_UINT("alsa_period_size", tmp->alsa_period_size)
1675 M_UINT("alsa_periods_in_buffer", tmp->alsa_periods_in_buffer)
1676 #endif /* CELLIAX_WINMM */
1677 M_STR("at_dial_pre_number", tmp->at_dial_pre_number)
1678 M_STR("at_dial_post_number", tmp->at_dial_post_number)
1679
1680 M_STR("at_dial_expect", tmp->at_dial_expect)
1681 M_UINT("at_early_audio", tmp->at_early_audio)
1682 M_STR("at_hangup", tmp->at_hangup)
1683 M_STR("at_hangup_expect", tmp->at_hangup_expect)
1684 M_STR("at_answer", tmp->at_answer)
1685 M_STR("at_answer_expect", tmp->at_answer_expect)
1686 M_STR("at_send_dtmf", tmp->at_send_dtmf)
1687
1688 M_UINT("at_initial_pause", tmp->at_initial_pause)
1689 M_STR("at_preinit_1", tmp->at_preinit_1)
1690 M_STR("at_preinit_1_expect", tmp->at_preinit_1_expect)
1691 M_STR("at_preinit_2", tmp->at_preinit_2)
1692 M_STR("at_preinit_2_expect", tmp->at_preinit_2_expect)
1693 M_STR("at_preinit_3", tmp->at_preinit_3)
1694 M_STR("at_preinit_3_expect", tmp->at_preinit_3_expect)
1695 M_STR("at_preinit_4", tmp->at_preinit_4)
1696 M_STR("at_preinit_4_expect", tmp->at_preinit_4_expect)
1697 M_STR("at_preinit_5", tmp->at_preinit_5)
1698 M_STR("at_preinit_5_expect", tmp->at_preinit_5_expect)
1699 M_UINT("at_after_preinit_pause", tmp->at_after_preinit_pause)
1700
1701 M_STR("at_postinit_1", tmp->at_postinit_1)
1702 M_STR("at_postinit_1_expect", tmp->at_postinit_1_expect)
1703 M_STR("at_postinit_2", tmp->at_postinit_2)
1704 M_STR("at_postinit_2_expect", tmp->at_postinit_2_expect)
1705 M_STR("at_postinit_3", tmp->at_postinit_3)
1706 M_STR("at_postinit_3_expect", tmp->at_postinit_3_expect)
1707 M_STR("at_postinit_4", tmp->at_postinit_4)
1708 M_STR("at_postinit_4_expect", tmp->at_postinit_4_expect)
1709 M_STR("at_postinit_5", tmp->at_postinit_5)
1710 M_STR("at_postinit_5_expect", tmp->at_postinit_5_expect)
1711
1712 M_STR("at_query_battchg", tmp->at_query_battchg)
1713 M_STR("at_query_battchg_expect", tmp->at_query_battchg_expect)
1714 M_STR("at_query_signal", tmp->at_query_signal)
1715 M_STR("at_query_signal_expect", tmp->at_query_signal_expect)
1716 M_STR("at_call_idle", tmp->at_call_idle)
1717 M_STR("at_call_incoming", tmp->at_call_incoming)
1718 M_STR("at_call_active", tmp->at_call_active)
1719 M_STR("at_call_failed", tmp->at_call_failed)
1720 M_STR("at_call_calling", tmp->at_call_calling)
1721 M_STR("at_indicator_noservice_string", tmp->at_indicator_noservice_string)
1722 M_STR("at_indicator_nosignal_string", tmp->at_indicator_nosignal_string)
1723 M_STR("at_indicator_lowsignal_string", tmp->at_indicator_lowsignal_string)
1724 M_STR("at_indicator_lowbattchg_string", tmp->at_indicator_lowbattchg_string)
1725 M_STR("at_indicator_nobattchg_string", tmp->at_indicator_nobattchg_string)
1726 M_STR("at_indicator_callactive_string", tmp->at_indicator_callactive_string)
1727 M_STR("at_indicator_nocallactive_string", tmp->at_indicator_nocallactive_string)
1728 M_STR("at_indicator_nocallsetup_string", tmp->at_indicator_nocallsetup_string)
1729 M_STR("at_indicator_callsetupincoming_string",
1730 tmp->at_indicator_callsetupincoming_string)
1731 M_STR("at_indicator_callsetupoutgoing_string",
1732 tmp->at_indicator_callsetupoutgoing_string)
1733 M_STR("at_indicator_callsetupremoteringing_string",
1734 tmp->at_indicator_callsetupremoteringing_string)
1735 M_UINT("celliax_dir_entry_extension_prefix",
1736 tmp->celliax_dir_entry_extension_prefix)
1737 M_UINT("celliax_dir_prefix", tmp->celliax_dir_prefix)
1738 #ifdef CELLIAX_LIBCSV
1739 M_UINT("csv_separator_is_semicolon", tmp->csv_separator_is_semicolon)
1740 M_UINT("csv_complete_name_pos", tmp->csv_complete_name_pos)
1741 M_UINT("csv_email_pos", tmp->csv_email_pos)
1742 M_UINT("csv_home_phone_pos", tmp->csv_home_phone_pos)
1743 M_UINT("csv_mobile_phone_pos", tmp->csv_mobile_phone_pos)
1744 M_UINT("csv_business_phone_pos", tmp->csv_business_phone_pos)
1745 M_UINT("csv_first_row_is_title", tmp->csv_first_row_is_title)
1746 #endif /* CELLIAX_LIBCSV */
1747 M_STR("sms_receiving_program", tmp->sms_receiving_program)
1748 M_BOOL("speexecho", tmp->speexecho)
1749 M_BOOL("speexpreprocess", tmp->speexpreprocess)
1750 M_END(;
1751 );
1752 }
1753
1754 if (debug_all) {
1755 celliax_debug = celliax_debug | DEBUG_ALL;
1756 if (!option_debug) {
1757 WARNINGA
1758 ("DEBUG_ALL activated, but option_debug is 0. You have to set debug level higher than zero to see some debugging output. Please use the command \"set debug 10\" or start Asterisk with \"-dddddddddd\" option for full DEBUG_ALL debugging output.\n",
1759 CELLIAX_TMP_LOG);
1760 } else {
1761 NOTICA("DEBUG_ALL activated. \n", CELLIAX_TMP_LOG);
1762 }
1763 }
1764 if (debug_at) {
1765 celliax_debug = celliax_debug | DEBUG_AT;
1766 if (!option_debug) {
1767 WARNINGA
1768 ("DEBUG_AT activated, but option_debug is 0. You have to set debug level higher than zero to see some debugging output. Please use the command \"set debug 10\" or start Asterisk with \"-dddddddddd\" option for full DEBUG_AT debugging output.\n",
1769 CELLIAX_TMP_LOG);
1770 } else {
1771 NOTICA("DEBUG_AT activated. \n", CELLIAX_TMP_LOG);
1772 }
1773 }
1774
1775 if (debug_fbus2) {
1776 celliax_debug = celliax_debug | DEBUG_FBUS2;
1777 if (!option_debug) {
1778 WARNINGA
1779 ("DEBUG_FBUS2 activated, but option_debug is 0. You have to set debug level higher than zero to see some debugging output. Please use the command \"set debug 10\" or start Asterisk with \"-dddddddddd\" option for full DEBUG_FBUS2 debugging output.\n",
1780 CELLIAX_TMP_LOG);
1781 } else {
1782 NOTICA("DEBUG_FBUS2 activated. \n", CELLIAX_TMP_LOG);
1783 }
1784 }
1785
1786 if (debug_serial) {
1787 celliax_debug = celliax_debug | DEBUG_SERIAL;
1788 if (!option_debug) {
1789 WARNINGA
1790 ("DEBUG_SERIAL activated, but option_debug is 0. You have to set debug level higher than zero to see some debugging output. Please use the command \"set debug 10\" or start Asterisk with \"-dddddddddd\" option for full DEBUG_SERIAL debugging output.\n",
1791 CELLIAX_TMP_LOG);
1792 } else {
1793 NOTICA("DEBUG_SERIAL activated. \n", CELLIAX_TMP_LOG);
1794 }
1795 }
1796
1797 if (debug_sound) {
1798 celliax_debug = celliax_debug | DEBUG_SOUND;
1799 if (!option_debug) {
1800 WARNINGA
1801 ("DEBUG_SOUND activated, but option_debug is 0. You have to set debug level higher than zero to see some debugging output. Please use the command \"set debug 10\" or start Asterisk with \"-dddddddddd\" option for full DEBUG_SOUND debugging output.\n",
1802 CELLIAX_TMP_LOG);
1803 } else {
1804 NOTICA("DEBUG_SOUND activated. \n", CELLIAX_TMP_LOG);
1805 }
1806 }
1807
1808 if (debug_pbx) {
1809 celliax_debug = celliax_debug | DEBUG_PBX;
1810 if (!option_debug) {
1811 WARNINGA
1812 ("DEBUG_PBX activated, but option_debug is 0. You have to set debug level higher than zero to see some debugging output. Please use the command \"set debug 10\" or start Asterisk with \"-dddddddddd\" option for full DEBUG_PBX debugging output.\n",
1813 CELLIAX_TMP_LOG);
1814 } else {
1815 NOTICA("DEBUG_PBX activated. \n", CELLIAX_TMP_LOG);
1816 }
1817 }
1818
1819 if (debug_call) {
1820 celliax_debug = celliax_debug | DEBUG_CALL;
1821 if (!option_debug) {
1822 WARNINGA
1823 ("DEBUG_CALL activated, but option_debug is 0. You have to set debug level higher than zero to see some debugging output. Please use the command \"set debug 10\" or start Asterisk with \"-dddddddddd\" option for full DEBUG_CALL debugging output.\n",
1824 CELLIAX_TMP_LOG);
1825 } else {
1826 NOTICA("DEBUG_CALL activated. \n", CELLIAX_TMP_LOG);
1827 }
1828 }
1829
1830 if (debug_locks) {
1831 celliax_debug = celliax_debug | DEBUG_LOCKS;
1832 if (!option_debug) {
1833 WARNINGA
1834 ("DEBUG_LOCKS activated, but option_debug is 0. You have to set debug level higher than zero to see some debugging output. Please use the command \"set debug 10\" or start Asterisk with \"-dddddddddd\" option for full DEBUG_LOCKS debugging output.\n",
1835 CELLIAX_TMP_LOG);
1836 } else {
1837 NOTICA("DEBUG_LOCKS activated. \n", CELLIAX_TMP_LOG);
1838 }
1839 }
1840
1841 if (debug_monitorlocks) {
1842 celliax_debug = celliax_debug | DEBUG_MONITORLOCKS;
1843 if (!option_debug) {
1844 WARNINGA
1845 ("DEBUG_MONITORLOCKS activated, but option_debug is 0. You have to set debug level higher than zero to see some debugging output. Please use the command \"set debug 10\" or start Asterisk with \"-dddddddddd\" option for full DEBUG_MONITORLOCKS debugging output.\n",
1846 CELLIAX_TMP_LOG);
1847 } else {
1848 NOTICA("DEBUG_MONITORLOCKS activated. \n", CELLIAX_TMP_LOG);
1849 }
1850 }
1851 #ifdef CELLIAX_CVM
1852 if (debug_cvm) {
1853 celliax_debug = celliax_debug | DEBUG_CVM;
1854 if (!option_debug) {
1855 WARNINGA
1856 ("DEBUG_CVM activated, but option_debug is 0. You have to set debug level higher than zero to see some debugging output. Please use the command \"set debug 10\" or start Asterisk with \"-dddddddddd\" option for full DEBUG_CVM debugging output.\n",
1857 CELLIAX_TMP_LOG);
1858 } else {
1859 NOTICA("DEBUG_CVM activated. \n", CELLIAX_TMP_LOG);
1860 }
1861 }
1862 #endif /* CELLIAX_CVM */
1863
1864 if (option_debug > 1) {
1865 DEBUGA_SOUND("playback_boost is %f\n", CELLIAX_TMP_LOG, tmp->playback_boost);
1866 DEBUGA_SOUND("capture_boost is %f\n", CELLIAX_TMP_LOG, tmp->capture_boost);
1867 }
1868
1869 /* serial protocols are named in config with a string, but as int in this software */
1870 if (strcasecmp(tmp->controldevprotocolname, "fbus2") == 0)
1871 tmp->controldevprotocol = PROTOCOL_FBUS2;
1872 else if (strcasecmp(tmp->controldevprotocolname, "at") == 0)
1873 tmp->controldevprotocol = PROTOCOL_AT;
1874 else if (strcasecmp(tmp->controldevprotocolname, "no_serial") == 0)
1875 tmp->controldevprotocol = PROTOCOL_NO_SERIAL;
1876 else if (strcasecmp(tmp->controldevprotocolname, "alsa_voicemodem") == 0)
1877 tmp->controldevprotocol = PROTOCOL_ALSA_VOICEMODEM;
1878 #ifdef CELLIAX_CVM
1879 else if (strcasecmp(tmp->controldevprotocolname, "cvm_busmail") == 0)
1880 tmp->controldevprotocol = PROTOCOL_CVM_BUSMAIL;
1881 #endif /* CELLIAX_CVM */
1882 else {
1883 #ifndef CELLIAX_CVM
1884 ERRORA
1885 ("control_device_protocol in celliax.conf MUST be = fbus2|at|no_serial|alsa_voicemodem, but is = '%s'\n",
1886 CELLIAX_TMP_LOG,
1887 tmp->controldevprotocolname ? tmp->controldevprotocolname : "NULL");
1888 #else
1889 ERRORA
1890 ("control_device_protocol in celliax.conf MUST be = fbus2|at|no_serial|alsa_voicemodem|cvm_busmail, but is = '%s'\n",
1891 CELLIAX_TMP_LOG,
1892 tmp->controldevprotocolname ? tmp->controldevprotocolname : "NULL");
1893 #endif /* CELLIAX_CVM */
1894
1895 /* we failed, free the PVT */
1896 free(tmp);
1897 return NULL;
1898 }
1899
1900 if (tmp->controldevice_speed != celliax_default.controldevice_speed) {
1901 /* serial speeds are numbers in config file, but we needs definitions in this software */
1902 if (tmp->controldevice_speed == 9600)
1903 tmp->controldevice_speed = B9600;
1904 else if (tmp->controldevice_speed == 19200)
1905 tmp->controldevice_speed = B19200;
1906 else if (tmp->controldevice_speed == 38400)
1907 tmp->controldevice_speed = B38400;
1908 else if (tmp->controldevice_speed == 57600)
1909 tmp->controldevice_speed = B57600;
1910 else if (tmp->controldevice_speed == 115200)
1911 tmp->controldevice_speed = B115200;
1912 else {
1913 ERRORA
1914 ("controldevice_speed has to be given one of the following values: 9600|19200|38400|57600|115200. In the config file, was given: %d\n",
1915 CELLIAX_TMP_LOG, tmp->controldevice_speed);
1916 free(tmp);
1917 return NULL;
1918 }
1919 }
1920
1921 /* CVM PP DECT modules supports registration to two DECT FPs (bases), but CVM can be only connected to one DECT FP at the time, so we need two PINs (for registration) and info to which DECT FP connect*/
1922 #ifdef CELLIAX_CVM
1923 if (tmp->cvm_subsc_no != celliax_default.cvm_subsc_no) {
1924 if ((tmp->cvm_subsc_no != 1) && (tmp->cvm_subsc_no != 2)) {
1925 ERRORA
1926 ("cvm_subscription_no has to be given one of the following values: 1|2. In the config file, was given: %d\n",
1927 CELLIAX_TMP_LOG, tmp->cvm_subsc_no);
1928 free(tmp);
1929 return NULL;
1930 }
1931 }
1932
1933 if (tmp->cvm_subsc_1_pin != celliax_default.cvm_subsc_1_pin) {
1934 if (4 != strlen(tmp->cvm_subsc_1_pin)) {
1935 ERRORA
1936 ("cvm_subscription_1_pin has to be 4 digits long. In the config file, was given: %s\n",
1937 CELLIAX_TMP_LOG, tmp->cvm_subsc_1_pin);
1938 free(tmp);
1939 return NULL;
1940 }
1941 }
1942
1943 if (tmp->cvm_subsc_2_pin != celliax_default.cvm_subsc_2_pin) {
1944 if (4 != strlen(tmp->cvm_subsc_2_pin)) {
1945 ERRORA
1946 ("cvm_subscription_2_pin has to be 4 digits long. In the config file, was given: %s\n",
1947 CELLIAX_TMP_LOG, tmp->cvm_subsc_2_pin);
1948 free(tmp);
1949 return NULL;
1950 }
1951 }
1952
1953 if (tmp->cvm_volume_level != celliax_default.cvm_volume_level) {
1954 if ((0 > tmp->cvm_volume_level) && (9 < tmp->cvm_volume_level)) {
1955 ERRORA("cvm_volume_level has to be 0-9. In the config file, was given: %d\n",
1956 CELLIAX_TMP_LOG, tmp->cvm_volume_level);
1957 free(tmp);
1958 return NULL;
1959 }
1960 }
1961
1962 if (tmp->cvm_celliax_serial_delay != celliax_default.cvm_celliax_serial_delay) {
1963 if ((0 > tmp->cvm_celliax_serial_delay) && (65535 < tmp->cvm_celliax_serial_delay)) {
1964 ERRORA
1965 ("cvm_celliax_serial_dealy has to be 0-65535. In the config file, was given: %d\n",
1966 CELLIAX_TMP_LOG, tmp->cvm_celliax_serial_delay);
1967 free(tmp);
1968 return NULL;
1969 }
1970 }
1971 #endif /* CELLIAX_CVM */
1972 if (tmp->need_acoustic_ring) {
1973 /* alloc and initialize a new dsp struct for this interface pvt, WITH silence suppression */
1974 if (celliax_sound_dsp_set(tmp, tmp->dsp_silence_threshold, 1)) {
1975 ERRORA("celliax_sound_dsp_set failed\n", CELLIAX_TMP_LOG);
1976 celliax_sound_shutdown(tmp);
1977 if (tmp)
1978 free(tmp);
1979 return NULL;
1980 }
1981
1982 /* initialize the soundcard channels (input and output) used by this interface (a multichannel soundcard can be used by multiple interfaces), optionally starting the sound managing threads */
1983 res = celliax_sound_init(tmp);
1984 if (res == -1) {
1985 ERRORA("Failed initializing sound device\n", CELLIAX_TMP_LOG);
1986 /* we failed, free the PVT */
1987 if (tmp)
1988 free(tmp);
1989 return NULL;
1990 }
1991
1992 }
1993
1994 /* init the serial port */
1995 if (tmp->controldevprotocol != PROTOCOL_NO_SERIAL) {
1996 tmp->controldevfd = celliax_serial_init(tmp, tmp->controldevice_speed);
1997 if (tmp->controldevfd < 1) {
1998 ERRORA("celliax_serial_init failed\n", CELLIAX_TMP_LOG);
1999 celliax_sound_shutdown(tmp);
2000 if (tmp)
2001 free(tmp);
2002 return NULL;
2003 }
2004 }
2005
2006 /* config the phone/modem on the serial port */
2007 if (tmp->controldevprotocol != PROTOCOL_NO_SERIAL) {
2008 //int res;
2009 res = celliax_serial_config(tmp);
2010 if (res) {
2011 ERRORA("celliax_serial_config failed\n", CELLIAX_TMP_LOG);
2012 celliax_sound_shutdown(tmp);
2013 if (tmp)
2014 free(tmp);
2015 return NULL;
2016 }
2017 }
2018
2019 /* return the newly created celliax_pvt */
2020 return tmp;
2021 }
2022
2023 /*! \brief (Re)Start the module main monitor thread, watching for incoming calls on the interfaces */
celliax_restart_monitor(void)2024 int celliax_restart_monitor(void)
2025 {
2026 static struct celliax_pvt *p = &celliax_log_struct;
2027 /* If we're supposed to be stopped -- stay stopped */
2028 if (celliax_monitor_thread == AST_PTHREADT_STOP)
2029 return 0;
2030 LOKKA(&celliax_monlock);
2031 /* Do not seems possible to me that this function can be called by the very same monitor thread, but let's be paranoid */
2032 if (celliax_monitor_thread == pthread_self()) {
2033 UNLOCKA(&celliax_monlock);
2034 ERRORA("Cannot kill myself\n", CELLIAX_P_LOG);
2035 return -1;
2036 }
2037 /* if the monitor thread exists */
2038 if (celliax_monitor_thread != AST_PTHREADT_NULL) {
2039 /* Wake up the thread, it can be stuck waiting in a select or so */
2040 pthread_kill(celliax_monitor_thread, SIGURG);
2041 pthread_kill(celliax_monitor_audio_thread, SIGURG);
2042 } else {
2043 /* the monitor thread does not exists, start a new monitor */
2044 if (ast_pthread_create(&celliax_monitor_thread, NULL, celliax_do_monitor, NULL) < 0) {
2045 UNLOCKA(&celliax_monlock);
2046 ERRORA("Unable to start monitor thread.\n", CELLIAX_P_LOG);
2047 return -1;
2048 }
2049
2050 if (ast_pthread_create
2051 (&celliax_monitor_audio_thread, NULL, celliax_do_audio_monitor, NULL) < 0) {
2052 ERRORA("Unable to start audio_monitor thread.\n", CELLIAX_P_LOG);
2053 return -1;
2054 }
2055
2056 }
2057 UNLOCKA(&celliax_monlock);
2058 return 0;
2059 }
2060
2061 /*! \brief The celliax monitoring thread
2062 * \note This thread monitors all the celliax interfaces that are not in a call
2063 * (and thus do not have a separate thread) indefinitely
2064 * */
celliax_do_monitor(void * data)2065 void *celliax_do_monitor(void *data)
2066 {
2067 fd_set rfds;
2068 int res;
2069 struct celliax_pvt *p = NULL;
2070 int max = -1;
2071 struct timeval to;
2072 time_t now_timestamp;
2073
2074 if (pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL)) {
2075 ERRORA("Unable to set cancel type to deferred\n", CELLIAX_P_LOG);
2076 return NULL;
2077 }
2078
2079 for (;;) {
2080 pthread_testcancel();
2081 /* Don't let anybody kill us right away. Nobody should lock the interface list
2082 and wait for the monitor list, but the other way around is okay. */
2083 PUSHA_UNLOCKA(&celliax_monlock);
2084 MONITORLOKKA(&celliax_monlock);
2085 /* Lock the interface list */
2086 PUSHA_UNLOCKA(&celliax_iflock);
2087 MONITORLOKKA(&celliax_iflock);
2088 /* Build the stuff we're going to select on, that is the celliax_serial_fd of every
2089 celliax_pvt that does not have an associated owner channel. In the case of FBUS2 3310
2090 and in the case of PROTOCOL_NO_SERIAL we add the audio_fd as well, because there is not serial signaling of incoming calls */
2091 FD_ZERO(&rfds);
2092
2093 time(&now_timestamp);
2094 p = celliax_iflist;
2095 while (p) {
2096 if (!p->owner) {
2097 /* This interface needs to be watched, as it lacks an owner */
2098
2099 if (p->controldevprotocol != PROTOCOL_NO_SERIAL && !p->controldev_dead) {
2100 /* This interface needs its serial connection to be watched, nokia 3310 and compatibles needs sounds as well */
2101 if (FD_ISSET(p->controldevfd, &rfds)) {
2102 ERRORA("Bizarre! Descriptor %d (controldevfd) appears twice ?\n",
2103 CELLIAX_P_LOG, p->controldevfd);
2104 }
2105 if (p->controldevfd > 0) {
2106
2107 //time(&now_timestamp);
2108 if ((now_timestamp - p->celliax_serial_synced_timestamp) > p->celliax_serial_sync_period) { //TODO find a sensible period. 5min? in config?
2109 int rt;
2110 if (option_debug > 1)
2111 DEBUGA_SERIAL("Syncing Serial\n", CELLIAX_P_LOG);
2112 rt = celliax_serial_sync(p);
2113 if (rt) {
2114 p->controldev_dead = 1;
2115 close(p->controldevfd);
2116 ERRORA("serial sync failed, declaring %s dead\n", CELLIAX_P_LOG,
2117 p->controldevice_name);
2118 }
2119 rt = celliax_serial_getstatus(p);
2120 if (rt) {
2121 p->controldev_dead = 1;
2122 close(p->controldevfd);
2123 ERRORA("serial getstatus failed, declaring %s dead\n", CELLIAX_P_LOG,
2124 p->controldevice_name);
2125 }
2126
2127 }
2128
2129 if (!p->controldev_dead) {
2130 /* add this file descriptor to the set watched by the select */
2131 FD_SET(p->controldevfd, &rfds);
2132 if (p->controldevfd > max) {
2133 /* adjust the maximum file descriptor value the select has to watch for */
2134 max = p->controldevfd;
2135 }
2136 }
2137 }
2138 }
2139
2140 }
2141 /* next interface, please */
2142 p = p->next;
2143 }
2144 /* Okay, now that we know what to do, release the interface lock */
2145 MONITORUNLOCKA(&celliax_iflock);
2146 POPPA_UNLOCKA(&celliax_iflock);
2147 /* And from now on, we're okay to be killed, so release the monitor lock as well */
2148 MONITORUNLOCKA(&celliax_monlock);
2149 POPPA_UNLOCKA(&celliax_monlock);
2150
2151 /* you want me to die? */
2152 pthread_testcancel();
2153
2154 /* Wait for something to happen */
2155 to.tv_sec = 0;
2156 to.tv_usec = 500000; /* we select with this timeout because under cygwin we avoid the signal usage, so there is no way to end the thread if it is stuck waiting for select */
2157 res = ast_select(max + 1, &rfds, NULL, NULL, &to);
2158
2159 /* you want me to die? */
2160 pthread_testcancel();
2161
2162 /* Okay, select has finished. Let's see what happened. */
2163
2164 /* If there are errors... */
2165 if (res < 0) {
2166 if (errno == EINTR) /* EINTR is just the select
2167 being interrupted by a SIGURG, or so */
2168 continue;
2169 else {
2170 ERRORA("select returned %d: %s\n", CELLIAX_P_LOG, res, strerror(errno));
2171 //FIXME what to do here? is the interface that failed signaled? which interface we have to disable?
2172 return NULL;
2173 }
2174 }
2175
2176 /* must not be killed while celliax_iflist is locked */
2177 PUSHA_UNLOCKA(&celliax_monlock);
2178 MONITORLOKKA(&celliax_monlock);
2179 /* Alright, lock the interface list again, and let's look and see what has
2180 happened */
2181 PUSHA_UNLOCKA(&celliax_iflock);
2182 MONITORLOKKA(&celliax_iflock);
2183
2184 p = celliax_iflist;
2185 for (; p; p = p->next) {
2186
2187 if (p->controldevprotocol != PROTOCOL_NO_SERIAL && !p->controldev_dead) {
2188 if (!p->owner) { //give all the serial channels that have no owner a read, so we can have the timers clicking
2189
2190 if (!p->celliax_serial_monitoring) {
2191 p->celliax_serial_monitoring = 1;
2192 res = celliax_serial_monitor(p);
2193 if (res == -1) { //manage the graceful interface shutdown
2194 p->controldev_dead = 1;
2195 close(p->controldevfd);
2196 ERRORA("celliax_serial_monitor failed, declaring %s dead\n", CELLIAX_P_LOG,
2197 p->controldevice_name);
2198 } else if (!p->need_acoustic_ring
2199 && p->controldevprotocol != PROTOCOL_NO_SERIAL
2200 && p->interface_state == AST_STATE_RING) {
2201 if (option_debug)
2202 DEBUGA_PBX("INCOMING RING\n", CELLIAX_P_LOG);
2203 if (!celliax_new(p, AST_STATE_RING, p->context)) {
2204 //FIXME what to do here?
2205 ERRORA("celliax_new failed! BAD BAD BAD\n", CELLIAX_P_LOG);
2206 }
2207 }
2208 p->celliax_serial_monitoring = 0;
2209 }
2210 }
2211 }
2212
2213 if (p->controldevprotocol != PROTOCOL_NO_SERIAL && p->controldev_dead) {
2214
2215 /* init the serial port */
2216 p->controldevfd = celliax_serial_init(p, p->controldevice_speed);
2217 if (p->controldevfd < 1) {
2218 DEBUGA_SERIAL("celliax_serial_init failed\n", CELLIAX_P_LOG);
2219 } else {
2220
2221 /* config the phone/modem on the serial port */
2222 res = celliax_serial_config(p);
2223 if (res) {
2224 DEBUGA_SERIAL("celliax_serial_config failed\n", CELLIAX_P_LOG);
2225 close(p->controldevfd);
2226 } else {
2227
2228 NOTICA("Wow, the serial port has come back! Let's see if it will work\n",
2229 CELLIAX_P_LOG);
2230 p->controldev_dead = 0;
2231 }
2232
2233 }
2234
2235 }
2236
2237 }
2238 MONITORUNLOCKA(&celliax_iflock);
2239 POPPA_UNLOCKA(&celliax_iflock);
2240 MONITORUNLOCKA(&celliax_monlock);
2241 POPPA_UNLOCKA(&celliax_monlock);
2242 pthread_testcancel();
2243 }
2244 /* Never reached */
2245 return NULL;
2246
2247 }
2248
celliax_do_audio_monitor(void * data)2249 void *celliax_do_audio_monitor(void *data)
2250 {
2251 fd_set rfds;
2252 int res;
2253 struct celliax_pvt *p = NULL;
2254 int max = -1;
2255 struct timeval to;
2256
2257 if (pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL)) {
2258 ERRORA("Unable to set cancel type to deferred\n", CELLIAX_P_LOG);
2259 return NULL;
2260 }
2261
2262 for (;;) {
2263 pthread_testcancel();
2264 /* Lock the interface list */
2265 PUSHA_UNLOCKA(&celliax_iflock);
2266 MONITORLOKKA(&celliax_iflock);
2267
2268 FD_ZERO(&rfds);
2269
2270 p = celliax_iflist;
2271 while (p) {
2272 if (!p->owner) {
2273 /* This interface needs to be watched, as it lacks an owner */
2274
2275 if (p->controldevprotocol == PROTOCOL_NO_SERIAL || p->need_acoustic_ring) {
2276 /* This interface needs its incoming sound to be watched, because it cannot signal incoming ring from serial (eg nokia 3310 and compatibles) */
2277 if (p->celliax_sound_capt_fd > 0) {
2278 /* if fd exist */
2279 if (FD_ISSET(p->celliax_sound_capt_fd, &rfds)) {
2280 ERRORA("Bizarre! Descriptor %d (celliax_sound_capt_fd) appears twice ?\n",
2281 CELLIAX_P_LOG, p->celliax_sound_capt_fd);
2282 }
2283 /* add this file descriptor to the set watched by the select */
2284 FD_SET(p->celliax_sound_capt_fd, &rfds);
2285 if (p->celliax_sound_capt_fd > max) {
2286 /* adjust the maximum file descriptor value the select has to watch for */
2287 max = p->celliax_sound_capt_fd;
2288 }
2289 }
2290 }
2291
2292 }
2293 /* next interface, please */
2294 p = p->next;
2295 }
2296 /* Okay, now that we know what to do, release the interface lock */
2297
2298 MONITORUNLOCKA(&celliax_iflock);
2299 POPPA_UNLOCKA(&celliax_iflock);
2300 /* you want me to die? */
2301 pthread_testcancel();
2302
2303 /* Wait for something to happen */
2304 to.tv_sec = 0;
2305 to.tv_usec = 500000; /* we select with this timeout because under cygwin we avoid the signal usage, so there is no way to end the thread if it is stuck waiting for select */
2306 res = ast_select(max + 1, &rfds, NULL, NULL, &to);
2307
2308 /* you want me to die? */
2309 pthread_testcancel();
2310
2311 /* Okay, select has finished. Let's see what happened. */
2312
2313 /* If there are errors... */
2314 if (res < 0) {
2315 if (errno == EINTR) { /* EINTR is just the select
2316 being interrupted by a SIGURG, or so */
2317 usleep(100);
2318 continue;
2319 } else {
2320 ERRORA("select returned %d: %s\n", CELLIAX_P_LOG, res, strerror(errno));
2321 //FIXME what to do here? is the interface that failed signaled? which interface we have to disable?
2322 return NULL;
2323 }
2324 }
2325 /* If there are no file descriptors changed, just continue */
2326
2327 if (res == 0) {
2328 usleep(100); //let's breath
2329 continue;
2330 }
2331 //usleep(10); //let's breath
2332
2333 /* Lock the interface list */
2334 PUSHA_UNLOCKA(&celliax_iflock);
2335 MONITORLOKKA(&celliax_iflock);
2336
2337 p = celliax_iflist;
2338 for (; p; p = p->next) {
2339
2340 if (FD_ISSET(p->celliax_sound_capt_fd, &rfds)) {
2341 res = celliax_sound_monitor(p);
2342 if (res < 0) {
2343 ERRORA("celliax_sound_monitor ERROR %d\n", CELLIAX_P_LOG, res);
2344 } else if (res == CALLFLOW_INCOMING_RING) {
2345 p->phone_callflow = CALLFLOW_INCOMING_RING;
2346 p->interface_state = AST_STATE_RING;
2347 if (option_debug)
2348 DEBUGA_PBX("INCOMING RING\n", CELLIAX_P_LOG);
2349 if (!celliax_new(p, AST_STATE_RING, p->context))
2350 ERRORA("celliax_new failed! BAD BAD BAD\n", CELLIAX_P_LOG);
2351 } else {
2352 }
2353
2354 }
2355
2356 }
2357 /* Okay, now that we know what to do, release the interface lock */
2358
2359 MONITORUNLOCKA(&celliax_iflock);
2360 POPPA_UNLOCKA(&celliax_iflock);
2361
2362 pthread_testcancel();
2363 }
2364 /* Never reached */
2365 return NULL;
2366 }
2367
2368 /*!
2369 * \brief Initialize the soundcard channels (input and output) used by one interface (a multichannel soundcard can be used by multiple interfaces)
2370 * \param p the celliax_pvt of the interface
2371 *
2372 * This function initialize the soundcard channels (input and output) used by one interface (a multichannel soundcard can be used by multiple interfaces). It simply pass its parameters to the right function for the sound system for which has been compiled, eg. alsa_init for ALSA, oss_init for OSS, winmm_init for Windows Multimedia, etc and return the result
2373 *
2374 * \return zero on success, -1 on error.
2375 */
2376
celliax_sound_init(struct celliax_pvt * p)2377 int celliax_sound_init(struct celliax_pvt *p)
2378 {
2379 #ifdef CELLIAX_ALSA
2380 return alsa_init(p);
2381 #endif /* CELLIAX_ALSA */
2382 #ifdef CELLIAX_PORTAUDIO
2383 return celliax_portaudio_init(p);
2384 #endif /* CELLIAX_PORTAUDIO */
2385
2386 return -1;
2387 }
2388
2389 /*!
2390 * \brief Shutdown the soundcard channels (input and output) used by one interface (a multichannel soundcard can be used by multiple interfaces)
2391 * \param p the celliax_pvt of the interface
2392 *
2393 * This function shutdown the soundcard channels (input and output) used by one interface (a multichannel soundcard can be used by multiple interfaces). It simply pass its parameters to the right function for the sound system for which has been compiled, eg. alsa_shutdown for ALSA, oss_shutdown for OSS, winmm_shutdown for Windows Multimedia, etc and return the result
2394 *
2395 * \return zero on success, -1 on error.
2396 */
2397
celliax_sound_shutdown(struct celliax_pvt * p)2398 int celliax_sound_shutdown(struct celliax_pvt *p)
2399 {
2400
2401 #ifdef CELLIAX_ALSA
2402 return alsa_shutdown(p);
2403 #endif /* CELLIAX_ALSA */
2404 #ifdef CELLIAX_PORTAUDIO
2405 return celliax_portaudio_shutdown(p);
2406 #endif /* CELLIAX_PORTAUDIO */
2407
2408 return -1;
2409 }
2410
2411 /*! \brief returns an asterisk frame categorized by dsp algorithms */
celliax_sound_dsp_analize(struct celliax_pvt * p,struct ast_frame * f,int dsp_silence_threshold)2412 struct ast_frame *celliax_sound_dsp_analize(struct celliax_pvt *p, struct ast_frame *f,
2413 int dsp_silence_threshold)
2414 {
2415 if (!p->dsp) {
2416 DEBUGA_SOUND("no dsp, initializing it \n", CELLIAX_P_LOG);
2417 if (celliax_sound_dsp_set(p, dsp_silence_threshold, 1)) {
2418 ERRORA("celliax_sound_dsp_set failed\n", CELLIAX_P_LOG);
2419 return NULL;
2420 }
2421 }
2422
2423 /* process with dsp */
2424 if (p->dsp) {
2425 if (f->frametype == AST_FRAME_VOICE) {
2426 f = ast_dsp_process(p->owner, p->dsp, f);
2427 } else {
2428 //WARNINGA("not a VOICE frame ! \n", CELLIAX_P_LOG);
2429 }
2430 }
2431 return f;
2432 }
2433
2434 /*! \brief initialize the dsp algorithms and structures */
celliax_sound_dsp_set(struct celliax_pvt * p,int dsp_silence_threshold,int silence_suppression)2435 int celliax_sound_dsp_set(struct celliax_pvt *p, int dsp_silence_threshold,
2436 int silence_suppression)
2437 {
2438
2439 /* let asterisk dsp algorithms detect dtmf */
2440 if (p->dsp) {
2441 return 0;
2442 }
2443 if (option_debug > 1)
2444 DEBUGA_SOUND("alloc dsp \n", CELLIAX_P_LOG);
2445 p->dsp = ast_dsp_new();
2446 if (p->dsp) {
2447 if (silence_suppression) {
2448 ast_dsp_set_threshold(p->dsp, dsp_silence_threshold);
2449 DEBUGA_SOUND("set dsp_silence_threshold=%d\n", CELLIAX_P_LOG,
2450 dsp_silence_threshold);
2451 if (option_debug > 1)
2452 DEBUGA_SOUND("Detecting silence, I mean, voice\n", CELLIAX_P_LOG);
2453 ast_dsp_set_features(p->dsp, 0 | DSP_FEATURE_SILENCE_SUPPRESS);
2454 } else {
2455 if (option_debug > 1)
2456 DEBUGA_SOUND("WITHOUT SILENCE_SUPPRESS, Detecting inband dtmf with sw DSP\n",
2457 CELLIAX_P_LOG);
2458
2459 #ifdef ASTERISK_VERSION_1_6_0_1
2460 ast_dsp_set_features(p->dsp, 0 | DSP_FEATURE_DIGIT_DETECT);
2461 #else
2462 ast_dsp_set_features(p->dsp, 0 | DSP_FEATURE_DTMF_DETECT);
2463 #endif /* ASTERISK_VERSION_1_6_0_1 */
2464 }
2465
2466 /*
2467 if (ast_dsp_digitmode(p->dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF)) {
2468 ERRORA("ast_dsp_digitmode failed\n", CELLIAX_P_LOG);
2469 return -1;
2470 }
2471 */
2472 } else {
2473 ERRORA("ast_dsp_new failed\n", CELLIAX_P_LOG);
2474 return -1;
2475 }
2476 return 0;
2477 }
2478
2479 /*! \brief Read audio frames from interface */
celliax_sound_read(struct celliax_pvt * p)2480 struct ast_frame *celliax_sound_read(struct celliax_pvt *p)
2481 {
2482 struct ast_frame *f = NULL;
2483 #ifdef CELLIAX_ALSA
2484 f = alsa_read(p);
2485 #endif /* CELLIAX_ALSA */
2486 #ifdef CELLIAX_PORTAUDIO
2487 f = celliax_portaudio_read(p);
2488 #endif /* CELLIAX_PORTAUDIO */
2489
2490 return f;
2491 }
2492
2493 /*! \brief Send audio frame to interface */
celliax_sound_write(struct celliax_pvt * p,struct ast_frame * f)2494 int celliax_sound_write(struct celliax_pvt *p, struct ast_frame *f)
2495 {
2496 int ret = -1;
2497
2498 #ifdef CELLIAX_ALSA
2499 ret = alsa_write(p, f);
2500 #endif /* CELLIAX_ALSA */
2501 #ifdef CELLIAX_PORTAUDIO
2502 ret = celliax_portaudio_write(p, f);
2503 #endif /* CELLIAX_PORTAUDIO */
2504
2505 return ret;
2506 }
2507
2508 /*! \brief read an audio frame and tell if is "voice" (interpreted as incoming RING) */
celliax_sound_monitor(struct celliax_pvt * p)2509 int celliax_sound_monitor(struct celliax_pvt *p)
2510 {
2511 struct ast_frame *f;
2512 f = celliax_sound_read(p);
2513 if (f) {
2514 f = celliax_sound_dsp_analize(p, f, p->dsp_silence_threshold);
2515 if (f) {
2516 if (f->frametype == AST_FRAME_VOICE) {
2517 DEBUGA_SOUND("VOICE\n", CELLIAX_P_LOG);
2518 return CALLFLOW_INCOMING_RING;
2519 } else {
2520 return AST_STATE_DOWN;
2521 }
2522 }
2523 }
2524 return -1;
2525 }
2526
2527 /*!
2528 * \brief This thread runs during a call, and monitor the interface serial port for signaling, like hangup, caller id, etc
2529 *
2530 */
celliax_do_controldev_thread(void * data)2531 void *celliax_do_controldev_thread(void *data)
2532 {
2533 struct celliax_pvt *p = data;
2534 int res;
2535
2536 DEBUGA_SERIAL("In celliax_do_controldev_thread: started, p=%p\n", CELLIAX_P_LOG, p);
2537
2538 if (pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL)) {
2539 ERRORA("Unable to set cancel type to deferred\n", CELLIAX_P_LOG);
2540 return NULL;
2541 }
2542
2543 while (1) {
2544 int rt;
2545 time_t now_timestamp;
2546
2547 if (p->controldevprotocol == PROTOCOL_NO_SERIAL) {
2548 while (1) {
2549 usleep(10000);
2550 pthread_testcancel();
2551 }
2552 }
2553 #ifdef CELLIAX_CVM
2554 if (p->controldevprotocol == PROTOCOL_CVM_BUSMAIL) {
2555 usleep(p->cvm_celliax_serial_delay * 1000); //to get msecs
2556 } else {
2557 usleep(1000);
2558 }
2559
2560 #else
2561 usleep(1000);
2562 #endif /* CELLIAX_CVM */
2563
2564 pthread_testcancel();
2565 /* do not read from a dead controldev */
2566 if (p->controldev_dead) {
2567 DEBUGA_SERIAL("celliax_do_controldev_thread: device %s is dead\n", CELLIAX_P_LOG,
2568 p->controldevice_name);
2569 if (p->owner)
2570 celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
2571 return NULL;
2572 } else {
2573 pthread_testcancel();
2574 res = celliax_serial_read(p);
2575 pthread_testcancel();
2576 if (res == -1) {
2577 p->controldev_dead = 1;
2578 close(p->controldevfd);
2579 ERRORA("serial read failed, declaring %s dead\n", CELLIAX_P_LOG,
2580 p->controldevice_name);
2581 }
2582 }
2583
2584 pthread_testcancel();
2585 time(&now_timestamp);
2586 if ((now_timestamp - p->celliax_serial_synced_timestamp) > p->celliax_serial_synced_timestamp && !p->controldev_dead) { //TODO find a sensible period. 5min? in config?
2587 DEBUGA_SERIAL("Syncing Serial\n", CELLIAX_P_LOG);
2588 pthread_testcancel();
2589 rt = celliax_serial_sync(p);
2590 pthread_testcancel();
2591 if (rt) {
2592 p->controldev_dead = 1;
2593 close(p->controldevfd);
2594 ERRORA("serial sync failed, declaring %s dead\n", CELLIAX_P_LOG,
2595 p->controldevice_name);
2596 }
2597 pthread_testcancel();
2598 rt = celliax_serial_getstatus(p);
2599 pthread_testcancel();
2600 if (rt) {
2601 p->controldev_dead = 1;
2602 close(p->controldevfd);
2603 ERRORA("serial getstatus failed, declaring %s dead\n", CELLIAX_P_LOG,
2604 p->controldevice_name);
2605 }
2606
2607 }
2608 pthread_testcancel();
2609 }
2610 return NULL;
2611
2612 }
2613
celliax_serial_init(struct celliax_pvt * p,speed_t controldevice_speed)2614 int celliax_serial_init(struct celliax_pvt *p, speed_t controldevice_speed)
2615 {
2616 int fd;
2617 int rt;
2618 struct termios tp;
2619
2620 /* if there is a file descriptor, close it. But it is probably just an old value, so don't check for close success*/
2621 fd = p->controldevfd;
2622 if (fd) {
2623 close(fd);
2624 }
2625 /* open the serial port */
2626 #ifdef __CYGWIN__
2627 fd = open(p->controldevice_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
2628 sleep(1);
2629 close(fd);
2630 #endif /* __CYGWIN__ */
2631 fd = open(p->controldevice_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
2632 if (fd == -1) {
2633 DEBUGA_SERIAL("serial error: %s\n", CELLIAX_P_LOG, strerror(errno));
2634 p->controldevfd = fd;
2635 return -1;
2636 }
2637 /* flush it */
2638 rt = tcflush(fd, TCIFLUSH);
2639 if (rt == -1) {
2640 ERRORA("serial error: %s", CELLIAX_P_LOG, strerror(errno));
2641 }
2642 /* attributes */
2643 tp.c_cflag = B0 | CS8 | CLOCAL | CREAD | HUPCL;
2644 tp.c_iflag = IGNPAR;
2645 tp.c_cflag &= ~CRTSCTS;
2646 tp.c_oflag = 0;
2647 tp.c_lflag = 0;
2648 tp.c_cc[VMIN] = 1;
2649 tp.c_cc[VTIME] = 0;
2650 /* set controldevice_speed */
2651 rt = cfsetispeed(&tp, p->controldevice_speed);
2652 if (rt == -1) {
2653 ERRORA("serial error: %s", CELLIAX_P_LOG, strerror(errno));
2654 }
2655 rt = cfsetospeed(&tp, p->controldevice_speed);
2656 if (rt == -1) {
2657 ERRORA("serial error: %s", CELLIAX_P_LOG, strerror(errno));
2658 }
2659 /* set port attributes */
2660 if (tcsetattr(fd, TCSADRAIN, &tp) == -1) {
2661 ERRORA("serial error: %s", CELLIAX_P_LOG, strerror(errno));
2662 }
2663 rt = tcsetattr(fd, TCSANOW, &tp);
2664 if (rt == -1) {
2665 ERRORA("serial error: %s", CELLIAX_P_LOG, strerror(errno));
2666 }
2667 unsigned int status = 0;
2668 #ifndef __CYGWIN__
2669 ioctl(fd, TIOCMGET, &status);
2670 status |= TIOCM_DTR; /* Set DTR high */
2671 status &= ~TIOCM_RTS; /* Set RTS low */
2672 ioctl(fd, TIOCMSET, &status);
2673 ioctl(fd, TIOCMGET, &status);
2674 unsigned int flags = TIOCM_DTR;
2675 ioctl(fd, TIOCMBIS, &flags);
2676 flags = TIOCM_RTS;
2677 ioctl(fd, TIOCMBIC, &flags);
2678 ioctl(fd, TIOCMGET, &status);
2679 #else /* __CYGWIN__ */
2680 ioctl(fd, TIOCMGET, &status);
2681 status |= TIOCM_DTR; /* Set DTR high */
2682 status &= ~TIOCM_RTS; /* Set RTS low */
2683 ioctl(fd, TIOCMSET, &status);
2684 #endif /* __CYGWIN__ */
2685 p->controldevfd = fd;
2686 DEBUGA_SERIAL("Syncing Serial\n", CELLIAX_P_LOG);
2687 rt = celliax_serial_sync(p);
2688 if (rt == -1) {
2689 ERRORA("Serial init error\n", CELLIAX_P_LOG);
2690 return -1;
2691 }
2692 return (fd);
2693 }
2694
celliax_serial_sync(struct celliax_pvt * p)2695 int celliax_serial_sync(struct celliax_pvt *p)
2696 {
2697 if (p->controldevprotocol == PROTOCOL_AT)
2698 return celliax_serial_sync_AT(p);
2699 #ifdef CELLIAX_FBUS2
2700 if (p->controldevprotocol == PROTOCOL_FBUS2)
2701 return celliax_serial_sync_FBUS2(p);
2702 #endif /* CELLIAX_FBUS2 */
2703 #ifdef CELLIAX_CVM
2704 if (p->controldevprotocol == PROTOCOL_CVM_BUSMAIL)
2705 return celliax_serial_sync_CVM_BUSMAIL(p);
2706 #endif /* CELLIAX_CVM */
2707
2708 return -1;
2709 }
2710
celliax_serial_getstatus(struct celliax_pvt * p)2711 int celliax_serial_getstatus(struct celliax_pvt *p)
2712 {
2713 if (p->controldevprotocol == PROTOCOL_AT)
2714 return celliax_serial_getstatus_AT(p);
2715 #ifdef CELLIAX_FBUS2
2716 if (p->controldevprotocol == PROTOCOL_FBUS2)
2717 return celliax_serial_getstatus_FBUS2(p);
2718 #endif /* CELLIAX_FBUS2 */
2719
2720 #ifdef CELLIAX_CVM
2721 if (p->controldevprotocol == PROTOCOL_CVM_BUSMAIL)
2722 return celliax_serial_getstatus_CVM_BUSMAIL(p);
2723 #endif /* CELLIAX_CVM */
2724 return -1;
2725 }
2726
celliax_serial_read(struct celliax_pvt * p)2727 int celliax_serial_read(struct celliax_pvt *p)
2728 {
2729 if (p->controldevprotocol == PROTOCOL_AT)
2730 return celliax_serial_read_AT(p, 0, 100000, 0, NULL, 1); // a 10th of a second timeout
2731 #ifdef CELLIAX_FBUS2
2732 if (p->controldevprotocol == PROTOCOL_FBUS2)
2733 return celliax_serial_read_FBUS2(p);
2734 #endif /* CELLIAX_FBUS2 */
2735 #ifdef CELLIAX_CVM
2736 if (p->controldevprotocol == PROTOCOL_CVM_BUSMAIL)
2737 return celliax_serial_read_CVM_BUSMAIL(p);
2738 #endif /* CELLIAX_CVM */
2739 return -1;
2740 }
2741
celliax_serial_hangup(struct celliax_pvt * p)2742 int celliax_serial_hangup(struct celliax_pvt *p)
2743 {
2744 if (p->controldevprotocol == PROTOCOL_AT)
2745 return celliax_serial_hangup_AT(p);
2746 #ifdef CELLIAX_FBUS2
2747 if (p->controldevprotocol == PROTOCOL_FBUS2)
2748 return celliax_serial_hangup_FBUS2(p);
2749 #endif /* CELLIAX_FBUS2 */
2750 #ifdef CELLIAX_CVM
2751 if (p->controldevprotocol == PROTOCOL_CVM_BUSMAIL)
2752 return celliax_serial_hangup_CVM_BUSMAIL(p);
2753 #endif /* CELLIAX_CVM */
2754 return -1;
2755 }
2756
celliax_serial_answer(struct celliax_pvt * p)2757 int celliax_serial_answer(struct celliax_pvt *p)
2758 {
2759 if (p->controldevprotocol == PROTOCOL_AT)
2760 return celliax_serial_answer_AT(p);
2761 #ifdef CELLIAX_FBUS2
2762 if (p->controldevprotocol == PROTOCOL_FBUS2)
2763 return celliax_serial_answer_FBUS2(p);
2764 #endif /* CELLIAX_FBUS2 */
2765 #ifdef CELLIAX_CVM
2766 if (p->controldevprotocol == PROTOCOL_CVM_BUSMAIL)
2767 return celliax_serial_answer_CVM_BUSMAIL(p);
2768 #endif /* CELLIAX_CVM */
2769 return -1;
2770 }
2771
celliax_serial_config(struct celliax_pvt * p)2772 int celliax_serial_config(struct celliax_pvt *p)
2773 {
2774 if (p->controldevprotocol == PROTOCOL_AT)
2775 return celliax_serial_config_AT(p);
2776 #ifdef CELLIAX_FBUS2
2777 if (p->controldevprotocol == PROTOCOL_FBUS2)
2778 return celliax_serial_config_FBUS2(p);
2779 #endif /* CELLIAX_FBUS2 */
2780 #ifdef CELLIAX_CVM
2781 if (p->controldevprotocol == PROTOCOL_CVM_BUSMAIL)
2782 return celliax_serial_config_CVM_BUSMAIL(p);
2783 #endif /* CELLIAX_CVM */
2784 return -1;
2785 }
2786
celliax_serial_monitor(struct celliax_pvt * p)2787 int celliax_serial_monitor(struct celliax_pvt *p)
2788 {
2789 if (p->controldevprotocol == PROTOCOL_AT)
2790 return celliax_serial_read_AT(p, 0, 100000, 0, NULL, 1); // a 10th of a second timeout
2791 #ifdef CELLIAX_FBUS2
2792 if (p->controldevprotocol == PROTOCOL_FBUS2)
2793 return celliax_serial_read_FBUS2(p);
2794 #endif /* CELLIAX_FBUS2 */
2795 #ifdef CELLIAX_CVM
2796 if (p->controldevprotocol == PROTOCOL_CVM_BUSMAIL)
2797 return celliax_serial_read_CVM_BUSMAIL(p);
2798 #endif /* CELLIAX_CVM */
2799 return -1;
2800 }
2801
2802 /************************************************/
2803
2804 /* LUIGI RIZZO's magic */
2805 /*
2806 * store the boost factor
2807 */
2808 #ifdef ASTERISK_VERSION_1_6_0
celliax_store_boost(const char * s,double * boost)2809 void celliax_store_boost(const char *s, double *boost)
2810 #else
2811 void celliax_store_boost(char *s, double *boost)
2812 #endif /* ASTERISK_VERSION_1_6_0 */
2813 {
2814 struct celliax_pvt *p = NULL;
2815
2816 if (sscanf(s, "%lf", boost) != 1) {
2817 ERRORA("invalid boost <%s>\n", CELLIAX_P_LOG, s);
2818 return;
2819 }
2820 if (*boost < -BOOST_MAX) {
2821 WARNINGA("boost %s too small, using %d\n", CELLIAX_P_LOG, s, -BOOST_MAX);
2822 *boost = -BOOST_MAX;
2823 } else if (*boost > BOOST_MAX) {
2824 WARNINGA("boost %s too large, using %d\n", CELLIAX_P_LOG, s, BOOST_MAX);
2825 *boost = BOOST_MAX;
2826 }
2827 *boost = exp(log(10) * *boost / 20) * BOOST_SCALE;
2828 if (option_debug > 1)
2829 DEBUGA_SOUND("setting boost %s to %f\n", CELLIAX_P_LOG, s, *boost);
2830 }
2831
celliax_serial_call(struct celliax_pvt * p,char * dstr)2832 int celliax_serial_call(struct celliax_pvt *p, char *dstr)
2833 {
2834 if (p->controldevprotocol == PROTOCOL_AT)
2835 return celliax_serial_call_AT(p, dstr);
2836 #ifdef CELLIAX_FBUS2
2837 if (p->controldevprotocol == PROTOCOL_FBUS2)
2838 return celliax_serial_call_FBUS2(p, dstr);
2839 #endif /* CELLIAX_FBUS2 */
2840 if (p->controldevprotocol == PROTOCOL_NO_SERIAL)
2841 return 0;
2842 #ifdef CELLIAX_CVM
2843 if (p->controldevprotocol == PROTOCOL_CVM_BUSMAIL)
2844 return celliax_serial_call_CVM_BUSMAIL(p, dstr);
2845 #endif /* CELLIAX_CVM */
2846 return -1;
2847 }
2848
2849 /*
2850 * returns a pointer to the descriptor with the given name
2851 */
celliax_console_find_desc(char * dev)2852 struct celliax_pvt *celliax_console_find_desc(char *dev)
2853 {
2854 struct celliax_pvt *p;
2855
2856 for (p = celliax_iflist; p && strcmp(p->name, dev) != 0; p = p->next);
2857 if (p == NULL)
2858 WARNINGA("could not find <%s>\n", CELLIAX_P_LOG, dev);
2859
2860 return p;
2861 }
2862
celliax_console_playback_boost(int fd,int argc,char * argv[])2863 int celliax_console_playback_boost(int fd, int argc, char *argv[])
2864 {
2865 struct celliax_pvt *p = celliax_console_find_desc(celliax_console_active);
2866
2867 if (argc > 2)
2868 return RESULT_SHOWUSAGE;
2869 if (!p) {
2870 ast_cli(fd,
2871 "No \"current\" celliax_console for playback_boost, please enter 'help celliax_console'\n");
2872 return RESULT_SUCCESS;
2873 }
2874
2875 if (argc == 1) {
2876 ast_cli(fd, "playback_boost on the active celliax_console, that is [%s], is: %5.1f\n",
2877 celliax_console_active,
2878 20 * log10(((double) p->playback_boost / (double) BOOST_SCALE)));
2879 } else if (argc == 2) {
2880 celliax_store_boost(argv[1], &p->playback_boost);
2881
2882 ast_cli(fd,
2883 "playback_boost on the active celliax_console, that is [%s], is now: %5.1f\n",
2884 celliax_console_active,
2885 20 * log10(((double) p->playback_boost / (double) BOOST_SCALE)));
2886 }
2887
2888 return RESULT_SUCCESS;
2889 }
2890
celliax_console_capture_boost(int fd,int argc,char * argv[])2891 int celliax_console_capture_boost(int fd, int argc, char *argv[])
2892 {
2893 struct celliax_pvt *p = celliax_console_find_desc(celliax_console_active);
2894
2895 if (argc > 2)
2896 return RESULT_SHOWUSAGE;
2897 if (!p) {
2898 ast_cli(fd,
2899 "No \"current\" celliax_console for capture_boost, please enter 'help celliax_console'\n");
2900 return RESULT_SUCCESS;
2901 }
2902
2903 if (argc == 1) {
2904 ast_cli(fd, "capture_boost on the active celliax_console, that is [%s], is: %5.1f\n",
2905 celliax_console_active,
2906 20 * log10(((double) p->capture_boost / (double) BOOST_SCALE)));
2907 } else if (argc == 2) {
2908 celliax_store_boost(argv[1], &p->capture_boost);
2909
2910 ast_cli(fd,
2911 "capture_boost on the active celliax_console, that is [%s], is now: %5.1f\n",
2912 celliax_console_active,
2913 20 * log10(((double) p->capture_boost / (double) BOOST_SCALE)));
2914 }
2915
2916 return RESULT_SUCCESS;
2917 }
2918
celliax_console_echo(int fd,int argc,char * argv[])2919 int celliax_console_echo(int fd, int argc, char *argv[])
2920 {
2921 struct celliax_pvt *p = celliax_console_find_desc(celliax_console_active);
2922
2923 if (argc != 3 && argc != 1)
2924 return RESULT_SHOWUSAGE;
2925 if (!p) {
2926 ast_cli(fd,
2927 "No \"current\" celliax_console for celliax_echo, please enter 'help celliax_console'\n");
2928 return RESULT_SUCCESS;
2929 }
2930
2931 if (argc == 1) {
2932 ast_cli(fd,
2933 "On the active celliax_console, that is [%s], speexecho and speexpreprocess are: %d and %d\n",
2934 celliax_console_active, p->speexecho, p->speexpreprocess);
2935 } else if (argc == 3) {
2936 sscanf(argv[1], "%d", &p->speexecho);
2937 sscanf(argv[2], "%d", &p->speexpreprocess);
2938 ast_cli(fd,
2939 "On the active celliax_console, that is [%s], speexecho and speexpreprocess are NOW: %d and %d\n",
2940 celliax_console_active, p->speexecho, p->speexpreprocess);
2941 }
2942
2943 return RESULT_SUCCESS;
2944 }
2945
2946 #ifndef ASTERISK_VERSION_1_6_0
celliax_console_hangup(int fd,int argc,char * argv[])2947 int celliax_console_hangup(int fd, int argc, char *argv[])
2948 {
2949 struct celliax_pvt *p = celliax_console_find_desc(celliax_console_active);
2950
2951 if (argc != 1)
2952 return RESULT_SHOWUSAGE;
2953 if (!p) {
2954 ast_cli(fd,
2955 "No \"current\" celliax_console for hanging up, please enter 'help celliax_console'\n");
2956 return RESULT_SUCCESS;
2957 }
2958 if (!p->owner) {
2959 ast_cli(fd, "No call to hangup on the active celliax_console, that is [%s]\n",
2960 celliax_console_active);
2961 return RESULT_FAILURE;
2962 }
2963 if (p->owner)
2964 ast_queue_hangup(p->owner);
2965 return RESULT_SUCCESS;
2966 }
2967 #else /* ASTERISK_VERSION_1_6_0 */
celliax_console_hangup(struct ast_cli_entry * e,int cmd,struct ast_cli_args * a)2968 char *celliax_console_hangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2969 {
2970 struct celliax_pvt *p = celliax_console_find_desc(celliax_console_active);
2971
2972
2973 switch (cmd) {
2974 case CLI_INIT:
2975 e->command = "celliax hangup";
2976 e->usage =
2977 "Usage: celliax hangup\n"
2978 " Hangup a call on the celliax channel.\n";
2979
2980 return NULL;
2981 case CLI_GENERATE:
2982 return NULL;
2983 }
2984
2985 if (a->argc != 2)
2986 return CLI_SHOWUSAGE;
2987 if (!p) {
2988 ast_cli(a->fd,
2989 "No \"current\" celliax_console for hanging up, please enter 'help celliax_console'\n");
2990 return CLI_SUCCESS;
2991 }
2992 if (!p->owner) {
2993 ast_cli(a->fd, "No call to hangup on the active celliax_console, that is [%s]\n",
2994 celliax_console_active);
2995 return CLI_FAILURE;
2996 }
2997 if (p->owner)
2998 ast_queue_hangup(p->owner);
2999 return CLI_SUCCESS;
3000 }
3001
3002 #endif /* ASTERISK_VERSION_1_6_0 */
celliax_console_sendsms(int fd,int argc,char * argv[])3003 int celliax_console_sendsms(int fd, int argc, char *argv[])
3004 {
3005 char *s = NULL;
3006 char *s1 = NULL;
3007 char command[512];
3008
3009 if (argc != 3)
3010 return RESULT_SHOWUSAGE;
3011
3012 s = argv[1];
3013 s1 = argv[2];
3014
3015 memset(command, 0, sizeof(command));
3016
3017 sprintf(command, "%s|%s|", s, s1);
3018
3019 celliax_sendsms(NULL, (void *) &command);
3020
3021 return RESULT_SUCCESS;
3022 }
3023
celliax_console_dial(int fd,int argc,char * argv[])3024 int celliax_console_dial(int fd, int argc, char *argv[])
3025 {
3026 char *s = NULL;
3027 struct celliax_pvt *p = celliax_console_find_desc(celliax_console_active);
3028
3029 if (argc != 2)
3030 return RESULT_SHOWUSAGE;
3031 if (!p) {
3032 ast_cli(fd,
3033 "No \"current\" celliax_console for dialing, please enter 'help celliax_console'\n");
3034 return RESULT_SUCCESS;
3035 }
3036
3037 if (p->owner) { /* already in a call */
3038 int i;
3039 struct ast_frame f = { AST_FRAME_DTMF, 0 };
3040
3041 s = argv[1];
3042 /* send the string one char at a time */
3043 for (i = 0; i < strlen(s); i++) {
3044 f.subclass = s[i];
3045 ast_queue_frame(p->owner, &f);
3046 }
3047 return RESULT_SUCCESS;
3048 } else
3049 ast_cli(fd,
3050 "No call in which to dial on the \"current\" celliax_console, that is [%s]\n",
3051 celliax_console_active);
3052 if (s)
3053 free(s);
3054 return RESULT_SUCCESS;
3055 }
3056
celliax_console_set_active(int fd,int argc,char * argv[])3057 int celliax_console_set_active(int fd, int argc, char *argv[])
3058 {
3059 if (argc == 1)
3060 ast_cli(fd,
3061 "\"current\" celliax_console is [%s]\n Enter 'celliax_console show' to see the available interfaces.\n Enter 'celliax_console interfacename' to change the \"current\" celliax_console.\n",
3062 celliax_console_active);
3063 else if (argc != 2)
3064 return RESULT_SHOWUSAGE;
3065 else {
3066 struct celliax_pvt *p;
3067 if (strcmp(argv[1], "show") == 0) {
3068 ast_cli(fd, "Available interfaces:\n");
3069 for (p = celliax_iflist; p; p = p->next)
3070 ast_cli(fd, " [%s]\n", p->name);
3071 return RESULT_SUCCESS;
3072 }
3073 p = celliax_console_find_desc(argv[1]);
3074 if (p == NULL)
3075 ast_cli(fd, "Interface [%s] do not exists!\n", argv[1]);
3076 else {
3077 celliax_console_active = p->name;
3078 ast_cli(fd, "\"current\" celliax_console is now: [%s]\n", argv[1]);
3079 }
3080 }
3081 return RESULT_SUCCESS;
3082 }
3083
celliax_console_celliax(int fd,int argc,char * argv[])3084 int celliax_console_celliax(int fd, int argc, char *argv[])
3085 {
3086 return RESULT_SHOWUSAGE;
3087 }
3088
3089 #ifdef ASTERISK_VERSION_1_4
3090 #ifndef AST_MODULE
3091 #define AST_MODULE "chan_celliax"
3092 #endif
3093 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Celliax, Audio-Serial Driver");
3094 #endif /* ASTERISK_VERSION_1_4 */
3095