We expose _transceiver._[[Sender]].[[SenderTransport]] to JS, which can then hold on to it:
pc.onnegotiationneeded = () => { /* negotiation code */ };
const transport1 = pc.getTransceivers()[0].sender.transport;
const transport2 = pc.getTransceivers()[1].sender.transport;
There are a couple of ways to shut down a transport:
pc.getTransceivers()[0].stop()pc.setConfiguration({bundlePolicy: "max-bundle"}) if it were previously "max-compat".What, if anything should happen to transport.state and transport2.state?
Also, will events still fire on these objects? Will getRemoteCertificates() work or throw something?
I wasn't able to repro any of these circumstances in Chrome because of the lack of transceiver.stop() and https://bugs.chromium.org/p/chromium/issues/detail?id=1058826.
Proposal: Close the transport (i.e. fire the close event) and then freeze the object. getRemoteCertificates() would continue to return its previous value.
@aboba does this note mean the "closed" RTCDtlsTransportState is not terminal?
_"A new DTLS association for an existing RTCRtpTransceiver will be represented by an existing RTCDtlsTransport object, whose state will be updated accordingly, as opposed to being represented by a new object."_
BTW example 2) of changing bundlePolicy is not possible due to
If the value of configuration.bundlePolicy is set and its value differs from the connection's bundle policy, throw an InvalidModificationError.
However stopping a transceiver may or may not stop the transport depending on bundle policy and number of m= sections. I suggest delaying stopping the transport until the O/A exchange for a few reasons...
@aboba does this note mean the "closed" RTCDtlsTransportState is not terminal?
"A new DTLS association for an existing RTCRtpTransceiver will be represented by an existing RTCDtlsTransport object, whose state will be updated accordingly, as opposed to being represented by a new object."
Not sure but I think this refers to if you do an ICE restart then you shouldn't create a new transport object. As I recall, the "terminalness" of connection states only applies until ICE restart happens. So technically it is not terminal...
changing bundlePolicy is not possible ...
@henbos Great! Thanks for catching that.
But another case in which transports are stopped are shown in the crbug I link to: use "max-compat" when both end-points support bundle (which is common). The fiddle in the crbug has a pilot error, so here's a working fiddle that I think does the right thing in Chrome (all extra transports on offer get closed on processing the answer).
Not sure but I think this refers to if you do an ICE restart then you shouldn't create a new transport object. As I recall, the "terminalness" of connection states only applies until ICE restart happens. So technically it is not terminal...
That makes sense, as there's a similar (but not identical, difference highlighted) note for iceTranport: _"An ICE restart for an existing RTCRtpTransceiver will be represented by an existing RTCIceTransport object, whose state will be updated accordingly, as opposed to being represented by a new object."_
If ICE restart is what both notes refer to, I propose a PR to change the former note to match the latter. Except...
However stopping a transceiver may or may not stop the transport
When we solved _"the BUNDLE problem"_ in https://github.com/w3c/webrtc-pc/pull/2220 we said it only existed on the answerer side, not in SLD on the offerer side where JSEP can easily reshuffle the _"offerer tagged"_ m-line.
But stop() will still stop sending and receiving immediately ON BOTH SIDES, which should fire the appropriate events on the local transport objects I claim.
The only issue wrt to these notes I think is whether we ressurect the same transport object on SLD(offer) or create a new one. Since transceiver.stop() is terminal for the _transceiver_ being stopped, I see no benefit (only pain) in keeping events firing on that stopped transceiver.(sender|receiver).transport.
For other transceivers affected indirectly through BUNDLE, I think I prefer changing their transceiver.(sender|receiver).transport to a new object, because that's consistent with what happens with "max-compat" and the fiddle.
Stop sending and receiving immediately results in RTCP BYE on the RTP stream, which is already reflected by the track getting muted on the other side. But I don't believe the transport is killed until the m= section's port is set to 0, which I imagined requires another O/A exchange, unless there is a good reason to clean up early. Remember that we do not truly stop the transceiver until the O/A exchange, we only mark it as "stopping" and stop sending media, but for the event to get finalized requires SDP.
In the PR I wrote I made it so that upon returning to stable, if any transceiver was removed from the set of transcievers, their transports gets stopped. I think this kind of makes sense for rollback? We won't let the transceiver start sending again because it's RTCP BYE'd, but the transport is still pending being negotiated to have port 0. Until that happens, we could get a remote offer where the port isn't 0. So until then, we haven't truly killed the transport.
If there is an issue with whether to reuse or create a new transport in some edge case of stopping and creating a new transciever, I think that deserves to be tracked in a separate issue.
Shorter version reply:
But stop() will still stop sending and receiving immediately ON BOTH SIDES, which should fire the appropriate events on the local transport objects I claim.
This is already true (mute), but stop sending/receiving is separate from stopping the transport used to carry the RTP stream.
stop sending/receiving is separate from stopping the transport used to carry the RTP stream.
@henbos I believe you're right, that the key JSEP language here is stopped and/or having a zero port in the _current_ local description or the _current_ remote description (i.e. ignoring the _pending_ ones).
But I can't find the exact spec link tying that to the lifespan of a DTLS association. Our spec seems a bit vague there. Is it in a different spec?
But I can't find the exact spec link tying that to the lifespan of a DTLS association. Our spec seems a bit vague there. Is it in a different spec?
I don't know. It's turtles specs all the way down.