/* * Copyright (C) 2011 in-somnia * * This file is part of JAAD. * * JAAD 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 3 of the * License, or (at your option) any later version. * * JAAD 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, see <http://www.gnu.org/licenses/>. */ package net.sourceforge.jaad.spi.javasound; /** * CircularBuffer for asynchronous reading. * Adopted from Tritonus (http://www.tritonus.org/). * @author in-somnia */ class CircularBuffer { private static final int BUFFER_SIZE = 327670; private final byte[] data; private final Trigger trigger; private long readPos, writePos; private boolean open; CircularBuffer(Trigger trigger) { this.trigger = trigger; data = new byte[BUFFER_SIZE]; readPos = 0; writePos = 0; open = true; } public void close() { open = false; } public boolean isOpen() { return open; } public int availableRead() { return (int) (writePos-readPos); } public int availableWrite() { return BUFFER_SIZE-availableRead(); } private int getReadPos() { return (int) (readPos%BUFFER_SIZE); } private int getWritePos() { return (int) (writePos%BUFFER_SIZE); } public int read(byte[] b) { return read(b, 0, b.length); } public int read(byte[] b, int off, int len) { if(!isOpen()) { if(availableRead()>0) len = Math.min(len, availableRead()); else return -1; } synchronized(this) { if(trigger!=null&&availableRead()<len) { trigger.execute(); } len = Math.min(availableRead(), len); int remaining = len; while(remaining>0) { while(availableRead()==0) { try { wait(); } catch(InterruptedException e) { } } int available = Math.min(availableRead(), remaining); int toRead; while(available>0) { toRead = Math.min(available, BUFFER_SIZE-getReadPos()); System.arraycopy(data, getReadPos(), b, off, toRead); readPos += toRead; off += toRead; available -= toRead; remaining -= toRead; } notifyAll(); } return len; } } public int write(byte[] b) { return write(b, 0, b.length); } public int write(byte[] b, int off, int len) { synchronized(this) { int remaining = len; while(remaining>0) { while(availableWrite()==0) { try { wait(); } catch(InterruptedException e) { } } int available = Math.min(availableWrite(), remaining); int toWrite; while(available>0) { toWrite = Math.min(available, BUFFER_SIZE-getWritePos()); System.arraycopy(b, off, data, getWritePos(), toWrite); writePos += toWrite; off += toWrite; available -= toWrite; remaining -= toWrite; } notifyAll(); } return len; } } static interface Trigger { void execute(); } }