teleportxr 1.0.16 → 1.0.18

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.
package/client/client.js CHANGED
@@ -38,7 +38,7 @@ class Client {
38
38
  tick(timestamp){
39
39
  this.geometryService.GetNodesToSend();
40
40
  }
41
- streamingConnectionStateChanged(wrtcConn,newState)
41
+ streamingConnectionStateChanged(newState)
42
42
  {
43
43
  //this.webRtcConnection=wrtcConn;
44
44
  // This should have come from our own existing webRtcConnection and nowhere else.
@@ -140,6 +140,13 @@ class Client {
140
140
  // function(value) {myDisplayer(value);},
141
141
  // function(error) {myDisplayer(error);}
142
142
  }
143
+ //! Cleanly shut down the WebRTC connection. This may be called when the client has signalled that it is
144
+ //! disconnecting, or when the server determines that the client is lost or needs to be booted.
145
+ StopStreaming()
146
+ {
147
+ this.webRtcConnectionManager.destroyConnection(this.clientID);
148
+ this.webRtcConnection=null;
149
+ }
143
150
  // Generic message acknowledgement. Certain kinds of message are expected to be ack'ed.
144
151
  ReceiveAcknowledgement(data)
145
152
  {
@@ -239,6 +246,7 @@ class Client {
239
246
  if(!this.webRtcConnection.sendGeometry)
240
247
  {
241
248
  console.error("this.webRtcConnection.sendGeometry is null");
249
+ console.log(JSON.stringify(this.webRtcConnection));
242
250
  return;
243
251
  }
244
252
  this.webRtcConnection.sendGeometry(view2);
@@ -94,6 +94,13 @@ class ClientManager
94
94
  c.Start();
95
95
  return c;
96
96
  }
97
+ disconnectClient(clientID) {
98
+ // then we tell the client manager to start this client.
99
+ var c=this.GetClient(clientID);
100
+ if(!c)
101
+ return;
102
+ c.StopStreaming();
103
+ }
97
104
  writeState() {
98
105
  var content="<table><tr><th>Client Id</th><th>IP Address</th><th>Signalling State</th></tr>";
99
106
  for (let [cl_id,cl] of this.clients) {
@@ -46,10 +46,9 @@ class WebRtcConnection extends EventEmitter
46
46
  timeToReconnected
47
47
  } = options;
48
48
 
49
- this.connectionStateChanged =options.connectionStateChanged;
50
49
  this.messageReceivedReliableCb =options.messageReceivedReliable;
51
50
  this.messageReceivedUnreliableCb =options.messageReceivedUnreliable;
52
-
51
+ this.connectionStateChangedCb=options.connectionStateChanged;
53
52
  this.sendConfigMessage =options.sendConfigMessage;
54
53
 
55
54
 
@@ -81,12 +80,17 @@ class WebRtcConnection extends EventEmitter
81
80
  });
82
81
  this.reconnect();
83
82
  }
84
-
83
+ connectionStateChanged()
84
+ {
85
+ if(!this.peerConnection)
86
+ return;
87
+ this.connectionStateChangedCb(this.peerConnection.connectionState);
88
+ }
85
89
  reconnect()
86
90
  {
87
91
  this.peerConnection =new DefaultRTCPeerConnection({ sdpSemantics: 'unified-plan', 'iceServers': this.iceServers});
88
92
  this.beforeOffer();
89
- let connectionTimer = this.options.setTimeout(() =>
93
+ this.connectionTimer = this.options.setTimeout(() =>
90
94
  {
91
95
  if (this.peerConnection.iceConnectionState !== 'connected'
92
96
  && this.peerConnection.iceConnectionState !== 'completed')
@@ -96,55 +100,16 @@ class WebRtcConnection extends EventEmitter
96
100
  }
97
101
  }, this.options.timeToConnected);
98
102
 
99
- let reconnectionTimer = null;
100
-
101
- const onIceConnectionStateChange = () =>
102
- {
103
- console.log("ICE state changed to: "+this.peerConnection.iceConnectionState);
104
- if (this.peerConnection.iceConnectionState === 'connected'
105
- || this.peerConnection.iceConnectionState === 'completed')
106
- {
107
- if (connectionTimer)
108
- {
109
- this.options.clearTimeout(connectionTimer);
110
- connectionTimer = null;
111
- }
112
- this.options.clearTimeout(reconnectionTimer);
113
- reconnectionTimer = null;
114
- } else if (this.peerConnection.iceConnectionState === 'disconnected'
115
- || this.peerConnection.iceConnectionState === 'failed')
116
- {
117
- this.peerConnection.restartIce();
118
- console.log("restartIce()");
119
- if (!connectionTimer && !reconnectionTimer)
120
- {
121
- const self = this;
122
- reconnectionTimer = this.options.setTimeout(() =>
123
- {
124
- this.reconnect();
125
- this.doOffer();
126
- }, this.options.timeToReconnected);
127
- }
128
- }
129
- };
130
- const onIceGatheringStateChange = () =>
131
- {
132
- console.log("ICE gathering state changed to: "+this.peerConnection.iceGatheringState);
133
- };
103
+ this.reconnectionTimer = null;
134
104
 
135
- this.peerConnection.addEventListener('iceconnectionstatechange', onIceConnectionStateChange);
136
- this.peerConnection.addEventListener('icegatheringstatechange', onIceGatheringStateChange);
105
+ this.peerConnection.addEventListener('iceconnectionstatechange', this.onIceConnectionStateChange.bind(this));
106
+ this.peerConnection.addEventListener('icegatheringstatechange', this.onIceGatheringStateChange.bind(this));
137
107
  this.peerConnection.addEventListener("icecandidateerror", (event) => {
138
108
 
139
109
  console.log("ICE candidate error: "+event.errorCode+" "+event.errorText+" "+event.port+" "+event.url);
140
110
  });
141
111
 
142
- const onConnectionStateChange = () =>
143
- {
144
- console.log("Connection State changed to: "+this.peerConnection.connectionState.toString());
145
- this.connectionStateChanged(this,this.peerConnection.connectionState);
146
- }
147
- this.peerConnection.addEventListener("connectionstatechange", onConnectionStateChange);
112
+ this.peerConnection.addEventListener("connectionstatechange", this.connectionStateChanged.bind(this));
148
113
 
149
114
  this.onIceCandidate= ({ candidate })=>
150
115
  {
@@ -179,11 +144,11 @@ class WebRtcConnection extends EventEmitter
179
144
 
180
145
  this.timeout = options.setTimeout(() =>
181
146
  {
182
- peerConnection.removeEventListener('icecandidate', this.onIceCandidate);
147
+ peerConnection.removeEventListener('icecandidate', this.onIceCandidate.bind(this));
183
148
  this.deferred.reject(new Error('Timed out waiting for host candidates'));
184
149
  }, timeToHostCandidates);
185
150
 
186
- peerConnection.addEventListener('icecandidate', this.onIceCandidate);
151
+ peerConnection.addEventListener('icecandidate', this.onIceCandidate.bind(this));
187
152
 
188
153
  await this.deferred.promise;
189
154
  }
@@ -202,7 +167,6 @@ class WebRtcConnection extends EventEmitter
202
167
  console.error("doOffer error: "+error.toString());
203
168
  this.close();
204
169
  console.log("doOffer close");
205
- throw error;
206
170
  }
207
171
  };
