/* * Mobicents, Communications Middleware * * Copyright (c) 2008, Red Hat Middleware LLC or third-party * contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Middleware LLC. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program 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 distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * * Boston, MA 02110-1301 USA */ package org.mobicents.media.server.impl.resource.audio; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.Semaphore; import org.mobicents.media.Buffer; /** * Implements cache for recorded audio. * * Recorder implementation uses <code>push(Buffer)</code> method to * fill the cache. Java Sound AudioSystem can access this cache as * <code>java.io.InputStream</code> for constructing internal * <code>AudioInputStream</code>. * * The cache is locked for reading until will be explicitly unblocked by Recorder. * * * @author Oleg Kulikov */ public class RecorderCache extends InputStream { private int available = 0; private int offset; protected Semaphore semaphore = new Semaphore(0); protected volatile boolean blocked = false; private int bufferSize = 16000 * 60; private byte[] localBuffer = new byte[bufferSize]; @Override public int available() { return available; } @Override public int read() throws IOException { if (available == 0) { return -1; } if (blocked) { try { semaphore.acquire(); } catch (InterruptedException e) { throw new IOException(e.getMessage()); } } available--; int b =localBuffer[offset++] & 0xff; return b; } /** * Duplicates size of local buffer. */ private void resizeLocalBuffer() { //save data in temp array byte[] temp = new byte[available]; System.arraycopy(localBuffer, 0, temp, 0, available); //resize local bufer and restore data localBuffer = new byte[2 * localBuffer.length]; System.arraycopy(temp, 0, localBuffer, 0, available); } /** * Appends data from media buffer to the local buffer. * * @param buffer the buffer which contains media data */ protected void push(Buffer buffer) { int remainder = localBuffer.length - available; boolean enouphSpace = remainder > buffer.getLength(); //@FIXME //Do not extend buffer without limit! Use disk cache instead! if (!enouphSpace) { resizeLocalBuffer(); } byte[] data = (byte[]) buffer.getData(); System.arraycopy(data, buffer.getOffset(), localBuffer, available, buffer.getLength()); available += buffer.getLength(); } /** * Unblocks cache and allow reading from this cache. */ protected void unblock() { semaphore.release(); } }