/** Play a random http stream. */
  public void playStream()
      throws EncoderException, LineUnavailableException, IOException, UnsupportedAudioFileException,
          InterruptedException {
    String source;

    SourceDataLine line;
    DataLine.Info info;

    // The source stream
    source = "http://mp3.streampower.be/stubru-high.mp3";
    source = "http://mp3.streampower.be/klara-high.mp3";

    // Set the transcoding to WAV PCM, 16bits LE, 16789Hz (to make sure resampling is done).
    Attributes attributes = DefaultAttributes.WAV_PCM_S16LE_STEREO_44KHZ.getAttributes();
    attributes.setSamplingRate(16789);

    // Stream the same file with on the fly decoding:
    AudioInputStream streamedAudioInputStream = Streamer.stream(source, attributes);
    AudioFormat audioFormat = Streamer.streamAudioFormat(attributes);

    byte[] streamBuffer = new byte[1024];

    info = new DataLine.Info(SourceDataLine.class, audioFormat);
    line = (SourceDataLine) AudioSystem.getLine(info);
    line.open(audioFormat);
    line.start();

    while (streamedAudioInputStream.available() > streamBuffer.length) {
      int bytesRead = streamedAudioInputStream.read(streamBuffer);
      int bytesWrote = line.write(streamBuffer, 0, streamBuffer.length);
      assertEquals(
          "The number of bytes read should match the number of bytes written to the dataline",
          bytesRead,
          bytesWrote);
    }
    line.close();
    streamedAudioInputStream.close();
  }
  /**
   * Streaming and transcoding the same file should yield the exact same results. To test this an
   * mp3 is decoded and resampled and via transcoding and via streaming.
   */
  public void compareTranscodingAndStreaming(String source)
      throws EncoderException, LineUnavailableException, IOException, UnsupportedAudioFileException,
          InterruptedException {
    System.out.println("Testing: " + source);
    // Set the transcoding to WAV PCM, 16bits LE, 16789Hz (to make sure resampling is done).
    Attributes attributes = DefaultAttributes.WAV_PCM_S16LE_STEREO_44KHZ.getAttributes();
    attributes.setSamplingRate(16789);

    // Save the transcoded file:
    File temporaryTranscoded = File.createTempFile("temporaryTranscoded", ".wav");

    Transcoder.transcode(source, temporaryTranscoded.getAbsolutePath(), attributes);
    AudioInputStream transcodedAudioInputStream =
        AudioSystem.getAudioInputStream(temporaryTranscoded);

    // Stream the same file with on the fly decoding:
    AudioInputStream streamedAudioInputStream = Streamer.stream(source, attributes);

    byte[] streamBuffer = new byte[1024];
    byte[] transcodedBuffer = new byte[streamBuffer.length];

    int sampleCounter = 0;
    while (streamedAudioInputStream.available() > streamBuffer.length
        && transcodedAudioInputStream.available() > streamBuffer.length) {

      streamedAudioInputStream.read(streamBuffer);
      transcodedAudioInputStream.read(transcodedBuffer);

      for (int i = 0; i < streamBuffer.length; i++) {
        sampleCounter++;
        assertEquals(
            "Difference at sample: " + sampleCounter, transcodedBuffer[i], streamBuffer[i]);
      }
    }
    streamedAudioInputStream.close();
    transcodedAudioInputStream.close();
    temporaryTranscoded.delete();
  }
  public AudioInputStream pipe(Attributes attributes) throws EncoderException {
    String pipeEnvironment;
    String pipeArgument;
    File pipeLogFile;
    int pipeBuffer;

    if (System.getProperty("os.name").indexOf("indows") > 0) {
      pipeEnvironment = "cmd.exe";
      pipeArgument = "/C";
    } else {
      pipeEnvironment = "/bin/bash";
      pipeArgument = "-c";
    }
    pipeLogFile = new File("decoder_log.txt");
    // buffer 1/4 second of audio.
    pipeBuffer = attributes.getSamplingRate() / 4;

    AudioFormat audioFormat = Encoder.getTargetAudioFormat(attributes);

    String command = toString();

    ProcessBuilder pb = new ProcessBuilder(pipeEnvironment, pipeArgument, command);

    pb.redirectError(Redirect.appendTo(pipeLogFile));

    LOG.fine("Starting piped decoding process");
    final Process process;
    try {
      process = pb.start();
    } catch (IOException e1) {
      throw new EncoderException("Problem starting piped sub process: " + e1.getMessage());
    }

    InputStream stdOut = new BufferedInputStream(process.getInputStream(), pipeBuffer);

    // read and ignore the 46 byte wav header, only pipe the pcm samples to the audioinputstream
    byte[] header = new byte[46];
    double sleepSeconds = 0;
    double timeoutLimit = 20; // seconds

    try {
      while (stdOut.available() < header.length) {
        try {
          Thread.sleep(100);
          sleepSeconds += 0.1;
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        if (sleepSeconds > timeoutLimit) {
          throw new Error("Could not read from pipe within " + timeoutLimit + " seconds: timeout!");
        }
      }
      int bytesRead = stdOut.read(header);
      if (bytesRead != header.length) {
        throw new EncoderException(
            "Could not read complete WAV-header from pipe. This could result in mis-aligned frames!");
      }
    } catch (IOException e1) {
      throw new EncoderException("Problem reading from piped sub process: " + e1.getMessage());
    }

    final AudioInputStream audioStream =
        new AudioInputStream(stdOut, audioFormat, AudioSystem.NOT_SPECIFIED);

    // This thread waits for the end of the subprocess.
    new Thread(
            new Runnable() {
              public void run() {
                try {
                  process.waitFor();
                  LOG.fine("Finished piped decoding process");
                } catch (InterruptedException e) {
                  LOG.severe("Interrupted while waiting for sub process exit.");
                  e.printStackTrace();
                }
              }
            },
            "Decoding Pipe Reader")
        .start();
    return audioStream;
  }