Webrtc sdp exchange stuck - webrtc

Does anyone knows a walkaround, ideea or solution for the following webrtc sdp exchange issues. (I'm using an async messaging service to send my sdp candidates from A<->B.)
In the same time :
A <- OFFER -> B (both are creating and send its own sdp(offer) to the other peer).
The problem is that after the sdp arrives to the destination it can't be setted (in order to create an answer) because the destination will be in state "khavelocaloffer" (which waits for an answer).

you can not have both sides create an offer and expect things to work. One side needs to offer, the other side needs to answer.

Related

Should I send a WebRTC answer before my side's localMedia tracks were added?

I'm building a video calling app using WebRTC which allows one peer to call another by selecting someone in the lobby. When peer A sends a call request, the other peer B can accept. At this point, WebRTC signaling starts:
Both peers get their local media using MediaDevices.getUserMedia()
Both peers create an RTCPeerConnection and attach event listeners
Both peers calls RTCPeerConnection.addTrack() to add their local media
One peer A (the impolite user) creates an offer, calls RTCPeerConnection.setLocalDescription() to set that offer as the local description, and sends it to the WebSocket server, which forwards it to the other peer B.
The other peer B receives this offer and adds calls RTCPeerConnection.setRemoteDescription() to record it as the remote description
The other peer B then creates an answer and transmits it again to the first peer A.
(Steps based on https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Connectivity)
This flow is almost working well. In 1 out of 10 calls, I receive no video/audio from one of the peers (while both peers have working local video). In such a case, I have noticed that the answer SDP contains a=recvonly while this should be a=sendrecv under normal circumstances.
I have further determined that by the time the other peer receives the offer and needs to reply with an answer, the localMedia of this side has sometimes not yet been added, because MediaDevices.getUserMedia can take a while to complete. I have also confirmed this order of operations by logging and observing that the offer sometimes arrives before local tracks were added.
I'm assuming that I shouldn't send an answer before the local media has been added?
I'm thinking of two ways to fix this, but I am not sure which option is best, if any:
Create the RTCPeerConnection only after MediaDevices.getUserMedia() completes. In the meantime, when receiving an offer, there is no peer connection yet, so we save offers in a buffer to process them later once the RTCPeerConnection is created.
When receiving an offer, and there are no localMedia tracks yet, hold off on creating the answer until the localMedia tracks have been added.
I am having difficulties to decide which solution (or another) matches best with the "Perfect Negotiation" pattern.
Thanks in advance!
Yes, it is good to add the stream before creating an offer if you do it 'statically', but the best way to do it is to do it in the onnegotiationneeded event because the addtrack event triggers an onnegotiationneeded event. So you should add the stream and then use the createoffer inside onnegotiationneeded. As far as the answer you can do it before with no issues, but remember that a well-established connection will let you add/remove tracks with no problems (even after the SDP has been set). You didn't post any code but remember that you also MUST exchange ice candidates.
The last piece of advice, remember that all of the above IS asynchronous! so you should use promises, and await until the description is set, only THEN create an offer/answer.
Hopefully, this will help

Send offers with WebRTC only

I want to create something similar like chat roulette:
There are two peers. Both peers send an SDP offer to the signaling server asking it to get connected with someone. The signaling server uses the offer of peer A to send it as an answer to peer B and vice versa.
Both peers could setLocalDescription() and setRemoteDescription() without using createAnswer().
Could they now go to the next step and exchange candidates? Or is it necessary that at least one is sending a real answer created with createAnswer()?
No. An offer is not an answer. An answer builds on an offer, it's a refinement, an iteration on it, a negotiation.
The offer-answer exchange is inherently asymmetric, so your peers will be in incompatible states if they've both sent out offers.
Instead, solve discovery (pairing) of A and B first, then do WebRTC from A to B.

How looks WebRTC peer negotiation workflow?

I need to develop a custom WebRTC peer (I need to establish audio or/and data connection between web-browser and non-browser). I however, struggle to find a proper, clear description of the handshake phase.
Answers to questions such as How to create data channel in WebRTC peer connection? are not entirely helpful, as they are not too detailed. Specifically, they say nothing about SDP contents.
Can anyone explain this or recommend any good documentation?
Here is a page with some graphs showing how the signaling process works. Basically, you set some client side stuff first:
PeerConnectionFactory; to generate PeerConnections,
PeerConnection; one for every connection to another peer you want (usually 1),
MediaStream; to hook up the audio and video from your client device.
Then you generate an SDP offer
peerConnection.createOffer();
on the caller side and send it to the callee. The callee sets this offer
peerConnection.setRemoteDescription(insert-the-offer-here);
and generates an SDP answer
peerConnection.createAnswer();
and sends it back to the caller. The caller receives this answer and sets it.
peerConnection.setRemoteDescription(insert-the-answer-here);
Both the caller and callee get a call to
onAddStream() {...} //needs to be implemented in your code
The callee when the caller's offer is set and the caller when the callee's answer is set. This callback signals the beginning of the connection.
You can also use ICE (STUN/TURN) to avoid firewall and NAT issues, but this is optional. Although in production code, you probably want to implement it anyway.
Note: Webrtc documentation is scarce and subject to change, take everything you read about webrtc (at least anything written as of now) with a grain of salt...

Why does ICE needs both-ways signaling?

To establish WebRTC connections the ICE protocol is used with a signaling server which must send messages in both directions. I wonder why after the initiator sent its offer and candidates to the other participant, the participant needed to send back its answer and candidates using the signaling channel in the other direction. Cannot the participant open the connection to the initiator using candidates from both sides and send back its answer using the open connection?
I started reading ICE RFC and the only relevant part I found is in section 5.2 where the initiator must take the controlling role and nominates candidate pairs. But it does not explain why the other could not initiate connection.
To give some background, I am trying to build a webapp for which I want users to establish WebRTC connections without using a signaling server. I thought of having the app to generate a URL including the offer and candidates and providing this URL to other participants through other medium like instant messaging. The issue I got is that the participant need to send back its answer and candidates using the same medium, which is not practical. In the end I will go for a signalling server but I wonder the technical reason.
Yes, you can do that if caller is behind public IP or Full Cone NAT(in this case, router connection mapping needs not to be timed out).
You can able full fill above conditions rarely.
What's the problem with other NAT types?
For example , PRC(port restricted cone) NAT won't allow you to receive a packet from a IP:Port , if you didn't send any packet to that IP:Port before. So callee will never able to send you a packet.
So if callee sends her candidates list to you . you can send some dummy data(with low TTL) to her IP:Port to fool your PRC NAT (now it allow incoming packets from callee's IP:Port as it sends a packet to that IP:Port before).
To know more about different types of NAT:
https://en.wikipedia.org/wiki/Network_address_translation
http://think-like-a-computer.com/2011/09/16/types-of-nat/

webRTC to setup signaling server

how to setup a signaling server for webRTC when the system are connected in Local Area Network? Its mandatory that we must use STUN and TURN server for signaling?
To make WebRTC run on LAN, you will require to have a signaling server in that LAN. A signaling server is any web server that will allow your web clients to exchange the SDP offer/answer and ICE candidates that are generated by the WebRTC PeerConnection. This can be done using AJAX or WebSockets.
I have listed some top sources for information about WebRTC. Please go through some of the links on that page to better understand how the WebRTC signaling works.
You will not require a STUN/TURN server as your WebRTC clients (i.e. Web Browser) will be in the LAN and accessible to each other. FYI... STUN/TURN servers are not part of the signaling but part of the media leg and usually required for NAT traversals of media.
Webrtc needs some kind of signalling system for initial negotiation.. like transferring SDP, ICE-candidates, sending and receiving offers etc... rest is done by peer-peer connection. For initial signalling you can use any technique like sending AJAX calls, using socket.io etc.
STUN and TURN servers are required for NAT traversal, NAT traversal is important because it is needed for determining the path between peers. You can use google provided STUN/TURN server address stun:stun.l.google.com:19302 etc , or you can configure your own turn server by using rfc-5766 turn server
Making signalling server for WebRTC is quite easy.
I used PHP, MYSQL and AJAX to maintain signalling data.
Suppose A wants to call B.
Then A creates offer using createOffer method. This method returns an offer object.
You have to transfer this offer object to user B, This is a part of signalling process.
Now create MYSQL database, having columns :
caller, callee, offer, answer, callerICE and calleeICE
Now offer created by A is stored in offer attribute with the help of AJAX call .
(Remember to use JSON.stringify the JS object before "POSTing" object to server.)
Now user B scans this offer attribute created by caller A , again with the help of AJAX call.
In this way , offer object created at user A can arrive at user B.
Now, user B responds to the offer by calling createAnswer method. This method returns answer object. This can again be stored in "answer" attribute of database.
Then the caller A scans this "answer" attribute created by callee B.
In this way, answer object created by B can arrive at A.
To store iceCandidate object representing caller A, use "callerIce" attribute of MYSQL table. Note that, callee B is scanning "callerIce" to know the details of caller A.
In this way we can transfer the iceCandidate objects representing future peer.
After you complete transferring of iceCandidate object, the connectionState property holds "connected" indicating two peers are connected.
If any questions, let me know!
Cheers ! You can now share local media stream to the remote peer.