简体   繁体   中英

Why does WebRTC set up a connection only after second offer?

I want to set up a WebRTC datachannel and send some text. Therefore I create a RTCPeerConnection object with an "onicecandidate" and "ondatachannel" handler. (I keep "configuration" for RTCPeerConnection empty because connection is between localhost only.)

var configuration = {}; 
myConnection = new RTCPeerConnection(configuration);
  
myConnection.onicecandidate = function (event) {
    if (event.candidate) { 
        send({ 
            type: "candidate", 
            candidate: event.candidate 
        }); 
    } 
};

myConnection.ondatachannel = function (event) {
    dataChannel = event.channel;
    dataChannel.onerror = function (error) { 
        console.log("Error:", error); 
    };
                
    dataChannel.onmessage = function (event) { 
        console.log("RTC message:", event.data); 
    };  
};

Then I'm sending an offer from A to B.

offer = await myConnection.createOffer();
await myConnection.setLocalDescription(offer);
send({type: "offer", offer: offer});

Receiver B then sends an answer.

async function onOffer(offer, name) { 
    myConnection.setRemoteDescription(new RTCSessionDescription(offer));

    answer = await myConnection.createAnswer();
    await myConnection.setLocalDescription(answer);
    send({type: "answer", answer: answer});
}

Which A sets as remote description and opens up the datachannel.

function onAnswer(answer) { 
    myConnection.setRemoteDescription(new RTCSessionDescription(answer));
    openDataChannel();
}

function openDataChannel() { 
    var dataChannelOptions = { 
        reliable:true 
    }; 
    
    dataChannel = myConnection.createDataChannel("myDataChannel", dataChannelOptions);
        
    dataChannel.onerror = function (error) { 
        console.log("Error:", error); 
    };
        
    dataChannel.onmessage = function (event) { 
        console.log("RTC message:", event.data); 
    };  
}

There is also a function which handles the received candidates on both sides.

function onCandidate(candidate) { 
    myConnection.addIceCandidate(new RTCIceCandidate(candidate));
}

After A sends the first offer, it receives an answer but the "iceGatheringState" and "iceConnectionState" of the RTCPeerConnection stays "new". No "onicecandidate" events are triggered. After A calls createOffer() again, the offer looks "bigger" (contains more values). After setting the second offer to local description "onicecandicate" events are fired on both sides. But the datachannel only establishes after A sends the second offer to B.

I know this is the same question but the answer doesn't seem to fit because I have an "onicecandidate" handler. I also read about trickle ice but still don't know what the issue is.

You must call myConnection.createDataChannel at least once before negotiating, to have the connection negotiate the use of datachannels. They're not included by default.

There's no media and no datachannel before then, nothing to negotiate. This makes your first negotiation redundant, a no-op, which is why the state never leave "new" .

Once you've done this, there's no need to do it again, as all subsequent datachannels are multiplexed over the same sctp transport.

To have negotiation only happen when needed, consider setting up:

pc.onnegotiationneeded = async () => {
  try {
    await pc.setLocalDescription(await pc.createOffer());
    send({type: "offer", offer: pc.localDescription});
  } catch (e) {
    console.error(e);
  }
};

Then negotiation will be triggered automatically when you call pc.createDataChannel the first time (but not the subsequent times).

But beware of glare if you do this on both ends, or use the perfect negotiation pattern.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM