/** * Copyright (C) 2005 DFKI GmbH. All rights reserved. */ package org.jsresources; import java.io.IOException; import java.util.Collection; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; /** * @author Marc Schröder * */ public class AppendableSequenceAudioInputStream extends SequenceAudioInputStream { protected boolean doneAppending = false; /** * Create a sequence audio input stream to which more AudioInputStreams can be appended after creation. When the currently * available audio input streams have been read, calls to read() will block until new audio data is appended or * doneAppending() is called. After doneAppending() is called, read() will return -1 when running out of data. * * @param audioFormat * audioformat * @param audioInputStreams * audioinputstreams */ public AppendableSequenceAudioInputStream(AudioFormat audioFormat, Collection audioInputStreams) { super(audioFormat, audioInputStreams); } /** * Append the new audio input stream to the end of the list of audio input streams. * * @param ais * ais * @throws IllegalArgumentException * if this method is called after doneAppending() was called. */ public synchronized void append(AudioInputStream ais) { if (ais == this) throw new IllegalArgumentException("Cannot append me to myself"); if (doneAppending) throw new IllegalArgumentException("Cannot append after doneAppending() was called!"); m_audioInputStreamList.add(ais); // System.err.println("Appending audio"); notifyAll(); } /** * Inform this audio input stream not to expect any further calls to append(), and report end-of-stream when all data has been * read. */ public synchronized void doneAppending() { doneAppending = true; // System.err.println("Done appending"); notifyAll(); } public synchronized int read() throws IOException { while (m_audioInputStreamList.size() == 0) { if (doneAppending) // never had any data, no more to come return -1; // no data yet, wait try { wait(); } catch (InterruptedException ie) { } } int n = -1; // Try to read data while ((n = super.read()) <= 0) { // no data, but more expected if (n == -1 && doneAppending) // finished reading return -1; // wait and try again try { wait(); } catch (InterruptedException ie) { } } return n; } public synchronized int read(byte[] buf, int off, int len) throws IOException { int n = -1; while (m_audioInputStreamList.size() == 0) { if (doneAppending) // never had any data, no more to come return -1; // no data yet, wait try { wait(); } catch (InterruptedException ie) { } } // Try to read data while (m_nCurrentStream >= m_audioInputStreamList.size() || (n = super.read(buf, off, len)) <= 0) { // no data, but more // expected if (n == -1 && doneAppending) // finished reading return -1; // wait and try again try { wait(); } catch (InterruptedException ie) { } } // System.err.println("Read "+ n + " bytes"); return n; } /** * Return the frame length of this appendable sequence audio input stream. As long as <code>doneAppending()</code> has not * been called, returns <code>AudioSystem.NOT_SPECIFIED</code>; after that, the frame length is the sum of the frame lengths * of individual frame lengths. * * @return total */ public long getFrameLength() { if (!doneAppending) { return AudioSystem.NOT_SPECIFIED; } else { long total = 0; for (int i = 0, n = m_audioInputStreamList.size(); i < n; i++) { long length = ((AudioInputStream) m_audioInputStreamList.get(i)).getFrameLength(); if (length == AudioSystem.NOT_SPECIFIED) { // If one is not specified, all are not specified return AudioSystem.NOT_SPECIFIED; } total += length; } return total; } } }