Home Page
Products
Support
NicIVR     
NicSC
7/24 Support
Answers Knowledgebase (FAQ)
About Us    
Contact
Application Development
Call Flow Scripts
Case Studies
Links
Call Flow Scripts

 

Creating a Basic IVR Application

Application development is very easy on NicIVR/NicSC. State of art call processor allows perfect synchronization between SIP call signals and scripting language. CCS scripting language is more systematic and meaningful than XML based languages. So developers could implement powerful and flexible applications in a very short time.

Following example demonstrates the relation between a basic IVR application scripts and related signalling states. Please click SIP signals to see the related application code.

IVR Scenario:

1. Caller and Callee registers to NicIVR.

2. The call from caller is received by NicIVR.

3. NicIVR plays "wellcome" and "language selection" announces to caller.

4. Authenticates from billing server and plays the remaining credit to caller.

5. Authorizes from billing server according to called number and obtains the maximum call duration.

6. Starts the call to callee. When the call establishes then starts the session timer for maximum call duration.

7. NicIVR interrupts the call and plays the last minute announce to callee. Then binds the call again.

8. NicIVR ends the call in case of

If maximum duration expires then sends SIP BYE message to both side and ends the call session.

If caller or callee hangs up the phone then NicIVR sends SIP BYE message to other side and ends the call session.

                          
	      CALLER                    NICIVR                   CALLEE
		|                        |                        |
		|                        |                        |
		|>REGISTER ------------->|<------------- REGISTER<|
		|                        |                        |
		|<--------------- 200 Ok<|>200 Ok---------------->|
		|                        |                        |
		|>INVITE (sdp)---------->|                        |
		|                        |                        |
		|<----------- 100 TRYING<|                        |
		|                        |                        |
		|<-----------180 RINGING<|                        |
		|                        |                        |
		|<----------(sdp) 200 Ok<|                        |
		|                        |                        |
		|>ACK------------------->|                        |
		|                        |                        |
		|<=====MEDIA SESSION====>|                        |
		|                        |                        |
		|                        |>INVITE (sdp)---------->|
		|                        |                        |
		|                        |<---------- 180 RINGING<|
		|                        |                        |
		|                        |<----------(sdp) 200 Ok<|
		|                        |                        |
		|                        |>ACK ------------------>|
		|                        |                        |
		|<-------(sdp) re-INVITE<|                        |
		|                        |                        |
		|>200 Ok (sdp)---------->|                        |
		|                        |                        |
		|<------------------ ACK<|                        |
		|                        |                        |
		|<================MEDIA SESSION==================>|
		|                        |                        |
		|                        |>re-INVITE (sdp)------->|
		|                        |                        |
		|                        |<----------(sdp) 200 Ok<|
		|                        |                        |
		|                        |>ACK ------------------>|
		|                        |                        |
		|<-------(sdp) re-INVITE<|                        |
		|                        |                        |
		|>200 Ok (sdp)---------->|                        |
		|                        |                        |
		|<------------------ ACK<|                        |
		|                        |                        |
		|                        |                        |
		|<===LAST MIN WARNING===>|                        |
		|                        |                        |	
		|                        |                        |
		|<-------(sdp) re-INVITE<|                        |
		|                        |                        |
		|>200 Ok (sdp)---------->|                        |
		|                        |                        |
		|<------------------ ACK<|                        |
		|                        |                        |
		|                        |>re-INVITE (sdp)------->|
		|                        |                        |
		|                        |<----------(sdp) 200 Ok<|
		|                        |                        |
		|                        |>ACK ------------------>|
		|                        |                        |
		|<================MEDIA SESSION==================>|
		|                        |                        |
		|>BYE ------------------>|                        |
		|                        |                        |
		|<--------------- 20O Ok<|                        |
		|                        |                        |
		|                        |>BYE ------------------>|
		|                        |                        |
		|                        |<--------------- 200 Ok<| 
		|                        |                        |
		
			


