Closed domschiener closed 4 years ago
I have had similar problems. I am considering, well no, actually starting to fold the peerjs server into Meteor. Basically because both peerjs and meteor use sockets for communications, and I see little value in maintaining 2 socket connections. I can provide my source code if I am successful and you are interested - or did you abandon the project?
For me it was an absent sdpMid in RTCIceCandidate (negotiator.js:298), which drops a webrtc data connection between browser and nodejs imediatelly after establishment, but only if clients in different network segments or via internet (in the same local network it works without sdpMid). This is according to the official MDN spec:
https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addIceCandidate
When an error occurs while attempting to add the ICE candidate, the Promise returned by this method is rejected, returning one of the errors below as the name attribute in the specified DOMException object passed to the rejection handler.
TypeError The specified candidate doesn't have values for both sdpMid and sdpMLineIndex.
[negotiator.js:298] /* Handle a candidate. / Negotiator.handleCandidate = function(connection, ice) { var candidate = ice.candidate; var sdpMid = ice.sdpMid; // add sdpMid which is absent in original peerjs var sdpMLineIndex = ice.sdpMLineIndex; connection.pc.addIceCandidate(new RTCIceCandidate({ sdpMid: sdpMid, // add sdpMid which is absent in original peerjs sdpMLineIndex: sdpMLineIndex, candidate: candidate })); util.log('Added ICE candidate for:', connection.peer); }
What is the solution for this? I'm also using peerjs @abardik @domschiener @mikkelking
In lib/negotiator.js add to lines as shown above with comment // add sdpMid which is absent in original peerjs
OOH ok fine but I'm using this library https://cdnjs.cloudflare.com/ajax/libs/peerjs/0.3.18/peer.min.js so what I need to do now? @abardik
Well, I forked from 0.3.13 two years ago and changed a lot. But you can fix this by yourself in new version as well. You have to modify the source code, so:
Negotiator.handleCandidate = function(connection, ice) {
var candidate = ice.candidate;
var sdpMid = ice.sdpMid; // !!! THIS LINE
var sdpMLineIndex = ice.sdpMLineIndex;
connection.pc.addIceCandidate(
new RTCIceCandidate({
sdpMid: sdpMid, // !!! AND THIS LINE
sdpMLineIndex: sdpMLineIndex,
candidate: candidate
})
);
util.log("Added ICE candidate for:", connection.peer);
};
Good luck!
Let me try, Many many thanks
On Wed, Nov 28, 2018 at 12:31 PM Andy Bard notifications@github.com wrote:
Well, I forked from 0.3.13 two years ago and changed a lot. But you can fix this by yourself in new version as well. You have to modify the source code, so:
- Grab the non-minified version from here: https://cdnjs.cloudflare.com/ajax/libs/peerjs/0.3.18/peer.js
- Go to the line 722 (Negotiator.handleCandidate)
- Add two lines shown in previous comment or change the whole function to the following:
Negotiator.handleCandidate = function(connection, ice) { var candidate = ice.candidate; var sdpMid = ice.sdpMid; // !!! THIS LINE var sdpMLineIndex = ice.sdpMLineIndex; connection.pc.addIceCandidate( new RTCIceCandidate({ sdpMid: sdpMid, // !!! AND THIS LINE sdpMLineIndex: sdpMLineIndex, candidate: candidate }) ); util.log("Added ICE candidate for:", connection.peer); };
- In your project include your modified library instead of from CDN.
Good luck!
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/peers/peerjs/issues/347#issuecomment-442341314, or mute the thread https://github.com/notifications/unsubscribe-auth/AkxCQgtIvZDVrFLfdI-Q2l7conFJ00ldks5uzjTdgaJpZM4IkV8R .
I keep on getting this error now @abardik ICE failed, add a TURN server and see about:webrtc for more details
TypeError: connection.pc is undefined[Learn More] this error also @abardik
TURN is required if your peers cannot establish a direct connection. For example, this is possible, if one of them behind the NAT. I have to use TURN often when one of the peers is mobile client (LTE). So, try to install your own TURN or find a public one (which is hard to find). Actually, did you configured ICE servers settings? Maybe the problem is just ICE (STUN), not TURN. STUN is required for any peers that not in your network. So, if you did not configure STUN (ICE) settings, your remote peers will be unavailable.
You can use Google's STUN:
var config = { 'iceServers': [{ 'urls': ['stun:stun.l.google.com:19302'] }] };
and then:
var peer = new Peer(id, config);
After googling a lot I found these things only but I don't think so this is also working.
peer = new Peer(id,{
debug: 2
config: {'iceServers': [
{ url: 'stun:stun.l.google.com:19302' }, // Pass in optional STUN and TURN server for maximum network compatibility
{ url: 'turn:numb.viagenie.ca:3478', credential: 'muazkh', username:'webrtc@live.com' },
{ url: 'turn:numb.viagenie.ca', credential: 'muazkh', username:'webrtc@live.com' },
{ url: 'turn:numb.viagenie.ca:3478', credential: 'peerjsdemo', username:'p.srikanta@gmail.com' },
{ url: 'turn:192.158.29.39:3478?transport=udp', credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
username:'28224511:1379330808' }
{ url: 'turn:192.158.29.39:3478?transport=tcp', credential: 'JZEOEt2V3Qb0y27GRntt2u2PAYA=', -->
username:'28224511:1379330808' }
]}
});
and yes I'm trying to connect from the Mobile(LTE) and how to install TURN server whether its a paid one? Please let me know the possible solution. I'm struggling from last week. @abardik
About TypeError... I need more info from your browser console (at least file and line of the error, or trace or something). Try to include the original 0.3.18 (not minified) and then just add those two lines.
Sure I will let you know @abardik
I don't know about those TURNs in your example (it seems like old test servers from peerjs developers), but STUN is good. Remove all TURNs and try again. You can try my example above with just one Google's server ('urls' is a new standard instead of old 'url' from your example). P.S. From my experience, iPhone LTE requires TURN anyway. At least, with my mobile carrier. So, if you connect from iPhone, try to install your own TURN.
/* Handle a candidate. /
Negotiator.handleCandidate = function (connection, ice) {
var candidate = ice.candidate;
var sdpMid = ice.sdpMid; // !!! THIS LINE
var sdpMLineIndex = ice.sdpMLineIndex;
connection.pc.addIceCandidate(new RTCIceCandidate({ //TypeError: connection.pc is undefined
sdpMid: sdpMid, // !!! AND THIS LINE
sdpMLineIndex: sdpMLineIndex
, candidate: candidate
}));
util.log("Added ICE candidate for:", connection.peer);
};
module.exports = Negotiator;
connection.pc.addIceCandidate(new RTCIceCandidate({ //TypeError: connection.pc is undefined
This is the line I'm getting that error
and after adding that Google STUN server,this is what I got ICE failed, add a TURN server and see about:webrtc for more details @abardik
and now this is my code
var config = { 'iceServers':
[{ 'urls': ['stun:stun.l.google.com:19302']
}]
};
peer = new Peer(id, config);
Config is good, but the browser says you need TURN, because ICE failed. This is the same behavior I have with iPhone. If any of those TURNs from your example did not work, you should to install your own TURN or maybe try to create account here: http://numb.viagenie.ca/ (I never tried them). You have to create that account because their TURN requires an authentication, and you should put your login/password to your config (like in your example config above).
For TypeError. I see that error in line 650 (peer.js). But line 650 (at least in my copy of peer.js that I just downloaded) contains: util.log("Failed to createOffer, ", err); As you see, there is no connection.pc in this line. Maybe you use the wrong peer.js? Anyway, try to use the original peer.js after you install TURN. When the TURN problem is gone - come back to sdpMid problem.
Many many thanks abardik.Let me try and I will let you know @abardik
After creating an account, this is how I configured in my code. Whether it's correct or not? var config = { 'iceServers': [{ 'urls':'stun:stun.l.google.com:19302'}, { 'urls': 'turn:numb.viagenie.ca', credential: 'mypassword', username:'myusername' } ] }; @abardik
Just for the code modification, you can clone the repository, make the changes, and compile, you only need to launch grunt (don't need to mess with minified code). And ofc any PR is welcome.
By spec it should be:
{
"iceServers": [
{ "urls": ["stun:stun.l.google.com:19302"] },
{ "urls": ["turn:numb.viagenie.ca:3478"], "username": "###", "credential": "###" }
]
}
I tried but often I'm getting the same issue if I I tried to connect 5times,in that only 3 times works. and media streams are getting strucked its not at all moving more than 2 minutes - 3minutes @abardik
If you successfully established LTE connection and transfered some data and it has been live for several minutes, than I believe the reason of your initial issue is gone. Now, I think you have another problem - unstable connection. It can be anything. For example, bad LTE signal or bug in your code. You should try to write as simple test as possible to exclude your bugs. But from the other side, your serverreflexive candidate is failed on your screenshot. Without srvflx candidate you can not rich remote peer if your device does not have a public IP (it's true for many home routers and LTE devices). If you have established LTE connection, than: a) you have a public IP and your connection is established with host candidate; or b) your screenshot is outdated because it's not possible to connect to remote peer without public IP and with failed srvflx (STUN) and/or relay (TURN) candidates. Anyway, it's hard to say something more usefull without being on your computer, sorry.
Can I share my code? @abardik
Sure.
Here I have attached my file as a txt. Please change it as HTML file. Sender file is the one who is creating connection and receiver is the one who is receiving the connetion. Sender.txt receiver.txt
and here after getting the stream in video tag,I'm drawing it into the canvas using drawImage. Please let me know and to make the connection url it will be look like http://ipaddress:8080/Sender.html and for receiver it should be like, http://ipaddress:8080/Receiver.html?roomId= //In this only we will pass our id as params.For eg,roomId=xxxxxx @abardik
`
Sorry, I don't have https server to upload and try your code. It's not possible to establish a non-secured (http) connection for webrtc (only localhost, but you need LTE). I suggest to start from very simple webrtc/peerjs example to avoid your own bugs. Then, when you successfully establish LTE connection in that simple example, you can start to add your own logic.
But it works great in Firefox and one more doubt I'm having in firefox documentation,they said webrtc won't work in safari. Whether it will work on safari or not? @abardik
It will. MediaConnection
will work as is. But for DataConnection
you have to make a little fix to send binary data (this is not required if you plan to send strings only). To do this in DataConnection.prototype._trySend
find this._dc.send
and replace it with the following:
if ( ios ) this._dc.send(new Uint8Array(msg));
else this._dc.send(msg);
Or you can handle this in your main code where you calling DataConnection.send(). Maybe it has been fixed already, but in v. 0.3.13 this bug exists.
And you have to define ios
somewhere, of course.
Ok, I will ask this when I will work on that issue. Right now Let me try to get the connection clearly @abardik
@abardik Is there any other bug fixes needed to get peerjs to work on ios?
I am having an issue where only on iOS, if a peer connects to iOS it does not work. But if iOS connects to anything else it works fine. Any ideas?
Just those two: sdpMid and Uint8Array. But in my case iOS doesn't work without TURN. Maybe it's because of my LTE provider. Wi-Fi is ok without TURN, as I remember. Didn't try on Android with LTE. Maybe it's the same.
Well I was just planning to only send strings, and my application will be wifi only. So technically it should work then?
Maybe I am just missing something. In my case it says it is connected and I get the connection event being fired off of the peer object that gives a DataConnection object, but then any interaction I have with the DataConnection object, does not work. No console logs, no errors, just nothing at all. Not sure what is going on. Super annoying though.
Can you confirm that you got peerjs to work correctly on iOS 11 in a MKWebView application? I am guessing that Meteor is some sort of cross platform web based framework like cordova?
There is tons of things saying that iOS 11 is not supported for webRTC, based on my research this is not entirely true, and in fact it works fine but you cannot get the data stream through the browser. Since we can get the data stream natively I am trying to find out if WebRTC and peerJS actually do work in iOS and Android minus the data stream issue in iOS 11. Any thoughts?
Yes, it works totally correctly on iOS, starting from iOS 9 or 10 when WebRTC has been announced by Apple (pure Safari and Phonegap app with WKWebView and iosrtc plugin, because WKWebView for Cordova still doesn't support WebRTC). No issues with DataConnection and MediaConnection. It's hard to deal with iosrtc plugin, but it works finally. Android the same - everything works, starting from Android 5.
Meteor is not lika Cordova. Meteor it's just a full-stack web framework. Cordova is a mobile framework. Cordova gives you an access to device's features. Meteor just gives you an exellent way to deal with data and UI.
Ok so you never actually created a native mobile app then? Meteor just allows you to code a website for mobile, but it is using prue safari not WKWebView. Based no ym research WKWebView is the issue.
@abardik So how do you define iOS or not in the Uint8Array bug?
Also does this refer to the person you are sending it to is on iOS or does it mean that client who is sending it is on iOS?
Something like this:
var isCordovaIOS = /Apple/.test(navigator.vendor) && /YourAppUA/.test(navigator.userAgent);
var isSafari = /Apple/.test(navigator.vendor) && /Safari/.test(navigator.userAgent) && ! isCordovaIOS;
Phonegap (Cordova) is a native app. You just use JS to code instead of Objective C or Java. Meteor is a web framework. You can not build a native app with meteor only. You have to wrap meteor app into cordova app. Then you have WKWebView in your cordova app, in which meteor web app is running. But from the WebRTC point of view it doesn't meter what web framework you're using. You have cordova implementation of WKWebView, which is on iOS has no WebRTC yet. So, you have to add iosrtc plugin in your cordova app. For Android app WebRTC just works, as well as Safari on your iPhone. But for iOS cordova app you need iosrtc plugin.
And yes, there are no issues with WebRTC and peerjs on all of those platforms. Only restrictions I have with WebRTC are in IE and Edge. Chrome, Firefox, Safari, UIWebView, WKWebView - all of them just work.
@abardik Cool that is good to here. Thanks for the input. At this point I just need to figure out how to piece all this together.
Right now I am doing a test with data connection and i am having issues with it in both safari and iOS MKWebView. Maybe you can help me out with it?
When setting breakpoints it would appear the issue is related to RTCPeerConnection and the event onicecandidate. With full logging, getting no errors, this only happens when another device tries to connect to safari or iOS. So the device connection works correctly and even fires the open connection event, but when i send stuff nothing happens. On iOS and Safari for some reason the onicecandidate never fires which seems to be causing the issues.
I have implemented both of your fixes and still having issues. Any ideas?
Uint8Array is for already established connection and just for binary data transfer. For strings only you don't need it. And, actually, I see now, that I've commented sdpMid fix almost a year ago. It works now without that fix for me. Sorry for that. Comment it and try again. Your problem is ICE. If you have no onicecandidate, you have no peer to connect to. I had the same issue on iOS on LTE without TURN. But, I think, this is just my provider's LTE network configuration. If your provider provides a direct IP for LTE, you don't need TURN. If both of your peers are in the same wi-fi network, you even dont' need STUN, just host candidates. But i'm not sure WebRTC will work on iOS without STUN config (if I remember, it didn't work for me without google STUN in peerjs config, even in the same wi-fi). So, for the first, make sure you've configured STUN (see comments above) and connect both peers to the same wi-fi network. Then look at the 'host' and 'srvflx' candidates in webrtc logs. Then configure TURN, connect through LTE and look for 'relay' candidates. 'srvflx' and/or 'relay' are required for LTE connections.
I have tried with COTURN configuration with my local system using my local IP address. It worked. But now, I'm trying to configure this using my public IP. Is it possible? and I'm doing this using Cygwin, can I able to configure this in my system with my public IP address? @abardik
Theoretically, yes. But I never configured TURN locally, so, practically, I don't know.
Hey @abardik,
Thanks a ton for the great input on this subject, you are a huge help. Currently I am only sending strings, so guessing the fix does not matter. Also I have tried with and without the stun servers, I basically copied the above suggestions to the letter. There is no change on behavior for my app. The requirement for this app is it only needs to work over wifi, nothing else. So I do not have to worry about turn servers.
You mention if you have no onicecandidate then you have no peer, but here is the log of the bnroken one.
[Log] PeerJS: – "Socket open" (vendor.js, line 88282)
[Log] GET "http://192.168.102.146:8080/api/connected-users/" (main.js, line 2166)
succeeded in 33 ms, with body: ["ax8p10z501g00000 (You)"]
[Log] PeerJS: – "Creating RTCPeerConnection." (vendor.js, line 88282)
[Log] PeerJS: – "Listening for ICE candidates." (vendor.js, line 88282)
[Log] PeerJS: – "Listening for data channel" (vendor.js, line 88282)
[Log] PeerJS: – "Listening for remote stream" (vendor.js, line 88282)
[Log] PeerJS: – "Setting remote description" – RTCSessionDescription {type: "offer", sdp: "v=0
↵o=- 817605983474189040 2 IN IP4 127.0.0.1
↵s=…id:data
↵a=sctpmap:5000 webrtc-datachannel 1024
↵", toJSON: function} (vendor.js, line 88282)
RTCSessionDescription {type: "offer", sdp: "v=0
↵o=- 817605983474189040 2 IN IP4 127.0.0.1
↵s=…id:data
↵a=sctpmap:5000 webrtc-datachannel 1024
↵", toJSON: function}RTCSessionDescription
[Log] Got connection event in page: fmri5l4xjz000000 (main.js, line 2166)
[Log] Data connection opened. (main.js, line 2166)
[Log] Data connection setup with fmri5l4xjz000000 (main.js, line 2166)
[Log] PeerJS: – "Added ICE candidate for:" – "fmri5l4xjz000000" (vendor.js, line 88282)
[Log] PeerJS: – "Set remoteDescription:" – "OFFER" – "for:" – "fmri5l4xjz000000" (vendor.js, line 88282)
[Log] PeerJS: – "Added ICE candidate for:" – "fmri5l4xjz000000" (vendor.js, line 88282)
[Log] PeerJS: – "Created answer." (vendor.js, line 88282)
[Log] PeerJS: – "Set localDescription: answer" – "for:" – "fmri5l4xjz000000" (vendor.js, line 88282)
[Log] PeerJS: – "Added ICE candidate for:" – "fmri5l4xjz000000" (vendor.js, line 88282)
Now here is the log for the one that works.
logging.service.ts:11 Connected to server as 7tvukmruwhq00000
logging.service.ts:11 GET "http://192.168.102.146:8080/api/connected-users/"
succeeded in 29 ms, with body: ["ax8p10z501g00000","tvjfqg34iuo00000","7tvukmruwhq00000 (You)"]
util.js:65 PeerJS: Creating RTCPeerConnection.
util.js:65 PeerJS: Listening for ICE candidates.
util.js:65 PeerJS: Listening for data channel
util.js:65 PeerJS: Listening for remote stream
util.js:65 PeerJS: Setting remote description RTCSessionDescription {type: "offer", sdp: "v=0
↵o=mozilla...THIS_IS_SDPARTA-63.0.3 1691102812…a=sctp-port:5000
↵a=max-message-size:1073741823
↵"}
logging.service.ts:11 Got connection event in page: tvjfqg34iuo00000
logging.service.ts:11 Data connection opened.
logging.service.ts:11 Data connection setup with tvjfqg34iuo00000
3util.js:65 PeerJS: Added ICE candidate for: tvjfqg34iuo00000
util.js:65 PeerJS: Set remoteDescription: OFFER for: tvjfqg34iuo00000
util.js:65 PeerJS: Created answer.
util.js:65 PeerJS: Set localDescription: answer for: tvjfqg34iuo00000
2util.js:65 PeerJS: Received ICE candidates for: tvjfqg34iuo00000
util.js:65 PeerJS: Received data channel
util.js:65 PeerJS: Data channel connection success
logging.service.ts:11 Data connection open according to peerjs.
As you can see, it is getting the handshake, just after it creates the offer nothing happens, but on the one that works it gets a Received ICE candidates
message. Also sometimes if I wait long enough I get a this on the client that is broken. The client that is connecting to the broken ones appears the same as a normal one, aka it connects and a open event shows.
[Log] PeerJS: – "iceConnectionState is disconnected, closing connections to fmri5l4xjz000000" (vendor.js, line 88282)
[Log] Error on Receive listening: There was an error Error: Negotiation of connection to fmri5l4xjz000000 failed. (pages-dashboard-dashboard-module.js, line 238)
Any thoughts?
Thanks, Bob
I have to see your candidates to say something. If you have just one candidate 127.0.0.1 (localhost), no other peer can connect to you, except others on the same device. Go to Negotiator.handleCandidate
and change the last line to this:
util.log('Added ICE candidate for:', connection.peer, candidate);
Currently using PeerJS with Meteor (here is the project: https://github.com/domschiener/peered). Everything works fine locally on the same connection, but as I deploy it to my server and try to connect with a friend, the connection is very unstable and oftentimes drops immediately after connecting.
Anyone have an idea as to why that could be?