www.pudn.com > d4j.zip > GCChannel.java


// local.dialogic.GCChannel 
// Implements Global Call functionality, uses DialogicGC.dll 
// $Id: GCChannel.java,v 1.6 2003/11/13 11:44:16 cgm8 Exp $ 
/*  
 * Copyright (c) 1999 Carlos G Mendioroz. 
 * 
 *  This file is part of D4J. 
 * 
 *  D4J is free software; you can redistribute it and/or 
 *  modify it under the terms of the GNU Lesser General Public 
 *  License as published by the Free Software Foundation; either 
 *  version 2 of the License, or (at your option) any later version. 
 *   
 *  D4J is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 *  Lesser General Public License for more details. 
 *   
 *  You should have received a copy of the GNU Lesser General Public 
 *  License along with this library; if not, write to the 
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
 *  Boston, MA  02111-1307, USA. 
 * 
 * Report problems and direct all questions to: 
 * 
 *	tron@acm.org 
 */ 
 
package local.dialogic; 
 
public class GCChannel extends Channel implements Runnable { 
    // Constantes 
    private static final int RESET = 0; 
    private static final int IDLE = 1; 
    private static final int ICALL = 2; 
    private static final int RINGS = 3; 
    private static final int IN = 4; 
    private static final int OFFH = 5; 
    private static final int DIAL = 6; 
    private static final int OUT = 7; 
    //private static final int ANI = 8; 
    //private static final int SANI = 9; 
	private static final int ERROR = 10; 
     
    public static final int DT_GC = 0x800; 
    public static final int GCEV_TASKFAIL    = (DT_GC | 0x01); /* Abnormal condition; state unchanged */ 
    public static final int GCEV_ANSWERED    = (DT_GC | 0x02); /* Call answered and connected */ 
    public static final int GCEV_CALLPROGRESS= (DT_GC | 0x03); 
    public static final int GCEV_ACCEPT      = (DT_GC | 0x04); /* Call is accepted */ 
    public static final int GCEV_DROPCALL    = (DT_GC | 0x05); /* gc_DropCall is completed */ 
    public static final int GCEV_RESETLINEDEV= (DT_GC | 0x06); /* Restart event */ 
    public static final int GCEV_CALLINFO    = (DT_GC | 0x07); /* Info message received */ 
    public static final int GCEV_REQANI      = (DT_GC | 0x08); /* gc_ReqANI() is completed */ 
    public static final int GCEV_SETCHANSTATE= (DT_GC | 0x09); /* gc_SetChanState() is completed */ 
    public static final int GCEV_FACILITY_ACK= (DT_GC | 0x0A); 
    public static final int GCEV_FACILITY_REJ= (DT_GC | 0x0B); 
    public static final int GCEV_MOREDIGITS  = (DT_GC | 0x0C); /* cc_moredigits() is completed*/ 
    public static final int GCEV_SETBILLING  = (DT_GC | 0x0E); /* gc_SetBilling() is completed */ 
    public static final int GCEV_ALERTING    = (DT_GC | 0x21); /* The destination telephone terminal 
                                           * equipment has received connection 
                                           * request (in ISDN accepted the 
                                           * connection request.  This event is 
                                           * an unsolicited event 
                                           */ 
    public static final int GCEV_CONNECTED   = (DT_GC | 0x22); /* Destination answered the request */ 
    public static final int GCEV_ERROR       = (DT_GC | 0x23); /* unexpected error event */ 
    public static final int GCEV_OFFERED     = (DT_GC | 0x24); /* A connection request has been made */ 
    public static final int GCEV_DISCONNECTED= (DT_GC | 0x26); /* Remote end disconnected */ 
    public static final int GCEV_PROCEEDING  = (DT_GC | 0x27); /* The call state has been changed to 
                                           * the proceeding state */ 
    public static final int GCEV_PROGRESSING = (DT_GC | 0x28); /* A call progress message has been 
                                           * received */ 
    public static final int GCEV_USRINFO     = (DT_GC | 0x29); /* A user to user information event is 
                                           * coming */ 
    public static final int GCEV_FACILITYREQ = (DT_GC | 0x2A); /* A facility request is made by CO */ 
                                          /* NB: ISDN equivalent value is */ 
                                          /* CCEV_FACILITY */ 
    public static final int GCEV_CONGESTION  = (DT_GC | 0x2B); /* Remote end is not ready to accept 
                                           * incoming user information */ 
    public static final int GCEV_FACILITY    = (DT_GC | 0x2C); /* Facility info. available */ 
    public static final int GCEV_D_CHAN_STATUS=(DT_GC | 0x2E); /* Report D-channel status to the user */ 
    public static final int GCEV_NOUSRINFOBUF= (DT_GC | 0x30); /* User information element buffer is 
                                           * not ready */ 
    public static final int GCEV_NOFACILITYBUF=(DT_GC | 0x31); /* Facility buffer is not ready */ 
    public static final int GCEV_BLOCKED     = (DT_GC | 0x32); /* Line device is blocked */ 
    public static final int GCEV_UNBLOCKED   = (DT_GC | 0x33); /* Line device is no longer blocked */ 
    public static final int GCEV_ISDNMSG     = (DT_GC | 0x34); 
    public static final int GCEV_NOTIFY      = (DT_GC | 0x35); /* Notify message received */ 
    public static final int GCEV_L2FRAME     = (DT_GC | 0x36);  
    public static final int GCEV_L2BFFRFULL  = (DT_GC | 0x37); 
    public static final int GCEV_L2NOBFFR    = (DT_GC | 0x38); 
    public static final int GCEV_SETUP_ACK   = (DT_GC | 0x39); 
    public static final int GCEV_CALLSTATUS  = (DT_GC | 0x3A); /* call status, e.g. busy */ 
 
