• Main Page
  • Related Pages
  • Packages
  • Classes
  • Files
  • File List

protocol/CallContext.java

Go to the documentation of this file.
00001 
00002 package protocol;
00003 
00004 import java.io.IOException;
00005 
00006 import utils.Log;
00007 import utils.OctetBuffer;
00008 
00009 import audio.AudioInterface;
00010 
00011 /**
00012  *  CallContext deals with all the packets that are part of a specific call.
00013  *
00014  *  The thing to remember is that a <em>received</em> message contains fields 
00015  *  with the <em>senders</em> viewpoint so <em>source</em> is the far end and 
00016  *  <em>dest</em> is us. in the reply the oposite is true: <em>source</em> 
00017  *  is us and <em>dest</em> is them.
00018  *  
00019  *  @author Mikica B Kocic
00020  */
00021 public class CallContext 
00022 {
00023     /** Represents the Source Call Number in the PDU header */
00024     private int sourceCallNumber = 1;
00025     
00026     /** Represents the Destination Call Number in the PDU header */
00027     private int destinationCallNumber = 0;
00028 
00029     /** The outbound stream sequence number */
00030     private int outSeqNo = 0;
00031 
00032     /** The inbound stream sequence number */
00033     private int inSeqNo = 0;
00034     
00035     /** The start time-stamp of the call */
00036     private long startTimestamp = 0;
00037 
00038     /** The remote peer; owner of the call */
00039     private RemotePeer remotePeer = null;
00040     
00041     /** The audio interface used to play/record for our voice PDUs */
00042     AudioInterface audioInterface = null;
00043     
00044     /** The flag that indicates that the call is established */
00045     private boolean callEstablished = false;
00046     
00047     /** Used by onReceivedVoicePDU() to stop ringing */
00048     private boolean receivedFirstVoicePDU = false;
00049 
00050     /**
00051      * The outbound constructor for Call. We know nothing except where to send it.
00052      */
00053     public CallContext( RemotePeer remotePeer, AudioInterface audioInterface ) 
00054     {
00055         this.audioInterface = audioInterface;
00056         
00057         synchronized( remotePeer )
00058         {
00059             this.remotePeer = remotePeer;
00060             this.remotePeer.addNewCall( this );
00061         }
00062     }
00063 
00064     /**
00065      *  Generates a new outbound stream sequence number.
00066      */
00067     synchronized public int getOutSeqNoInc ()
00068     {
00069         return ( this.outSeqNo++ ) & 0xFF;
00070     }
00071 
00072     /**
00073      *  Returns the outbound stream sequence number, oSeqno.
00074      */
00075     synchronized public int getOutSeqNo () 
00076     {
00077         return this.outSeqNo;
00078     }
00079 
00080     /**
00081      *  Returns the inbound stream sequence number.
00082      */
00083     public int getInSeqNo ()
00084     {
00085         return this.inSeqNo;
00086     }
00087 
00088     /**
00089      *  Sets the inbound stream sequence number.
00090      */
00091     public void setInSeqNo( int next ) 
00092     {
00093         this.inSeqNo = next % 256;
00094     }
00095 
00096     /**
00097      *  Sends a PDU to our peer.
00098      *
00099      *  @param pdu The PDU (in bytes)
00100      */
00101     public void send( OctetBuffer pdu )
00102     {
00103         if ( this.remotePeer != null ) {
00104             this.remotePeer.send( pdu );
00105         }
00106     }
00107 
00108     /**
00109      *  Returns the timestamp of this call. This is the number of milliseconds 
00110      *  since the call started.
00111      */
00112     public int getTimestamp () 
00113     {
00114         long now = System.currentTimeMillis ();
00115         return (int) ( now - this.startTimestamp );
00116     }
00117 
00118     /**
00119      *  Starts sending our audio interface recording. This method creates a new
00120      *  VoicePduSender object to do that.
00121      */
00122     private void startAudioRecording ()
00123     {
00124         if ( this.audioInterface == null ) {
00125             return;
00126         }
00127 
00128         VoicePDUSender voicePduSender = new VoicePDUSender( this.audioInterface, this );
00129         this.audioInterface.setAudioSender( voicePduSender );
00130         
00131         this.audioInterface.startRecording ();
00132     }
00133 
00134     /**
00135      *  Stops sending audio
00136      */
00137     public void stopAudioRecording ()
00138     {
00139         if ( this.audioInterface == null ) {
00140             return;
00141         }
00142 
00143         this.audioInterface.stopRecording ();
00144     }
00145 
00146     /**
00147      *  Sets if this call is established.
00148      *  This can either be when we receive a ANSWER PDU from our peer
00149      *  to an outbound call, or when we answer an incoming call ourselves.
00150      */
00151     public void setCallEstablished( boolean established )
00152     {
00153         if ( ! this.callEstablished && established )
00154         {
00155             this.audioInterface.stopRinging ();
00156             startAudioRecording ();
00157         }
00158 
00159         this.callEstablished = established;
00160     }
00161 
00162     /**
00163      *  Returns if this call has been callAnswered.
00164      */
00165     public boolean isEstablished ()
00166     {
00167         return this.callEstablished;
00168     }
00169 
00170     /**
00171      * Writes audio data to the speaker.
00172      *
00173      * @param bs The incoming audio payload
00174      * @param timestamp The time-stamp
00175      * @exception IOException Description of Exception
00176      */
00177     public void audioWrite( byte[] bs, long timestamp ) throws IOException 
00178     {
00179         if ( this.audioInterface != null )
00180         {
00181             this.audioInterface.writeBuffered( bs, timestamp );
00182         }
00183     }
00184 
00185     /**
00186      *  Notifies us that a Voice PDU has been received.
00187      */
00188     public void onReceivedVoicePDU( long timestamp, byte[] audioSample )
00189     {
00190         if ( ( this.audioInterface != null ) && ( ! this.receivedFirstVoicePDU ) )
00191         {
00192             /* Stop ringing audio interface
00193              */
00194             this.receivedFirstVoicePDU = true;
00195             this.audioInterface.stopRinging ();
00196         }
00197 
00198         /* write samples to audio interface 
00199          */
00200         try {
00201             audioWrite( audioSample, timestamp );
00202         } catch( IOException e ) {
00203             Log.exception( Log.WARN, e );
00204         }
00205     }
00206 
00207     /**
00208      *  Sets the local call number as a character.
00209      */
00210     public void setSourceCallNumber( int callNo )
00211     {
00212         this.sourceCallNumber = callNo;
00213     }
00214 
00215     /**
00216      *  Returns the local call number. Together with the remote call
00217      *  number, they uniquely identify the call between two parties.
00218      *
00219      *  On an outgoing call this represents 'Source Call Number', and
00220      *  on an incoming call this represents 'Destination Call Number'.
00221      */
00222     public int getSourceCallNumber ()
00223     {
00224         return this.sourceCallNumber & 0x7FFF;
00225     }
00226 
00227     /**
00228      *  Sets the remote call number as a character. This bit of information comes 
00229      *  in with received accept call.
00230      */
00231     public void setDestinationCallNumber( int callNo )
00232     {
00233         this.destinationCallNumber = callNo;
00234     }
00235 
00236     /**
00237      *  Returns the remote call number. Together with the local call
00238      *  number, they uniquely identify the call between two parties.
00239      *
00240      *  On an outgoing call this represents 'Destination Call Number', and
00241      *  on an inbound call this represents 'Source Call Number'.
00242      */
00243     public int getDestinationCallNumber ()
00244     {
00245         return this.destinationCallNumber & 0x7FFF;
00246     }
00247 
00248     /**
00249      *  Resets the clock. This method sets the start timestamp of a new call.
00250      */
00251     public void resetClock ()
00252     {
00253         this.startTimestamp = System.currentTimeMillis ();
00254     }
00255 
00256     /**
00257      *  Returns the start time-stamp of the call.
00258      */
00259     public long getStartTimestamp () 
00260     {
00261         return this.startTimestamp;
00262     }
00263 
00264     /**
00265      *  Passed a newly arrived PDU. If the PDU is the next one we
00266      *  are expecting, then put it in the buffer and adjust our
00267      *  expectations. Return it, so it can be acted upon. If it isn't
00268      *  the next expected then ignore it and return null (Warn).
00269      */
00270     public synchronized ProtocolDataUnit addIn( ProtocolDataUnit pdu )
00271     {
00272         ProtocolDataUnit ret = null;
00273         int where = pdu.outSeqNo;
00274         int expected = this.getInSeqNo ();
00275         if ( expected == where ) {
00276             setInSeqNo( ++where );
00277             ret = pdu;
00278         }
00279         return ret;
00280     }
00281 
00282     /**
00283      *  Cleans up and detaches call from peer
00284      */
00285     public void cleanUp ()
00286     {
00287         if ( this.audioInterface != null ) 
00288         {
00289             this.audioInterface.setAudioSender( null );
00290             this.audioInterface.stopPlay ();
00291             this.audioInterface.stopRecording ();
00292         }
00293         
00294         this.remotePeer = null;
00295     }
00296 
00297     /**
00298      * Returns the audio interface sample size (used to determine size of the VoicePDU).
00299      */
00300     public int getAudioSampleSize () 
00301     {
00302         if ( this.audioInterface != null ) {
00303             return this.audioInterface.getSampleSize ();
00304         }
00305         return 0;
00306     }
00307 }

Generated on Thu Dec 16 2010 14:44:42 for VoIP Kryptofon by  doxygen 1.7.2