How to set remote description for a WebRTC caller in Chrome without errors?

后端 未结 1 1234
慢半拍i
慢半拍i 2020-12-11 17:19

I hope there is no flaw in the logic.

Step 1: caller creates offer

Step 2: caller sets localDescription

Ste

相关标签:
1条回答
  • 2020-12-11 18:03

    Your code is correct. This is a long-standing bug in Chrome with negotiationneeded.

    I've instrumented it in a fiddle (right-click and open in TWO adjacent windows, then click call in one).

    In Firefox, it works. The offerer negotiates once because you add two tracks (video/audio) at once:

    negotiating in stable
    onmessage answer
    

    and, on the answerer side, the tracks you add outside of 'stable' state are added to the answer:

    onmessage offer
    adding audio track
    adding video track
    

    But in Chrome, it's broken, firing negotiationneeded twice on the offerer, once per track added:

    negotiating in stable
    negotiating in stable
    onmessage offer
    DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection':
      Failed to set remote offer sdp: Called in wrong state: kHaveLocalOffer
    onmessage offer
    DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection':
      Failed to set remote offer sdp: Called in wrong state: kHaveLocalOffer
    onmessage offer
    DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection':
      Failed to set remote offer sdp: Called in wrong state: kHaveLocalOffer
    

    and firing negotiationneeded twice on the answerer side, which isn't even in 'stable' state:

    onmessage offer
    adding audio track
    adding video track
    negotiating in have-remote-offer
    negotiating in have-remote-offer
    onmessage offer
    DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection':
      Failed to set remote offer sdp: Called in wrong state: kHaveLocalOffer
    

    These extra events cause the havoc of reciprocal state errors seen on both ends here.

    To be specific, Chrome violates two parts of the spec here:

    1. "Queue a task" to fire this event. "queueing prevents negotiationneeded from firing prematurely, in the common situation where multiple modifications to connection are being made at once."

    2. If connection's signaling state is not "stable", abort these steps [to fire the event].

    Workaround

    Working around both Chrome bugs requires (using async/await for brevity):

    let negotiating = false;
    pc.onnegotiationneeded = async e => {
      try {
        if (negotiating || pc.signalingState != "stable") return;
        negotiating = true;
        /* Your async/await-using code goes here */
      } finally {
        negotiating = false;
      }
    }
    
    0 讨论(0)
提交回复
热议问题