    /*gc5*/ 
    /* these events only apply to those sites using ISDN DPNSS */ 
    public static final int GCEV_DIVERTED    = (DT_GC | 0x40); 
    public static final int GCEV_HOLDACK     = (DT_GC | 0x41); 
    public static final int GCEV_HOLDCALL    = (DT_GC | 0x42); 
    public static final int GCEV_HOLDREJ     = (DT_GC | 0x43); 
    public static final int GCEV_RETRIEVEACK = (DT_GC | 0x44); 
    public static final int GCEV_RETRIEVECALL= (DT_GC | 0x45); 
    public static final int GCEV_RETRIEVEREJ = (DT_GC | 0x46); 
    public static final int GCEV_NSI         = (DT_GC | 0x47); 
    public static final int GCEV_TRANSFERACK = (DT_GC | 0x48); 
    public static final int GCEV_TRANSFERREJ = (DT_GC | 0x49); 
    public static final int GCEV_TRANSIT     = (DT_GC | 0x4A); 
 
    /* end of ISDN DPNSS specific */ 
    public static final int GCEV_ACKCALL     = (DT_GC | 0x50); /* Termination event for gc_CallACK() */ 
     
    /* 
     * Cause definitions for dropping a call 
     */ 
    public static final int GC_UNASSIGNED_NUMBER   =  0x01;   /* Number unassigned / unallocated */ 
    public static final int GC_NORMAL_CLEARING     =  0x10;   /* Call dropped under normal conditions*/ 
    public static final int GC_CHANNEL_UNACCEPTABLE=  0x06; 
    public static final int GC_USER_BUSY           =  0x11;   /* End user is busy */ 
    public static final int GC_CALL_REJECTED       =  0x15;   /* Call was rejected */ 
    public static final int GC_DEST_OUT_OF_ORDER   =  0x19;   /* Destination is out of order */ 
    public static final int GC_NETWORK_CONGESTION  =  0x2a; 
    public static final int GC_REQ_CHANNEL_NOT_AVAIL= 0x2c;   /* Requested channel is not available */ 
    public static final int GC_SEND_SIT            =  0x300;  /* send Special Info. Tone (SIT) */ 
 
    /* 
     * RATE types for gc_SetBilling() 
     */ 
    public static final int GCR_CHARGE            =  0x0000; /* Charge call (default) */ 
    public static final int GCR_NOCHARGE          =  0x0100; /* Do not charge call */ 
 
     
    // Variables 
    private static Unloader loaded = null; 
    Voice voiceDev = null; 
    private GCLine lineDev = null; 
    private String name; 
    private int linestate = RESET; 
    private boolean cas = false; 
    private boolean blocked = true; 
	private boolean waiting = false; 
    private int crn = 0; 
	private String dnisPref = ""; 
     
    // Native 
    // called via Dialogic loop for linux thread issue. 
    protected static native void gc_Start(); 
    protected static native void gc_Stop(); 
    protected static native int gc_Open(String name); 
    protected static native void gc_Close(int line); 
    protected static native int gc_GetVoiceH(int line); 
    protected static native int gc_GetNetworkH(int line); 
    protected static native void gc_Attach(int line, int voiceH, int mode); 
    protected static native void gc_Detach(int line, int voiceH, int mode); 
    protected static native int gc_WaitCall(int line, int timeout, int mode); 
    protected static native void gc_AcceptCall(int crn, int rings, int mode); 
    protected static native void gc_AnswerCall(int crn, int rings, int mode); 
    protected static native void gc_CallAck(int crn, int dnis, int mode); 
    protected static native void gc_DropCall(int crn, int cause, int mode); 
    protected static native int gc_GetDNIS(int crn, byte buf[]); 
    protected static native int gc_GetANI(int crn, byte buf[]); 
    protected static native void gc_GetCallInfo(int crn, int id, byte buf[]); 
    protected static native int gc_GetParm(int line, int id); 
    protected static native void gc_SetParm(int line, int id, int value); 
    protected static native int gc_MakeCall(int line, String number, int to, int mode); 
    protected static native void gc_ReleaseCall(int crn); 
    protected static native void gc_ResetLineDev(int line, int mode); 
    protected static native void gc_SetBilling(int crn, int rate, int mode); 
    protected static native void gc_SetChanState(int line, int state, int mode); 
    protected static native void gc_getMeta(EVT evt);  
 
    static { 
        try { 
            Class.forName("local.dialogic.Dialogic");  
        } catch (ClassNotFoundException cnfe) { 
            throw new RuntimeException("Loading Dialogic class"); 
        } 
        System.loadLibrary("DialogicGC"); 
        loaded = new GCChannel().new Unloader(); 
    } 
     
    // This class is a trick to get a class finalizer... 
    class Unloader { 
        protected void finalize() throws Throwable { 
            Dialogic.gc_Stop(); 
        } 
    } 
     
    private GCChannel() { 
        name = "Unloader stub"; 
    } 
 
    public GCChannel(String GCName) { 
    	this(GCName, ""); 
    } 
 
    public GCChannel(String GCName, String dnisPreffix) { 
        super(); 
    	if (!GC) { 
	        Dialogic.gc_Start(); 
	        GC = true; 
	    } 
 
        name = GCName; 
		dnisPref = dnisPreffix; 
         
        if (GCName.indexOf("P_isdn") >= 0) { 
            // independent voice implementations like ISDN 
            int vstart = GCName.indexOf(":V_"); 
            if (vstart < 0)  
                throw new RuntimeException("No voice resource for ISDN"); 
            int vend = GCName.indexOf(":", vstart + 2); 
            if (vend < 0)  
                vend = GCName.length(); 
            String DxName = GCName.substring(vstart+3, vend); 
            GCName = name.substring(0, vstart) + name.substring(vend); 
            lineDev = new GCLine(this, GCName); 
            voiceDev = new Voice(this, DxName); 
            // link 
            lineDev.listen(voiceDev); 
            voiceDev.listen(lineDev); 
        } else { 
            // dependent voice implementations like R2CAS 
            lineDev = new GCLine(this, GCName); 
            voiceDev = lineDev.getVoice(this); 
            cas = true; 
        } 
 
        linestate = RESET; 
        group = new ThreadGroup(name + " group"); 
 
        serviceThread = new Thread(group, this, name + " service"); 
        serviceThread.start(); 
    } 
 
    public void close() 
    { 
        super.clear(); 
        if (serviceThread != null) { 
            Channel.stopGroup(this); 
            serviceThread.interrupt(); 
            try { 
                serviceThread.join(500); 
            } 
            catch (InterruptedException ie) {}; 
            serviceThread = null; 
        } 
        if (lineDev != null) { 
            lineDev.close(); 
            lineDev = null; 
        } 
        if (voiceDev != null) { 
            voiceDev.close(); 
            voiceDev = null; 
        } 
    } 
 
    public Voice getVoice() { 
        return voiceDev; 
    } 
 
    public Device getNetwork() { 
        return lineDev; 
    } 
 
    public void run() { 
		EVT evt; 
 
        while(true) try { 
            clear(); 
            while (blocked) 
				evt = serviceWaitEvent(); 
			if (!waiting) { 
	            lineDev.waitCall(); 
	            waiting = true; 
			} 
            beginService(); 
       	    while(true) { 
           	    evt = serviceWaitEvent(); 
           	    if (evt.type == GCEV_OFFERED) { 
               	    linestate = ICALL; 
           	        setState(INCOMING); 
           	        crn = (int)evt.crn; 
           	        call = new Call(GCChannel.this); 
           	        byte dnis[] = new byte[10]; 
           	        try { 
           	        	int dnisl = Dialogic.gc_GetDNIS(crn, dnis); 
           	        	call.dnis = dnisPref + new String(dnis, 0, dnisl); 
           	        } catch (RuntimeException rte) { 
           	        	call.dnis = dnisPref; 
           	        } 
               	    if ((Dialogic.debug & Dialogic.DEBUG_GC) != 0) 
               	        System.out.println(new java.util.Date().toString().substring(11,19) + this + ": Call to " + call.dnis + "(" + crn + ")"); 
                   	if (handler != null) { 
                   	    endService(); 
       	                handler.handleCall(call); 
       	            } 
               	} else { 
               	    if ((Dialogic.debug & Dialogic.DEBUG_GC) != 0) 
                   	    System.out.println(new java.util.Date().toString().substring(11,19) + this + ": Event " + evt); 
               	} 
       	    } 
       	}  
       	catch (Exception e)  { 
       		if (linestate == DIAL) 
       			// Someone asking me to leave... 
       			return; 
       	    System.err.println(this.toString() + " service loop: " + e); 
       	} 
       	finally { 
       	    endService(); 
       	} 
    } 
 
    public String toString() { 
        return "GCChannel on " + name; 
    } 
 
    void accept() { 
        if (linestate != ICALL) 
            throw new ChannelException("accept(): wrong state"); 
   	    if ((Dialogic.debug & Dialogic.DEBUG_GC) != 0) 
   	        System.out.println(new java.util.Date().toString().substring(11,19) + this + ": accepting " + crn); 
        try { 
            beginService(); 
            Dialogic.gc_AcceptCall(crn, 0, Dialogic.EV_ASYNC); 
            EVT evt = serviceWaitEvent(); 
            if (evt.type != GCEV_ACCEPT) 
                throw new ChannelException("Accept error:" + evt); 
            linestate = RINGS; 
        } finally { 
            endService(); 
        } 
    } 
 
    void answer(int rings) { 
        // It is ok to answer w/o accept... 
        if (!(linestate == RINGS || linestate == ICALL)) 
            throw new ChannelException("answer(): wrong state"); 
        if (linestate == ICALL) 
            accept(); 
        // Ring cycle 
        EVT evt = null; 
        long now = System.currentTimeMillis(); 
        long conn = call.startTime() + rings * 3000; // 3 secs each 
        try { 
            beginService(); 
            if (conn > now)  
                evt = serviceWaitEvent(conn - now); 
            if (evt == null) {     
		   	    if ((Dialogic.debug & Dialogic.DEBUG_GC) != 0) 
		   	        System.out.println(new java.util.Date().toString().substring(11,19) + this + ": answering " + crn); 
                Dialogic.gc_AnswerCall(crn, 0, Dialogic.EV_ASYNC); 
                evt = serviceWaitEvent(); 
                if (evt.type != GCEV_ANSWERED) 
                    throw new ChannelException("Answer error:" + evt); 
                linestate = IN; 
            } else { 
                linestate = ERROR; 
                setState(OOS); 
                throw new ChannelException("answer():" + evt); 
            } 
        } finally { 
            endService(); 
        } 
    } 
 
    void reject(int reason) { 
        if (linestate != ICALL) 
            throw new ChannelException("reject(): wrong state"); 
        throw new ChannelException("reject: not implemented!"); 
    } 
 
