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


// Voice: Dialogic voice devices 
// $Id: Voice.java,v 1.12 2003/11/13 11:54:45 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 Voice extends Device 
{ 
    // Class varialbles 
    static Object toneLock = new Object(); // serialize tone making 
    // Variables 
    protected int physio;   // low level malloc() memory 
    private IOTT iott;      // reference to current IOTT being used, 
                            // to delay IOTT closing before end of play/rec 
    private XPB xpb;        // same for XPB  
    private boolean GC = false;// Device managed by GC 
     
    /** Open a dx device */ 
    public Voice(Channel ch, String name) 
    { 
        super(ch, name); 
        physio = 0; 
        device = Dialogic.dx_open(name, 0); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Voice open: " + name + " (" + device + ")"); 
        Dialogic.dx_deltones(device); 
        Dialogic.dx_setdigtyp(device, Dialogic.DM_DTMF|Dialogic.DM_DPD); 
        register(); 
    } 
     
    // create a Voice object from an open handle 
    public Voice(Channel ch, int handle) 
    { 
        super(ch, "Device"+handle); 
        physio = 0; 
        device = handle; 
        GC = true; 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Voice open from handle (" + device + ")"); 
        register(); 
    } 
     
    public void close()  
    { 
        if (device != 0) { 
            Dialogic.dx_close(this); 
            if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
                System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Voice close (" + device + ")"); 
            super.close(); 
            device = 0;     // just in case 
            physio = 0; 
        } 
    } 
 
    public void waitIdle() { 
        boolean idle = false; 
        boolean guard = false; 
         
        synchronized(this) { 
            idle = (Dialogic.ATDX_STATE(device) == Dialogic.CS_IDLE); 
        } 
        try { 
            while (!idle) { 
                if (!channel.inService()) { 
                    guard = true; 
                    channel.beginService(); 
                } 
                if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
                    System.out.println(new java.util.Date().toString().substring(11,20) + 
                    "Voice waitIdle (" + device + ")"); 
                try { 
	                channel.serviceWaitEvent(); 
	            } catch (ChannelException ce) { 
	    	        stop(); 
	    	        throw ce; 
	            } 
                synchronized(this) { 
                    idle = (Dialogic.ATDX_STATE(device) == Dialogic.CS_IDLE); 
                } 
            } 
        } finally { 
            if (guard) channel.endService(); 
        } 
        channel.flush(); 
        iott = null; 
        xpb = null; 
    } 
     
    public synchronized void setHook(boolean hook) { 
        boolean guard = false; 
        try { 
            if (!channel.inService()) { 
                guard = true; 
                channel.beginService(); 
            } 
            waitIdle(); 
            if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
                System.out.println(new java.util.Date().toString().substring(11,20) + 
                    "Voice sethook " + hook + " (" + device + ")"); 
            if (hook)  
                Dialogic.dx_sethook(device, Dialogic.DX_OFFHOOK, Dialogic.EV_ASYNC); 
            else 
                Dialogic.dx_sethook(device, Dialogic.DX_ONHOOK, Dialogic.EV_ASYNC); 
                 
            EVT evt = channel.serviceWaitEvent(); 
            // should check it is a hook confirmation... 
        } finally { 
            if (guard) channel.endService(); 
        } 
    } 
     
    public synchronized void waitRings(int nRings) { 
        EVT evt; 
        try { 
            channel.beginService(); 
            waitIdle(); 
            if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
                System.out.println(new java.util.Date().toString().substring(11,20) + 
                    "Voice waitRings " + nRings + " (" + device + ")"); 
            Dialogic.dx_setevtmsk(device, Dialogic.DM_RINGS|Dialogic.DM_RNGOFF); 
            Dialogic.dx_setparm(device, Dialogic.DXCH_RINGCNT, nRings); 
            int linest = Dialogic.ATDX_LINEST(device); 
            if ((linest & Dialogic.RLS_HOOK) == 0) { 
                Dialogic.dx_sethook(device, Dialogic.DX_ONHOOK, Dialogic.EV_ASYNC); 
                waitIdle(); 
            } 
            do { 
                    evt = channel.serviceWaitEvent(); 
            } while (evt.type != EVT.TDX_CST || evt.cstevt != EVT.DE_RINGS); 
        } finally { 
            channel.endService(); 
        } 
    } 
     
    /** Play smth */ 
    public synchronized void play(IOTT iott, TPT tpt, int mode) { 
        if (iott == null || tpt == null) 
            throw new RuntimeException("Bad parameter value"); 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Voice play (" + device + ")"); 
        Dialogic.dx_play(this, iott, tpt, mode|Dialogic.EV_ASYNC); 
        this.iott = iott; 
    } 
     
    /** Play tone */ 
    public synchronized void playtone(TNGEN tn, TPT tpt) { 
		if (tn == null || tpt == null) 
			throw new RuntimeException("Bad parameter value"); 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Voice playtone (" + device + ")"); 
        Dialogic.dx_playtone(this, tn, tpt, Dialogic.EV_ASYNC); 
    } 
     
    /** Record smth */ 
    public synchronized void record(IOTT iott, TPT tpt, int mode) { 
        if (iott == null || tpt == null) 
            throw new RuntimeException("Bad parameter value"); 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Voice record (" + device + ")"); 
        Dialogic.dx_rec(this, iott, tpt, mode|Dialogic.EV_ASYNC); 
        this.iott = iott; 
    } 
     
    /** Play smth maybe wav */ 
    public synchronized void playiottdata(IOTT iott, TPT tpt, XPB xpb, int mode) { 
        if (iott == null || tpt == null || xpb == null) 
            throw new RuntimeException("Bad parameter value"); 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "IOTTdata play (" + device + ")"); 
        Dialogic.dx_playiottdata(this, iott, tpt, xpb, mode|Dialogic.EV_ASYNC); 
        this.iott = iott; 
        this.xpb = xpb; 
    } 
     
    /** Record smth maybe wav */ 
    public synchronized void recordiottdata(IOTT iott, TPT tpt, XPB xpb, int mode) { 
        if (iott == null || tpt == null || xpb == null) 
            throw new RuntimeException("Bad parameter value"); 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "IOTTdata record (" + device + ")"); 
        Dialogic.dx_reciottdata(this, iott, tpt, xpb, mode|Dialogic.EV_ASYNC); 
        this.iott = iott; 
        this.xpb = xpb; 
    } 
 
    /** Record smth maybe wav from 2 sources*/ 
    public synchronized void recordiottdata(IOTT iott, TPT tpt, XPB xpb, int mode, int ts1, int ts2) { 
        if (iott == null || tpt == null || xpb == null) 
            throw new RuntimeException("Bad parameter value"); 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "IOTTdata record 2 (" + device + ")"); 
        Dialogic.dx_mreciottdata(this, iott, tpt, xpb, mode|Dialogic.EV_ASYNC, ts1, ts2); 
        this.iott = iott; 
        this.xpb = xpb; 
    } 
 
    /** Get last transfer count (# of bytes played/recorded) */ 
    public synchronized int trcount() { 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Get transfer count()"); 
        return Dialogic.ATDX_TRCOUNT(device); 
    } 
 
    /** Set Xfer size for UIO */ 
    public synchronized void setBufSize(int size) { 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Set buffer size (" + device + "," + size + ")"); 
        Dialogic.dx_setparm(device,Dialogic.DXCH_XFERBUFSIZE, size); 
    } 
     
    /** Read Xfer size */ 
    public synchronized int getBufSize() { 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Get buffer size ()"); 
        return Dialogic.dx_getparm(device,Dialogic.DXCH_XFERBUFSIZE); 
    } 
 
    /** Set ANI (analog caller-ID) enabling */ 
    public synchronized void setCallerIdEnabled(boolean enable) { 
        int param = enable ? Dialogic.DX_CALLIDENABLE : Dialogic.DX_CALLIDDISABLE; 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "enable CallerId (" + device + "," + enable + ")"); 
        Dialogic.dx_setparm(device, Dialogic.DXCH_CALLID, param); 
    } 
     
    /** Read # of digits in queue */ 
    public synchronized int digits() { 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Get buffered digits()"); 
        return Dialogic.ATDX_BUFDIGS(device); 
    } 
 
    /** Get a digit from channel */ 
    public synchronized String getdig(TPT tpt) { 
		if (tpt == null) 
			throw new RuntimeException("Bad parameter value"); 
        byte buf[] = new byte[64]; // Should be >= 2 * (DG_MAXDIGS+1) = 64 
        EVT evt; 
        try { 
            channel.beginService(); 
            waitIdle(); 
            if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
                System.out.println(new java.util.Date().toString().substring(11,20) + 
                    "Voice getdig (" + device + ")"); 
            Dialogic.dx_getdig(this, tpt, Dialogic.EV_ASYNC); 
            do { 
                    evt = channel.serviceWaitEvent(); 
            } while (evt.type != EVT.TDX_GETDIG); 
 
            int i = Dialogic.dx_getdig(this, buf); 
            // returns number of digits 
            if (i < 1) 
                return ""; 
            else 
                return new String(buf, 0, i); 
        } finally { 
            channel.endService(); 
        } 
    } 
     
    protected int callpStatus() { 
        int result =  Dialogic.ATDX_CPTERM(device); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Voice CPTERM (" + device + "): " + result); 
        return result; 
    } 
     
    /** Clear "memory" of voice resource when clearing channel */ 
    public synchronized void clear() { 
        cleardig(); 
        digitEvents(false); 
    } 
     
    /** Clear digit buffer */ 
    public synchronized void cleardig() { 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Voice cleardig (" + device + ")"); 
        Dialogic.dx_clrdigbuf(device); 
    } 
     
    /** Enable digit events */ 
    public synchronized void digitEvents(boolean doEvents) { 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Voice digitEvents (" + device + "," + doEvents + ")"); 
        if (doEvents) 
            Dialogic.dx_setevtmsk(device, Dialogic.DM_DIGITS); 
        else  
            Dialogic.dx_setevtmsk(device, Dialogic.DM_DIGOFF); 
    } 
     
    /** Get ANI (analog caller-ID) from channel */ 
    public synchronized String getAni() { 
        byte buf[] = new byte[81];  // Should be able to get away with 21... 
 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Voice getAni (" + device + ")"); 
        buf[0] = 0; 
        int len = Dialogic.dx_gtcallid(device, buf); 
        // figure out what we got 
        if (len < 0) { 
            // Map Caller-ID errors back to strings 
            switch (-len) { 
            case Dialogic.EDX_CLIDINFO:  // Info/sub-msg not available 
                return ""; 
 
            case Dialogic.EDX_CLIDBLK:   // Private / blocked 
                return "P"; 
 
            case Dialogic.EDX_CLIDOOA:   // Out of area 
                return "O"; 
 
            case Dialogic.EDX_CLIDPUB:   // Public phone 
                return "C"; 
 
            case Dialogic.EDX_CLIDPLAN:  // Unknown plan 
                return "S"; 
 
            default: 
                return ""; 
            } 
        } else { 
            // Return a string 
            return new String(buf, 0, len); 
        } 
    } 
 
    /** Get ANI details from channel */ 
    public synchronized String getCallerIdExtended(int infoType) { 
 
        if (infoType == Dialogic.CLIDINFO_FRAMETYPE) { 
            throw new IllegalArgumentException("Use getCallerIdFrameType"); 
        } 
 
        byte buf[] = new byte[259];  // Dialogic specifies max buffer is 258 data bytes. 
 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Voice getCallerIdExtended (" + device + "," + infoType + ")"); 
        buf[0] = 0; 
        int len = Dialogic.dx_gtextcallid(device, infoType, buf); 
        // figure out what we got 
        if (len < 0) { 
            if (len == -Dialogic.EDX_CLIDINFO) {  // Info/sub-msg not available 
                return ""; 
            } 
            if (infoType == Dialogic.CLIDINFO_CALLID) { 
                // Map Caller-ID errors back to strings 
                switch (-len) { 
                case Dialogic.EDX_CLIDBLK:   // Private / blocked 
                    return "P"; 
 
                case Dialogic.EDX_CLIDOOA:   // Out of area 
                    return "O"; 
 
                case Dialogic.EDX_CLIDPUB:   // Public phone 
                    return "C"; 
 
                case Dialogic.EDX_CLIDPLAN:  // Unknown plan 
                    return "S"; 
                } 
            } 
            throw new RuntimeException("getCallerIdExtended(" + infoType + ") returned " + -len + " for " + this); 
        } else { 
            // Return a string 
            return new String(buf, 0, len); 
        } 
    } 
     
    /** Get caller-ID frame type */ 
    public synchronized int getCallerIdFrameType() { 
        byte buf[] = new byte[259]; 
 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Voice getCallerIdFrameType (" + device + ")"); 
        buf[0] = 0; 
        int len = Dialogic.dx_gtextcallid(device, Dialogic.CLIDINFO_FRAMETYPE, buf); 
        if (len == 1) { 
            return ((int) buf[0]) & 0x0FF;   // Force unsigned conversion to integer. 
        } else { 
            throw new RuntimeException("getCallerIdFrameType returned len=" + len + " for " + this); 
        } 
    } 
 
    /** Enable perfect call */ 
    public synchronized void initPerfectCall() { 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Init perfect call (" + device + ")"); 
        Dialogic.dx_initcallp(device); 
    } 
     
    public void dial(String number, DXCAP cap) { 
    	dial(number, cap, false); 
    } 
     
    public void dial(String number, DXCAP cap, boolean perfect) { 
 
        waitIdle(); 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "Voice dial (" + device + ")"); 
         
        int linest = Dialogic.ATDX_LINEST(device); 
        if ((linest & Dialogic.RLS_HOOK) != 0) { 
            channel.beginService(); 
            try { 
                Dialogic.dx_sethook(device, Dialogic.DX_OFFHOOK, Dialogic.EV_ASYNC); 
                channel.serviceWaitEvent(); 
            } finally { 
                channel.endService(); 
            } 
        } 
         
        int ret = Dialogic.dx_dial(device, number, cap, (perfect?Dialogic.DX_CALLP:0)|Dialogic.EV_ASYNC); 
    } 
 
    // Make a single GTD tone 
    int GTDid = 1; 
    public synchronized int buildStGTD(int freq, int dev) { 
        waitIdle(); 
        synchronized(toneLock) { 
            Dialogic.dx_bldst(GTDid, freq, dev,Dialogic.TN_LEADING); 
            int ok = Dialogic.dx_addtone(device, 0, 0); 
            if (ok != 0) 
                    throw new RuntimeException("Addtone failed for " + this); 
            Dialogic.dx_distone(device, GTDid, Dialogic.DM_TONEON|Dialogic.DM_TONEOFF); 
        } 
        return GTDid++; 
    } 
     
    // Make a dual GTD tone 
    public synchronized int buildDtGTD(int freq1, int freq2, int dev) { 
        waitIdle(); 
        synchronized(toneLock) { 
            Dialogic.dx_blddt(GTDid, freq1, dev, freq2, dev, Dialogic.TN_LEADING); 
            int ok = Dialogic.dx_addtone(device, 0, 0); 
            if (ok != 0) 
                    throw new RuntimeException("Addtone failed for " + this); 
            Dialogic.dx_distone(device, GTDid, Dialogic.DM_TONEON|Dialogic.DM_TONEOFF); 
        } 
        return GTDid++; 
    } 
     
    // enable/disable GTD tones 
    public synchronized void setGTD(int id, boolean toneOn, boolean toneOff) { 
        waitIdle(); 
        int mask = 0; 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
                "GTD " + id + " (" + device + ") " + (toneOn ? "On/":"Off/") + (toneOff ? "On":"Off")); 
        if (toneOn) mask |= Dialogic.DM_TONEON; 
        if (toneOff) mask |= Dialogic.DM_TONEOFF; 
        if ((Dialogic.dx_distone(device, id,  
                (Dialogic.DM_TONEON|Dialogic.DM_TONEOFF) & ~mask) != 0) || 
            (Dialogic.dx_enbtone(device, id, mask) != 0)) 
            throw new RuntimeException("setGTD failed for " + this);             
    } 
     
    // stop channel 
    public synchronized void stop() { 
        try { 
            channel.beginService(); 
            while (Dialogic.ATDX_STATE(device) != Dialogic.CS_IDLE) { 
                if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
                    System.out.println(new java.util.Date().toString().substring(11,20) + 
                    "Voice stop (" + device + ")"); 
                Dialogic.dx_stopch(device, Dialogic.EV_ASYNC); 
                channel.serviceWaitEvent(200); 
            } 
            channel.flush(); 
        } finally { 
            channel.endService(); 
        } 
    } 
     
    // SC routing fns 
    public int getTs() { 
        return Dialogic.dx_getxmitslot(device); 
    } 
     
    public void listen(Device source) { 
        if (source != null && source != this) 
            Dialogic.dx_listen(device, source.getTs()); 
        else 
            Dialogic.dx_unlisten(device); 
    } 
 
     public void listen(Channel ch, Resource res) { 
        int ts = res.getTs(ch); 
        if (ts < 0) 
            Dialogic.dx_unlisten(device); 
        else  
            Dialogic.dx_listen(device, ts); 
    } 
 
 
    // R2 utility  
    /* 
     *  Group I Forward Signals 
     */ 
    public static final int   SIGI_ZERO=100; 
    public static final int   SIGI_1   =101; 
    public static final int   SIGI_2   =102; 
    public static final int   SIGI_3   =103; 
    public static final int   SIGI_4   =104; 
    public static final int   SIGI_5   =105; 
    public static final int   SIGI_6   =106; 
    public static final int   SIGI_7   =107; 
    public static final int   SIGI_8   =108; 
    public static final int   SIGI_9   =109; 
    public static final int   SIGI_10  =110; 
    public static final int   SIGI_11  =111; 
    public static final int   SIGI_12  =112; 
    public static final int   SIGI_13  =113; 
    public static final int   SIGI_14  =114; 
    public static final int   SIGI_15  =115; 
