/** Gets the correct codec from the camera */
  public Codec fetchCodec(Format inFormat, Format outFormat) {
    Vector codecs = PlugInManager.getPlugInList(inFormat, outFormat, PlugInManager.CODEC);
    if (codecs == null) return null;

    for (int i = 0; i < codecs.size(); i++) {
      Codec codec = null;
      try {
        Class codecClass = Class.forName((String) codecs.elementAt(i));
        if (codecClass != null) codec = (Codec) codecClass.newInstance();
      } catch (Exception e) {
        continue;
      }
      if (codec == null || codec.setInputFormat(inFormat) == null) continue;

      Format[] outFormats = codec.getSupportedOutputFormats(inFormat);
      if (outFormats == null) continue;
      for (int j = 0; j < outFormats.length; j++) {
        if (outFormats[j].matches(outFormat)) {
          try {
            codec.setOutputFormat(outFormats[j]);
            codec.open();
            return codec;
          } catch (Exception e) {
          }
        }
      }
    }
    return null;
  }
  /**
   * Open the plugin. Must be called after the formats have been determined and before "process" is
   * called.
   *
   * <p>Open the DataLine.
   */
  public void open() throws ResourceUnavailableException {
    javax.sound.sampled.AudioFormat audioFormat = convertFormat(inputFormat);
    logger.info("opening with javax.sound format: " + audioFormat);
    try {

      if (!inputFormat.getEncoding().equals(AudioFormat.LINEAR)) {
        logger.info("JavaSoundRenderer: Audio format is not linear, creating conversion");

        if (inputFormat.getEncoding().equals(AudioFormat.ULAW))
          codec =
              new net.sf.fmj.media.codec.audio.ulaw
                  .Decoder(); // much more efficient than JavaSoundCodec
        else if (inputFormat.getEncoding().equals(AudioFormat.ALAW))
          codec =
              new net.sf.fmj.media.codec.audio.alaw
                  .Decoder(); // much more efficient than JavaSoundCodec
        else
          throw new ResourceUnavailableException(
              "Unsupported input format encoding: " + inputFormat.getEncoding());
        // codec = new net.sf.fmj.media.codec.JavaSoundCodec();
        codec.setInputFormat(inputFormat);
        final Format[] outputFormats = codec.getSupportedOutputFormats(inputFormat);
        if (outputFormats.length < 1)
          throw new ResourceUnavailableException(
              "Unable to get an output format for input format: " + inputFormat);
        final AudioFormat codecOutputFormat =
            (AudioFormat) outputFormats[0]; // TODO: choose the best quality one.
        codec.setOutputFormat(codecOutputFormat);
        audioFormat = convertFormat(codecOutputFormat);

        codec.open();

        logger.info(
            "JavaSoundRenderer: Audio format is not linear, created conversion from "
                + inputFormat
                + " to "
                + codecOutputFormat);
      }

      sourceLine = getSourceDataLine(audioFormat);
      sourceLine.open(audioFormat);

      {
        FloatControl gainFloatControl = null;
        BooleanControl muteBooleanControl = null;

        try {
          gainFloatControl = (FloatControl) sourceLine.getControl(FloatControl.Type.MASTER_GAIN);
        } catch (Exception e) {
          e.printStackTrace();
        }

        try {
          muteBooleanControl = (BooleanControl) sourceLine.getControl(BooleanControl.Type.MUTE);
        } catch (Exception e) {
          e.printStackTrace();
        }

        // TODO add other controls
        JavaSoundGainControl gainControl =
            new JavaSoundGainControl(gainFloatControl, muteBooleanControl);
        controls.addControl(gainControl);
      }

      logControls(sourceLine.getControls());
    } catch (LineUnavailableException e) {
      throw new ResourceUnavailableException(e.getMessage());
    }
  }