This document explains the structure of the code in the IAPs, the main interfaces with the other components of Iceberg. This is to be used as a guide in writing new IAPs to extends Iceberg to new end-points.
An IAP is a proxy between the device or service specific side and the Internet core. Hence a portion of it is device or service specific and a portion of it is generic.
In ICEBERG v1, DTMF passing has not been implemented. Adding this would involve adding an appropriate message between the control signaling that goes on in the form of heart-beats between call-agents in a session.
An IAP need not necessarily support incoming calls as well as outgoing calls. Accordingly, we define server and client IAPs as follows. Server IAPs: Those that implement the interface for incoming calls (incoming from the Internet-core side). Client IAPs: Those that support outgoing calls (outgoing to the Internet-core side). An IAP can serve as only as a client, or only as a server, or both.
The IAP interacts with the Call Agent through heart-beats. The generic part of the IAP itself is split into two parts -- the state-machine-engine and the rest -- this document describes the latter.
This part of the IAP actually has the misnomer ui (in the code tree) since this part was first written for the IPPhone -- for which case the bulk of this part of the IAP is the Java GUI.
The state-machine-engine part of an IAP instantiates a UI object when it runs. The UI object implements the iceberg1.sme.UI_IF interface.
These are made from the UI part of the IAP. The relevant calls are:
<UIObj>.sme.recv(iceberg1.iap.events.OutgoingCall); <UIObj>.sme.recv(iceberg1.iap.events.DevHangUp);
The "UIObj" is the 'this' object and the "sme" is that stored from the "setStateMachine" call (see UI_IF description above).
The state-machine actually sends these events to the other end of the call (rather than receiving, as the name seems to indicate).
The events for OutgoingCall and DevHangUp are formed as follows:
DevHangUp evt = new DevHangUp(smiID, sessionID); OutgoingCall evt = new OutgoingCall (smiID, sessionID, callerID, endPointInfo, callerDevAddr, calleeDevAddr, <UIObj>.sme.getMcastTransportAddr(), <UIObj>.sme.getMcastTransportPort());
For DevHangUp, the state-machine-instance ID and the sessionID are given as arguments.
For the OutgoingCall, in addition, we have the caller and callee information, the multicast address and port from the state-machine-engine, and the EndPointInfo object. The EndPointInfo object is described below as part of the interface with the APC.
The APC service is responsible for establishing the data path between the ends of a communication session. The IAP serves as the data source or sink. The source is considered part of the "path" created by the APC service. Hence a "ConnectorManager" has to run at the IAP (see the APC documentation for what a ConnectorManager is). Technically, the ConnectorManager does not have to run as a vSpace service, but in the current implementation, it does.
The APC service passes the relevant arguments for running the source operator at the IAP, through this ConnectorManager. In some cases, there may not be any source operator at the IAP end. There are two possible reasons for this:
The EndPointInfo sent by the IAP to the CA, during incoming call or an outgoing call, is given as argument for path setup by the CA to the APC service. The APC service passes this on to the ConnectorManager at the IAP end.
The EndPointInfo object is constructed as follows:
new EndPointInfo(IPAddr, iSpacePort, Format, Args, WorkerName, sessionID);
The IPAddr specifies the host where the data stream is supposed to start/end -- this is the machine where the ConnectorManager is running. The "iSpacePort" argument is a vestigial argument from ICEBERG-v0. "Format" gives the data format (e.g., "gsm", "pcm-ul-8000", "mp3"). Notes: (a) Ideally, we should have a different format for the incoming and outgoing direction - these two are forced to be the same in the current implementation (b) Ideally, we should have a richer description of the format than just a string -- not there in the current implementation.
"Args" is an array of strings that describes the data end-point (source/sink). The format of this array of strings is understood by the ConnectorManager/Operator of the APC service. For instance, for an RTP stream based source, this array of strings has a single string "IPAddr:Port" that gives the IPAddress and port describing the data sink. For an MP3 stream, the array of strings has a single string: the MP3 URL.
The WorkerName has the format: "APC_"+<vSpaceWorkerName>. The vSpaceWorkerName is the name of the worker that runs as the ConnectorManager under vSpace at the IAP. For instance, "APC_CMGR_VAT_Worker" gives the worker-name for the ConnectorManager associated with a VAT IAP. Finally, the "sessionID" argument identifies the call session associated with the data path.
The IAP is a state-machine. It moves from one state to another based on events. There are handlers for each event -- used by the state machine engine. The generic set of handlers for IAPs are in the package "iceberg1.iap.hdlrs.generic". The other handlers extend the generic handlers.
Handler generation
Handlers are generated by the TCL program "iceberg1/codegen/codegen.tcl". The program is run as:
codegen.tcl <config-file>
The config-file template is given in "iceberg1/codegen/cfgs/template". To generate handlers, set the following variables:
dontwriteCustomHdlrs = false specFile = /path/to/iceberg1/iceberg1/smSpec/iap.sms hdlrPkgName = iceberg1.iap.hdlrs.<iap-pkg-name> icebergDir = /path/to/iceberg1 evtTpltFile = /path/to/iceberg1/iceberg1/codegen/eventTemplate.java hdlrTpltFile = /path/to/iceberg1/iceberg1/codegen/hdlrTemplate.java
After generating the handlers, remove the code from inside the class of all the handlers -- this will make the handlers use the default generic handlers for all these events. Do this for all handlers except "IAP_idle_IncomingCall_hdlr.java". For "IAP_idle_IncomingCall_hdlr.java", the "handle" routine has to set the EndPointInfo for the state-machine-instance. Look for the "smi.setSessionState" call and the code before that. This EndPointInfo describes the IAP data end-point for this IAP.
Each IAP, as mentioned earlier, also runs a ConnectorManager in the same machine. The generic worker for this purpose is "iceberg1.APCpath.workers.CMGR_Worker" which all specific ConnectorManager extend. CMGR_VAT_Worker itself has evolved into a generic ConnectorManager. The vSpace service container delivers the events "CMGR_CR_Task" and "CMGR_RUN_Task" to this worker. The methods "handleCMGR_CR_Task" and "handleCMGR_RUN_Task" have to be implemented by the worker.
An operator is an object instantiated when "CMGR_CR_Task" is delivered (during data path creation). The operator object is "Runnable". It is "started" when "CMGR_RUN_Task" is delivered. An operator has to implement the "iceberg1.APCpath.operators.OperatorIF" interface. "ProcessOperator" is a generic operator class which execs a generic executable program -- a transformation agent that can take input from stdin and writes output to stdout. Operators that extend this class implement the following methods: "genInputType", "getOutputType", "ipBlockSize", "opBlockSize", "start", and "getCmd". See "VatOp" as an example. For an example of an operator that does not extend the "ProcessOperator", see "JBOp".
Implementing an IAP for a new device or service end-point involves the following steps: