what is the appropriate way to migrate from addTrack to addTransceiver?

373 views
Skip to first unread message

Ahmed Karam

unread,
Nov 29, 2022, 7:09:38 AM11/29/22
to discuss-webrtc
my question is long a little so i will not asking another time here but full question is here 
in stackover flow 
https://stackoverflow.com/questions/74613775/what-is-the-appropriate-way-to-migrate-from-addtrack-to-addtransceiver

Henrik Boström

unread,
Nov 29, 2022, 8:36:53 AM11/29/22
to discuss-webrtc
Writing from memory, have not tested, but should work:

Instead of
senderPc.addTrack(senderTrack);
receiverPc.addTrack(receiverTrack);
receiverPc.ontrack = e => { /* do something with e.track */ };
<negotiate>

You can do:

senderPc.addTransceiver(senderTrack);
receiverPc.ontrack = await e => {
  /* do something with e.track */
  e.transceiver.direction = 'sendrecv';
  await e.transceiver.sender.replaceTrack(receiverTrack);
};
<negotiate>

The transceiver created by the sender is sendrecv by default. This gets mirrored by a transceiver on the receiver side for the same mid. Here it's exposed in the ontrack event, but in an "offer to receive" use case you could obtain it via getTransceivers() instead.
Anyway on the receiver side, the direction is "downgraded" from sendrecv to recvonly because by default this transceiver is not configured to send anything back from receiverPc to senderPc. After all, it was just created in response to setRemoteDescription(offer).
To fix this, you "upgrade" the direction to sendrecv and set a track to send. If you do this prior to creating the local SDP answer on receiverPc, you should be able to achieve "sendrecv" without more SDP negotiations. The ontrack event is fired before the SRD promise is resolved, so any modification you do in that event should have completed before the SDP answer is created.

Remember, transceiver.direction is what you're willing to negotiate and transceiver.currentDirection is what you're currently configured to do, so debug log the direction and currentDirection values before, during and after negotiation if you run into trouble.

Henrik Boström

unread,
Nov 29, 2022, 8:44:19 AM11/29/22
to discuss-webrtc
The only difference between a transceiver that was created via addTrack and a transceiver that was created via addTransceiver, is that an addTrack-transceiver can attach to m= sections on offer, whereas addTransceiver-transceiver have to be associated with a mid via an SDP offer.

This is why both endpoints can do addTrack and still end up with a single m= section and only a single transceiver each.

But when the receiver uses addTransceiver instead of addTrack, that transceiver will not attach to the m= section on offer... so instead the receiver ends up with two transceivers. The workaround is to not create any transceivers on the receiverPc and instead piggypack on transceivers that get created in response to receiverPc.setRemoteDescription(offer).

You can live in a world where both endpoints call addTransceiver() explicitly, but only if you are willing to have both endpoints act as both offers and answerers. You can do this, but then you have to be careful to avoid "glare", the situation where both endpoints start create an SDP offer at the same time, and end up in a state where they can't apply a remote offer without rolling back their locally created offer. This is possible with the Perfect Negotiation pattern, see this demo. This pattern is timing sensitive though, so it only works if everything is "perfect".
Message has been deleted

adam rama

unread,
Dec 2, 2022, 11:40:41 AM12/2/22
to discuss-webrtc
first i'm really thankful to you , and from what i understanding i will detailed ur answer with
 point after point so bear with me it will be a lot from me to find someone guiding me 

1- you say to create addTransceiver on the localPeer side like that

senderPc.addTransceiver(senderTrack);
 
and in my app case it will be like so

yourConn.addTransceiver(streams.getAudeoTracks()[0], {direction: "sendrecv"});

and while The transceiver created by the sender is sendrecv by default.
so it will be like so

yourConn.addTransceiver(streams.getAudeoTracks()[0]);

no need to specify it while it's by default is sendrecv



2- "This gets mirrored by a transceiver on the receiver side for the same mid"

so what u mean about that is when i send from p1(yourConn) to p2(yourConn2) the sendrecv is been
mirrored to recvonly "cause by default this transceiver is not configured to send anything back from receiverPc to senderPc"

i read about about mid and i understand it but what i need to know about it  is
 RTCRtpTransceiver mid created automatically by RTCRtpTransceiver  or it's gotten from
sdp m-line and equalizing it with to be mid = sdp.m
 and if that true , does it will be the same on the remote and local side ? that m-line from sdp or both side has different sdp with different  m-line
 
