【问题标题】:WebRTC connection does not resume after mobile browser is backgrounded移动浏览器后台运行后,WebRTC 连接不会恢复
【发布时间】:2022-12-15 09:17:07
【问题描述】:

我有一个在 iPad 上的 Safari 上运行的 Web 应用程序,显示实时 WebRTC 视频流。当用户离开 Safari 几秒钟,然后再切换回来时,<video> 元素只显示一个黑色矩形。

我已将日志记录添加到 onsignalingstatechange 处理程序,并在恢复 Safari 后检查控制台日志是否有任何明显的错误,但没有任何明显的失败迹象。

用户切换回 Safari 后如何恢复/恢复/重新启动流?

这是我的 cargo cult WebRTC 代码,供参考:

export default class WebRtcPlayer {
  static server = "http://127.0.0.1:8083";

  server = null;
  stream = null;
  channel = null;

  webrtc = null;
  mediastream = null;
  video = null;

  constructor(id, stream, channel) {
    this.server = WebRtcPlayer.server;
    this.video = document.getElementById(id);
    this.stream = stream;
    this.channel = channel;

    this.video.addEventListener("loadeddata", () => {
      this.video.play();
    });

    this.video.addEventListener("error", () => {
      console.error("video error");
    });

    this.play();
  }

  getStreamUrl() {
    // RTSPtoWeb only, not RTSPtoWebRTC
    return `${this.server}/stream/${this.stream}/channel/${this.channel}/webrtc`;
  }

  async play() {
    console.log("webrtc play");
    this.mediastream = new MediaStream();
    this.video.srcObject = this.mediastream;

    this.webrtc = new RTCPeerConnection({
      iceServers: [{
        urls: ["stun:stun.l.google.com:19302"],
      }],
      sdpSemantics: "unified-plan"
    });

    this.webrtc.onnegotiationneeded = this.handleNegotiationNeeded.bind(this);
    this.webrtc.onsignalingstatechange = this.handleSignalingStateChange.bind(this);
    this.webrtc.ontrack = this.handleTrack.bind(this);

    this.webrtc.addTransceiver("video", {
      "direction": "sendrecv",
    });
  }

  async handleNegotiationNeeded() {    
    console.log("handleNegotiationNeeded");
    let offer = await this.webrtc.createOffer({
      offerToReceiveAudio: false,
      offerToReceiveVideo: true
    });
    await this.webrtc.setLocalDescription(offer);
  }

  async handleSignalingStateChange() {
    console.log(`handleSignalingStateChange ${this.webrtc.signalingState}`);
    switch (this.webrtc.signalingState) {
      case "have-local-offer":
        let formData = new FormData();
        formData.append("data", btoa(this.webrtc.localDescription.sdp));
        const response = await fetch(this.getStreamUrl(), {
          method: "POST",
          body: formData,
        });

        this.webrtc.setRemoteDescription(new RTCSessionDescription({
          type: "answer",
          sdp: atob(await response.text()),
        }));

        break;

      case "stable":
        /*
        * There is no ongoing exchange of offer and answer underway.
        * This may mean that the RTCPeerConnection object is new, in which case both the localDescription and remoteDescription are null;
        * it may also mean that negotiation is complete and a connection has been established.
        */
        break;

      case "closed":
        /*
        * The RTCPeerConnection has been closed.
        */
        break;

      default:
        console.log(`unhandled signalingState is ${this.webrtc.signalingState}`);
        break;
    }
  }

  handleTrack(event) {
    console.log("handle track");
    this.mediastream.addTrack(event.track);
  }

  static setServer(serv) {
    this.server = serv;
  }
}

【问题讨论】:

    标签: ios webrtc html5-video mobile-safari ipados


    【解决方案1】:

    我不确定这是否是最好的方式,但我使用Page Visibility API 订阅了visibilitychange 事件:

        document.addEventListener("visibilitychange", () => {
           if (document.visibilityState === "visible") {
             console.log("Document became visible, restarting WebRTC stream.");
             this.play();
           }
         });
    

    【讨论】:

      猜你喜欢
      • 2018-10-25
      • 2015-06-20
      • 2017-07-19
      • 1970-01-01
      • 2019-01-16
      • 2013-06-18
      • 2021-09-20
      • 2013-08-16
      • 1970-01-01
      相关资源
      最近更新 更多