warpr 1.0.20 → 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.
Files changed (36) hide show
  1. package/fesm2022/warpr.mjs +716 -0
  2. package/fesm2022/warpr.mjs.map +1 -0
  3. package/index.d.ts +5 -0
  4. package/lib/components/stream-host/stream-host.component.d.ts +26 -0
  5. package/lib/data/frames.d.ts +20 -0
  6. package/lib/data/signaling-messages.d.ts +29 -0
  7. package/lib/data/streaming-messages.d.ts +53 -0
  8. package/lib/infrastructure/array-stream.d.ts +21 -0
  9. package/lib/infrastructure/events.d.ts +25 -0
  10. package/lib/infrastructure/message-assembler.d.ts +6 -0
  11. package/lib/networking/messaging-client.d.ts +5 -0
  12. package/lib/networking/web-socket-client.d.ts +17 -0
  13. package/lib/services/messaging.service.d.ts +12 -0
  14. package/lib/services/streaming.service.d.ts +30 -0
  15. package/package.json +26 -15
  16. package/{src/public-api.ts → public-api.d.ts} +0 -4
  17. package/ng-package.json +0 -7
  18. package/src/lib/components/stream-host/stream-host.component.html +0 -5
  19. package/src/lib/components/stream-host/stream-host.component.scss +0 -31
  20. package/src/lib/components/stream-host/stream-host.component.spec.ts +0 -23
  21. package/src/lib/components/stream-host/stream-host.component.ts +0 -170
  22. package/src/lib/data/frames.ts +0 -37
  23. package/src/lib/data/signaling-messages.ts +0 -64
  24. package/src/lib/data/streaming-messages.ts +0 -136
  25. package/src/lib/infrastructure/array-stream.ts +0 -109
  26. package/src/lib/infrastructure/events.ts +0 -61
  27. package/src/lib/infrastructure/message-assembler.ts +0 -60
  28. package/src/lib/networking/messaging-client.ts +0 -7
  29. package/src/lib/networking/web-socket-client.ts +0 -55
  30. package/src/lib/services/messaging.service.spec.ts +0 -16
  31. package/src/lib/services/messaging.service.ts +0 -32
  32. package/src/lib/services/streaming.service.spec.ts +0 -16
  33. package/src/lib/services/streaming.service.ts +0 -126
  34. package/tsconfig.lib.json +0 -14
  35. package/tsconfig.lib.prod.json +0 -10
  36. package/tsconfig.spec.json +0 -14
