--- channels/Makefile 2008-02-07 23:59:47.000000000 +0300 +++ ../../asterisk-addons-1.6.1.0/channels/Makefile 2009-07-29 00:46:18.000000000 +0400 @@ -26,6 +26,7 @@ h323/MULTIMEDIA-SYSTEM-CONTROLDec.o h323/MULTIMEDIA-SYSTEM-CONTROLEnc.o H323CFLAGS=-Iooh323c/src -Iooh323c/src/h323 +ASTCFLAGS+=-g all: _all @@ -38,5 +39,7 @@ chan_ooh323.o: ASTCFLAGS+=$(H323CFLAGS) +chan_ooh323.so: ASTLDFLAGS+=-lrt -lspandsp + $(if $(filter chan_ooh323,$(EMBEDDED_MODS)),modules.link,chan_ooh323.so): ASTCFLAGS+=$(H323CFLAGS) $(if $(filter chan_ooh323,$(EMBEDDED_MODS)),modules.link,chan_ooh323.so): $(addprefix ooh323c/src/,$(H323OBJS)) chan_ooh323.o ooh323cDriver.o --- ./channels/ooh323cDriver.h 2009-07-29 03:07:53.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323cDriver.h 2009-07-28 22:49:05.000000000 +0400 @@ -36,5 +36,5 @@ (struct ast_codec_pref *prefs, int capability, int dtmf); int convertH323CapToAsteriskCap(int cap); int ooh323c_set_capability_for_call - (ooCallData *call, struct ast_codec_pref *prefs, int capability, int dtmf); + (ooCallData *call, struct ast_codec_pref *prefs, int capability, int dtmf, int t38support); #endif --- ./channels/chan_ooh323.h 2008-05-28 18:45:23.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/chan_ooh323.h 2009-07-28 22:49:05.000000000 +0400 @@ -61,6 +61,8 @@ #include #include +#include + #include "ootypes.h" #include "ooCapability.h" #include "oochannels.h" --- ./channels/chan_ooh323.c 2009-07-29 03:07:53.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/chan_ooh323.c 2009-07-29 02:51:38.000000000 +0400 @@ -16,6 +16,14 @@ #include "chan_ooh323.h" +#include + +#define HAVE_SPANDSP_EXPOSE_H +#include +#ifdef HAVE_SPANDSP_EXPOSE_H +#include +#endif +#include /* Defaults */ #define DEFAULT_CONTEXT "default" @@ -34,6 +42,12 @@ #define H323_DISABLEGK (1<<7) #define H323_NEEDSTART (1<<8) +#define MAXT30 240 +#define T38TOAUDIOTIMEOUT 30 +#define T38_DISABLED 0 +#define T38_TRANSPARENT 1 +#define T38_FAXGW 2 + /* Channel description */ static const char type[] = "OOH323"; static const char tdesc[] = "Objective Systems H323 Channel Driver"; @@ -51,6 +65,7 @@ static struct ast_frame *ooh323_read(struct ast_channel *ast); static int ooh323_write(struct ast_channel *ast, struct ast_frame *f); static int ooh323_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); +static int ooh323_queryoption(struct ast_channel *ast, int option, void *data, int *datalen); static int ooh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static enum ast_rtp_get_result ooh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp); @@ -58,6 +73,9 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active); +static struct ast_udptl *ooh323_get_udptl_peer(struct ast_channel *chan); +static int ooh323_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl); + static void print_codec_to_cli(int fd, struct ast_codec_pref *pref); static void ast_ooh323c_exit(); @@ -78,6 +96,7 @@ .indicate = ooh323_indicate, .fixup = ooh323_fixup, .send_html = 0, + .queryoption = ooh323_queryoption, /* .bridge = ast_rtp_bridge, */ }; @@ -88,6 +107,14 @@ .set_rtp_peer = ooh323_set_rtp_peer }; +static struct ast_udptl_protocol ooh323_udptl = { + type: "H323", + get_udptl_info: ooh323_get_udptl_peer, + set_udptl_peer: ooh323_set_udptl_peer, +}; + + + struct ooh323_user; /* H.323 channel private structure */ @@ -95,6 +122,17 @@ ast_mutex_t lock; /* Channel private lock */ struct ast_rtp *rtp; struct ast_rtp *vrtp; /* Placeholder for now */ + + int t38support; /* T.38 mode - disable, transparent, faxgw */ + struct ast_udptl *udptl; + int faxmode; + int t38_tx_enable; + int t38_init; + t38_gateway_state_t t38r_state; + struct sockaddr_in udptlredirip; + time_t lastTxT38; + int chmodepend; + struct ast_channel *owner; /* Master Channel */ union { char *user; /* cooperating user/peer */ @@ -149,6 +187,7 @@ int capability; struct ast_codec_pref prefs; int dtmfmode; + int t38support; int rtptimeout; int mUseIP; /* Use IP address or H323-ID to search user */ char mIP[20]; @@ -166,6 +205,7 @@ char accountcode[20]; int amaflags; int dtmfmode; + int t38support; int mFriend; /* indicates defined as friend */ char ip[20]; int port; @@ -209,6 +249,7 @@ int onOutgoingCall(ooCallData *call); int onCallEstablished(ooCallData *call); int onCallCleared(ooCallData *call); +void onModeChanged(ooCallData *call, int t38mode); static char gLogFile[256] = DEFAULT_LOGFILE; static int gPort = 1720; @@ -218,6 +259,7 @@ static int gCapability = AST_FORMAT_ULAW; static struct ast_codec_pref gPrefs; static int gDTMFMode = H323_DTMF_RFC2833; +static int gT38Support = T38_FAXGW; static char gGatekeeper[100]; static enum RasGatekeeperMode gRasGkMode = RasNoGatekeeper; @@ -234,6 +276,7 @@ static int gIncomingLimit = 1024; static int gOutgoingLimit = 1024; OOBOOL gH323Debug = FALSE; +static int gTRCLVL = OOTRCLVLERR; static int t35countrycode = 0; static int t35extensions = 0; @@ -289,20 +332,21 @@ if (!fmt) fmt = ast_best_codec(capability); - ch->nativeformats = fmt; - /* ch->nativeformats = (capability) ? 0 : AST_FORMAT_SLINEAR; */ + ch->nativeformats = ch->rawwriteformat = ch->rawreadformat = fmt; ast_channel_set_fd(ch, 0, ast_rtp_fd(i->rtp)); ast_channel_set_fd(ch, 1, ast_rtcp_fd(i->rtp)); + ast_channel_set_fd(ch, 5, ast_udptl_fd(i->udptl)); + if (state == AST_STATE_RING) ch->rings = 1; ch->adsicpe = AST_ADSI_UNAVAILABLE; - ch->writeformat = capability; - ch->rawwriteformat = 0; - ch->readformat = capability; - ch->rawreadformat = 0; + if (capability) + fmt = ast_best_codec(capability); + ast_set_write_format(ch, fmt); + ast_set_read_format(ch, fmt); ch->tech_pvt = i; i->owner = ch; @@ -310,6 +354,11 @@ if (i->dtmfmode & H323_DTMF_INBAND) { 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) ast_dsp_set_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF); } @@ -413,6 +462,19 @@ ast_rtp_setqos(pvt->rtp, gTOS, 0, "ooh323"); + if (!(pvt->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, ipAddr))) { + ast_log(LOG_WARNING, "Unable to create UDPTL session: %s\n", + strerror(errno)); + ast_mutex_unlock(&pvt->lock); + ast_mutex_destroy(&pvt->lock); + free(pvt); + return NULL; + } + + ast_udptl_set_error_correction_scheme(pvt->udptl, UDPTL_ERROR_CORRECTION_NONE); + pvt->faxmode = 0; + pvt->t38support = gT38Support; + pvt->call_reference = callref; if (callToken) pvt->callToken = strdup(callToken); @@ -527,17 +589,15 @@ if (ext) ast_copy_string(p->exten, ext, sizeof(p->exten)); - /* if (peer->capability & format) { - p->capability = peer->capability & format; - } else { */ - p->capability = peer->capability; - /* } */ + p->capability = peer->capability; memcpy(&p->prefs, &peer->prefs, sizeof(struct ast_codec_pref)); p->dtmfmode |= peer->dtmfmode; + p->t38support = peer->t38support; ast_copy_string(p->accountcode, peer->accountcode, sizeof(p->accountcode)); p->amaflags = peer->amaflags; } else { p->dtmfmode = gDTMFMode; + p->t38support = gT38Support; p->capability = gCapability; memcpy(&p->prefs, &gPrefs, sizeof(struct ast_codec_pref)); @@ -719,7 +779,15 @@ return -1; } ast_mutex_lock(&p->lock); - if (p->rtp && (p->dtmfmode & H323_DTMF_RFC2833)) { + 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)) { ast_rtp_senddigit_begin(p->rtp, digit); } else if (((p->dtmfmode & H323_DTMF_Q931) || (p->dtmfmode & H323_DTMF_H245ALPHANUMERIC) || @@ -978,18 +1046,68 @@ struct ooh323_pvt *p = ast->tech_pvt; int res = 0; char *callToken = (char *)NULL; + int16_t* t38data; + int t38samples; if (p) { ast_mutex_lock(&p->lock); - -/* sending progress for first */ - if (!ast_test_flag(p, H323_OUTGOING) && !p->progsent) { - callToken = (p->callToken ? strdup(p->callToken) : NULL); - ooManualProgress(callToken); - p->progsent = 1; - free(callToken); + + if (f->frametype == AST_FRAME_MODEM) { + ast_debug(1, "Send UDPTL %d/%d len %d for %s\n", + f->frametype, f->subclass, f->datalen, ast->name); + if (p->udptl) + res = ast_udptl_write(p->udptl, f); + ast_mutex_unlock(&p->lock); + return res; } + + if (f->frametype == AST_FRAME_VOICE) { +/* sending progress for first */ + if (!ast_test_flag(p, H323_OUTGOING) && !p->progsent) { + callToken = (p->callToken ? strdup(p->callToken) : NULL); + ooManualProgress(callToken); + p->progsent = 1; + free(callToken); + } + + +/* if we are in fax t30-t38 transparent mode */ + + if (p->faxmode && p->t38support == T38_TRANSPARENT) { + if (f->subclass == AST_FORMAT_SLINEAR) { + t38data = f->data.ptr; + t38samples = f->samples; + } else { + t38samples = 0; + ast_verbose("Got non-slin frame for %s in transparent fax mode\n", + ast->name); + ast_set_write_format(ast, AST_FORMAT_SLINEAR); + ast_set_read_format(ast, AST_FORMAT_SLINEAR); + ast_mutex_unlock(&p->lock); + return 0; + } + + if (t38samples) { + t38_gateway_rx(&p->t38r_state, t38data, t38samples); + if (gH323Debug) + ast_debug(4, "t38gw_rx %d\n", t38samples); + } + + res = f->samples; + time_t ct = time(NULL); + if (ct - p->lastTxT38 > T38TOAUDIOTIMEOUT && !p->chmodepend) { + if (gH323Debug) + ast_verbose("request to change %s to audio because" + "t38 timeout\n", ast->name); + ooRequestChangeMode(p->callToken, 0); + p->chmodepend = 1; + } + ast_mutex_unlock(&p->lock); + return res; + } + + if (!(f->subclass & ast->nativeformats)) { if (ast->nativeformats != 0) { ast_log(LOG_WARNING, "Asked to transmit frame type %d," @@ -1093,6 +1211,45 @@ case AST_CONTROL_SRCUPDATE: ast_rtp_new_source(p->rtp); break; + + case AST_CONTROL_T38: + if (p->t38support != T38_FAXGW) { + enum ast_control_t38 message = AST_T38_REFUSED; + ast_queue_control_data(ast, AST_CONTROL_T38, &message, sizeof(message)); + break; + } + if (datalen != sizeof(enum ast_control_t38)) { + ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38. " + "Expected %d, got %d\n", + (int)sizeof(enum ast_control_t38), (int)datalen); + } else { + enum ast_control_t38* message = (enum ast_control_t38*) data; + switch (*message) { + + case AST_T38_REQUEST_NEGOTIATE: + + if (!p->chmodepend && !p->faxmode) { + ooRequestChangeMode(p->callToken, 1); + p->chmodepend = 1; + } + break; + + case AST_T38_REQUEST_TERMINATE: + + if (!p->chmodepend && p->faxmode) { + ooRequestChangeMode(p->callToken, 0); + p->chmodepend = 1; + } + break; + + + default: + ; + + } + + } + break; case AST_CONTROL_PROCEEDING: case -1: break; @@ -1101,15 +1258,65 @@ condition, callToken); } - ast_mutex_unlock(&p->lock); + ast_mutex_unlock(&p->lock); if (gH323Debug) ast_verbose("++++ ooh323_indicate %d on %s\n", condition, callToken); - free(callToken); + free(callToken); return -1; } +static int ooh323_queryoption(struct ast_channel *ast, int option, void *data, int *datalen) +{ + + struct ooh323_pvt *p = (struct ooh323_pvt *) ast->tech_pvt; + int res = -1; + enum ast_t38_state state = T38_STATE_UNAVAILABLE; + char* cp; + + if (!p) return -1; + + ast_mutex_lock(&p->lock); + + if (gH323Debug) + ast_verbose("----- ooh323_queryoption %d on channel %s\n", option, ast->name); + + switch (option) { + + case AST_OPTION_T38_STATE: + + if (*datalen != sizeof(enum ast_t38_state)) { + 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; + + + *((enum ast_t38_state *) data) = state; + res = 0; + break; + + default: ; + + } + + if (gH323Debug) + ast_verbose("+++++ ooh323_queryoption %d on channel %s\n", option, ast->name); + + ast_mutex_unlock(&p->lock); + + return res; +} + + + static int ooh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) { struct ooh323_pvt *p = newchan->tech_pvt; @@ -1171,14 +1378,11 @@ return; } if (gH323Debug) - ast_verbose("Writeformat before update %s\n", - ast_getformatname_multiple(formats,512, p->owner->writeformat)); + ast_verbose("Writeformat before update %s/%s\n", + ast_getformatname_multiple(formats,512, p->owner->writeformat), + ast_getformatname_multiple(formats,512, p->owner->nativeformats)); p->owner->nativeformats = fmt; - if (p->owner->writeformat == 0) - p->owner->writeformat = fmt; ast_set_write_format(p->owner, p->owner->writeformat); - if (p->owner->readformat == 0) - p->owner->readformat = fmt; ast_set_read_format(p->owner, p->owner->readformat); ast_channel_unlock(p->owner); } else @@ -1228,12 +1432,7 @@ ast_verbose("Readformat before update %s\n", ast_getformatname_multiple(formats,512, p->owner->readformat)); p->owner->nativeformats = fmt; - if (p->owner->readformat == 0) - p->owner->readformat = fmt; ast_set_read_format(p->owner, p->owner->readformat); - /* if (p->owner->writeformat == 0) - p->owner->writeformat = fmt; - ast_set_write_format(p->owner, p->owner->writeformat); */ ast_channel_unlock(p->owner); } else ast_log(LOG_ERROR, "No owner found\n"); @@ -1479,6 +1678,7 @@ p->capability = user->capability; memcpy(&p->prefs, &user->prefs, sizeof(struct ast_codec_pref)); p->dtmfmode |= user->dtmfmode; + p->t38support = user->t38support; /* Since, call is coming from a pbx user, no need to use gk */ /* OO_SETFLAG(p->flags, H323_DISABLEGK); OO_SETFLAG(call->flags, OO_M_DISABLEGK); */ @@ -1502,11 +1702,11 @@ } /* } */ - ooh323c_set_capability_for_call(call, &p->prefs, p->capability, p->dtmfmode); + ooh323c_set_capability_for_call(call, &p->prefs, p->capability, p->dtmfmode, p->t38support); configure_local_rtp(p, call); /* Incoming call */ - c = ooh323_new(p, AST_STATE_RING, p->username, p->capability); + c = ooh323_new(p, AST_STATE_RING, p->username, 0); if(!c) { ast_mutex_unlock(&p->lock); ast_log(LOG_ERROR, "Could not create ast_channel\n"); @@ -1662,7 +1862,7 @@ } ooh323c_set_capability_for_call(call, &p->prefs, p->capability, - p->dtmfmode); + p->dtmfmode, p->t38support); configure_local_rtp(p, call); ast_mutex_unlock(&p->lock); @@ -1861,6 +2061,7 @@ memcpy(&user->prefs, &gPrefs, sizeof(user->prefs)); user->rtptimeout = gRTPTimeout; user->dtmfmode = gDTMFMode; + user->t38support = gT38Support; /* set default context */ ast_copy_string(user->context, gContext, sizeof(user->context)); ast_copy_string(user->accountcode, gAccountcode, sizeof(user->accountcode)); @@ -1893,13 +2094,12 @@ } else if (!strcasecmp(v->name, "amaflags")) { user->amaflags = ast_cdr_amaflags2int(v->value); } else if (!strcasecmp(v->name, "ip")) { - strncpy(user->mIP, v->value, sizeof(user->mIP)-1); - user->mUseIP = 1; - } - else if (!strcasecmp(v->name, "host")) { - strncpy(user->mIP, v->value, sizeof(user->mIP)-1); + strncpy(user->mIP, v->value, sizeof(user->mIP)-1); + user->mUseIP = 1; + } else if (!strcasecmp(v->name, "host")) { + strncpy(user->mIP, v->value, sizeof(user->mIP)-1); user->mUseIP = 1; - } else if (!strcasecmp(v->name, "dtmfmode")) { + } else if (!strcasecmp(v->name, "dtmfmode")) { if (!strcasecmp(v->value, "rfc2833")) user->dtmfmode = H323_DTMF_RFC2833; else if (!strcasecmp(v->value, "q931keypad")) @@ -1912,6 +2112,17 @@ user->dtmfmode = H323_DTMF_INBAND; } else if (!strcasecmp(v->name, "relaxdtmf")) { user->dtmfmode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0; + } else if (!strcasecmp(v->name, "t38support")) { + if (!strcasecmp(v->value, "disabled")) + user->t38support = T38_DISABLED; + if (!strcasecmp(v->value, "no")) + user->t38support = T38_DISABLED; + else if (!strcasecmp(v->value, "faxgw")) + user->t38support = T38_FAXGW; + else if (!strcasecmp(v->value, "yes")) + user->t38support = T38_FAXGW; + else if (!strcasecmp(v->value, "transparent")) + user->t38support = T38_TRANSPARENT; } v = v->next; } @@ -1941,6 +2152,7 @@ ast_copy_string(peer->accountcode, gAccountcode, sizeof(peer->accountcode)); peer->amaflags = gAMAFLAGS; peer->dtmfmode = gDTMFMode; + peer->t38support = gT38Support; peer->port = 1720; if (0 == friend_type) { peer->mFriend = 1; @@ -2016,6 +2228,17 @@ peer->dtmfmode = H323_DTMF_INBAND; } else if (!strcasecmp(v->name, "relaxdtmf")) { peer->dtmfmode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0; + } else if (!strcasecmp(v->name, "t38support")) { + if (!strcasecmp(v->value, "disabled")) + peer->t38support = T38_DISABLED; + if (!strcasecmp(v->value, "no")) + peer->t38support = T38_DISABLED; + else if (!strcasecmp(v->value, "faxgw")) + peer->t38support = T38_FAXGW; + else if (!strcasecmp(v->value, "yes")) + peer->t38support = T38_FAXGW; + else if (!strcasecmp(v->value, "transparent")) + peer->t38support = T38_TRANSPARENT; } v = v->next; } @@ -2132,6 +2355,8 @@ gCapability = AST_FORMAT_ALAW; memset(&gPrefs, 0, sizeof(struct ast_codec_pref)); gDTMFMode = H323_DTMF_RFC2833; + gT38Support = T38_FAXGW; + gTRCLVL = OOTRCLVLERR; gRasGkMode = RasNoGatekeeper; gGatekeeper[0] = '\0'; gRTPTimeout = 60; @@ -2310,6 +2535,20 @@ } } else if (!strcasecmp(v->name, "relaxdtmf")) { gDTMFMode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0; + } else if (!strcasecmp(v->name, "t38support")) { + if (!strcasecmp(v->value, "disabled")) + gT38Support = T38_DISABLED; + if (!strcasecmp(v->value, "no")) + gT38Support = T38_DISABLED; + else if (!strcasecmp(v->value, "faxgw")) + gT38Support = T38_FAXGW; + else if (!strcasecmp(v->value, "yes")) + gT38Support = T38_FAXGW; + else if (!strcasecmp(v->value, "transparent")) + gT38Support = T38_TRANSPARENT; + } else if (!strcasecmp(v->name, "tracelevel")) { + gTRCLVL = atoi(v->value); + ooH323EpSetTraceLevel(gTRCLVL); } v = v->next; } @@ -2420,6 +2659,15 @@ 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_TRANSPARENT) + ast_cli(a->fd, "%s\n", "audio-transparent"); + 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)); @@ -2548,6 +2796,15 @@ 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_TRANSPARENT) + ast_cli(a->fd, "%s\n", "audio-transparent"); + 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)); @@ -2712,6 +2969,14 @@ else ast_cli(a->fd, "%s\n", "unknown"); + ast_cli(a->fd,"%-20s", "T.38 Mode: "); + if (gT38Support == T38_DISABLED) + ast_cli(a->fd, "%s\n", "disabled"); + else if (gT38Support == T38_TRANSPARENT) + ast_cli(a->fd, "%s\n", "audio-transparent"); + else if (gT38Support == T38_FAXGW) + ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible"); + ast_cli(a->fd, "%-20s%ld\n", "Call counter: ", callnumber); ast_cli(a->fd, "%-20s%s\n", "AccountCode: ", gAccountcode); @@ -2762,7 +3027,8 @@ .onCallEstablished = onCallEstablished, .onCallCleared = onCallCleared, .openLogicalChannels = NULL, - .onReceivedDTMF = &ooh323_onReceivedDigit + .onReceivedDTMF = &ooh323_onReceivedDigit, + .onModeChanged = onModeChanged }; ast_log(LOG_NOTICE, @@ -2799,6 +3065,7 @@ return 0; } ast_rtp_proto_register(&ooh323_rtp); + ast_udptl_proto_register(&ooh323_udptl); ast_cli_register_multiple(cli_ooh323, sizeof(cli_ooh323) / sizeof(struct ast_cli_entry)); /* fire up the H.323 Endpoint */ @@ -2811,12 +3078,11 @@ if (gIsGateway) ooH323EpSetAsGateway(); - ooH323EpSetVersionInfo(t35countrycode, t35extensions, manufacturer, vendor, version); + ooH323EpSetVersionInfo(t35countrycode, t35extensions, manufacturer, vendor, version); ooH323EpDisableAutoAnswer(); ooH323EpSetH225MsgCallbacks(h225Callbacks); - /* ooH323EpSetTraceLevel(OOTRCLVLDBGC); */ - ooH323EpSetTraceLevel(OOTRCLVLERR); + ooH323EpSetTraceLevel(gTRCLVL); ooH323EpSetLocalAddress(gIP, gPort); ooH323EpSetCallerID(gCallerID); @@ -3065,6 +3331,11 @@ ast_rtp_destroy(cur->rtp); cur->rtp = 0; } + + if (cur->udptl) { + ast_udptl_destroy(cur->udptl); + cur->udptl = NULL; + } /* Unlink us from the owner if we have one */ if (cur->owner) { @@ -3168,6 +3439,7 @@ /* First, take us out of the channel loop */ ast_cli_unregister_multiple(cli_ooh323, sizeof(cli_ooh323) / sizeof(struct ast_cli_entry)); ast_rtp_proto_unregister(&ooh323_rtp); + ast_udptl_proto_unregister(&ooh323_udptl); ast_channel_unregister(&ooh323_tech); #if 0 ast_unregister_atexit(&ast_ooh323c_exit); @@ -3435,6 +3707,16 @@ } } + ast_udptl_get_us(p->udptl, &us); + ast_copy_string(mediaInfo.lMediaIP, ast_inet_ntoa(us.sin_addr), sizeof(mediaInfo.lMediaIP)); + mediaInfo.lMediaPort = ntohs(us.sin_port); + mediaInfo.lMediaCntrlPort = mediaInfo.lMediaPort +1; + mediaInfo.cap = OO_T38; + strcpy(mediaInfo.dir, "transmit"); + ooAddMediaInfo(call, mediaInfo); + strcpy(mediaInfo.dir, "receive"); + ooAddMediaInfo(call, mediaInfo); + if (gH323Debug) ast_verbose("+++ configure_local_rtp\n"); @@ -3446,7 +3728,6 @@ { struct ooh323_pvt *p = NULL; struct sockaddr_in them; - char *callToken = (char *)NULL; if (gH323Debug) ast_verbose("--- setup_rtp_connection\n"); @@ -3498,6 +3779,150 @@ return; } +/* + udptl handling functions + */ + +static struct ast_udptl *ooh323_get_udptl_peer(struct ast_channel *chan) +{ + struct ooh323_pvt *p; + struct ast_udptl *udptl = NULL; + + p = chan->tech_pvt; + if (!p) + return NULL; + + ast_mutex_lock(&p->lock); + if (p->udptl) + udptl = p->udptl; + ast_mutex_unlock(&p->lock); + return udptl; +} + +static int ooh323_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl) +{ + struct ooh323_pvt *p; + + p = chan->tech_pvt; + if (!p) + return -1; + ast_mutex_lock(&p->lock); + if (udptl) + ast_udptl_get_peer(udptl, &p->udptlredirip); + else + memset(&p->udptlredirip, 0, sizeof(p->udptlredirip)); + + ast_mutex_unlock(&p->lock); + return 0; +} + +void setup_udptl_connection(ooCallData *call, const char *remoteIp, + int remotePort) +{ + struct ooh323_pvt *p = NULL; + struct sockaddr_in them; + + if (gH323Debug) + ast_verbose("--- setup_udptl_connection\n"); + + /* Find the call or allocate a private structure if call not found */ + p = find_call(call); + + if (!p) { + ast_log(LOG_ERROR, "Something is wrong: rtp\n"); + return; + } + + ast_mutex_lock(&p->lock); + if (p->owner) { + while (p->owner && ast_channel_trylock(p->owner)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + ast_mutex_unlock(&p->lock); + usleep(1); + ast_mutex_lock(&p->lock); + } + if (!p->owner) { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return; + } + } else { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return; + } + + them.sin_family = AF_INET; + them.sin_addr.s_addr = inet_addr(remoteIp); /* only works for IPv4 */ + them.sin_port = htons(remotePort); + ast_udptl_set_peer(p->udptl, &them); + p->t38_tx_enable = 1; + p->lastTxT38 = time(NULL); + if (p->t38support == T38_FAXGW) { + enum ast_control_t38 message = AST_T38_NEGOTIATED; + ast_queue_control_data(p->owner, AST_CONTROL_T38, &message, sizeof(message)); + } + if (gH323Debug) + ast_debug(1, "Receiving UDPTL %s:%d\n", ast_inet_ntoa(them.sin_addr), + ntohs(them.sin_port)); + + ast_channel_unlock(p->owner); + ast_mutex_unlock(&p->lock); + + if(gH323Debug) + ast_verbose("+++ setup_udptl_connection\n"); + + return; +} + +void close_udptl_connection(ooCallData *call) +{ + struct ooh323_pvt *p = NULL; + + if(gH323Debug) + ast_verbose("--- close_udptl_connection\n"); + + p = find_call(call); + if (!p) { + ast_log(LOG_ERROR, "Couldn't find matching call to close udptl " + "connection\n"); + return; + } + ast_mutex_lock(&p->lock); + if (p->owner) { + while (p->owner && ast_channel_trylock(p->owner)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + ast_mutex_unlock(&p->lock); + usleep(1); + ast_mutex_lock(&p->lock); + } + if (!p->owner) { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return; + } + } else { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return; + } + + p->t38_tx_enable = 0; + if (p->t38support == T38_FAXGW) { + enum ast_control_t38 message = AST_T38_TERMINATED; + ast_queue_control_data(p->owner, AST_CONTROL_T38, &message, sizeof(message)); + } + + ast_channel_unlock(p->owner); + ast_mutex_unlock(&p->lock); + + if(gH323Debug) + ast_verbose("+++ close_udptl_connection\n"); + + return; +} + +/* end of udptl handling */ int update_our_aliases(ooCallData *call, struct ooh323_pvt *p) { @@ -3546,6 +3971,24 @@ case 3: f = ast_rtcp_read(p->vrtp); /* RTCP Control Channel for video */ break; + case 5: + f = ast_udptl_read(p->udptl); /* UDPTL t.38 data */ + if (gH323Debug) ast_debug(1, "Got UDPTL %d/%d len %d for %s\n", + f->frametype, f->subclass, f->datalen, ast->name); + +/* if not transparent audio t.38 mode */ + if (p->t38support != T38_TRANSPARENT) + break; + + if (!p->faxmode) p->faxmode = 1; + if (p->t38_init) { + t38_core_rx_ifp_packet(&p->t38r_state.t38x.t38, (uint8_t *)f->data.ptr, + f->datalen, 0); + p->lastTxT38 = time(NULL); + } + f = &null_frame; + break; + default: f = &null_frame; } @@ -3556,7 +3999,7 @@ if (p->owner) { /* We already hold the channel lock */ - if (f->frametype == AST_FRAME_VOICE) { + if (f->frametype == AST_FRAME_VOICE && !p->faxmode) { if (f->subclass != p->owner->nativeformats) { ast_debug(1, "Oooh, format changed to %d\n", f->subclass); p->owner->nativeformats = f->subclass; @@ -3578,6 +4021,202 @@ return f; } +static int t30_read(const void *data) { + + struct ast_channel *c = (struct ast_channel *) data; + struct ooh323_pvt *p = (struct ooh323_pvt *) c->tech_pvt; + int len; + + static uint8_t buffer[AST_FRIENDLY_OFFSET + MAXT30 * sizeof(uint16_t)]; + int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET); + static struct ast_frame outf = { + .frametype = AST_FRAME_VOICE, + .subclass = AST_FORMAT_SLINEAR, + }; + + + if (!p) { + ast_log(LOG_ERROR, "No private structure for %s\n", c->name); + return 0; + } + + ast_mutex_lock(&p->lock); + + if (p->owner) { + while (p->owner && ast_channel_trylock(c)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + ast_mutex_unlock(&p->lock); + usleep(1); + ast_mutex_lock(&p->lock); + } + if (!p->owner) { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return 0; + } + } else { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return 0; + } + + + + if (p->faxmode && p->t38_init && p->t38_tx_enable) { + + + if ((len = t38_gateway_tx(&p->t38r_state, buf, MAXT30))) { + + outf.samples = len; + AST_FRAME_SET_BUFFER(&outf, buffer, AST_FRIENDLY_OFFSET, + len * sizeof(int16_t)); + ast_queue_frame(c, &outf); + + } + } + + ast_channel_unlock(c); + ast_mutex_unlock(&p->lock); + return 0; +} + + +static int t38_tx_packet_handler(t38_core_state_t *s, void *data, + unsigned int* buf, int len, int cout) +{ + struct ast_frame f = { AST_FRAME_MODEM, AST_MODEM_T38 }; + struct ooh323_pvt* p = (struct ooh323_pvt*) data; + int res; + f.datalen = len; + f.data.ptr = buf; + f.offset = 0; + + if (gH323Debug) + ast_debug(1, "Sending UDPTL packet of %d bytes\n", len); + if (p) { + ast_mutex_lock(&p->lock); + if (p->udptl) { + res = ast_udptl_write(p->udptl, &f); + p->lastTxT38 = time(NULL); + } + ast_mutex_unlock(&p->lock); + } + return 0; + +} + +static void span_message(int level, const char* msg) { + if (gH323Debug) ast_debug(1, msg); +} + + +void onModeChanged(ooCallData *call, int t38mode) { + struct ooh323_pvt *p; + struct ast_frame f; + + p = find_call(call); + if (!p) { + ast_log(LOG_ERROR, "No matching call found for %s\n", call->callToken); + return; + } + + ast_mutex_lock(&p->lock); + + if (gH323Debug) + ast_debug(1, "change mode to %d for %s\n", t38mode, call->callToken); + + if (t38mode == p->faxmode) { + if (gH323Debug) + ast_debug(1, "mode for %s is already %d\n", call->callToken, + t38mode); + ast_mutex_unlock(&p->lock); + return; + } + + if (p->owner) { + while (p->owner && ast_channel_trylock(p->owner)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + ast_mutex_unlock(&p->lock); + usleep(1); + ast_mutex_lock(&p->lock); + } + if (!p->owner) { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return; + } + } else { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return; + } + + if (t38mode) { + + + if (p->t38support == T38_FAXGW) { +/* AST_T38_CONTROL mode */ + + enum ast_control_t38 message = AST_T38_REQUEST_NEGOTIATE; + ast_queue_control_data(p->owner, AST_CONTROL_T38, &message, sizeof(message)); + p->faxmode = 1; + + } else if (t38_gateway_init(&p->t38r_state, t38_tx_packet_handler, p)) { +/* transparent slinear mode */ + + p->t38_init = 1; + + t38_gateway_set_transmit_on_idle(&p->t38r_state, FALSE); + + span_log_set_tag(&p->t38r_state.logging, "T.38G"); + span_log_set_tag(&p->t38r_state.t38x.t38.logging, "T.38"); + + span_log_set_message_handler(&p->t38r_state.logging, span_message); + span_log_set_message_handler(&p->t38r_state.t38x.t38.logging, span_message); + + span_log_set_level(&p->t38r_state.logging, + SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); + span_log_set_level(&p->t38r_state.t38x.t38.logging, + SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); + + + t38_set_t38_version(&p->t38r_state.t38x.t38, 0); + + t38_set_sequence_number_handling(&p->t38r_state.t38x.t38,0); + + t38_gateway_set_ecm_capability(&p->t38r_state, 1); + + t38_gateway_set_tep_mode(&p->t38r_state, TRUE); + + t38_gateway_set_supported_modems(&p->t38r_state, + T30_SUPPORT_V17 | T30_SUPPORT_V29 | T30_SUPPORT_V27TER); + + if (gH323Debug) + ast_debug(1,"Going to change native format for %s\n", call->callToken); + p->owner->nativeformats = AST_FORMAT_SLINEAR; + p->owner->rawreadformat = AST_FORMAT_SLINEAR; + p->owner->rawwriteformat = AST_FORMAT_SLINEAR; + ast_set_read_format(p->owner, p->owner->rawreadformat); + ast_set_write_format(p->owner, p->owner->rawwriteformat); + p->faxmode = 1; + ast_settimeout(p->owner, 34, t30_read, p->owner); + p->lastTxT38 = time(NULL); + } + } else { + if (p->t38support == T38_FAXGW) { + enum ast_control_t38 message = AST_T38_REQUEST_TERMINATE; + ast_queue_control_data(p->owner, AST_CONTROL_T38, &message, sizeof(message)); + } + p->faxmode = 0; + p->t38_init = 0; + } + + p->chmodepend = 0; + ast_channel_unlock(p->owner); + ast_mutex_unlock(&p->lock); +} + + int ooh323_convert_hangupcause_asteriskToH323(int cause) { --- ./channels/ooh323cDriver.c 2009-07-29 03:07:53.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323cDriver.c 2009-07-28 22:49:05.000000000 +0400 @@ -36,6 +36,11 @@ int ooh323c_stop_receive_channel(ooCallData *call, ooLogicalChannel *pChannel); int ooh323c_stop_transmit_channel(ooCallData *call, ooLogicalChannel *pChannel); +int ooh323c_start_receive_datachannel(ooCallData *call, ooLogicalChannel *pChannel); +int ooh323c_start_transmit_datachannel(ooCallData *call, ooLogicalChannel *pChannel); +int ooh323c_stop_receive_datachannel(ooCallData *call, ooLogicalChannel *pChannel); +int ooh323c_stop_transmit_datachannel(ooCallData *call, ooLogicalChannel *pChannel); + void* ooh323c_stack_thread(void* dummy) { @@ -266,7 +271,7 @@ } int ooh323c_set_capability_for_call - (ooCallData *call, struct ast_codec_pref *prefs, int capability, int dtmf) + (ooCallData *call, struct ast_codec_pref *prefs, int capability, int dtmf, int t38support) { int ret, x, txframes; int format=0; @@ -280,6 +285,13 @@ if(dtmf & H323_DTMF_H245SIGNAL || 1) ret |= ooCallEnableDTMFH245Signal(call); + if (t38support) + ooCapabilityAddT38Capability(call, OO_T38, OORXANDTX, + &ooh323c_start_receive_datachannel, + &ooh323c_start_transmit_datachannel, + &ooh323c_stop_receive_datachannel, + &ooh323c_stop_transmit_datachannel, + 0); for(x=0; 0 !=(format=ast_codec_pref_index(prefs, x)); x++) { @@ -345,7 +357,7 @@ if(gH323Debug) ast_verbose("\tAdding g729 capability to call(%s, %s)\n", call->callType, call->callToken); - ret|= ooCallAddG729Capability(call, OO_G729, txframes, 24, + ret|= ooCallAddG729Capability(call, OO_G729, txframes, 4, OORXANDTX, &ooh323c_start_receive_channel, &ooh323c_start_transmit_channel, &ooh323c_stop_receive_channel, @@ -353,7 +365,7 @@ if(gH323Debug) ast_verbose("\tAdding g729A capability to call(%s, %s)\n", call->callType, call->callToken); - ret= ooCallAddG729Capability(call, OO_G729A, txframes, 24, + ret= ooCallAddG729Capability(call, OO_G729A, txframes, 4, OORXANDTX, &ooh323c_start_receive_channel, &ooh323c_start_transmit_channel, &ooh323c_stop_receive_channel, @@ -361,7 +373,7 @@ if(gH323Debug) ast_verbose("\tAdding g729B capability to call(%s, %s)\n", call->callType, call->callToken); - ret|= ooCallAddG729Capability(call, OO_G729B, txframes, 24, + ret|= ooCallAddG729Capability(call, OO_G729B, txframes, 4, OORXANDTX, &ooh323c_start_receive_channel, &ooh323c_start_transmit_channel, &ooh323c_stop_receive_channel, @@ -490,6 +502,29 @@ return 1; } + +int ooh323c_start_receive_datachannel(ooCallData *call, ooLogicalChannel *pChannel) +{ + return 1; +} + +int ooh323c_start_transmit_datachannel(ooCallData *call, ooLogicalChannel *pChannel) +{ + setup_udptl_connection(call, pChannel->remoteIP, pChannel->remoteMediaPort); + return 1; +} + +int ooh323c_stop_receive_datachannel(ooCallData *call, ooLogicalChannel *pChannel) +{ + return 1; +} + +int ooh323c_stop_transmit_datachannel(ooCallData *call, ooLogicalChannel *pChannel) +{ + close_udptl_connection(call); + return 1; +} + int convertH323CapToAsteriskCap(int cap) { --- ./channels/ooh323c/src/ooCalls.c 2009-07-29 03:07:43.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323c/src/ooCalls.c 2009-07-28 22:49:05.000000000 +0400 @@ -98,6 +98,10 @@ if (OO_TESTFLAG(gH323ep.flags, OO_M_MEDIAWAITFORCONN)) OO_SETFLAG (call->flags, OO_M_MEDIAWAITFORCONN); + +// May 20090713. Fix it for Video session + + OO_SETFLAG(call->flags, OO_M_AUDIOSESSION); call->callState = OO_CALL_CREATED; call->callEndReason = OO_REASON_UNKNOWN; @@ -827,6 +831,23 @@ } } } + if(type == OO_CAP_TYPE_DATA) + { + if(!ooGetLogicalChannel(call, 3, dir)) + { + sessionID = 3; + } + else{ + if(call->masterSlaveState == OO_MasterSlave_Master) + sessionID = call->nextSessionID++; + else{ + sessionID = 0; /* Will be assigned by remote */ + OOTRACEDBGC4("Session id for %s channel of type data has to be " + "provided by remote.(%s, %s)\n", dir, call->callType, + call->callToken); + } + } + } return sessionID; } --- ./channels/ooh323c/src/ooStackCmds.h 2009-07-29 03:07:11.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323c/src/ooStackCmds.h 2009-07-28 22:49:05.000000000 +0400 @@ -66,7 +66,8 @@ OO_CMD_SENDDIGIT, /*!< Send dtmf */ OO_CMD_MANUALRINGBACK, /*!< Send Alerting - ringback */ OO_CMD_MANUALPROGRESS, /*!< Send progress */ - OO_CMD_STOPMONITOR /*!< Stop the event monitor */ + OO_CMD_STOPMONITOR, /*!< Stop the event monitor */ + OO_CMD_REQMODE /*!< Request new mode */ } OOStackCmdID; --- ./channels/ooh323c/src/ooCapability.h 2009-07-29 03:07:53.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323c/src/ooCapability.h 2009-07-29 00:25:40.000000000 +0400 @@ -71,7 +71,8 @@ OO_H263VIDEO = 31, OO_IS11172VIDEO = 32, /* mpeg */ OO_GENERICVIDEO = 33, - OO_EXTELEMVIDEO = 34 + OO_EXTELEMVIDEO = 34, + OO_T38 = 35 } OOCapabilities; @@ -659,6 +660,14 @@ ooH323EpCapability* ooIsDataTypeSupported (struct OOH323CallData *call, H245DataType *data, int dir); +/* fill t.38 application data */ +struct H245DataApplicationCapability_application* ooCreateT38ApplicationData + (OOCTXT* pctxt, H245DataApplicationCapability_application *app); + +/* create t.38 capability */ +struct H245DataApplicationCapability* ooCapabilityCreateT38Capability + (ooH323EpCapability *epCap, OOCTXT* pctxt, int dir); + /** * This function is used to clear the capability preference order. * @param call Handle to call, if capability preference order for call @@ -722,6 +731,9 @@ EXTERN const char* ooGetCapTypeText (OOCapabilities cap); +EXTERN int epCapIsPreferred(struct OOH323CallData *call, ooH323EpCapability *epCap); + + /** * @} */ --- ./channels/ooh323c/src/ooh323ep.c 2009-07-29 03:07:11.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323c/src/ooh323ep.c 2009-07-28 22:49:05.000000000 +0400 @@ -345,6 +345,7 @@ gH323ep.h323Callbacks.onCallCleared = h323Callbacks.onCallCleared; gH323ep.h323Callbacks.openLogicalChannels = h323Callbacks.openLogicalChannels; gH323ep.h323Callbacks.onReceivedDTMF = h323Callbacks.onReceivedDTMF; + gH323ep.h323Callbacks.onModeChanged = h323Callbacks.onModeChanged; return OO_OK; } --- ./channels/ooh323c/src/ooStackCmds.c 2009-07-29 03:07:11.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323c/src/ooStackCmds.c 2009-07-28 22:49:05.000000000 +0400 @@ -494,6 +494,54 @@ return OO_STKCMD_SUCCESS; } +OOStkCmdStat ooRequestChangeMode(const char *callToken, int isT38Mode) +{ + OOStackCommand cmd; + OOH323CallData *call; + + if(!callToken) + { + return OO_STKCMD_INVALIDPARAM; + } + + if(!(call = ooFindCallByToken(callToken))) { + return OO_STKCMD_INVALIDPARAM; + } + + if(call->CmdChan == 0) + { + if(ooCreateCallCmdConnection(call) != OO_OK) + return OO_STKCMD_CONNECTIONERR; + } + + memset(&cmd, 0, sizeof(OOStackCommand)); + cmd.type = OO_CMD_REQMODE; + + cmd.param1 = (void*) malloc(strlen(callToken)+1); + cmd.param2 = (void*) malloc(sizeof(int)); + if(!cmd.param1 || !cmd.param2) + { + if(cmd.param1) free(cmd.param1); /* Release memory */ + if(cmd.param2) free(cmd.param2); + return OO_STKCMD_MEMERR; + } + strcpy((char*)cmd.param1, callToken); + cmd.plen1 = strlen(callToken); + *((int *) cmd.param2) = isT38Mode; + cmd.plen2 = sizeof(int); + + if(ooWriteCallStackCommand(call,&cmd) != OO_OK) + { + free(cmd.param1); + free(cmd.param2); + return OO_STKCMD_WRITEERR; + } + free(cmd.param1); + free(cmd.param2); + + return OO_STKCMD_SUCCESS; +} + const char* ooGetStkCmdStatusCodeTxt(OOStkCmdStat stat) { --- ./channels/ooh323c/src/ooh323.c 2009-07-29 03:07:53.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323c/src/ooh323.c 2009-07-28 22:49:05.000000000 +0400 @@ -474,6 +474,26 @@ } if(!strcmp(pChannel->dir, "transmit")) { + /* May 20090728 */ + if (!epCapIsPreferred(call, pChannel->chanCap)) { + if(call->localTermCapState == OO_LocalTermCapExchange_Idle) { + ret = ooSendTermCapMsg(call); + if(ret != OO_OK) { + OOTRACEERR3("ERROR:Sending Terminal capability message (%s, %s)\n", + call->callType, call->callToken); + return ret; + } + } + if(call->masterSlaveState == OO_MasterSlave_Idle) { + ret = ooSendMasterSlaveDetermination(call); + if(ret != OO_OK) { + OOTRACEERR3("ERROR:Sending Master-slave determination message " + "(%s, %s)\n", call->callType, call->callToken); + return ret; + } + } + } + if(olc->forwardLogicalChannelParameters.multiplexParameters.t != T_H245OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters) { @@ -671,6 +691,26 @@ } if(!strcmp(pChannel->dir, "transmit")) { + /* May 20090728 */ + if (!epCapIsPreferred(call, pChannel->chanCap)) { + if(call->localTermCapState == OO_LocalTermCapExchange_Idle) { + ret = ooSendTermCapMsg(call); + if(ret != OO_OK) { + OOTRACEERR3("ERROR:Sending Terminal capability message (%s, %s)\n", + call->callType, call->callToken); + return ret; + } + } + if(call->masterSlaveState == OO_MasterSlave_Idle) { + ret = ooSendMasterSlaveDetermination(call); + if(ret != OO_OK) { + OOTRACEERR3("ERROR:Sending Master-slave determination message " + "(%s, %s)\n", call->callType, call->callToken); + return ret; + } + } + } + if(olc->forwardLogicalChannelParameters.multiplexParameters.t != T_H245OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters) { @@ -716,11 +756,11 @@ return OO_FAILED; } pChannel->chanCap->startTransmitChannel(call, pChannel); - } - /* Mark the current channel as established and close all other - logical channels with same session id and in same direction. - */ - ooOnLogicalChannelEstablished(call, pChannel); + /* Mark the current channel as established and close all other + logical channels with same session id and in same direction. + */ + ooOnLogicalChannelEstablished(call, pChannel); + } } finishPrint(); removeEventHandler(call->pctxt); @@ -763,6 +803,8 @@ return OO_FAILED; } } + + return OO_OK; } @@ -867,6 +909,26 @@ } if(!strcmp(pChannel->dir, "transmit")) { + /* May 20090728 */ + if (!epCapIsPreferred(call, pChannel->chanCap)) { + if(call->localTermCapState == OO_LocalTermCapExchange_Idle) { + ret = ooSendTermCapMsg(call); + if(ret != OO_OK) { + OOTRACEERR3("ERROR:Sending Terminal capability message (%s, %s)\n", + call->callType, call->callToken); + return ret; + } + } + if(call->masterSlaveState == OO_MasterSlave_Idle) { + ret = ooSendMasterSlaveDetermination(call); + if(ret != OO_OK) { + OOTRACEERR3("ERROR:Sending Master-slave determination message " + "(%s, %s)\n", call->callType, call->callToken); + return ret; + } + } + } + if(olc->forwardLogicalChannelParameters.multiplexParameters.t != T_H245OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters) { @@ -959,6 +1021,7 @@ return OO_FAILED; } } + return OO_OK; } --- ./channels/ooh323c/src/ooh245.h 2009-07-29 03:07:11.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323c/src/ooh245.h 2009-07-28 22:49:05.000000000 +0400 @@ -288,7 +288,7 @@ * * @return OO_OK, on success. OO_FAILED, on failure. */ -EXTERN int ooCloseAllLogicalChannels(struct OOH323CallData *call); +EXTERN int ooCloseAllLogicalChannels(struct OOH323CallData *call, char* dir); /** --- ./channels/ooh323c/src/ooCalls.h 2009-07-29 03:07:43.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323c/src/ooCalls.h 2009-07-28 23:52:21.000000000 +0400 @@ -55,6 +55,9 @@ #define OO_M_MANUALRINGBACK ASN1UINTCNT(0x10000000) #define OO_M_TRYBEMASTER ASN1UINTCNT(0x00000010) +#define OO_M_AUDIOSESSION ASN1UINTCNT(0x00000100) +#define OO_M_DATASESSION ASN1UINTCNT(0x00000200) +#define OO_M_T38SUPPORTED ASN1UINTCNT(0x00000400) /** * Call states. @@ -198,6 +201,9 @@ unsigned nextSessionID; /* Note by default 1 is audio session, 2 is video and 3 is data, from 3 onwards master decides*/ DList timerList; ASN1UINT msdRetries; + ASN1UINT8 requestSequence; + ASN1UINT reqFlags; + ASN1UINT t38sides; H235TimeStamp alertingTime, connectTime, endTime; /* time data for gatekeeper */ FastStartResponse *pFastStartRes; /* fast start response */ void *usrData; /*!flags, OO_M_FASTSTART) && pCall->remoteFastStartOLCs.count>0) { pFS = (ASN1DynOctStr*)memAlloc(pctxt, @@ -2471,7 +2471,10 @@ continue; } +/* don't send t38/other data caps in fasstart olcs */ + if (epCap->capType == OO_CAP_TYPE_DATA) + continue; OOTRACEDBGC4("Building olcs with capability %s. (%s, %s)\n", ooGetCapTypeText(epCap->cap), call->callType, @@ -2656,8 +2659,10 @@ /* For H.323 version 4 and higher, if fast connect, tunneling should be supported. */ - if(OO_TESTFLAG(call->flags, OO_M_FASTSTART)) + if(OO_TESTFLAG(call->flags, OO_M_FASTSTART)) { q931msg->userInfo->h323_uu_pdu.h245Tunneling = TRUE; + OO_SETFLAG(call->flags, OO_M_TUNNELING); + } OOTRACEDBGA3("Built SETUP message (%s, %s)\n", call->callType, call->callToken); @@ -2708,7 +2713,7 @@ return OO_FAILED; } q931msg->userInfo->h323_uu_pdu.m.h245TunnelingPresent=1; - q931msg->userInfo->h323_uu_pdu.h245Tunneling = OO_TESTFLAG(gH323ep.flags, + q931msg->userInfo->h323_uu_pdu.h245Tunneling = OO_TESTFLAG(call->flags, OO_M_TUNNELING); q931msg->userInfo->h323_uu_pdu.h323_message_body.t = T_H225H323_UU_PDU_h323_message_body_information; @@ -2979,9 +2984,6 @@ return OO_OK; } - - - int ooQ931SetCallingPartyNumberIE (OOCTXT* pctxt, Q931Message *pmsg, const char *number, unsigned plan, unsigned type, unsigned presentation, unsigned screening) @@ -3603,7 +3605,11 @@ "OORequestChannelCloseAck", "OORequestChannelCloseReject", "OORequestChannelCloseRelease", - "OOEndSessionCommand" + "OOEndSessionCommand", + "OOUserInputIndication", + "OORequestModeAck", + "OORequestModeReject", + "OORequestMode" }; int idx = msgType - OO_MSGTYPE_MIN; return ooUtilsGetText (idx, msgTypeText, OONUMBEROF(msgTypeText)); --- ./channels/ooh323c/src/ootypes.h 2009-07-29 03:07:43.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323c/src/ootypes.h 2009-07-28 22:49:05.000000000 +0400 @@ -185,8 +185,11 @@ #define OORequestChannelCloseRelease 128 #define OOEndSessionCommand 129 #define OOUserInputIndication 130 +#define OORequestModeAck 131 +#define OORequestModeReject 132 +#define OORequestMode 133 -#define OO_MSGTYPE_MAX 130 +#define OO_MSGTYPE_MAX 133 /* Timer types */ #define OO_CALLESTB_TIMER (1<<0) --- ./channels/ooh323c/src/ooCmdChannel.c 2009-07-29 03:07:43.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323c/src/ooCmdChannel.c 2009-07-28 22:49:05.000000000 +0400 @@ -397,6 +397,12 @@ break; + case OO_CMD_REQMODE: + OOTRACEINFO3("Processing RequestMode command %s, requested mode is %d\n", + (char *)cmd.param1, *(int *)cmd.param2); + ooSendRequestMode(call, *(int *)cmd.param2); + break; + default: OOTRACEERR1("ERROR:Unknown command\n"); } } --- ./channels/ooh323c/src/ooLogChan.c 2009-07-29 03:07:12.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323c/src/ooLogChan.c 2009-07-28 22:49:05.000000000 +0400 @@ -233,6 +233,26 @@ return NULL; } +/* function is to get channel with particular direction */ + +OOLogicalChannel* ooGetTransmitLogicalChannel + (OOH323CallData *call) +{ + OOLogicalChannel * pChannel = NULL; + pChannel = call->logicalChans; + while(pChannel) + { + OOTRACEINFO6("Listing logical channel %d cap %d state %d for (%s, %s)\n", + pChannel->channelNo, pChannel->chanCap->cap, pChannel->state, + call->callType, call->callToken); + if(!strcmp(pChannel->dir, "transmit") && pChannel->state == OO_LOGICALCHAN_IDLE) + return pChannel; + else + pChannel = pChannel->next; + } + return NULL; +} + int ooClearAllLogicalChannels(OOH323CallData *call) { OOLogicalChannel * temp = NULL, *prev = NULL; --- ./channels/ooh323c/src/ooh245.c 2009-07-29 03:07:53.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323c/src/ooh245.c 2009-07-29 00:34:05.000000000 +0400 @@ -323,6 +323,7 @@ ooH323EpCapability *epCap=NULL; H245TerminalCapabilitySet *termCap=NULL; H245AudioCapability *audioCap=NULL; + H245DataApplicationCapability *t38Cap = NULL; H245AudioTelephonyEventCapability *ateCap=NULL; H245UserInputCapability *userInputCap = NULL; H245CapabilityTableEntry *entry=NULL; @@ -479,6 +480,80 @@ altSetAudio->n++; i++; } + else if(epCap->capType == OO_CAP_TYPE_DATA) + { + + /* Create t.38 capability. If capability supports receive, we only + add it as receive capability in TCS. However, if it supports only + transmit, we add it as transmit capability in TCS. + */ + if((epCap->dir & OORX) && !(epCap->dir & OOTX)) + { + + OOTRACEDBGC3("Sending receive capability t38 in TCS.(%s, %s)\n", + call->callType, call->callToken); + + t38Cap = ooCapabilityCreateT38Capability(epCap, pctxt, OORX); + if(!t38Cap) + { + OOTRACEWARN3("WARN:Failed to create t38 capability for" + "%s, %s\n", + call->callType, call->callToken); + continue; + } + } + else if((epCap->dir & OOTX) && !(epCap->dir & OORX)) + { + OOTRACEDBGC3("Sending transmit capability t38 in TCS.(%s, %s)\n", + call->callType, call->callToken); + t38Cap = ooCapabilityCreateT38Capability(epCap, pctxt, OOTX); + if(!t38Cap) + { + OOTRACEWARN3("WARN:Failed to create capability t38 " + "(%s, %s)\n", + call->callType, call->callToken); + continue; + } + } + else{ + OOTRACEDBGC3("Sending transmit&recevie capability t38 in TCS.(%s, %s)\n", + call->callType, call->callToken); + t38Cap = ooCapabilityCreateT38Capability(epCap, pctxt, OOTX&OORX); + if(!t38Cap) + { + OOTRACEWARN3("WARN:Failed to create capability t38 " + "(%s, %s)\n", + call->callType, call->callToken); + continue; + } + } + /* Add Capabilities to Capability Table */ + entry = (H245CapabilityTableEntry*) memAlloc(pctxt, + sizeof(H245CapabilityTableEntry)); + if(!entry) + { + OOTRACEERR3("Error:Memory - ooSendTermCapMsg - entry(audio Cap)." + "(%s, %s)\n", call->callType, call->callToken); + return OO_FAILED; + } + memset(entry, 0, sizeof(H245CapabilityTableEntry)); + entry->m.capabilityPresent = 1; + if((epCap->dir & OORX) && (epCap->dir & OOTX)) { + entry->capability.t = T_H245Capability_receiveAndTransmitDataApplicationCapability; + entry->capability.u.receiveAndTransmitDataApplicationCapability = t38Cap; + } else if((epCap->dir & OORX)) { + entry->capability.t = T_H245Capability_receiveDataApplicationCapability; + entry->capability.u.receiveDataApplicationCapability = t38Cap; + }else{ + entry->capability.t = T_H245Capability_transmitDataApplicationCapability; + entry->capability.u.transmitDataApplicationCapability = t38Cap; + } + entry->capabilityTableEntryNumber = i+1; + dListAppend(pctxt , &(termCap->capabilityTable), entry); + altSetAudio->elem[altSetAudio->n] = i+1; + altSetAudio->n++; + i++; + } else if(epCap->capType == OO_CAP_TYPE_VIDEO) { if((epCap->dir & OORX)) @@ -1092,6 +1167,260 @@ return OO_OK; } +/* handling requestmode routines */ + +int ooSendRequestModeAck(OOH323CallData* call, + H245SequenceNumber sequenceNumber) +{ + int ret=0; + H245ResponseMessage* response=NULL; + H245Message *ph245msg=NULL; + OOCTXT *pctxt=call->msgctxt; + + ret = ooCreateH245Message(call, &ph245msg, + T_H245MultimediaSystemControlMessage_response); + if(ret != OO_OK) + { + OOTRACEERR3("Error:H245 message creation failed for - RequestMode " + "Ack (%s, %s)\n",call->callType, + call->callToken); + return OO_FAILED; + } + ph245msg->msgType = OORequestModeAck; + response = ph245msg->h245Msg.u.response; + memset(response, 0, sizeof(H245ResponseMessage)); + response->t = T_H245ResponseMessage_requestModeAck; + response->u.requestModeAck = (H245RequestModeAck *) + ASN1MALLOC(pctxt, sizeof(H245RequestModeAck)); + memset(response->u.requestModeAck, 0, + sizeof(H245RequestModeAck)); + + response->u.requestModeAck->sequenceNumber = sequenceNumber; + response->u.requestModeAck->response.t = + T_H245RequestModeAck_response_willTransmitMostPreferredMode; + + OOTRACEDBGA3("Built RequestModeAck (%s, %s)\n", + call->callType, call->callToken); + ret = ooSendH245Msg(call, ph245msg); + if(ret != OO_OK) + { + OOTRACEERR3("Error:Failed to enqueue RequestModeAck message" + " to outbound queue. (%s, %s)\n", call->callType, + call->callToken); + } + + ooFreeH245Message(call, ph245msg); + return ret; +} + +int ooSendRequestModeReject(OOH323CallData* call, + H245SequenceNumber sequenceNumber) +{ + int ret=0; + H245ResponseMessage* response=NULL; + H245Message *ph245msg=NULL; + OOCTXT *pctxt=call->msgctxt; + + ret = ooCreateH245Message(call, &ph245msg, + T_H245MultimediaSystemControlMessage_response); + if(ret != OO_OK) + { + OOTRACEERR3("Error:H245 message creation failed for - RequstMode " + "Reject (%s, %s)\n",call->callType, + call->callToken); + return OO_FAILED; + } + ph245msg->msgType = OORequestModeReject; + response = ph245msg->h245Msg.u.response; + memset(response, 0, sizeof(H245ResponseMessage)); + response->t = T_H245ResponseMessage_requestModeReject; + response->u.requestModeReject = (H245RequestModeReject *) + ASN1MALLOC(pctxt, sizeof(H245RequestModeReject)); + memset(response->u.requestModeReject, 0, + sizeof(H245RequestModeReject)); + + response->u.requestModeReject->sequenceNumber = sequenceNumber; + response->u.requestModeReject->cause.t = + T_H245RequestModeReject_cause_modeUnavailable; + + OOTRACEDBGA3("Built RequestModeReject (%s, %s)\n", + call->callType, call->callToken); + ret = ooSendH245Msg(call, ph245msg); + if(ret != OO_OK) + { + OOTRACEERR3("Error:Failed to enqueue RequestModeReject message" + " to outbound queue. (%s, %s)\n", call->callType, + call->callToken); + } + + ooFreeH245Message(call, ph245msg); + return ret; +} + +int ooSendRequestMode(OOH323CallData* call, + int isT38Mode) +{ + int ret=0; + H245RequestMessage *request; + H245Message *ph245msg=NULL; + OOCTXT *pctxt=call->msgctxt; + + + H245ModeDescription pModeDesc; + H245ModeElement pModeElem; + H245ModeElement* pModeElemRef = &pModeElem; + + if (isT38Mode && !OO_TESTFLAG(call->flags, OO_M_T38SUPPORTED)) /* t38 req but we dont support */ + return OO_OK; + + ret = ooCreateH245Message(call, &ph245msg, + T_H245MultimediaSystemControlMessage_request); + if(ret != OO_OK) + { + OOTRACEERR3("Error:H245 message creation failed for - RequstMode " + "(%s, %s)\n",call->callType, + call->callToken); + return OO_FAILED; + } + ph245msg->msgType = OORequestMode; + request = ph245msg->h245Msg.u.request; + memset(request, 0, sizeof(H245RequestMessage)); + request->t = T_H245RequestMessage_requestMode; + + request->u.requestMode = (H245RequestMode *) + ASN1MALLOC(pctxt, sizeof(H245RequestMode)); + memset(request->u.requestMode, 0, + sizeof(H245RequestMode)); + + call->requestSequence++; + call->reqFlags = (isT38Mode) ? OO_M_DATASESSION : OO_M_AUDIOSESSION; + + request->u.requestMode->sequenceNumber = call->requestSequence; + memset(&pModeElem, 0, sizeof(pModeElem)); + memset(&pModeDesc, 0, sizeof(pModeDesc)); + dListInit(&(request->u.requestMode->requestedModes)); + dListInit(&pModeDesc); + + if (isT38Mode) { + + pModeElem.type.t = T_H245ModeElementType_dataMode; + pModeElem.type.u.dataMode = (H245DataMode *) memAllocZ(pctxt, sizeof(H245DataMode)); + pModeElem.type.u.dataMode->bitRate = 144; + if (!ooCreateT38ApplicationData(pctxt, + (H245DataApplicationCapability_application*) &(pModeElem.type.u.dataMode->application))) { + OOTRACEERR3("Error:Memory - ooCapabilityCreateT38Capability - (%s, %s)\n", + call->callType, + call->callToken); + } + } else { + pModeElem.type.t = T_H245ModeElementType_audioMode; + pModeElem.type.u.audioMode = (H245AudioMode *) memAllocZ(pctxt, sizeof(H245AudioMode)); + pModeElem.type.u.audioMode->t = T_H245AudioMode_genericAudioMode; + pModeElem.type.u.audioMode->u.genericAudioMode = (H245GenericCapability *) + memAllocZ(pctxt, sizeof(H245GenericCapability)); + pModeElem.type.u.audioMode->u.genericAudioMode->capabilityIdentifier.t = + T_H245CapabilityIdentifier_domainBased; + pModeElem.type.u.audioMode->u.genericAudioMode->capabilityIdentifier.u.domainBased = + "H.323"; + pModeElem.type.u.audioMode->u.genericAudioMode->m.maxBitRatePresent = TRUE; + pModeElem.type.u.audioMode->u.genericAudioMode->maxBitRate = 144; + } + + dListAppend(pctxt, &pModeDesc, &pModeElem); + dListAppend(pctxt, &(request->u.requestMode->requestedModes), &pModeDesc); + + ret = ooSendH245Msg(call, ph245msg); + if(ret != OO_OK) + { + OOTRACEERR3("Error:Failed to enqueue RequestMode message" + " to outbound queue. (%s, %s)\n", call->callType, + call->callToken); + } + + ooFreeH245Message(call, ph245msg); + return ret; +} + +void ooOnReceivedRequestModeAck(OOH323CallData* call, H245RequestModeAck * requestModeAck) +{ + int t38mode; + + if (!call->reqFlags) return; + + if (OO_TESTFLAG(call->reqFlags, OO_M_AUDIOSESSION)) { + OO_SETFLAG(call->flags, OO_M_AUDIOSESSION); + OO_CLRFLAG(call->flags, OO_M_DATASESSION); + t38mode = 0; + } else { + OO_CLRFLAG(call->flags, OO_M_AUDIOSESSION); + OO_SETFLAG(call->flags, OO_M_DATASESSION); + t38mode = 1; + } + + call->reqFlags = 0; /* don't handle duplicate ack packet */ + + ooCloseAllLogicalChannels(call, "transmit"); + if(gH323ep.h323Callbacks.onModeChanged) { + OOTRACEDBGA3("Handle RequestModeAck: (%s, %s), calling " + "callback onModeChanged\n", call->callType, call->callToken); + gH323ep.h323Callbacks.onModeChanged(call, t38mode); + } +} + +int ooHandleRequestMode(OOH323CallData* call, + H245RequestMode *requestMode) +{ + + H245ModeDescription** pModeRef; + H245ModeElement** pModeElem; + H245ModeElementType* pMode; + int ret = 0; + + pModeRef = (H245ModeDescription**)dListFindByIndex(&requestMode->requestedModes, 0); + pModeElem = (H245ModeElement **) dListFindByIndex(*pModeRef, 0); + pMode = &((*pModeElem)->type); + OOTRACEDBGA5("Handle RequestMode: " + " modetype: %d/%d for (%s, %s)\n", pMode->t, pMode->u.dataMode->application.t, + call->callType, + call->callToken); + switch (pMode->t) { + case T_H245ModeElementType_dataMode: + if (pMode->u.dataMode->application.t == T_H245DataMode_application_t38fax && + OO_TESTFLAG(call->flags, OO_M_T38SUPPORTED)) { + if (ooSendRequestModeAck(call, requestMode->sequenceNumber) == OO_OK && + OO_TESTFLAG(call->flags, OO_M_AUDIOSESSION)) { + + OO_CLRFLAG(call->flags, OO_M_AUDIOSESSION); + OO_SETFLAG(call->flags, OO_M_DATASESSION); + if(gH323ep.h323Callbacks.onModeChanged) { + OOTRACEDBGA3("Handle RequestMode: (%s, %s), calling " + "callback onModeChanged\n", call->callType, call->callToken); + gH323ep.h323Callbacks.onModeChanged(call, 1); + } + } + } else { + ooSendRequestModeReject(call, requestMode->sequenceNumber); + } + break; + case T_H245ModeElementType_audioMode: + if (ooSendRequestModeAck(call, requestMode->sequenceNumber) == OO_OK && + OO_TESTFLAG(call->flags, OO_M_DATASESSION)) { + + OO_CLRFLAG(call->flags, OO_M_DATASESSION); + OO_SETFLAG(call->flags, OO_M_AUDIOSESSION); + if(gH323ep.h323Callbacks.onModeChanged) { + OOTRACEDBGA3("Handle RequestMode: (%s, %s), calling " + "callback onModeChanged\n", call->callType, call->callToken); + gH323ep.h323Callbacks.onModeChanged(call, 0); + } + } + break; + default: + ; + } + return OO_OK; + +} int ooHandleOpenLogicalChannel(OOH323CallData* call, H245OpenLogicalChannel *olc) @@ -1126,14 +1455,8 @@ break; case T_H245DataType_videoData: case T_H245DataType_audioData: - ooHandleOpenLogicalChannel_helper(call, olc); - break; case T_H245DataType_data: - OOTRACEWARN3("Warn:Media channel data type " - "'T_H245DataType_data' not supported (%s, %s)\n", - call->callType, call->callToken); - ooSendOpenLogicalChannelReject(call, olc->forwardLogicalChannelNumber, - T_H245OpenLogicalChannelReject_cause_dataTypeNotSupported); + ooHandleOpenLogicalChannel_helper(call, olc); break; case T_H245DataType_encryptionData: OOTRACEWARN3("Warn:Media channel data type " @@ -1417,7 +1740,7 @@ H245UnicastAddress *unicastAddr; H245UnicastAddress_iPAddress *iPAddress; H245UnicastAddress *unicastAddr1; - H245UnicastAddress_iPAddress *iPAddress1; + H245UnicastAddress_iPAddress *iPAddress1 = NULL; if(!((olcAck->m.forwardMultiplexAckParametersPresent == 1) && (olcAck->forwardMultiplexAckParameters.t == @@ -1462,30 +1785,29 @@ iPAddress->network.data[3]); /* Extract media control channel address */ - if(h2250lcap->m.mediaControlChannelPresent != 1) - { - OOTRACEERR3("Error: Processing OpenLogicalChannelAck - Missing media " - "control channel (%s, %s)\n", call->callType, call->callToken); - return OO_FAILED; - } - if(h2250lcap->mediaControlChannel.t != + if(h2250lcap->m.mediaControlChannelPresent == 1) { + if(h2250lcap->mediaControlChannel.t != T_H245TransportAddress_unicastAddress) - { - OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media control " + { + OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media control " "channel addres type is not unicast (%s, %s)\n", call->callType, call->callToken); - return OO_FAILED; - } + return OO_FAILED; + } - unicastAddr1 = h2250lcap->mediaControlChannel.u.unicastAddress; - if(unicastAddr1->t != T_H245UnicastAddress_iPAddress) - { - OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media control " + unicastAddr1 = h2250lcap->mediaControlChannel.u.unicastAddress; + if(unicastAddr1->t != T_H245UnicastAddress_iPAddress) { + OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media control " "channel address type is not IP (%s, %s)\n", call->callType, call->callToken); - return OO_FAILED; + return OO_FAILED; + } + + iPAddress1 = unicastAddr1->u.iPAddress; + } else { + OOTRACEDBGA3("Warning: Processing OpenLogicalChannelAck - Missing media " + "control channel (%s, %s)\n", call->callType, call->callToken); } - iPAddress1 = unicastAddr1->u.iPAddress; /* Set remote destination address for rtp session */ // strcpy(call->remoteIP, remoteip); @@ -1508,7 +1830,8 @@ /* Populate ports &ip for channel */ strcpy(pLogicalChannel->remoteIP, remoteip); pLogicalChannel->remoteMediaPort = iPAddress->tsapIdentifier; - pLogicalChannel->remoteMediaControlPort = iPAddress1->tsapIdentifier; + if (iPAddress1) + pLogicalChannel->remoteMediaControlPort = iPAddress1->tsapIdentifier; if(pLogicalChannel->chanCap->startTransmitChannel) { @@ -1765,14 +2088,15 @@ return OO_OK; } -int ooCloseAllLogicalChannels(OOH323CallData *call) +int ooCloseAllLogicalChannels(OOH323CallData *call, char* dir) { ooLogicalChannel *temp; temp = call->logicalChans; while(temp) { - if(temp->state == OO_LOGICALCHAN_ESTABLISHED) + if(temp->state == OO_LOGICALCHAN_ESTABLISHED && + (dir == NULL || !strcmp(temp->dir,dir))) { /* Sending closelogicalchannel only for outgoing channels*/ if(!strcmp(temp->dir, "transmit")) @@ -2217,13 +2541,23 @@ case T_H245RequestMessage_openLogicalChannel: ooHandleOpenLogicalChannel(call, request->u.openLogicalChannel); + if(!ooGetTransmitLogicalChannel(call)) + ooOpenLogicalChannels(call); break; + case T_H245RequestMessage_requestMode: + OOTRACEINFO4("Received request mode - %d (%s, %s)\n", + request->u.requestMode->sequenceNumber, call->callType, call->callToken); + ooHandleRequestMode(call, + request->u.requestMode); + break; case T_H245RequestMessage_closeLogicalChannel: OOTRACEINFO4("Received close logical Channel - %d (%s, %s)\n", request->u.closeLogicalChannel->forwardLogicalChannelNumber, call->callType, call->callToken); - ooOnReceivedCloseLogicalChannel(call, - request->u.closeLogicalChannel); + if (ooOnReceivedCloseLogicalChannel(call, + request->u.closeLogicalChannel) == OO_OK) { + ooCloseAllLogicalChannels(call, NULL); + } break; case T_H245RequestMessage_requestChannelClose: OOTRACEINFO4("Received RequestChannelClose - %d (%s, %s)\n", @@ -2328,6 +2662,21 @@ call->callEndReason = OO_REASON_NOCOMMON_CAPABILITIES; } break; + case T_H245ResponseMessage_requestModeAck: + if (call->requestSequence == response->u.requestModeAck->sequenceNumber) { + /* response to our last request, process it */ + ooOnReceivedRequestModeAck(call, response->u.requestModeAck); + } + break; + case T_H245ResponseMessage_requestModeReject: + OOTRACEDBGC3("Received requestModeReject, clearing call (%s, %s)\n", + call->callType, call->callToken); + if(call->callState < OO_CALL_CLEAR) + { + call->callState = OO_CALL_CLEAR; + call->callEndReason = OO_REASON_REMOTE_REJECTED; + } + break; case T_H245ResponseMessage_openLogicalChannelAck: for(i = 0; itimerList.count; i++) { @@ -2547,6 +2896,10 @@ } } + if (call->t38sides == 3) /* both side support t.38 */ + OO_SETFLAG(call->flags, OO_M_T38SUPPORTED); + else + OO_CLRFLAG(call->flags, OO_M_T38SUPPORTED); /* Update remoteTermCapSetState */ call->remoteTermCapState = OO_RemoteTermCapSetRecvd; @@ -2866,21 +3219,20 @@ if(gH323ep.callMode == OO_CALLMODE_AUDIOCALL || gH323ep.callMode == OO_CALLMODE_AUDIOTX) { - //if (!OO_TESTFLAG (call->flags, OO_M_AUDIOSESSION)) - //{ + if (OO_TESTFLAG (call->flags, OO_M_AUDIOSESSION)) { ret = ooOpenLogicalChannel(call, OO_CAP_TYPE_AUDIO); - if(ret != OO_OK) - { - OOTRACEERR3("ERROR:Failed to open audio channels. Clearing call." - "(%s, %s)\n", call->callType, call->callToken); - if(call->callState < OO_CALL_CLEAR) - { - call->callEndReason = OO_REASON_LOCAL_CLEARED; - call->callState = OO_CALL_CLEAR; - } - return ret; - } - // } + } else if (OO_TESTFLAG (call->flags, OO_M_DATASESSION)) { + ret = ooOpenLogicalChannel(call, OO_CAP_TYPE_DATA); + } + if(ret != OO_OK) { + OOTRACEERR3("ERROR:Failed to open audio/data channels. Clearing call." + "(%s, %s)\n", call->callType, call->callToken); + if (call->callState < OO_CALL_CLEAR) { + call->callEndReason = OO_REASON_LOCAL_CLEARED; + call->callState = OO_CALL_CLEAR; + } + return ret; + } } if(gH323ep.callMode == OO_CALLMODE_VIDEOCALL) @@ -3015,6 +3367,7 @@ case OO_GSMHALFRATE: case OO_GSMENHANCEDFULLRATE: case OO_H263VIDEO: + case OO_T38: ooOpenChannel(call, epCap); break; @@ -3035,6 +3388,7 @@ H245OpenLogicalChannel_forwardLogicalChannelParameters *flcp = NULL; H245AudioCapability *audioCap = NULL; H245VideoCapability *videoCap = NULL; + H245DataApplicationCapability *t38Cap = NULL; H245H2250LogicalChannelParameters *h2250lcp = NULL; H245UnicastAddress *unicastAddrs = NULL; H245UnicastAddress_iPAddress *iPAddress = NULL; @@ -3136,6 +3490,23 @@ flcp->dataType.u.videoData = videoCap; } + else if(epCap->capType == OO_CAP_TYPE_DATA) + { + flcp->dataType.t = T_H245DataType_data; + /* set audio capability for channel */ + t38Cap = ooCapabilityCreateT38Capability(epCap,pctxt, OOTX); + if(!t38Cap) + { + OOTRACEERR4("Error:Failed to create duplicate T38 capability in " + "ooOpenChannel- %s (%s, %s)\n", + ooGetCapTypeText(epCap->cap), call->callType, + call->callToken); + ooFreeH245Message(call, ph245msg); + return OO_FAILED; + } + + flcp->dataType.u.data = t38Cap; + } else{ OOTRACEERR1("Error: Unhandled media type in ooOpenChannel\n"); return OO_FAILED; @@ -3187,7 +3558,7 @@ } ooFreeH245Message(call, ph245msg); - return ret; + return ret; } @@ -3530,13 +3901,20 @@ int ooRequestChannelCloseTimerExpired(void *pdata) { int ret = 0; + ooLogicalChannel *pChannel = NULL; ooTimerCallback *cbData = (ooTimerCallback*)pdata; OOH323CallData *call = cbData->call; - OOTRACEINFO3("OpenLogicalChannelTimer expired. (%s, %s)\n", call->callType, + OOTRACEINFO3("CloseLogicalChannelTimer expired. (%s, %s)\n", call->callType, call->callToken); - ooSendRequestChannelCloseRelease(call, cbData->channelNumber); + pChannel = ooFindLogicalChannelByLogicalChannelNo(call, + cbData->channelNumber); + if(pChannel) + ooSendRequestChannelCloseRelease(call, cbData->channelNumber); + else + return OO_OK; + ret = ooClearLogicalChannel(call, cbData->channelNumber); if(ret != OO_OK) --- ./channels/ooh323c/src/ooCapability.c 2009-07-29 03:07:53.000000000 +0400 +++ ../../asterisk-addons-1.6.1.0/./channels/ooh323c/src/ooCapability.c 2009-07-29 00:21:44.000000000 +0400 @@ -338,8 +338,7 @@ if(!call->ourCaps){ call->ourCaps = epCap; ooResetCapPrefs(call); - } - else{ + }else{ cur = call->ourCaps; while(cur->next) cur = cur->next; cur->next = epCap; @@ -452,6 +451,19 @@ return OO_OK; } +int epCapIsPreferred(OOH323CallData *call, ooH323EpCapability *epCap) +{ + ooH323EpCapability *curCap = call->ourCaps; + while (curCap) { + if (curCap->capType == epCap->capType) { + if (curCap->cap == epCap->cap) + return 1; + else + return 0; + } + curCap = curCap->next; + } +} int ooCapabilityAddGSMCapability(OOH323CallData *call, int cap, unsigned framesPerPkt, OOBOOL comfortNoise, @@ -547,6 +559,100 @@ return OO_OK; } +/* Used for T38 */ +int ooCapabilityAddT38Capability + (OOH323CallData *call, int cap, int dir, + cb_StartReceiveChannel startReceiveChannel, + cb_StartTransmitChannel startTransmitChannel, + cb_StopReceiveChannel stopReceiveChannel, + cb_StopTransmitChannel stopTransmitChannel, + OOBOOL remote) +{ + ooH323EpCapability *epCap = NULL, *cur=NULL; + OOCapParams *params=NULL; + OOCTXT *pctxt=NULL; + if(!call) pctxt = &gH323ep.ctxt; + else pctxt = call->pctxt; + + epCap = (ooH323EpCapability*)memAllocZ(pctxt, sizeof(ooH323EpCapability)); + params = (OOCapParams*) memAlloc(pctxt, sizeof(OOCapParams)); + memset(params, 0 , sizeof(OOCapParams)); + if(!epCap || !params) + { + OOTRACEERR1("ERROR: Memory - ooCapabilityAddT38Capability - " + "epCap/params\n"); + return OO_FAILED; + } + + if(dir & OORXANDTX) { + epCap->dir = OORX; + epCap->dir |= OOTX; + } + else { + epCap->dir = dir; + } + + epCap->cap = cap; + epCap->capType = OO_CAP_TYPE_DATA; + epCap->params = (void*)params; + epCap->startReceiveChannel = startReceiveChannel; + epCap->startTransmitChannel = startTransmitChannel; + epCap->stopReceiveChannel = stopReceiveChannel; + epCap->stopTransmitChannel = stopTransmitChannel; + epCap->next = NULL; + + if(!call) + { + /* Add as local capability */ + OOTRACEDBGC2("Adding endpoint capability %s. \n", + ooGetCapTypeText(epCap->cap)); + if(!gH323ep.myCaps) { + gH323ep.myCaps = epCap; + } + else{ + cur = gH323ep.myCaps; + while(cur->next) cur = cur->next; + cur->next = epCap; + } + ooAppendCapToCapPrefs(NULL, cap); + gH323ep.noOfCaps++; + } + else{ + if(remote) + { + /* Add as remote capability */ + if(!call->remoteCaps) { + call->remoteCaps = epCap; + } + else{ + cur = call->remoteCaps; + while(cur->next) cur = cur->next; + cur->next = epCap; + } + call->t38sides |= 2; + } + else{ + /* Add as our capability */ + OOTRACEDBGC4("Adding call specific capability %s. (%s, %s)\n", + ooGetCapTypeText(epCap->cap), call->callType, + call->callToken); + if(!call->ourCaps){ + call->ourCaps = epCap; + ooResetCapPrefs(call); + } + else{ + cur = call->ourCaps; + while(cur->next) cur = cur->next; + cur->next = epCap; + } + ooAppendCapToCapPrefs(call, cap); + call->t38sides |= 1; + } + } + + return OO_OK; +} + @@ -990,6 +1096,79 @@ return NULL; } +/* Our t.38 params */ + +struct H245DataApplicationCapability_application* ooCreateT38ApplicationData + (OOCTXT* pctxt, H245DataApplicationCapability_application *app) +{ + app->t = T_H245DataApplicationCapability_application_t38fax; + app->u.t38fax = + (H245DataApplicationCapability_application_t38fax *) memAlloc(pctxt, + sizeof(H245DataApplicationCapability_application_t38fax)); + if (!app->u.t38fax) { + OOTRACEERR1("Error:Memory - ooCreateT38AppData\n"); + return NULL; + } + memset(app->u.t38fax, 0, sizeof(H245DataApplicationCapability_application_t38fax)); + app->u.t38fax->t38FaxProtocol.t = T_H245DataProtocolCapability_udp; + app->u.t38fax->t38FaxProfile.m.versionPresent = TRUE; + app->u.t38fax->t38FaxProfile.version = 0; + app->u.t38fax->t38FaxProfile.m.t38FaxRateManagementPresent = TRUE; + app->u.t38fax->t38FaxProfile.t38FaxRateManagement.t = + T_H245T38FaxRateManagement_transferredTCF; + app->u.t38fax->t38FaxProfile.m.t38FaxUdpOptionsPresent = TRUE; + app->u.t38fax->t38FaxProfile.t38FaxUdpOptions.m.t38FaxMaxBufferPresent = TRUE; + app->u.t38fax->t38FaxProfile.t38FaxUdpOptions.t38FaxMaxBuffer = 200; + app->u.t38fax->t38FaxProfile.t38FaxUdpOptions.m.t38FaxMaxDatagramPresent = TRUE; + app->u.t38fax->t38FaxProfile.t38FaxUdpOptions.t38FaxMaxDatagram = 72; + app->u.t38fax->t38FaxProfile.t38FaxUdpOptions.t38FaxUdpEC.t = + T_H245T38FaxUdpOptions_t38FaxUdpEC_t38UDPRedundancy; + + return app; +} + +/* This is used for T.38 */ +struct H245DataApplicationCapability* ooCapabilityCreateT38Capability + (ooH323EpCapability *epCap, OOCTXT* pctxt, int dir) +{ + H245DataApplicationCapability *pT38=NULL; + OOCapParams *params; + if(!epCap || !epCap->params) + { + OOTRACEERR1("Error:Invalid capability parameters to " + "ooCapabilityCreateSimpleCapability.\n"); + return NULL; + } + params =(OOCapParams*)epCap->params; + pT38 = (H245DataApplicationCapability*)memAlloc(pctxt, + sizeof(H245DataApplicationCapability)); + if(!pT38) + { + OOTRACEERR1("ERROR:Memory - ooCapabilityCreateT38Capability - pT38\n"); + return NULL; + } + memset(pT38, 0, sizeof(H245DataApplicationCapability)); + + + switch(epCap->cap) + { + case OO_T38: + pT38->maxBitRate = 144; + if (!ooCreateT38ApplicationData(pctxt,&(pT38->application))) { + OOTRACEERR2("Error:Memory - ooCapabilityCreateT38Capability - %d\n", epCap->cap); + memFreePtr(pctxt, pT38); + return NULL; + } + return pT38; + + default: + OOTRACEERR2("ERROR: Don't know how to create T38 capability %d\n", + epCap->cap); + } + return NULL; +} + + /* Used for g711 ulaw/alaw, g728, g729, g729a, g7231 */ ASN1BOOL ooCapabilityCheckCompatibility_Simple (OOH323CallData *call, ooH323EpCapability* epCap, @@ -1179,6 +1358,25 @@ } +OOBOOL ooCapabilityCheckCompatibility_T38 + (OOH323CallData *call, ooH323EpCapability* epCap, + H245DataApplicationCapability* t38Cap, int dir) +{ + unsigned cap = 0; + switch(t38Cap->application.t) + { + case T_H245DataApplicationCapability_application_t38fax: + cap = OO_T38; + break; + default: + return FALSE; + } + + if(cap != epCap->cap) { return FALSE; } + + return TRUE; +} + OOBOOL ooCapabilityCheckCompatibility_H263Video (struct OOH323CallData *call, ooH323EpCapability *epCap, @@ -1407,6 +1605,8 @@ dataType->u.videoData, dir); break; case T_H245DataType_data: + if(epCap->capType == OO_CAP_TYPE_DATA) + return ooCapabilityCheckCompatibility_T38(call, epCap, dataType->u.data, dir); default: OOTRACEDBGC3("ooCapabilityCheckCompatibility - Unsupported " "capability. (%s, $s)\n", call->callType, call->callToken); @@ -1930,6 +2130,110 @@ } } +ooH323EpCapability* ooIsT38Supported + (OOH323CallData *call, H245DataApplicationCapability* t38Cap, int dir) +{ + int cap = 0; + ooH323EpCapability *cur=NULL, *epCap=NULL; + OOCapParams *params= NULL; + /* Find similar capability */ + switch(t38Cap->application.t) + { + case T_H245DataApplicationCapability_application_t38fax: + cap = OO_T38; + break; + default: + return NULL; + } + + if(call->ourCaps) + cur = call->ourCaps; + else + cur = gH323ep.myCaps; + + while(cur) + { + OOTRACEDBGC4("Local cap being compared %s. (%s, %s)\n", + ooGetCapTypeText(cur->cap),call->callType, call->callToken); + + if(cur->cap == cap && (cur->dir & dir)) + break; + cur = cur->next; + } + + if(!cur) return NULL; + + OOTRACEDBGC4("Found matching t38 capability type %s. Comparing" + " other parameters. (%s, %s)\n", ooGetCapTypeText(cap), + call->callType, call->callToken); + + /* can we receive this capability */ + if(dir & OORX) + { + OOTRACEDBGC4("We can receive Simple capability %s. (%s, %s)\n", + ooGetCapTypeText(cur->cap), call->callType, + call->callToken); + epCap = (ooH323EpCapability*)memAllocZ(call->pctxt, + sizeof(ooH323EpCapability)); + params=(OOCapParams*)memAlloc(call->pctxt,sizeof(OOCapParams)); + if(!epCap || !params) + { + OOTRACEERR3("Error:Memory - ooIsT38Supported - " + "epCap/params (%s, %s)\n", call->callType, + call->callToken); + return NULL; + } + epCap->params = params; + epCap->cap = cur->cap; + epCap->dir = cur->dir; + epCap->capType = cur->capType; + epCap->startReceiveChannel = cur->startReceiveChannel; + epCap->startTransmitChannel= cur->startTransmitChannel; + epCap->stopReceiveChannel = cur->stopReceiveChannel; + epCap->stopTransmitChannel = cur->stopTransmitChannel; + epCap->next = NULL; + memcpy(epCap->params, cur->params, sizeof(OOCapParams)); + OOTRACEDBGC4("Returning copy of matched receive capability %s. " + "(%s, %s)\n", + ooGetCapTypeText(cur->cap), call->callType, + call->callToken); + return epCap; + } + + /* Can we transmit compatible stream */ + if(dir & OOTX) + { + OOTRACEDBGC4("We can transmit Simple capability %s. (%s, %s)\n", + ooGetCapTypeText(cur->cap), call->callType, + call->callToken); + epCap = (ooH323EpCapability*)memAlloc(call->pctxt, + sizeof(ooH323EpCapability)); + params =(OOCapParams*)memAllocZ(call->pctxt,sizeof(OOCapParams)); + if(!epCap || !params) + { + OOTRACEERR3("Error:Memory - ooIsAudioDataTypeSimpleSupported - " + "epCap/params (%s, %s)\n", call->callType, + call->callToken); + return NULL; + } + epCap->params = params; + epCap->cap = cur->cap; + epCap->dir = cur->dir; + epCap->capType = cur->capType; + epCap->startReceiveChannel = cur->startReceiveChannel; + epCap->startTransmitChannel= cur->startTransmitChannel; + epCap->stopReceiveChannel = cur->stopReceiveChannel; + epCap->stopTransmitChannel = cur->stopTransmitChannel; + epCap->next = NULL; + memcpy(epCap->params, cur->params, sizeof(OOCapParams)); + OOTRACEDBGC4("Returning copy of matched transmit capability %s." + "(%s, %s)\n", + ooGetCapTypeText(cur->cap), call->callType, + call->callToken); + return epCap; + } + return NULL; +} ooH323EpCapability* ooIsVideoDataTypeH263Supported (OOH323CallData *call, H245H263VideoCapability* pH263Cap, int dir, @@ -2130,10 +2434,12 @@ OOTRACEDBGC3("Looking for audio dataType support. (%s, %s)\n", call->callType, call->callToken); return ooIsAudioDataTypeSupported(call, data->u.audioData, dir); + case T_H245DataType_data: - OOTRACEDBGC3("Data type not supported.(%s, %s)\n", + OOTRACEDBGC3("Looking for application data dataType support.(%s, %s)\n", call->callType, call->callToken); - return NULL; + return ooIsT38Supported(call, data->u.data, dir); + case T_H245DataType_encryptionData: OOTRACEDBGC3("Encryption data type not supported.(%s, %s)\n", call->callType, call->callToken); @@ -2260,7 +2566,6 @@ return OO_OK; } - int ooAddRemoteCapability(OOH323CallData *call, H245Capability *cap) { switch(cap->t) @@ -2274,6 +2579,19 @@ case T_H245Capability_receiveAndTransmitAudioCapability: return ooAddRemoteAudioCapability(call, cap->u.receiveAndTransmitAudioCapability, OORXTX); + + + case T_H245Capability_receiveDataApplicationCapability: + return ooAddRemoteDataApplicationCapability(call, cap->u.receiveDataApplicationCapability, + OORX); + case T_H245Capability_transmitDataApplicationCapability: + return ooAddRemoteDataApplicationCapability(call, cap->u.transmitDataApplicationCapability, + OOTX); + case T_H245Capability_receiveAndTransmitDataApplicationCapability: + return ooAddRemoteDataApplicationCapability(call, + cap->u.receiveAndTransmitDataApplicationCapability, OORXTX); + + default: OOTRACEDBGA3("Unsupported cap type encountered. Ignoring. (%s, %s)\n", call->callType, call->callToken); @@ -2281,6 +2599,23 @@ return OO_OK; } +int ooAddRemoteDataApplicationCapability(OOH323CallData *call, + H245DataApplicationCapability *dataCap, + int dir) +{ + switch(dataCap->application.t) + { + case T_H245DataApplicationCapability_application_t38fax: + return ooCapabilityAddT38Capability(call, OO_T38, + dir, NULL, NULL, NULL, NULL,TRUE); + default: + OOTRACEDBGA1("Unsupported data capability type\n"); + + } + return OO_OK; +} + + int ooAddRemoteAudioCapability(OOH323CallData *call, H245AudioCapability *audioCap, int dir) @@ -2442,10 +2777,6 @@ return OO_OK; } - - - - int ooCapabilityUpdateJointCapabilities (OOH323CallData* call, H245Capability *cap) { @@ -2474,6 +2805,22 @@ case T_H245Capability_transmitVideoCapability: return ooCapabilityUpdateJointCapabilitiesVideo(call, cap->u.transmitVideoCapability, OORX); + + case T_H245Capability_receiveDataApplicationCapability: + epCap= ooIsT38Supported(call, cap->u.receiveDataApplicationCapability, + OOTX); + break; + case T_H245Capability_transmitDataApplicationCapability: + epCap = ooIsT38Supported(call, cap->u.transmitDataApplicationCapability, + OORX); + break; + case T_H245Capability_receiveAndTransmitDataApplicationCapability: + epCap = ooIsT38Supported(call, cap->u.receiveAndTransmitDataApplicationCapability, OOTX); + if (!epCap) + epCap = ooIsT38Supported(call, cap->u.receiveAndTransmitDataApplicationCapability, OORX); + break; + + case T_H245Capability_receiveUserInputCapability: if((cap->u.receiveUserInputCapability->t == T_H245UserInputCapability_basicString) && @@ -2686,7 +3033,8 @@ "OO_H263VIDEO", "OO_IS11172VIDEO", /* mpeg */ "OO_GENERICVIDEO", - "OO_EXTELEMVIDEO" + "OO_EXTELEMVIDEO", + "OO_T38" /* T.38 */ }; return ooUtilsGetText (cap, capTypes, OONUMBEROF(capTypes)); }