bool EventCallBack(SIPX_EVENT_CATEGORY category, void* pInfo, void* pUserData) { assert (pInfo != NULL); // Dump event char cBuf[1024] ; // Print the timestamp if requested. if (g_timestamp) { OsDateTime d; OsDateTime::getCurTime(d); UtlString s; d.getIsoTimeStringZ(s); printf("%s ", s.data()); } printf("%s\n", sipxEventToString(category, pInfo, cBuf, sizeof(cBuf))) ; if (category == EVENT_CATEGORY_CALLSTATE) { SIPX_CALLSTATE_INFO* pCallInfo = static_cast<SIPX_CALLSTATE_INFO*>(pInfo); printf(" hCall=%d, hAssociatedCall=%d\n", pCallInfo->hCall, pCallInfo->hAssociatedCall) ; switch (pCallInfo->event) { case CALLSTATE_OFFERING: // Get and print the From: URI. { char remote[200]; sipxCallGetRemoteID(pCallInfo->hCall, remote, sizeof (remote)); printf(" From: %s\n", remote); } sipxCallAccept(pCallInfo->hCall) ; break ; case CALLSTATE_ALERTING: clearLoopback() ; { // Determine the answering delay. int delay; if (g_callAnswerDelay == NULL || g_callAnswerDelay[0] == '\0') { // No answer string is active, so delay is 0. delay = 0; } else { // Get the delay to be used from the delay string. delay = atoi(g_callAnswerDelay); // Remove the first number, if there is a comma. char* p = strchr(g_callAnswerDelay, ','); if (p != NULL) { g_callAnswerDelay = p + 1; } } if (delay == 0) { // If the delay is 0, answer immediately. sipxCallAnswer(pCallInfo->hCall); } else { // The delay is non-0, so set the timer to answer. // Stop the timer in case it is running. callAnswerTimer.stop(); // Record the call to be answered. callAnswerNotification.setHCall(pCallInfo->hCall); // Construct the delay to be used. OsTime d(delay, 0); // Start the timer. callAnswerTimer.oneshotAfter(d); } } break ; case CALLSTATE_CONNECTED: // Per conversation with Bob A., commented this sleep out // to prevent trouble with processing re-INVITEs that come // just after INVITEs. This should be replaced with a proper // timer-wait event. But that leads to the open question // of whether to use the sipX OsTimer system, or the underlying // OS mechanisms (to avoid dependency on sipXportLib). Ugh. //SLEEP(1000) ; // BAD: Do not block the callback thread // Start the timer that limits the length of the call. { // Stop the timer in case it is running. callHangupTimer.stop(); // Record the call to be answered. callHangupNotification.setHCall(pCallInfo->hCall); // Start the timer, scaled to seconds. OsTime delay(iDuration, 0); callHangupTimer.oneshotAfter(delay); } // Play file if provided if (g_szFile) { if (!playFile(g_szFile, pCallInfo->hCall)) { printf("Failed to play file: %s\n", g_szFile) ; } } // Play tones if provided if (g_szPlayTones) { if (!playTones(g_szPlayTones, pCallInfo->hCall)) { printf("Failed to play tones: %s\n", g_szPlayTones) ; } } break ; case CALLSTATE_DISCONNECTED: // Stop the timers in case they are running. callAnswerTimer.stop(); callHangupTimer.stop(); // Destroy the call. sipxCallDestroy(pCallInfo->hCall) ; break ; case CALLSTATE_AUDIO_EVENT: if (pCallInfo->cause == CALLSTATE_AUDIO_START) { printf("* Negotiated codec: %s, payload type %d\n", pCallInfo->codecs.audioCodec.cName, pCallInfo->codecs.audioCodec.iPayloadType); } break; case CALLSTATE_DESTROYED: // Stop the timer in case it is running. callAnswerTimer.stop(); break ; default: // There are many other events which we ignore. break; } } // Ensure the output is not delayed by buffering. fflush(stdout); return true; }