Add -lncurses to LDD flags
[lcr.git] / chan_lcr.c
index ee221b7..a396013 100644 (file)
@@ -238,6 +238,8 @@ void chan_lcr_log(int type, const char *file, int line, const char *function, st
        char ast_text[128] = "NULL";
        va_list args;
 
+       if (!option_debug) return;
+
        ast_mutex_lock(&log_lock);
 
        va_start(args,fmt);
@@ -255,8 +257,8 @@ void chan_lcr_log(int type, const char *file, int line, const char *function, st
 #endif
        ast_text[sizeof(ast_text)-1] = '\0';
 
-//     ast_log(type, file, line, function, "[call=%s ast=%s] %s", call_text, ast_text, buffer);
-       printf("[call=%s ast=%s line=%d] %s", call_text, ast_text, line, buffer);
+       ast_log(type, file, line, function, "[call=%s ast=%s] %s", call_text, ast_text, buffer);
+//     printf("[call=%s ast=%s line=%d] %s", call_text, ast_text, line, buffer);
 
        ast_mutex_unlock(&log_lock);
 }
@@ -331,6 +333,10 @@ struct chan_call *alloc_call(void)
        }
        fcntl((*callp)->pipe[0], F_SETFL, O_NONBLOCK);
        CDEBUG(*callp, NULL, "Call instance allocated.\n");
+
+       /* unset dtmf (default, use option 'd' to enable) */
+       (*callp)->dsp_dtmf = 0;
+
        return *callp;
 }
 
@@ -426,13 +432,13 @@ void apply_opt(struct chan_call *call, char *data)
                                send_message(MESSAGE_NOTIFY, call->ref, &newparam);
                        }
                        break;
-               case 'n':
+               case 'D':
                        if (opt[1] != '\0') {
-                               CERROR(call, call->ast, "Option 'n' (no DTMF) expects no parameter.\n", opt);
+                               CERROR(call, call->ast, "Option 'D' (DTMF) expects no parameter.\n", opt);
                                break;
                        }
-                       CDEBUG(call, call->ast, "Option 'n' (no DTMF).\n");
-                       call->dsp_dtmf = 0;
+                       CDEBUG(call, call->ast, "Option 'D' (DTMF).\n");
+                       call->dsp_dtmf = 1;
                        break;
 #if 0
                case 'c':
@@ -513,43 +519,22 @@ void apply_opt(struct chan_call *call, char *data)
                        break;
 #endif
                case 'f':
