All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.jarnbjo.ogg.UncachedUrlStream Maven / Gradle / Ivy

/*
 * $ProjectName$
 * $ProjectRevision$
 * -----------------------------------------------------------
 * $Id: UncachedUrlStream.java,v 1.1 2003/04/10 19:48:22 jarnbjo Exp $
 * -----------------------------------------------------------
 *
 * $Author: jarnbjo $
 *
 * Description:
 *
 * Copyright 2002-2003 Tor-Einar Jarnbjo
 * -----------------------------------------------------------
 *
 * Change History
 * -----------------------------------------------------------
 * $Log: UncachedUrlStream.java,v $
 * Revision 1.1  2003/04/10 19:48:22  jarnbjo
 * no message
 */
package de.jarnbjo.ogg;

import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;

/**
 * Implementation of the {@code PhysicalOggStream} interface for reading an Ogg
 * stream from a URL. This class performs only the necessary caching to provide
 * continuous playback. Seeking within the stream is not supported.
 */
public class UncachedUrlStream implements PhysicalOggStream {
    private boolean closed = false;
    final private URLConnection source;
    final private InputStream sourceStream;
    final private Object drainLock = new Object();
    final private LinkedList pageCache = new LinkedList<>();

    final private HashMap logicalStreams
            = new HashMap<>();

    final private LoaderThread loaderThread;

    private static final int PAGECACHE_SIZE = 10;

    /**
     * Creates an instance of the {@code PhysicalOggStream} interface suitable
     * for reading an Ogg stream from a URL.
     *
     * @param source
     * @throws OggFormatException
     * @throws IOException
     */
    public UncachedUrlStream(URL source)
            throws OggFormatException, IOException {
        this.source = source.openConnection();
        this.sourceStream = this.source.getInputStream();

        loaderThread = new LoaderThread(sourceStream, pageCache);
        new Thread(loaderThread).start();

        while (!loaderThread.isBosDone() || pageCache.size() < PAGECACHE_SIZE) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException ex) {
                // do nothing
            }
            //System.out.print("caching "+pageCache.size()
            //+"/"+PAGECACHE_SIZE+" pages\r");
        }
        //System.out.println();
    }

    @Override
    public Collection getLogicalStreams() {
        return logicalStreams.values();
    }

    @Override
    public boolean isOpen() {
        return !closed;
    }

    @Override
    public void close() throws IOException {
        closed = true;
        sourceStream.close();
    }

    @Override
    public OggPage getOggPage(int index) throws IOException {
        while (pageCache.isEmpty()) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
                // do nothing
            }
        }
        synchronized (drainLock) {
            return (OggPage) pageCache.removeFirst();
        }
    }

    private LogicalOggStream getLogicalStream(int serialNumber) {
        return (LogicalOggStream) logicalStreams.get(serialNumber);
    }

    @Override
    public void setTime(long granulePosition) throws IOException {
        throw new UnsupportedOperationException(
                "Method not supported by this class");
    }

    public class LoaderThread implements Runnable {

        final private InputStream source;
        final private Deque pageCache;
        private RandomAccessFile drain;
        private byte[] memoryCache;

        private boolean bosDone = false;

        private int pageNumber;

        public LoaderThread(InputStream source, LinkedList pageCache) {
            this.source = source;
            this.pageCache = pageCache;
        }

        @Override
        public void run() {
            try {
                boolean eos = false;
                byte[] buffer = new byte[8192];
                while (!eos) {
                    OggPage op = OggPage.create(source);
                    synchronized (drainLock) {
                        pageCache.add(op);
                    }

                    if (!op.isBos()) {
                        bosDone = true;
                    }
                    if (op.isEos()) {
                        eos = true;
                    }

                    LogicalOggStreamImpl los = (LogicalOggStreamImpl)
                            getLogicalStream(op.getStreamSerialNumber());
                    if (los == null) {
                        los = new LogicalOggStreamImpl(UncachedUrlStream.this,
                                op.getStreamSerialNumber());
                        logicalStreams.put(op.getStreamSerialNumber(), los);
                        los.checkFormat(op);
                    }

                    pageNumber++;

                    while (pageCache.size() > PAGECACHE_SIZE) {
                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException ex) {
                            // do nothing
                        }
                    }
                }
            } catch (EndOfOggStreamException e) {
                // ok
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public boolean isBosDone() {
            return bosDone;
        }
    }

    /**
     * @return always {@code false}
     */
    @Override
    public boolean isSeekable() {
        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy