- From: Jan-Ivar Bruaroey via GitHub <sysbot+gh@w3.org>
- Date: Thu, 09 Jul 2020 15:21:50 +0000
- To: public-webrtc@w3.org
jan-ivar has just created a new issue for https://github.com/w3c/webrtc-extensions:
== When is negotiation complete? ==
A problem arose while writing [perfect negotiation](https://w3c.github.io/webrtc-pc/#perfect-negotiation-example) [wpt tests](https://phabricator.services.mozilla.com/D66817#C2294894NL1): When is negotiation complete?
You know, something like:
```js
const transceiver = pc.addTransceiver("video");
await /* some event or promise */
assert_equals(transceiver.currentDirection, "sendonly", "negotiates to sendonly");
```
Naively, one might think this works:
```js
const state = (pc, s) => new Promise(r => pc.onsignalingstatechange =
() => pc.signalingState == s && r());
const transceiver = pc.addTransceiver("video");
await state(pc, "stable");
assert_equals(transceiver.currentDirection, "sendonly", "negotiates to sendonly");
```
Unfortunately, outside a lab, →`"stable"` might come from rollback, or answering a remote offer.
Or even from _juuust_ missing our own negotiation train triggered by a previous local action.
This leaves us stuck writing action-specific spin-tests, not a great API:
```js
const transceiver = pc.addTransceiver("video");
while (!transceiver.currentDirection) {
await state(pc, "stable");
}
assert_true(true, "we didn't time out!");
assert_equals(transceiver.currentDirection, "sendonly", "negotiates to sendonly");
```
So I tried solving this in JS by dispatching my own `negotiated` event in SRD(answer):
```js
// - The perfect negotiation logic, separated from the rest of the application ---
signaling.onmessage = async ({data: {description, candidate}}) => {
try {
if (description) {
const offerCollision = description.type == "offer" &&
(makingOffer || pc.signalingState != "stable");
ignoreOffer = !polite && offerCollision;
if (ignoreOffer) {
return;
}
await pc.setRemoteDescription(description); // SRD rolls back as needed
if (description.type == "offer") {
await pc.setLocalDescription();
signaling.send({description: pc.localDescription});
} else {
pc.dispatchEvent(new Event("negotiated")); // <--- here!
}
} else if (candidate) {
```
This avoids rollbacks and remote offers, but we _still_ have to account for just missing a local train:
```js
const negotiated = pc => new Promise(r => pc.addEventListener("negotiated", r,
{once: true});
const transceiver = pc.addTransceiver("video");
await negotiated(pc);
if (!transceiver.currentDirection) {
await negotiated(pc); // catch the next train
}
assert_equals(transceiver.currentDirection, "sendonly", "We're negotiated!");
```
This avoids the dreaded `while` loop. But who's going to remember this over some intermittent?
Please view or discuss this issue at https://github.com/w3c/webrtc-extensions/issues/45 using your GitHub account
Received on Thursday, 9 July 2020 15:21:52 UTC