net.sf.jack4j
Class RingBuffer

java.lang.Object
  extended by net.sf.jack4j.RingBuffer

public class RingBuffer
extends java.lang.Object

Thread-safe, lock-free ringbuffer.

The ringbuffer can be accessed by two threads simultaneously. One thread can read from the buffer, while the other can write to it. The access to the ringbuffer need not to be synchronized, However, there can be only one reader and one writer thread, and their roles can't be interchanged.

Note on synchronization: the various read/write methods in this class are not synchronized (lack of synchronization is the point of lock-free buffers), but it's developer's responsibility to ensure that there's always only one thread reading, and only one thread writing.

Author:
repa

Constructor Summary
RingBuffer(int size)
          Creates new ringbuffer that can hold specified number of bytes.
RingBuffer(int size, boolean freeWhenFinalized)
          Creates new ringbuffer that can hold specified number of bytes.
RingBuffer(long ringbufferHandle, int capacity, boolean freeWhenFinalized)
          Creates new Java object, using pre-allocated ringbuffer.
 
Method Summary
 java.nio.channels.ReadableByteChannel createReadableByteChannel()
          Creates and returns ReadableByteChannel associated with this RingBuffer.
 RingBufferVector createReadVector(java.nio.ByteOrder byteOrder)
          Creates and returns RingBufferVector that covers readable part of the buffer.
 java.nio.channels.WritableByteChannel createWritableByteChannel()
          Creates and returns WritableByteChannel associated with this RingBuffer.
 RingBufferVector createWriteVector(java.nio.ByteOrder byteOrder)
          Creates and returns RingBufferVector that covers writable part of the buffer.
protected  void finalize()
          Frees the ringbuffer, if it didn't happen before.
 void free()
          Frees the ringbuffer.
 int getCapacity()
          Returns the total capacity of the ringbuffer (in bytes).
 boolean getFreeWhenFinalized()
          Returns true if the native ringbuffer will be freed when this Java object is finalized.
 int getReadSpaceBytes()
          Returns the number of bytes available for reading.
 int getReadSpaceSamples()
          Returns the number of samples available for reading.
 long getRingbufferHandle()
          Returns the native pointer to jack_ringbuffer_t structure.
 int getWriteSpaceBytes()
          Returns the number of bytes available for writing.
 int getWriteSpaceSamples()
          Returns the number of samples available for writing.
 void mlock()
          Attempts to lock the underlying native buffer in memory.
 void readAdvanceBytes(int size)
          Advances read position in the ringbuffer, skipping some readable data.
 void readAdvanceSamples(int size)
          Advances read position in the ringbuffer, skipping some readable data.
 int readBytesToArray(byte[] array, int start, int size)
          Reads data from the ringbuffer and stores them into specified direct buffer, then advances read pointer.
 int readBytesToArray(byte[] array, int start, int size, boolean advance)
          Reads data from the ringbuffer and stores them into specified direct buffer, then optionally advances read pointer.
 int readBytesToBuffer(java.nio.ByteBuffer buffer, int size)
          Reads data from the ringbuffer and stores them into specified direct buffer, then optionally advances read pointer.
 int readBytesToBuffer(java.nio.ByteBuffer buffer, int size, boolean advance)
          Reads data from the ringbuffer and stores them into specified direct buffer, then optionally advances read pointer.
 int readBytesToDirectBuffer(java.nio.ByteBuffer buffer, int size)
          Reads data from the ringbuffer and stores them into specified direct buffer, then advances pointer.
 int readBytesToDirectBuffer(java.nio.ByteBuffer buffer, int size, boolean advance)
          Reads data from the ringbuffer and stores them into specified direct buffer, then optionally advances read pointer.
 int readSamplesToDirectBuffer(java.nio.FloatBuffer buffer, int size)
          Reads data from the ringbuffer and stores them into specified direct buffer, then advances pointer.
 int readSamplesToDirectBuffer(java.nio.FloatBuffer buffer, int size, boolean advance)
          Reads data from the ringbuffer and stores them into specified direct buffer, then optionally advances read pointer.
 void reset()
          Resets (clears) the buffer.
 void setFreeWhenFinalized(boolean freeWhenFinalized)
          Sets the flag that says if the native ringbuffer will be freed when this Java object is finalized.
 void writeAdvanceBytes(int size)
          Advances write position in the ringbuffer, skipping some writable space.
 void writeAdvanceSamples(int size)
          Advances write position in the ringbuffer, skipping some writable space.
 int writeBytesFromArray(byte[] array, int start, int size)
          Writes from the specified array into ringbuffer.
 int writeBytesFromBuffer(java.nio.ByteBuffer buffer, int size)
          Writes from the specified direct buffer into ringbuffer.
 int writeBytesFromDirectBuffer(java.nio.ByteBuffer buffer, int size)
          Writes from the specified direct buffer into ringbuffer.
 int writeSamplesFromDirectBuffer(java.nio.FloatBuffer buffer, int size)
          Writes from the specified direct buffer into ringbuffer.
 