Main.ccs
// Global variables
string APP_SERVER_RADIUS = "192.168.1.3";
string APP_SERVER_HTTP = "127.0.0.1";
bool g_CallEstablished = FALSE;
string g_strDigits;
string g_strUser;
string g_strPassword;
string g_strh323confid;
string g_strSetupTime;
int iTimerID;
g_CreditAmountInt;
g_CreditAmountDec;
g_nMaxCallDuration;

// main function
FUNCTION main()
{
	// generate 32 char random string
	// Exp: output  70562F75F241E8A46B07CDD8417F8EF2 
	g_strh323confid = randHex(32);
	LOG("Conf Id : " + g_strh323confid);
	
	// Switch to next script file named NewSession.ccs in Prepaid directory
	RunScript("Prepaid\\NewSession.ccs");
}

FUNCTION CloseSession()
{
	LOG("CloseSession in Main is interpreting");
	LOG("_CLOSING_LEG_ = " + i2str(_CLOSING_LEG_ ));
	if (_CLOSING_LEG_ == _LEG_A_) {
		LOG("Closing LEG is LEG_A");
		EndCall(_LEG_B_);
	}
	else {
		LOG("Closing LEG is LEG_B");
		EndCall(_LEG_A_);
	}

	LOG("-------SESSION_ID:[" + i2str(_SESSION_ID_) + "]---------");
	LOG("Session has closed.");
	ReleaseSession();
}

FUNCTION AbortSession()
{
	EndCall(_LEG_A_);
	LOG("-------SESSION_ID:[" + i2str(_SESSION_ID_) + "]---------");
	LOG("Session has aborted.");
	ReleaseSession();
}



NewSession.ccs
EVENT NewCall()
{
	LOG("-------SESSION_ID:[" + i2str(_SESSION_ID_) + "]---------");
	LOG("NewCall received. Session has started!");
	LOG("Calling Number:" + _CALLING_NR_);
	
	AcceptCall(); 
	AnswerCall(); 
}

EVENT CallActive()
{
	LOG("Call is active");
	bool bRet = OpenAudioChannel(_LEG_A_);
	if (bRet == FALSE) {
		LOG("OpenAudioChannel returned FALSE");
		AbortSession();
	}
	
	// Play welcome audio
	PlayAudio(_LEG_A_, "Welcome");
	
	// Change voice directory for selected language
	ChangeLanguage();
	
	// obtaion the balance from billing server
	// 8.62 Euro
	g_CreditAmountInt = 8;
	g_CreditAmountDec = 62;
	// Play the amount to caller
	PlayAmount();
	
	// Make an authorization request and obtain the maximum call duration
	// Check out the sample radius request
	g_nMaxCallDuration = 600; // second

	LOG("Starting call to: " + _CALLED_NR_);
	StartCall(_LEG_A_, _LEG_B_, _CALLED_NR_);
	RunScript("Prepaid\\Ringing.ccs");
}

FUNCTION PlayAmount() 
{
    LOG("Credit Int:" + i2str(g_CreditAmountInt));
    LOG("Credit Dec:" + i2str(g_CreditAmountDec));

    PlayAudio(_LEG_A_, "SayBalance"); // You have
    if (g_CreditAmountInt > 0) {
        PlayCredit(_LEG_A_, g_CreditAmountInt, "Say_Euro");
    }
    if (g_CreditAmountDec > 0) {
        PlayCredit(_LEG_A_, g_CreditAmountDec, "Say_Cent");
    }
}

FUNCTION ChangeLanguage()
{
	// Press 1 for German, 2 French, 3 Spanish
	string strDigit = GetDigits(_LEG_A_, 1, "Language_Option");
	if (strDigit == "1") {
		_LANGUAGE_ = "german";
	}
	if (strDigit == "2") {
		_LANGUAGE_ = "french";
	}
	if (strDigit == "3") {
		_LANGUAGE_ = "spanish";
	}
}

EVENT CallEnd() 
{
	// BYE received
	LOG("CallEnd in newsession");
	AbortSession();
}


Ringing.ccs
EVENT CallRinging()
{
	g_PlayingRinging = TRUE;
	PlayBackgroundAudio(_LEG_A_, "Ringing", TRUE, 2);
}