-                       if (opt[1] == '\0') {
-                               CERROR(call, call->ast, "Option 'f' (faxdetect) expects parameter.\n", opt);
+                       if (opt[1] != '\0') {
+                               CERROR(call, call->ast, "Option 'f' (faxdetect) expects no parameter.\n", opt);
                                break;
                        }
-                       call->faxdetect=atoi(opt+1);
-                       if (!call->dsp)
-                               call->dsp=ast_dsp_new();
-                       if (call->dsp) {
-                               #ifdef LCR_FOR_CALLWEAVER
-                               ast_dsp_set_features(call->dsp, DSP_FEATURE_DTMF_DETECT| DSP_FEATURE_FAX_CNG_DETECT);
-                               #endif
-                               #ifdef LCR_FOR_ASTERISK
-                               #ifdef DSP_FEATURE_DTMF_DETECT
-                               ast_dsp_set_features(call->dsp, DSP_FEATURE_DTMF_DETECT| DSP_FEATURE_FAX_DETECT);
-                               #else
-                               ast_dsp_set_features(call->dsp, DSP_FEATURE_DIGIT_DETECT| DSP_FEATURE_FAX_DETECT);
-                               #endif
-
-                               #endif
-                               if (!call->trans) {
-                                       #ifdef LCR_FOR_CALLWEAVER
-                                       call->trans=ast_translator_build_path(AST_FORMAT_SLINEAR, 8000, (options.law=='a')?AST_FORMAT_ALAW:AST_FORMAT_ULAW, 8000);
-                                       #endif
-                                       #ifdef LCR_FOR_ASTERISK
-                                       #if ASTERISK_VERSION_NUM < 100000
-                                       call->trans=ast_translator_build_path(AST_FORMAT_SLINEAR, (options.law=='a')?AST_FORMAT_ALAW:AST_FORMAT_ULAW);
-                                       #else
-                                       struct ast_format src;
-                                       struct ast_format dst;
-                                       ast_format_set(&dst, AST_FORMAT_SLINEAR, 0);
-                                       ast_format_set(&dst,(options.law=='a')?AST_FORMAT_ALAW:AST_FORMAT_ULAW , 0);
-                                       call->trans=ast_translator_build_path(&dst, &src);
-                                       #endif
-                                       #endif
-                               }
+                       call->faxdetect = 1;
+                       call->dsp_dtmf = 0;
+                       CDEBUG(call, call->ast, "Option 'f' (faxdetect).\n");
+                       break;
+               case 'a':
+                       if (opt[1] != '\0') {
+                               CERROR(call, call->ast, "Option 'a' (asterisk DTMF) expects no parameter.\n", opt);
+                               break;
                        }
-                       CDEBUG(call, call->ast, "Option 'f' (faxdetect) with config '%s'.\n", call->faxdetect);
+                       call->ast_dsp = 1;
+                       call->dsp_dtmf = 0;
+                       CDEBUG(call, call->ast, "Option 'a' (Asterisk DTMF detection).\n");
                        break;
                case 'r':
                        if (opt[1] != '\0') {
@@ -604,6 +589,40 @@ void apply_opt(struct chan_call *call, char *data)
                        CERROR(call, call->ast, "Option '%s' unknown.\n", opt);
                }
        }
+
+       if (call->faxdetect || call->ast_dsp) {
+               if (!call->dsp)
+                       call->dsp=ast_dsp_new();
+               if (call->dsp) {
+                       #ifdef LCR_FOR_CALLWEAVER
+                       ast_dsp_set_features(call->dsp, DSP_FEATURE_DTMF_DETECT | ((call->faxdetect) ? DSP_FEATURE_FAX_CNG_DETECT : 0));
+                       #endif
+                       #ifdef LCR_FOR_ASTERISK
+                       #ifdef DSP_FEATURE_DTMF_DETECT
+                       ast_dsp_set_features(call->dsp, DSP_FEATURE_DTMF_DETECT | ((call->faxdetect) ? DSP_FEATURE_FAX_DETECT : 0));
+                       #else
+                       ast_dsp_set_features(call->dsp, DSP_FEATURE_DIGIT_DETECT | ((call->faxdetect) ? DSP_FEATURE_FAX_DETECT : 0));
+                       #endif
+
+                       #endif
+                       if (!call->trans) {
+                               #ifdef LCR_FOR_CALLWEAVER
+                               call->trans=ast_translator_build_path(AST_FORMAT_SLINEAR, 8000, (options.law=='a')?AST_FORMAT_ALAW:AST_FORMAT_ULAW, 8000);
+                               #endif
+                               #ifdef LCR_FOR_ASTERISK
+                               #if ASTERISK_VERSION_NUM < 100000
+                               call->trans=ast_translator_build_path(AST_FORMAT_SLINEAR, (options.law=='a')?AST_FORMAT_ALAW:AST_FORMAT_ULAW);
+//                             #else
+//                             struct ast_format src;
+//                             struct ast_format dst;
+//                             ast_format_set(&dst, AST_FORMAT_SLINEAR, 0);
+//                             ast_format_set(&dst,(options.law=='a')?AST_FORMAT_ALAW:AST_FORMAT_ULAW , 0);
+//                             call->trans=ast_translator_build_path(&dst, &src);
+                               #endif
+                               #endif
+                       }
+               }
+       }
 }
 
 /*
@@ -633,8 +652,6 @@ static void send_setup_to_lcr(struct chan_call *call)
                strncpy(newparam.setup.dialinginfo.keypad, call->dialstring, sizeof(newparam.setup.dialinginfo.keypad)-1);
        else
                strncpy(newparam.setup.dialinginfo.id, call->dialstring, sizeof(newparam.setup.dialinginfo.id)-1);
-       if (!!strcmp(call->interface, "pbx"))
-               strncpy(newparam.setup.dialinginfo.interfaces, call->interface, sizeof(newparam.setup.dialinginfo.interfaces)-1);
        newparam.setup.callerinfo.itype = INFO_ITYPE_CHAN;
        newparam.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
        strncpy(newparam.setup.callerinfo.display, call->display, sizeof(newparam.setup.callerinfo.display)-1);
@@ -919,8 +936,12 @@ CDEBUG(call, ast, "Got 'sending complete', but extension '%s' will not match at
 static void lcr_in_setup(struct chan_call *call, int message_type, union parameter *param)
 {
        struct ast_channel *ast;
+#ifdef AST_1_8_OR_HIGHER
        struct ast_party_redirecting *ast_redir;
        struct ast_party_caller *ast_caller;
+#else
+       struct ast_callerid *ast_caller;
+#endif
 #if ASTERISK_VERSION_NUM >= 110000
        struct ast_party_redirecting s_ast_redir;
        struct ast_party_caller s_ast_caller;
@@ -944,9 +965,13 @@ static void lcr_in_setup(struct chan_call *call, int message_type, union paramet
        #endif
 
 #if ASTERISK_VERSION_NUM < 110000
+#ifdef AST_1_8_OR_HIGHER
        ast_redir = &ast->redirecting;
        ast_caller = &ast->caller;
 #else
+       ast_caller = &ast->cid;
+#endif
+#else
        ast_redir = &s_ast_redir;
        ast_caller = &s_ast_caller;
 #endif
@@ -981,8 +1006,8 @@ static void lcr_in_setup(struct chan_call *call, int message_type, union paramet
                strncpy(ast->context, param->setup.callerinfo.interface, AST_MAX_CONTEXT-1);
 #else
                ast_channel_exten_set(ast, param->setup.dialinginfo.id);
-       if (param->setup.context[0])
-               ast_channel_context_set(ast, param->setup.context);
+       if (param->setup.dialinginfo.context[0])
+               ast_channel_context_set(ast, param->setup.dialinginfo.context);
        else
                ast_channel_context_set(ast, param->setup.callerinfo.interface);
 #endif
@@ -1393,7 +1418,9 @@ static void lcr_in_information(struct chan_call *call, int message_type, union p
 #if ASTERISK_VERSION_NUM < 110000
                strncat(ast->exten, param->information.id, AST_MAX_EXTENSION-1);
 #else
-               ast_channel_exten_set(ast, param->information.id);
+               char *tmp[AST_MAX_EXTENSION];
+               snprintf(tmp,AST_MAX_EXTENSION,"%s%s",ast_channel_exten(ast),param->information.id);
+               ast_channel_exten_set(ast, tmp);
 #endif
                lcr_start_pbx(call, ast, param->information.sending_complete);
                return;
@@ -1419,8 +1446,21 @@ static void lcr_in_information(struct chan_call *call, int message_type, union p
 
        /* use bridge to forware message not supported by asterisk */
        if (call->state == CHAN_LCR_STATE_CONNECT) {
-               CDEBUG(call, call->ast, "Call is connected, bridging.\n");
-               bridge_message_if_bridged(call, message_type, param);
+               if (call->bridge_call) {
+                       CDEBUG(call, call->ast, "Call is connected, bridging.\n");
+                       bridge_message_if_bridged(call, message_type, param);
+               } else {
+                       if (call->dsp_dtmf) {
+                               if (!wake_global) {
+                                       wake_global = 1;
+                                       char byte = 0;
+                                       int rc;
+                                       rc = write(wake_pipe[1], &byte, 1);
+                               }
+                               strncat(call->queue_string, param->information.id, sizeof(call->queue_string)-1);
+                       } else
+                               CDEBUG(call, call->ast, "LCR's DTMF detection is disabled.\n");
+               }
        }
 }
 
