Re: [webrtc-pc] offerToReceive* legacy behaviour spec does not match the behaviour of legacy implementations

I think we need to figure out when state is created and modified and if that has changed in the evolution from the streams model to the transceiver model.

When I say that in the addStreams model createOffer is stateless I mean that it does not modify the state on the peerconnection object. I think you mean that the offer that is created carries state. Two sides of the same coin. This is somewhat consistent with Chrome's behaviour when you do this
```
var pc = new RTCPeerConnection();
pc.createOffer({offerToReceiveAudio: true})
.then(offer => {
  console.log(offer.sdp)
  return pc.createOffer({offerToReceiveAudio: true});
})
.then(offer => {
  console.log(offer.sdp)
});
```
the ice-ufrag and ice-pwd change. Note that Firefox behaves slightly different and does not change the ice-ufrag/ice-pwd. Both implementations use the same fingerprint which suggests that createOffer does not create a certificate but it is created earlier (as the spec suggests for the constructor).

Only once you call setLocalDescription with an offer the peerconnection future calls to createOffer will return the same ufrag/pwd.
In the [ORTC-peerconnection shim](https://github.com/webrtc/adapter/pull/136) I created RTPSenders in createOffer as well. Which might have been wrong, [this shows another interpretation which seems to work](https://github.com/twilio/ortc-adapter/blob/master/lib/rtcpeerconnection.js#L401).

My interpretation of createOffer in the transceivers model is that it merely dumps the internal state of the peerconnection into a blob of SDP. Roughly like like:
```
let sdp = createSessionPart()
pc.transceivers.forEach(transceiver => {
   sdp += generateMediaSection(transceiver);
})
return {type: offer, sdp}
```
The transceivers are created by createTransceiver or addTrack.

The problem we have now is that offerToReceive* not only dumps state but potentially modifies it.
As jib says,  "will behave as if addTransceiver("audio") had been called once" leaves a bit of leeway. I am interpreting it as "call addTransceiver", i.e.
```
if (offerToReceiveAudio)
  pc.createTransceiver(audio); // adds a audio transceiver to pc.transceivers
let sdp = createSessionPart();
pc.transceivers.forEach(transceiver => {
   sdp += generateMediaSection(transceiver);
})
return {type: offer, sdp};
```
which is very convenient and straightforward to implement. Also it does not create objects with a limited lifetime that are only loosely bound to the peerconnection. But it does not act like the legacy implementation.

To make things worse consider this assuming that offerToReceiveAudio does not call addTransceiver but creates some temporary transceiver:
```
var pc = new RTCPeerConnection();
let r1;
let r2;
pc.createOffer({offerToReceiveAudio: true})
.then(() => {
  r1 = pc.getReceivers()[0];
  return pc.createOffer({offerToReceiveAudio: true});
})
.then(() => {
  r2 = pc.getReceivers()[0];
});
```
Two questions:
1) is r1 set? I.e. does the call to getReceivers() return anything? (I need to review the getReceivers algorithm)
2) If the answer to (1) is yes, does r1 === r2 hold, i.e. is the same object returned?

-- 
GitHub Notification of comment by fippo
Please view or discuss this issue at https://github.com/w3c/webrtc-pc/issues/1383#issuecomment-308647050 using your GitHub account

Received on Thursday, 15 June 2017 07:02:28 UTC