Methods inherited from class java.lang.Object
clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

RingBuffer

public RingBuffer(int size,
                  boolean freeWhenFinalized)
           throws JackException
Creates new ringbuffer that can hold specified number of bytes.

The size is in bytes, not samples!

Parameters:
size - size in bytes
freeWhenFinalized - specifies whether free() should be called during finalization
Throws:
JackException

RingBuffer

public RingBuffer(int size)
           throws JackException
Creates new ringbuffer that can hold specified number of bytes.

Equivalent to RingBuffer(size, true)

Throws:
JackException

RingBuffer

public RingBuffer(long ringbufferHandle,
                  int capacity,
                  boolean freeWhenFinalized)
Creates new Java object, using pre-allocated ringbuffer.

This method is useful when you obtain pointer to jack_ringbuffer_t from another JNI call and want to build the Java object around that native ringbuffer.

Parameters:
ringbufferHandle - pointer to jack_ringbuffer_t, packed as long
capacity - total capacity of the ringbuffer
freeWhenFinalized - specifies whether free() should be called during finalization
Method Detail

finalize

protected void finalize()
                 throws java.lang.Throwable
Frees the ringbuffer, if it didn't happen before.

Overrides:
finalize in class java.lang.Object
Throws:
java.lang.Throwable
See Also:
Object.finalize()

free

public void free()
          throws JackException
Frees the ringbuffer.

This object will be unusable after the call.

This method may be called multiple calls; second and subsequent calls have no effect.

Throws:
JackException

getRingbufferHandle

public long getRingbufferHandle()
Returns the native pointer to jack_ringbuffer_t structure.

The pointer is packed as long value, and can be used in JNI calls.


getCapacity

public int getCapacity()
Returns the total capacity of the ringbuffer (in bytes).


createReadableByteChannel

public java.nio.channels.ReadableByteChannel createReadableByteChannel()
Creates and returns ReadableByteChannel associated with this RingBuffer.

It's recommended (faster) to use only direct buffers with the returned channel.

The channel behaves as a non-blocking channel, that is, read method doesn't block and reads only as many bytes as is available for reading in the associated RingBuffer.

The channel must not be used by multiple threads simultaneously. This also means that the read method of the returned channel doesn't fully conform to ReadableByteChannel specification - if another thread starts reading from the channel during read operation, it won't block and the results are unpredictable.

Closing the channel doesn't affect underlying buffer. If the underlying buffer is freed, the channel's read method will throw exception.


createWritableByteChannel

public java.nio.channels.WritableByteChannel createWritableByteChannel()
Creates and returns WritableByteChannel associated with this RingBuffer.

It's recommended (faster) to use only direct buffers with the returned channel.

The channel behaves as a non-blocking channel, that is, write method doesn't block and writes only as many bytes as is available for writing in the associated RingBuffer.