/* 
 *  Group II Forward Signals 
 */ 
    public static final int   SIGII_ZERO=100; 
    public static final int   SIGII_1   =101; 
    public static final int   SIGII_2   =102; 
    public static final int   SIGII_3   =103; 
    public static final int   SIGII_4   =104; 
    public static final int   SIGII_5   =105; 
    public static final int   SIGII_6   =106; 
    public static final int   SIGII_7   =107; 
    public static final int   SIGII_8   =108; 
    public static final int   SIGII_9   =109; 
    public static final int   SIGII_10  =110; 
    public static final int   SIGII_11  =111; 
    public static final int   SIGII_12  =112; 
    public static final int   SIGII_13  =113; 
    public static final int   SIGII_14  =114; 
    public static final int   SIGII_15  =115; 
/* 
 *  Group A Backward Signals 
 */ 
    public static final int   SIGA_ZERO=115; 
    public static final int   SIGA_1   =116; 
    public static final int   SIGA_2   =117; 
    public static final int   SIGA_3   =118; 
    public static final int   SIGA_4   =119; 
    public static final int   SIGA_5   =120; 
    public static final int   SIGA_6   =121; 
    public static final int   SIGA_7   =122; 
    public static final int   SIGA_8   =123; 
    public static final int   SIGA_9   =124; 
    public static final int   SIGA_10  =125; 
    public static final int   SIGA_11  =126; 
    public static final int   SIGA_12  =127; 
    public static final int   SIGA_13  =128; 
    public static final int   SIGA_14  =129; 
    public static final int   SIGA_15  =130; 
