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 }