001package net.bramp.ffmpeg.progress;
002
003import static com.google.common.base.Preconditions.checkNotNull;
004
005import com.google.common.net.InetAddresses;
006import java.io.IOException;
007import java.net.InetAddress;
008import java.net.URI;
009import java.net.URISyntaxException;
010import java.util.concurrent.CountDownLatch;
011import javax.annotation.CheckReturnValue;
012
013public abstract class AbstractSocketProgressParser implements ProgressParser {
014
015  final StreamProgressParser parser;
016
017  Thread thread; // Thread for handling incoming connections
018
019  public AbstractSocketProgressParser(ProgressListener listener) {
020    this.parser = new StreamProgressParser(listener);
021  }
022
023  /**
024   * Creates a URL to parse to FFmpeg based on the scheme, address and port.
025   *
026   * <p>TODO Move this method to somewhere better.
027   *
028   * @param scheme
029   * @param address
030   * @param port
031   * @return
032   * @throws URISyntaxException
033   */
034  @CheckReturnValue
035  static URI createUri(String scheme, InetAddress address, int port) throws URISyntaxException {
036    checkNotNull(address);
037    return new URI(
038        scheme,
039        null /* userInfo */,
040        InetAddresses.toUriString(address),
041        port,
042        null /* path */,
043        null /* query */,
044        null /* fragment */);
045  }
046
047  @CheckReturnValue
048  protected abstract String getThreadName();
049
050  protected abstract Runnable getRunnable(CountDownLatch startSignal);
051
052  /**
053   * Starts the ProgressParser waiting for progress.
054   *
055   * @exception IllegalThreadStateException if the parser was already started.
056   */
057  @Override
058  public synchronized void start() {
059    if (thread != null) {
060      throw new IllegalThreadStateException("Parser already started");
061    }
062
063    String name = getThreadName() + "(" + getUri().toString() + ")";
064
065    CountDownLatch startSignal = new CountDownLatch(1);
066    Runnable runnable = getRunnable(startSignal);
067
068    thread = new Thread(runnable, name);
069    thread.start();
070
071    // Block until the thread has started
072    try {
073      startSignal.await();
074    } catch (InterruptedException e) {
075      Thread.currentThread().interrupt();
076    }
077  }
078
079  @Override
080  public void stop() throws IOException {
081    if (thread != null) {
082      thread.interrupt(); // This unblocks processStream();
083
084      try {
085        thread.join();
086      } catch (InterruptedException e) {
087        Thread.currentThread().interrupt();
088      }
089    }
090  }
091
092  @Override
093  public void close() throws IOException {
094    stop();
095  }
096}