/**
   * Changes the current video settings for the peer with the desired quality settings and inform
   * the peer to stream the video with those settings.
   *
   * @param preset the desired video settings
   * @throws MediaException when the re-invite fails
   */
  @Override
  public void setPreferredRemoteSendMaxPreset(QualityPreset preset) throws MediaException {
    QualityControl qControls = getMediaQualityControl();

    if (qControls != null) {
      qControls.setRemoteSendMaxPreset(preset);
      try {
        // re-invites the peer with the new settings
        peer.sendReInvite();
      } catch (Throwable cause) {
        String message = "Failed to re-invite for video quality change.";

        logger.error(message, cause);

        throw new MediaException(message, MediaException.GENERAL_ERROR, cause);
      }
    }
  }
  /**
   * Implements {@link PacketListener}. Notifies this instance that a specific {@link Packet} (which
   * this instance has already expressed interest into by returning <tt>true</tt> from {@link
   * #accept(Packet)}) has been received.
   *
   * @param packet the <tt>Packet</tt> which has been received and which this instance is given a
   *     chance to process
   */
  public void processPacket(Packet packet) {
    /*
     * As we do elsewhere, acknowledge the receipt of the Packet first and
     * then go about our business with it.
     */
    IQ iq = (IQ) packet;

    if (iq.getType() == IQ.Type.SET)
      protocolProvider.getConnection().sendPacket(IQ.createResultIQ(iq));

    /*
     * Now that the acknowledging is out of the way, do go about our
     * business with the Packet.
     */
    ColibriConferenceIQ conferenceIQ = (ColibriConferenceIQ) iq;
    boolean interrupted = false;

    try {
      processColibriConferenceIQ(conferenceIQ);
    } catch (Throwable t) {
      logger.error(
          "An error occurred during the processing of a " + packet.getClass().getName() + " packet",
          t);

      if (t instanceof InterruptedException) {
        /*
         * We cleared the interrupted state of the current Thread by
         * catching the InterruptedException. However, we do not really
         * care whether the current Thread has been interrupted - we
         * caught the InterruptedException because we want to swallow
         * any Throwable. Consequently, we should better restore the
         * interrupted state.
         */
        interrupted = true;
      } else if (t instanceof ThreadDeath) throw (ThreadDeath) t;
    }
    if (interrupted) Thread.currentThread().interrupt();
  }