EVENT CallAnswered()
{
	LOG("CallAnswered in Ringing is interpreting");
	if (g_PlayingRinging == TRUE) {
		g_PlayingRinging = FALSE;
		StopBackgroundAudio(_LEG_A_);
	}
	
	CloseAudioChannel(_LEG_A_);
	JoinLegs(_LEG_B_, _LEG_A_);
	RunScript("Prepaid\\CallMonitor.ccs");
}

EVENT CallReject()
{
	LOG("CallReject in Ringing, Reject Cause: " + i2str(_RESPONSE_));

	if (g_PlayingRinging == TRUE) {
		g_PlayingRinging = FALSE;
		StopBackgroundAudio(_LEG_A_);
	}
	
	if (_RESPONSE_ == 404) {
		LOG("Called number is not found");
		PlayAudio(_LEG_A_, "DestinationNotFound");
	}
	if (_RESPONSE_ == 486) {
		LOG("Called number is busy");
		PlayAudio(_LEG_A_, "NumberIsBusy");
	}
	if ((_RESPONSE_ == 408) || (_RESPONSE_ == 480) || 
		(_RESPONSE_ == 484) || (_RESPONSE_ == 487)) {
		LOG("Called number does not answer");
		PlayAudio(_LEG_A_, "NoAnsver");
	}
	if (_RESPONSE_ == 500) {
		LOG("Interval Server Error (Sip Cause 500)");
		PlayAudio(_LEG_A_, "ErrorMessage");
	}
	AbortSession();
}

EVENT CallEnd()
{
	LOG("CallEnd in Ringing is interpreting");
	if (g_PlayingRinging == TRUE) {
		StopBackgroundAudio(_LEG_A_);
	}
	CloseSession();
}


CallMonitor.ccs
EVENT CallEstablished()
{
	LOG("CallEstablised in CallMonitor is interpreting");

	if (g_CallEstablished == TRUE) {
		RunScript("Prepaid\\CallMonitor.ccs");
	} 
	
	int nRet = 0;
	g_Pound = FALSE;
	g_IsTimerExpired = FALSE;
	g_strConnectTime = GetTime();
	g_CallEstablished = TRUE;
	LOG("Connect Time :" + FormatTime(g_strConnectTime, "%H:%M:%S.000 UTC %a %b %d %Y"));

	if (g_CreditTime >= 60) {
		LOG("First 60sec setted..." );
		g_iTimerId = StartTimer(g_CreditTime - 60, "LastMinWarning", TRUE);		
	}
	else {
		g_iTimerId = StartTimer(g_CreditTime, "TimerExpired", TRUE);
	}

	LOG("Timer Active");
}

EVENT LastMinWarning()
{	
	LOG("LastMinWarning occured");	
	RunScript("Prepaid\\LastMinuteWarning.ccs", "UserEvent");
}

EVENT TimerExpired()
{	
	LOG("TimerExpired in CallMonitor is interpreting");
	string strTime = GetTime();
	LOG("Time: " + FormatTime(strTime, "%H:%M:%S.000 UTC %a %b %d %Y"));

	// Close Both LEG
	EndCall(_LEG_IVR_);
	//RadiusStopAccounting();
	ReleaseSession();
}

EVENT LastMinCallback()
{	
	LOG("LastMinCallback is interpreting");	

	if (g_iTimerId != 0) {
		LOG("Old Timer stopping." + i2str(g_iTimerId));
		StopTimer(g_iTimerId);
		g_iTimerId = StartTimer(60, "TimerExpired", TRUE);
	}
	RunScript("Prepaid\\CallMonitor.ccs");
}

