/**
   * Creates a <tt>MediaFormat</tt> for the specified <tt>encoding</tt>, <tt>clockRate</tt>,
   * <tt>channels</tt> and set of format parameters. If <tt>encoding</tt> is known to this
   * <tt>MediaFormatFactory</tt>, returns a <tt>MediaFormat</tt> which is either an
   * <tt>AudioMediaFormat</tt> or a <tt>VideoMediaFormat</tt> instance. Otherwise, returns
   * <tt>null</tt>.
   *
   * @param encoding the well-known encoding (name) to create a <tt>MediaFormat</tt> for
   * @param clockRate the clock rate in Hz to create a <tt>MediaFormat</tt> for
   * @param frameRate the frame rate in number of frames per second to create a <tt>MediaFormat</tt>
   *     for
   * @param channels the number of available channels (1 for mono, 2 for stereo) if it makes sense
   *     for the <tt>MediaFormat</tt> with the specified <tt>encoding</tt>; otherwise, ignored
   * @param formatParams any codec specific parameters which have been received via SIP/SDP or
   *     XMPP/Jingle
   * @param advancedParams any parameters which have been received via SIP/SDP or XMPP/Jingle
   * @return a <tt>MediaFormat</tt> with the specified <tt>encoding</tt>, <tt>clockRate</tt>,
   *     <tt>channels</tt> and set of format parameters which is either an <tt>AudioMediaFormat</tt>
   *     or a <tt>VideoMediaFormat</tt> instance if <tt>encoding</tt> is known to this
   *     <tt>MediaFormatFactory</tt>; otherwise, <tt>null</tt>
   * @see MediaFormatFactory#createMediaFormat(String, double, int, float, Map, Map)
   */
  public MediaFormat createMediaFormat(
      String encoding,
      double clockRate,
      int channels,
      float frameRate,
      Map<String, String> formatParams,
      Map<String, String> advancedParams) {
    MediaFormat mediaFormat = createMediaFormat(encoding, clockRate, channels, formatParams);

    if (mediaFormat == null) return null;

    /*
     * MediaFormatImpl is immutable so if the caller wants to change the
     * format parameters and/or the advanced attributes, we'll have to
     * create a new MediaFormatImpl.
     */
    Map<String, String> formatParameters = null;
    Map<String, String> advancedParameters = null;

    if ((formatParams != null) && !formatParams.isEmpty()) formatParameters = formatParams;
    if ((advancedParams != null) && !advancedParams.isEmpty()) advancedParameters = advancedParams;

    if ((formatParameters != null) || (advancedParameters != null)) {
      switch (mediaFormat.getMediaType()) {
        case AUDIO:
          mediaFormat =
              new AudioMediaFormatImpl(
                  ((AudioMediaFormatImpl) mediaFormat).getFormat(),
                  formatParameters,
                  advancedParameters);
          break;
        case VIDEO:
          VideoMediaFormatImpl videoMediaFormatImpl = (VideoMediaFormatImpl) mediaFormat;

          /*
           * If the format of VideoMediaFormatImpl is
           * a ParameterizedVideoFormat, it's possible for the format
           * parameters of that ParameterizedVideoFormat and of the new
           * VideoMediaFormatImpl (to be created) to be out of sync. While
           * it's not technically perfect, it should be practically safe
           * for the format parameters which distinguish VideoFormats with
           * the same encoding and clock rate because mediaFormat has
           * already been created in sync with formatParams (with respect
           * to the format parameters which distinguish VideoFormats with
           * the same encoding and clock rate).
           */
          mediaFormat =
              new VideoMediaFormatImpl(
                  videoMediaFormatImpl.getFormat(),
                  videoMediaFormatImpl.getClockRate(),
                  frameRate,
                  formatParameters,
                  advancedParameters);
          break;
        default:
          mediaFormat = null;
      }
    }
    return mediaFormat;
  }
  /**
   * Gets the <tt>MediaFormat</tt>s among the specified <tt>mediaFormats</tt> which have the
   * specified <tt>encoding</tt> and, optionally, <tt>clockRate</tt>.
   *
   * @param mediaFormats the <tt>MediaFormat</tt>s from which to filter out only the ones which have
   *     the specified <tt>encoding</tt> and, optionally, <tt>clockRate</tt>
   * @param encoding the well-known encoding (name) of the <tt>MediaFormat</tt>s to be retrieved
   * @param clockRate the clock rate of the <tt>MediaFormat</tt>s to be retrieved; {@link
   *     #CLOCK_RATE_NOT_SPECIFIED} if any clock rate is acceptable
   * @return a <tt>List</tt> of the <tt>MediaFormat</tt>s among <tt>mediaFormats</tt> which have the
   *     specified <tt>encoding</tt> and, optionally, <tt>clockRate</tt>
   */
  private List<MediaFormat> getMatchingMediaFormats(
      MediaFormat[] mediaFormats, String encoding, double clockRate) {
    /*
     * XXX Use String#equalsIgnoreCase(String) because some clients transmit
     * some of the codecs starting with capital letters.
     */

    /*
     * As per RFC 3551.4.5.2, because of a mistake in RFC 1890 and for
     * backward compatibility, G.722 should always be announced as 8000 even
     * though it is wideband. So, if someone is looking for G722/16000,
     * then: Forgive them, for they know not what they do!
     */
    if ("G722".equalsIgnoreCase(encoding) && (16000 == clockRate)) {
      clockRate = 8000;
      if (logger.isInfoEnabled()) logger.info("Suppressing erroneous 16000 announcement for G.722");
    }

    List<MediaFormat> supportedMediaFormats = new ArrayList<MediaFormat>();

    for (MediaFormat mediaFormat : mediaFormats) {
      if (mediaFormat.getEncoding().equalsIgnoreCase(encoding)
          && ((CLOCK_RATE_NOT_SPECIFIED == clockRate)
              || (mediaFormat.getClockRate() == clockRate))) {
        supportedMediaFormats.add(mediaFormat);
      }
    }
    return supportedMediaFormats;
  }
  private MediaFormat[] getEncodings() {
    if (encodings != null) return encodings;

    MediaFormat[] availableEncodings = encodingConfiguration.getAllEncodings(type);
    int encodingCount = availableEncodings.length;

    if (encodingCount < 1) encodings = MediaUtils.EMPTY_MEDIA_FORMATS;
    else {
      /*
       * The MediaFormats will be displayed by encoding (name) and clock
       * rate and EncodingConfiguration will store them that way so this
       * TableModel should better display unique encoding-clock rate
       * pairs.
       */
      HashMap<String, MediaFormat> availableEncodingSet = new HashMap<String, MediaFormat>();

      for (MediaFormat availableEncoding : availableEncodings) {
        availableEncodingSet.put(
            availableEncoding.getEncoding() + "/" + availableEncoding.getClockRateString(),
            availableEncoding);
      }
      availableEncodings = availableEncodingSet.values().toArray(MediaUtils.EMPTY_MEDIA_FORMATS);
      encodingCount = availableEncodings.length;

      encodings = new MediaFormat[encodingCount];
      System.arraycopy(availableEncodings, 0, encodings, 0, encodingCount);
      // Display the encodings in decreasing priority.
      Arrays.sort(
          encodings,
          0,
          encodingCount,
          new Comparator<MediaFormat>() {
            public int compare(MediaFormat format0, MediaFormat format1) {
              int ret =
                  encodingConfiguration.getPriority(format1)
                      - encodingConfiguration.getPriority(format0);

              if (ret == 0) {
                /*
                 * In the cases of equal priorities, display them
                 * sorted by encoding name in increasing order.
                 */
                ret = format0.getEncoding().compareToIgnoreCase(format1.getEncoding());
                if (ret == 0) {
                  /*
                   * In the cases of equal priorities and equal
                   * encoding names, display them sorted by clock
                   * rate in decreasing order.
                   */
                  ret = Double.compare(format1.getClockRate(), format0.getClockRate());
                }
              }
              return ret;
            }
          });
    }
    return encodings;
  }
 /**
  * Creates a <tt>MediaFormat</tt> for the specified RTP payload type with default clock rate and
  * set of format parameters. If <tt>rtpPayloadType</tt> is known to this
  * <tt>MediaFormatFactory</tt>, returns a <tt>MediaFormat</tt> which is either an
  * <tt>AudioMediaFormat</tt> or a <tt>VideoMediaFormat</tt> instance. Otherwise, returns
  * <tt>null</tt>.
  *
  * @param rtpPayloadType the RTP payload type of the <tt>MediaFormat</tt> to create
  * @return a <tt>MediaFormat</tt> with the specified <tt>rtpPayloadType</tt> which is either an
  *     <tt>AudioMediaFormat</tt> or a <tt>VideoMediaFormat</tt> instance if
  *     <tt>rtpPayloadType</tt> is known to this <tt>MediaFormatFactory</tt>; otherwise,
  *     <tt>null</tt>
  * @see MediaFormatFactory#createMediaFormat(byte)
  */
 public MediaFormat createMediaFormat(byte rtpPayloadType) {
   /*
    * We know which are the MediaFormat instances with the specified
    * rtpPayloadType but we cannot directly return them because they do not
    * reflect the user's configuration with respect to being enabled and
    * disabled.
    */
   for (MediaFormat rtpPayloadTypeMediaFormat : MediaUtils.getMediaFormats(rtpPayloadType)) {
     MediaFormat mediaFormat =
         createMediaFormat(
             rtpPayloadTypeMediaFormat.getEncoding(), rtpPayloadTypeMediaFormat.getClockRate());
     if (mediaFormat != null) return mediaFormat;
   }
   return null;
 }
 private MediaFormat createMediaFormat(
     String encoding, double clockRate, int channels, Map<String, String> fmtps) {
   for (MediaFormat format : getSupportedMediaFormats(encoding, clockRate)) {
     /*
      * The mediaType, encoding and clockRate properties are sure to
      * match because format is the result of the search for encoding and
      * clockRate. We just want to make sure that the channels and the
      * format parameters match.
      */
     if (format.matches(
         format.getMediaType(), format.getEncoding(), format.getClockRate(), channels, fmtps))
       return format;
   }
   return null;
 }
  /**
   * Creates a <tt>MediaFormat</tt> either for the specified <tt>rtpPayloadType</tt> or for the
   * specified <tt>encoding</tt>, <tt>clockRate</tt>, <tt>channels</tt> and set of format
   * parameters. If <tt>encoding</tt> is known to this <tt>MediaFormatFactory</tt>, ignores
   * <tt>rtpPayloadType</tt> and returns a <tt>MediaFormat</tt> which is either an
   * <tt>AudioMediaFormat</tt> or a <tt>VideoMediaFormat</tt> instance. If <tt>rtpPayloadType</tt>
   * is not {@link MediaFormat#RTP_PAYLOAD_TYPE_UNKNOWN} and <tt>encoding</tt> is <tt>null</tt>,
   * uses the encoding associated with <tt>rtpPayloadType</tt>.
   *
   * @param rtpPayloadType the RTP payload type to create a <tt>MediaFormat</tt> for; {@link
   *     MediaFormat#RTP_PAYLOAD_TYPE_UNKNOWN} if <tt>encoding</tt> is not <tt>null</tt>. If
   *     <tt>rtpPayloadType</tt> is not <tt>MediaFormat#RTP_PAYLOAD_TYPE_UNKNOWN</tt> and
   *     <tt>encoding</tt> is not <tt>null</tt>, <tt>rtpPayloadType</tt> is ignored
   * @param encoding the well-known encoding (name) to create a <tt>MediaFormat</tt> for;
   *     <tt>null</tt>
   * @param clockRate the clock rate in Hz to create a <tt>MediaFormat</tt> for
   * @param frameRate the frame rate in number of frames per second to create a <tt>MediaFormat</tt>
   *     for
   * @param channels the number of available channels (1 for mono, 2 for stereo) if it makes sense
   *     for the <tt>MediaFormat</tt> with the specified <tt>encoding</tt>; otherwise, ignored
   * @param formatParams any codec specific parameters which have been received via SIP/SDP or
   *     XMPP/Jingle
   * @param advancedParams any parameters which have been received via SIP/SDP or XMPP/Jingle
   * @return a <tt>MediaFormat</tt> with the specified <tt>encoding</tt>, <tt>clockRate</tt>,
   *     <tt>channels</tt> and set of format parameters which is either an <tt>AudioMediaFormat</tt>
   *     or a <tt>VideoMediaFormat</tt> instance if <tt>encoding</tt> is known to this
   *     <tt>MediaFormatFactory</tt>; otherwise, <tt>null</tt>
   */
  public MediaFormat createMediaFormat(
      byte rtpPayloadType,
      String encoding,
      double clockRate,
      int channels,
      float frameRate,
      Map<String, String> formatParams,
      Map<String, String> advancedParams) {

    /*
     * If rtpPayloadType is specified, use it only to figure out encoding
     * and/or clockRate in case either one of them is unknown.
     */
    if ((MediaFormat.RTP_PAYLOAD_TYPE_UNKNOWN != rtpPayloadType)
        && ((encoding == null) || (CLOCK_RATE_NOT_SPECIFIED == clockRate))) {
      MediaFormat[] rtpPayloadTypeMediaFormats = MediaUtils.getMediaFormats(rtpPayloadType);

      if (rtpPayloadTypeMediaFormats.length > 0) {
        if (encoding == null) encoding = rtpPayloadTypeMediaFormats[0].getEncoding();

        // Assign or check the clock rate.
        if (CLOCK_RATE_NOT_SPECIFIED == clockRate)
          clockRate = rtpPayloadTypeMediaFormats[0].getClockRate();
        else {
          boolean clockRateIsValid = false;

          for (MediaFormat rtpPayloadTypeMediaFormat : rtpPayloadTypeMediaFormats)
            if (rtpPayloadTypeMediaFormat.getEncoding().equals(encoding)
                && (rtpPayloadTypeMediaFormat.getClockRate() == clockRate)) {
              clockRateIsValid = true;
              break;
            }

          if (!clockRateIsValid) return null;
        }
      }
    }

    return createMediaFormat(
        encoding, clockRate, channels, frameRate, formatParams, advancedParams);
  }
  /**
   * Notifies this instance that the dynamic payload types of the associated {@link MediaStream}
   * have changed.
   */
  public void onDynamicPayloadTypesChanged() {
    rtxPayloadType = -1;
    rtxAssociatedPayloadType = -1;

    MediaStream mediaStream = channel.getStream();

    Map<Byte, MediaFormat> mediaFormatMap = mediaStream.getDynamicRTPPayloadTypes();

    Iterator<Map.Entry<Byte, MediaFormat>> it = mediaFormatMap.entrySet().iterator();

    while (it.hasNext() && rtxPayloadType == -1) {
      Map.Entry<Byte, MediaFormat> entry = it.next();
      MediaFormat format = entry.getValue();
      if (!Constants.RTX.equalsIgnoreCase(format.getEncoding())) {
        continue;
      }

      // XXX(gp) we freak out if multiple codecs with RTX support are
      // present.
      rtxPayloadType = entry.getKey();
      rtxAssociatedPayloadType = Byte.parseByte(format.getFormatParameters().get("apt"));
    }
  }
  public Object getValueAt(int rowIndex, int columnIndex) {
    MediaFormat encoding = getEncodings()[rowIndex];

    switch (columnIndex) {
      case 0:
        return (encodingConfiguration.getPriority(encoding) > 0);
      case 1:
        if (MediaType.VIDEO.equals(encoding.getMediaType())
            && (VideoMediaFormatImpl.DEFAULT_CLOCK_RATE == encoding.getClockRate()))
          return encoding.getEncoding();
        else {
          return encoding.getEncoding() + "/" + encoding.getRealUsedClockRateString();
        }
      default:
        return null;
    }
  }