![]() |
Version 5.1 |
||||||||||||||||||||||||||||||||
|
|
A Real-Time Application Environment is a set of files that may include:
Environments are designed to support several human (spoken) languages. The default Environment language is English. To support other languages, an Environment should contain language directories, named as the languages they support (french, russian, japanese, etc.)
A language directory can contain the same files as the Environment itself, but it cannot contain language subdirectories.
Real-Time Application Tasks can select a language to be used. When a non-default language is selected, and the application code tries to read a file from the Application Environment, the selected language subdirectory is used. If the file is not found in the language subdirectory, the file is retrieved from the Application Environment itself (i.e. the default language file is used).
The CommuniGate Pro server comes with a built-in "Stock" Real-Time Application Environment. This Environment contains some basic applications and all files required by those applications, as well as some useful code section and media files.
Each CommuniGate Pro system has its Server-wide Application Environment. A CommuniGate Pro Dynamic Cluster installation also has a Cluster-wide Application Environment. To modify these Environments, open the WebAdmin Interface Domains section and follow the PBX link.
Each CommuniGate Pro Domain has its own Application Environment. To modify that Environment, open the WebAdmin Interface Domains section, open the Domain Settings for the selected Domain and follow the PBX link.
Modifications of the Cluster-wide Environment, as well as modifications of an Environment in any Shared Domain are automatically distributed to all Cluster Members.
Since Domains have their own Application Environments, different applications in different Domains can have the same name.
All Application Environment files should use the UTF-8 character set for non-ASCII symbols.
Real-Time Application Tasks are executed "on behalf" of a certain
CommuniGate Pro Account.
When an application requests an "environment file" and the default language is selected,
the Server looks for the file in:
If a non-default language is selected, the Server first looks for the file in the language directories of the Environments listed above. If the file is not found in any of those directories, the listed Environments themselves are searched. So, if a language-specific file has not been created, the default-language (English) file is used.
This hierarchy provides for simple Application customization. Accounts in all Domains can use the same Stock or Server-wide applications, while Domain Administrators can customize these applications by uploading custom files into their Domain Environments.
The WebAdmin Interface provides the Real-Time Application Environment Editor pages to manage Server-wide, Cluster-wide, and Domain Application Environments.
To manage the Server-wide and Cluster-wide Environments, open the Domains realm of the WebAdmin Interface, and click the PBX link.
To manage the Domain Environment, open that Domain page in the Domains realm of the WebAdmin Interface, and click the PBX link. The Domain Administrator should have the CanModifyPBXApps Access Right to be able to create and modify the Domain Application Environment.
The Environment Editor page contains the list of all files "visible" in this Environment: it lists files directly uploaded to this particular Environment, as well as all files uploaded to the Environments used as the "default files" source for this Environment:
Files directly uploaded to the Environment have a checkbox in the Marker column. Files from the other Environments "visible" in this Environment have the word default in that column.
You can download any of the Environment files by clicking the file name.
You can upload a file to the Environment by clicking the Browse button and selecting a file on your workstation, then clicking the Upload button.
You can delete any of the files uploaded to the Environment by selecting the checkboxes and clicking the Delete Marked button.
If you are uploading a file with the .sppr or the .sppi extension,
the Editor assumes that the file contain some CG/PL program code, and it tries to compile that code.
If the compiler detects an error, the file is not uploaded, and the file content
is displayed on the Editor page, with the red <--ERROR--> marker
indicating the location of the error.
The Server places used Real-Time Environment files into an internal cache. When you upload a file to any Environment, that Environment cache is automatically cleared. If you upload a file to a Shared Domain Environment or to the Cluster-wide Environment, the updated file automatically propagates to all Cluster Members.
You can upload a set of files by uploading a TAR-archive (a file with .tar name extension). For example, when you have a TAR-archive with a predesigned Real-Time Application you can open the Environment you want to modify, and upload the .tar file. The Server will unpack the archive and store each file individually, as if they were uploaded one-by-one.
The Editor page contains the list of all Language directories:
To create a new Variant, enter the language name, and click the Create Language button.
To open a Language directory, click its name. The Editor will display the Language name, and it will provide the UP link to the list of the default language files.
Real-Time Applications run as Tasks. To start an Application, the CommuniGate Pro Server starts a new Task and instructs it to execute the main entry code section of the specified Application.
A Real-Time Application Task can run in the disconnected mode, or it can be a part of exactly one Real-Time session (such as a phone call) with some peer. A peer is any Real-Time entity, such as a SIP phone, a PSTN gateway, a remote Real-Time application communicating via SIP, or a local Real-Time Application, i.e. some other Task.
If a Task is participating in a session with some peer, it can be in one of the following modes:
A Task can receive Signals from its peer, and it can send Signals itself. Signals can be used to end the current session, to update the session parameters, etc. Some of the Signals sent by the peer are processed by the Real-Time Application Environment itself, while other Signals are passed to the Task for processing.
A Real-Time Application Task has a Media Channel associated with it. When a session is established, the Task Media Channel is connected to the peer's media channel.
A Task can use its Media Channel to send media (audio, video) to the peer, and to record media sent by the peer.
A Task can switch the peer media somewhere else - for example, to a separate service providing music on hold or other media services. When the peer media is switched away, the Task Media Channel cannot be used, but the Task still can control the peer by sending Signals to it and it still receives Signals from the peer. The Task can switch the peer media back to its own Media Channel.
A Media Channel provides a conversation space. A Task can attach other peer media to the Task own Media Channel. This operation creates a conversation space (or a conference) that includes the Task own peer and all peers with media attached to this Task. Media sent by any peer in a conversation space is relayed to all other peers in that space, using the data mixing algorithms and parameters defined for that media type.
A Task with attached peer media can use its Media Channel to send media to its own peer and to all attached peers at once.
Real-Time Application Tasks can automatically process Call Transfer requests.
When a Task receives a REFER request (from a remote client, or from a different Task), it can:
If a Task is instructed to processes REFER requests automatically, it creates a new INVITE request and sends it to the address specified in the Refer-To: field. While this INVITE request is in progress, the task informs the peer about the call progress by sending it NOTIFY requests.
If the INVITE request is completed successfully, the Task sends the BYE Signal request to the current peer (unless it has already received the BYE Signal from the current peer), and then it switches its Signal dialog and the Media Channel to the new peer:
The INVITE signal initiated with the REFER signal can contain authentication information. The application program can instruct the Task:
To process "Assisted" Call Transfer, the Real-Time Application engine detects all INVITE signals with the Replaces field.
If the dialog data specified in the Replaces field matches an active dialog established in any Real-Time Task, the INVITE signal
is directed to that Task. The Task sends a BYE signal to the current peer, and it switches its Signal dialog to the
source of this INVITE signal, and it switches the Media channel to the entity specified in the INVITE signal.
This processing takes place automatically, transparently to the application program the Task is running.
A pair of Real-Time Application Tasks can build a Media Bridge. When a Media Bridge is built, the Tasks' peers exchange media, while each Task stays in control of the peer signaling.
To build a bridge:
When the Tasks A and B are in the "bridged" state, one of the Tasks (Task B here) can receive a re-INVITE signal from its peer. The new media description in this signal request may ask the Task to change its media parameters (hold/resume, switching to a different media source, etc.). This re-INVITE signal is processed automatically, without any involvement of the application programs the Tasks are running:
When the Tasks A and B are in the "bridged" state, one of the Tasks (Task A here) can receive a Call Transfer (REFER) signal from its peer:
When the Tasks A and B are in the "bridged" state, one of the Tasks (Task A here) can receive Call Transfer (INVITE with Replaces) signal (delivered to it by the Signal module based on the Replaces field content):
When the Tasks A and B are in the "bridged" state, one of the Tasks (Task A here) can decide to break the Media Bridge:
When the Tasks A and B are in the "bridged" state, one of the Tasks (Task A here) can receive a disconnect (BYE) signal from its peer, or it can quit for various reasons. In this case:
The Real-Time Application engine may choose to implement a Media Bridge using one Task Media Channel as a "media relay".
The Bridged Call functionality is used to implement the B2BUA (Back-to-Back User Agents) technology. A pair of Real-Time Tasks in the Bridged Mode can work as a "smart proxy": while peers connected to these tasks can communicate directly, the signaling is still controlled with the Tasks and the application programs these Tasks are running.
Real-Time Applications can be written using the CG/PL language.
When a Task is created to process an incoming call, the main entry of the specified CG/PL application program is executed.
Real-Time Applications can use CG/PL external-declarations.
When a code section (a procedure or a function) declared as external is called,
a file with the code section name and the .sppi extension is loaded from the current
Environment. The program code in this file must contain the code section with the specified name
and of the proper type (a procedure or a function).
The program code in an .sppi file may contain other code sections as well.
Real-Time Applications written in the CG/PL language can use the following built-in procedures and functions.
When the peer disconnects, the Task receives a Disconnect Event from the system (this Event dictionary does not contain the .sender element).
// // Sample: ReadInput() // Accept an incoming call (stop if it's not possible). // Play the PressPound media file. // Wait for any input for up to 5 seconds. // If the "pound" ("#") symbol was entered, // play the Good media file. // Otherwise, // play the Bad media file. // Stop. // entry Main is if AcceptCall() != null then stop; end if; PlayFile("PressPound"); PlayFile(ReadInput(5) == "#" ? "Good" : "Bad"); end entry;
// // Sample: AcceptCall()/RejectCall() // If the current local time is not between 8:00 and 17:00, // reject the call (with the 403 error code) and stop. // Otherwise, // accept the call (stop if it is not possible) // play the Welcome media file and stop. // entry Main is currentTime = TimeOfDay(GMTToLocal(GMTTime())); currentHour = currentTime / 3600; if currentHour < 8 or currentHour >= 17 then RejectCall(403); stop; end if; if AcceptCall() != null then stop; end if; PlayFile("Welcome"); end entry;
// // Sample: RedirectCall()/ProvisionCall() // Provision the call (stop if it is not possible). // If the current local time is between 12:00 and 13:00, // fork the call to user1 in the same domain. // Play the "PleaseWait" media file. // If the current local time is not between 8:00 and 17:00, // redirect the call to user2 in the same domain, and stop. // Otherwise, // Accept the call (stop if it's not possible). // Play the Welcome media file, and stop. // entry Main is if ProvisionCall(true,true) != null then stop; end if; currentTime = TimeOfDay(GMTToLocal(GMTTime())); currentHour = currentTime / 3600; if currentHour >= 12 and currentHour <= 13 then ForkCall("sip:user1@" + MyDomain()); stop; end if; PlayFile("PleaseWait"); if currentHour < 8 or currentHour >= 17 then RedirectCall("sip:user2@" + MyDomain()); stop; end if; if AcceptCall() != null then stop; end if; PlayFile("Welcome"); end entry;
Note: if a pending incoming call has been cancelled, the Task receives a Disconnect Event, and the Task mode changes to disconnected.
// // Sample: StartCall()/Disconnect() // Accept an incoming call (stop if it's not possible). // Remember the caller URI. // Play the CallBack media file. // Disconnect(); // Call the caller back (stop if it's not possible). // Play the IamBack media file, and stop. // entry Main is if AcceptCall() != null then stop; end if; fromWhom = RemoteURI(); PlayFile("CallBack"); Disconnect(); if StartCall(fromWhom) != null then stop; end if; loop input = ReadInput(3600); exitif not IsCallProvisionEvent(input); null; end loop; if not IsCallCompletedEvent(input) or else input.parameter != null then stop; end if; PlayFile("IamBack"); end entry;
Each Task has a DTMF buffer string. When a DTMF symbol is received either in an INFO Request or as a media packet (via the Media Channel), the symbol is appended to this buffer.
// // Sample: ReadInput()/SendDTMF() // Accept an incoming call (stop if it's not possible). // Wait for an input for 10 seconds. If no input - stop. // If a digit is entered // play that digit, and send it back. // (using "0" ... "9" files) // If a star ("*") is entered, // wait for a digit (for 3 seconds) // and play the digit number square (2 digits) // If a pound ("#") is entered or the Peer // has disconnected, or any Event was sent, stop. // entry Main is if AcceptCall() != null then stop; end if; loop input = ReadInput(10); if input == "*" then input = ReadInput(3); if IsString(input) and input != "#" then input = "*" + input; end if; end if; exitif not IsString(input) or input == "#"; if Substring(input,0,1) != "*" then PlayFile(input); void(SendDTMF(input)); else input = Number(Substring(input,1,1); product = input * input; PlayFile(String(product/10)); PlayFile(String(product%10)); end if; end loop; end entry;
// // Sample: Record()/PlayFile()/Play() // Accept an incoming call (stop if it's not possible). // Play the GreetingIs file. // Read the current prompt from // the MyGreeting.wav file in the Personal Site. // Loop playing the greeting. // if "1" is entered, rewrite the prompt file and quit // if "2" is entered, play "Beep" and record the prompt. // entry Main is if AcceptCall() != null then stop; end if; PlayFile("GreetingIs"); prompt = ReadSiteFile("MyGreeting.wav"); loop if IsData(prompt) then Play(prompt); end if; input = ReadInput(10); exitif not IsString(input) or else input == "#"; if input == "1" then if WriteSiteFile("MyGreeting.wav",prompt) then PlayFile("Goodbye"); stop; end if; PlayFile("Failure"); elif input == "2" then PlayFile("Beep"); prompt = Record(30); else PlayFile("InvalidEntry"); end if; end loop; PlayFile("GoodBye"); end entry;
When a Media Bridge is successfully established between a pair of Tasks, their peer
media are connected to each other. Tasks Media Channels are disconnected from their peers
and the Media Channel operations (PlayFile, Record, etc.) cannot be used.
A Task cannot use the StartBridge, AcceptBridge, and AttachMixer
functions while a Media Bridge is active.
If a Task disconnects its peer, or the Task peer disconnects itself, or a Task stops (normally, or because of an error), and there is an active Media Bridge, this Media Bridge is automatically removed.
// // Sample: StartBridge()/AcceptBridge()/BreakBridge() // Accept an incoming call (stop if it's not possible). // Create a new Task to run the Caller code, // and send it an Event with the URI to dial. // Play the PleaseWait media file. // Wait for a StartBridge Event from the Caller Task. // Accept it and loop till the user disconnects. // // The Caller code: // Receive a URI to call as an Event from the parent Task // Connect to the URI and play the YouGotACall media file // StartBridge with the parent, loop till the user disconnects // entry Caller forward; procedure ControlBridge() forward; entry Main is if AcceptCall() != null then stop; end if; callerTask = spawn Caller; if callerTask == null or else SendEvent(callerTask,"dial","sip:internal@partner.dom") != null then PlayFile("Failure"); stop; end if; PlayFile("PleaseWait"); input = ReadInput(30); if not IsStartBridgeEvent(input) or else AcceptBridge(input) != null then PlayFile("Failure"); stop; end if; // we have established a bridge ControlBridge(); PlayFile("GoodBye"); end entry; // // Caller Task code // entry Caller is // wait for a "dial" event from the main task input = ReadInput(30); if input == null or input.what != "dial" then stop; end if; mainTask = input.sender; // Calling the URI specified as the Event parameter // If connection failed, send an Event back to the // main task and quit resultCode = StartCall(startEvent.parameter); if resultCode != null then void(SendEvent(mainTask,"result",resultCode)); stop; end if; // wait for any Event other than provisional ones loop input = ReadInput(3600); exitif not IsCallProvisionEvent(input); end loop; // the parent has sent us "stop" - then we'll die immediately if IsDictionary(input) and then input.what == "stop" then stop; end if; if not IsCallCompletedEvent(input) or else input.parameter != null then void(SendEvent(mainTask,"result","generic error")); stop; end if; if StartBridge(mainTask) != null then PlayFile("Failure"); stop; end if; // we have established a bridge ControlBridge(); PlayFile("GoodBye"); end entry; // // Controlling the peer signaling: // while the media is bridged: // exit if the peer hangs up, dials "#" // or if the bridge is removed // procedure ControlBridge() is loop input = ReadInput(3600); exitif IsBreakBridgeEvent(input) or else IsDisconnectEvent(input) or else input == "#"; end loop; void(BreakBridge()); end procedure;
When a Task has other Task peer media attached to its Media Channel, all media are placed into one conversation space (or a conference).
This Task cannot use the StartBridge or AcceptBridge functions.
Note: in certain cases the system may decide to convert an AcceptBridge function operation into an AttachMixer function operation. As a result, the BreakBridge operation can be used by a Task that has exactly one other peer media attached to its Media Channel.
If a Task disconnects its peer, or the Task peer disconnects itself, or a Task stops (normally, or because of an error), and there are other Task peer media attached to this Task Media Channel, the system automatically detaches all of them.
If the peers have been connected, both Tasks stay in the connected mode, unless their peers explicitly send the disconnect Signals. The Tasks should either quit or they should use the Disconnect procedure to fully disconnect from their peers.
Applications can receive and send INFO requests.
Certain INFO requests (such as DTMF event requests) are processed automatically and this section does not apply to them.
INFO request data is presented as a dictionary, with the following elements:
When an INFO request is sent to a Task, the Task receives a special CallInfo Event. The Event parameter element contains a dictionary - the INFO request data.
The following audio file formats are supported: