title: WebRTC state checking
body: <p>I would like connect 2 devices with WebRTC on localhost. All devices have no internet access.  They are connected to a same local wifi.</p>
  
  <p>I try this on React Native App.</p>
  
  <p>In this context offline, do I need to trickle ICE candidates and <code>addIceCandidate</code> ? If I understund correctly, ICE candidates is for <code>iceServer</code>. But my case, <code>iceServer</code> is null (because i'm offline only, connected on same localhost wifi) : </p>
  
  <p><code>const configuration = { iceServers: [{ urls: [] }] };</code></p>
  
  <p>So actualty i exchange offer and answer, but after <code>setRemoteDescription</code> the answer, the <code>connectionState</code> stay on <code>checking</code>.</p>
  
  <p>You can see my React Component : </p>
  
  <pre><code>  constructor(props) {
      super(props);
      this.pc = new RTCPeerConnection(configuration);
    }
  
    state = initialState;
  
    componentDidMount() {
      const { pc } = this;
  
      if (pc) {
        this.setState({
          peerCreated: true
        });
      }
  
      this.setConnectionState();
  
      pc.oniceconnectionstatechange = () =&gt; this.setConnectionState();
  
      pc.onaddstream = ({ stream }) =&gt; {
        if (stream) {
          this.setState({
            receiverVideoURL: stream.toURL()
          });
        }
      };
  
      pc.onnegotiationneeded = () =&gt; {
        if (this.state.initiator) {
          this.createOffer();
        }
      };
  
      pc.onicecandidate = ({ candidate }) =&gt; {
        if (candidate === null) {
          const { offer } = this.state;
          const field = !offer ? 'offer' : 'data';
  
          setTimeout(() =&gt; {
            alert('setTimeout started');
            this.setState({
              [field]: JSON.stringify(pc.localDescription)
            });
          }, 2000);
        }
      };
    }
  
    @autobind
    setConnectionState() {
      this.setState({
        connectionState: this.pc.iceConnectionState
      });
    }
  
    getUserMedia() {
      MediaStreamTrack.getSources(() =&gt; {
        getUserMedia(
          {
            audio: false,
            video: true
          },
          this.getUserMediaSuccess,
          this.getUserMediaError
        );
      });
    }
  
    @autobind
    async getUserMediaSuccess(stream) {
      const { pc } = this;
  
      pc.addStream(stream);
  
      await this.setState({ videoURL: stream.toURL() });
  
      if (this.state.initiator) {
        return this.createOffer();
      }
  
      return this.createAnswer();
    }
  
    getUserMediaError(error) {
      console.log(error);
    }
  
    @autobind
    logError(error) {
      const errorArray = [...this.state.error, error];
      return this.setState({
        error: errorArray
      });
    }
  
    /**
     * Create offer
     *
     * @memberof HomeScreen
     */
    @autobind
    createOffer() {
      const { pc } = this;
  
      pc.createOffer()
        .then(offer =&gt; pc.setLocalDescription(offer))
        .then(() =&gt; {
          this.setState({
            offerCreated: true
          });
        })
        .catch(this.logError);
    }
  
    /**
     * Create anwser
     *
     * @memberof HomeScreen
     */
    @autobind
    async createAnswer() {
      const { pc } = this;
      const { data } = this.state;
  
      if (data) {
        const sd = new RTCSessionDescription(JSON.parse(data));
  
        await this.setState({
          offerImported: true
        });
  
        pc.setRemoteDescription(sd)
          .then(() =&gt; pc.createAnswer())
          .then(answer =&gt; pc.setLocalDescription(answer))
          .then(() =&gt; {
            this.setState({
              answerCreated: true
            });
          })
          .catch(this.logError);
      }
    }
  
    @autobind
    receiveAnswer() {
      const { pc } = this;
      const { data } = this.state;
      const sd = new RTCSessionDescription(JSON.parse(data));
  
      return pc
        .setRemoteDescription(sd)
        .then(() =&gt; {
          this.setState({
            answerImported: true
          });
        })
        .catch(this.logError);
    }
  
    /**
     * Start communication
     *
     * @param {boolean} [initiator=true]
     * @returns
     * @memberof HomeScreen
     */
    @autobind
    async start(initiator = true) {
      if (!initiator) {
        await this.setState({
          initiator: false
        });
      }
  
      return this.getUserMedia();
    }
  </code></pre>
  
  <p>Anyone can help me?</p>