The channel must not be used by multiple threads simultaneously. This also means that the write method of the returned channel doesn't fully conform to WritableByteChannel specification - if another thread starts writing to the channel during write operation, it won't block and the results are unpredictable.

Closing the channel doesn't affect underlying buffer. If the underlying buffer is freed, the channel's write method will throw exception.


getReadSpaceBytes

public int getReadSpaceBytes()
Returns the number of bytes available for reading.


getReadSpaceSamples

public int getReadSpaceSamples()
Returns the number of samples available for reading.


getWriteSpaceBytes

public int getWriteSpaceBytes()
Returns the number of bytes available for writing.


getWriteSpaceSamples

public int getWriteSpaceSamples()
Returns the number of samples available for writing.


readBytesToDirectBuffer

public int readBytesToDirectBuffer(java.nio.ByteBuffer buffer,
                                   int size,
                                   boolean advance)
Reads data from the ringbuffer and stores them into specified direct buffer, then optionally advances read pointer.

This method behaves exactly as readBytesToBuffer(ByteBuffer, int), but the specified buffer must be a direct buffer, otherwise an exception is thrown.

Returns:
number of bytes actually copied

readBytesToDirectBuffer

public int readBytesToDirectBuffer(java.nio.ByteBuffer buffer,
                                   int size)
Reads data from the ringbuffer and stores them into specified direct buffer, then advances pointer.

This is an equivalent to readBytesToDirectBuffer(buffer, size, true)


readSamplesToDirectBuffer

public int readSamplesToDirectBuffer(java.nio.FloatBuffer buffer,
                                     int size,
                                     boolean advance)
Reads data from the ringbuffer and stores them into specified direct buffer, then optionally advances read pointer.

If the buffer is not direct, the method throws IllegalArgumentException.

The number of samples read is a minimum of: size parameter, return value of buffer.remaining(), and return value of getReadSpaceSamples().

Returns:
number of samples actually copied

readSamplesToDirectBuffer

public int readSamplesToDirectBuffer(java.nio.FloatBuffer buffer,
                                     int size)
Reads data from the ringbuffer and stores them into specified direct buffer, then advances pointer.

This is an equivalent to readSamplesToDirectBuffer(buffer, size, true)


readBytesToBuffer

public int readBytesToBuffer(java.nio.ByteBuffer buffer,
                             int size,
                             boolean advance)
Reads data from the ringbuffer and stores them into specified direct buffer, then optionally advances read pointer.

The number of bytes read is a minimum of: specified size parameter, available space in target buffer, and size of available data in the ringbuffer, as returned by getReadSpaceBytes().

Returns:
number of bytes actually copied

readBytesToBuffer

public int readBytesToBuffer(java.nio.ByteBuffer buffer,
                             int size)
Reads data from the ringbuffer and stores them into specified direct buffer, then optionally advances read pointer.

This is equivalent to readBytesToBuffer(buffer, size, true)


readBytesToArray

public int readBytesToArray(byte[] array,
                            int start,
                            int size,
                            boolean advance)
Reads data from the ringbuffer and stores them into specified direct buffer, then optionally advances read pointer.

The number of bytes read is a minimum of specified size parameter and size of available data in the ringbuffer, as returned by getReadSpaceBytes().

start must be non-negative and not greater than array.length; size must be non-negative and not greater than array.length - start.

Parameters:
array - the array into which will the data be copied
start - index of first element to overwrite
size - number of requested bytes
advance - if set to true, read pointer is advanced after read
Returns:
number of bytes copied
Throws:
JackException - if internal error occurs
java.lang.IndexOutOfBoundsException - if start or size are out of bounds

readBytesToArray

public int readBytesToArray(byte[] array,
                            int start,
                            int size)
Reads data from the ringbuffer and stores them into specified direct buffer, then advances read pointer.

This is equivalent to readBytesToArray(array, start, size, true)


