1/*
2 * Copyright (c) 2009-2010 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33package com.jme3.audio.plugins;
34
35import de.jarnbjo.ogg.*;
36import java.io.IOException;
37import java.io.InputStream;
38import java.util.Collection;
39import java.util.HashMap;
40import java.util.LinkedList;
41
42/**
43 * Single-threaded physical ogg stream. Decodes audio in the same thread
44 * that reads.
45 */
46public class UncachedOggStream implements PhysicalOggStream {
47
48    private boolean closed = false;
49    private boolean eos = false;
50    private boolean bos = false;
51    private InputStream sourceStream;
52    private LinkedList<OggPage> pageCache = new LinkedList<OggPage>();
53    private HashMap<Integer, LogicalOggStream> logicalStreams
54            = new HashMap<Integer, LogicalOggStream>();
55    private OggPage lastPage = null;
56
57    public UncachedOggStream(InputStream in) throws OggFormatException, IOException {
58        this.sourceStream = in;
59
60        // read until beginning of stream
61        while (!bos){
62            readNextOggPage();
63        }
64
65        // now buffer up an addition 25 pages
66//        while (pageCache.size() < 25 && !eos){
67//            readNextOggPage();
68//        }
69    }
70
71    public OggPage getLastOggPage() {
72        return lastPage;
73    }
74
75    private void readNextOggPage() throws IOException {
76        OggPage op = OggPage.create(sourceStream);
77        if (!op.isBos()){
78            bos = true;
79        }
80        if (op.isEos()){
81            eos = true;
82            lastPage = op;
83        }
84
85        LogicalOggStreamImpl los = (LogicalOggStreamImpl) getLogicalStream(op.getStreamSerialNumber());
86        if (los == null){
87            los = new LogicalOggStreamImpl(this, op.getStreamSerialNumber());
88            logicalStreams.put(op.getStreamSerialNumber(), los);
89            los.checkFormat(op);
90        }
91
92        pageCache.add(op);
93    }
94
95    public OggPage getOggPage(int index) throws IOException {
96        if (eos){
97            return null;
98        }
99
100//        if (!eos){
101//            int num = pageCache.size();
102//            long fiveMillis = 5000000;
103//            long timeStart  = System.nanoTime();
104//            do {
105//                readNextOggPage();
106//            } while ( !eos && (System.nanoTime() - timeStart) < fiveMillis );
107//            System.out.println( pageCache.size() - num );
108
109            if (pageCache.size() == 0 /*&& !eos*/){
110                readNextOggPage();
111            }
112//        }
113
114        return pageCache.removeFirst();
115    }
116
117    private LogicalOggStream getLogicalStream(int serialNumber) {
118        return logicalStreams.get(Integer.valueOf(serialNumber));
119    }
120
121    public Collection<LogicalOggStream> getLogicalStreams() {
122        return logicalStreams.values();
123    }
124
125    public void setTime(long granulePosition) throws IOException {
126    }
127
128    public boolean isSeekable() {
129        return false;
130    }
131
132    public boolean isOpen() {
133        return !closed;
134    }
135
136    public void close() throws IOException {
137        closed = true;
138        sourceStream.close();
139    }
140}
141