@@ -0,0 +1,716 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, ViewChild, Component } from '@angular/core';
3
+ import { v4 } from 'uuid';
4
+ import * as i2 from '@angular/common';
5
+ import { CommonModule } from '@angular/common';
6
+
7
+ class ArrayStream {
8
+ constructor(buffer) {
9
+ this._view = new DataView(buffer);
10
+ this._position = 0;
11
+ }
12
+ get Position() {
13
+ return this._position;
14
+ }
15
+ set Position(value) {
16
+ if (value < 0 || this._view.buffer.byteLength < value) {
17
+ throw new RangeError("The provided value lies outside the stream's bounds.");
18
+ }
19
+ this._position = value;
20
+ }
21
+ ReadBool() {
22
+ let result = this._view.getUint8(this._position) != 0;
23
+ this._position += 1;
24
+ return result;
25
+ }
26
+ ReadUInt8() {
27
+ let result = this._view.getUint8(this._position);
28
+ this._position += 1;
29
+ return result;
30
+ }
31
+ ReadUInt16() {
32
+ let result = this._view.getUint16(this._position, true);
33
+ this._position += 2;
34
+ return result;
35
+ }
36
+ ReadUInt32() {
37
+ let result = this._view.getUint32(this._position, true);
38
+ this._position += 4;
39
+ return result;
40
+ }
41
+ ReadUInt64() {
42
+ let result = this._view.getBigUint64(this._position, true);
43
+ this._position += 8;
44
+ return result;
45
+ }
46
+ ReadInt8() {
47
+ let result = this._view.getInt8(this._position);
48
+ this._position += 1;
49
+ return result;
50
+ }
51
+ ReadInt16() {
52
+ let result = this._view.getInt16(this._position, true);
53
+ this._position += 2;
54
+ return result;
55
+ }
56
+ ReadInt32() {
57
+ let result = this._view.getInt32(this._position, true);
58
+ this._position += 4;
59
+ return result;
60
+ }
61
+ ReadInt64() {
62
+ let result = this._view.getBigInt64(this._position, true);
63
+ this._position += 8;
64
+ return result;
65
+ }
66
+ ReadSingle() {
67
+ let result = this._view.getFloat32(this._position, true);
68
+ this._position += 4;
69
+ return result;
70
+ }
71
+ ReadDouble() {
72
+ let result = this._view.getFloat64(this._position, true);
73
+ this._position += 8;
74
+ return result;
75
+ }
76
+ ReadBuffer() {
77
+ let length = this.ReadUInt32();
78
+ let result = this._view.buffer.slice(this._position, this._position + length);
79
+ this._position += length;
80
+ return result;
81
+ }
82
+ ReadToEnd() {
83
+ let length = this._view.buffer.byteLength - this._position;
84
+ let result = this._view.buffer.slice(this._position, this._position + length);
85
+ this._position += length;
86
+ return result;
87
+ }
88
+ ReadString() {
89
+ let length = this.ReadUInt32();
90
+ let decoder = new TextDecoder();
91
+ let result = decoder.decode(this._view.buffer.slice(this._position, this._position + length));
92
+ this._position += length;
93
+ return result;
94
+ }
95
+ }
96
+
97
+ var FrameType;
98
+ (function (FrameType) {
99
+ FrameType[FrameType["Unknown"] = 0] = "Unknown";
100
+ FrameType[FrameType["Key"] = 1] = "Key";
101
+ FrameType[FrameType["Delta"] = 2] = "Delta";
102
+ })(FrameType || (FrameType = {}));
103
+ class EncodedFrame {
104
+ constructor(buffer) {
105
+ let stream = new ArrayStream(buffer);
106
+ this.Type = stream.ReadUInt32();
107
+ this.Index = stream.ReadUInt32();
108
+ this.Width = stream.ReadUInt32();
109
+ this.Height = stream.ReadUInt32();
110
+ this.Bytes = stream.ReadBuffer();
111
+ }
112
+ }
113
+ class Size {
114
+ constructor(Width, Height) {
115
+ this.Width = Width;
116
+ this.Height = Height;
117
+ }
118
+ static { this.Empty = { Width: 0, Height: 0 }; }
119
+ static AreEqual(a, b) {
120
+ return a.Width === b.Width && a.Height === b.Height;
121
+ }
122
+ }
123
+
124
+ var WarprSignalingMessageType;
125
+ (function (WarprSignalingMessageType) {
126
+ WarprSignalingMessageType["ConnectionRequest"] = "ConnectionRequest";
127
+ WarprSignalingMessageType["PairingCompleteMessage"] = "PairingCompleteMessage";
128
+ WarprSignalingMessageType["PeerConnectionDescriptionMessage"] = "PeerConnectionDescriptionMessage";
129
+ WarprSignalingMessageType["PeerConnectionCandidateMessage"] = "PeerConnectionCandidateMessage";
130
+ WarprSignalingMessageType["StreamingSourcesMessage"] = "StreamingSourcesMessage";
131
+ })(WarprSignalingMessageType || (WarprSignalingMessageType = {}));
132
+ class ConnectionRequest {
133
+ constructor() {
134
+ this.$type = WarprSignalingMessageType.ConnectionRequest;
135
+ }
136
+ }
137
+ class PairingCompleteMessage {
138
+ constructor() {
139
+ this.$type = WarprSignalingMessageType.PairingCompleteMessage;
140
+ }
141
+ }
142
+ function GetConfiguration(iceServers) {
143
+ let result = {};
144
+ result.iceServers = new Array();
145
+ if (iceServers) {
146
+ let regex = /^(?<protocol>stun|turn):(?:(?<username>\w+):(?<password>\w+)@)?(?<url>[\w\.:?=&]+)$/im;
147
+ for (let server of iceServers) {
148
+ let match = regex.exec(server);
149
+ if (!match || !match.groups) {
150
+ console.warn(`Failed to parse ICE server URI ${server}.`);
151
+ continue;
152
+ }
153
+ result.iceServers.push({
154
+ urls: `${match.groups['protocol']}:${match.groups['url']}`,
155
+ username: match.groups['username'],
156
+ credential: match.groups['password']
157
+ });
158
+ }
159
+ }
160
+ return result;
161
+ }
162
+ class PeerConnectionDescriptionMessage {
163
+ constructor() {
164
+ this.$type = WarprSignalingMessageType.PeerConnectionDescriptionMessage;
165
+ }
166
+ }
167
+ class PeerConnectionCandidateMessage {
168
+ constructor() {
169
+ this.$type = WarprSignalingMessageType.PeerConnectionCandidateMessage;
170
+ }
171
+ }
172
+ class StreamingSourcesMessage {
173
+ constructor() {
174
+ this.$type = WarprSignalingMessageType.StreamingSourcesMessage;
175
+ }
176
+ }
177
+
178
+ var WarprStreamingMessageType;
179
+ (function (WarprStreamingMessageType) {
180
+ WarprStreamingMessageType["PointerInputMessage"] = "PointerInputMessage";
181
+ WarprStreamingMessageType["ResizeSurfaceMessage"] = "ResizeSurfaceMessage";
182
+ })(WarprStreamingMessageType || (WarprStreamingMessageType = {}));
183
+ var PointerType;
184
+ (function (PointerType) {
185
+ PointerType["Unknown"] = "Unknown";
186
+ PointerType["Mouse"] = "Mouse";
187
+ PointerType["Pen"] = "Pen";
188
+ PointerType["Touch"] = "Touch";
189
+ })(PointerType || (PointerType = {}));
190
+ var PointerAction;
191
+ (function (PointerAction) {
192
+ PointerAction["Unknown"] = "Unknown";
193
+ PointerAction["Pressed"] = "Pressed";
194
+ PointerAction["Moved"] = "Moved";
195
+ PointerAction["Released"] = "Released";
196
+ PointerAction["WheelChanged"] = "WheelChanged";
197
+ })(PointerAction || (PointerAction = {}));
198
+ var PointerFlags;
199
+ (function (PointerFlags) {
200
+ PointerFlags[PointerFlags["None"] = 0] = "None";
201
+ PointerFlags[PointerFlags["LeftButton"] = 1] = "LeftButton";
202
+ PointerFlags[PointerFlags["MiddleButton"] = 2] = "MiddleButton";
203
+ PointerFlags[PointerFlags["RightButton"] = 4] = "RightButton";
204
+ PointerFlags[PointerFlags["Wheel"] = 8] = "Wheel";
205
+ PointerFlags[PointerFlags["Captured"] = 16] = "Captured";
206
+ })(PointerFlags || (PointerFlags = {}));
207
+ ;
208
+ class PointerState {
209
+ constructor() {
210
+ this.Buttons = 0;
211
+ }
212
+ }
213
+ class PointerInputMessage {
214
+ constructor(event, states, target, wheelDelta) {
215
+ this.$type = WarprStreamingMessageType.PointerInputMessage;
216
+ this.Id = -1;
217
+ this.Type = PointerType.Unknown;
218
+ this.Action = PointerAction.Unknown;
219
+ this.Position = { X: 0, Y: 0 };
220
+ this.Flags = PointerFlags.None;
221
+ this.WheelDelta = 0;
222
+ let state = states[event.pointerId];
223
+ if (state === undefined) {
224
+ state = new PointerState();
225
+ states[event.pointerId] = state;
226
+ }
227
+ this.Id = event.pointerId;
228
+ switch (event.pointerType) {
229
+ case "mouse":
230
+ this.Type = PointerType.Mouse;
231
+ break;
232
+ case "pen":
233
+ this.Type = PointerType.Pen;
234
+ break;
235
+ case "touch":
236
+ this.Type = PointerType.Touch;
237
+ break;
238
+ default:
239
+ this.Type = PointerType.Mouse;
240
+ break;
241
+ }
242
+ switch (event.type) {
243
+ case "pointerdown":
244
+ this.Action = PointerAction.Pressed;
245
+ state.Buttons |= 1 << event.button;
246
+ break;
247
+ case "pointerup":
248
+ this.Action = PointerAction.Released;
249
+ state.Buttons &= ~(1 << event.button);
250
+ break;
251
+ case "pointermove":
252
+ this.Action = PointerAction.Moved;
253
+ break;
254
+ case "wheel":
255
+ this.Action = PointerAction.WheelChanged;
256
+ break;
257
+ }
258
+ if (state.Buttons & 1)
259
+ this.Flags |= PointerFlags.LeftButton;
260
+ if (state.Buttons & 2)
261
+ this.Flags |= PointerFlags.MiddleButton;
262
+ if (state.Buttons & 4)
263
+ this.Flags |= PointerFlags.RightButton;
264
+ if (wheelDelta != 0)
265
+ this.Flags |= PointerFlags.Wheel;
266
+ if (target.hasPointerCapture(event.pointerId))
267
+ this.Flags |= PointerFlags.Captured;
268
+ this.Position = PointerInputMessage.GetRemotePosition(event, target);
269
+ this.WheelDelta = -wheelDelta;
270
+ }
271
+ static GetRemotePosition(event, target) {
272
+ let offsetX = 0;
273
+ let offsetY = 0;
274
+ let scale = 1;
275
+ let canvasAspectRatio = target.clientWidth / target.clientHeight;
276
+ let videoAspectRatio = target.width / target.height;
277
+ if (videoAspectRatio > canvasAspectRatio) {
278
+ offsetY = 0.5 * (target.clientHeight - target.clientWidth / videoAspectRatio);
279
+ scale = target.width / target.clientWidth;
280
+ }
281
+ else {
282
+ offsetX = 0.5 * (target.clientWidth - target.clientHeight * videoAspectRatio);
283
+ scale = target.height / target.clientHeight;
284
+ }
285
+ return {
286
+ X: (event.x - offsetX) * scale,
287
+ Y: (event.y - offsetY) * scale
288
+ };
289
+ }
290
+ }
291
+ class ResizeSurfaceMessage {
292
+ constructor(Width, Height) {
293
+ this.Width = Width;
294
+ this.Height = Height;
295
+ this.$type = WarprStreamingMessageType.ResizeSurfaceMessage;
296
+ }
297
+ }
298
+
299
+ class EventSubscription {
300
+ constructor(_owner, _token) {
301
+ this._owner = _owner;
302
+ this._token = _token;
303
+ }
304
+ Unsubscribe() {
305
+ this._owner.Unsubscribe(this._token);
306
+ }
307
+ }
308
+ class EventOwner {
309
+ constructor() {
310
+ this.Token = Symbol();
311
+ }
312
+ Raise(event, sender, eventArgs) {
313
+ event.Raise(this, sender, eventArgs);
314
+ }
315
+ }
316
+ class EventArgs {
317
+ static { this.Empty = new EventArgs(); }
318
+ }
319
+ class EventPublisher {
320
+ constructor(owner) {
321
+ this._handlers = new Map;
322
+ this._token = owner.Token;
323
+ }
324
+ Subscribe(handler) {
325
+ const token = Symbol();
326
+ this._handlers.set(token, handler);
327
+ return new EventSubscription(this, token);
328
+ }
329
+ Raise(owner, sender, eventArgs) {
330
+ if (owner.Token === this._token) {
331
+ for (let [symbol, handler] of this._handlers) {
332
+ handler(sender, eventArgs);
333
+ }
334
+ }
335
+ else {
336
+ throw Error("Cannot raise event: this event source does not belong to the specified owner.");
337
+ }
338
+ }
339
+ Unsubscribe(token) {
340
+ this._handlers.delete(token);
341
+ }
342
+ }
343
+
344
+ class MessageBuilder {
345
+ constructor(Id, Size, FragmentSize) {
346
+ this.Id = Id;
347
+ this.Size = Size;
348
+ this.FragmentSize = FragmentSize;
349
+ this.FragmentsReady = 0;
350
+ this.FragmentCount = Math.ceil(Size / FragmentSize);
351
+ this.Buffer = new Uint8Array(Size);
352
+ }
353
+ AddFragment(index, buffer) {
354
+ if (this.FragmentCount == this.FragmentsReady)
355
+ throw RangeError("All message parts have been already collected.");
356
+ this.Buffer.set(buffer, this.FragmentSize * index);
357
+ this.FragmentsReady++;
358
+ return this.FragmentCount == this.FragmentsReady;
359
+ }
360
+ }
361
+ class MessageAssembler {
362
+ constructor(_maxBuilderCount = 3) {
363
+ this._maxBuilderCount = _maxBuilderCount;
364
+ this._builders = new Map();
365
+ }
366
+ PushMessage(buffer) {
367
+ let stream = new ArrayStream(buffer);
368
+ let messageIndex = stream.ReadUInt32();
369
+ let messageSize = stream.ReadUInt32();
370
+ let fragmentSize = stream.ReadUInt32();
371
+ let fragmentIndex = stream.ReadUInt32();
372
+ let fragment = new Uint8Array(stream.ReadToEnd());
373
+ let builder = this._builders.get(messageIndex);
374
+ if (builder === undefined) {
375
+ builder = new MessageBuilder(messageIndex, messageSize, fragmentSize);
376
+ this._builders.set(messageIndex, builder);
377
+ if (this._builders.size > this._maxBuilderCount) {
378
+ let [oldest] = this._builders.keys();
379
+ this._builders.delete(oldest);
380
+ console.log("Message lost.");
381
+ }
382
+ }
383
+ if (builder.AddFragment(fragmentIndex, fragment)) {
384
+ this._builders.delete(messageIndex);
385
+ return builder.Buffer.buffer;
386
+ }
387
+ else {
388
+ return null;
389
+ }
390
+ }
391
+ }
392
+
393
+ class WebSocketClient {
394
+ constructor(_uri) {
395
+ this._uri = _uri;
396
+ this._events = new EventOwner();
397
+ this.Connected = new EventPublisher(this._events);
398
+ this.MessageReceived = new EventPublisher(this._events);
399
+ this.Disconnected = new EventPublisher(this._events);
400
+ }
401
+ Connect() {
402
+ console.log(`Connecting to ${this._uri}...`);
403
+ let socket = new WebSocket(this._uri);
404
+ socket.onopen = () => this.OnConnected();
405
+ socket.onmessage = (e) => this.OnMessageReceived(e);
406
+ socket.onclose = () => this.OnDisconnected();
407
+ socket.onerror = (e) => this.OnError(e);
408
+ this._socket = socket;
409
+ }
410
+ SendMessage(message) {
411
+ if (!this._socket)
412
+ return;
413
+ let content = JSON.stringify(message);
414
+ console.debug(`Sending message: ${content}`);
415
+ this._socket.send(content);
416
+ }
417
+ OnConnected() {
418
+ console.log(`Connected to: ${this._uri}.`);
419
+ this._events.Raise(this.Connected, this, EventArgs.Empty);
420
+ }
421
+ OnMessageReceived(eventArgs) {
422
+ console.debug('Message received: ' + eventArgs.data);
423
+ let message = JSON.parse(eventArgs.data);
424
+ this._events.Raise(this.MessageReceived, this, message);
425
+ }
426
+ OnDisconnected() {
427
+ console.log(`Disconnected from: ${this._uri}.`);
428
+ this._events.Raise(this.Disconnected, this, EventArgs.Empty);
429
+ }
430
+ OnError(error) {
431
+ console.log('Connection failed: ' + error);
432
+ }
433
+ }
434
+
435
+ class MessagingService extends WebSocketClient {
436
+ static { this._connectionUri = 'api/sinks/connect'; }
437
+ constructor() {
438
+ const uri = MessagingService.GetServerUri();
439
+ super(uri);
440
+ this._sessionId = v4();
441
+ }
442
+ static GetServerUri() {
443
+ const location = window.location;
444
+ const protocol = location.protocol === 'https:' ? 'wss' : 'ws';
445
+ return `${protocol}://${location.host}/${this._connectionUri}`;
446
+ }
447
+ OnConnected() {
448
+ super.OnConnected();
449
+ let request = new ConnectionRequest();
450
+ request.SessionId = this._sessionId;
451
+ this.SendMessage(request);
452
+ }
453
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MessagingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
454
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MessagingService, providedIn: 'root' }); }
455
+ }
456
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MessagingService, decorators: [{
457
+ type: Injectable,
458
+ args: [{
459
+ providedIn: 'root'
460
+ }]
461
+ }], ctorParameters: () => [] });
462
+
463
+ class StreamingService {
464
+ constructor(_messagingService) {
465
+ this._messagingService = _messagingService;
466
+ this._events = new EventOwner();
467
+ this.FrameReceived = new EventPublisher(this._events);
468
+ this.Connected = new EventPublisher(this._events);
469
+ this.ControlMessageReceived = new EventPublisher(this._events);
470
+ this.AuxMessageReceived = new EventPublisher(this._events);
471
+ this._lastRefreshTime = performance.now();
472
+ this._count = 0;
473
+ _messagingService.MessageReceived.Subscribe((sender, message) => this.OnSignalingMessageReceived(sender, message));
474
+ _messagingService.Connect();
475
+ }
476
+ Reconnect(configuration) {
477
+ console.log("Establishing peer connection...");
478
+ this._controlConnection?.close();
479
+ this._streamConnection?.close();
480
+ this._messageBuilder = new MessageAssembler();
481
+ this._auxConnection?.close();
482
+ this._peerConnection?.close();
483
+ this._peerConnection = new RTCPeerConnection(configuration);
484
+ this._peerConnection.onicecandidate = (event) => this.OnIceCandidateAdded(event.candidate?.candidate);
485
+ this._peerConnection.ondatachannel = (event) => this.OnDataChannel(event);
486
+ this._peerConnection.onconnectionstatechange = (event) => this.OnConnectionStateChanged();
487
+ }
488
+ SendControlMessage(message) {
489
+ let json = JSON.stringify(message);
490
+ this._controlConnection?.send(json);
491
+ }
492
+ SendAuxMessage(message) {
493
+ this._auxConnection?.send(message);
494
+ }
495
+ OnConnectionStateChanged() {
496
+ console.log("WebRTC: " + this._peerConnection?.connectionState);
497
+ }
498
+ OnDataChannel(event) {
499
+ console.log(`WebRTC data channel ${event.channel.label} connected.`);
500
+ switch (event.channel.label) {
501
+ case "control":
502
+ this._controlConnection = event.channel;
503
+ this._controlConnection.binaryType = "arraybuffer";
504
+ this._controlConnection.onmessage = (event) => this._events.Raise(this.ControlMessageReceived, this, event.data);
505
+ this._events.Raise(this.Connected, this, null);
506
+ break;
507
+ case "stream":
508
+ this._streamConnection = event.channel;
509
+ this._streamConnection.binaryType = "arraybuffer";
510
+ this._streamConnection.onmessage = (event) => this.OnLowLatencyMessage(event);
511
+ break;
512
+ case "aux":
513
+ this._auxConnection = event.channel;
514
+ this._auxConnection.binaryType = "arraybuffer";
515
+ this._auxConnection.onmessage = (event) => this._events.Raise(this.AuxMessageReceived, this, event.data);
516
+ this._events.Raise(this.Connected, this, null);
517
+ break;
518
+ }
519
+ }
520
+ OnLowLatencyMessage(event) {
521
+ let message = this._messageBuilder?.PushMessage(event.data);
522
+ if (!message)
523
+ return;
524
+ let now = performance.now();
525
+ let elapsed = now - this._lastRefreshTime;
526
+ this._count++;
527
+ if (elapsed > 1000) {
528
+ this._lastRefreshTime = now;
529
+ console.debug(`Messages: ${this._count / elapsed * 1000} FPS`);
530
+ this._count = 0;
531
+ }
532
+ let frame = new EncodedFrame(message);
533
+ this._events.Raise(this.FrameReceived, this, frame);
534
+ }
535
+ OnIceCandidateAdded(candidate) {
536
+ if (candidate == null)
537
+ return;
538
+ let message = new PeerConnectionCandidateMessage();
539
+ message.Candidate = candidate;
540
+ this._messagingService.SendMessage(message);
541
+ }
542
+ async OnSignalingMessageReceived(sender, message) {
543
+ switch (message.$type) {
544
+ case WarprSignalingMessageType.PairingCompleteMessage:
545
+ this.Reconnect(GetConfiguration(message.IceServers));
546
+ break;
547
+ case WarprSignalingMessageType.PeerConnectionDescriptionMessage:
548
+ if (!this._peerConnection)
549
+ return;
550
+ await this._peerConnection.setRemoteDescription({ type: "offer", sdp: message.Description });
551
+ let answer = await this._peerConnection.createAnswer();
552
+ await this._peerConnection.setLocalDescription(answer);
553
+ let answerMessage = new PeerConnectionDescriptionMessage();
554
+ answerMessage.Description = answer.sdp;
555
+ this._messagingService.SendMessage(answerMessage);
556
+ break;
557
+ case WarprSignalingMessageType.PeerConnectionCandidateMessage:
558
+ if (!this._peerConnection)
559
+ return;
560
+ await this._peerConnection.addIceCandidate({ candidate: message.Candidate, sdpMid: "0" });
561
+ break;
562
+ }
563
+ }
564
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: StreamingService, deps: [{ token: MessagingService }], target: i0.ɵɵFactoryTarget.Injectable }); }
565
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: StreamingService, providedIn: 'root' }); }
566
+ }
567
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: StreamingService, decorators: [{
568
+ type: Injectable,
569
+ args: [{
570
+ providedIn: 'root'
571
+ }]
572
+ }], ctorParameters: () => [{ type: MessagingService }] });
573
+
574
+ class StreamHostComponent {
575
+ get IsFullScreenAvailable() {
576
+ return document.fullscreenEnabled;
577
+ }
578
+ constructor(_streamingService) {
579
+ this._streamingService = _streamingService;
580
+ this._renderingContext = null;
581
+ this._videoSize = Size.Empty;
582
+ this._displaySize = Size.Empty;
583
+ this._isDecoderInitialized = false;
584
+ this._pointerStates = {};
585
+ this._streamingService.Connected.Subscribe((sender, eventArgs) => this.OnConnected());
586
+ this._streamingService.FrameReceived.Subscribe((sender, eventArgs) => this.OnFrameReceived(eventArgs));
587
+ this._decoder = new VideoDecoder({
588
+ output: (frame) => this.OnFrameDecoded(frame),
589
+ error: (error) => console.log(error)
590
+ });
591
+ }
592
+ async ngAfterViewInit() {
593
+ console.log("Initializing stream host...");
594
+ let canvas = this._canvas.nativeElement;
595
+ this._renderingContext = canvas.getContext("2d");
596
+ canvas.onpointerdown = (event) => this.OnPointerEvent(event);
597
+ canvas.onpointermove = (event) => this.OnPointerEvent(event);
598
+ canvas.onpointerup = (event) => this.OnPointerEvent(event);
599
+ canvas.onwheel = (event) => this.OnWheelEvent(event);
600
+ canvas.oncontextmenu = (event) => event.preventDefault();
601
+ if (this._renderingContext) {
602
+ console.log("Stream host initialized.");
603
+ }
604
+ else {
605
+ console.log("Stream host failed to initialize.");
606
+ }
607
+ requestAnimationFrame(() => this.RenderFrame());
608
+ }
609
+ OnPointerEvent(event, wheelDelta = 0) {
610
+ //console.log(event);
611
+ event.preventDefault();
612
+ if (event.type == "pointerdown")
613
+ this._canvas.nativeElement.setPointerCapture(event.pointerId);
614
+ let message = new PointerInputMessage(event, this._pointerStates, this._canvas.nativeElement, wheelDelta);
615
+ //console.log(message);
616
+ this._streamingService.SendControlMessage(message);
617
+ }
618
+ OnWheelEvent(event) {
619
+ //console.log(event);
620
+ event.preventDefault();
621
+ let pointerEvent = new PointerEvent(event.type, event);
622
+ this.OnPointerEvent(pointerEvent, event.deltaY);
623
+ }
624
+ OnConnected() {
625
+ this._displaySize = Size.Empty;
626
+ }
627
+ OnFrameReceived(frame) {
628
+ let chunk = new EncodedVideoChunk({
629
+ data: frame.Bytes,
630
+ type: frame.Type == FrameType.Key ? "key" : "delta",
631
+ timestamp: frame.Index
632
+ });
633
+ //Initialize decoder
634
+ let frameSize = new Size(frame.Width, frame.Height);
635
+ if (!Size.AreEqual(frameSize, this._videoSize)) {
636
+ console.log("Configuring decoder...");
637
+ this._decoder.configure({
638
+ codec: "hvc1.1.6.L93.B0",
639
+ codedWidth: frame.Width,
640
+ codedHeight: frame.Height,
641
+ hardwareAcceleration: "prefer-hardware",
642
+ optimizeForLatency: true
643
+ });
644
+ console.log("Decoder configured.");
645
+ console.log(`Resolution is ${frame.Width} x ${frame.Height}.`);
646
+ this._videoSize = frameSize;
647
+ }
648
+ //Decode frame
649
+ if (!this._isDecoderInitialized && chunk.type != "key")
650
+ return;
651
+ this._isDecoderInitialized = true;
652
+ this._decoder.decode(chunk);
653
+ }
654
+ OnFrameDecoded(frame) {
655
+ if (this._framePending)
656
+ this._framePending.close();
657
+ this._framePending = frame;
658
+ requestAnimationFrame(() => this.RenderFrame());
659
+ }
660
+ RenderFrame() {
661
+ let frame = this._framePending;
662
+ this._framePending = undefined;
663
+ if (frame) {
664
+ //Set canvas resolution to video resolution
665
+ let canvas = this._canvas.nativeElement;
666
+ canvas.width = frame.displayWidth;
667
+ canvas.height = frame.displayHeight;
668
+ //Check for control size change
669
+ let canvasRect = canvas.getBoundingClientRect();
670
+ let canvasSize = new Size(Math.round(canvasRect.width * window.devicePixelRatio), Math.round(canvasRect.height * window.devicePixelRatio));
671
+ if (!Size.AreEqual(canvasSize, this._displaySize)) {
672
+ this._displaySize = canvasSize;
673
+ console.log(`Resized to ${canvasSize.Width} x ${canvasSize.Height}`);
674
+ let message = new ResizeSurfaceMessage(canvasSize.Width, canvasSize.Height);
675
+ this._streamingService.SendControlMessage(message);
676
+ }
677
+ //Draw new frame
678
+ if (this._renderingContext) {
679
+ this._renderingContext.drawImage(frame, 0, 0, frame.displayWidth, frame.displayHeight);
680
+ }
681
+ //Release memory
682
+ frame.close();
683
+ }
684
+ }
685
+ ToggleFullScreen() {
686
+ if (document.fullscreenElement === this._root?.nativeElement) {
687
+ document.exitFullscreen();
688
+ }
689
+ else {
690
+ this._root?.nativeElement.requestFullscreen();
691
+ }
692
+ }
693
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: StreamHostComponent, deps: [{ token: StreamingService }], target: i0.ɵɵFactoryTarget.Component }); }
694
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.6", type: StreamHostComponent, isStandalone: true, selector: "warpr-stream-host", viewQueries: [{ propertyName: "_root", first: true, predicate: ["root"], descendants: true }, { propertyName: "_canvas", first: true, predicate: ["renderTarget"], descendants: true }], ngImport: i0, template: "<div #root class=\"root\">\n <canvas #renderTarget class=\"renderTarget\"></canvas>\n\n <div class=\"overlay\" (click)=\"ToggleFullScreen()\" *ngIf=\"IsFullScreenAvailable\" title=\"Warpr\">W</div>\n</div>\n", styles: [".root{background-color:#000;color:#fff;display:flex;position:relative}.renderTarget{width:100%;height:100%;object-fit:contain;touch-action:none}.overlay{position:absolute;bottom:10px;right:10px;background-color:#00000080;color:#ffffffbf;padding:10px;border-radius:5px;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;font-weight:700;cursor:pointer}.overlay:hover{background-color:#000000bf;color:#fff}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
695
+ }
696
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: StreamHostComponent, decorators: [{
697
+ type: Component,
698
+ args: [{ selector: 'warpr-stream-host', imports: [CommonModule], template: "<div #root class=\"root\">\n <canvas #renderTarget class=\"renderTarget\"></canvas>\n\n <div class=\"overlay\" (click)=\"ToggleFullScreen()\" *ngIf=\"IsFullScreenAvailable\" title=\"Warpr\">W</div>\n</div>\n", styles: [".root{background-color:#000;color:#fff;display:flex;position:relative}.renderTarget{width:100%;height:100%;object-fit:contain;touch-action:none}.overlay{position:absolute;bottom:10px;right:10px;background-color:#00000080;color:#ffffffbf;padding:10px;border-radius:5px;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;font-weight:700;cursor:pointer}.overlay:hover{background-color:#000000bf;color:#fff}\n"] }]
699
+ }], ctorParameters: () => [{ type: StreamingService }], propDecorators: { _root: [{
700
+ type: ViewChild,
701
+ args: ["root"]
702
+ }], _canvas: [{
703
+ type: ViewChild,
704
+ args: ["renderTarget"]
705
+ }] } });
706
+
707
+ /*
708
+ * Public API Surface of warpr-lib
709
+ */
710
+
711
+ /**
712
+ * Generated bundle index. Do not edit.
713
+ */
714
+
715
+ export { ArrayStream, ConnectionRequest, EncodedFrame, EventArgs, EventOwner, EventPublisher, EventSubscription, FrameType, GetConfiguration, MessageAssembler, MessagingService, PairingCompleteMessage, PeerConnectionCandidateMessage, PeerConnectionDescriptionMessage, PointerAction, PointerFlags, PointerInputMessage, PointerState, PointerType, ResizeSurfaceMessage, Size, StreamHostComponent, StreamingService, StreamingSourcesMessage, WarprSignalingMessageType, WarprStreamingMessageType, WebSocketClient };
716
+ //# sourceMappingURL=warpr.mjs.map