Reputation: 4065
I'm trying to write an algorithm, that downloads a video live stream. Specifically, the respective stream I'm trying to fetch is based on a dynamic .m3u8 playlist file, which periodically provides URIs of new video files. The main goal is to combine those individual media files into one coherent InputStream.
I actually succeeded in getting it to work: I periodically check for new media files, that appear inside the playlist, and pass their HTTP streams to a custom InputStream implementation, namely InputStreamChain. Since it's a live stream, I assume it to be endless, at least for the time being. Ergo, I wanted my InputStreamChain
's read()
never to send the -1. Unfortunately, it did; every time when all queued media streams were consumed, the InputStreamChain
ended. Instead, I wanted it to block I/O, until a new media file arrives.
So, I came up with a working solution: I adjusted the read()
method to loop until there's a new stream available (a TimerTask
will provide the new files). In the loop, I built in a Thread.sleep()
, in order to reduce the CPU load:
public int read() throws IOException {
int bit = current.read();
if (bit == -1 && streams.size() > 0) {
// left out due to lacking relevance
} else if(bit == -1 && streams.size() == 0) {
while(streams.size() == 0) {
Thread.currentThread().sleep(50);
}
return read();
}
return bit;
}
Although it seems to work, I have a feeling, that I'm not doing it how I'm supposed to. I also tried using Lock
together with Condition.await()
, but when my TimerTask
tried to trigger Condition.signal()
, it just threw a IllegalMonitorStateException
.
That's why I'm asking the question:
In what way should I delay/block an InputStream's read()
method, especially in my scenario?
Edit:
For the sake of completeness, I'm going to provide my failed Lock
approach, too:
private ReentrantLock ioLock;
private Condition ioCond;
private boolean waitingForStream = false;
public InputStreamChain() {
ioLock = new ReentrantLock();
ioCond = ioLock.newCondition();
}
public synchronized InputStreamChain addInputStream(final InputStream stream) {
streams.addLast(stream);
if (current == null) {
current = streams.removeFirst();
}
if(waitingForStream) {
ioCond.signal();
}
return this;
}
public int read() throws IOException {
int bit = current.read();
if (bit == -1 && streams.size() > 0) {
// do stuff
} else if(bit == -1) {
waitingForStream = true;
ioLock.lock();
try {
ioCond.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
waitingForStream = false;
ioLock.unlock();
}
return read();
}
return bit;
}
Upvotes: 0
Views: 560
Reputation: 5163
Probably you are not using synchronized block. Here is an example:
class MyReader
{
public int read() throws IOException {
int bit = current.read();
if (bit == -1 && streams.size() > 0) {
// left out due to lacking relevance
} else if(bit == -1 && streams.size() == 0) {
waitForNextStream();
return read();
}
return bit;
}
private synchronized void waitForNextStream()
{
// TODO add close handling, set current here
while (streams.isEmpty())
{
wait();
}
}
public synchronized void addNextStream(InputStream is)
{
streams.add(is);
notify();
}
}
Upvotes: 1