teleportxr 1.0.21 → 1.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,437 +1,437 @@
1
- 'use strict';
2
-
3
- const EventEmitter = require('events');
4
- const wrtc =require('@roamhq/wrtc');
5
- const DefaultRTCPeerConnection = require('@roamhq/wrtc').RTCPeerConnection;
6
-
7
- const TIME_TO_CONNECTED = 30000;
8
- const TIME_TO_HOST_CANDIDATES = 3000; // NOTE: Too long.
9
- const TIME_TO_RECONNECTED = 1000;
10
- function EVEN_ID(id) {
11
- return (id-(id%2))
12
- }
13
- function ODD_ID(id) {
14
- return (EVEN_ID(id)+1)
15
- }
16
- class WebRtcConnection extends EventEmitter
17
- {
18
- constructor(id, options = {})
19
- {
20
- super();
21
- const iceServers=[
22
- "stun:stun.l.google.com:19302"
23
- ];
24
- this.iceServers = [] ;
25
- for(const s in iceServers)
26
- {
27
- this.iceServers.push({ 'urls': iceServers[s] });
28
- }
29
- //this.iceServers=[{'urls': 'stun:stun.l.google.com:19302'}];
30
- this.id = id;
31
- this.state = 'open';
32
-
33
- this.options = {
34
- RTCPeerConnection: DefaultRTCPeerConnection,
35
- clearTimeout,
36
- setTimeout,
37
- timeToConnected: TIME_TO_CONNECTED,
38
- timeToHostCandidates: TIME_TO_HOST_CANDIDATES,
39
- timeToReconnected: TIME_TO_RECONNECTED,
40
- ...options
41
- };
42
-
43
- const {
44
- RTCPeerConnection,
45
- timeToConnected,
46
- timeToReconnected
47
- } = options;
48
-
49
- this.messageReceivedReliableCb =options.messageReceivedReliable;
50
- this.messageReceivedUnreliableCb =options.messageReceivedUnreliable;
51
- this.connectionStateChangedCb=options.connectionStateChanged;
52
- this.sendConfigMessage =options.sendConfigMessage;
53
-
54
-
55
- Object.defineProperties(this, {
56
- iceConnectionState: {
57
- get ()
58
- {
59
- return this.peerConnection.iceConnectionState;
60
- }
61
- },
62
- localDescription: {
63
- get ()
64
- {
65
- return descriptionToJSON(this.peerConnection.localDescription, true);
66
- }
67
- },
68
- remoteDescription: {
69
- get ()
70
- {
71
- return descriptionToJSON(this.peerConnection.remoteDescription);
72
- }
73
- },
74
- signalingState: {
75
- get ()
76
- {
77
- return this.peerConnection.signalingState;
78
- }
79
- }
80
- });
81
- this.reconnect();
82
- }
83
- connectionStateChanged()
84
- {
85
- if(!this.peerConnection)
86
- return;
87
- this.connectionStateChangedCb(this.peerConnection.connectionState);
88
- }
89
- reconnect()
90
- {
91
- this.peerConnection =new DefaultRTCPeerConnection({ sdpSemantics: 'unified-plan', 'iceServers': this.iceServers});
92
- this.beforeOffer();
93
- this.connectionTimer = this.options.setTimeout(() =>
94
- {
95
- if (this.peerConnection.iceConnectionState !== 'connected'
96
- && this.peerConnection.iceConnectionState !== 'completed')
97
- {
98
- console.log("WebRtcConnection timeout, this.peerConnection.iceConnectionState = "+this.peerConnection.iceConnectionState);
99
- this.close();
100
- }
101
- }, this.options.timeToConnected);
102
-
103
- this.reconnectionTimer = null;
104
-
105
- this.peerConnection.addEventListener('iceconnectionstatechange', this.onIceConnectionStateChange.bind(this));
106
- this.peerConnection.addEventListener('icegatheringstatechange', this.onIceGatheringStateChange.bind(this));
107
- this.peerConnection.addEventListener("icecandidateerror", (event) => {
108
-
109
- console.log("ICE candidate error: "+event.errorCode+" "+event.errorText+" "+event.port+" "+event.url);
110
- });
111
-
112
- this.peerConnection.addEventListener("connectionstatechange", this.connectionStateChanged.bind(this));
113
-
114
- this.onIceCandidate= ({ candidate })=>
115
- {
116
- if (!candidate)
117
- {
118
- this.options.clearTimeout(this.timeout);
119
- //this.peerConnection.removeEventListener('icecandidate', this.onIceCandidate);
120
- this.deferred.resolve();
121
- return;
122
- }
123
- // send the candidate
124
- var mid=candidate.sdpMid;
125
- var mlineindex=candidate.sdpMLineIndex;
126
- var message = '{"teleport-signal-type":"candidate","candidate":"'+candidate.candidate+'","mid":"'+mid.toString()+'","mlineindex":'+mlineindex.toString()+'}';
127
- this.sendConfigMessage(this.id,message);
128
- }
129
- this.waitUntilIceGatheringStateComplete= async (peerConnection, options) =>
130
- {
131
- if (peerConnection.iceGatheringState === 'complete')
132
- {
133
- return;
134
- }
135
-
136
- const { timeToHostCandidates } = options;
137
-
138
- this.deferred = {};
139
- this.deferred.promise = new Promise((resolve, reject) =>
140
- {
141
- this.deferred.resolve = resolve;
142
- this.deferred.reject = reject;
143
- });
144
-
145
- this.timeout = options.setTimeout(() =>
146
- {
147
- peerConnection.removeEventListener('icecandidate', this.onIceCandidate.bind(this));
148
- this.deferred.reject(new Error('Timed out waiting for host candidates'));
149
- }, timeToHostCandidates);
150
-
151
- peerConnection.addEventListener('icecandidate', this.onIceCandidate.bind(this));
152
-
153
- await this.deferred.promise;
154
- }
155
-
156
- this.doOffer = async () =>
157
- {
158
- try
159
- {
160
- const offer = await this.peerConnection.createOffer();
161
- await this.peerConnection.setLocalDescription(offer);
162
- var message = '{"teleport-signal-type":"offer","sdp":"'+offer.sdp+'"}'; //
163
- this.sendConfigMessage(this.id,message);
164
- await this.waitUntilIceGatheringStateComplete(this.peerConnection, this.options);
165
- } catch (error)
166
- {
167
- console.error("doOffer error: "+error.toString());
168
- this.close();
169
- console.log("doOffer close");
170
- }
171
- };
172
-
173
- this.applyAnswer = async answer =>
174
- {
175
- console.log("received remote answer.");
176
- var escapedStr=answer.toString();
177
- try{
178
- escapedStr=escapedStr.replaceAll('\r','\\r');
179
- escapedStr=escapedStr.replaceAll('\n','\\n');
180
- } catch(error)
181
- {
182
- console.error("applyAnswer error: "+error.toString());
183
- }
184
- var sessionDescription=new wrtc.RTCSessionDescription();
185
- sessionDescription.sdp=answer;
186
- sessionDescription.type="answer";
187
- if(this.peerConnection)
188
- await this.peerConnection.setRemoteDescription( sessionDescription);
189
- };
190
- this.applyRemoteCandidate = async(candidate_txt,mid,mlineindex)=>
191
- {
192
- console.log("received remote candidate: "+candidate_txt);
193
- const ice=new wrtc.RTCIceCandidate({
194
- candidate: candidate_txt,
195
- sdpMLineIndex: mlineindex,
196
- sdpMid: mid
197
- });
198
- if(this.peerConnection)
199
- this.peerConnection.addIceCandidate(ice).catch((e)=>{
200
- console.log(`Failure during addIceCandidate(): ${e.name}`);
201
- });
202
- };
203
-
204
- this.toJSON = () =>
205
- {
206
- return {
207
- id: this.id,
208
- state: this.state,
209
- iceConnectionState: this.iceConnectionState,
210
- localDescription: this.localDescription,
211
- remoteDescription: this.remoteDescription,
212
- signalingState: this.signalingState
213
- };
214
- };
215
- }
216
- onIceConnectionStateChange()
217
- {
218
- if(!this.peerConnection)
219
- return;
220
- console.log("ICE state changed to: "+this.peerConnection.iceConnectionState);
221
- if (this.peerConnection.iceConnectionState === 'connected'
222
- || this.peerConnection.iceConnectionState === 'completed')
223
- {
224
- if (this.connectionTimer)
225
- {
226
- this.options.clearTimeout(this.connectionTimer);
227
- this.connectionTimer = null;
228
- }
229
- this.options.clearTimeout(this.reconnectionTimer);
230
- this.reconnectionTimer = null;
231
- } else if (this.peerConnection.iceConnectionState === 'disconnected'
232
- || this.peerConnection.iceConnectionState === 'failed')
233
- {
234
- this.peerConnection.restartIce();
235
- console.log("restartIce()");
236
- if (!this.connectionTimer && !this.reconnectionTimer)
237
- {
238
- const self = this;
239
- this.reconnectionTimer = this.options.setTimeout(() =>
240
- {
241
- this.reconnect();
242
- this.doOffer();
243
- }, this.options.timeToReconnected);
244
- }
245
- }
246
- }
247
- onIceGatheringStateChange()
248
- {
249
- // This could get hit in the WebRtcConnection constructor where we've had no chance to set the peerConnection pointer!
250
- if(this.peerConnection)
251
- console.log("ICE gathering state changed to: "+this.peerConnection.iceGatheringState);
252
- }
253
-
254
- close()
255
- {
256
- console.log("WebRtcConnection.close()");
257
- if(this.peerConnection)
258
- {
259
- this.peerConnection.removeEventListener('iceconnectionstatechange', this.onIceConnectionStateChange.bind(this));
260
-
261
- this.peerConnection.eve
262
- this.peerConnection.removeEventListener('iceconnectionstatechange', this.onIceConnectionStateChange.bind(this));
263
- this.peerConnection.removeEventListener('icegatheringstatechange', this.onIceGatheringStateChange.bind(this));
264
- //this.peerConnection.removeEventListener("icecandidateerror", (event) => {
265
- this.peerConnection.removeEventListener("connectionstatechange", this.connectionStateChanged.bind(this));
266
- }
267
- if (this.connectionTimer)
268
- {
269
- this.options.clearTimeout(this.connectionTimer);
270
- this.connectionTimer = null;
271
- }
272
- if (this.reconnectionTimer)
273
- {
274
- this.options.clearTimeout(this.reconnectionTimer);
275
- this.reconnectionTimer = null;
276
- }
277
-
278
- // Check the connection state
279
- if(this.peerConnection)
280
- if (this.peerConnection.connectionState == "connected" ||
281
- this.peerConnection.connectionState == "failed")
282
- {
283
- // Close each track
284
- /* this.peerConnection.cl.forEach(mediaStream => { {
285
- mediaStream.videoTracks.forEach( it => {it.setEnabled(false); });
286
- mediaStream.audioTracks.forEach( it => {it.setEnabled(false); });
287
-
288
- };
289
- });;6'7*/
290
-
291
- // Close the connection
292
- this.peerConnection.close();
293
- }
294
-
295
- // Nullify the reference
296
- this.peerConnection = null;
297
- this.state = 'closed';
298
- this.emit('closed');
299
- };
300
- sendGeometry(buffer) {
301
- try {
302
- this.geometryDataChannel.send(buffer);
303
- }
304
- catch(exception) {
305
- console.error('datachannel.sendGeometry exception: '+exception.message);
306
- }
307
- }
308
- beforeOffer() {
309
-
310
- this.videoDataChannel = this.createDataChannel("video",20);
311
- this.tagDataChannel = this.createDataChannel("video_tags",40);
312
- this.audioToClientDataChannel = this.createDataChannel("audio_server_to_client",60);
313
- this.geometryDataChannel = this.createDataChannel("geometry_unframed",80);
314
- this.reliableDataChannel = this.createDataChannel("reliable",100);
315
- this.unreliableDataChannel = this.createDataChannel("unreliable",120,false);
316
-
317
- function onMessage({ data }) {
318
- if (data === 'ping') {
319
- //dataChannel.send('pong');
320
- }
321
- }
322
-
323
- // NOTE(mroberts): This is a hack so that we can get a callback when the
324
- // RTCPeerConnection is closed. In the future, we can subscribe to
325
- // "connectionstatechange" events.
326
- const { close } = this.peerConnection;
327
- var self=this;
328
- this.peerConnection.close = function() {
329
- //self.dataChannel.removeEventListener('message', onMessage);
330
- return close.apply(this, arguments);
331
- };
332
- }
333
-
334
- receiveMessage(id,event)
335
- {
336
- //.videoDataChannel = .("video",20);
337
- //.tagDataChannel = .("video_tags",40);
338
- //.audioToClientDataChannel = .("audio_server_to_client",60);
339
- //.geometryDataChannel =l("geometry_unframed",80);
340
- //.reliableDataChannel =l("reliable",100);
341
- //.unreliableDataChannelnel("unreliable",120,false);
342
- switch(id)
343
- {
344
- case 120:
345
- this.messageReceivedUnreliableCb(id,event);
346
- break;
347
- case 100:
348
- this.messageReceivedReliableCb(id,event);
349
- break;
350
- default:
351
- break;
352
- }
353
- // event is an ArrayBuffer.
354
- };
355
- createDataChannel(label,id,reliable=true)
356
- {
357
- //See https://web.dev/articles/webrtc-datachannels. Can only use id if negotiated=true.
358
- const dataChannelOptions={ordered:reliable,maxRetransmits:reliable?10000:0,id:id};
359
-
360
- var dc=this.peerConnection.createDataChannel(label,dataChannelOptions);
361
-
362
- dc.onmessage = this.receiveMessage.bind(this,id);
363
-
364
- dc.onopen = (event) => {
365
- console.log('datachannel '+label+' open');
366
- //dc.send('XXXX');
367
- };
368
-
369
- dc.onclose = (event) => {
370
- console.log('datachannel '+label+' close');
371
- };
372
-
373
- dc.onclosing = (event) => {
374
- console.log('datachannel '+label+' onclosing');
375
- };
376
-
377
-
378
- dc.onbufferedamountlow = (event) => {
379
- console.log('datachannel '+label+' onbufferedamountlow;');
380
- };
381
-
382
-
383
- // dc.addEventListener('message', onMessage);
384
- return dc;
385
- }
386
- receiveStreamingControlMessage(txt)
387
- {
388
- var message = JSON.parse(txt);
389
- if (!message.hasOwnProperty("teleport-signal-type"))
390
- {
391
- console.error("Streaming message ill-formed.");
392
- return;
393
- }
394
- var teleport_signal_type=message["teleport-signal-type"];
395
- if (teleport_signal_type == "answer")
396
- {
397
- var sdp = message["sdp"];
398
- this.receiveAnswer(sdp);
399
- }
400
- else if (teleport_signal_type == "candidate")
401
- {
402
- var candidate = message["candidate"];
403
- var mid = message["mid"];
404
- var mlineindex = message["mlineindex"];
405
- this.applyRemoteCandidate(candidate, mid, mlineindex);
406
- }
407
- }
408
- receiveAnswer(sdp)
409
- {
410
- this.applyAnswer(sdp);
411
- }
412
- receiveCandidate(candidate,mid,mlineindex)
413
- {
414
- peerConn.addIceCandidate(new RTCIceCandidate({
415
- candidate: message.candidate,
416
- sdpMLineIndex: message.label,
417
- sdpMid: message.id
418
- }));
419
- }
420
-
421
- }
422
-
423
-
424
- function descriptionToJSON (description, shouldDisableTrickleIce)
425
- {
426
- return !description ? {} : {
427
- type: description.type,
428
- sdp: shouldDisableTrickleIce ? disableTrickleIce(description.sdp) : description.sdp
429
- };
430
- }
431
-
432
- function disableTrickleIce (sdp)
433
- {
434
- return sdp.replace(/\r\na=ice-options:trickle/g, '');
435
- }
436
-
437
- module.exports = WebRtcConnection;
1
+ 'use strict';
2
+
3
+ const EventEmitter = require('events');
4
+ const wrtc =require('@roamhq/wrtc');
5
+ const DefaultRTCPeerConnection = require('@roamhq/wrtc').RTCPeerConnection;
6
+
7
+ const TIME_TO_CONNECTED = 30000;
8
+ const TIME_TO_HOST_CANDIDATES = 3000; // NOTE: Too long.
9
+ const TIME_TO_RECONNECTED = 1000;
10
+ function EVEN_ID(id) {
11
+ return (id-(id%2))
12
+ }
13
+ function ODD_ID(id) {
14
+ return (EVEN_ID(id)+1)
15
+ }
16
+ class WebRtcConnection extends EventEmitter
17
+ {
18
+ constructor(id, options = {})
19
+ {
20
+ super();
21
+ const iceServers=[
22
+ "stun:stun.l.google.com:19302"
23
+ ];
24
+ this.iceServers = [] ;
25
+ for(const s in iceServers)
26
+ {
27
+ this.iceServers.push({ 'urls': iceServers[s] });
28
+ }
29
+ //this.iceServers=[{'urls': 'stun:stun.l.google.com:19302'}];
30
+ this.id = id;
31
+ this.state = 'open';
32
+
33
+ this.options = {
34
+ RTCPeerConnection: DefaultRTCPeerConnection,
35
+ clearTimeout,
36
+ setTimeout,
37
+ timeToConnected: TIME_TO_CONNECTED,
38
+ timeToHostCandidates: TIME_TO_HOST_CANDIDATES,
39
+ timeToReconnected: TIME_TO_RECONNECTED,
40
+ ...options
41
+ };
42
+
43
+ const {
44
+ RTCPeerConnection,
45
+ timeToConnected,
46
+ timeToReconnected
47
+ } = options;
48
+
49
+ this.messageReceivedReliableCb =options.messageReceivedReliable;
50
+ this.messageReceivedUnreliableCb =options.messageReceivedUnreliable;
51
+ this.connectionStateChangedCb=options.connectionStateChanged;
52
+ this.sendConfigMessage =options.sendConfigMessage;
53
+
54
+
55
+ Object.defineProperties(this, {
56
+ iceConnectionState: {
57
+ get ()
58
+ {
59
+ return this.peerConnection.iceConnectionState;
60
+ }
61
+ },
62
+ localDescription: {
63
+ get ()
64
+ {
65
+ return descriptionToJSON(this.peerConnection.localDescription, true);
66
+ }
67
+ },
68
+ remoteDescription: {
69
+ get ()
70
+ {
71
+ return descriptionToJSON(this.peerConnection.remoteDescription);
72
+ }
73
+ },
74
+ signalingState: {
75
+ get ()
76
+ {
77
+ return this.peerConnection.signalingState;
78
+ }
79
+ }
80
+ });
81
+ this.reconnect();
82
+ }
83
+ connectionStateChanged()
84
+ {
85
+ if(!this.peerConnection)
86
+ return;
87
+ this.connectionStateChangedCb(this.peerConnection.connectionState);
88
+ }
89
+ reconnect()
90
+ {
91
+ this.peerConnection =new DefaultRTCPeerConnection({ sdpSemantics: 'unified-plan', 'iceServers': this.iceServers});
92
+ this.beforeOffer();
93
+ this.connectionTimer = this.options.setTimeout(() =>
94
+ {
95
+ if (this.peerConnection.iceConnectionState !== 'connected'
96
+ && this.peerConnection.iceConnectionState !== 'completed')
97
+ {
98
+ console.log("WebRtcConnection timeout, this.peerConnection.iceConnectionState = "+this.peerConnection.iceConnectionState);
99
+ this.close();
100
+ }
101
+ }, this.options.timeToConnected);
102
+
103
+ this.reconnectionTimer = null;
104
+
105
+ this.peerConnection.addEventListener('iceconnectionstatechange', this.onIceConnectionStateChange.bind(this));
106
+ this.peerConnection.addEventListener('icegatheringstatechange', this.onIceGatheringStateChange.bind(this));
107
+ this.peerConnection.addEventListener("icecandidateerror", (event) => {
108
+
109
+ console.log("ICE candidate error: "+event.errorCode+" "+event.errorText+" "+event.port+" "+event.url);
110
+ });
111
+
112
+ this.peerConnection.addEventListener("connectionstatechange", this.connectionStateChanged.bind(this));
113
+
114
+ this.onIceCandidate= ({ candidate })=>
115
+ {
116
+ if (!candidate)
117
+ {
118
+ this.options.clearTimeout(this.timeout);
119
+ //this.peerConnection.removeEventListener('icecandidate', this.onIceCandidate);
120
+ this.deferred.resolve();
121
+ return;
122
+ }
123
+ // send the candidate
124
+ var mid=candidate.sdpMid;
125
+ var mlineindex=candidate.sdpMLineIndex;
126
+ var message = '{"teleport-signal-type":"candidate","candidate":"'+candidate.candidate+'","mid":"'+mid.toString()+'","mlineindex":'+mlineindex.toString()+'}';
127
+ this.sendConfigMessage(this.id,message);
128
+ }
129
+ this.waitUntilIceGatheringStateComplete= async (peerConnection, options) =>
130
+ {
131
+ if (peerConnection.iceGatheringState === 'complete')
132
+ {
133
+ return;
134
+ }
135
+
136
+ const { timeToHostCandidates } = options;
137
+
138
+ this.deferred = {};
139
+ this.deferred.promise = new Promise((resolve, reject) =>
140
+ {
141
+ this.deferred.resolve = resolve;
142
+ this.deferred.reject = reject;
143
+ });
144
+
145
+ this.timeout = options.setTimeout(() =>
146
+ {
147
+ peerConnection.removeEventListener('icecandidate', this.onIceCandidate.bind(this));
148
+ this.deferred.reject(new Error('Timed out waiting for host candidates'));
149
+ }, timeToHostCandidates);
150
+
151
+ peerConnection.addEventListener('icecandidate', this.onIceCandidate.bind(this));
152
+
153
+ await this.deferred.promise;
154
+ }
155
+
156
+ this.doOffer = async () =>
157
+ {
158
+ try
159
+ {
160
+ const offer = await this.peerConnection.createOffer();
161
+ await this.peerConnection.setLocalDescription(offer);
162
+ var message = '{"teleport-signal-type":"offer","sdp":"'+offer.sdp+'"}'; //
163
+ this.sendConfigMessage(this.id,message);
164
+ await this.waitUntilIceGatheringStateComplete(this.peerConnection, this.options);
165
+ } catch (error)
166
+ {
167
+ console.error("doOffer error: "+error.toString());
168
+ this.close();
169
+ console.log("doOffer close");
170
+ }
171
+ };
172
+
173
+ this.applyAnswer = async answer =>
174
+ {
175
+ console.log("received remote answer.");
176
+ var escapedStr=answer.toString();
177
+ try{
178
+ escapedStr=escapedStr.replaceAll('\r','\\r');
179
+ escapedStr=escapedStr.replaceAll('\n','\\n');
180
+ } catch(error)
181
+ {
182
+ console.error("applyAnswer error: "+error.toString());
183
+ }
184
+ var sessionDescription=new wrtc.RTCSessionDescription();
185
+ sessionDescription.sdp=answer;
186
+ sessionDescription.type="answer";
187
+ if(this.peerConnection)
188
+ await this.peerConnection.setRemoteDescription( sessionDescription);
189
+ };
190
+ this.applyRemoteCandidate = async(candidate_txt,mid,mlineindex)=>
191
+ {
192
+ console.log("received remote candidate: "+candidate_txt);
193
+ const ice=new wrtc.RTCIceCandidate({
194
+ candidate: candidate_txt,
195
+ sdpMLineIndex: mlineindex,
196
+ sdpMid: mid
197
+ });
198
+ if(this.peerConnection)
199
+ this.peerConnection.addIceCandidate(ice).catch((e)=>{
200
+ console.log(`Failure during addIceCandidate(): ${e.name}`);
201
+ });
202
+ };
203
+
204
+ this.toJSON = () =>
205
+ {
206
+ return {
207
+ id: this.id,
208
+ state: this.state,
209
+ iceConnectionState: this.iceConnectionState,
210
+ localDescription: this.localDescription,
211
+ remoteDescription: this.remoteDescription,
212
+ signalingState: this.signalingState
213
+ };
214
+ };
215
+ }
216
+ onIceConnectionStateChange()
217
+ {
218
+ if(!this.peerConnection)
219
+ return;
220
+ console.log("ICE state changed to: "+this.peerConnection.iceConnectionState);
221
+ if (this.peerConnection.iceConnectionState === 'connected'
222
+ || this.peerConnection.iceConnectionState === 'completed')
223
+ {
224
+ if (this.connectionTimer)
225
+ {
226
+ this.options.clearTimeout(this.connectionTimer);
227
+ this.connectionTimer = null;
228
+ }
229
+ this.options.clearTimeout(this.reconnectionTimer);
230
+ this.reconnectionTimer = null;
231
+ } else if (this.peerConnection.iceConnectionState === 'disconnected'
232
+ || this.peerConnection.iceConnectionState === 'failed')
233
+ {
234
+ this.peerConnection.restartIce();
235
+ console.log("restartIce()");
236
+ if (!this.connectionTimer && !this.reconnectionTimer)
237
+ {
238
+ const self = this;
239
+ this.reconnectionTimer = this.options.setTimeout(() =>
240
+ {
241
+ this.reconnect();
242
+ this.doOffer();
243
+ }, this.options.timeToReconnected);
244
+ }
245
+ }
246
+ }
247
+ onIceGatheringStateChange()
248
+ {
249
+ // This could get hit in the WebRtcConnection constructor where we've had no chance to set the peerConnection pointer!
250
+ if(this.peerConnection)
251
+ console.log("ICE gathering state changed to: "+this.peerConnection.iceGatheringState);
252
+ }
253
+
254
+ close()
255
+ {
256
+ console.log("WebRtcConnection.close()");
257
+ if(this.peerConnection)
258
+ {
259
+ this.peerConnection.removeEventListener('iceconnectionstatechange', this.onIceConnectionStateChange.bind(this));
260
+
261
+ this.peerConnection.eve
262
+ this.peerConnection.removeEventListener('iceconnectionstatechange', this.onIceConnectionStateChange.bind(this));
263
+ this.peerConnection.removeEventListener('icegatheringstatechange', this.onIceGatheringStateChange.bind(this));
264
+ //this.peerConnection.removeEventListener("icecandidateerror", (event) => {
265
+ this.peerConnection.removeEventListener("connectionstatechange", this.connectionStateChanged.bind(this));
266
+ }
267
+ if (this.connectionTimer)
268
+ {
269
+ this.options.clearTimeout(this.connectionTimer);
270
+ this.connectionTimer = null;
271
+ }
272
+ if (this.reconnectionTimer)
273
+ {
274
+ this.options.clearTimeout(this.reconnectionTimer);
275
+ this.reconnectionTimer = null;
276
+ }
277
+
278
+ // Check the connection state
279
+ if(this.peerConnection)
280
+ if (this.peerConnection.connectionState == "connected" ||
281
+ this.peerConnection.connectionState == "failed")
282
+ {
283
+ // Close each track
284
+ /* this.peerConnection.cl.forEach(mediaStream => { {
285
+ mediaStream.videoTracks.forEach( it => {it.setEnabled(false); });
286
+ mediaStream.audioTracks.forEach( it => {it.setEnabled(false); });
287
+
288
+ };
289
+ });;6'7*/
290
+
291
+ // Close the connection
292
+ this.peerConnection.close();
293
+ }
294
+
295
+ // Nullify the reference
296
+ this.peerConnection = null;
297
+ this.state = 'closed';
298
+ this.emit('closed');
299
+ };
300
+ sendGeometry(buffer) {
301
+ try {
302
+ this.geometryDataChannel.send(buffer);
303
+ }
304
+ catch(exception) {
305
+ console.error('datachannel.sendGeometry exception: '+exception.message);
306
+ }
307
+ }
308
+ beforeOffer() {
309
+
310
+ this.videoDataChannel = this.createDataChannel("video",20);
311
+ this.tagDataChannel = this.createDataChannel("video_tags",40);
312
+ this.audioToClientDataChannel = this.createDataChannel("audio_server_to_client",60);
313
+ this.geometryDataChannel = this.createDataChannel("geometry_unframed",80);
314
+ this.reliableDataChannel = this.createDataChannel("reliable",100);
315
+ this.unreliableDataChannel = this.createDataChannel("unreliable",120,false);
316
+
317
+ function onMessage({ data }) {
318
+ if (data === 'ping') {
319
+ //dataChannel.send('pong');
320
+ }
321
+ }
322
+
323
+ // NOTE(mroberts): This is a hack so that we can get a callback when the
324
+ // RTCPeerConnection is closed. In the future, we can subscribe to
325
+ // "connectionstatechange" events.
326
+ const { close } = this.peerConnection;
327
+ var self=this;
328
+ this.peerConnection.close = function() {
329
+ //self.dataChannel.removeEventListener('message', onMessage);
330
+ return close.apply(this, arguments);
331
+ };
332
+ }
333
+
334
+ receiveMessage(id,event)
335
+ {
336
+ //.videoDataChannel = .("video",20);
337
+ //.tagDataChannel = .("video_tags",40);
338
+ //.audioToClientDataChannel = .("audio_server_to_client",60);
339
+ //.geometryDataChannel =l("geometry_unframed",80);
340
+ //.reliableDataChannel =l("reliable",100);
341
+ //.unreliableDataChannelnel("unreliable",120,false);
342
+ switch(id)
343
+ {
344
+ case 120:
345
+ this.messageReceivedUnreliableCb(id,event);
346
+ break;
347
+ case 100:
348
+ this.messageReceivedReliableCb(id,event);
349
+ break;
350
+ default:
351
+ break;
352
+ }
353
+ // event is an ArrayBuffer.
354
+ };
355
+ createDataChannel(label,id,reliable=true)
356
+ {
357
+ //See https://web.dev/articles/webrtc-datachannels. Can only use id if negotiated=true.
358
+ const dataChannelOptions={ordered:reliable,maxRetransmits:reliable?10000:0,id:id};
359
+
360
+ var dc=this.peerConnection.createDataChannel(label,dataChannelOptions);
361
+
362
+ dc.onmessage = this.receiveMessage.bind(this,id);
363
+
364
+ dc.onopen = (event) => {
365
+ console.log('datachannel '+label+' open');
366
+ //dc.send('XXXX');
367
+ };
368
+
369
+ dc.onclose = (event) => {
370
+ console.log('datachannel '+label+' close');
371
+ };
372
+
373
+ dc.onclosing = (event) => {
374
+ console.log('datachannel '+label+' onclosing');
375
+ };
376
+
377
+
378
+ dc.onbufferedamountlow = (event) => {
379
+ console.log('datachannel '+label+' onbufferedamountlow;');
380
+ };
381
+
382
+
383
+ // dc.addEventListener('message', onMessage);
384
+ return dc;
385
+ }
386
+ receiveStreamingControlMessage(txt)
387
+ {
388
+ var message = JSON.parse(txt);
389
+ if (!message.hasOwnProperty("teleport-signal-type"))
390
+ {
391
+ console.error("Streaming message ill-formed.");
392
+ return;
393
+ }
394
+ var teleport_signal_type=message["teleport-signal-type"];
395
+ if (teleport_signal_type == "answer")
396
+ {
397
+ var sdp = message["sdp"];
398
+ this.receiveAnswer(sdp);
399
+ }
400
+ else if (teleport_signal_type == "candidate")
401
+ {
402
+ var candidate = message["candidate"];
403
+ var mid = message["mid"];
404
+ var mlineindex = message["mlineindex"];
405
+ this.applyRemoteCandidate(candidate, mid, mlineindex);
406
+ }
407
+ }
408
+ receiveAnswer(sdp)
409
+ {
410
+ this.applyAnswer(sdp);
411
+ }
412
+ receiveCandidate(candidate,mid,mlineindex)
413
+ {
414
+ peerConn.addIceCandidate(new RTCIceCandidate({
415
+ candidate: message.candidate,
416
+ sdpMLineIndex: message.label,
417
+ sdpMid: message.id
418
+ }));
419
+ }
420
+
421
+ }
422
+
423
+
424
+ function descriptionToJSON (description, shouldDisableTrickleIce)
425
+ {
426
+ return !description ? {} : {
427
+ type: description.type,
428
+ sdp: shouldDisableTrickleIce ? disableTrickleIce(description.sdp) : description.sdp
429
+ };
430
+ }
431
+
432
+ function disableTrickleIce (sdp)
433
+ {
434
+ return sdp.replace(/\r\na=ice-options:trickle/g, '');
435
+ }
436
+
437
+ module.exports = WebRtcConnection;