3-"Here it's exposed in the ontrack event, but in an "offer to receive" use case you could obtain it via getTransceivers() instead."

what about configure it ,  and make it work to recieve and sending as u suggest got the Transceivers and after that make an offer to send like so ?
is this way that  supposed to send audio back to yourConn(the offer sender or local peer .the caller)?


RemoteAudioFromlocal = yourConn2.getTransceivers()[0];

and do that after sending asnwer to the caller

RemoteAudioFromlocal.direction = "sendrecv"
await RemoteAudioFromlocal.sender.replaceTrack(localStream.getAudioTracks()[0]);

and i obtain audio in both side like so ontrack event ?


in remote peer or the callee side  upgrading the direction and send a track to local peer
   await yourConn2.setRemoteDescription(offer);
  yourConn2.ontrack = (e) => {
          if (e.candidate !== null) {
            const track = e.track


            /* do something with e.track */
           
            console.log(`event addtrack is ${e.streams[0].getTracks()} and kind is ${track.kind}`);
             e.transceiver.direction = 'sendrecv';
        await e.transceiver.sender.replaceTrack(await RemoteAudioFromlocal.sender.replaceTrack(););
            }else {
            console.log("there is an error with on trackevent", event);
            }
    };          
   
   after that i should do
    yourConn2.setLocalDescription(answer)
   so is that right with thoes steps every thing will work just as fine ?
   
   what about local side ?
   i will do these steps in my condition
   
yourConn.addTransceiver(streams.getAudeoTracks()[0]);

what should i do about ontrack event just offer to recieve right  ?

like so

yourConn.ontrack = (e) => {
  e.transceiver.direction = 'sendrecv';
  await e.transceiver.reciever.replaceTrack(LocalPeerStramIn);
};

or that wrong as localpeer make offer to send and recieve and the remotepeer peer has agree so no need to ontrack event?
   
 as in my case these value equal to
 in localside or the caller
 
 
  localVideo = document.getElementById("wbrtclocal");
      LocalPeerStramIn = new MediaStream();
      localVideo.srcObject = LocalPeerStramIn;
     

and on the callee side      
 remoteVideo = document.getElementById("wbrtcremote");
          remotePeerStramIn = new MediaStream();
          remoteVideo.srcObject = remotePeerStramIn

         
         
         
"Remember, transceiver.direction is what you're willing to negotiate and transceiver.currentDirection is what you're currently configured to do, so debug log the direction and currentDirection values before, during and after negotiation if you run into trouble.
"

as caller will send offer to send data and will do if the other peer (romtepeer )accept that  so in this case if i debug the trsniver dir and transceiver.currentDirection what should i expect?



"The only difference between a transceiver that was created via addTrack and a transceiver that was created via addTransceiver, is that an addTrack-transceiver can attach to m= sections on offer, whereas addTransceiver-transceiver have to be associated with a mid via an SDP offer.
"
what the differnce here as media line will be there anyway ?          

"This is why both endpoints can do addTrack and still end up with a single m= section and only a single transceiver each.
But when the receiver uses addTransceiver instead of addTrack, that transceiver will not attach to the m= section on offer... so instead the receiver ends up with two transceivers. The workaround is to not create any transceivers on the receiverPc and instead piggypack on transceivers that get created in response to receiverPc.setRemoteDescription(offer).
"

i didn't understand that for bad


"You can live in a world where both endpoints call addTransceiver() explicitly, but only if you are willing to have both endpoints act as both offers and answerers. You can do this, but then you have to be careful to avoid "glare", the situation where both endpoints start create an SDP offer at the same time, and end up in a state where they can't apply a remote offer without rolling back their locally created offer. This is possible with the Perfect Negotiation pattern, see this demo. This pattern is timing sensitive though, so it only works if everything is "perfect".
"

so ur here willing to say that if i intend to create addtransciever on both side i have to renegotitaion again?

adam rama

unread,
Dec 2, 2022, 11:44:15 AM12/2/22
to discuss-webrtc
if this to long to u i can simplified it by just know where and when 2 answer 
where i can obtain audio from p1 in p2 
and where i can obtain audio from p2 in p1 

after i got the 
 RTCRtpTransceiverArrays = yourConn2.getTransceivers()[0];

what sould i do afeter that and these steps that should i do to recieve where i can adding it ?
same on p1 how i can obtain from p2 and where should i add these steps after every thing is done or in specidiec point 
Reply all
Reply to author
Forward
0 new messages