@@ -1497,7 +1537,7 @@ void lcr_in_dtmf(struct chan_call *call, int val)
                return;
 
        if (!call->dsp_dtmf) {
-               CDEBUG(call, call->ast, "Recognised DTMF digit '%c', but ignoring. This is fixed in later mISDN driver.\n", val);
+               CDEBUG(call, call->ast, "Recognised DTMF digit '%c' by LCR, but ignoring. (disabled by option)\n", val);
                return;
        }
 
@@ -1540,8 +1580,6 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
                        /* set ref */
                        call->ref = ref;
                        call->ref_was_assigned = 1;
-                       /* set dtmf (default, use option 'n' to disable */
-                       call->dsp_dtmf = 1;
                        /* wait for setup (or release from asterisk) */
                } else {
                        /* new ref, as requested from this remote application */
@@ -1555,8 +1593,6 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
                        /* store new ref */
                        call->ref = ref;
                        call->ref_was_assigned = 1;
-                       /* set dtmf (default, use option 'n' to disable */
-                       call->dsp_dtmf = 1;
                        /* send pending setup info */
                        if (call->state == CHAN_LCR_STATE_OUT_PREPARE)
                                send_setup_to_lcr(call);
@@ -1572,6 +1608,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
                                return 0;
                        }
                }