/* 
 *  Group B Backward Signals 
 */ 
    public static final int   SIGB_ZERO=115; 
    public static final int   SIGB_1   =116; 
    public static final int   SIGB_2   =117; 
    public static final int   SIGB_3   =118; 
    public static final int   SIGB_4   =119; 
    public static final int   SIGB_5   =120; 
    public static final int   SIGB_6   =121; 
    public static final int   SIGB_7   =122; 
    public static final int   SIGB_8   =123; 
    public static final int   SIGB_9   =124; 
    public static final int   SIGB_10  =125; 
    public static final int   SIGB_11  =126; 
    public static final int   SIGB_12  =127; 
    public static final int   SIGB_13  =128; 
    public static final int   SIGB_14  =129; 
    public static final int   SIGB_15  =130; 
     
    private boolean r2Tones = false; 
    static final int r2fdev = 30; 
    static final int r2ampl = -10; 
    static final int[][] forwardSig = { {1380,1500}, {1380,1620}, {1500,1620},  
                                        {1380,1740}, {1500,1740}, {1620,1740},  
                                        {1380,1860}, {1500,1860}, {1620,1860},  
                                        {1740,1860}, {1380,1980}, {1500,1980},  
                                        {1620,1980}, {1740,1980}, {1860,1980} }; 
    static final int[][] backwardSig = { {1140,1020}, {1140,900}, {1020,900},  
                                        {1140, 780}, {1020,780}, {900, 780},  
                                        {1140, 660}, {1020,660}, {900, 660},  
                                        {780,  660}, {1140,540}, {1020,540},  
                                        {900,  540}, {780, 540}, {660, 540} }; 
    static final TNGEN[] backwardTone = new TNGEN[15]; 
    static final TNGEN[] forwardTone = new TNGEN[15]; 
    static final TPT[] forwardStop = new TPT[15]; 
    static final TPT backwardStop = new TPT(); 
    static final TPT impulseStop = new TPT(); 
     
    public synchronized void r2_creasig() { 
        waitIdle(); 
        if (r2Tones)  
            return; 
        if (backwardTone[0] == null) { 
            for (int id = 0; id < 15; id++) { 
                backwardTone[id] = new TNGEN(backwardSig[id][0], r2ampl,  
                                            backwardSig[id][1], r2ampl, 1500); 
                forwardTone[id] = new TNGEN(forwardSig[id][0], r2ampl,  
                                            forwardSig[id][1], r2ampl, 1500); 
                forwardStop[id] = new TPT(TPT.TONE, SIGI_1+id,  
                                            TPT.EDGE|TPT.USE|TPT.CLRBEG, TPT.TONEOFF); 
                // Dialogic does not support 15 tones in TPT ???? 
                if (id < 10) 
                backwardStop.add(TPT.TONE, SIGA_1+id,  
                                    TPT.EDGE|TPT.USE|TPT.CLRBEG, TPT.TONEON); 
            } 
        } 
        synchronized(toneLock) { 
            for (int id = 0; id < 15; id++) { 
                Dialogic.dx_blddt(SIGI_1+id, forwardSig[id][0], r2fdev, 
                                  forwardSig[id][1], r2fdev,Dialogic.TN_LEADING); 
                int ok = Dialogic.dx_addtone(device, 0, 0); 
                if (ok != 0) 
                    throw new RuntimeException("Addtone failed for " + this); 
                Dialogic.dx_distone(device, SIGI_1+id, Dialogic.DM_TONEON|Dialogic.DM_TONEOFF); 
            } 
            for (int id = 0; id < 15; id++) { 
                Dialogic.dx_blddt(SIGA_1+id, backwardSig[id][0], r2fdev, 
                                  backwardSig[id][1], r2fdev,Dialogic.TN_LEADING); 
                int ok = Dialogic.dx_addtone(device, 0, 0); 
                if (ok != 0) 
                    throw new RuntimeException("Addtone failed for " + this); 
                Dialogic.dx_distone(device, SIGA_1+id, Dialogic.DM_TONEON|Dialogic.DM_TONEOFF); 
            } 
        } 
        r2Tones = true; 
    } 
     
    // Enable forward tones 
    public void r2_fenable() { 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
            "R2 forward enable (" + device + ")"); 
        if (!r2Tones)  
            r2_creasig(); 
        for (int id = 0; id < 15; id++) 
            Dialogic.dx_enbtone(device, SIGI_1+id, Dialogic.DM_TONEON|Dialogic.DM_TONEOFF); 
    } 
    // Disable forward tones 
    public void r2_fdisable() { 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
            "R2 forward disable (" + device + ")"); 
        if (!r2Tones)  
            r2_creasig(); 
        else 
            for (int id = 0; id < 15; id++) 
                Dialogic.dx_distone(device, SIGI_1+id, Dialogic.DM_TONEON|Dialogic.DM_TONEOFF); 
    } 
    // Enable backward tones 
    public void r2_benable() { 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
            "R2 backward enable (" + device + ")"); 
        if (!r2Tones)  
            r2_creasig(); 
        for (int id = 0; id < 15; id++) 
            Dialogic.dx_enbtone(device, SIGA_1+id, Dialogic.DM_TONEON|Dialogic.DM_TONEOFF); 
    } 
    // Disable backward tones 
    public void r2_bdisable() { 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
            "R2 backward disable (" + device + ")"); 
        if (!r2Tones)  
            r2_creasig(); 
        else 
            for (int id = 0; id < 15; id++) 
                Dialogic.dx_distone(device, SIGA_1+id, Dialogic.DM_TONEON|Dialogic.DM_TONEOFF); 
    } 
    TNGEN tn; 
     
    // send a forward tone 
    public synchronized void r2_sendf(int sig) { 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
            "R2 sendf " + sigName(sig) + " (" + device + ")"); 
        if (sig < SIGI_1 || sig > SIGI_15) 
            throw new RuntimeException("r2_sendf: invalid R2 sig"); 
        int id = sig - SIGI_1; 
        waitIdle(); 
        Dialogic.dx_playtone(this, forwardTone[id],  
                            backwardStop, Dialogic.EV_ASYNC); 
    } 
 
    // send a backward tone 
    public synchronized void r2_sendb(int sig, int sigp) { 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
            "R2 sendb " + sigName(sig) + " (" + device + ")"); 
        if (sig < SIGA_1 || sig > SIGA_15) 
            throw new RuntimeException("r2_sendb: invalid R2 sig"); 
        if (sigp < SIGI_1 || sigp > SIGI_15) 
            throw new RuntimeException("r2_sendb: invalid R2 sig present"); 
        int id = sig - SIGA_1; 
        int idp = sigp - SIGI_1; 
        waitIdle(); 
        Dialogic.dx_playtone(this, backwardTone[id],  
                            forwardStop[idp], Dialogic.EV_ASYNC); 
    } 
     
    // send a backward impulsive tone 
    public synchronized void r2_sendbp(int sig) { 
        if ((Dialogic.debug & Dialogic.DEBUG_VFNS) != 0) 
            System.out.println(new java.util.Date().toString().substring(11,20) + 
            "R2 sendbp " + sigName(sig) + " (" + device + ")"); 
        if (sig < SIGA_1 || sig > SIGA_15) 
            throw new RuntimeException("r2_sendbp: invalid R2 sig"); 
        int id = sig - SIGA_1; 
        waitIdle(); 
        Dialogic.dx_playtone(this, backwardTone[id],  
                            impulseStop, Dialogic.EV_ASYNC); 
    } 
     
    // Util to print signals for debug 
    static String sigNames[] = { 
    "Fwd_1",    "Fwd_2",    "Fwd_3",    "Fwd_4", 
    "Fwd_5",    "Fwd_6",    "Fwd_7",    "Fwd_8", 
    "Fwd_9",    "Fwd_10",    "Fwd_11",    "Fwd_12", 
    "Fwd_13",    "Fwd_14",    "Fwd_15", 
    "Bwd_1",    "Bwd_2",    "Bwd_3",    "Bwd_4", 
    "Bwd_5",    "Bwd_6",    "Bwd_7",    "Bwd_8", 
    "Bwd_9",    "Bwd_10",    "Bwd_11",    "Bwd_12", 
    "Bwd_13",    "Bwd_14",    "Bwd_15"}; 
         
    private String sigName(int sig) { 
        if (sig < 101 || sig > 130) 
            return "Invalid SIG"; 
        else 
            return sigNames[sig-101]; 
    } 
 
 
    // IOTT/TPT/digbuf tables... 
    // We keep a block to keep it in scope for the length of the play()/rec() 
    // that should be freed... 
    public void finalize() throws Throwable { 
        close(); 
        super.finalize(); 
    } 
}