    void dial(Call call, String number) { 
        if (linestate != IDLE) 
            throw new ChannelException("dial(): wrong state"); 
        if (blocked)  
            throw new ChannelException("dial(): blocked"); 
        linestate = DIAL; 
        if (serviceThread != null) { 
			Channel.stopGroup(this); 
			serviceThread.interrupt(); 
			/* Service thread will normally die,  
			 * but simultaneous seizure may prevent that from happening... */ 
			try { 
				serviceThread.join(500); 
			} 
			catch(InterruptedException ie) { 
				Thread.currentThread().interrupt(); 
			} 
			// Give up if it did not quit... 
			if (serviceThread.isAlive()) { 
				System.err.println("Seizure failure: service not quitting"); 
				throw new ChannelException("dial(): seizure failure"); 
			} 
			serviceThread = null; 
		} 
        this.call = call; 
        setState(OUTGOING); 
        // Wait for call completion... 
        try { 
            beginService(); 
	   	    if ((Dialogic.debug & Dialogic.DEBUG_GC) != 0) 
		        System.out.println(new java.util.Date().toString().substring(11,19) + this + ": dialing " + number); 
        	crn = lineDev.dial(number, 30); // Note the 30 seconds timeout 
            EVT evt = serviceWaitEvent(); 
            if (evt.type != GCEV_ALERTING) 
                throw new ChannelException("Dial error:" + evt); 
        } finally { 
            endService(); 
        } 
         
        return; 
    } 
 
    String ani() { 
        String ani = ""; 
        if (crn == 0) 
            return ""; 
        byte anis[] = new byte[40]; 
        try { 
            int anisl = Dialogic.gc_GetANI(crn,anis); 
            ani = new String(anis, 0, anisl); 
        } catch (Exception e) { 
            // Runtime exception thrown by GC layer if ani not available 
            ani = ""; 
        } 
        return ani; 
    } 
 
    int pulses() { 
        throw new ChannelException("pulses: not implemented!"); 
    } 
 
	synchronized void clear() { 
        if (linestate == RESET) 
            return; 
        linestate = RESET; 
        super.clear(); 
        if (voiceDev != null) { 
          voiceDev.stop(); 
          voiceDev.clear(); 
          if (cas) { 
			  lineDev.listen(voiceDev); 
			  voiceDev.listen(lineDev); 
		  } 
        } 
        if (crn != 0) { 
	   	    if ((Dialogic.debug & Dialogic.DEBUG_GC) != 0) 
   		        System.out.println(new java.util.Date().toString().substring(11,19) + this + ": dropping " + crn); 
            Dialogic.gc_DropCall(crn, GC_NORMAL_CLEARING, Dialogic.EV_ASYNC); 
        }  
        flush(); 
   		if (serviceThread == null) { 
			serviceThread = new Thread(group, this, name + " service"); 
        	serviceThread.start(); 
		} 
 
    } 
 
    // Our line state service fn 
    protected EVT service(EVT evt) { 
        switch (evt.type) { 
        case GCEV_BLOCKED:  
            blocked = true; 
            waiting = false; 
            evt = null; 
            linestate = ERROR; 
            setState(OOS); 
	   	    if ((Dialogic.debug & Dialogic.DEBUG_GC) != 0) 
   		        System.out.println(new java.util.Date().toString().substring(11,19) + this + ": resetting"); 
            lineDev.reset(); 
            break; 
        case GCEV_UNBLOCKED:  
            blocked = false; 
            if (linestate == RESET) { 
                linestate = IDLE; 
                setState(FREE); 
            } 
            break;             
        case GCEV_DISCONNECTED: 
            voiceDev.stop(); 
	   	    if ((Dialogic.debug & Dialogic.DEBUG_GC) != 0) 
   		        System.out.println(new java.util.Date().toString().substring(11,19) + this + ": dropping " + crn); 
            Dialogic.gc_DropCall(crn, GC_NORMAL_CLEARING, Dialogic.EV_ASYNC); 
            if (call != null) call.drop(); 
            clear(); 
            throw new HangUpException(); 
        case GCEV_DROPCALL: 
            voiceDev.stop(); 
	   	    if ((Dialogic.debug & Dialogic.DEBUG_GC) != 0) 
   		        System.out.println(new java.util.Date().toString().substring(11,19) + this + ": releasing " + crn); 
            Dialogic.gc_ReleaseCall(crn); 
            if (call != null) call.drop(); 
            crn = 0; 
            evt = null; 
            linestate = IDLE; 
            setState(FREE); 
            break; 
        case GCEV_CONNECTED: 
			// Remote answer 
			if (call != null) call.connect(); 
			break; // Let the event go up 
        } 
        return evt; 
    } 
}