blob: f35219db326167e8be9179257e3da5795a480fb4 [file] [log] [blame]
Constantin Kaplinsky903009e2002-05-20 10:55:47 +00001//
2// Copyright (C) 2002 HorizonLive.com, Inc. All Rights Reserved.
3//
4// This is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This software is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this software; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17// USA.
18//
19
20//
21// FbsInputStream.java
22//
23
24import java.io.*;
25
26class FbsInputStream extends InputStream {
27
28 protected InputStream in;
29 protected long startTime;
30 protected long timeOffset;
Constantin Kaplinskyba0c4df2002-05-30 12:23:25 +000031 protected boolean paused;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000032
33 protected byte[] buffer;
34 protected int bufferSize;
35 protected int bufferPos;
36
37 //
38 // Constructors.
39 //
40
41 FbsInputStream() throws IOException {
42 throw new IOException("FbsInputStream: no such constructor");
43 }
44
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +000045 //
46 // Construct FbsInputStream object, begin playback.
47 //
48
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000049 FbsInputStream(InputStream in) throws IOException
50 {
51 this.in = in;
52 startTime = System.currentTimeMillis();
53 timeOffset = 0;
Constantin Kaplinskyba0c4df2002-05-30 12:23:25 +000054 paused = false;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000055
56 byte[] b = new byte[12];
57 readFully(b);
58
59 if (b[0] != 'F' || b[1] != 'B' || b[2] != 'S' || b[3] != ' ' ||
60 b[4] != '0' || b[5] != '0' || b[6] != '1' || b[7] != '.' ||
61 b[8] < '0' || b[8] > '9' || b[9] < '0' || b[9] > '9' ||
62 b[10] < '0' || b[10] > '9' || b[11] != '\n') {
63 throw new IOException("Incorrect protocol version");
64 }
65
66 buffer = null;
67 bufferSize = 0;
68 bufferPos = 0;
69 }
70
71 //
72 // Basic methods overriding InputStream's methods.
73 //
74
75 public int read() throws IOException
76 {
77 while (bufferSize == 0) {
78 if (!fillBuffer())
79 return -1;
80 }
81 bufferSize--;
82 return buffer[bufferPos++] & 0xFF;
83 }
84
85 public int available() throws IOException
86 {
87 // FIXME: This will work incorrectly if our caller will wait until
88 // some amount of data is available when the buffer contains less
89 // data than then that. Current implementation never reads more
90 // data until the buffer is fully exhausted.
91 return bufferSize;
92 }
93
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +000094 public synchronized void close() throws IOException
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000095 {
96 in.close();
97 in = null;
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +000098 startTime = -1;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000099 timeOffset = 0;
Constantin Kaplinskyba0c4df2002-05-30 12:23:25 +0000100 paused = false;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000101
102 buffer = null;
103 bufferSize = 0;
104 bufferPos = 0;
105 }
106
107 //
108 // Methods providing additional functionality.
109 //
110
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000111 public long getTimeOffset()
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000112 {
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000113 return timeOffset;
Constantin Kaplinskyfe079832002-05-29 00:52:32 +0000114 }
115
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000116 public void setTimeOffset(int pos)
Constantin Kaplinsky30f786a2002-05-29 10:59:52 +0000117 {
118 }
119
120 public boolean isSeeking()
121 {
122 return false;
123 }
124
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000125 public synchronized void pausePlayback()
Constantin Kaplinsky30f786a2002-05-29 10:59:52 +0000126 {
Constantin Kaplinskyba0c4df2002-05-30 12:23:25 +0000127 paused = true;
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000128 notify();
Constantin Kaplinsky30f786a2002-05-29 10:59:52 +0000129 }
130
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000131 public synchronized void resumePlayback()
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000132 {
Constantin Kaplinskyba0c4df2002-05-30 12:23:25 +0000133 paused = false;
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000134 startTime = System.currentTimeMillis() - timeOffset;
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000135 notify();
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000136 }
137
138 //
139 // Methods for internal use.
140 //
141
142 private boolean fillBuffer() throws IOException
143 {
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000144 waitWhilePaused();
145
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000146 bufferSize = (int)readUnsigned32();
147 if (bufferSize >= 0) {
148 int realSize = (bufferSize + 3) & 0xFFFFFFFC;
149 buffer = new byte[realSize];
150 readFully(buffer);
151 bufferPos = 0;
152
153 timeOffset = readUnsigned32();
154 }
155
156 if (bufferSize < 0 || timeOffset < 0) {
157 buffer = null;
158 bufferSize = 0;
159 bufferPos = 0;
160 return false;
161 }
162
163 while (true) {
164 long timeDiff = startTime + timeOffset - System.currentTimeMillis();
165 if (timeDiff <= 0) {
166 break;
167 }
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000168 synchronized(this) {
169 try {
170 wait(timeDiff);
171 } catch (InterruptedException e) {
172 }
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000173 }
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000174 waitWhilePaused();
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000175 }
176
177 return true;
178 }
179
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000180 //
181 // In paused mode, wait for external notification on this object.
182 //
183
184 private void waitWhilePaused()
185 {
Constantin Kaplinskyba0c4df2002-05-30 12:23:25 +0000186 while (paused) {
Constantin Kaplinskyac6420d2002-05-29 17:05:39 +0000187 synchronized(this) {
188 try {
189 wait();
190 } catch (InterruptedException e) {
191 }
192 }
193 }
194 }
195
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000196 private long readUnsigned32() throws IOException
197 {
198 byte[] buf = new byte[4];
199 if (!readFully(buf))
200 return -1;
201
202 return ((long)(buf[0] & 0xFF) << 24 |
203 (buf[1] & 0xFF) << 16 |
204 (buf[2] & 0xFF) << 8 |
205 (buf[3] & 0xFF));
206 }
207
208 private boolean readFully(byte[] b) throws IOException
209 {
210 int off = 0;
211 int len = b.length;
212
213 while (off != len) {
214 int count = in.read(b, off, len - off);
215 if (count < 0) {
216 return false;
217 }
218 off += count;
219 }
220
221 return true;
222 }
223}
224