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