208
172
 
@@ -220,6 +184,7 @@ class WebRtcConnection extends EventEmitter
220
184
  var sessionDescription=new wrtc.RTCSessionDescription();
221
185
  sessionDescription.sdp=answer;
222
186
  sessionDescription.type="answer";
187
+ if(this.peerConnection)
223
188
  await this.peerConnection.setRemoteDescription( sessionDescription);
224
189
  };
225
190
  this.applyRemoteCandidate = async(candidate_txt,mid,mlineindex)=>
@@ -230,28 +195,11 @@ class WebRtcConnection extends EventEmitter
230
195
  sdpMLineIndex: mlineindex,
231
196
  sdpMid: mid
232
197
  });
198
+ if(this.peerConnection)
233
199
  this.peerConnection.addIceCandidate(ice).catch((e)=>{
234
200
  console.log(`Failure during addIceCandidate(): ${e.name}`);
235
201
  });
236
202
  };
237
- this.close = () =>
238
- {
239
- console.log("WebRtcConnection.close()");
240
- this.peerConnection.removeEventListener('iceconnectionstatechange', onIceConnectionStateChange);
241
- if (connectionTimer)
242
- {
243
- this.options.clearTimeout(connectionTimer);
244
- connectionTimer = null;
245
- }
246
- if (reconnectionTimer)
247
- {
248
- this.options.clearTimeout(reconnectionTimer);
249
- reconnectionTimer = null;
250
- }
251
- this.peerConnection.close();
252
- this.state = 'closed';
253
- this.emit('closed');
254
- };
255
203
 
