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


// local.dialogic.ServiceChannel 
// $Id: ServiceChannel.java,v 1.8 2003/09/16 12:23:38 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; 
 
/** 
  * ServiceChennel: 
  * This is a mess... :-) 
  * Now seriously, this is a way to have a Voice resource wrapped 
  * on channel control logic for use by those pesty ill behaved  
  * resources known as stations... 
  * Starting at 1.11, there's also a version without Voice! 
  * That making sense when a call is made from station to station... 
  * .. in which case we also support multi-binding (2 networks!) 
  * to get disconnect supervision on any party 
  */ 
 
public class ServiceChannel extends Channel { 
    // Constantes 
 
    // Variables 
    Voice voiceDev = null; 
    Device network = null; 
    Device network2 = null; 
    private String mydev; 
    private String myani;   // ANI to be answered by this channel 
    private int linestate;  // An internal linestate for dummy ringback control 
    private static final int INIT = 0; 
    private static final int ACCEPTED = 1; 
    private static final int ANSWERED = 2; 
    private static final int CLEARED = 3; 
     
 
    /** 
     * Create a ServiceChannel wrapper on a given voice device name, with fixed ani 
     */ 
    public ServiceChannel(String voiceName, String ani) { 
        super(); 
        if (voiceName == null) 
            mydev = "NONE"; 
        else 
            mydev = voiceName; 
        myani = ani; 
        if (!mydev.equals("NONE")) 
            voiceDev = new Voice(this, mydev); 
        setState(FREE); 
        linestate =  INIT; 
    } 
     
    /** 
     * Create a ServiceChannel wrapper on a given voice device name 
     */ 
    public ServiceChannel(String voiceName) { 
        this(voiceName, ""); 
    } 
     
    /** 
     * Create a ServiceChannel without resources 
     */ 
    public ServiceChannel() { 
        this("NONE", ""); 
    } 
 
    public void close() 
    { 
        super.clear(); 
        if (voiceDev != null) { 
            voiceDev.close(); 
            voiceDev = null; 
        } 
    } 
     
    public String toString() { 
        return "ServiceChannel on " + mydev  
                    + (myani.equals("") ? "" : " for " + myani) 
                    + ((call == null) ? "" : "(" + call.id() + ")"); 
    } 
     
    public Voice getVoice() { 
        return voiceDev; 
    } 
     
    /** 
     * Bind: bind this service channel to an MSI station 
     *       good up to next clear() or unbind() 
     *       by default, associate to current thread 
     */ 
    public void bind(Station stat) { 
        bind(stat, true); 
    } 
     
    public void bind(Station stat, boolean setGroup) { 
        if (voiceDev == null && network != null) { 
            if ((Dialogic.debug & Dialogic.DEBUG_STATION) != 0) 
                System.out.println(this.toString() + " bind2 to " + stat); 
            network2 = stat; 
        } else { 
            network = (Device)stat; 
            if ((Dialogic.debug & Dialogic.DEBUG_STATION) != 0) 
                System.out.println(this.toString() + " bind to " + stat); 
        } 
        if (setGroup) setGroup(); 
        stat.setServiceChannel(this); 
        setState(OUTGOING); // Not really :-) 
    } 
     
    /** 
     * Unbind: release a binding, reason being call transfer 
     */ 
    public void unbind(Station stat) { 
        if (network == stat || network2 == stat) { 
            if (network == stat)  
                network = network2; 
            network2 = null; 
            stat.setServiceChannel(null); 
        } 
        // Should we do some more checks ? 
    } 
 
    /** 
     * Return our network device 
     * If we are bound, then this is usually a station 
     * if not, answer our voice resource for listen() to hear to it... 
     */ 
    public Device getNetwork() { 
        if (network != null) 
            return network; 
        return voiceDev; 
    } 
 
    /** 
     * Return our network2 device 
     * If we are bound2, then this is usually a station 
     * needed to reconnect from either way of an internall call. 
     */ 
    public Device getNetwork2() { 
        return network2; 
    } 
 
    /** 
     * newCall(dnis) 
     * Associate a new call object for given dnis 
     */ 
    public Call newCall(String dnis) { 
        linestate =  INIT; 
        call = new Call(this); 
        call.dnis = dnis; 
        return call; 
    } 
     
