【问题标题】:WebRTC state checkingWebRTC 状态检查
【发布时间】:2018-12-03 07:49:29
【问题描述】:

我想在 localhost 上使用 WebRTC 连接 2 台设备。所有设备都无法访问互联网。它们连接到同一个本地 wifi。

我在 React Native App 上试试这个。

在这种离线情况下,我是否需要涓流 ICE 候选人和 addIceCandidate ?如果我理解正确的话,ICE 候选人是iceServer。但我的情况,iceServer 是空的(因为我只离线,连接在同一个 localhost wifi 上):

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

所以实际上我交换了offer和answer,但是在setRemoteDescription回答之后,connectionState留在checking

你可以看到我的 React 组件:

  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(() => {
          alert('setTimeout started');
          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 HomeScreen
   */
  @autobind
  createOffer() {
    const { pc } = this;

    pc.createOffer()
      .then(offer => pc.setLocalDescription(offer))
      .then(() => {
        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(() => 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 HomeScreen
   */
  @autobind
  async start(initiator = true) {
    if (!initiator) {
      await this.setState({
        initiator: false
      });
    }

    return this.getUserMedia();
  }

谁能帮帮我?

【问题讨论】:

    标签: react-native webrtc


    【解决方案1】:

    iceServers 在 LAN 上没有问题,但对等点仍必须交换至少一个候选者:他们的 主机 候选者(基于他们机器的 LAN IP 地址)。

    要么:

    1. 像往常一样使用onicecandidate -> 信令-> addIceCandidate 的涓流候选者,或者

    2. 在交换 pc.localDescription 之前等待 ICE 进程(几秒钟)。

    看起来您正在尝试后者。这种方法之所以有效,是因为...

    Trickle ICE 是一种优化。

    使用onicecandidate 向单个候选ICE 发出信号(滴流)是一种旨在加快协商速度的优化。一旦setLocalDescription 成功,浏览器的内部ICE 代理 就会启动,将发现的ICE 候选者插入localDescription 本身。等待几秒钟进行协商,根本不需要涓涓细流:所有 ICE 候选人都将在报价中并传输答案。

    您的代码

    从您的 onicecandidate 代码看来,您已经在尝试在 ICE 完成后收集 localDescription(并且您已经将其编写为从两端工作):

    pc.onicecandidate = ({ candidate }) => {
      if (!candidate) {
        const { offer } = this.state;
        const field = !offer ? 'offer' : 'data';
    
        this.setState({
          [field]: JSON.stringify(pc.localDescription)
        });
      }
    };
    

    在报价方方面,您已正确注释掉 createOffer 中的等效代码:

    pc.createOffer()
      .then(offer => pc.setLocalDescription(offer))
      .catch(this.logError);
    // .then(() => {
    //   this.setState({
    //     offer: JSON.stringify(pc.localDescription)
    //   });
    // });
    

    但在回答者方面,你没有,这很可能是问题所在:

    createAnswer() {
        const { pc } = this;
        const { data } = this.state;
    
        if (data) {
          const sd = new RTCSessionDescription(JSON.parse(data));
    
          pc.setRemoteDescription(sd)
            .then(() => pc.createAnswer())
            .then(answer => pc.setLocalDescription(answer))
            .then(() => {
              this.setState({
                offer: JSON.stringify(pc.localDescription)
              });
            })
            .catch(this.logError);
        }
      }
    

    这意味着它会在回答者的 ICE 代理 有时间将任何候选人插入答案之前立即发回答案。 这可能是它失败的原因。

    附带说明:似乎也没有什么可以等待 getUserMedia 完成,因此答案可能也不包含任何视频,具体取决于您的 getUserMediaSuccess 函数的时间安排,无法将任何轨道或​​流添加到连接。但假设你只是在做数据通道,这应该适用于我推荐的修复。

    【讨论】:

    • 嗨,小臂!谢谢你的好帖子。我已尝试使用您推荐的修复程序,但结果相同,启动器保持检查状态。我已经编辑了我的第一篇文章。我注意到状态应答方永远不会改变:总是留在new,也许是问题?
    • 我继续我的测试。我发现,一旦在 answer 端导入了 offer,pc.signalingState 从`stable` 变为have-remote-offer 1 秒钟,然后又变回`stable`。我不知道问题是来自报价还是答案的生成:/手机在同一个wifi连接共享上:/
    • signalingState 听起来很正常。
    • Arf,我以为问题出在那儿^^
    • 也许我在this other answer 中的剪切粘贴演示会有所帮助。
    猜你喜欢
    • 2016-09-27
    • 2016-01-09
    • 2021-11-17
    • 1970-01-01
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多