@needle-tools/engine 2.28.0-pre → 2.30.0-pre
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/CHANGELOG.md +19 -0
- package/dist/needle-engine.d.ts +232 -139
- package/dist/needle-engine.js +349 -345
- package/dist/needle-engine.js.map +4 -4
- package/dist/needle-engine.min.js +24 -20
- package/dist/needle-engine.min.js.map +4 -4
- package/lib/engine/engine.d.ts +1 -0
- package/lib/engine/engine_input.d.ts +13 -1
- package/lib/engine/engine_input.js +47 -16
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_physics.d.ts +1 -0
- package/lib/engine/engine_physics.js +2 -1
- package/lib/engine/engine_physics.js.map +1 -1
- package/lib/engine/engine_playerview.d.ts +26 -0
- package/lib/engine/engine_playerview.js +65 -0
- package/lib/engine/engine_playerview.js.map +1 -0
- package/lib/engine/engine_serialization.d.ts +1 -0
- package/lib/engine/engine_serialization.js +1 -0
- package/lib/engine/engine_serialization.js.map +1 -1
- package/lib/engine/engine_serialization_core.js +5 -0
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_setup.d.ts +8 -0
- package/lib/engine/engine_setup.js +23 -0
- package/lib/engine/engine_setup.js.map +1 -1
- package/lib/engine/engine_utils.d.ts +1 -1
- package/lib/engine/engine_utils.js +25 -8
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_deferred_texture.d.ts +1 -1
- package/lib/engine/extensions/NEEDLE_deferred_texture.js +26 -14
- package/lib/engine/extensions/NEEDLE_deferred_texture.js.map +1 -1
- package/lib/engine/extensions/NEEDLE_lighting_settings.js +6 -2
- package/lib/engine/extensions/NEEDLE_lighting_settings.js.map +1 -1
- package/lib/engine/extensions/extension_utils.js +24 -13
- package/lib/engine/extensions/extension_utils.js.map +1 -1
- package/lib/engine/extensions/extensions.js +3 -1
- package/lib/engine/extensions/extensions.js.map +1 -1
- package/lib/engine-components/Camera.js +7 -0
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/Component.d.ts +1 -1
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/Light.js +1 -0
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/OrbitControls.js +3 -3
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/ParticleSystem.d.ts +0 -1
- package/lib/engine-components/ParticleSystem.js +24 -27
- package/lib/engine-components/ParticleSystem.js.map +1 -1
- package/lib/engine-components/PlayerColor.js +1 -2
- package/lib/engine-components/PlayerColor.js.map +1 -1
- package/lib/engine-components/Renderer.d.ts +1 -0
- package/lib/engine-components/Renderer.js +10 -3
- package/lib/engine-components/Renderer.js.map +1 -1
- package/lib/engine-components/ScreenCapture.d.ts +1 -0
- package/lib/engine-components/ScreenCapture.js +265 -1
- package/lib/engine-components/ScreenCapture.js.map +1 -1
- package/lib/engine-components/SpectatorCamera.d.ts +24 -17
- package/lib/engine-components/SpectatorCamera.js +435 -182
- package/lib/engine-components/SpectatorCamera.js.map +1 -1
- package/lib/engine-components/SyncedCamera.d.ts +8 -4
- package/lib/engine-components/SyncedCamera.js +15 -18
- package/lib/engine-components/SyncedCamera.js.map +1 -1
- package/lib/engine-components/SyncedRoom.js +2 -0
- package/lib/engine-components/SyncedRoom.js.map +1 -1
- package/lib/engine-components/VideoPlayer.d.ts +10 -1
- package/lib/engine-components/VideoPlayer.js +64 -15
- package/lib/engine-components/VideoPlayer.js.map +1 -1
- package/lib/engine-components/Volume.d.ts +4 -0
- package/lib/engine-components/Volume.js +44 -3
- package/lib/engine-components/Volume.js.map +1 -1
- package/lib/engine-components/WebARSessionRoot.d.ts +9 -2
- package/lib/engine-components/WebARSessionRoot.js +69 -24
- package/lib/engine-components/WebARSessionRoot.js.map +1 -1
- package/lib/engine-components/WebXR.d.ts +6 -3
- package/lib/engine-components/WebXR.js +43 -7
- package/lib/engine-components/WebXR.js.map +1 -1
- package/lib/engine-components/WebXRAvatar.d.ts +3 -0
- package/lib/engine-components/WebXRAvatar.js +20 -0
- package/lib/engine-components/WebXRAvatar.js.map +1 -1
- package/lib/engine-components/WebXRController.js +14 -8
- package/lib/engine-components/WebXRController.js.map +1 -1
- package/lib/engine-components/WebXRSync.js +3 -3
- package/lib/engine-components/WebXRSync.js.map +1 -1
- package/lib/engine-components/XRFlag.d.ts +2 -1
- package/lib/engine-components/XRFlag.js +1 -0
- package/lib/engine-components/XRFlag.js.map +1 -1
- package/lib/engine-components/ui/CanvasGroup.d.ts +1 -0
- package/lib/engine-components/ui/CanvasGroup.js +1 -0
- package/lib/engine-components/ui/CanvasGroup.js.map +1 -1
- package/lib/engine-components/ui/EventSystem.js +13 -4
- package/lib/engine-components/ui/EventSystem.js.map +1 -1
- package/lib/engine-components/ui/Graphic.d.ts +1 -0
- package/lib/engine-components/ui/Graphic.js +2 -0
- package/lib/engine-components/ui/Graphic.js.map +1 -1
- package/lib/engine-components/ui/Interfaces.d.ts +2 -0
- package/package.json +2 -2
- package/src/engine/engine_components.js +16 -0
- package/src/engine/engine_input.ts +62 -20
- package/src/engine/engine_physics.ts +2 -1
- package/src/engine/engine_playerview.ts +80 -0
- package/src/engine/engine_serialization.ts +3 -1
- package/src/engine/engine_serialization_core.ts +8 -0
- package/src/engine/engine_setup.ts +24 -0
- package/src/engine/engine_utils.ts +34 -8
- package/src/engine/extensions/NEEDLE_deferred_texture.ts +25 -19
- package/src/engine/extensions/NEEDLE_lighting_settings.ts +4 -2
- package/src/engine/extensions/extension_utils.ts +24 -12
- package/src/engine/extensions/extensions.ts +3 -2
- package/src/engine-components/Camera.ts +9 -1
- package/src/engine-components/Component.ts +1 -1
- package/src/engine-components/Light.ts +3 -0
- package/src/engine-components/OrbitControls.ts +3 -3
- package/src/engine-components/ParticleSystem.ts +25 -26
- package/src/engine-components/PlayerColor.ts +1 -1
- package/src/engine-components/Renderer.ts +11 -3
- package/src/engine-components/ScreenCapture.ts +312 -2
- package/src/engine-components/SpectatorCamera.ts +490 -195
- package/src/engine-components/SyncedCamera.ts +23 -22
- package/src/engine-components/SyncedRoom.ts +1 -0
- package/src/engine-components/VideoPlayer.ts +97 -21
- package/src/engine-components/Volume.ts +47 -4
- package/src/engine-components/WebARSessionRoot.ts +78 -28
- package/src/engine-components/WebXR.ts +51 -15
- package/src/engine-components/WebXRAvatar.ts +27 -2
- package/src/engine-components/WebXRController.ts +21 -15
- package/src/engine-components/WebXRSync.ts +3 -3
- package/src/engine-components/XRFlag.ts +1 -0
- package/src/engine-components/ui/CanvasGroup.ts +2 -0
- package/src/engine-components/ui/EventSystem.ts +21 -15
- package/src/engine-components/ui/Graphic.ts +3 -0
- package/src/engine-components/ui/Interfaces.ts +2 -0
|
@@ -5,6 +5,7 @@ import { getParam } from "../engine/engine_utils";
|
|
|
5
5
|
import { serializeable } from "../engine/engine_serialization_decorator";
|
|
6
6
|
import { RGBAColor } from "./js-extensions/RGBAColor";
|
|
7
7
|
import { PerspectiveCamera } from "three";
|
|
8
|
+
import { XRSessionMode } from "../engine/engine_setup";
|
|
8
9
|
|
|
9
10
|
export enum ClearFlags {
|
|
10
11
|
Skybox = 1,
|
|
@@ -192,13 +193,20 @@ export class Camera extends Behaviour {
|
|
|
192
193
|
}
|
|
193
194
|
|
|
194
195
|
private environmentIsTransparent(): boolean {
|
|
195
|
-
const session = this.context.renderer.xr?.getSession()
|
|
196
|
+
const session = this.context.renderer.xr?.getSession();
|
|
196
197
|
if (!session) return false;
|
|
197
198
|
const environmentBlendMode = session.environmentBlendMode;
|
|
198
199
|
const transparent = environmentBlendMode === 'additive' || environmentBlendMode === 'alpha-blend';
|
|
200
|
+
// workaround for Quest 2 returning opaque when it should be alpha-blend
|
|
201
|
+
// check user agent if this is the Quest browser and return true if so
|
|
202
|
+
|
|
203
|
+
if (environmentBlendMode === "opaque" && navigator.userAgent?.includes("OculusBrowser")) {
|
|
204
|
+
if (this.context.xrSessionMode === XRSessionMode.ImmersiveAR) return true;
|
|
205
|
+
}
|
|
199
206
|
return transparent;
|
|
200
207
|
}
|
|
201
208
|
|
|
209
|
+
|
|
202
210
|
private enableSkybox() {
|
|
203
211
|
if (!this._skybox)
|
|
204
212
|
this._skybox = new CameraSkybox(this);
|
|
@@ -644,7 +644,7 @@ abstract class GameObject extends THREE.Object3D implements THREE.Object3D {
|
|
|
644
644
|
return object.getComponentsInChildren(typeName, go, arr);
|
|
645
645
|
}
|
|
646
646
|
|
|
647
|
-
public static getComponentInParent<T>(go: GameObject | THREE.Object3D
|
|
647
|
+
public static getComponentInParent<T>(go: GameObject | THREE.Object3D | Array<Object3D>, typeName: Constructor<T>): T | null {
|
|
648
648
|
return object.getComponentInParent(typeName, go);
|
|
649
649
|
}
|
|
650
650
|
|
|
@@ -9,7 +9,6 @@ import { serializeable } from "../engine/engine_serialization_decorator";
|
|
|
9
9
|
import { Vector3 } from "three";
|
|
10
10
|
|
|
11
11
|
export class OrbitControls extends Behaviour {
|
|
12
|
-
|
|
13
12
|
public get controls() {
|
|
14
13
|
return this._controls;
|
|
15
14
|
}
|
|
@@ -31,7 +30,7 @@ export class OrbitControls extends Behaviour {
|
|
|
31
30
|
minZoom: number = 0;
|
|
32
31
|
maxZoom: number = Infinity;
|
|
33
32
|
enablePan: boolean = true;
|
|
34
|
-
@serializeable(
|
|
33
|
+
@serializeable()
|
|
35
34
|
lookAtConstraint: LookAtConstraint | null = null;
|
|
36
35
|
lookAtConstraint01: number = 1;
|
|
37
36
|
middleClickToFocus: boolean = true;
|
|
@@ -103,7 +102,8 @@ export class OrbitControls extends Behaviour {
|
|
|
103
102
|
if (this._controls) {
|
|
104
103
|
const camGo = GameObject.getComponent(this.gameObject, Camera);
|
|
105
104
|
if (camGo && !this.setFromTargetPosition()) {
|
|
106
|
-
|
|
105
|
+
if(this.debugLog)
|
|
106
|
+
console.log("NO TARGET");
|
|
107
107
|
const forward = new THREE.Vector3(0, 0, -1).applyMatrix4(camGo.cam.matrixWorld);
|
|
108
108
|
this.setTarget(forward, true);
|
|
109
109
|
}
|
|
@@ -61,7 +61,7 @@ export class ParticleSystem extends Behaviour {
|
|
|
61
61
|
|
|
62
62
|
awake(): void {
|
|
63
63
|
this.renderer = GameObject.getComponent(this.gameObject, ParticleSystemRenderer)!;
|
|
64
|
-
if (debug)
|
|
64
|
+
// if (debug)
|
|
65
65
|
console.log(this);
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -108,31 +108,30 @@ export class ParticleSystem extends Behaviour {
|
|
|
108
108
|
this.activeCount = this.main.prewarm ? this.main.maxParticles : 0;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
update() {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
111
|
+
// update() {
|
|
112
|
+
// if (!this.geometry) return;
|
|
113
|
+
|
|
114
|
+
// const t = this.context.time.deltaTime;
|
|
115
|
+
// this.emit(t);
|
|
116
|
+
|
|
117
|
+
// for (let i = 0; i < this.activeCount; i += 1) {
|
|
118
|
+
// const ps = this.particleStates[i];
|
|
119
|
+
// if (!ps) continue;
|
|
120
|
+
// const vx = ps.velocity.x * t;
|
|
121
|
+
// const vy = ps.velocity.y * t;
|
|
122
|
+
// const vz = ps.velocity.z * t;
|
|
123
|
+
// ps.position.x += vx;
|
|
124
|
+
// ps.position.y += vy;
|
|
125
|
+
// ps.position.z += vz;
|
|
126
|
+
// this.updateOverLifetime(i, ps);
|
|
127
|
+
// this.geometry.attributes.position.setXYZ(i, ps.position.x, ps.position.y, ps.position.z);
|
|
128
|
+
// this.geometry.attributes.color.setXYZ(i, ps.color.r, ps.color.g, ps.color.b);
|
|
129
|
+
// }
|
|
130
|
+
// if (this.geometry) {
|
|
131
|
+
// this.geometry.attributes.position.needsUpdate = true;
|
|
132
|
+
// this.geometry.setDrawRange(0, this.activeCount);
|
|
133
|
+
// }
|
|
134
|
+
// }
|
|
136
135
|
|
|
137
136
|
emit(deltaTime: number) {
|
|
138
137
|
const count = this.activeCount;
|
|
@@ -13,6 +13,7 @@ const suppressInstancing = getParam("noInstancing");
|
|
|
13
13
|
const debugLightmap = getParam("debuglightmaps") ? true : false;
|
|
14
14
|
const debugInstancing = getParam("debuginstancing");
|
|
15
15
|
const debugProgressiveLoading = getParam("debugprogressiveload");
|
|
16
|
+
const suppressProgressiveLoading = getParam("noprogressiveload");
|
|
16
17
|
|
|
17
18
|
export class FieldWithDefault {
|
|
18
19
|
public path: string | null = null;
|
|
@@ -172,6 +173,8 @@ export class Renderer extends Behaviour {
|
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
awake() {
|
|
176
|
+
this.clearInstancingState();
|
|
177
|
+
|
|
175
178
|
const type = this.gameObject.type;
|
|
176
179
|
if (type === "Group") {
|
|
177
180
|
for (const child of this.gameObject.children) {
|
|
@@ -245,6 +248,11 @@ export class Renderer extends Behaviour {
|
|
|
245
248
|
private handles: InstanceHandle[] | null | undefined = undefined;
|
|
246
249
|
private prevLayers: number[] | null | undefined = undefined;
|
|
247
250
|
|
|
251
|
+
private clearInstancingState() {
|
|
252
|
+
this._isInstancingEnabled = false;
|
|
253
|
+
this.handles = undefined;
|
|
254
|
+
this.prevLayers = undefined;
|
|
255
|
+
}
|
|
248
256
|
setInstancingEnabled(enabled: boolean): boolean {
|
|
249
257
|
if (this._isInstancingEnabled === enabled) return enabled && (this.handles === undefined || this.handles != null && this.handles.length > 0);
|
|
250
258
|
this._isInstancingEnabled = enabled;
|
|
@@ -338,16 +346,16 @@ export class Renderer extends Behaviour {
|
|
|
338
346
|
onBeforeRenderThree(_renderer, _scene, _camera, _geometry, material, _group) {
|
|
339
347
|
|
|
340
348
|
// progressive load before rendering so we only load textures for visible materials
|
|
341
|
-
if (material._didRequestTextureLOD === undefined) {
|
|
349
|
+
if (!suppressProgressiveLoading && material._didRequestTextureLOD === undefined) {
|
|
342
350
|
material._didRequestTextureLOD = 0;
|
|
343
351
|
if (debugProgressiveLoading) {
|
|
344
352
|
console.log("Load material LOD (with delay)", material.name);
|
|
345
353
|
setTimeout(() => {
|
|
346
|
-
NEEDLE_deferred_texture.assignTextureLOD(this.context, material);
|
|
354
|
+
NEEDLE_deferred_texture.assignTextureLOD(this.context, this.sourceId, material);
|
|
347
355
|
}, 2000);
|
|
348
356
|
}
|
|
349
357
|
else {
|
|
350
|
-
NEEDLE_deferred_texture.assignTextureLOD(this.context, material);
|
|
358
|
+
NEEDLE_deferred_texture.assignTextureLOD(this.context, this.sourceId, material);
|
|
351
359
|
}
|
|
352
360
|
}
|
|
353
361
|
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { Behaviour, GameObject } from "./Component";
|
|
2
2
|
import { VideoPlayer } from "./VideoPlayer";
|
|
3
|
+
import Peer from "peerjs"
|
|
4
|
+
import { Context } from "../engine/engine_setup";
|
|
5
|
+
import { RoomEvents } from "../engine/engine_networking";
|
|
6
|
+
import { UserJoinedOrLeftRoomModel } from "../engine/engine_networking";
|
|
7
|
+
import { serializeable } from "../engine/engine_serialization";
|
|
8
|
+
import { IModel } from "../engine/engine_networking";
|
|
3
9
|
|
|
4
10
|
export class ScreenCapture extends Behaviour {
|
|
5
11
|
|
|
12
|
+
@serializeable()
|
|
6
13
|
streamOnAwake: boolean = true;
|
|
7
14
|
|
|
8
15
|
start() {
|
|
16
|
+
console.warn("EXPERIMENTAL screen capture", this);
|
|
9
17
|
if (this.streamOnAwake)
|
|
10
18
|
this.open();
|
|
11
19
|
}
|
|
@@ -22,7 +30,7 @@ export class ScreenCapture extends Behaviour {
|
|
|
22
30
|
if (player) {
|
|
23
31
|
const displayMediaOptions: DisplayMediaStreamConstraints = {
|
|
24
32
|
video: true,
|
|
25
|
-
audio:
|
|
33
|
+
audio: true
|
|
26
34
|
};
|
|
27
35
|
this.captureStream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);
|
|
28
36
|
if (this.captureStream && this.requestOpen) {
|
|
@@ -30,6 +38,7 @@ export class ScreenCapture extends Behaviour {
|
|
|
30
38
|
player.clip = this.captureStream;
|
|
31
39
|
player.create(true);
|
|
32
40
|
}
|
|
41
|
+
this.handleNetworkedVideo();
|
|
33
42
|
}
|
|
34
43
|
} catch (err) {
|
|
35
44
|
console.error("Error: " + err);
|
|
@@ -44,4 +53,305 @@ export class ScreenCapture extends Behaviour {
|
|
|
44
53
|
this.captureStream = null;
|
|
45
54
|
}
|
|
46
55
|
}
|
|
47
|
-
|
|
56
|
+
|
|
57
|
+
private handleNetworkedVideo() {
|
|
58
|
+
if (!this.context.connection.isConnected) {
|
|
59
|
+
console.warn("Will not stream video - not connected to room");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (this.captureStream) {
|
|
63
|
+
const handle = PeerHandle.getOrCreate(this.context, this.guid);
|
|
64
|
+
handle.enable();
|
|
65
|
+
// if (!this.peer)
|
|
66
|
+
// this.peer = new Peer();
|
|
67
|
+
const net = new NetworkedVideo(this.context, handle);
|
|
68
|
+
net.enable();
|
|
69
|
+
net.startSendingVideo(this.captureStream);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
enum PeerHandleEvent {
|
|
77
|
+
Connected = "peer-user-connected",
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
class PeerUserConnectedModel implements IModel {
|
|
81
|
+
/** the peer handle id */
|
|
82
|
+
readonly guid: string;
|
|
83
|
+
readonly peerId: string;
|
|
84
|
+
// internal so server doesnt save it to persistent storage
|
|
85
|
+
readonly dontSave: boolean = true;
|
|
86
|
+
constructor(handle: PeerHandle, peerId: string) {
|
|
87
|
+
this.guid = handle.id;
|
|
88
|
+
this.peerId = peerId;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
enum CallDirection {
|
|
93
|
+
Incoming = "incoming",
|
|
94
|
+
Outgoing = "outgoing",
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
class CallHandle {
|
|
98
|
+
readonly direction: CallDirection;
|
|
99
|
+
readonly call: Peer.MediaConnection;
|
|
100
|
+
stream: MediaStream | null;
|
|
101
|
+
|
|
102
|
+
constructor(call: Peer.MediaConnection, direction: CallDirection) {
|
|
103
|
+
this.call = call;
|
|
104
|
+
this.direction = direction;
|
|
105
|
+
this.stream = null;
|
|
106
|
+
call.on("stream", stream => {
|
|
107
|
+
this.stream = stream;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
class PeerHandle {
|
|
113
|
+
|
|
114
|
+
private static readonly instances: Map<string, PeerHandle> = new Map();
|
|
115
|
+
|
|
116
|
+
static getOrCreate(context: Context, guid: string): PeerHandle {
|
|
117
|
+
// if (id === undefined) {
|
|
118
|
+
// // randomId
|
|
119
|
+
// id = Math.random().toFixed(5);
|
|
120
|
+
// }
|
|
121
|
+
if (PeerHandle.instances.has(guid))
|
|
122
|
+
return PeerHandle.instances.get(guid)!;
|
|
123
|
+
const peer = new PeerHandle(context, guid);
|
|
124
|
+
PeerHandle.instances.set(guid, peer);
|
|
125
|
+
return peer;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
getPeerIdFromUserId(userConnectionId: string): string {
|
|
129
|
+
// we build the peer id ourselves so we dont need to wait for peer to report it
|
|
130
|
+
return this.id + "-" + userConnectionId;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
getUserIdFromPeerId(peerId: string): string {
|
|
134
|
+
return peerId.substring(this.id.length + 1);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
makeCall(peerId: string, stream: MediaStream): CallHandle | undefined {
|
|
138
|
+
// if (userId === this.context.connection.connectionId) {
|
|
139
|
+
// console.warn("Can not call self");
|
|
140
|
+
// return;
|
|
141
|
+
// }
|
|
142
|
+
// const peerId = this.getUserPeerId(userId);
|
|
143
|
+
console.log("CALL", peerId);
|
|
144
|
+
const call = this._peer?.call(peerId, stream);
|
|
145
|
+
if (call)
|
|
146
|
+
return this.registerCall(call, CallDirection.Outgoing);
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
get peer(): Peer | undefined { return this._peer; }
|
|
151
|
+
|
|
152
|
+
readonly id: string;
|
|
153
|
+
readonly context: Context;
|
|
154
|
+
private _peer: Peer | undefined;
|
|
155
|
+
private _incomingCalls: CallHandle[] = [];
|
|
156
|
+
private _outgoingCalls: CallHandle[] = [];
|
|
157
|
+
|
|
158
|
+
private constructor(context: Context, id: string) {
|
|
159
|
+
this.context = context;
|
|
160
|
+
this.id = id;
|
|
161
|
+
this.setupPeer();
|
|
162
|
+
navigator["getUserMedia"] = (
|
|
163
|
+
navigator["getUserMedia"] || navigator["webkitGetUserMedia"] ||
|
|
164
|
+
navigator["mozGetUserMedia"] || navigator["msGetUserMedia"]
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private _enabled: boolean = false;
|
|
169
|
+
private _enabledPeer: boolean = false;
|
|
170
|
+
private onConnectRoomFn: Function = this.onConnectRoom.bind(this);
|
|
171
|
+
private onUserJoinedOrLeftRoomFn: Function = this.onUserJoinedOrLeftRoom.bind(this);
|
|
172
|
+
private onPeerConnectFn: (id) => void = this.onPeerConnect.bind(this);
|
|
173
|
+
private onPeerReceiveCallFn: (call) => void = this.onPeerReceivingCall.bind(this);
|
|
174
|
+
// private _connectionPeerIdMap : Map<string, string> = new Map();
|
|
175
|
+
|
|
176
|
+
enable() {
|
|
177
|
+
if (this._enabled) return;
|
|
178
|
+
this._enabled = true;
|
|
179
|
+
this.context.connection.beginListen(RoomEvents.JoinedRoom, this.onConnectRoomFn);
|
|
180
|
+
this.context.connection.beginListen(RoomEvents.UserJoinedRoom, this.onUserJoinedOrLeftRoomFn);
|
|
181
|
+
this.context.connection.beginListen(RoomEvents.UserLeftRoom, this.onUserJoinedOrLeftRoomFn);
|
|
182
|
+
this.subscribePeerEvents();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
disable() {
|
|
186
|
+
if (!this._enabled) return;
|
|
187
|
+
this._enabled = false;
|
|
188
|
+
this.context.connection.stopListening(RoomEvents.JoinedRoom, this.onConnectRoomFn);
|
|
189
|
+
this.context.connection.stopListening(RoomEvents.UserJoinedRoom, this.onUserJoinedOrLeftRoomFn);
|
|
190
|
+
this.context.connection.stopListening(RoomEvents.UserLeftRoom, this.onUserJoinedOrLeftRoomFn);
|
|
191
|
+
this.unsubscribePeerEvents();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private onConnectRoom(): void {
|
|
195
|
+
this.setupPeer();
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
private onUserJoinedOrLeftRoom(_: UserJoinedOrLeftRoomModel): void {
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
private setupPeer() {
|
|
202
|
+
if (!this.context.connection.connectionId) return;
|
|
203
|
+
if (this._enabledPeer) return;
|
|
204
|
+
this._enabledPeer = true;
|
|
205
|
+
if (!this._peer) {
|
|
206
|
+
const peerId = this.getPeerIdFromUserId(this.context.connection.connectionId);
|
|
207
|
+
this._peer = new Peer(peerId);
|
|
208
|
+
}
|
|
209
|
+
if (this._enabled)
|
|
210
|
+
this.subscribePeerEvents();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private subscribePeerEvents() {
|
|
214
|
+
if (!this._peer) return;
|
|
215
|
+
this._peer.on("open", this.onPeerConnectFn);
|
|
216
|
+
this._peer.on("call", this.onPeerReceiveCallFn);
|
|
217
|
+
// this.context.connection.beginListen(PeerEvent.Connected, this.onRemotePeerConnect.bind(this));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private unsubscribePeerEvents() {
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private onPeerConnect(id): void {
|
|
224
|
+
console.log("connect", id);
|
|
225
|
+
this.context.connection.send(PeerHandleEvent.Connected, new PeerUserConnectedModel(this, id));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private onPeerReceivingCall(call: Peer.MediaConnection): void {
|
|
229
|
+
console.log("RECEIVE CALL");
|
|
230
|
+
call.answer();
|
|
231
|
+
this.registerCall(call, CallDirection.Incoming);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private registerCall(call: Peer.MediaConnection, direction: CallDirection): CallHandle {
|
|
235
|
+
const arr = direction === CallDirection.Incoming ? this._incomingCalls : this._outgoingCalls;
|
|
236
|
+
const handle = new CallHandle(call, direction);
|
|
237
|
+
arr.push(handle);
|
|
238
|
+
call.on("error", err => {
|
|
239
|
+
console.error(err);
|
|
240
|
+
});
|
|
241
|
+
call.on("close", () => {
|
|
242
|
+
const index = arr.indexOf(handle);
|
|
243
|
+
if (index !== -1)
|
|
244
|
+
arr.splice(index, 1);
|
|
245
|
+
});
|
|
246
|
+
return handle;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// private onRemotePeerConnect(user: PeerUserConnectedModel) {
|
|
250
|
+
// console.log("other user connected", user);
|
|
251
|
+
// }
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
type UserVideoCall = {
|
|
256
|
+
call: Peer.MediaConnection;
|
|
257
|
+
stream: MediaStream;
|
|
258
|
+
userId: string;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
class NetworkedVideo {
|
|
262
|
+
|
|
263
|
+
private readonly context: Context;
|
|
264
|
+
private readonly peer: PeerHandle;
|
|
265
|
+
|
|
266
|
+
private _sendingVideoStreams: Map<MediaStream, UserVideoCall[]> = new Map();
|
|
267
|
+
|
|
268
|
+
constructor(context: Context, peer: PeerHandle) {
|
|
269
|
+
this.context = context;
|
|
270
|
+
this.peer = peer;
|
|
271
|
+
|
|
272
|
+
// this.peer.on("open", (id) => {
|
|
273
|
+
// console.log("PEERID", id);
|
|
274
|
+
// });
|
|
275
|
+
// // this.peer.on("call", (call) => {
|
|
276
|
+
// // });
|
|
277
|
+
// // this.peer.on("connection", (conn) => {
|
|
278
|
+
// // });
|
|
279
|
+
// // this.peer.on("error", (err) => {
|
|
280
|
+
// // });
|
|
281
|
+
// // this.peer.on("disconnected", () => {
|
|
282
|
+
// // });
|
|
283
|
+
// // this.peer.on("close", () => {
|
|
284
|
+
// // });
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
startSendingVideo(stream: MediaStream) {
|
|
288
|
+
if (!this._sendingVideoStreams.has(stream)) {
|
|
289
|
+
this._sendingVideoStreams.set(stream, []);
|
|
290
|
+
this.updateSendingCalls();
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
stopSendingVideo(_steam: MediaStream) {
|
|
295
|
+
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
private onConnectRoomFn: Function = this.onConnectRoom.bind(this);
|
|
299
|
+
private onUserConnectedFn: Function = this.onUserConnected.bind(this);
|
|
300
|
+
private onUserLeftFn: Function = this.onUserLeft.bind(this);
|
|
301
|
+
|
|
302
|
+
enable() {
|
|
303
|
+
this.context.connection.beginListen(PeerHandleEvent.Connected, this.onUserConnectedFn);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
disable() {
|
|
307
|
+
// this.context.connection.stopListening(RoomEvents.UserJoinedRoom, this.onUserConnectedFn);
|
|
308
|
+
// this.context.connection.stopListening(RoomEvents.UserLeftRoom, this.onUserLeftFn);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
private onConnectRoom() {
|
|
312
|
+
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
private onUserConnected(user: PeerUserConnectedModel) {
|
|
316
|
+
// console.log(this.peer.id, user.guid)
|
|
317
|
+
if (this.peer.id === user.guid) {
|
|
318
|
+
console.log("USER CONNECTED", user);
|
|
319
|
+
const userId = this.peer.getUserIdFromPeerId(user.peerId);
|
|
320
|
+
console.log(userId);
|
|
321
|
+
// this.updateSendingCalls();
|
|
322
|
+
const call = this.peer.makeCall(user.peerId, this._sendingVideoStreams.keys().next().value);
|
|
323
|
+
|
|
324
|
+
// for (const userId of this.context.connection.usersInRoom()) {
|
|
325
|
+
// const id = this.peer.getPeerIdFromUserId(userId);
|
|
326
|
+
// if(id === user.peerId) console.log(userId);
|
|
327
|
+
// }
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
private onUserLeft(_: UserJoinedOrLeftRoomModel) {
|
|
332
|
+
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
private updateSendingCalls() {
|
|
336
|
+
// for (const str of this._sendingVideoStreams.keys()) {
|
|
337
|
+
// const calls = this._sendingVideoStreams.get(str) || [];
|
|
338
|
+
// for (const userId of this.context.connection.usersInRoom()) {
|
|
339
|
+
// const existing = calls.find(c => c.userId === userId);
|
|
340
|
+
// if (!existing) {
|
|
341
|
+
// const call = this.peer.makeCall(userId, str);
|
|
342
|
+
// console.log(call);
|
|
343
|
+
// if (call) {
|
|
344
|
+
// calls.push({
|
|
345
|
+
// call: call,
|
|
346
|
+
// stream: str,
|
|
347
|
+
// userId: userId
|
|
348
|
+
// });
|
|
349
|
+
// }
|
|
350
|
+
// }
|
|
351
|
+
// }
|
|
352
|
+
// this._sendingVideoStreams.set(str, calls);
|
|
353
|
+
// }
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// const call = peer.call(peerId, stream);
|
|
357
|
+
}
|