code: private void setupAudioChannelInbound(MediaDescriptionField remoteAudio) throws IOException {
          // Negotiate audio codecs
          this.audioChannel.negotiateFormats(remoteAudio);
          if (!this.audioChannel.containsNegotiatedFormats()) {
              throw new IOException("Audio codecs were not supported");
          }
  
          // Bind audio channel to an address provided by UdpManager
          this.audioChannel.bind(false, remoteAudio.isRtcpMux());
  
          boolean enableIce = remoteAudio.containsIce();
          if (enableIce) {
              // Enable ICE. Wait for ICE handshake to finish before connecting RTP/RTCP channels
              this.audioChannel.enableICE(this.externalAddress, remoteAudio.isRtcpMux());
          } else {
              String remoteAddr = remoteAudio.getConnection().getAddress();
              this.audioChannel.connectRtp(remoteAddr, remoteAudio.getPort());
              this.audioChannel.connectRtcp(remoteAddr, remoteAudio.getRtcpPort());
          }
  
          // Enable DTLS according to remote SDP description
          boolean enableDtls = this.remoteSdp.containsDtls();
          if (enableDtls) {
              FingerprintAttribute fingerprint = this.remoteSdp.getFingerprint(audioChannel.getMediaType());
              this.audioChannel.enableDTLS(fingerprint.getHashFunction(), fingerprint.getFingerprint());
          }
      }
docs: Reads the remote SDP offer and sets up the available resources according to the call type.
  
  @param remoteAudio The description of the remote audio channel.
  
  @throws IOException When binding the audio data channel or when failing to negotiate codecs.