/**
   * Checks whether RTP packets from {@code sourceChannel} should be forwarded to {@link #channel}.
   *
   * @param sourceChannel the channel.
   * @return {@code true} iff RTP packets from {@code sourceChannel} should be forwarded to {@link
   *     #channel}.
   */
  public boolean isForwarded(Channel sourceChannel) {
    if (lastN < 0 && currentLastN < 0) {
      // If Last-N is disabled, we forward everything.
      return true;
    }

    if (sourceChannel == null) {
      logger.warn("Invalid sourceChannel: null.");
      return false;
    }

    Endpoint channelEndpoint = sourceChannel.getEndpoint();
    if (channelEndpoint == null) {
      logger.warn("sourceChannel has no endpoint.");
      return false;
    }

    if (forwardedEndpoints == INITIAL_EMPTY_LIST) {
      // LastN is enabled, but we haven't yet initialized the list of
      // endpoints in the conference.
      initializeConferenceEndpoints();
    }

    // This may look like a place to optimize, because we query an unordered
    // list (in O(n)) and it executes on each video packet if lastN is
    // enabled. However, the size of  forwardedEndpoints is restricted to
    // lastN and so small enough that it is not worth optimizing.
    return forwardedEndpoints.contains(channelEndpoint.getID());
  }
 /** {@inheritDoc} */
 @Override
 public void expire() {
   try {
     eventDispatcher.shutdown();
   } finally {
     super.expire();
   }
 }