    /** 
     * newCall(dnis, ani) 
     * Associate a new call object for given dnis, and set caller ani 
     */ 
    public Call newCall(String dnis, String ani) { 
        linestate =  INIT; 
        call = new Call(this); 
        call.dnis = dnis; 
        call.ani = ani; 
        return call; 
    } 
      
    /** 
     * Accept: just take note... 
     */ 
    void accept() { 
        linestate =  ACCEPTED; 
        return; 
    } 
     
    /**  
     *  answer()Be easy, some times we want to go on 
     *          for call handlers to work with ServiceChannels 
     */ 
    void answer(int rings) { 
        if (voiceDev != null && (linestate == INIT || linestate == ACCEPTED) && rings > 0) { 
            boolean flip = false; 
            TNGEN t1 = new TNGEN(440, -10, 100); 
            TNGEN t2 = new TNGEN(330, -40, 200); 
            TPT tpt = new TPT(); 
            voiceDev.playtone(t1, tpt); 
            EVT evt; 
            // Ring cycle 
            while(true) { 
                evt = serviceWaitEvent(); 
                if (evt.type == EVT.TDX_PLAYTONE) { 
                    if (rings-- <= 0) 
                        break; 
                    if (flip) 
                        voiceDev.playtone(t1, tpt); 
                    else 
                        voiceDev.playtone(t2, tpt); 
                    flip = !flip; 
                    continue; 
                } else { 
                    voiceDev.stop(); 
                    // offHook ? 
                    break; 
                } 
            } 
        } 
        setState(INCOMING); 
        linestate =  ANSWERED; 
        return; 
    } 
 
    /** 
     * reject(reason): throw a BusyException 
     */ 
    void reject(int reason) { 
        if (voiceDev != null) { 
            TNGEN t1 = new TNGEN(330, -10, 40); 
            TNGEN t2 = new TNGEN(440, -10, 40); 
            TNGEN t3 = new TNGEN(600, -10, 40); 
            TPT tpt = new TPT(); 
            voiceDev.playtone(t1, tpt); 
            voiceDev.playtone(t2, tpt); 
            voiceDev.playtone(t3, tpt); 
            voiceDev.waitIdle(); 
        } 
        setState(OOS); 
        linestate =  CLEARED; 
        throw new BusyException(); 
    } 
     
    void dial(Call call, String number) { 
        throw new ChannelException("dial(): wrong state"); 
    } 
     
    /** 
     * ani(): We have a static ani support 
     */ 
    String ani() { 
        return myani; 
    } 
     
    /** 
     * pulses(): No way to know, return 1 if dialed ? 
     */ 
    int pulses() { 
        return 0; 
    } 
     
    public void clear() { 
        if ((Dialogic.debug & Dialogic.DEBUG_STATION) != 0) 
            System.out.println(this.toString() + " cleared"); 
		linestate =  CLEARED; 
        super.clear(); 
        if (voiceDev != null) { 
            voiceDev.stop(); 
            voiceDev.listen(null); 
            voiceDev.clear(); 
        } 
        // Network is a Station in this version 
        if (network != null) 
            ((Station)network).setServiceChannel(null); 
        network = null; 
        serviceThread = null; 
        group = null; 
        call = null; 
 
        try { 
            Thread.sleep(200); 
        }  
        catch(InterruptedException ie) { 
            Thread.currentThread().interrupt(); 
        } 
        flush(); 
		setState(FREE); 
	    linestate =  INIT; 
   } 
     
    // Our line state service fn 
    protected EVT service(EVT evt) { 
        if ((network != null && network.source(evt)) 
            || (network2 != null && network2.source(evt))) { 
            // my station (or peer) event 
            if (evt.type == EVT.DTEV_SIG  
               && (evt.data & Dialogic.DTC_ABIT) != 0 
               && (evt.data & Dialogic.DTB_ABIT) == 0) { 
                // Station onhook... 
                if (call != null) call.drop(); 
                if (linestate != CLEARED) // Do not interrupt clearing channel 
	                throw new HangUpException(); 
            } else if (evt.type == EVT.DTEV_SIG  
                && (evt.data & Dialogic.DTMM_WINK) != 0) { 
                // Station flash... same as onhook if reached this far 
                if (call != null) call.drop();                                  
				if (linestate != CLEARED) // Do not interrupt clearing channel 
	                throw new HangUpException();  
            } 
        } 
        return evt; 
    } 
}