muaz-khan / WebRTC-Experiment

WebRTC, WebRTC and WebRTC. Everything here is all about WebRTC!!
https://www.webrtc-experiment.com/
MIT License
11.71k stars 3.95k forks source link

Question: Which library to choose? #63

Open erichlof opened 11 years ago

erichlof commented 11 years ago

Hello Muaz, I love your website/repositories/experiments! I was wondering about which library to choose: I am a game developer looking to make a network game for 2 to 4 players. Since my games are are action-oriented, I need the data transfer to be as quick as the channel will allow. I need the messages to be JSON objects that relay game player position, alive flags, shooting flags, ping latency, etc.

Also, since I am new to WebRTC and your libraries, I also wanted to know which is the easiest library to use for a relative newbie to WebRTC like me, but that will still be the fastest for game data transfer. I have been looking at the DataChannel, RTCMultiConnection and RTCPeerConnection libraries but I'm confused as to which one I should start learning.

Any advice or recommendations would be greatly appreciated. Thanks! :-)

muaz-khan commented 11 years ago

DataChannel.js is preferred for data & file sharing. Here is a quick demo for you:

<script src="https://webrtc-experiment.appspot.com/firebase.js"></script>
<script src="https://webrtc-experiment.appspot.com/DataChannel.js"></script>

<button id="open-new-data-connection">Open New Data Connection</button>

 var channel = new DataChannel();

 // to be alerted on data connection
 channel.onopen = function (userid) {
     console.log('Data Connection is opened between you and', userid);
 };

 // data strong/object/blob is passed over "onmessage"
 channel.onmessage = function (data, userid) {
     console.log(userid, 'sent you', data);
 };

 // search previously opened connection; if exists; connect
 channel.connect('channel-name');

 // open new data connection
 document.getElementById('open-new-data-connection').onclick = function () {
     channel.open('channel-name');
     this.disabled = true;
 };

You can use socket.io over node.js for signaling too.

What about fastest data transmission?

Current chrome stable/beta/dev releases supports unreliable channels only. Maximum length for a single message over RTP data ports is about 1100-to-1400 chars. On RTP data ports, you can't send data over more than one channel simultaneously. It is "unordered (UDP-Like)" delivery of messages.

SCTP-based channels are landed on Canary (for Windows) however still buggy. SCTP protocol provides reliable TCP-like data streaming. Multi-streaming allows fastest data sharing experience.

You an enjoy SCTP streaming on Firefox nightlies. Remember, out of broken, non-backward compatible changes, DataChannel.js may not work over Firefox standard releases.

Interoperability between Firefox and Chrome is not supported in the moment.

Note:

You can transmit string of any length; however; if string is URL-blob; i.e. string contains double quotes or unknown characters; then data transmission may fail. It is planned to be fixed soon.

Simultaneous transmission of multiple longest string messages is not supported in the moment. It is a bug which will be fixed soon. Until this bug is fixed; make sure string length doesn't exceed 1000 char. Otherwise don't try to send longer strings concurrently.

DataChannel.js uses JSON stringify/parse for each non-string object. Because chrome allows only string transmission in the moment. Blob or JavaScript objects' transmission will be added for SCTP-based channels.

On IE or non-WebRTC browsers; DataChannel.js transmits data using signaling solution you provided e.g. firebase, websocket or socket.io.

erichlof commented 11 years ago

Thank you so much Muaz! The DataChannel library was what I was looking at the most, so I'm glad that you have confirmed that this is the preferred choice for my network gaming solution. The reason I was looking at the other libraries was because they have some interesting features such as the concept of 'rooms' and 'presence detection'. Eventually it would be nice to have a game 'room' where players could connect to if they want to quickly join and play an ongoing game that runs 24/7. Also, if they disconnect, it would be nice to send a notification to all the others that " 'player01' has left the room."

For now, I'm going to dive in and try to create a bare-bones simple chat with DataChannel.js and I will post my code if I get it working. One more question, is there latency detection in your libraries as of yet? I want to send back and forth the amount of time it took for the message to arrive and display the result along with the chat output. Maybe something like Player1 says: "Hi" (75ms) Player2 says: "Oh hello!" (40ms) Player1 says: "How's it going?" (56ms) Player2 says: "Pretty good" (92ms)

If you already have a timing feature, please let me know, otherwise I will try to get one working on my own using the system clock.

Thanks again for the detailed and quick response!
-Erich

erichlof commented 11 years ago

Oops my bad. I just was reading further down the DataChannel.js code and there IS in fact rooms and presence detection already included. I will definitely enjoy using those features - thanks! :)

muaz-khan commented 11 years ago

RTCMultiConnection can work same like DataChannel except that there is no fallback to WebSocket/Socket.io.

connection.session = {
    data: true
};

I'll add latency detection feature in both DataChannel.js and RTCMultiConnection.

