/**
   * Sets the values of the properties of a specific <tt>ColibriConferenceIQ</tt> to the values of
   * the respective properties of this instance. Thus, the specified <tt>iq</tt> may be thought of
   * as a description of this instance.
   *
   * <p><b>Note</b>: The copying of the values is deep i.e. the <tt>Contents</tt>s of this instance
   * are described in the specified <tt>iq</tt>.
   *
   * @param iq the <tt>ColibriConferenceIQ</tt> to set the values of the properties of this instance
   *     on
   */
  public void describeDeep(ColibriConferenceIQ iq) {
    describeShallow(iq);

    if (isRecording()) {
      ColibriConferenceIQ.Recording recordingIQ =
          new ColibriConferenceIQ.Recording(State.ON.toString());
      recordingIQ.setDirectory(getRecordingDirectory());
      iq.setRecording(recordingIQ);
    }
    for (Content content : getContents()) {
      ColibriConferenceIQ.Content contentIQ = iq.getOrCreateContent(content.getName());

      for (Channel channel : content.getChannels()) {
        if (channel instanceof SctpConnection) {
          ColibriConferenceIQ.SctpConnection sctpConnectionIQ =
              new ColibriConferenceIQ.SctpConnection();

          channel.describe(sctpConnectionIQ);
          contentIQ.addSctpConnection(sctpConnectionIQ);
        } else {
          ColibriConferenceIQ.Channel channelIQ = new ColibriConferenceIQ.Channel();

          channel.describe(channelIQ);
          contentIQ.addChannel(channelIQ);
        }
      }
    }
  }
  /**
   * Notifies this <tt>Conference</tt> that the ordered list of <tt>Endpoint</tt>s of {@link
   * #speechActivity} i.e. the dominant speaker history has changed.
   *
   * <p>This instance notifies the video <tt>Channel</tt>s about the change so that they may update
   * their last-n lists and report to this instance which <tt>Endpoint</tt>s are to be asked for
   * video keyframes.
   */
  private void speechActivityEndpointsChanged() {
    List<Endpoint> endpoints = null;

    for (Content content : getContents()) {
      if (MediaType.VIDEO.equals(content.getMediaType())) {
        Set<Endpoint> endpointsToAskForKeyframes = null;

        endpoints = speechActivity.getEndpoints();
        for (Channel channel : content.getChannels()) {
          if (!(channel instanceof RtpChannel)) continue;

          RtpChannel rtpChannel = (RtpChannel) channel;
          List<Endpoint> channelEndpointsToAskForKeyframes =
              rtpChannel.speechActivityEndpointsChanged(endpoints);

          if ((channelEndpointsToAskForKeyframes != null)
              && !channelEndpointsToAskForKeyframes.isEmpty()) {
            if (endpointsToAskForKeyframes == null) {
              endpointsToAskForKeyframes = new HashSet<>();
            }
            endpointsToAskForKeyframes.addAll(channelEndpointsToAskForKeyframes);
          }
        }

        if ((endpointsToAskForKeyframes != null) && !endpointsToAskForKeyframes.isEmpty()) {
          content.askForKeyframes(endpointsToAskForKeyframes);
        }
      }
    }
  }