+               send_message(MESSAGE_ENABLEKEYPAD, call->ref, &newparam);
                return 0;
        }
 
@@ -1651,6 +1688,10 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
                rc = write(call->pipe[1], param->traffic.data, param->traffic.len);
                break;
 
+               case MESSAGE_DTMF:
+               lcr_in_dtmf(call, param->dtmf);
+               break;
+
                default:
                CDEBUG(call, call->ast, "Message %d from LCR unhandled.\n", message_type);
                break;
@@ -1996,8 +2037,10 @@ struct ast_channel *lcr_request(const char *type, int format, void *data, int *c
        char exten[256], *dial, *interface, *opt;
        struct ast_channel *ast;
        struct chan_call *call;
+#ifdef AST_1_8_OR_HIGHER
        const struct ast_party_redirecting *req_redir;
        const struct ast_party_caller *req_caller;
+#endif
 
        ast_mutex_lock(&chan_lock);
        CDEBUG(NULL, NULL, "Received request from Asterisk. (data=%s)\n", (char *)data);
@@ -2041,8 +2084,10 @@ struct ast_channel *lcr_request(const char *type, int format, void *data, int *c
 #if ASTERISK_VERSION_NUM < 110000
        ast->tech = &lcr_tech;
        ast->tech_pvt = (void *)1L; // set pointer or asterisk will not call
+#ifdef AST_1_8_OR_HIGHER
        req_redir = &requestor->redirecting;
        req_caller = &requestor->caller;
+#endif
 #else
        ast_channel_tech_set(ast, &lcr_tech);
        ast_channel_tech_pvt_set(ast, (void *)1L); // set pointer or asterisk will not call
@@ -2382,6 +2427,7 @@ static int lcr_call(struct ast_channel *ast, char *dest, int timeout)
        /* send MESSAGE_NEWREF */
        memset(&newparam, 0, sizeof(union parameter));
        newparam.newref.direction = 0; /* request from app */
+       strncpy(newparam.newref.interface, call->interface, sizeof(newparam.newref.interface) - 1);
        send_message(MESSAGE_NEWREF, 0, &newparam);
 
        /* set hdlc if capability requires hdlc */
@@ -2738,12 +2784,13 @@ static int lcr_write(struct ast_channel *ast, struct ast_frame *fr)
 #else
        call = ast_channel_tech_pvt(ast);
 #endif
-       if (!call) {
+       if (!call || !call->ref) {
+               /* drop the frame, if no ref exists, but return successfull delivery, or asterisk will abort connection */
                ast_mutex_unlock(&chan_lock);
                if (f != fr) {
                        ast_frfree(f);
                }
-               return -1;
+               return 0;
        }
        len = f->samples;
        p = *((unsigned char **)&(f->data));
@@ -2769,6 +2816,7 @@ static struct ast_frame *lcr_read(struct ast_channel *ast)
 {
        struct chan_call *call;
        int len = 0;
+       struct ast_frame *f = NULL;
 
        ast_mutex_lock(&chan_lock);
 #if ASTERISK_VERSION_NUM < 110000
@@ -2848,8 +2896,21 @@ static struct ast_frame *lcr_read(struct ast_channel *ast)
        }
        call->read_fr.delivery = ast_tv(0,0);
        *((unsigned char **)&(call->read_fr.data)) = call->read_buff;
+
+       if (call->dsp)
+               f = ast_dsp_process(ast, call->dsp, &call->read_fr);
+       if (f && f->frametype == AST_FRAME_DTMF)
+#ifdef AST_1_8_OR_HIGHER
+               CDEBUG(call, ast, "Asterisk detected inband DTMF: %c.\n", f->subclass.integer);
+#else
+               CDEBUG(call, ast, "Asterisk detected inband DTMF: %c.\n", f->subclass);
+#endif
+
        ast_mutex_unlock(&chan_lock);
 
+       if (f && f->frametype == AST_FRAME_DTMF)
+               return f;
+
        return &call->read_fr;
 }
 
@@ -2953,6 +3014,15 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
                        break;
                case AST_CONTROL_PROGRESS:
                        CDEBUG(call, ast, "Received indicate AST_CONTROL_PROGRESS from Asterisk.\n");
+                       if (call->state == CHAN_LCR_STATE_IN_SETUP
+                        || call->state == CHAN_LCR_STATE_IN_DIALING) {
+                               CDEBUG(call, ast, "Changing to proceeding state, because no more dialing possible.\n");
+                               /* send message to lcr */
+                               memset(&newparam, 0, sizeof(union parameter));
+                               send_message(MESSAGE_PROCEEDING, call->ref, &newparam);
+                               /* change state */
+                               call->state = CHAN_LCR_STATE_IN_PROCEEDING;
+                       }
                        /* request bchannel */
                        CDEBUG(call, ast, "Requesting audio path.\n");
                        memset(&newparam, 0, sizeof(union parameter));
@@ -3095,6 +3165,9 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
        struct ast_frame        *f;
        int                     bridge_id;
 
+/* bridge is disabled, because there is currerntly no concept to bridge mISDN channels */
+return AST_BRIDGE_FAILED;
+
        CDEBUG(NULL, NULL, "Received bridging request from Asterisk.\n");
 
        carr[0] = ast1;
@@ -3123,18 +3196,11 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
        /* get bridge id and join */
        bridge_id = new_bridge_id();
 
-#if 0
        call1->bridge_id = bridge_id;
-       if (call1->bchannel)
-               bchannel_join(call1->bchannel, bridge_id);
-
        call2->bridge_id = bridge_id;
-       if (call2->bchannel)
-               bchannel_join(call2->bchannel, bridge_id);
-#else
-       printf("FIXME");
-       exit(0);
-#endif
+       // FIXME: do bridiging
+       // bchannel_join(call1->bchannel, bridge_id);
+       // bchannel_join(call2->bchannel, bridge_id);
 
        call1->bridge_call = call2;
        call2->bridge_call = call1;
@@ -3396,7 +3462,7 @@ static int lcr_config_exec(struct ast_channel *ast, void *data, char **argv)
                        break;
                call = call->next;
        }
-       if (call)
+       if (call) {
 
                #ifdef LCR_FOR_ASTERISK
                apply_opt(call, (char *)data);
@@ -3414,7 +3480,7 @@ static int lcr_config_exec(struct ast_channel *ast, void *data, char **argv)
                        newparam.queue = call->tx_queue * 8;
                        send_message(MESSAGE_DISABLE_DEJITTER, call->ref, &newparam);
                }
-       else
+       else
                CERROR(NULL, ast, "lcr_config app not called by chan_lcr channel.\n");
 
        ast_mutex_unlock(&chan_lock);
@@ -3487,18 +3553,18 @@ int load_module(void)
                                 "\n"
                                 "The available options are:\n"
                                 "    d - Send display text on called phone, text is the optarg.\n"
-                                "    n - Don't detect dtmf tones on called channel.\n"
+                                "    D - Forward detected dtmf tones from LCR.\n"
                                 "    h - Force data call (HDLC).\n"
                                 "    q - Add queue to make fax stream seamless (required for fax app).\n"
                                 "        Use queue size in miliseconds for optarg. (try 250)\n"
-                                "    f - Adding fax detection. It it timeouts, mISDN_dsp is used.\n"
-                                "        Use time to detect for optarg.\n"
+                                "    a - Adding DTMF detection.\n"
+                                "    f - Adding fax detection.\n"
 #if 0
                                 "    c - Make crypted outgoing call, optarg is keyindex.\n"
                                 "    e - Perform echo cancelation on this channel.\n"
 #endif
                                 "        Takes mISDN pipeline option as optarg.\n"
-                                "    s - Send Non Inband DTMF as inband.\n"
+                                "    s - Send Non Inband DTMF as inband. (disables LCR's DTMF)\n"
                                 "    r - re-buffer packets (160 bytes). Required for some SIP-phones and fax applications.\n"
 #if 0
                                 "   vr - rxgain control\n"