readAdvanceBytes

public void readAdvanceBytes(int size)
Advances read position in the ringbuffer, skipping some readable data.

Parameters:
size - number of bytes to skip

readAdvanceSamples

public void readAdvanceSamples(int size)
Advances read position in the ringbuffer, skipping some readable data.

Parameters:
size - number of samples to skip

createReadVector

public RingBufferVector createReadVector(java.nio.ByteOrder byteOrder)
Creates and returns RingBufferVector that covers readable part of the buffer.

See RingBufferVector description for details.

The use of these vectors in Java is not very efficient.

Parameters:
byteOrder - requested byte order of the ByteBuffers in the returned vector

writeBytesFromDirectBuffer

public int writeBytesFromDirectBuffer(java.nio.ByteBuffer buffer,
                                      int size)
Writes from the specified direct buffer into ringbuffer.

This method behaves exactly as writeBytesFromBuffer(ByteBuffer, int), but the specified buffer must be a direct buffer, otherwise an exception is thrown.

Returns:
number of bytes actually copied

writeSamplesFromDirectBuffer

public int writeSamplesFromDirectBuffer(java.nio.FloatBuffer buffer,
                                        int size)
Writes from the specified direct buffer into ringbuffer.

If the buffer is not direct, the method throws IllegalArgumentException.

The number of bytes written is a minimum of: size parameter, return value of buffer.remaining(), and return value of getWriteSpaceBytes().

Returns:
number of samples actually copied

writeBytesFromBuffer

public int writeBytesFromBuffer(java.nio.ByteBuffer buffer,
                                int size)
Writes from the specified direct buffer into ringbuffer.

The number of bytes written is a minimum of: specified size parameter, number of available bytes in target buffer, and size of available data in the ringbuffer, as returned by getWriteSpaceBytes().

Returns:
number of bytes actually copied

writeBytesFromArray

public int writeBytesFromArray(byte[] array,
                               int start,
                               int size)
Writes from the specified array into ringbuffer.

The number of bytes read is a minimum of specified size parameter and size of available data in the ringbuffer, as returned by getWriteSpaceBytes().

start must be non-negative and not greater than array.length; size must be non-negative and not greater than array.length - start.

Parameters:
array - the array from which will the data be copied
start - index of first element that holds the data
size - requested number of bytes to copy
Returns:
number of bytes copied
Throws:
java.lang.IndexOutOfBoundsException - if start or size are out of bounds

writeAdvanceBytes

public void writeAdvanceBytes(int size)
Advances write position in the ringbuffer, skipping some writable space.

Parameters:
size - number of bytes to skip

writeAdvanceSamples

public void writeAdvanceSamples(int size)
Advances write position in the ringbuffer, skipping some writable space.

Parameters:
size - number of samples to skip

createWriteVector

public RingBufferVector createWriteVector(java.nio.ByteOrder byteOrder)
Creates and returns RingBufferVector that covers writable part of the buffer.

See RingBufferVector description for details.

The use of these vectors in Java is not very efficient.

Parameters:
byteOrder - requested byte order of the ByteBuffers in the returned vector

reset

public void reset()
Resets (clears) the buffer.

This method is not thread-safe.


mlock

public void mlock()
           throws JackException
Attempts to lock the underlying native buffer in memory.

You can call this if you want to use the ringbuffer during real-time callbacks and want to avoid swapping.

Throws:
JackException

getFreeWhenFinalized

public boolean getFreeWhenFinalized()
Returns true if the native ringbuffer will be freed when this Java object is finalized.


setFreeWhenFinalized

public void setFreeWhenFinalized(boolean freeWhenFinalized)
Sets the flag that says if the native ringbuffer will be freed when this Java object is finalized.

Normally, the flag is set to true; setting it to false may be useful if you want to share the ringbuffer with native code that will survive the destruction of this Java object.



Copyright © 2008 Ondrej Par. All Rights Reserved.