JLayer Synchronization - PullRequest
       25

JLayer Synchronization

1 голос
/ 04 января 2011

(я пытаюсь сделать мой предыдущий вопрос более общим в надежде найти решение.)

Я использую библиотеку JLayer и файл sample.mp3. Я хотел бы воспроизвести и декодировать файл одновременно.

Однако я хочу, чтобы они были синхронизированы - если часть песни декодируется, она также воспроизводится. Ничто не декодируется до того, как оно будет воспроизведено, и наоборот (в разумной степени, конечно).

Вот как с уважением воспроизводится и декодируется песня:

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

Я сейчас использую:

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

но при этом используется целая песня сразу, поэтому я не могу синхронизироваться. Есть ли способ разбить sample.mp3 на части, которыми могут манипулировать оба процесса? Если бы у меня было достаточно маленьких кусочков, я мог бы запустить оба кусочка в процессы, подождать, пока оба не закончатся, а затем взять следующий маленький кусочек и повторить, пока у меня не закончились маленькие кусочки.

Примечание. Я пытался использовать ByteArrayInputStream безуспешно, но, возможно, моя методика неверна при его использовании.

1 Ответ

1 голос
/ 04 января 2011

Надеюсь, я правильно понял:

  • У вас есть один входной файл
  • Вы хотите, чтобы два разных входных потока были синхронизированы в том смысле, что «они должны достичь одинакового прогресса» в потоке.

Это интересный вопрос. Я придумал следующий набросок (компилируется, но не выполнил его, поэтому сначала вы можете провести небольшое тестирование).

  • Создайте объект-оболочку «StreamSynchronizer», который управляет доступом к базовому входу. Только один байт читается, пока все производные потоки не прочитают этот байт.
  • Получите из этого числа любое количество экземпляров SynchronizedStream, которые делегируют «чтение» обратно 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;
        }
    }
}

<code>
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);
    }
}

...