Bug 191202 - sender.replaceTrack() fails with InvalidStateError if the transceiver.direction is "inactive"
Summary: sender.replaceTrack() fails with InvalidStateError if the transceiver.directi...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebRTC (show other bugs)
Version: Safari Technology Preview
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: youenn fablet
URL:
Keywords: InRadar
: 191698 (view as bug list)
Depends on:
Blocks:
 
Reported: 2018-11-02 11:48 PDT by Iñaki Baz
Modified: 2018-11-15 18:18 PST (History)
4 users (show)

See Also:


Attachments
Test script (1.39 KB, application/javascript)
2018-11-04 01:01 PST, Iñaki Baz
no flags Details
Patch (8.86 KB, patch)
2018-11-05 02:45 PST, youenn fablet
no flags Details | Formatted Diff | Diff
Test script 2 with sender.replaceTrack(null) (1.46 KB, text/javascript)
2018-11-05 03:39 PST, Iñaki Baz
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Iñaki Baz 2018-11-02 11:48:59 PDT
Scenario:

* A peerconnection with a sending track (no receiving tracks).

transceiver = pc.addTransceiver(track, { direction: 'sendonly' });

* Later I remove the track:

pc.removeTrack(transceiver.sender);

* When calling pc.createOffer() it generates a m= section with a=inactive (it was a=sendonly before, so it makes sense). The remote SDP answer has also a=inactive as per spec (but it does NOT have port=0 in the m line).

* Later I want to reuse the same transceiver (which is NOT stopped, this is: transceiver.stopped is false) for sending a new track:

const promise = transceiver.sender.replaceTrack(newTrack);

* However, promise is rejected with "InvalidStateError: The object is in an invalid state." which IMHO doesnot make any sense. What does "invalid state" mean for a RtpSender? Yes, `pc.removeTrack(transceiver.sender)` was called before this, but it should not mean that the transceiver becomes unusable for sending new media. It's not stopped, it's just inactive. I should be able to set a new sending track.

NOTE: This works fine in Chrome 72.
Comment 1 Iñaki Baz 2018-11-02 17:23:43 PDT
NOTE: My workaround for now is not trying to reuse an inactive transceiver  but, instead, creating always a new transceiver and leave inactive ones unused forever.
Comment 2 Iñaki Baz 2018-11-04 01:01:33 PST
Created attachment 353801 [details]
Test script

To test this script, just open Safari 12.1, have "Develop - Experimental Features - WebRTC Unified-Plan" enabled, and paste the script in the Safari console.

In this script the "InvalidStateError" does not happen, probably because there is no full SDP OA (there is no remote SDP). Anyway, it also fails with a 100% related issue:

* The scripts gets two audio tracks and creates a sending transceiver with the first audio track.
* Then it removes it via `pc.removeTrack(micTransceiver.sender);`.
* Then it replaces the previous mic track with the second one:
```js
micTransceiver.sender.replaceTrack(micTrack2);
micTransceiver.direction = 'sendonly'; // <--- IMPORTANT
```
* However, `pc.createOffer()` generates an SDP offer with `a=inactive`.

This is: once `pc.removeTrack(sender)` is called, the corresponding transceiver becomes 100% unusable for sending a new track. Setting the transceiver.direction = "sendonly" is ignored by Safari (here the bug probably).

NOTE: The script properly works in Chrome and Firefox.
Comment 3 youenn fablet 2018-11-05 00:37:27 PST
(In reply to Iñaki Baz from comment #1)
> NOTE: My workaround for now is not trying to reuse an inactive transceiver 
> but, instead, creating always a new transceiver and leave inactive ones
> unused forever.

You could also try using replaceTrack(null) instead of removeTrack()
Comment 4 youenn fablet 2018-11-05 02:45:02 PST
Created attachment 353842 [details]
Patch
Comment 5 Iñaki Baz 2018-11-05 03:39:18 PST
Created attachment 353847 [details]
Test script 2 with sender.replaceTrack(null)

Unfortunately calling sender.replaceTrack(null) does not set "a=inactive". Instead it remains "a=sendonly" even if I set transceiver.direction = "inactive" once the replaceTrack(null) promise resolves.

The new attached script is similar to the first one, but instead of pc.removeTrack(sender) it uses sender.replaceTrack(null).then(() => { transceiver.direction = "inactive"; }):

* Once replaceTrack(null) resolves the script changes the transceiver direction to "inactive" and generates an offer. The offer still has a=sendonly, so this is not a valid solution yet.

* And much worse: If after that I call sameSender.replaceTrack(newTrack), it generates a new audio transceiver with its corresponding new m=audio section, both with "a=sendonly". This is an important bug somewhere IMHO.

This script properly works in Chrome and Firefox works fine.

NOTE: In Safari, and when doing real SDP O/A (with pc.setRemoteDescription() and so on) changing transceiver.direction produces an exception (something like "cannot change readonly property") if I do it before the replaceTrack(null) promise resolves. This does not happen in Chrome or Firefox and the spec says nothing about when transceiver.direction can be changed. It's supposed to be changed at any time. It just happens that its effective value (pc.currentDirection) takes an effective value later, may be after a proper SDP O/A, but IMHO it should never produce an exception.
Comment 6 Iñaki Baz 2018-11-05 06:48:35 PST
In order to not mix different issues, I've open a new one to just report the issue when setting transceiver.direction = "inactive" (which is just ignored in Safari 12.1):

https://bugs.webkit.org/show_bug.cgi?id=191260

So, if you developers wish, we can handle here just the original issue related to unusable transceiver.sender once pc.removeTrack(sender) is called (for which I see there is already a patch).
Comment 7 Iñaki Baz 2018-11-05 07:00:43 PST
I've also created a separate issue for the issue "Calling sender.replaceTrack() twice produces a new transceiver and its corresponding m= section":

https://bugs.webkit.org/show_bug.cgi?id=191261
Comment 8 WebKit Commit Bot 2018-11-06 22:05:13 PST
Comment on attachment 353842 [details]
Patch

Clearing flags on attachment: 353842

Committed r237916: <https://trac.webkit.org/changeset/237916>
Comment 9 WebKit Commit Bot 2018-11-06 22:05:15 PST
All reviewed patches have been landed.  Closing bug.
Comment 10 Radar WebKit Bug Importer 2018-11-06 22:06:24 PST
<rdar://problem/45866014>
Comment 11 youenn fablet 2018-11-15 18:18:21 PST
*** Bug 191698 has been marked as a duplicate of this bug. ***