Index: addons/chan_ooh323.c =================================================================== --- addons/chan_ooh323.c (revision 327358) +++ addons/chan_ooh323.c (working copy) @@ -24,6 +24,42 @@ #include "chan_ooh323.h" #include +/*** DOCUMENTATION + + + Allow Setting / Reading OOH323 Settings + + + + + + Fax Detect [R/W] + Returns 0 or 1 + Write yes or no + + + + + t38support [R/W] + Returns 0 or 1 + Write yes or no + + + + + Returns h323id [R] + + + + + + Read and set channel parameters in the dialplan. + name is one of the above only those with a [W] can be writen to. + + + +***/ + #define FORMAT_STRING_SIZE 512 /* Defaults */ @@ -138,6 +174,8 @@ static struct ooh323_pvt { struct ast_rtp_instance *vrtp; /* Placeholder for now */ int t38support; /* T.38 mode - disable, transparent, faxgw */ + int faxdetect; + int faxdetected; int rtptimeout; struct ast_udptl *udptl; int faxmode; @@ -199,25 +237,26 @@ AST_MUTEX_DEFINE_STATIC(iflock); /* Profile of H.323 user registered with PBX*/ struct ooh323_user{ ast_mutex_t lock; - char name[256]; - char context[AST_MAX_EXTENSION]; - int incominglimit; - unsigned inUse; - char accountcode[20]; - int amaflags; + char name[256]; + char context[AST_MAX_EXTENSION]; + int incominglimit; + unsigned inUse; + char accountcode[20]; + int amaflags; struct ast_format_cap *cap; struct ast_codec_pref prefs; - int dtmfmode; - int dtmfcodec; - int t38support; - int rtptimeout; - int mUseIP; /* Use IP address or H323-ID to search user */ - char mIP[4*8+7+2]; /* Max for IPv6 - 2 brackets, 8 4hex, 7 - : */ - struct OOH323Regex *rtpmask; - char rtpmaskstr[120]; - int rtdrcount, rtdrinterval; - int faststart, h245tunneling; - int g729onlyA; + int dtmfmode; + int dtmfcodec; + int faxdetect; + int t38support; + int rtptimeout; + int mUseIP; /* Use IP address or H323-ID to search user */ + char mIP[4*8+7+2]; /* Max for IPv6 - 2 brackets, 8 4hex, 7 - : */ + struct OOH323Regex *rtpmask; + char rtpmaskstr[120]; + int rtdrcount, rtdrinterval; + int faststart, h245tunneling; + int g729onlyA; struct ooh323_user *next; }; @@ -233,6 +272,7 @@ struct ooh323_peer{ int amaflags; int dtmfmode; int dtmfcodec; + int faxdetect; int t38support; int mFriend; /* indicates defined as friend */ char ip[4*8+7+2]; /* Max for IPv6 - 2 brackets, 8 4hex, 7 - : */ @@ -295,6 +335,7 @@ static struct ast_format_cap *gCap; static struct ast_codec_pref gPrefs; static int gDTMFMode = H323_DTMF_RFC2833; static int gDTMFCodec = 101; +static int gFAXdetect = 1; static int gT38Support = T38_FAXGW; static char gGatekeeper[100]; static enum RasGatekeeperMode gRasGkMode = RasNoGatekeeper; @@ -343,10 +384,12 @@ static pthread_t monitor_thread = AST_PTHREADT_NUL static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state, - const char *host, struct ast_format_cap *cap, const char *linkedid) + const char *host, struct ast_format_cap *cap, const char *linkedid) { struct ast_channel *ch = NULL; struct ast_format tmpfmt; + int features = 0; + if (gH323Debug) ast_verbose("--- ooh323_new - %s\n", host); @@ -388,18 +431,29 @@ static struct ast_channel *ooh323_new(struct ooh32 ast_module_ref(myself); /* Allocate dsp for in-band DTMF support */ - if (i->dtmfmode & H323_DTMF_INBAND) { + if ((i->dtmfmode & H323_DTMF_INBAND) || i->faxdetect) { i->vad = ast_dsp_new(); - ast_dsp_set_features(i->vad, DSP_FEATURE_DIGIT_DETECT); - ast_dsp_set_features(i->vad, - DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_FAX_DETECT); - ast_dsp_set_faxmode(i->vad, - DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED); + } - if (i->dtmfmode & H323_DTMF_INBANDRELAX) + /* inband DTMF*/ + if (i->dtmfmode & H323_DTMF_INBAND) { + features |= DSP_FEATURE_DIGIT_DETECT; + if (i->dtmfmode & H323_DTMF_INBANDRELAX) { ast_dsp_set_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF); + } } + /* fax detection*/ + if (i->faxdetect) { + features |= DSP_FEATURE_FAX_DETECT; + ast_dsp_set_faxmode(i->vad, + DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED); + } + + if (features) { + ast_dsp_set_features(i->vad, features); + } + ast_mutex_lock(&usecnt_lock); usecnt++; ast_mutex_unlock(&usecnt_lock); @@ -484,6 +538,9 @@ static struct ooh323_pvt *ooh323_alloc(int callref ast_mutex_lock(&pvt->lock); pvt->faxmode = 0; + pvt->chmodepend = 0; + pvt->faxdetected = 0; + pvt->faxdetect = gFAXdetect; pvt->t38support = gT38Support; pvt->rtptimeout = gRTPTimeout; pvt->rtdrinterval = gRTDRInterval; @@ -610,6 +667,7 @@ static struct ast_channel *ooh323_request(const ch p->g729onlyA = peer->g729onlyA; p->dtmfmode |= peer->dtmfmode; p->dtmfcodec = peer->dtmfcodec; + p->faxdetect = peer->faxdetect; p->t38support = peer->t38support; p->rtptimeout = peer->rtptimeout; p->faststart = peer->faststart; @@ -639,6 +697,7 @@ static struct ast_channel *ooh323_request(const ch p->g729onlyA = g729onlyA; p->dtmfmode = gDTMFMode; p->dtmfcodec = gDTMFCodec; + p->faxdetect = gFAXdetect; p->t38support = gT38Support; p->rtptimeout = gRTPTimeout; ast_format_cap_copy(p->cap, gCap); @@ -828,17 +887,7 @@ static int ooh323_digit_begin(struct ast_channel * } ast_mutex_lock(&p->lock); - - if (digit == 'e' && !p->faxmode && p->t38support != T38_DISABLED) { - if (!p->chmodepend) { - if (gH323Debug) - ast_verbose("request to change %s to t.38 because fax cng\n", - p->callToken); - p->chmodepend = 1; - ooRequestChangeMode(p->callToken, 1); - } - - } else if (p->rtp && ((p->dtmfmode & H323_DTMF_RFC2833) || (p->dtmfmode & H323_DTMF_CISCO))) { + if (p->rtp && ((p->dtmfmode & H323_DTMF_RFC2833) || (p->dtmfmode & H323_DTMF_CISCO))) { ast_rtp_instance_dtmf_begin(p->rtp, digit); } else if (((p->dtmfmode & H323_DTMF_Q931) || (p->dtmfmode & H323_DTMF_H245ALPHANUMERIC) || @@ -1270,27 +1319,50 @@ static int ooh323_indicate(struct ast_channel *ast (int)sizeof(enum ast_control_t38), (int)datalen); } else { const struct ast_control_t38_parameters *parameters = data; + struct ast_control_t38_parameters our_parameters; enum ast_control_t38 message = parameters->request_response; switch (message) { + case AST_T38_NEGOTIATED: + if (p->faxmode) { + res = 0; + break; + } case AST_T38_REQUEST_NEGOTIATE: - if (!p->chmodepend && !p->faxmode) { + if (p->faxmode) { + /* T.38 already negotiated */ + our_parameters.request_response = AST_T38_NEGOTIATED; + our_parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl); + our_parameters.rate = AST_T38_RATE_14400; + ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &our_parameters, sizeof(our_parameters)); + } else if (!p->chmodepend) { + p->chmodepend = 1; ooRequestChangeMode(p->callToken, 1); - p->chmodepend = 1; res = 0; } break; case AST_T38_REQUEST_TERMINATE: - if (!p->chmodepend && p->faxmode) { + if (!p->faxmode) { + /* T.38 already terminated */ + our_parameters.request_response = AST_T38_TERMINATED; + ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &our_parameters, sizeof(our_parameters)); + } else if (!p->chmodepend) { + p->chmodepend = 1; ooRequestChangeMode(p->callToken, 0); - p->chmodepend = 1; res = 0; } break; + case AST_T38_REQUEST_PARMS: + our_parameters.request_response = AST_T38_REQUEST_PARMS; + our_parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl); + our_parameters.rate = AST_T38_RATE_14400; + ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &our_parameters, sizeof(our_parameters)); + res = AST_T38_REQUEST_PARMS; + break; default: ; @@ -1336,17 +1408,18 @@ static int ooh323_queryoption(struct ast_channel * case AST_OPTION_T38_STATE: if (*datalen != sizeof(enum ast_t38_state)) { - ast_log(LOG_ERROR, "Invalid datalen for AST_OPTION_T38_STATE option." + ast_log(LOG_ERROR, "Invalid datalen for AST_OPTION_T38_STATE option." " Expected %d, got %d\n", (int)sizeof(enum ast_t38_state), *datalen); break; } - if (p->t38support != T38_DISABLED) - state = T38_STATE_UNKNOWN; - if (p->faxmode) - state = (p->chmodepend) ? T38_STATE_UNKNOWN : T38_STATE_NEGOTIATED; - else if (p->chmodepend) - state = T38_STATE_NEGOTIATING; + if (p->t38support != T38_DISABLED) { + if (p->faxmode) { + state = (p->chmodepend) ? T38_STATE_NEGOTIATING : T38_STATE_NEGOTIATED; + } else { + state = T38_STATE_UNKNOWN; + } + } *((enum ast_t38_state *) data) = state; res = 0; @@ -1762,6 +1835,7 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931M memcpy(&p->prefs, &user->prefs, sizeof(struct ast_codec_pref)); p->dtmfmode |= user->dtmfmode; p->dtmfcodec = user->dtmfcodec; + p->faxdetect = user->faxdetect; p->t38support = user->t38support; p->rtptimeout = user->rtptimeout; p->h245tunneling = user->h245tunneling; @@ -2202,6 +2276,7 @@ static struct ooh323_user *build_user(const char * user->rtptimeout = gRTPTimeout; user->dtmfmode = gDTMFMode; user->dtmfcodec = gDTMFCodec; + user->faxdetect = gFAXdetect; user->t38support = gT38Support; user->faststart = gFastStart; user->h245tunneling = gTunneling; @@ -2279,7 +2354,13 @@ static struct ooh323_user *build_user(const char * user->dtmfmode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0; } else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) { user->dtmfcodec = atoi(v->value); - } else if (!strcasecmp(v->name, "t38support")) { + } else if (!strcasecmp(v->name, "faxdetect")) { + if (ast_true(v->value)) { + user->faxdetect = 1; + } else { + user->faxdetect = 0; + } + } else if (!strcasecmp(v->name, "t38support")) { if (!strcasecmp(v->value, "disabled")) user->t38support = T38_DISABLED; if (!strcasecmp(v->value, "no")) @@ -2322,11 +2403,12 @@ static struct ooh323_peer *build_peer(const char * peer->amaflags = gAMAFLAGS; peer->dtmfmode = gDTMFMode; peer->dtmfcodec = gDTMFCodec; + peer->faxdetect = gFAXdetect; peer->t38support = gT38Support; peer->faststart = gFastStart; peer->h245tunneling = gTunneling; peer->g729onlyA = g729onlyA; - peer->port = 1720; + peer->port = 1720; if (0 == friend_type) { peer->mFriend = 1; } @@ -2426,7 +2508,13 @@ static struct ooh323_peer *build_peer(const char * peer->dtmfmode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0; } else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) { peer->dtmfcodec = atoi(v->value); - } else if (!strcasecmp(v->name, "t38support")) { + } else if (!strcasecmp(v->name, "faxdetect")) { + if (ast_true(v->value)) { + peer->faxdetect = 1; + } else { + peer->faxdetect = 0; + } + } else if (!strcasecmp(v->name, "t38support")) { if (!strcasecmp(v->value, "disabled")) peer->t38support = T38_DISABLED; if (!strcasecmp(v->value, "no")) @@ -2548,6 +2636,7 @@ int reload_config(int reload) memset(&gPrefs, 0, sizeof(struct ast_codec_pref)); gDTMFMode = H323_DTMF_RFC2833; gDTMFCodec = 101; + gFAXdetect = 1; gT38Support = T38_FAXGW; gTRCLVL = OOTRCLVLERR; gRasGkMode = RasNoGatekeeper; @@ -2751,7 +2840,13 @@ int reload_config(int reload) gDTMFMode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0; } else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) { gDTMFCodec = atoi(v->value); - } else if (!strcasecmp(v->name, "t38support")) { + } else if (!strcasecmp(v->name, "faxdetect")) { + if (ast_true(v->value)) { + gFAXdetect = 1; + } else { + gFAXdetect = 0; + } + } else if (!strcasecmp(v->name, "t38support")) { if (!strcasecmp(v->value, "disabled")) gT38Support = T38_DISABLED; if (!strcasecmp(v->value, "no")) @@ -2838,14 +2933,13 @@ static char *handle_cli_ooh323_show_peer(struct as if (a->argc != 4) return CLI_SHOWUSAGE; - ast_mutex_lock(&peerl.lock); peer = peerl.peers; while (peer) { ast_mutex_lock(&peer->lock); - if(!strcmp(peer->name, a->argv[3])) + if (!strcmp(peer->name, a->argv[3])) { break; - else { + } else { prev = peer; peer = peer->next; ast_mutex_unlock(&prev->lock); @@ -2853,53 +2947,55 @@ static char *handle_cli_ooh323_show_peer(struct as } if (peer) { - sprintf(ip_port, "%s:%d", peer->ip, peer->port); - ast_cli(a->fd, "%-15.15s%s\n", "Name: ", peer->name); - ast_cli(a->fd, "%s:%s,%s\n", "FastStart/H.245 Tunneling", peer->faststart?"yes":"no", + sprintf(ip_port, "%s:%d", peer->ip, peer->port); + ast_cli(a->fd, "%-15.15s%s\n", "Name: ", peer->name); + ast_cli(a->fd, "%s:%s,%s\n", "FastStart/H.245 Tunneling", peer->faststart?"yes":"no", peer->h245tunneling?"yes":"no"); - ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "("); - print_codec_to_cli(a->fd, &peer->prefs); - ast_cli(a->fd, ")\n"); - ast_cli(a->fd, "%-15.15s", "DTMF Mode: "); + ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "("); + print_codec_to_cli(a->fd, &peer->prefs); + ast_cli(a->fd, ")\n"); + ast_cli(a->fd, "%-15.15s", "DTMF Mode: "); if (peer->dtmfmode & H323_DTMF_CISCO) { - ast_cli(a->fd, "%s\n", "cisco"); - ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", peer->dtmfcodec); + ast_cli(a->fd, "%s\n", "cisco"); + ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", peer->dtmfcodec); } else if (peer->dtmfmode & H323_DTMF_RFC2833) { - ast_cli(a->fd, "%s\n", "rfc2833"); - ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", peer->dtmfcodec); - } else if (peer->dtmfmode & H323_DTMF_Q931) - ast_cli(a->fd, "%s\n", "q931keypad"); - else if (peer->dtmfmode & H323_DTMF_H245ALPHANUMERIC) - ast_cli(a->fd, "%s\n", "h245alphanumeric"); - else if (peer->dtmfmode & H323_DTMF_H245SIGNAL) - ast_cli(a->fd, "%s\n", "h245signal"); - else if (peer->dtmfmode & H323_DTMF_INBAND && peer->dtmfmode & H323_DTMF_INBANDRELAX) - ast_cli(a->fd, "%s\n", "inband-relaxed"); - else if (peer->dtmfmode & H323_DTMF_INBAND) - ast_cli(a->fd, "%s\n", "inband"); - else - ast_cli(a->fd, "%s\n", "unknown"); - - ast_cli(a->fd,"%-15s", "T.38 Mode: "); - if (peer->t38support == T38_DISABLED) - ast_cli(a->fd, "%s\n", "disabled"); - else if (peer->t38support == T38_FAXGW) - ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible"); - - ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", peer->accountcode); - ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", - ast_cdr_flags2str(peer->amaflags)); - ast_cli(a->fd, "%-15.15s%s\n", "IP:Port: ", ip_port); - ast_cli(a->fd, "%-15.15s%d\n", "OutgoingLimit: ", peer->outgoinglimit); - ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", peer->rtptimeout); - if (peer->rtpmaskstr[0]) - ast_cli(a->fd, "%-15.15s%s\n", "rtpmask: ", peer->rtpmaskstr); - if (peer->rtdrcount && peer->rtdrinterval) - ast_cli(a->fd, "%-15.15s%d,%d\n", "RoundTrip: ", peer->rtdrcount, peer->rtdrinterval); - ast_mutex_unlock(&peer->lock); + ast_cli(a->fd, "%s\n", "rfc2833"); + ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", peer->dtmfcodec); + } else if (peer->dtmfmode & H323_DTMF_Q931) { + ast_cli(a->fd, "%s\n", "q931keypad"); + } else if (peer->dtmfmode & H323_DTMF_H245ALPHANUMERIC) { + ast_cli(a->fd, "%s\n", "h245alphanumeric"); + } else if (peer->dtmfmode & H323_DTMF_H245SIGNAL) { + ast_cli(a->fd, "%s\n", "h245signal"); + } else if (peer->dtmfmode & H323_DTMF_INBAND && peer->dtmfmode & H323_DTMF_INBANDRELAX) { + ast_cli(a->fd, "%s\n", "inband-relaxed"); + } else if (peer->dtmfmode & H323_DTMF_INBAND) { + ast_cli(a->fd, "%s\n", "inband"); + } else { + ast_cli(a->fd, "%s\n", "unknown"); + } + ast_cli(a->fd,"%-15s", "T.38 Mode: "); + if (peer->t38support == T38_DISABLED) { + ast_cli(a->fd, "%s\n", "disabled"); + } else if (peer->t38support == T38_FAXGW) { + ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible"); + } + ast_cli(a->fd,"%-15s%s\n", "FAX Detect:", (peer->faxdetect) ? "Yes" : "No"); + ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", peer->accountcode); + ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", ast_cdr_flags2str(peer->amaflags)); + ast_cli(a->fd, "%-15.15s%s\n", "IP:Port: ", ip_port); + ast_cli(a->fd, "%-15.15s%d\n", "OutgoingLimit: ", peer->outgoinglimit); + ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", peer->rtptimeout); + if (peer->rtpmaskstr[0]) { + ast_cli(a->fd, "%-15.15s%s\n", "rtpmask: ", peer->rtpmaskstr); + } + if (peer->rtdrcount && peer->rtdrinterval) { + ast_cli(a->fd, "%-15.15s%d,%d\n", "RoundTrip: ", peer->rtdrcount, peer->rtdrinterval); + } + ast_mutex_unlock(&peer->lock); } else { - ast_cli(a->fd, "Peer %s not found\n", a->argv[3]); - ast_cli(a->fd, "\n"); + ast_cli(a->fd, "Peer %s not found\n", a->argv[3]); + ast_cli(a->fd, "\n"); } ast_mutex_unlock(&peerl.lock); @@ -2989,9 +3085,9 @@ static char *handle_cli_ooh323_show_user(struct as user = userl.users; while (user) { ast_mutex_lock(&user->lock); - if(!strcmp(user->name, a->argv[3])) { + if (!strcmp(user->name, a->argv[3])) { break; - } else { + } else { prev = user; user = user->next; ast_mutex_unlock(&prev->lock); @@ -2999,53 +3095,55 @@ static char *handle_cli_ooh323_show_user(struct as } if (user) { - ast_cli(a->fd, "%-15.15s%s\n", "Name: ", user->name); - ast_cli(a->fd, "%s:%s,%s\n", "FastStart/H.245 Tunneling", user->faststart?"yes":"no", + ast_cli(a->fd, "%-15.15s%s\n", "Name: ", user->name); + ast_cli(a->fd, "%s:%s,%s\n", "FastStart/H.245 Tunneling", user->faststart?"yes":"no", user->h245tunneling?"yes":"no"); - ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "("); - print_codec_to_cli(a->fd, &user->prefs); - ast_cli(a->fd, ")\n"); - ast_cli(a->fd, "%-15.15s", "DTMF Mode: "); + ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "("); + print_codec_to_cli(a->fd, &user->prefs); + ast_cli(a->fd, ")\n"); + ast_cli(a->fd, "%-15.15s", "DTMF Mode: "); if (user->dtmfmode & H323_DTMF_CISCO) { - ast_cli(a->fd, "%s\n", "cisco"); - ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", user->dtmfcodec); + ast_cli(a->fd, "%s\n", "cisco"); + ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", user->dtmfcodec); } else if (user->dtmfmode & H323_DTMF_RFC2833) { - ast_cli(a->fd, "%s\n", "rfc2833"); - ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", user->dtmfcodec); - } else if (user->dtmfmode & H323_DTMF_Q931) - ast_cli(a->fd, "%s\n", "q931keypad"); - else if (user->dtmfmode & H323_DTMF_H245ALPHANUMERIC) - ast_cli(a->fd, "%s\n", "h245alphanumeric"); - else if (user->dtmfmode & H323_DTMF_H245SIGNAL) - ast_cli(a->fd, "%s\n", "h245signal"); - else if (user->dtmfmode & H323_DTMF_INBAND && user->dtmfmode & H323_DTMF_INBANDRELAX) - ast_cli(a->fd, "%s\n", "inband-relaxed"); - else if (user->dtmfmode & H323_DTMF_INBAND) - ast_cli(a->fd, "%s\n", "inband"); - else - ast_cli(a->fd, "%s\n", "unknown"); - - ast_cli(a->fd,"%-15s", "T.38 Mode: "); - if (user->t38support == T38_DISABLED) - ast_cli(a->fd, "%s\n", "disabled"); - else if (user->t38support == T38_FAXGW) - ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible"); - - ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", user->accountcode); - ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", - ast_cdr_flags2str(user->amaflags)); - ast_cli(a->fd, "%-15.15s%s\n", "Context: ", user->context); - ast_cli(a->fd, "%-15.15s%d\n", "IncomingLimit: ", user->incominglimit); - ast_cli(a->fd, "%-15.15s%d\n", "InUse: ", user->inUse); - ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", user->rtptimeout); - if (user->rtpmaskstr[0]) - ast_cli(a->fd, "%-15.15s%s\n", "rtpmask: ", user->rtpmaskstr); + ast_cli(a->fd, "%s\n", "rfc2833"); + ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", user->dtmfcodec); + } else if (user->dtmfmode & H323_DTMF_Q931) { + ast_cli(a->fd, "%s\n", "q931keypad"); + } else if (user->dtmfmode & H323_DTMF_H245ALPHANUMERIC) { + ast_cli(a->fd, "%s\n", "h245alphanumeric"); + } else if (user->dtmfmode & H323_DTMF_H245SIGNAL) { + ast_cli(a->fd, "%s\n", "h245signal"); + } else if (user->dtmfmode & H323_DTMF_INBAND && user->dtmfmode & H323_DTMF_INBANDRELAX) { + ast_cli(a->fd, "%s\n", "inband-relaxed"); + } else if (user->dtmfmode & H323_DTMF_INBAND) { + ast_cli(a->fd, "%s\n", "inband"); + } else { + ast_cli(a->fd, "%s\n", "unknown"); + } + ast_cli(a->fd,"%-15s", "T.38 Mode: "); + if (user->t38support == T38_DISABLED) { + ast_cli(a->fd, "%s\n", "disabled"); + } else if (user->t38support == T38_FAXGW) { + ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible"); + } + ast_cli(a->fd,"%-15s%s\n", "FAX Detect:", (user->faxdetect) ? "Yes" : "No"); + ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", user->accountcode); + ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", ast_cdr_flags2str(user->amaflags)); + ast_cli(a->fd, "%-15.15s%s\n", "Context: ", user->context); + ast_cli(a->fd, "%-15.15s%d\n", "IncomingLimit: ", user->incominglimit); + ast_cli(a->fd, "%-15.15s%d\n", "InUse: ", user->inUse); + ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", user->rtptimeout); + if (user->rtpmaskstr[0]) { + ast_cli(a->fd, "%-15.15s%s\n", "rtpmask: ", user->rtpmaskstr); + } ast_mutex_unlock(&user->lock); - if (user->rtdrcount && user->rtdrinterval) - ast_cli(a->fd, "%-15.15s%d,%d\n", "RoundTrip: ", user->rtdrcount, user->rtdrinterval); + if (user->rtdrcount && user->rtdrinterval) { + ast_cli(a->fd, "%-15.15s%d,%d\n", "RoundTrip: ", user->rtdrcount, user->rtdrinterval); + } } else { - ast_cli(a->fd, "User %s not found\n", a->argv[3]); - ast_cli(a->fd, "\n"); + ast_cli(a->fd, "User %s not found\n", a->argv[3]); + ast_cli(a->fd, "\n"); } ast_mutex_unlock(&userl.lock); @@ -3144,91 +3242,85 @@ static char *handle_cli_ooh323_show_config(struct if (a->argc != 3) return CLI_SHOWUSAGE; - - - ast_cli(a->fd, "\nObjective Open H.323 Channel Driver's Config:\n"); + ast_cli(a->fd, "\nObjective Open H.323 Channel Driver's Config:\n"); snprintf(value, sizeof(value), "%s:%d", gIP, gPort); - ast_cli(a->fd, "%-20s%s\n", "IP:Port: ", value); - ast_cli(a->fd, "%-20s%d-%d\n", "H.225 port range: ", - ooconfig.mTCPPortStart, ooconfig.mTCPPortEnd); - ast_cli(a->fd, "%-20s%s\n", "FastStart", gFastStart?"yes":"no"); - ast_cli(a->fd, "%-20s%s\n", "Tunneling", gTunneling?"yes":"no"); - ast_cli(a->fd, "%-20s%s\n", "CallerId", gCallerID); - ast_cli(a->fd, "%-20s%s\n", "MediaWaitForConnect", - gMediaWaitForConnect?"yes":"no"); + ast_cli(a->fd, "%-20s%s\n", "IP:Port: ", value); + ast_cli(a->fd, "%-20s%d-%d\n", "H.225 port range: ", ooconfig.mTCPPortStart, ooconfig.mTCPPortEnd); + ast_cli(a->fd, "%-20s%s\n", "FastStart", gFastStart?"yes":"no"); + ast_cli(a->fd, "%-20s%s\n", "Tunneling", gTunneling?"yes":"no"); + ast_cli(a->fd, "%-20s%s\n", "CallerId", gCallerID); + ast_cli(a->fd, "%-20s%s\n", "MediaWaitForConnect", gMediaWaitForConnect?"yes":"no"); #if (0) extern OOH323EndPoint gH323ep; - ast_cli(a->fd, "%-20s%s\n", "FASTSTART", - (OO_TESTFLAG(gH323ep.flags, OO_M_FASTSTART) != 0) ? "yes" : "no"); - ast_cli(a->fd, "%-20s%s\n", "TUNNELING", - (OO_TESTFLAG(gH323ep.flags, OO_M_TUNNELING) != 0) ? "yes" : "no"); - ast_cli(a->fd, "%-20s%s\n", "MEDIAWAITFORCONN", - (OO_TESTFLAG(gH323ep.flags, OO_M_MEDIAWAITFORCONN) != 0) ? "yes" : "no"); + ast_cli(a->fd, "%-20s%s\n", "FASTSTART", + (OO_TESTFLAG(gH323ep.flags, OO_M_FASTSTART) != 0) ? "yes" : "no"); + ast_cli(a->fd, "%-20s%s\n", "TUNNELING", + (OO_TESTFLAG(gH323ep.flags, OO_M_TUNNELING) != 0) ? "yes" : "no"); + ast_cli(a->fd, "%-20s%s\n", "MEDIAWAITFORCONN", + (OO_TESTFLAG(gH323ep.flags, OO_M_MEDIAWAITFORCONN) != 0) ? "yes" : "no"); #endif - if (gRasGkMode == RasNoGatekeeper) + if (gRasGkMode == RasNoGatekeeper) { snprintf(value, sizeof(value), "%s", "No Gatekeeper"); - else if (gRasGkMode == RasDiscoverGatekeeper) + } else if (gRasGkMode == RasDiscoverGatekeeper) { snprintf(value, sizeof(value), "%s", "Discover"); - else + } else { snprintf(value, sizeof(value), "%s", gGatekeeper); - - ast_cli(a->fd, "%-20s%s\n", "Gatekeeper:", value); - - ast_cli(a->fd, "%-20s%s\n", "H.323 LogFile:", gLogFile); - - ast_cli(a->fd, "%-20s%s\n", "Context:", gContext); - - ast_cli(a->fd, "%-20s%s\n", "Capability:", - ast_getformatname_multiple(value,FORMAT_STRING_SIZE,gCap)); - - ast_cli(a->fd, "%-20s", "DTMF Mode: "); + } + ast_cli(a->fd, "%-20s%s\n", "Gatekeeper:", value); + ast_cli(a->fd, "%-20s%s\n", "H.323 LogFile:", gLogFile); + ast_cli(a->fd, "%-20s%s\n", "Context:", gContext); + ast_cli(a->fd, "%-20s%s\n", "Capability:", + ast_getformatname_multiple(value,FORMAT_STRING_SIZE,gCap)); + ast_cli(a->fd, "%-20s", "DTMF Mode: "); if (gDTMFMode & H323_DTMF_CISCO) { - ast_cli(a->fd, "%s\n", "cisco"); - ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", gDTMFCodec); + ast_cli(a->fd, "%s\n", "cisco"); + ast_cli(a->fd, "%-20.15s%d\n", "DTMF Codec: ", gDTMFCodec); } else if (gDTMFMode & H323_DTMF_RFC2833) { - ast_cli(a->fd, "%s\n", "rfc2833"); - ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", gDTMFCodec); - } else if (gDTMFMode & H323_DTMF_Q931) - ast_cli(a->fd, "%s\n", "q931keypad"); - else if (gDTMFMode & H323_DTMF_H245ALPHANUMERIC) - ast_cli(a->fd, "%s\n", "h245alphanumeric"); - else if (gDTMFMode & H323_DTMF_H245SIGNAL) - ast_cli(a->fd, "%s\n", "h245signal"); - else if (gDTMFMode & H323_DTMF_INBAND && gDTMFMode & H323_DTMF_INBANDRELAX) - ast_cli(a->fd, "%s\n", "inband-relaxed"); - else if (gDTMFMode & H323_DTMF_INBAND) - ast_cli(a->fd, "%s\n", "inband"); - else + ast_cli(a->fd, "%s\n", "rfc2833"); + ast_cli(a->fd, "%-20.15s%d\n", "DTMF Codec: ", gDTMFCodec); + } else if (gDTMFMode & H323_DTMF_Q931) { + ast_cli(a->fd, "%s\n", "q931keypad"); + } else if (gDTMFMode & H323_DTMF_H245ALPHANUMERIC) { + ast_cli(a->fd, "%s\n", "h245alphanumeric"); + } else if (gDTMFMode & H323_DTMF_H245SIGNAL) { + ast_cli(a->fd, "%s\n", "h245signal"); + } else if (gDTMFMode & H323_DTMF_INBAND && gDTMFMode & H323_DTMF_INBANDRELAX) { + ast_cli(a->fd, "%s\n", "inband-relaxed"); + } else if (gDTMFMode & H323_DTMF_INBAND) { + ast_cli(a->fd, "%s\n", "inband"); + } else { ast_cli(a->fd, "%s\n", "unknown"); + } - ast_cli(a->fd,"%-20s", "T.38 Mode: "); - if (gT38Support == T38_DISABLED) + ast_cli(a->fd,"%-20s", "T.38 Mode: "); + if (gT38Support == T38_DISABLED) { ast_cli(a->fd, "%s\n", "disabled"); - else if (gT38Support == T38_FAXGW) + } else if (gT38Support == T38_FAXGW) { ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible"); + } + ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", (gFAXdetect) ? "Yes" : "No"); - if (gRTDRCount && gRTDRInterval) - ast_cli(a->fd, "%-15.15s%d,%d\n", "RoundTrip: ", gRTDRCount, gRTDRInterval); + if (gRTDRCount && gRTDRInterval) { + ast_cli(a->fd, "%-20.15s%d,%d\n", "RoundTrip: ", gRTDRCount, gRTDRInterval); + } - ast_cli(a->fd, "%-20s%ld\n", "Call counter: ", callnumber); - ast_cli(a->fd, "%-20s%s\n", "AccountCode: ", gAccountcode); + ast_cli(a->fd, "%-20s%ld\n", "Call counter: ", callnumber); + ast_cli(a->fd, "%-20s%s\n", "AccountCode: ", gAccountcode); + ast_cli(a->fd, "%-20s%s\n", "AMA flags: ", ast_cdr_flags2str(gAMAFLAGS)); - ast_cli(a->fd, "%-20s%s\n", "AMA flags: ", ast_cdr_flags2str(gAMAFLAGS)); - pAlias = gAliasList; - if(pAlias) { - ast_cli(a->fd, "%-20s\n", "Aliases: "); - } + if(pAlias) { + ast_cli(a->fd, "%-20s\n", "Aliases: "); + } while (pAlias) { pAliasNext = pAlias->next; if (pAliasNext) { - ast_cli(a->fd,"\t%-30s\t%-30s\n",pAlias->value, pAliasNext->value); + ast_cli(a->fd,"\t%-30s\t%-30s\n",pAlias->value, pAliasNext->value); pAlias = pAliasNext->next; - } - else{ - ast_cli(a->fd,"\t%-30s\n",pAlias->value); + } else { + ast_cli(a->fd,"\t%-30s\n",pAlias->value); pAlias = pAlias->next; } } @@ -3245,7 +3337,100 @@ static struct ast_cli_entry cli_ooh323[] = { AST_CLI_DEFINE(handle_cli_ooh323_reload, "reload ooh323 config") }; +/*! \brief OOH323 Dialplan function - reads ooh323 settings */ +static int function_ooh323_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +{ + struct ooh323_pvt *p = chan->tech_pvt; + ast_channel_lock(chan); + if (!p) { + ast_channel_unlock(chan); + return -1; + } + + if (strcmp(chan->tech->type, "OOH323")) { + ast_log(LOG_ERROR, "This function is only supported on OOH323 channels, Channel is %s\n", chan->tech->type); + ast_channel_unlock(chan); + return -1; + } + + ast_mutex_lock(&p->lock); + if (!strcasecmp(data, "faxdetect")) { + ast_copy_string(buf, p->faxdetect ? "1" : "0", len); + } else if (!strcasecmp(data, "t38support")) { + ast_copy_string(buf, p->t38support ? "1" : "0", len); + } else if (!strcasecmp(data, "caller_h323id")) { + ast_copy_string(buf, p->caller_h323id, len); + } else if (!strcasecmp(data, "caller_dialeddigits")) { + ast_copy_string(buf, p->caller_dialedDigits, len); + } else if (!strcasecmp(data, "caller_email")) { + ast_copy_string(buf, p->caller_email, len); + } else if (!strcasecmp(data, "h323id_url")) { + ast_copy_string(buf, p->caller_url, len); + } else if (!strcasecmp(data, "callee_h323id")) { + ast_copy_string(buf, p->callee_h323id, len); + } else if (!strcasecmp(data, "callee_dialeddigits")) { + ast_copy_string(buf, p->callee_dialedDigits, len); + } else if (!strcasecmp(data, "callee_email")) { + ast_copy_string(buf, p->callee_email, len); + } else if (!strcasecmp(data, "callee_url")) { + ast_copy_string(buf, p->callee_url, len); + } + ast_mutex_unlock(&p->lock); + + ast_channel_unlock(chan); + return 0; +} + +/*! \brief OOH323 Dialplan function - writes ooh323 settings */ +static int function_ooh323_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) +{ + struct ooh323_pvt *p = chan->tech_pvt; + int res = -1; + + ast_channel_lock(chan); + if (!p) { + ast_channel_unlock(chan); + return -1; + } + + if (strcmp(chan->tech->type, "OOH323")) { + ast_log(LOG_ERROR, "This function is only supported on OOH323 channels, Channel is %s\n", chan->tech->type); + ast_channel_unlock(chan); + return -1; + } + + ast_mutex_lock(&p->lock); + if (!strcasecmp(data, "faxdetect")) { + if (ast_true(value)) { + p->faxdetect = 1; + res = 0; + } else { + p->faxdetect = 0; + res = 0; + } + } else if (!strcasecmp(data, "t38support")) { + if (ast_true(value)) { + p->t38support = 1; + res = 0; + } else { + p->t38support = 0; + res = 0; + } + } + ast_mutex_unlock(&p->lock); + ast_channel_unlock(chan); + + return res; +} + +/*! \brief Structure to declare a dialplan function: OOH323 */ +static struct ast_custom_function ooh323_function = { + .name = "OOH323", + .read = function_ooh323_read, + .write = function_ooh323_write, +}; + static int load_module(void) { int res; @@ -3414,6 +3599,9 @@ static int load_module(void) restart_monitor(); } + /* Register dialplan functions */ + ast_custom_function_register(&ooh323_function); + return 0; } @@ -3689,7 +3877,7 @@ int delete_users() ast_mutex_unlock(&userl.lock); return 0; } - + static int unload_module(void) { struct ooh323_pvt *p; @@ -3804,8 +3992,11 @@ static int unload_module(void) } ooH323EpDestroy(); + /* Unregister dial plan functions */ + ast_custom_function_unregister(&ooh323_function); + if (gH323Debug) { - ast_verbose("+++ ooh323 unload_module \n"); + ast_verbose("+++ ooh323 unload_module \n"); } gCap = ast_format_cap_destroy(gCap); @@ -4310,6 +4501,7 @@ struct ast_frame *ooh323_rtp_read(struct ast_chann { /* Retrieve audio/etc from channel. Assumes p->lock is already held. */ struct ast_frame *f; + struct ast_frame *dfr = NULL; static struct ast_frame null_frame = { AST_FRAME_NULL, }; switch (ast->fdno) { case 0: @@ -4336,26 +4528,60 @@ struct ast_frame *ooh323_rtp_read(struct ast_chann f = &null_frame; } - if (p->owner) { + if (p->owner && !p->faxmode && (f->frametype == AST_FRAME_VOICE)) { /* We already hold the channel lock */ - if (f->frametype == AST_FRAME_VOICE && !p->faxmode) { - if (!(ast_format_cap_iscompatible(p->owner->nativeformats, &f->subclass.format))) { - ast_debug(1, "Oooh, voice format changed to %s\n", ast_getformatname(&f->subclass.format)); - ast_format_cap_set(p->owner->nativeformats, &f->subclass.format); - ast_set_read_format(p->owner, &p->owner->readformat); - ast_set_write_format(p->owner, &p->owner->writeformat); - } + if (!(ast_format_cap_iscompatible(p->owner->nativeformats, &f->subclass.format))) { + ast_debug(1, "Oooh, voice format changed to %s\n", ast_getformatname(&f->subclass.format)); + ast_format_cap_set(p->owner->nativeformats, &f->subclass.format); + ast_set_read_format(p->owner, &p->owner->readformat); + ast_set_write_format(p->owner, &p->owner->writeformat); + } + if (((p->dtmfmode & H323_DTMF_INBAND) || p->faxdetect) && p->vad && + (f->subclass.format.id == AST_FORMAT_SLINEAR || f->subclass.format.id == AST_FORMAT_ALAW || + f->subclass.format.id == AST_FORMAT_ULAW)) { + dfr = ast_frdup(f); + dfr = ast_dsp_process(p->owner, p->vad, dfr); + } + } else { + return f; + } - if ((p->dtmfmode & H323_DTMF_INBAND) && p->vad && - (f->subclass.format.id == AST_FORMAT_SLINEAR || f->subclass.format.id == AST_FORMAT_ALAW || - f->subclass.format.id == AST_FORMAT_ULAW)) { - f = ast_dsp_process(p->owner, p->vad, f); - if (f && (f->frametype == AST_FRAME_DTMF)) { - ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.integer); + /* process INBAND DTMF*/ + if (dfr && (dfr->frametype == AST_FRAME_DTMF) && ((dfr->subclass.integer == 'f') || (dfr->subclass.integer == 'e'))) { + ast_debug(1, "* Detected FAX Tone %s\n", (dfr->subclass.integer == 'e') ? "CED" : "CNG"); + /* Switch to T.38 ON CED*/ + if (!p->faxmode && !p->chmodepend && (dfr->subclass.integer == 'e') && (p->t38support != T38_DISABLED)) { + if (gH323Debug) + ast_verbose("request to change %s to t.38 because fax ced\n", p->callToken); + p->chmodepend = 1; + p->faxdetected = 1; + ooRequestChangeMode(p->callToken, 1); + } else if ((dfr->subclass.integer == 'f') && !p->faxdetected) { + const char *target_context = S_OR(p->owner->macrocontext, p->owner->context); + if ((strcmp(p->owner->exten, "fax")) && + (ast_exists_extension(p->owner, target_context, "fax", 1, + S_COR(p->owner->caller.id.number.valid, p->owner->caller.id.number.str, NULL)))) { + ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", p->owner->name); + pbx_builtin_setvar_helper(p->owner, "FAXEXTEN", p->owner->exten); + if (ast_async_goto(p->owner, target_context, "fax", 1)) { + ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", p->owner->name,target_context); } + p->faxdetected = 1; + if (dfr) { + ast_frfree(dfr); + } + return &ast_null_frame; } } + } else if (dfr && dfr->frametype == AST_FRAME_DTMF) { + ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.integer); + ast_frfree(f); + return dfr; } + + if (dfr) { + ast_frfree(dfr); + } return f; } @@ -4377,6 +4603,7 @@ void onModeChanged(ooCallData *call, int t38mode) if (gH323Debug) ast_debug(1, "mode for %s is already %d\n", call->callToken, t38mode); + p->chmodepend = 0; ast_mutex_unlock(&p->lock); return; } @@ -4387,11 +4614,13 @@ void onModeChanged(ooCallData *call, int t38mode) DEADLOCK_AVOIDANCE(&p->lock); } if (!p->owner) { + p->chmodepend = 0; ast_mutex_unlock(&p->lock); ast_log(LOG_ERROR, "Channel has no owner\n"); return; } } else { + p->chmodepend = 0; ast_mutex_unlock(&p->lock); ast_log(LOG_ERROR, "Channel has no owner\n"); return; @@ -4431,6 +4660,7 @@ void onModeChanged(ooCallData *call, int t38mode) ¶meters, sizeof(parameters)); } p->faxmode = 0; + p->faxdetected = 0; p->t38_init = 0; }