code: public void setDataSource(DataSource dataSource) throws IOException {
      Exception e = exceptions.get(dataSource);
      if (e != null) {
        e.fillInStackTrace();
        if (e instanceof IOException) {
          throw (IOException) e;
        } else if (e instanceof RuntimeException) {
          throw (RuntimeException) e;
        }
        throw new AssertionError("Invalid exception type for setDataSource: <" + e + '>');
      }
      checkStateException("setDataSource()", idleState);
      doSetDataSource(dataSource);
      state = INITIALIZED;
    }
docs: Common code path for all {@code setDataSource()} implementations.
  
  <p>* Checks for any specified exceptions for the specified data source and throws them. *
  Checks the current state and throws an exception if it is in an invalid state. * If no
  exception is thrown in either of the previous two steps, then {@link
  #doSetDataSource(DataSource)} is called to set the data source. * Sets the player state to
  {@code INITIALIZED}. Usually this method would not be called directly, but indirectly through
  one of the other {@link #setDataSource(String)} implementations, which use {@link
  DataSource#toDataSource(String)} methods to convert their discrete parameters into a single
  {@link DataSource} instance.
  
  @param dataSource the data source that is being set.
  @throws IOException if the specified data source has been configured to throw an IO exception.
  @see #addException(DataSource, IOException)
  @see #addException(DataSource, RuntimeException)
  @see #doSetDataSource(DataSource)