|
1 | 1 | /* MIT License: https://webrtc-experiment.appspot.com/licence/
|
2 |
| - 2013, Muaz Khan<muazkh>--[ github.com/muaz-khan ] |
| 2 | + 2013, Muaz Khan<muazkh>--[github.com/muaz-khan] |
3 | 3 |
|
4 | 4 | https://github.com/muaz-khan/WebRTC-Experiment/tree/master/DataChannel
|
5 | 5 | */
|
6 |
| - |
7 | 6 | (function () {
|
8 | 7 | window.DataChannel = function (channel, extras) {
|
9 | 8 | if (channel) this.automatic = true;
|
|
19 | 18 | };
|
20 | 19 |
|
21 | 20 | this.channels = {};
|
22 |
| - this.onopen = function (userid/*, _channel */) { |
| 21 | + this.onopen = function (userid) { |
23 | 22 | self.send(userid, 'is connected with you.');
|
24 | 23 | };
|
25 | 24 |
|
|
54 | 53 | channel = config.channel || self.channel || 'default-channel';
|
55 | 54 | var socket = new window.Firebase('https://' + (extras.firebase || self.firebase || 'chat') + '.firebaseIO.com/' + channel);
|
56 | 55 | socket.channel = channel;
|
| 56 | + |
57 | 57 | socket.on('child_added', function (data) {
|
58 | 58 | var value = data.val();
|
59 | 59 | if (value == 'joking') config.onopen && config.onopen();
|
| 60 | + else if (value == 'joking-again') { |
| 61 | + self.onDefaultSocketOpened && self.onDefaultSocketOpened(); |
| 62 | + } |
60 | 63 | else config.onmessage(value);
|
61 | 64 | });
|
| 65 | + |
62 | 66 | socket.send = function (data) {
|
63 | 67 | this.push(data);
|
64 | 68 | };
|
| 69 | + |
65 | 70 | socket.push('joking');
|
66 |
| - |
67 |
| - self.socket = socket; |
| 71 | + |
| 72 | + if (!self.socket) self.socket = socket; |
68 | 73 | return socket;
|
69 | 74 | };
|
70 | 75 |
|
71 | 76 | if (!window.Firebase) {
|
72 | 77 | var script = document.createElement('script');
|
73 | 78 | script.src = 'https://cdn.firebase.com/v0/firebase.js';
|
74 |
| - script.onload = callback; |
| 79 | + script.onload = function () { |
| 80 | + callback(); |
| 81 | + verifySocketConnection(); |
| 82 | + }; |
75 | 83 | document.documentElement.appendChild(script);
|
76 |
| - } else callback(); |
| 84 | + } else { |
| 85 | + callback(); |
| 86 | + verifySocketConnection(); |
| 87 | + } |
77 | 88 | } else callback();
|
78 | 89 | }
|
79 | 90 |
|
| 91 | + function verifySocketConnection() { |
| 92 | + if (window.Firebase) { |
| 93 | + // to check if firebase is connected |
| 94 | + var isFirebaseConnected = new window.Firebase('https://' + (extras.firebase || self.firebase || 'chat') + '.firebaseIO.com/.info/connected'); |
| 95 | + isFirebaseConnected.on('value', function (snap) { |
| 96 | + if (snap.val() === true) { |
| 97 | + if (self.socket) self.socket.send('joking-again'); |
| 98 | + } |
| 99 | + }); |
| 100 | + } |
| 101 | + } |
| 102 | + |
80 | 103 | function init() {
|
| 104 | + if (self.config) return; |
| 105 | + |
81 | 106 | self.config = {
|
82 | 107 | openSocket: function (config) {
|
83 | 108 | return self.openSignalingChannel(config);
|
|
130 | 155 | self.onFileProgress(packets);
|
131 | 156 | },
|
132 | 157 | channel: self.channel,
|
133 |
| - onDefaultSocketOpened: function () { |
134 |
| - if (self.onDefaultSocketOpened) self.onDefaultSocketOpened(); |
135 |
| - }, |
136 | 158 | onleave: function (userid) {
|
137 | 159 | self.onleave(userid);
|
138 | 160 | },
|
139 | 161 | transmitRoomOnce: !!extras.transmitRoomOnce
|
140 | 162 | };
|
141 | 163 |
|
142 | 164 | dataConnector = IsDataChannelSupported ?
|
143 |
| - new DataConnector(self.config) : |
144 |
| - new SocketConnector(self.config); |
| 165 | + new DataConnector(self.config) : |
| 166 | + new SocketConnector(self.config); |
145 | 167 |
|
146 | 168 | fileReceiver = new FileReceiver();
|
147 | 169 | textReceiver = new TextReceiver();
|
|
150 | 172 | this.open = function (_channel) {
|
151 | 173 | self.joinedARoom = true;
|
152 | 174 | if (_channel) self.channel = _channel;
|
| 175 | + |
| 176 | + setDefaults(true); |
| 177 | + |
153 | 178 | prepareInit(function () {
|
154 | 179 | init();
|
155 | 180 | if (IsDataChannelSupported) dataConnector.createRoom();
|
156 | 181 | });
|
157 |
| - if(self.socket) self.socket.onDisconnect().remove(); |
| 182 | + |
| 183 | + if (self.socket) self.socket.onDisconnect().remove(); |
158 | 184 | };
|
| 185 | + |
159 | 186 | this.connect = function (_channel) {
|
160 | 187 | if (_channel) self.channel = _channel;
|
| 188 | + setDefaults(false); |
161 | 189 | prepareInit(init);
|
162 | 190 | };
|
163 | 191 |
|
164 |
| - // auto creating/joing rooms |
165 | 192 | if (this.automatic) {
|
166 | 193 | this.connect();
|
167 | 194 | this.onDefaultSocketOpened = function () {
|
168 | 195 | if (self.isDefaultSocketOpened) return;
|
169 | 196 | self.isDefaultSocketOpened = true;
|
170 | 197 |
|
171 |
| - if (!self.joinedARoom) |
172 |
| - // wait 5 seconds for pre-created room; otherwise create new one |
173 |
| - setTimeout(function () { |
174 |
| - if (!self.joinedARoom) self.open(); |
175 |
| - }, 5000); |
| 198 | + if (!self.joinedARoom) setTimeout(function () { |
| 199 | + if (!self.joinedARoom) self.open(); |
| 200 | + }, 1500); |
176 | 201 | };
|
177 | 202 | }
|
178 | 203 |
|
|
205 | 230 | };
|
206 | 231 |
|
207 | 232 | this.leave = function (userid) {
|
| 233 | + if (typeof userid === 'function') { |
| 234 | + var callback = userid; |
| 235 | + userid = null; |
| 236 | + } |
| 237 | + |
| 238 | + if (!userid) { |
| 239 | + dataConnector.leaving = true; |
| 240 | + if (callback) (function looper() { |
| 241 | + if (dataConnector.left) callback(); |
| 242 | + else setTimeout(looper, 100); |
| 243 | + })(); |
| 244 | + } |
| 245 | + |
208 | 246 | dataConnector.leave(userid);
|
209 | 247 | };
|
| 248 | + |
| 249 | + function setDefaults(isInitiator) { |
| 250 | + self.defaults = { |
| 251 | + isInitiator: isInitiator |
| 252 | + }; |
| 253 | + |
| 254 | + self.reconnect = function () { |
| 255 | + if (self.joinedARoom) self.leave(); |
| 256 | + self.joinedARoom = false; |
| 257 | + |
| 258 | + if (self.defaults.isInitiator) self.open(); |
| 259 | + else self.connect(); |
| 260 | + }; |
| 261 | + } |
210 | 262 | };
|
211 | 263 |
|
212 | 264 | window.moz = !!navigator.mozGetUserMedia;
|
|
297 | 349 |
|
298 | 350 | function _openOffererChannel() {
|
299 | 351 | channel = peerConnection.createDataChannel(
|
300 |
| - options.channel || 'RTCDataChannel', |
301 |
| - moz ? {} : { |
302 |
| - reliable: false |
303 |
| - }); |
| 352 | + options.channel || 'RTCDataChannel', |
| 353 | + moz ? {} : { |
| 354 | + reliable: false |
| 355 | + }); |
304 | 356 | if (moz) channel.binaryType = 'blob';
|
305 | 357 | setChannelEvents();
|
306 | 358 | }
|
|
317 | 369 | if (options.onChannelClosed) options.onChannelClosed(event);
|
318 | 370 | };
|
319 | 371 | channel.onerror = function (event) {
|
320 |
| - console.error(event); |
321 | 372 | if (options.onChannelError) options.onChannelError(event);
|
322 | 373 | };
|
323 | 374 | }
|
|
342 | 393 | }
|
343 | 394 | }
|
344 | 395 |
|
345 |
| - function useless() { |
346 |
| - } |
| 396 | + function useless() { } |
347 | 397 |
|
348 | 398 | return {
|
349 | 399 | addAnswerSDP: function (sdp) {
|
|
378 | 428 |
|
379 | 429 | function openDefaultSocket() {
|
380 | 430 | defaultSocket = config.openSocket({
|
381 |
| - onmessage: onDefaultSocketResponse, |
382 |
| - onopen: function () { |
383 |
| - if (config.onDefaultSocketOpened) config.onDefaultSocketOpened(); |
384 |
| - } |
| 431 | + onmessage: onDefaultSocketResponse |
385 | 432 | });
|
386 | 433 | }
|
387 | 434 |
|
|
395 | 442 | if (response.userToken && response.joinUser == self.userToken && response.participant && channels.indexOf(response.userToken) == -1) {
|
396 | 443 | channels += response.userToken + '--';
|
397 | 444 |
|
398 |
| - console.debug('A person whose id is', response.userToken || response.channel, 'particiated with me!'); |
| 445 | + console.debug('A person whose id is', response.userToken || response.channel, 'is trying to share data with me!'); |
399 | 446 | openSubSocket({
|
400 | 447 | isofferer: true,
|
401 | 448 | channel: response.channel || response.userToken,
|
|
418 | 465 | };
|
419 | 466 |
|
420 | 467 | var socket = config.openSocket(socketConfig),
|
421 |
| - isofferer = _config.isofferer, |
422 |
| - gotstream, |
423 |
| - inner = {}, |
424 |
| - peer; |
| 468 | + isofferer = _config.isofferer, |
| 469 | + gotstream, |
| 470 | + inner = {}, |
| 471 | + peer; |
425 | 472 |
|
426 | 473 | var peerConfig = {
|
427 | 474 | onICE: function (candidate) {
|
|
459 | 506 | if (config.onChannelOpened) config.onChannelOpened(_config.userid, channel);
|
460 | 507 |
|
461 | 508 | if (config.direction === 'many-to-many' && isbroadcaster && channels.split('--').length > 3) {
|
462 |
| - |
463 |
| - console.debug('It is time to transmit participant\'s details: ', socket.channel); |
464 |
| - |
465 | 509 | defaultSocket.send({
|
466 | 510 | newParticipant: socket.channel,
|
467 | 511 | userToken: self.userToken
|
468 | 512 | });
|
469 | 513 | }
|
470 | 514 |
|
471 |
| - //if (_config.closeSocket) socket = null; |
472 |
| - |
473 | 515 | window.isFirstConnectionOpened = gotstream = true;
|
474 | 516 | }
|
475 | 517 |
|
|
505 | 547 | function socketResponse(response) {
|
506 | 548 | if (response.userToken == self.userToken) return;
|
507 | 549 |
|
508 |
| - console.log(response); |
| 550 | + console.debug('private socket:', response); |
509 | 551 |
|
510 | 552 | if (response.firstPart || response.secondPart || response.thirdPart) {
|
511 | 553 | if (response.firstPart) {
|
|
540 | 582 | }
|
541 | 583 |
|
542 | 584 | if (response.closeEntireSession) {
|
543 |
| - // room owner asked me to leave his room |
| 585 | + // room owner is trying to close the entire session |
544 | 586 | leaveChannels();
|
545 | 587 | } else if (socket) {
|
546 | 588 | socket.send({
|
|
609 | 651 | delete sockets[i];
|
610 | 652 | }
|
611 | 653 | }
|
| 654 | + |
| 655 | + /* closing all RTCDataChannels */ |
| 656 | + length = RTCDataChannels.length; |
| 657 | + for (i = 0; i < length; i++) { |
| 658 | + var _channel = RTCDataChannels[i]; |
| 659 | + if (_channel) { |
| 660 | + _channel.close(); |
| 661 | + delete RTCDataChannels[i]; |
| 662 | + } |
| 663 | + } |
| 664 | + that.left = true; |
612 | 665 | }
|
613 | 666 |
|
614 | 667 | // eject a specific user!
|
|
621 | 674 | }
|
622 | 675 | }
|
623 | 676 |
|
| 677 | + var that = this; |
| 678 | + |
624 | 679 | window.onunload = function () {
|
625 | 680 | leaveChannels();
|
626 | 681 | };
|
|
639 | 694 | broadcaster: self.userToken
|
640 | 695 | });
|
641 | 696 |
|
642 |
| - if (!config.transmitRoomOnce) { |
| 697 | + if (!config.transmitRoomOnce && !that.leaving) { |
643 | 698 | if (config.direction === 'one-to-one') {
|
644 | 699 | if (!window.isFirstConnectionOpened) setTimeout(transmit, 3000);
|
645 | 700 | } else setTimeout(transmit, 3000);
|
|
662 | 717 | },
|
663 | 718 | send: function (message, _channel) {
|
664 | 719 | var _channels = RTCDataChannels,
|
665 |
| - data, length = _channels.length; |
| 720 | + data, length = _channels.length; |
666 | 721 | if (!length) return;
|
667 | 722 |
|
668 | 723 | if (moz && message.file) data = message.file;
|
|
672 | 727 | else for (var i = 0; i < length; i++)
|
673 | 728 | _channels[i].send(data);
|
674 | 729 | },
|
675 |
| - leave: leaveChannels |
| 730 | + leave: function (userid) { |
| 731 | + leaveChannels(userid); |
| 732 | + if (!userid) { |
| 733 | + self.joinedARoom = isbroadcaster = false; |
| 734 | + isGetNewRoom = true; |
| 735 | + } |
| 736 | + } |
676 | 737 | };
|
677 | 738 | }
|
678 | 739 |
|
|
698 | 759 | var FileSender = {
|
699 | 760 | send: function (config) {
|
700 | 761 | var channel = config.channel,
|
701 |
| - _channel = config._channel, |
702 |
| - file = config.file; |
| 762 | + _channel = config._channel, |
| 763 | + file = config.file; |
703 | 764 |
|
704 | 765 | /* if firefox nightly: share file blob directly */
|
705 | 766 | if (moz && IsDataChannelSupported) {
|
|
831 | 892 | var TextSender = {
|
832 | 893 | send: function (config) {
|
833 | 894 | var channel = config.channel,
|
834 |
| - _channel = config._channel, |
| 895 | + _channel = config._channel, |
835 | 896 | initialText = config.text,
|
836 | 897 | packetSize = 1000 /* chars */,
|
837 | 898 | textToTransfer = '',
|
|
0 commit comments