/***************************************************************************** * Copyright (c) 2006, 2007 g-Eclipse Consortium * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Initial development of the original code was made for the * g-Eclipse project founded by European Union * project number: FP6-IST-034327 http://www.geclipse.eu/ * * Contributors: * Thomas Koeckerbauer GUP, JKU - initial API and implementation *****************************************************************************/ package eu.geclipse.gvid.internal; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.eclipse.core.runtime.IStatus; import eu.geclipse.gvid.Activator; import eu.geclipse.gvid.IConnection; /** * Connection class implementing a stream buffer. */ public class Connection implements IConnection { private final static int READ_BUFFER_SIZE = 2 * 1024 * 1024; private long bytesReceived, bytesSent, oldBytesReceived, oldBytesSent; private long sendSpeed, recvSpeed; private long lastSendMeasureTime, lastRecvMeasureTime; private byte[] readBuffer; private int readBufferDataStart = 0, bytesInBuffer; private InputStream inputStream; private OutputStream outputStream; /** * Creates a new buffering connection instance. * @param in stream to read the input (video) from. * @param out stream to write the output (events) to. */ public Connection( final InputStream in, final OutputStream out ) { this.inputStream = in; this.outputStream = out; this.bytesReceived = 0; this.bytesSent = 0; this.oldBytesReceived = 0; this.oldBytesSent = 0; this.sendSpeed = 0; this.recvSpeed = 0; this.lastSendMeasureTime = System.currentTimeMillis(); this.lastRecvMeasureTime = System.currentTimeMillis(); this.readBuffer = new byte[ READ_BUFFER_SIZE ]; this.readBufferDataStart = 0; this.bytesInBuffer = 0; } /** * @brief Writes data to the connection. * @param data pointer to the data. * @param len length of data in bytes. * @return number of bytes successfully written. * @throws IOException if an I/O error occurs. */ public int writeData( final byte[] data, final int len ) throws IOException { this.outputStream.write( data, 0, len ); this.bytesSent += len; return len; } /* (non-Javadoc) * @see eu.geclipse.gvid.internal.IConnection#fillBuffer(boolean) */ public void fillBuffer( final boolean blocking ) throws IOException { if( this.readBufferDataStart > READ_BUFFER_SIZE / 2 ) { System.arraycopy( this.readBuffer, this.readBufferDataStart, this.readBuffer, 0, this.bytesInBuffer ); this.readBufferDataStart = 0; } if( this.bytesInBuffer < READ_BUFFER_SIZE ) { if( blocking || this.inputStream.available() > 0 ) { int readResult = this.inputStream.read( this.readBuffer, this.readBufferDataStart + this.bytesInBuffer, READ_BUFFER_SIZE - this.bytesInBuffer - this.readBufferDataStart ); if( readResult < 0 ) { throw new IOException( Messages.getString("Connection.readFailed") ); //$NON-NLS-1$ } this.bytesReceived += readResult; this.bytesInBuffer += readResult; } } } /* (non-Javadoc) * @see eu.geclipse.gvid.internal.IConnection#getNumBytesInBuffer() */ public int getNumBytesInBuffer() throws IOException { fillBuffer( false ); return this.bytesInBuffer; } /* (non-Javadoc) * @see eu.geclipse.gvid.internal.IConnection#dropBytes(int) */ public void dropBytes( final int amount ) throws IOException { int realAmount = amount; if( amount > this.bytesInBuffer ) { Activator.logMessage( IStatus.ERROR, Messages.formatMessage( "Connection.amountGreaterBufferContents", //$NON-NLS-1$ Integer.valueOf( amount ), Integer.valueOf( this.bytesInBuffer ) ) ); realAmount = this.bytesInBuffer; } this.bytesInBuffer -= realAmount; this.readBufferDataStart += realAmount; fillBuffer( false ); } /* (non-Javadoc) * @see eu.geclipse.gvid.internal.IConnection#getDataStart() */ public int getDataStart() { return this.readBufferDataStart; } /* (non-Javadoc) * @see eu.geclipse.gvid.internal.IConnection#getDataBuffer() */ public byte[] getDataBuffer() { return this.readBuffer; } /** @see java.io.OutputStream#flush() */ public void flush() { try { this.outputStream.flush(); } catch( IOException ioException ) { Activator.logException( ioException ); } } /* (non-Javadoc) * @see eu.geclipse.gvid.internal.IConnection#readData(byte[], int) */ public int readData( final byte[] data, final int maxLen ) throws IOException { return readData( data, maxLen, 0 ); } /* (non-Javadoc) * @see eu.geclipse.gvid.internal.IConnection#readData(byte[], int, int) */ public int readData( final byte[] data, final int maxLen, final int startPos ) throws IOException { fillBuffer( this.bytesInBuffer == 0 ); int amount = maxLen; if( this.bytesInBuffer < amount ) amount = this.bytesInBuffer; System.arraycopy( this.readBuffer, this.readBufferDataStart, data, startPos, amount ); dropBytes( amount ); return amount; } /* (non-Javadoc) * @see eu.geclipse.gvid.internal.IConnection#getCurrentSendSpeed() */ public long getCurrentSendSpeed() { long currentTime; long timeDiff; currentTime = System.currentTimeMillis(); timeDiff = currentTime - this.lastSendMeasureTime; if( timeDiff > 1000 ) { this.lastSendMeasureTime = currentTime; this.sendSpeed = ( ( this.bytesSent - this.oldBytesSent ) * 1000 ) / timeDiff; this.oldBytesSent = this.bytesSent; } return this.sendSpeed; } /* (non-Javadoc) * @see eu.geclipse.gvid.internal.IConnection#getCurrentRecvSpeed() */ public long getCurrentRecvSpeed() { long currentTime; long timeDiff; currentTime = System.currentTimeMillis(); timeDiff = currentTime - this.lastRecvMeasureTime; if( timeDiff > 1000 ) { this.lastRecvMeasureTime = currentTime; this.recvSpeed = ( ( this.bytesReceived - this.oldBytesReceived ) * 1000 ) / timeDiff; this.oldBytesReceived = this.bytesReceived; } return this.recvSpeed; } /* (non-Javadoc) * @see eu.geclipse.gvid.internal.IConnection#readByte() */ public byte readByte() throws IOException { byte[] b = new byte[ 1 ]; readData( b, 1 ); return b[ 0 ]; } /* (non-Javadoc) * @see eu.geclipse.gvid.internal.IConnection#readUint16() */ public short readUint16() throws IOException { short val = 0; val = ( short )( 0x000000FF & readByte() ); val <<= 8; val += ( 0x000000FF & readByte() ); return val; } /* (non-Javadoc) * @see eu.geclipse.gvid.internal.IConnection#readUint32() */ public int readUint32() throws IOException { int val = 0; val = ( 0x000000FF & readByte() ); val <<= 8; val += ( 0x000000FF & readByte() ); val <<= 8; val += ( 0x000000FF & readByte() ); val <<= 8; val += ( 0x000000FF & readByte() ); return val; } }