Salut les amis,

Je recherche à créer une connection entre deux téléphones en WebRTC et dans un contexte offline (aucun connexion à l'extérieur, mais les deux téléphones sont sur le même réseau local, connecté en wifi). Ce schéma ce déroule dans une app React Native.

Ce que je fais

Etant donné que je suis en local uniquement, je n'ai pas besoin d'utiliser de serveur ICE.

Pour l'instant je cherche à effectuer la base : échange de l'offre et de la réponse. Voici ce que donne mon component React :

 const configuration = { iceServers: [{ urls: [] }] };

  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 = () => this.setConnectionState();

    pc.onaddstream = ({ stream }) => {
      if (stream) {
        this.setState({
          receiverVideoURL: stream.toURL()
        });
      }
    };

    pc.onnegotiationneeded = () => {
      if (this.state.initiator) {
        this.createOffer();
      }
    };

    pc.onicecandidate = ({ candidate }) => {
      if (candidate === null) {
        const { offer } = this.state;
        const field = !offer ? 'offer' : 'data';

        setTimeout(() => {
          this.setState({
            [field]: JSON.stringify(pc.localDescription)
          });
        }, 2000);
      }
    };
  }

  @autobind
  setConnectionState() {
    this.setState({
      connectionState: this.pc.iceConnectionState
    });
  }

  getUserMedia() {
    MediaStreamTrack.getSources(() => {
      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 InitiatorScreen
   */
  @autobind
  createOffer() {
    const { pc } = this;

    pc.createOffer()
      .then(offer => pc.setLocalDescription(offer))
      .then(() => {
        this.setState({
          offerCreated: true
        });
      })
      .catch(this.logError);
  }

  /**
   * Create anwser
   *
   * @memberof InitiatorScreen
   */
  @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(() => pc.createAnswer())
        .then(answer => pc.setLocalDescription(answer))
        .then(() => {
          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(() => {
        this.setState({
          answerImported: true
        });
      })
      .catch(this.logError);
  }

  /**
   * Start communication
   *
   * @param {boolean} [initiator=true]
   * @returns
   * @memberof InitiatorScreen
   */
  @autobind
  async start(initiator = this.state.initiator) {
    if (initiator) {
      await this.setState({
        initiator: true
      });
    }

    return this.getUserMedia();
  }

Ce que j'obtiens

Une fois l'offre et la réponse échanger sur les deux téléphones (pour l'instant, l'échange est via slack pour les tests), le connectionState reste sur checking, uniquement du côté de l'initiator, celui qui créer l'offre.

Du côté answer, le state ne bouge jamais, il reste à new (celui par défaut).

Je ne comprends pas pourquoi le connectionState de mon answer ne change jamais. L'offre est pourquoi gérée, puis importé dans new RTCSessionDescription(JSON.parse(data));.

Auriez-vous une petite idée ? J'imagine qu'il y a quelque chose que je dois mal faire :D

Merci à vous !

EDIT :

J'ai découvert qu'une fois l'offre importé du côté answer, pc.signalingState passe de stable à have-remote-offer pendant 1 seconde (vraiment rapide), puis revient à stable. Du coup, cela cofirme qu'il y a un problème soit du côté de l'offre générée, soit du côté de la réponse. Mais comment savoir ? :/

Les deux téléphones sont bien sur le même wifi, en partage de connexion.

Aucune réponse