1

(I'm attempting to make my previous question more generic in the hopes of a solution.)

I am using the JLayer library and a sample.mp3 file. I would like to play AND decode the file at the same time.

However, I want them to be synchronized - if a part of the song is decoded, it is also played. Nothing is decoded before it is played and vice versa (to a reasonable degree, of course).

Here is how a song is played and decoded, respectfully:

Player p = new Player(InputStream mp3stream);
p.play();

Decoder d = new Decoder();
BitStream bs = new Bitstream(InputStream mp3stream);
SampleBuffer s = (SampleBuffer) d.decodeFrame(bs.readFrame(), bs);
// ... for processing the SampleBuffer but irrelevant for the question

I currently use:

InputStream mp3stream = new FileInputStream("sample.mp3");

but this uses the whole song at once so I am unable to synchronize. Is there a way to break the sample.mp3 into pieces that can be manipulated by both processes? If I had small enough pieces I could run both pieces into the processes, wait until both finished, and then grab the next small piece and repeat until I was out of small pieces.

Note: I have tried using ByteArrayInputStream with no success - but perhaps my methodology is incorrect when using it.

Matt
  • 11
  • 2

1 Answers1

1

I hope i get this right:

  • You have a single input file
  • You want that two different input streams are synchronized in the sense, that "they must make the same progress" in the stream.

This is an interestig question. I came up with the following sketch (compiles, but didn't execute it, so you may do a little testing first).

  • Create a wrapper object "StreamSynchronizer" that controls access to the underlying input. Only a single byte is read until all derived streams have read this byte.
  • Derive any number of "SynchronizedStream" instances from this that delegate the "read" back t the StreamSynchronizer.

package de.mit.stackoverflow;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class StreamSynchronizer {

    final private InputStream inputStream;

    private List activeStreams = new ArrayList();

    private int lastByte;

    private Set waitingStreams = new HashSet();

    private Object lock = new Object();

    public StreamSynchronizer(InputStream is) throws IOException {
        super();
        this.inputStream = is;
        lastByte = getInputStream().read();
    }

    public void close(SynchronizedStream stream) {
        activeStreams.remove(stream);
    }

    public SynchronizedStream createStream() {
        SynchronizedStream stream = new SynchronizedStream(this);
        activeStreams.add(stream);
        return stream;
    }

    public InputStream getInputStream() {
        return inputStream;
    }

    public int read(SynchronizedStream stream) throws IOException {
        synchronized (lock) {
            while (waitingStreams.contains(stream)) {
                if (waitingStreams.size() == activeStreams.size()) {
                    waitingStreams.clear();
                    lastByte = getInputStream().read();
                    lock.notifyAll();
                } else {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        throw new IOException(e);
                    }
                }
            }
            waitingStreams.add(stream);
            return lastByte;
        }
    }
}


package de.mit.stackoverflow;

import java.io.IOException;
import java.io.InputStream;

public class SynchronizedStream extends InputStream {

    final private StreamSynchronizer synchronizer;

    protected SynchronizedStream(StreamSynchronizer synchronizer) {
        this.synchronizer = synchronizer;
    }

    @Override
    public void close() throws IOException {
        getSynchronizer().close(this);
    }

    public StreamSynchronizer getSynchronizer() {
        return synchronizer;
    }

    @Override
    public int read() throws IOException {
        return getSynchronizer().read(this);
    }
}

mtraut
  • 4,720
  • 3
  • 24
  • 33