erichlof commented 11 years ago

Ahh, I see. Thanks!

Also, thanks in advance for latency detection in future implementations! :)

erichlof commented 11 years ago

Looks great! Can't wait to try out the latency detection. What's funny is I just wrote a little latency code myself that uses the Date object. Turns out I should have just waited for your update, Muaz! :)

Thanks for everything!

erichlof commented 11 years ago

Hi again, the latency detection is working nicely - thanks for that additon! I have 2 quick questions and I didn't want to open a new issue. First, sometimes the latency number comes back negative, i. e. -4 ms and sometimes it comes back positive, like 4 ms. Is there something funny going on? I made a one line correction so it always outputs positive.: var latency = Math.abs (latency); But should this be necessary to add on my end?

Second, how do I get the userid of the initiator, or self? I can get the userid of the remote no problem because it is built into the function(userid) part of the library code. But I have tried channel.userid and self.userid without success. It just comes back undefined. What I want eventually is the number like I get for the remote connection, which usually starts with a 5, for example 502316. Thanks for all your help!

Erich

muaz-khan commented 11 years ago

I'm also using Date object; I don't know whether getStats API allows latency detection or not. I'm using something like this:

var sendingTime = new Date().getTime();
var receivingTime = new Date().getTime();

var latency = receivingTime - sendingTime;

For custom user-ids; see this section:

channel.userid = 'Erich';

connection.onopen = function() {
    console.log('self user-id is:', channel.userid);
}

If you've not set any custom user-id; unique token is generated.

muaz-khan commented 11 years ago

Should we use UTC?

var date = new Date();
var sendingTime = Date.UTC(date.getYear(), date.getMonth(), 
                                          date.getDay(), date.getHours(), date.getMinutes(), 
                                          date.getSeconds(), date.getMilliseconds())

user-id is fixed:

<script src="https://webrtc-experiment.appspot.com/DataChannel.js"></script>
erichlof commented 11 years ago

Thanks Muaz, yes I was using similar code and I had a similar results, sometimes the latency coming out positive and sometimes coming out negative. The Date object must have some inaccuracies. Either that or we have figured out how to time travel using javascript - haha! There is also a Window.performance library call that can be made to retrieve an even more accurate time, but I'll have to check that out and let you know if it works any better.

about the user ID, yes I had not explicitly set a custom userid when opening a data channel. I will have to make my own custom ID like you mentioned in the first example so that I can use that throughout the code. otherwise the unique token that you directed me to is what I was searching for in your library. That should do the trick - Thanks!

Edit: oops, just saw your post about UTC. I'm not sure if that will make things better, but I don't have a lot of experience with the date object so if you think that will work better I'm all for it. I'll get back to you about the window. performance

erichlof commented 11 years ago

Hi Muaz, please take a look at the following article about date.now vs. performance.now: http://updates.html5rocks.com/2012/08/When-milliseconds-are-not-enough-performance-now

The hyperlink inside this article for the "high resolution timer" explains why we were getting negative latencies, as explained by the W3C. This is why they invented the performance object. However I don't know if this call degrades performance if called repeatedly.

What did you mean by "user-id is fixed" in your above post? As in user-id is a fixed value or you have fixed something regarding the user-id in datachannel.js?

muaz-khan commented 11 years ago

Previously you was getting undefined value for userid if it is not customized. Now, you'll be able to get randomly generated user-id too, using channel.userid.

// if userid is customized; it will return that user-id
// if userid is not customized; it will return random numbers used as user-id
console.log(channel.userid);

Users are located in different locations and zones. performance.now will be same for all users?

erichlof commented 11 years ago

Awesome, thanks for the channel.userid update! I will get back to you on performance.now() in a little bit. I have to do some research about it. Thanks again, Muaz. :)

erichlof commented 11 years ago

I'm back! Thank you so much for the fix to user id, it works perfectly - just how I would expect when retrieving it. I have been working on a very simple chat using DataChannel.js (only about 75 lines of code so far and fully functional). I will post for all to see if you would like. It shows how easy it is to get your awesome DataChannel library up and running in no time! :)

Upon further research of the performance.now() method, it appears that it would not be useful for networked connections. Although it is extremely accurate and doesn't hiccup due to clock resets (it will never return a negative value), it turns out that performance.now() starts its clock counting from the moment the browser navigates to the webpage. So in fact as you questioned, it would not be the same for all users unfortunately. I guess if you wanted a really accurate timing of your own javascript code inside your own machine, it would be great; but as soon as you add other connections into the mix, it would all fall apart because 'latency = receiveTime - sendTime' wouldn't make any sense (they would be very different values for everyone).

Oh well, the Date object works well enough (we just have to disregard occasional '0' or negative results) . I don't think UTC will make any difference in accuracy, but it's worth a try.

Thanks again for all the help and updates. DataChannel.js is fantastic!