EVENT CallReject()
{
	LOG("CallReject in Ringing is interpreting");
	LOG("Reject Cause: " + i2str(_RESPONSE_));

	if (g_CallEstablished == TRUE) {
		LOG("Reject message for re-INVITE ");
		EndCall(_LEG_B_);
	}

	if (_RESPONSE_ == 404) {
		LOG("Called number is not found");
		PlayAudio(_LEG_A_, "DestinationNotFound");
	}
	if (_RESPONSE_ == 486) {
		LOG("Called number is busy");
		PlayAudio(_LEG_A_, "NumberIsBusy");
	}
	if ((_RESPONSE_ == 408) || (_RESPONSE_ == 480) || 
		(_RESPONSE_ == 484) || (_RESPONSE_ == 487)) {
		LOG("Called number does not answer");
		PlayAudio(_LEG_A_, "NoAnsver");
	}
	if (_RESPONSE_ == 500) {
		LOG("Interval Server Error (Sip Cause 500)");
		PlayAudio(_LEG_A_, "ErrorMessage");
	}
	AbortSession();
}

EVENT CallEnd()
{
	LOG("CallEnd in CallMonitor is interpreting");
	//RadiusStopAccounting();
	CloseSession();
}

EVENT OnDigit()
{
	LOG("OnDigit in CallMonitor is interpreting");
	SendDigit(_LEG_B_, _DIGIT_, _DIGIT_DURATION_);
}


LastMinuteWarning.ccs
EVENT UserEvent()
{
	LOG("LastMinWarning::UserEvent is interpreting");

	JoinLegs(_LEG_IVR_, _LEG_B_);
	JoinLegs(_LEG_IVR_, _LEG_A_);
	
	bool bRet = OpenAudioChannel(_LEG_A_);
	if (bRet == FALSE) {
		LOG("LastMinWarning::OpenAudioChannel returned FALSE");
	} 
	
	// Make the last minute announcement
	PlayAudio(_LEG_A_, "YourLast60Sec");
	
	CloseAudioChannel(_LEG_A_);

	JoinLegs(_LEG_B_, _LEG_A_);
	JoinLegs(_LEG_A_, _LEG_B_);
}

EVENT CallEstablished()
{
	LOG("CallEstablised in LastMinWarning is interpreting");
	RunScript("Prepaid\\CallMonitor.ccs", "LastMinCallback");
}

EVENT CallEnd()
{
	LOG("CallEnd in CallMonitor is interpreting");
	//RadiusStopAccounting();
	CloseSession();
}

Session Controller Logic

Call signalling is a bit different for NicSC SIP Session Controller. It does not take over the call and It behaves like a proxy. It does not have the capability of playing voice files like NicIVR but signalling-scripting integration seems like NicIVR.

                          
	      CALLER                    NICSC                   CALLEE
		|                        |                        |
		|                        |                        |
		|>REGİSTER ------------->|<------------- REGISTER<|
		|                        |                        |
		|<--------------- 200 Ok<|>200 Ok---------------->|
		|                        |                        |
		|>INVITE (sdp)---------->|                        |
		|                        |                        |
		|<----------- 100 TRYING<|                        |
		|                        |                        |
		|                        |>INVITE (sdp)---------->|
		|                        |                        |
		|                        |<---------- 180 RINGING<|
		|                        |                        |
		|<-----------180 RINGING<|                        |
		|                        |                        |
		|                        |<----------(sdp) 200 Ok<|
		|                        |                        |
		|                        |>ACK ------------------>|
		|                        |                        |
		|<----------(sdp) 200 Ok<|                        |
		|                        |                        |
		|>ACK------------------->|                        |
		|                        |                        |
		|>re-INVITE (sdp)------->|                        |
		|                        |                        |
		|<----------- 100 TRYING<|                        |
		|                        |                        |
		|                        |                        |
		|                        |>re-INVITE (sdp)------->|
		|                        |                        |
		|                        |<----------(sdp) 200 Ok<|
		|                        |                        |
		|                        |>ACK ------------------>|
		|                        |                        |
		|<----------(sdp) 200 Ok<|                        |
		|                        |                        |
		|>ACK------------------->|                        |
		|                        |                        |
		|                        |<------------------ BYE<|
		|                        |                        |
		|                        |>20O Ok --------------->|
		|                        |                        |
		|<------------------ BYE<|                        |
		|                        |                        |
		|>200 Ok --------------->|                        |
		
	
Please contact us for any question or further details: info@creacode.com.tr