Avin, Thank you for your answers. However, I have additional uncertanties about your answers. Avin Patel wrote: What exactly do you mean under "on logical channel established"? There isHi Aleksandar,As I already explained earlier on this forum, I'm running ooH323c stack on an uCLinux embedded system and I want to modify 'simple' example provided with the stack in order to use it with my media library. However, before I start voice streaming, I need to find out which codec is negotiated between two endpoints since this codec needs to be turned on in hardware. How to do this? I was not able to find. I was expecting that this information would exist in channel of call level calbacks (ooLogicalChannel and ooCallData structures).I guess you will need a callback function for logical channel established, so you can check the codec type of established channel. So, 1. You can check the established logical channel capability (i.e. OOLogicalChannel.type) in logical channel established function. 2. You will have to add a callback function on logical channel established to find out the codec types used for established channel. Search for "OO_LOGICALCHAN_ESTABLISHED" & add a callback function of logical channel established. int ooOnLogicalChannelEstablished OOH323CallData *call, OOLogicalChannel * pChannel) {..} in ooLogChan.c file within the stack. Do I need to edit this function directly in the stack? Also, OOLogicalChannel.type can be only OO_CAP_TYPE_AUDIO, OO_CAP_TYPE_VIDEO, or OO_CAP_TYPE_DATA. Maybe I was not clear enough in my question. My board supports only audio streaming and I need to know exacltly which audio codec is negotiated (G711, G723, G726, G728, or G729, including their variants). My media library mimics the obj-sys media and the logic is completely the same (though media is compiled as static library since uCLinux does not support shared libraries). In the attached file, I register some codecs at line 331:Also, when I register several capabilities for the same endpoint, it turns out that before a call is established, receive channel callbacks (caller party side) are triggered for every registered capability. This was strange for me since I was expecting that only negotiated codec's channel callback would be triggered. Any remarks on this?Which callback function you are taking about? Please provide the function name & line no in your code. /* Add audio capabilities */ ooH323EpAddG711Capability(OO_G711ALAW64K, 20, 160, OORXANDTX, &spcEpStartReceiveChannel, &spcEpStartTransmitChannel, &spcEpStopReceiveChannel, &spcEpStopTransmitChannel); ooH323EpAddG711Capability(OO_G711ULAW64K, 20, 160, OORXANDTX, &spcEpStartReceiveChannel, &spcEpStartTransmitChannel, &spcEpStopReceiveChannel, &spcEpStopTransmitChannel); ooH323EpAddG7231Capability(OO_G7231, 30, 24, TRUE, OORXANDTX, &spcEpStartReceiveChannel, &spcEpStartTransmitChannel, &spcEpStopReceiveChannel, &spcEpStopTransmitChannel); ooH323EpAddG729Capability(OO_G729, 20, 20, OORXANDTX, &spcEpStartReceiveChannel, &spcEpStartTransmitChannel, &spcEpStopReceiveChannel, &spcEpStopTransmitChannel); Is it legal to register several audio codecs at the same time? When I do this, caller party triggers spcEpStartReceiveChannel() four times, but after the voice streaming is established, only one transmit channel is started. In this case, it is the channel with OO_G711ALAW64K codec. If it may help, I can send you console output of the application and complete source code of media library. Best regards, Aleksandar Regards, Avin Patel Objective Systems, Inc. ------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Do you grep through log files for problems? Stop! Download the new AJAX search engine that makes searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! http://sel.as-us.falkag.net/sel?cmd=lnk&kid=103432&bid=230486&dat=121642 _______________________________________________ ooh323c-devel mailing list ooh323c-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/ooh323c-devel |
#include "ootypes.h" #include "ootrace.h" #include "oochannels.h" #include "ooh323ep.h" #include "ooCalls.h" #include "ooCapability.h" #include "ooStackCmds.h" #include "ooGkClient.h" #include "ooUtils.h" #include "ooLogChan.h" #include "spcm_common.h" #include "spcm_dev.h" #include "spcm_rtp.h" #include <pthread.h> #include <ctype.h> #include <signal.h> #define BASE_TCP_PORT 1720 #define BASE_CMD_PORT 7575 #define BASE_RTP_PORT 5000 #define PHONE_NUM_LEN 4 #define MAX_CODECS_USED 4 #define DEFAULT_CHANNEL 1 #define DEFAULT_CODEC ALAW #define DEFAULT_FRAME 20 enum FSM_STATES {IDLE, CALLING, RINGING, EXCHANGE, BUSY, RINGBACK, ADMIN}; void* spcEpHandlePhone(void*); static char callToken[20]; static char ourip[20]; static int ourport; static OOBOOL gCmdThrd; static int continue_running; static int currentState = IDLE; static int isPrinted = FALSE; static enum RasGatekeeperMode gkMode = RasDiscoverGatekeeper; /* Channel data */ static struct MediaData channelData; static pthread_mutex_t stateMutex; int spcEpStartReceiveChannel(ooCallData* call, ooLogicalChannel* pChannel); int spcEpStartTransmitChannel(ooCallData* call, ooLogicalChannel* pChannel); int spcEpStopReceiveChannel(ooCallData* call, ooLogicalChannel* pChannel); int spcEpStopTransmitChannel(ooCallData* call, ooLogicalChannel* pChannel); int spcEpOnIncomingCall(ooCallData* call); int spcEpOnOutgoingCall(ooCallData* call); int spcEpOnNewCallCreated(ooCallData* call); int spcEpOnCallEstablished(ooCallData* call); int spcEpOnCallForwarded(ooCallData* call); int spcEpOnCallCleared(ooCallData* call); int spcEpOnAlerting(ooCallData* call); int spcEpOpenLogicalChannels(ooCallData* call); int spcEpOnReceivedDTMF(OOH323CallData* call, const char* dtmf); char USAGE[] = { "SPiDCOM H323 peer client\n" "\t./simple [options]\n" "options:\n" "--channel <number> - Phone channel to be used. Need to be set either\n" " to 1 or 2 (default 1)\n" "--user-number <number> - Caller number\n" "--no-gk - Do not use gatekeeper\n" "--gk <ip:port> - Use specific gatekeeper\n" "--e164 <number> - E164 number used as callerid for\n" " this endpoint\n" "--use-ip <ip> - Ip address for the endpoint\n" " (default - uses gethostbyname)\n" "--no-faststart - Disable fast start (default - enabled)\n" "--no-tunneling - Disable H245 tunneling\n" "-t - Trace. Use multiple times to increase\n" " trace level\n" "--help - Prints this usage message\n" }; void reverse (char* st) { int i, j; char tmp; for (i=0, j=strlen(st)-1; i<j; i++, j--) tmp = st[i], st[i] = st[j], st[j] = tmp; } void itoa (int num, char* st) { int i, sign; if ((sign = num) < 0) num = -num; i = 0; do { st[i++] = num % 10 + '0'; } while ((num /= 10) > 0); if (sign == '\0') st[i++] = '-'; st[i] = '\0'; reverse(st); } void signalHandler(int sig) { switch(sig) { case SIGINT: case SIGTERM: continue_running = FALSE; break; default: break; } } void setState (int newState) { pthread_mutex_lock(&stateMutex); currentState = newState; isPrinted = FALSE; pthread_mutex_unlock(&stateMutex); } int main(int argc, char ** argv) { int ret = 0, x; char h323id[50], e164[50], user[50], user_num[50], dest[256], tmp[40]; char logfile[20]; int trace_level = 0; int cmdport; OOBOOL bFastStart = TRUE, bTunneling = TRUE; OOH323CALLBACKS h323Callbacks; char* gkIP = NULL; char* pcPort = NULL; int gkPort = 0; pthread_t threadHdl; continue_running = TRUE; channelData.channelId = DEFAULT_CHANNEL; channelData.codec = DEFAULT_CODEC; channelData.frameLength = DEFAULT_FRAME; signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); if(argc == 1) { printf("USAGE:\n%s", USAGE); return -1; } h323id[0] = '\0'; e164[0] = '\0'; ourip[0] = '\0'; dest[0] = '\0'; user[0] = '\0'; user_num[0] = '\0'; logfile[0] = '\0'; gCmdThrd = FALSE; /* parse args */ for (x=1; x<argc; x++) { if (!strcmp(argv[x], "--channel")) { x++; strncpy(tmp, argv[x], sizeof(tmp)-1); tmp[sizeof(tmp)-1] = '\0'; channelData.channelId = atoi(tmp); } else if (!strcmp(argv[x], "--no-faststart")) { bFastStart = FALSE; } else if (!strcmp(argv[x], "--no-tunneling")) { bTunneling = FALSE; } else if (!strcmp(argv[x], "--help")) { printf("USAGE:\n%s", USAGE); return 0; } else if (!strcmp(argv[x], "--user")) { x++; strncpy(user, argv[x], sizeof(user)-1); user[sizeof(user)-1] = '\0'; } else if (!strcmp(argv[x], "--user-number")) { x++; strncpy(user_num, argv[x], sizeof(user_num)-1); user_num[sizeof(user_num)-1]='\0'; } else if (!strcmp(argv[x], "--h323id")) { x++; strncpy(h323id, argv[x], sizeof(h323id)-1); h323id[sizeof(h323id)-1] = '\0'; } else if (!strcmp(argv[x], "--e164")) { x++; strncpy(e164, argv[x], sizeof(e164)-1); e164[sizeof(e164)-1] = '\0'; } else if (!strcmp(argv[x], "--no-gk")) { gkMode = RasNoGatekeeper; } else if (!strcmp(argv[x], "--gk")) { x++; strncpy(tmp, argv[x], sizeof(tmp)-1); tmp[sizeof(tmp)-1] = '\0'; pcPort = strchr(tmp, ':'); if (pcPort) { *pcPort = '\0'; pcPort++; gkPort = atoi(pcPort); } gkIP = tmp; gkMode = RasUseSpecificGatekeeper; } else if (!strcmp(argv[x], "-t")) { trace_level++; } else if (!strcmp(argv[x], "--use-ip")) { x++; strncpy(ourip, argv[x], sizeof(ourip)-1); ourip[sizeof(ourip)-1] = '\0'; } else if (!strcmp(argv[x],"--use-port")) { x++; ourport = atoi(argv[x]); } else { printf("USAGE:\n%s", USAGE); return -1; } } /* Determine peer's IP if not specified by user */ if (ooUtilsIsStrEmpty(ourip)) ooGetLocalIPAddress(ourip); if (!strcmp(ourip, "127.0.0.1")) { printf("Failed to determine local ip, please specify as command line " "option\n"); printf("USAGE:\n%s", USAGE); return -1; } /* Initialize the H323 endpoint - faststart and tunneling enabled */ strcpy(logfile, "h323peer"); if (channelData.channelId == 1) strcat(logfile, "1"); else if (channelData.channelId == 2) strcat(logfile, "2"); else { printf("USAGE:\n%s", USAGE); return -1; } strcat(logfile, ".log"); ret = ooH323EpInitialize(OO_CALLMODE_AUDIOCALL, logfile); if (ret != OO_OK) { printf("Failed to initialize H.323 Endpoint\n"); return -1; } if (!bFastStart) ooH323EpDisableFastStart(); if (!bTunneling) ooH323EpDisableH245Tunneling(); if(trace_level == 1) ooH323EpSetTraceLevel(OOTRCLVLDBGA); else if(trace_level == 2) ooH323EpSetTraceLevel(OOTRCLVLDBGB); else if(trace_level >= 3) ooH323EpSetTraceLevel(OOTRCLVLDBGC); ourport = BASE_TCP_PORT + channelData.channelId - 1; ooH323EpSetLocalAddress(ourip, ourport); /* CmdListener should always be created after local address is set */ cmdport = BASE_CMD_PORT + channelData.channelId - 1; ooH323EpCreateCmdListener(cmdport); ooH323EpDisableAutoAnswer(); char* phoneNumber = strrchr(ourip, '.') + 1; strcpy(user, "user"); switch (channelData.channelId) { case 1: strcat(user, "1"); break; case 2: strcat(user, "2"); break; default: break; } if (strlen(phoneNumber) == 1) strcat(user, "00"); if (strlen(phoneNumber) == 2) strcat(user, "0"); strcat(user, phoneNumber); strcpy(h323id, user); if (!ooUtilsIsStrEmpty(user)) ooH323EpSetCallerID(user); if (!ooUtilsIsStrEmpty(h323id)) ooH323EpAddAliasH323ID(h323id); if(!ooUtilsIsStrEmpty(user_num)) ooH323EpSetCallingPartyNumber(user_num); if (!ooUtilsIsStrEmpty(e164)) ooH323EpSetCallingPartyNumber(e164); /* Set callbacks */ h323Callbacks.onNewCallCreated = spcEpOnNewCallCreated; h323Callbacks.onAlerting = spcEpOnAlerting; h323Callbacks.onIncomingCall = spcEpOnIncomingCall; h323Callbacks.onOutgoingCall = spcEpOnOutgoingCall; h323Callbacks.onCallEstablished = spcEpOnCallEstablished; h323Callbacks.onCallForwarded = spcEpOnCallForwarded; h323Callbacks.onCallCleared = spcEpOnCallCleared; h323Callbacks.openLogicalChannels = spcEpOpenLogicalChannels; h323Callbacks.onReceivedDTMF = spcEpOnReceivedDTMF; /*dtmf stuff */ ooH323EpEnableDTMFH245Alphanumeric(); ooH323EpEnableDTMFH245Signal(); ooH323EpEnableDTMFRFC2833(0); ooH323EpSetH323Callbacks(h323Callbacks); /* Add audio capabilities */ ooH323EpAddG711Capability(OO_G711ALAW64K, 20, 160, OORXANDTX, &spcEpStartReceiveChannel, &spcEpStartTransmitChannel, &spcEpStopReceiveChannel, &spcEpStopTransmitChannel); ooH323EpAddG711Capability(OO_G711ULAW64K, 20, 160, OORXANDTX, &spcEpStartReceiveChannel, &spcEpStartTransmitChannel, &spcEpStopReceiveChannel, &spcEpStopTransmitChannel); ooH323EpAddG7231Capability(OO_G7231, 30, 24, TRUE, OORXANDTX, &spcEpStartReceiveChannel, &spcEpStartTransmitChannel, &spcEpStopReceiveChannel, &spcEpStopTransmitChannel); ooH323EpAddG729Capability(OO_G729, 20, 20, OORXANDTX, &spcEpStartReceiveChannel, &spcEpStartTransmitChannel, &spcEpStopReceiveChannel, &spcEpStopTransmitChannel); /* To use a gatekeeper */ if (gkMode != RasNoGatekeeper) { if (gkMode == RasDiscoverGatekeeper) ooGkClientInit(RasDiscoverGatekeeper, NULL, 0); else if (gkMode == RasUseSpecificGatekeeper) ooGkClientInit(RasUseSpecificGatekeeper, gkIP, gkPort); } /* Load media plug-in */ ret = spcInitializePlugin(channelData.channelId); if (ret != OO_OK) { printf("Failed to initialize the media library\n"); exit(0); } /* Print config */ printf("Endpoint configuration:\n"); printf("\tFastStart: %s\n", bFastStart ? "enabled" : "disabled"); printf("\tTunneling: %s\n", bTunneling ? "enabled" : "disabled"); if (!ooUtilsIsStrEmpty(h323id)) printf("\tH323ID: %s\n", h323id); if (!ooUtilsIsStrEmpty(e164)) printf("\te164: %s\n", e164); if (!ooUtilsIsStrEmpty(user)) printf("\tUser: %s\n", user); if (!ooUtilsIsStrEmpty(user_num)) printf("\tUser Number: %s\n", user_num); if (gkMode == RasNoGatekeeper) printf("\tGatekeeper: not used\n"); else if (gkMode == RasDiscoverGatekeeper) printf("\tGatekeeper: discover gatekeeper\n"); else if (gkMode == RasUseSpecificGatekeeper) { char gkAddr[60]; if (gkPort != 0) sprintf(gkAddr, "%s:%d", gkIP, gkPort); else sprintf(gkAddr, "%s:DEFAULT", gkIP); printf("\tGatekeeper: %s\n", gkAddr); } printf("\tListening for calls at: %s:%d\n", ourip, ourport); /* Create H.323 Listener */ ret = ooCreateH323Listener(); if (ret != OO_OK) { OOTRACEERR1("Failed to create H.323 listener"); return -1; } pthread_create(&threadHdl, NULL, spcEpHandlePhone, &channelData.channelId); ooMonitorChannels(); if (gCmdThrd) { pthread_cancel(threadHdl); pthread_join(threadHdl, NULL); } printf("Destroying H323 endpoint...\n"); ooH323EpDestroy(); spcRelease(channelData.channelId); return 0; } /* Callback to start receive media channel */ int spcEpStartReceiveChannel(ooCallData* call, ooLogicalChannel* pChannel) { struct MediaData* pSettings = (struct MediaData*) call->usrData; printf("Starting receive channel at %s:%d...\n", pChannel->localIP, pChannel->localRtpPort); fflush(stdout); spcCreateReceiveRTPChannel(&pSettings->channelId, pChannel->localIP, pChannel->localRtpPort); spcStartReceiveSpeaker(pSettings); return OO_OK; } /* Callback to start transmit media channel */ int spcEpStartTransmitChannel(ooCallData* call, ooLogicalChannel* pChannel) { struct MediaData* pSettings = (struct MediaData*) call->usrData; printf("Starting transmit channel to %s:%d...\n", pChannel->remoteIP, pChannel->remoteMediaPort); fflush(stdout); spcCreateTransmitRTPChannel(&pSettings->channelId, pChannel->remoteIP, pChannel->remoteMediaPort); spcStartTransmitMic(pSettings); return OO_OK; } /* Callback to stop receive media channel */ int spcEpStopReceiveChannel(ooCallData* call, ooLogicalChannel* pChannel) { struct MediaData* pSettings = (struct MediaData*) call->usrData; printf("\nStopping receive channel..."); fflush(stdout); spcStopReceiveSpeaker(pSettings); return OO_OK; } /* Callback to stop transmit media channel */ int spcEpStopTransmitChannel(ooCallData* call, ooLogicalChannel* pChannel) { struct MediaData* pSettings = (struct MediaData*) call->usrData; printf("\nStopping transmit channel..."); fflush(stdout); spcStopTransmitMic(pSettings); return OO_OK; } int spcEpOnReceivedDTMF(OOH323CallData* call, const char* dtmf) { OOLOG2(1, "StartOf:OnReceivedDTMF"); printf("\nReceived user input %s", dtmf); fflush(stdout); OOLOG2(1, "EndOf:OnReceivedDTMF"); return OO_OK; } int spcEpOnAlerting(ooCallData* call) { OOLOG2(1, "StartOf:OnAlerting"); if (!strcmp(call->callType, "incoming")) { printf("\nIncoming call from '%s' (%s). ", (call->remoteDisplayName) ? call->remoteDisplayName : "unknown name", call->callingPartyNumber ? call->callingPartyNumber : "unknown number"); if (currentState == IDLE) { printf("Do you want to answer?\n"); setState(RINGING); fflush(stdout); } } if (!strcmp(call->callType, "outgoing")) { printf("\nOutgoing call to '%s' (%s).", (call->remoteDisplayName) ? call->remoteDisplayName : "unknown name", call->callingPartyNumber ? call->callingPartyNumber : "unknown number"); printf("\n"); fflush(stdout); setState(RINGBACK); } OOLOG2(1, "EndOf:OnAlerting"); return OO_OK; } /* on incoming call callback */ int spcEpOnIncomingCall(ooCallData* call) { OOLOG2(1, "StartOf:OnIncomingCall"); if (currentState != IDLE) { ooHangCall(call->callToken, OO_REASON_LOCAL_BUSY); printf("\nIncoming call Rejected - line busy"); fflush(stdout); } OOLOG2(1, "EndOf:OnIncomingCall"); return OO_OK; } /* outgoing call callback */ int spcEpOnOutgoingCall(ooCallData* call) { OOLOG2(1, "StartOf:OnOutgoingCall"); OOLOG2(1, "EndOf:OnOutgoingCall"); return OO_OK; } int spcEpOnNewCallCreated(ooCallData* call) { int i; int codecs[MAX_CODECS_USED] = {OO_G711ALAW64K, OO_G711ULAW64K, OO_G7231, OO_G729}; OOLOG2(1, "StartOf:OnNewCallCreated"); /* Configure mediainfo for transmit and receive media channels */ for (i=0; i<MAX_CODECS_USED; i++) { int cmdPortOffset, comPortOffset; ooMediaInfo mediaInfo1, mediaInfo2; memset(&mediaInfo1, 0, sizeof(ooMediaInfo)); memset(&mediaInfo2, 0, sizeof(ooMediaInfo)); cmdPortOffset = (4*i+1) + 2*(channelData.channelId-1); comPortOffset = (4*i) + 2*(channelData.channelId-1); mediaInfo1.lMediaCntrlPort = BASE_RTP_PORT + cmdPortOffset; mediaInfo1.lMediaPort = BASE_RTP_PORT + comPortOffset; strcpy(mediaInfo1.lMediaIP, call->localIP); strcpy(mediaInfo1.dir, "transmit"); mediaInfo1.cap = codecs[i]; ooAddMediaInfo(call, mediaInfo1); mediaInfo2.lMediaCntrlPort = BASE_RTP_PORT + cmdPortOffset; mediaInfo2.lMediaPort = BASE_RTP_PORT + comPortOffset; strcpy(mediaInfo2.lMediaIP, call->localIP); strcpy(mediaInfo2.dir, "receive"); mediaInfo2.cap = codecs[i]; ooAddMediaInfo(call, mediaInfo2); } strcpy(callToken, call->callToken); call->usrData = (void*) &channelData; OOLOG2(1, "EndOf:OnNewCallCreated"); return OO_OK; } /* on open logical channels */ int spcEpOpenLogicalChannels(ooCallData* call) { OOLOG2(1, "StartOf:OpenLogicalChannels"); printf("call->logicalChans->type = %d\n", call->logicalChans->type); printf("call->logicalChans->state = %d\n", call->logicalChans->state); fflush(stdout); OOLOG2(1, "EndOf:OpenLogicalChannels"); return OO_OK; } /* on call established callback */ int spcEpOnCallEstablished(ooCallData* call) { OOLOG2(1, "StartOf:OnCallEstablished"); printf("\nCall %s established.\n", callToken); fflush(stdout); if (currentState != EXCHANGE) setState(EXCHANGE); OOLOG2(1, "EndOf:OnCallEstablished"); return OO_OK; } /* Callback when we are being forwarded to another destination * by remote endpoint. */ int spcEpOnCallForwarded(ooCallData* call) { OOLOG2(1, "StartOf:OnCallForwarded"); setState(IDLE); OOLOG2(1, "EndOf:OnCallForwarded"); return OO_OK; } /* on call cleared callback */ int spcEpOnCallCleared(ooCallData* call) { OOLOG2(1, "StartOf:OnCallCleared"); if (!strcmp(call->callToken , callToken)) { printf("\nCall %s ended - %s\n", callToken, ooGetReasonCodeText(call->callEndReason)); fflush(stdout); callToken[0]='\0'; if ((call->callEndReason == OO_REASON_REMOTE_BUSY) || (call->callEndReason == OO_REASON_REMOTE_CLEARED) || (call->callEndReason == OO_REASON_NOUSER) || (call->callEndReason == OO_REASON_GK_NOCALLEDUSER) || (call->callEndReason == OO_REASON_LOCAL_BUSY)) { setState(BUSY); } else if (call->callEndReason == OO_REASON_LOCAL_CLEARED) { /* this is because maximum ringback time reached */ setState(BUSY); } else { /* this is in case, for example, when a call was forwarded */ setState(CALLING); } } OOLOG2(1, "EndOf:OnCallCleared"); return OO_OK; } int getDestination(int channelId, char* dest) { int i = 0, j = 0; char port[5]; int isFirst = TRUE; if (gkMode != RasNoGatekeeper) strcpy(dest, "user"); else { char* end; strcpy(dest, ourip); end = strrchr(dest, '.') + 1; *end = '\0'; } i = strlen(dest); spcClearDTMFBuffer(channelId); do { if (spcIsDTMF(channelId)) { if ((gkMode == RasNoGatekeeper) && isFirst) { switch (spcGetDTMF(channelId)) { case '1': itoa(BASE_TCP_PORT, port); break; case '2': itoa(BASE_TCP_PORT+1, port); break; case '*': strcpy(dest, "*"); return SPC_OK; default: break; } isFirst = FALSE; } else dest[i++] = spcGetDTMF(channelId); j++; spcStopTone(channelId); } if (!spcGetHookState(channelId)) { spcStopTone(channelId); break; } } while (j < PHONE_NUM_LEN); if (j < PHONE_NUM_LEN) { spcStopTone(channelId); setState(IDLE); return 1; } dest[i] = '\0'; if (gkMode == RasNoGatekeeper) { strcat(dest, ":"); strcat(dest, port); } return SPC_OK; } void* spcEpHandlePhone(void* param) { int channelId = *((int*) param); OOStkCmdStat stat; char dest[256]; gCmdThrd = TRUE; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); while(continue_running) { switch (currentState) { case IDLE: if (!isPrinted) { OOLOG2(1, "<<<IDLE>>>"); isPrinted = TRUE; spcStopTone(channelId); } if (spcGetHookState(channelId)) setState(CALLING); break; case CALLING: if (!isPrinted) { OOLOG2(1, "<<<CALLING>>>"); isPrinted = TRUE; spcPlayDialtone(channelId); if (getDestination(channelId, dest)) break; if (!strcmp(dest, "*")) { setState(ADMIN); break; } spcStopTone(channelId); stat = ooMakeCall(dest, callToken, sizeof(callToken), NULL); if (stat != OO_STKCMD_SUCCESS) { printf("Failed to place a call to %s \n",dest); printf("\tReason: %s\n", ooGetStkCmdStatusCodeTxt(stat)); setState(BUSY); break; } else printf("Calling %s...\n", dest); } break; case RINGING: if (!isPrinted) { OOLOG2(1, "<<<RINGING>>>"); isPrinted = TRUE; spcStartRinging(channelId); } if (spcGetHookState(channelId)) { spcStopRinging(channelId); stat = ooAnswerCall(callToken); if (stat == OO_STKCMD_SUCCESS) { printf("Call %s successfully answered.\n", callToken); } else { printf("Failed to answer the %s call.\n", callToken); printf("\tReason: %s\n", ooGetStkCmdStatusCodeTxt(stat)); } setState(EXCHANGE); } break; case EXCHANGE: if (!isPrinted) { OOLOG2(1, "<<<EXCHANGE>>>"); isPrinted = TRUE; spcStopRinging(channelId); spcStopTone(channelId); spcSetGreenLED(channelId, LED_ON); } if (!spcGetHookState(channelId)) { stat = ooHangCall(callToken, OO_REASON_LOCAL_CLEARED); if (stat != OO_OK) { printf("Failed to hang call %s\n", callToken); printf("\tReason: %s\n", ooGetStkCmdStatusCodeTxt(stat)); } else { printf("Hanging %s call...\n", callToken); } spcSetGreenLED(channelId, LED_OFF); setState(IDLE); } if (spcIsDTMF(channelId)) { char digit; digit = spcGetDTMF(channelId); if (digit == '*') { if (getDestination(channelId, dest) == 0) { stat = ooForwardCall(callToken, dest); if (stat != OO_STKCMD_SUCCESS) { printf("Failed to forward call %s to %s\n", callToken, dest); printf("Reason: %s\n", ooGetStkCmdStatusCodeTxt(stat)); setState(BUSY); } else printf("Forwarding call %s to %s \n", callToken, dest); fflush(stdout); } spcSetGreenLED(channelId, LED_OFF); } } break; case BUSY: if (!isPrinted) { OOLOG2(1, "<<<BUSY>>>"); isPrinted = TRUE; spcPlayBusy(channelId); } if (!spcGetHookState(channelId)) { spcStopTone(channelId); setState(IDLE); } break; case RINGBACK: if (!isPrinted) { OOLOG2(1, "<<<RINGBACK>>>"); isPrinted = TRUE; ooSleep(200); if (currentState != RINGBACK) break; spcPlayRingback(channelId); } if (!spcGetHookState(channelId)) { spcStopTone(channelId); stat = ooHangCall(callToken, OO_REASON_LOCAL_CLEARED); if (stat != OO_OK) { printf("Failed to hang call %s\n", callToken); printf("\tReason: %s\n", ooGetStkCmdStatusCodeTxt(stat)); } else { printf("Hanging call %s...\n", callToken); } setState(IDLE); } break; case ADMIN: spcStopTone(channelId); OOLOG2(1, "<<<ADMIN>>>"); break; default: break; } ooSleep(1); } spcStopRinging(channelId); spcStopTone(channelId); printf("Closing down stack...\n"); fflush(stdout); ooStopMonitor(); gCmdThrd = FALSE; return NULL; }