256
204
  this.toJSON = () =>
257
205
  {
@@ -265,6 +213,90 @@ class WebRtcConnection extends EventEmitter
265
213
  };
266
214
  };
267
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
+ };
268
300
  sendGeometry(buffer) {
269
301
  try {
270
302
  this.geometryDataChannel.send(buffer);
@@ -281,7 +313,6 @@ class WebRtcConnection extends EventEmitter
281
313
  this.geometryDataChannel = this.createDataChannel("geometry_unframed",80);
282
314
  this.reliableDataChannel = this.createDataChannel("reliable",100);
283
315
  this.unreliableDataChannel = this.createDataChannel("unreliable",120,false);
284
- // this.dataChannel = this.peerConnection.createDataChannel('ping-pong',{id:2050});
285
316
 
286
317
  function onMessage({ data }) {
287
318
  if (data === 'ping') {
@@ -6,56 +6,65 @@ class WebRtcConnectionManager
6
6
  {
7
7
  constructor(options = {})
8
8
  {
9
- options = {
10
- Connection: WebRtcConnection,
11
- ...options
12
- };
13
- const { Connection } = options;
14
- const connections = new Map();
15
- const closedListeners = new Map();
9
+ this.connections = new Map();
10
+ this.closedListeners = new Map();
11
+ this.options=options;
12
+ }
16
13
 
17
- function deleteConnection(connection) {
14
+ deleteConnection(connection)
15
+ {
16
+ console.log("deleteConnection "+connection.clientID);
18
17
  // 1. Remove "closed" listener?
19
- //const closedListener = closedListeners.get(connection);
18
+ //const closedListener = this.closedListeners.get(connection);
20
19
  //connection.removeListener("closed", closedListener);
21
- //closedListeners.delete(connection);
20
+ //this.closedListeners.delete(connection);
21
+
22
+ // 2. Remove the WebRtcConnection from the Map.
23
+ this.connections.delete(connection.id);
24
+ }
25
+ getConnection(id)
26
+ {
27
+ return this.connections.get(id) || null;
28
+ }
29
+
30
+ getConnections()
31
+ {
32
+ return [...this.connections.values()];
33
+ };
22
34
 
23
- // 2. Remove the Connection from the Map.
24
- connections.delete(connection.id);
25
- }
26
35
 
27
- this.createConnection = (clientID,connectionStateChangedcb,messageReceivedReliableCb,messageReceivedUnreliableCb) =>
28
- {
29
- options.sendConfigMessage =this.sendConfigMessage;
30
-
31
- options.messageReceivedReliable =messageReceivedReliableCb;
32
- options.messageReceivedUnreliable =messageReceivedUnreliableCb;
33
- const connection = new Connection(clientID,options);
34
- connection.connectionStateChanged=connectionStateChangedcb;
35
- // 1. Add the "closed" listener.
36
- function closedListener() { deleteConnection(connection); }
37
- this.createConnection = (clientID) =>
38
- closedListeners.set(connection, closedListener);
39
- connection.once('closed', closedListener);
36
+ closedListener()
37
+ {
38
+ this.deleteConnection(connection);
39
+ }
40
+ createConnection(clientID,connectionStateChangedcb,messageReceivedReliableCb,messageReceivedUnreliableCb)
41
+ {
42
+ var options=this.options;
43
+ options.sendConfigMessage =this.sendConfigMessage;
44
+
45
+ options.messageReceivedReliable =messageReceivedReliableCb;
46
+ options.messageReceivedUnreliable =messageReceivedUnreliableCb;
47
+ options.connectionStateChanged =connectionStateChangedCb;
48
+ const connection = new WebRtcConnection(clientID,options);
49
+ // We will not add a "closed" listener, because only the client object will be permitted to close its connection.
50
+ //this.createConnection = (clientID) => this.closedListeners.set(connection, this.closedListener);
51
+ //connection.once('closed', this.closedListener);
40
52
 
41
- // 2. Add the Connection to the Map.
42
- connections.set(connection.id, connection);
53
+ // 2. Add the WebRtcConnection to the Map.
54
+ this.connections.set(connection.id, connection);
43
55
 
44
56
  connection.doOffer();
45
57
  return connection;
46
58
  };
47
-
48
- this.getConnection = id =>
59
+ destroyConnection(clientID)
49
60
  {
50
- return connections.get(id) || null;
51
- };
52
-
53
- this.getConnections = () =>
61
+ var connection=this.connections.get(clientID);
62
+ if(connection)
54
63
  {
55
- return [...connections.values()];
56
- };
64
+ connection.close();
65
+ this.connections.delete(clientID);
57
66
  }
58
-
67
+ }
59
68
  toJSON ()
60
69
  {
61
70
  return this.getConnections().map(connection => connection.toJSON());
@@ -69,7 +78,7 @@ class WebRtcConnectionManager
69
78
  WebRtcConnectionManager.create = function create (options)
70
79
  {
71
80
  return new WebRtcConnectionManager({
72
- Connection: function (id)
81
+ WebRtcConnection: function (id)
73
82
  {
74
83
  return new WebRtcConnection(id,options);
75
84
  },
package/index.js CHANGED
@@ -7,7 +7,7 @@ function initServer(signaling_port) {
7
7
  var cm=client_manager.getInstance();
8
8
  const webRtcConnectionManager = WebRtcConnectionManager.getInstance();
9
9
  webRtcConnectionManager.SetSendConfigMessage(signaling.sendConfigMessage);
10
- return signaling.init(webRtcConnectionManager,cm.newClient.bind(cm),signaling_port);
10
+ return signaling.init(webRtcConnectionManager,cm.newClient.bind(cm),cm.disconnectClient.bind(cm),signaling_port);
11
11
  }
12
12
 
13
13
  module.exports = {initServer}
package/package.json CHANGED
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "name": "teleportxr",
15
15
  "description": "Teleport Spatial Server on node.js",
16
- "version": "1.0.16",
16
+ "version": "1.0.18",
17
17
  "repository": {
18
18
  "type": "git",
19
19
  "url": "git+https://github.com/simul/teleport-nodejs.git"
package/signaling.js CHANGED
@@ -11,6 +11,7 @@ class SignalingState {
11
11
  static ACCEPTED = new SignalingState("Accepted");
12
12
  static STREAMING = new SignalingState("Streaming");
13
13
  static INVALID = new SignalingState("Invalid");
14
+ static STOP = new SignalingState("Stop");
14
15
 
15
16
  constructor(name) {
16
17
  this.name = name;
@@ -49,6 +50,7 @@ var signalingClients = new Map();
49
50
  var desiredIP = "";
50
51
  var webRtcConnectionManager = null;
51
52
  var newClient=null;
53
+ var disconnectClient=null;
52
54
  function startStreaming(signalingClient) {
53
55
  signalingClient.ChangeSignalingState(SignalingState.ACCEPTED);
54
56
  // And we send the WebSockets request-response.
@@ -70,7 +72,9 @@ function sendResponseToClient(clientID) {
70
72
  }
71
73
  }
72
74
  function processDisconnection(clientID,signalingClient){
73
-
75
+ signalingClient.ChangeSignalingState(SignalingState.START);
76
+ disconnectClient(signalingClient.clientID);
77
+ signalingClients.delete(clientID);
74
78
  }
75
79
  function processInitialRequest(clientID, signalingClient, content) {
76
80
  var j_clientID = 0;
@@ -217,7 +221,7 @@ function OnWebSocket(ws, req) {
217
221
  console.log("Some Error occurred");
218
222
  };
219
223
  }
220
- exports.init = function (webRtcCM, newClientFn, signaling_port) {
224
+ exports.init = function (webRtcCM, newClientFn, disconnectClientFn, signaling_port) {
221
225
  // Creating a new websocket server
222
226
  // const signaling_port = process.env.PORT || 8081;
223
227
  var wss;
@@ -231,6 +235,7 @@ exports.init = function (webRtcCM, newClientFn, signaling_port) {
231
235
  }
232
236
  webRtcConnectionManager = webRtcCM;
233
237
  newClient=newClientFn;
238
+ disconnectClient=disconnectClientFn;
234
239
  // Creating connection using websocket
235
240
  wss.on("connection", (ws, req) => {
236
241
  OnWebSocket(ws, req);