@stormstreaming/stormstreamer 0.9.2-beta.2 → 0.9.3-beta.0
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/README.md +130 -3
- package/dist/amd/index.js +2206 -105
- package/dist/cjs/index.js +3 -3
- package/dist/esm/index.js +3 -3
- package/dist/iife/index.js +4 -4
- package/dist/types/StormStreamer.d.ts +394 -3
- package/dist/types/config/AudioData.d.ts +46 -0
- package/dist/types/config/ConfigManager.d.ts +47 -0
- package/dist/types/config/DebugData.d.ts +108 -0
- package/dist/types/config/IConfig.d.ts +3 -0
- package/dist/types/config/SettingsData.d.ts +114 -0
- package/dist/types/config/StorageData.d.ts +46 -0
- package/dist/types/config/StreamData.d.ts +75 -0
- package/dist/types/config/VideoData.d.ts +115 -0
- package/dist/types/config/enum/LogType.d.ts +3 -0
- package/dist/types/config/enum/ProtocolType.d.ts +3 -0
- package/dist/types/config/enum/ScalingType.d.ts +3 -0
- package/dist/types/config/enum/SecurityType.d.ts +3 -0
- package/dist/types/config/enum/SizeCalculationType.d.ts +3 -0
- package/dist/types/events/EventDispatcher.d.ts +34 -0
- package/dist/types/graph/MicrophoneGraph.d.ts +11 -0
- package/dist/types/logger/Logger.d.ts +103 -0
- package/dist/types/model/AbstractSourceItem.d.ts +23 -0
- package/dist/types/model/GatewayServerItem.d.ts +53 -0
- package/dist/types/model/IServerItem.d.ts +3 -0
- package/dist/types/model/ISourceItem.d.ts +3 -0
- package/dist/types/model/IStreamItem.d.ts +3 -0
- package/dist/types/model/RTMPSourceItem.d.ts +50 -0
- package/dist/types/model/RTSPSourceItem.d.ts +50 -0
- package/dist/types/model/StormMetaDataItem.d.ts +3 -0
- package/dist/types/model/StormServerItem.d.ts +53 -0
- package/dist/types/model/StormSourceItem.d.ts +27 -0
- package/dist/types/model/StreamInfo.d.ts +46 -0
- package/dist/types/network/AbstractSocket.d.ts +94 -0
- package/dist/types/network/NetworkController.d.ts +33 -0
- package/dist/types/network/WowzaConnection.d.ts +63 -0
- package/dist/types/network/WowzaStatusConnection.d.ts +54 -0
- package/dist/types/playback/CooldownMonitor.d.ts +17 -0
- package/dist/types/playback/StreamerController.d.ts +267 -1
- package/dist/types/playback/enum/ConnectionState.d.ts +3 -0
- package/dist/types/playback/player/AbstractPlayer.d.ts +23 -0
- package/dist/types/playback/task/IPlaybackTask.d.ts +3 -0
- package/dist/types/stage/ScreenElement.d.ts +54 -0
- package/dist/types/stage/StageController.d.ts +86 -0
- package/dist/types/statistics/StatsController.d.ts +8 -0
- package/dist/types/storage/StorageManager.d.ts +37 -0
- package/dist/types/utilities/DomUtilities.d.ts +7 -0
- package/dist/types/utilities/NumberUtilities.d.ts +7 -0
- package/dist/types/utilities/UserCapabilities.d.ts +44 -0
- package/dist/umd/index.js +4 -4
- package/package.json +1 -1
package/dist/amd/index.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* contact@stormstreaming.com
|
|
5
5
|
* https://stormstreaming.com
|
|
6
6
|
*
|
|
7
|
-
* Version: 0.9.
|
|
8
|
-
* Version: 3/
|
|
7
|
+
* Version: 0.9.3-beta.0
|
|
8
|
+
* Version: 3/8/2025, 11:51:36 PM
|
|
9
9
|
*
|
|
10
10
|
* LEGAL NOTICE:
|
|
11
11
|
* This software is subject to the terms and conditions defined in
|
|
@@ -45,7 +45,18 @@
|
|
|
45
45
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Class stores information related to storm servers
|
|
50
|
+
*/
|
|
48
51
|
class StormServerItem {
|
|
52
|
+
/**
|
|
53
|
+
* Constructor
|
|
54
|
+
*
|
|
55
|
+
* @param host server URL e.g. "cdn-e001.stormstreaming.com"
|
|
56
|
+
* @param applicationName e.g. "live
|
|
57
|
+
* @param port usually 443
|
|
58
|
+
* @param isSSL whenever connection should be stablished via SSL (true by default)
|
|
59
|
+
*/
|
|
49
60
|
constructor(host, application, port = 443, isSSL = true) {
|
|
50
61
|
this.host = host;
|
|
51
62
|
this.application = application;
|
|
@@ -53,24 +64,46 @@
|
|
|
53
64
|
this.isSSL = isSSL;
|
|
54
65
|
this.hasFaild = false;
|
|
55
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Returns server URL
|
|
69
|
+
*/
|
|
56
70
|
getHost() {
|
|
57
71
|
return this.host;
|
|
58
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Returns server application
|
|
75
|
+
*/
|
|
59
76
|
getApplication() {
|
|
60
77
|
return this.application;
|
|
61
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Returns port number
|
|
81
|
+
*/
|
|
62
82
|
getPort() {
|
|
63
83
|
return this.port;
|
|
64
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Returns whenever connection should be established via SSL
|
|
87
|
+
*/
|
|
65
88
|
getIfSSL() {
|
|
66
89
|
return this.isSSL;
|
|
67
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Returns whenever connection faild while trying to connect
|
|
93
|
+
*/
|
|
68
94
|
getIfFaild() {
|
|
69
95
|
return this.hasFaild;
|
|
70
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Marks this server as faild, prevent it from being used anymore
|
|
99
|
+
* @param value
|
|
100
|
+
*/
|
|
71
101
|
setAsFaild(value) {
|
|
72
102
|
this.hasFaild = value;
|
|
73
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Returns data from this object
|
|
106
|
+
*/
|
|
74
107
|
getData() {
|
|
75
108
|
return {
|
|
76
109
|
serverURL: this.getHost(),
|
|
@@ -84,13 +117,29 @@
|
|
|
84
117
|
}
|
|
85
118
|
}
|
|
86
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Class contains streaming data
|
|
122
|
+
*/
|
|
87
123
|
class StreamData {
|
|
124
|
+
//------------------------------------------------------------------------//
|
|
125
|
+
// CONSTRUCTOR
|
|
126
|
+
//------------------------------------------------------------------------//
|
|
127
|
+
/**
|
|
128
|
+
* Constructor
|
|
129
|
+
* @param streamConfig
|
|
130
|
+
*/
|
|
88
131
|
constructor(streamConfig) {
|
|
89
132
|
this._serverList = new Array();
|
|
90
133
|
this._sourceList = new Array();
|
|
91
134
|
this._streamKey = null;
|
|
92
135
|
this.parse(streamConfig);
|
|
93
136
|
}
|
|
137
|
+
//------------------------------------------------------------------------//
|
|
138
|
+
// MAIN METHODS
|
|
139
|
+
//------------------------------------------------------------------------//
|
|
140
|
+
/**
|
|
141
|
+
* Parses provided config
|
|
142
|
+
*/
|
|
94
143
|
parse(streamConfig) {
|
|
95
144
|
var _a, _b, _c;
|
|
96
145
|
this._streamConfig = streamConfig;
|
|
@@ -110,30 +159,68 @@
|
|
|
110
159
|
} else throw new Error("StormLibrary: Server list configuration is missing. Please check the config!");
|
|
111
160
|
this._streamKey = (_c = this._streamConfig.streamKey) !== null && _c !== void 0 ? _c : this._streamKey;
|
|
112
161
|
}
|
|
162
|
+
//------------------------------------------------------------------------//
|
|
163
|
+
// GETS & SETS
|
|
164
|
+
//------------------------------------------------------------------------//
|
|
165
|
+
/**
|
|
166
|
+
* Returns list of all provided servers
|
|
167
|
+
*/
|
|
113
168
|
getServerList() {
|
|
114
169
|
return this._serverList;
|
|
115
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Returns list of all video sources
|
|
173
|
+
*/
|
|
116
174
|
getSourceList() {
|
|
117
175
|
return this._sourceList;
|
|
118
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Returns group name;
|
|
179
|
+
*/
|
|
119
180
|
get streamKey() {
|
|
120
181
|
return this._streamKey;
|
|
121
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Returns group name;
|
|
185
|
+
*/
|
|
122
186
|
set streamKey(newValue) {
|
|
123
187
|
this._streamKey = newValue;
|
|
124
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Allows to push server list to the config
|
|
191
|
+
* @param serverList
|
|
192
|
+
*/
|
|
125
193
|
set serverList(serverList) {
|
|
126
194
|
this._serverList = serverList;
|
|
127
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Allows to push source list to the config
|
|
198
|
+
* @param sourceList
|
|
199
|
+
*/
|
|
128
200
|
set sourceList(sourceList) {
|
|
129
201
|
this._sourceList = sourceList;
|
|
130
202
|
}
|
|
203
|
+
//------------------------------------------------------------------------//
|
|
204
|
+
// OTHER
|
|
205
|
+
//------------------------------------------------------------------------//
|
|
206
|
+
/**
|
|
207
|
+
* Removes all sources
|
|
208
|
+
*/
|
|
131
209
|
clearSourceList() {
|
|
132
210
|
this._sourceList = new Array();
|
|
133
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Removes all SERVERS
|
|
214
|
+
*/
|
|
134
215
|
clearServerList() {
|
|
135
216
|
this._serverList = new Array();
|
|
136
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Prints current settings.
|
|
220
|
+
*
|
|
221
|
+
* @param logger reference to logger
|
|
222
|
+
* @param force if printing is disabled, this parameter can overwrite it
|
|
223
|
+
*/
|
|
137
224
|
print(logger, force = false) {
|
|
138
225
|
if (StreamData.PRINT_ON_STARTUP || force) {
|
|
139
226
|
logger.info(this, "Server List:");
|
|
@@ -144,10 +231,26 @@
|
|
|
144
231
|
}
|
|
145
232
|
}
|
|
146
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Decides whenever player will print this config data on startup
|
|
236
|
+
*
|
|
237
|
+
* @private
|
|
238
|
+
*/
|
|
147
239
|
StreamData.PRINT_ON_STARTUP = true;
|
|
240
|
+
/**
|
|
241
|
+
* Default storm port (usually 443)
|
|
242
|
+
* @private
|
|
243
|
+
*/
|
|
148
244
|
StreamData.DEFAULT_CONNECTION_PORT = 443;
|
|
245
|
+
/**
|
|
246
|
+
* Whenever all connection to strom should be made via SSL
|
|
247
|
+
* @private
|
|
248
|
+
*/
|
|
149
249
|
StreamData.IS_SSL_BY_DEFAULT = true;
|
|
150
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Different types of video scaling mechanisms
|
|
253
|
+
*/
|
|
151
254
|
var ScalingType;
|
|
152
255
|
(function (ScalingType) {
|
|
153
256
|
ScalingType["FILL"] = "fill";
|
|
@@ -156,6 +259,9 @@
|
|
|
156
259
|
ScalingType["ORIGINAL"] = "original";
|
|
157
260
|
})(ScalingType || (ScalingType = {}));
|
|
158
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Different types of security methods for player
|
|
264
|
+
*/
|
|
159
265
|
var SizeCalculationType;
|
|
160
266
|
(function (SizeCalculationType) {
|
|
161
267
|
SizeCalculationType["CLIENT_DIMENSIONS"] = "clientDimensions";
|
|
@@ -163,20 +269,77 @@
|
|
|
163
269
|
SizeCalculationType["FULL_BOX"] = "fullBox";
|
|
164
270
|
})(SizeCalculationType || (SizeCalculationType = {}));
|
|
165
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Class contains settings for video object
|
|
274
|
+
*/
|
|
166
275
|
class VideoData {
|
|
276
|
+
//------------------------------------------------------------------------//
|
|
277
|
+
// CONSTRUCTOR
|
|
278
|
+
//------------------------------------------------------------------------//
|
|
279
|
+
/**
|
|
280
|
+
* Constructor
|
|
281
|
+
*
|
|
282
|
+
* @param videoConfig video config object
|
|
283
|
+
*/
|
|
167
284
|
constructor(videoConfig) {
|
|
285
|
+
/**
|
|
286
|
+
* Selected scaling mode
|
|
287
|
+
* @private
|
|
288
|
+
*/
|
|
168
289
|
this._scalingMode = ScalingType.LETTER_BOX;
|
|
290
|
+
/**
|
|
291
|
+
* Aspect ratio saved as a string (two numbers with : in between)
|
|
292
|
+
* @private
|
|
293
|
+
*/
|
|
169
294
|
this._aspectRatio = "none";
|
|
295
|
+
/**
|
|
296
|
+
* Initial video container width
|
|
297
|
+
* @private
|
|
298
|
+
*/
|
|
170
299
|
this._videoWidthValue = 100;
|
|
300
|
+
/**
|
|
301
|
+
* Whenever width is in pixels
|
|
302
|
+
* @private
|
|
303
|
+
*/
|
|
171
304
|
this._isVideoWidthInPixels = false;
|
|
305
|
+
/**
|
|
306
|
+
* Whenever width was provided
|
|
307
|
+
* @private
|
|
308
|
+
*/
|
|
172
309
|
this._wasVideoWidthProvided = false;
|
|
310
|
+
/**
|
|
311
|
+
* Initial video container height;
|
|
312
|
+
* @private
|
|
313
|
+
*/
|
|
173
314
|
this._videoHeightValue = 100;
|
|
315
|
+
/**
|
|
316
|
+
* Whenever height is in pixels
|
|
317
|
+
* @private
|
|
318
|
+
*/
|
|
174
319
|
this._isVideoHeightInPixels = false;
|
|
320
|
+
/**
|
|
321
|
+
* Whenever height was provided
|
|
322
|
+
* @private
|
|
323
|
+
*/
|
|
175
324
|
this._wasVideoHeightProvided = false;
|
|
325
|
+
/**
|
|
326
|
+
* Resize debounce parameter
|
|
327
|
+
* @private
|
|
328
|
+
*/
|
|
176
329
|
this._resizeDebounce = 250;
|
|
330
|
+
/**
|
|
331
|
+
* Method used for calculating parent size;
|
|
332
|
+
* @private
|
|
333
|
+
*/
|
|
177
334
|
this._parentSizeCalculationMethod = SizeCalculationType.CLIENT_DIMENSIONS;
|
|
178
335
|
this.parse(videoConfig);
|
|
179
336
|
}
|
|
337
|
+
//------------------------------------------------------------------------//
|
|
338
|
+
// MAIN METHODS
|
|
339
|
+
//------------------------------------------------------------------------//
|
|
340
|
+
/**
|
|
341
|
+
* Parses provided config
|
|
342
|
+
*/
|
|
180
343
|
parse(config) {
|
|
181
344
|
var _a, _b;
|
|
182
345
|
this.videoConfig = config;
|
|
@@ -262,30 +425,60 @@
|
|
|
262
425
|
this._resizeDebounce = (_b = this.videoConfig.resizeDebounce) !== null && _b !== void 0 ? _b : this._resizeDebounce;
|
|
263
426
|
} else throw new Error("Missing video configuration. Please check player config!");
|
|
264
427
|
}
|
|
428
|
+
//------------------------------------------------------------------------//
|
|
429
|
+
// GETS & SETS
|
|
430
|
+
//------------------------------------------------------------------------//
|
|
431
|
+
/**
|
|
432
|
+
* Returns selected scaling mode
|
|
433
|
+
*/
|
|
265
434
|
get scalingMode() {
|
|
266
435
|
return this._scalingMode;
|
|
267
436
|
}
|
|
437
|
+
/**
|
|
438
|
+
* Returns ID of the main video container
|
|
439
|
+
*/
|
|
268
440
|
get containerID() {
|
|
269
441
|
return this._containerID;
|
|
270
442
|
}
|
|
443
|
+
/**
|
|
444
|
+
* Returns video screen initial width
|
|
445
|
+
*/
|
|
271
446
|
get videoWidthValue() {
|
|
272
447
|
return this._videoWidthValue;
|
|
273
448
|
}
|
|
449
|
+
/**
|
|
450
|
+
* Returns whenever screen width was provided in pixels
|
|
451
|
+
*/
|
|
274
452
|
get videoWidthInPixels() {
|
|
275
453
|
return this._isVideoWidthInPixels;
|
|
276
454
|
}
|
|
455
|
+
/**
|
|
456
|
+
* Returns whenever screen width was provided in pixels
|
|
457
|
+
*/
|
|
277
458
|
get videoWidthProvided() {
|
|
278
459
|
return this._wasVideoWidthProvided;
|
|
279
460
|
}
|
|
461
|
+
/**
|
|
462
|
+
* Returns video container initial width
|
|
463
|
+
*/
|
|
280
464
|
get videoHeightValue() {
|
|
281
465
|
return this._videoHeightValue;
|
|
282
466
|
}
|
|
467
|
+
/**
|
|
468
|
+
* Returns video container initial width
|
|
469
|
+
*/
|
|
283
470
|
get videoHeightInPixels() {
|
|
284
471
|
return this._isVideoHeightInPixels;
|
|
285
472
|
}
|
|
473
|
+
/**
|
|
474
|
+
* Returns whenever screen width was provided in pixels
|
|
475
|
+
*/
|
|
286
476
|
get videoHeightProvided() {
|
|
287
477
|
return this._wasVideoHeightProvided;
|
|
288
478
|
}
|
|
479
|
+
/**
|
|
480
|
+
* Returns aspect ratio;
|
|
481
|
+
*/
|
|
289
482
|
get aspectRatio() {
|
|
290
483
|
return this._aspectRatio;
|
|
291
484
|
}
|
|
@@ -295,21 +488,45 @@
|
|
|
295
488
|
set resizeDebounce(newValue) {
|
|
296
489
|
this._resizeDebounce = newValue;
|
|
297
490
|
}
|
|
491
|
+
/**
|
|
492
|
+
* Sets new width to the player config
|
|
493
|
+
* @param newWidth
|
|
494
|
+
*/
|
|
298
495
|
set videoWidthValue(newWidth) {
|
|
299
496
|
this._videoWidthValue = newWidth;
|
|
300
497
|
}
|
|
498
|
+
/**
|
|
499
|
+
* Sets new width to the player config
|
|
500
|
+
* @param newWidth
|
|
501
|
+
*/
|
|
301
502
|
set videoWidthInPixels(value) {
|
|
302
503
|
this._isVideoWidthInPixels = value;
|
|
303
504
|
}
|
|
505
|
+
/**
|
|
506
|
+
* Sets new height to the player config
|
|
507
|
+
* @param newHeight
|
|
508
|
+
*/
|
|
304
509
|
set videoHeightValue(newHeight) {
|
|
305
510
|
this._videoHeightValue = newHeight;
|
|
306
511
|
}
|
|
512
|
+
/**
|
|
513
|
+
* Sets new width to the player config
|
|
514
|
+
* @param newWidth
|
|
515
|
+
*/
|
|
307
516
|
set videoHeightInPixels(value) {
|
|
308
517
|
this._isVideoHeightInPixels = value;
|
|
309
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* Sets new containerID for the player
|
|
521
|
+
* @param newContainerID
|
|
522
|
+
*/
|
|
310
523
|
set containerID(newContainerID) {
|
|
311
524
|
this._containerID = newContainerID;
|
|
312
525
|
}
|
|
526
|
+
/**
|
|
527
|
+
* Sets new scaling mode
|
|
528
|
+
* @param newScalingMode
|
|
529
|
+
*/
|
|
313
530
|
set scalingMode(newScalingMode) {
|
|
314
531
|
switch (newScalingMode.toLowerCase()) {
|
|
315
532
|
case "fill":
|
|
@@ -331,6 +548,14 @@
|
|
|
331
548
|
get parentSizeCalculationMethod() {
|
|
332
549
|
return this._parentSizeCalculationMethod;
|
|
333
550
|
}
|
|
551
|
+
//------------------------------------------------------------------------//
|
|
552
|
+
// OTHER
|
|
553
|
+
//------------------------------------------------------------------------//
|
|
554
|
+
/**
|
|
555
|
+
* Prints current settings
|
|
556
|
+
*
|
|
557
|
+
* @param logger
|
|
558
|
+
*/
|
|
334
559
|
print(logger) {
|
|
335
560
|
let scalingMode = "";
|
|
336
561
|
switch (this._scalingMode) {
|
|
@@ -355,6 +580,9 @@
|
|
|
355
580
|
}
|
|
356
581
|
}
|
|
357
582
|
|
|
583
|
+
/**
|
|
584
|
+
* Contains all log types
|
|
585
|
+
*/
|
|
358
586
|
var LogType;
|
|
359
587
|
(function (LogType) {
|
|
360
588
|
LogType[LogType["TRACE"] = 0] = "TRACE";
|
|
@@ -364,18 +592,61 @@
|
|
|
364
592
|
LogType[LogType["ERROR"] = 4] = "ERROR";
|
|
365
593
|
})(LogType || (LogType = {}));
|
|
366
594
|
|
|
595
|
+
/**
|
|
596
|
+
* This class represents "debug" section of an original player config. If any field/value is missing in the config,
|
|
597
|
+
* default values defined within this class will be used instead.
|
|
598
|
+
*/
|
|
367
599
|
class DebugData {
|
|
600
|
+
//------------------------------------------------------------------------//
|
|
601
|
+
// CONSTRUCTOR
|
|
602
|
+
//------------------------------------------------------------------------//
|
|
603
|
+
/**
|
|
604
|
+
* Creates debug object based on parameters from config object
|
|
605
|
+
*
|
|
606
|
+
* @param debugConfig
|
|
607
|
+
*/
|
|
368
608
|
constructor(debugConfig) {
|
|
609
|
+
/**
|
|
610
|
+
* Decides whenever log will be outputted in browser console
|
|
611
|
+
* @private
|
|
612
|
+
*/
|
|
369
613
|
this._consoleLogEnabled = false;
|
|
614
|
+
/**
|
|
615
|
+
* List of enabled console log types (order doesn't matter)
|
|
616
|
+
* @private
|
|
617
|
+
*/
|
|
370
618
|
this._enabledConsoleTypes = [LogType.INFO, LogType.ERROR, LogType.SUCCESS, LogType.TRACE, LogType.WARNING];
|
|
619
|
+
/**
|
|
620
|
+
* If true, different types of logs for console will have the same color, but each player will have
|
|
621
|
+
* its own color (easier to debug with multiple players)
|
|
622
|
+
*
|
|
623
|
+
* @private
|
|
624
|
+
*/
|
|
371
625
|
this._consoleMonoColor = false;
|
|
626
|
+
/**
|
|
627
|
+
* List of enabled console log types (order doesn't matter)
|
|
628
|
+
* @private
|
|
629
|
+
*/
|
|
372
630
|
this._containerLogEnabled = false;
|
|
631
|
+
/**
|
|
632
|
+
*
|
|
633
|
+
* @private
|
|
634
|
+
*/
|
|
373
635
|
this._enabledContainerTypes = [LogType.INFO, LogType.ERROR, LogType.SUCCESS, LogType.TRACE, LogType.WARNING];
|
|
636
|
+
/**
|
|
637
|
+
* If true, different types of logs for container will have the same color, but each player will have
|
|
638
|
+
* its own color (easier to debug with multiple players)
|
|
639
|
+
*
|
|
640
|
+
* @private
|
|
641
|
+
*/
|
|
374
642
|
this._containerLogMonoColor = false;
|
|
375
643
|
this._stageController = true;
|
|
376
644
|
this._streamerController = true;
|
|
377
645
|
this.parse(debugConfig);
|
|
378
646
|
}
|
|
647
|
+
/**
|
|
648
|
+
* Parses provided config
|
|
649
|
+
*/
|
|
379
650
|
parse(debugConfig) {
|
|
380
651
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
|
|
381
652
|
this._debugConfig = debugConfig;
|
|
@@ -409,15 +680,32 @@
|
|
|
409
680
|
}
|
|
410
681
|
});
|
|
411
682
|
}
|
|
683
|
+
//------------------------------------------------------------------------//
|
|
684
|
+
// GETS & SETS
|
|
685
|
+
//------------------------------------------------------------------------//
|
|
686
|
+
/**
|
|
687
|
+
* Returns whenever logs from debug will be pushed to browser console. False by default.
|
|
688
|
+
*/
|
|
412
689
|
get consoleLogEnabled() {
|
|
413
690
|
return this._consoleLogEnabled;
|
|
414
691
|
}
|
|
692
|
+
/**
|
|
693
|
+
* Sets console logging on/off
|
|
694
|
+
* @param newValue
|
|
695
|
+
*/
|
|
415
696
|
set consoleLogEnabled(newValue) {
|
|
416
697
|
this._consoleLogEnabled = newValue;
|
|
417
698
|
}
|
|
699
|
+
/**
|
|
700
|
+
* Returns all enabled types of logs for console logging
|
|
701
|
+
*/
|
|
418
702
|
get enabledConsoleTypes() {
|
|
419
703
|
return this._enabledConsoleTypes;
|
|
420
704
|
}
|
|
705
|
+
/**
|
|
706
|
+
* Sets console log types
|
|
707
|
+
* @param newValue
|
|
708
|
+
*/
|
|
421
709
|
set enabledConsoleTypes(newValue) {
|
|
422
710
|
this._enabledConsoleTypes = new Array();
|
|
423
711
|
for (let i = 0; i < newValue.length; i++) {
|
|
@@ -440,21 +728,42 @@
|
|
|
440
728
|
}
|
|
441
729
|
}
|
|
442
730
|
}
|
|
731
|
+
/**
|
|
732
|
+
* Returns whenever logs from debug will be pushed to a cointainer. False by default.
|
|
733
|
+
*/
|
|
443
734
|
get containerLogEnabled() {
|
|
444
735
|
return this._containerLogEnabled;
|
|
445
736
|
}
|
|
737
|
+
/**
|
|
738
|
+
* Sets container debugging on/off
|
|
739
|
+
* @param newValue
|
|
740
|
+
*/
|
|
446
741
|
set containerLogEnabled(newValue) {
|
|
447
742
|
this._consoleLogEnabled = newValue;
|
|
448
743
|
}
|
|
744
|
+
/**
|
|
745
|
+
* Retruns true if all console outputs will have the same color (depending on playerID)
|
|
746
|
+
*/
|
|
449
747
|
get consoleLogMonoColor() {
|
|
450
748
|
return this._consoleMonoColor;
|
|
451
749
|
}
|
|
750
|
+
/**
|
|
751
|
+
* Sets console logging to monocolor
|
|
752
|
+
* @param newValue
|
|
753
|
+
*/
|
|
452
754
|
set consoleLogMonoColor(newValue) {
|
|
453
755
|
this._consoleMonoColor = newValue;
|
|
454
756
|
}
|
|
757
|
+
/**
|
|
758
|
+
* Returns all enabled types of logs for container logging
|
|
759
|
+
*/
|
|
455
760
|
get enabledContainerTypes() {
|
|
456
761
|
return this._enabledContainerTypes;
|
|
457
762
|
}
|
|
763
|
+
/**
|
|
764
|
+
* Sets console log types
|
|
765
|
+
* @param newValue
|
|
766
|
+
*/
|
|
458
767
|
set enabledContainerTypes(newValue) {
|
|
459
768
|
this._enabledContainerTypes = new Array();
|
|
460
769
|
for (let i = 0; i < newValue.length; i++) {
|
|
@@ -477,15 +786,29 @@
|
|
|
477
786
|
}
|
|
478
787
|
}
|
|
479
788
|
}
|
|
789
|
+
/**
|
|
790
|
+
* Return a reference to a object where logs will be pushed as text. Null by default.
|
|
791
|
+
*/
|
|
480
792
|
get containerID() {
|
|
481
793
|
return this._containerID;
|
|
482
794
|
}
|
|
795
|
+
/**
|
|
796
|
+
* Sets container for logging
|
|
797
|
+
* @param object
|
|
798
|
+
*/
|
|
483
799
|
set containerID(object) {
|
|
484
800
|
this._containerID = object;
|
|
485
801
|
}
|
|
802
|
+
/**
|
|
803
|
+
* Retruns true if all container outputs will have the same color (depending on playerID)
|
|
804
|
+
*/
|
|
486
805
|
get containerLogMonoColor() {
|
|
487
806
|
return this._containerLogMonoColor;
|
|
488
807
|
}
|
|
808
|
+
/**
|
|
809
|
+
* Sets container logging to monocolor
|
|
810
|
+
* @param newValue
|
|
811
|
+
*/
|
|
489
812
|
set containerLogMonoColor(newValue) {
|
|
490
813
|
this._containerLogMonoColor = newValue;
|
|
491
814
|
}
|
|
@@ -495,6 +818,14 @@
|
|
|
495
818
|
get streamerControllerDebug() {
|
|
496
819
|
return this._streamerController;
|
|
497
820
|
}
|
|
821
|
+
//------------------------------------------------------------------------//
|
|
822
|
+
// OTHER
|
|
823
|
+
//------------------------------------------------------------------------//
|
|
824
|
+
/**
|
|
825
|
+
* Prints current settings
|
|
826
|
+
*
|
|
827
|
+
* @param logger
|
|
828
|
+
*/
|
|
498
829
|
print(logger, force = false) {
|
|
499
830
|
if (DebugData.PRINT_ON_STARTUP || force) {
|
|
500
831
|
let consoleLogTypes = "";
|
|
@@ -547,14 +878,43 @@
|
|
|
547
878
|
}
|
|
548
879
|
}
|
|
549
880
|
}
|
|
881
|
+
/**
|
|
882
|
+
* Decides whenever player will print this config data on startup
|
|
883
|
+
*
|
|
884
|
+
* @private
|
|
885
|
+
*/
|
|
550
886
|
DebugData.PRINT_ON_STARTUP = true;
|
|
551
887
|
|
|
888
|
+
/**
|
|
889
|
+
* Class contains all parameters related to volume
|
|
890
|
+
*/
|
|
552
891
|
class AudioData {
|
|
892
|
+
//------------------------------------------------------------------------//
|
|
893
|
+
// CONSTRUCTOR
|
|
894
|
+
//------------------------------------------------------------------------//
|
|
895
|
+
/**
|
|
896
|
+
* Constructor
|
|
897
|
+
* @param volumeConfig
|
|
898
|
+
*/
|
|
553
899
|
constructor(volumeConfig) {
|
|
900
|
+
/**
|
|
901
|
+
* Default value for volume
|
|
902
|
+
* @private
|
|
903
|
+
*/
|
|
554
904
|
this._startVolume = 100;
|
|
905
|
+
/**
|
|
906
|
+
* Whenever video is muted
|
|
907
|
+
* @private
|
|
908
|
+
*/
|
|
555
909
|
this._isMuted = false;
|
|
556
910
|
this.parse(volumeConfig);
|
|
557
911
|
}
|
|
912
|
+
//------------------------------------------------------------------------//
|
|
913
|
+
// MAIN METHODS
|
|
914
|
+
//------------------------------------------------------------------------//
|
|
915
|
+
/**
|
|
916
|
+
* Parses provided config
|
|
917
|
+
*/
|
|
558
918
|
parse(config) {
|
|
559
919
|
var _a, _b, _c, _d;
|
|
560
920
|
this._audioConfig = config;
|
|
@@ -563,67 +923,203 @@
|
|
|
563
923
|
this._isMuted = (_d = (_c = this._audioConfig) === null || _c === void 0 ? void 0 : _c.muted) !== null && _d !== void 0 ? _d : this._isMuted;
|
|
564
924
|
}
|
|
565
925
|
}
|
|
926
|
+
//------------------------------------------------------------------------//
|
|
927
|
+
// GETS & SETS
|
|
928
|
+
//------------------------------------------------------------------------//
|
|
929
|
+
/**
|
|
930
|
+
* Returns player start volume
|
|
931
|
+
*/
|
|
566
932
|
get startVolume() {
|
|
567
933
|
return this._startVolume;
|
|
568
934
|
}
|
|
935
|
+
/**
|
|
936
|
+
* Sets start volume for the player (by default it's 100)
|
|
937
|
+
* @param newValue
|
|
938
|
+
*/
|
|
569
939
|
set startVolume(newValue) {
|
|
570
940
|
this._startVolume = newValue;
|
|
571
941
|
}
|
|
942
|
+
/**
|
|
943
|
+
* Returns whenever library should be muted on start
|
|
944
|
+
*/
|
|
572
945
|
get muted() {
|
|
573
946
|
return this._isMuted;
|
|
574
947
|
}
|
|
948
|
+
/**
|
|
949
|
+
* Sets whenever library should be muted or not
|
|
950
|
+
* @param newValue
|
|
951
|
+
*/
|
|
575
952
|
set muted(newValue) {
|
|
576
953
|
this._isMuted = newValue;
|
|
577
954
|
}
|
|
955
|
+
//------------------------------------------------------------------------//
|
|
956
|
+
// OTHER
|
|
957
|
+
//------------------------------------------------------------------------//
|
|
958
|
+
/**
|
|
959
|
+
* Prints current settings
|
|
960
|
+
*
|
|
961
|
+
* @param logger
|
|
962
|
+
*/
|
|
578
963
|
print(logger, force = false) {
|
|
579
964
|
if (AudioData.PRINT_ON_STARTUP || force) logger.info(this, "Audio :: startVolume: " + this._startVolume + " | isMuted: " + this._isMuted);
|
|
580
965
|
}
|
|
581
966
|
}
|
|
967
|
+
/**
|
|
968
|
+
* Decides whenever player will print this config data on startup
|
|
969
|
+
*
|
|
970
|
+
* @private
|
|
971
|
+
*/
|
|
582
972
|
AudioData.PRINT_ON_STARTUP = true;
|
|
583
973
|
|
|
974
|
+
/**
|
|
975
|
+
* Class contains all parameters related to volume
|
|
976
|
+
*/
|
|
584
977
|
class StorageData {
|
|
978
|
+
//------------------------------------------------------------------------//
|
|
979
|
+
// CONSTRUCTOR
|
|
980
|
+
//------------------------------------------------------------------------//
|
|
981
|
+
/**
|
|
982
|
+
* Constructor
|
|
983
|
+
* @param storageConfig
|
|
984
|
+
*/
|
|
585
985
|
constructor(storageConfig) {
|
|
986
|
+
/**
|
|
987
|
+
* Whenever storage is enabled or not (true by default)
|
|
988
|
+
* @private
|
|
989
|
+
*/
|
|
586
990
|
this._enabled = true;
|
|
991
|
+
/**
|
|
992
|
+
* Prefix for loading and saving settings
|
|
993
|
+
* @private
|
|
994
|
+
*/
|
|
587
995
|
this._prefix = "storm";
|
|
588
996
|
this.parse(storageConfig);
|
|
589
997
|
}
|
|
998
|
+
//------------------------------------------------------------------------//
|
|
999
|
+
// MAIN METHODS
|
|
1000
|
+
//------------------------------------------------------------------------//
|
|
1001
|
+
/**
|
|
1002
|
+
* Parses provided config
|
|
1003
|
+
*/
|
|
590
1004
|
parse(config) {
|
|
591
1005
|
var _a, _b, _c, _d;
|
|
592
1006
|
this._storageConfig = config;
|
|
593
1007
|
this._enabled = (_b = (_a = this._storageConfig) === null || _a === void 0 ? void 0 : _a.enabled) !== null && _b !== void 0 ? _b : this._enabled;
|
|
594
1008
|
this._prefix = (_d = (_c = this._storageConfig) === null || _c === void 0 ? void 0 : _c.prefix) !== null && _d !== void 0 ? _d : this._prefix;
|
|
595
1009
|
}
|
|
1010
|
+
//------------------------------------------------------------------------//
|
|
1011
|
+
// GETS & SETS
|
|
1012
|
+
//------------------------------------------------------------------------//
|
|
1013
|
+
/**
|
|
1014
|
+
* Returns if storage is enabled
|
|
1015
|
+
*/
|
|
596
1016
|
get enabled() {
|
|
597
1017
|
return this._enabled;
|
|
598
1018
|
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Sets new value for enabled
|
|
1021
|
+
* @param newValue
|
|
1022
|
+
*/
|
|
599
1023
|
set enabled(newValue) {
|
|
600
1024
|
this._enabled = newValue;
|
|
601
1025
|
}
|
|
1026
|
+
/**
|
|
1027
|
+
* Returns storage prefix
|
|
1028
|
+
*/
|
|
602
1029
|
get prefix() {
|
|
603
1030
|
return this._prefix;
|
|
604
1031
|
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Sets storage prefix
|
|
1034
|
+
* @param newValue
|
|
1035
|
+
*/
|
|
605
1036
|
set prefix(newValue) {
|
|
606
1037
|
this._prefix = newValue;
|
|
607
1038
|
}
|
|
1039
|
+
//------------------------------------------------------------------------//
|
|
1040
|
+
// OTHER
|
|
1041
|
+
//------------------------------------------------------------------------//
|
|
1042
|
+
/**
|
|
1043
|
+
* Prints current settings
|
|
1044
|
+
*
|
|
1045
|
+
* @param logger
|
|
1046
|
+
*/
|
|
608
1047
|
print(logger, force = false) {
|
|
609
1048
|
if (StorageData.PRINT_ON_STARTUP || force) logger.info(this, "Storage :: startVolume: " + this._enabled + " | prefix: " + this._prefix);
|
|
610
1049
|
}
|
|
611
1050
|
}
|
|
1051
|
+
/**
|
|
1052
|
+
* Decides whenever player will print this config data on startup
|
|
1053
|
+
*
|
|
1054
|
+
* @private
|
|
1055
|
+
*/
|
|
612
1056
|
StorageData.PRINT_ON_STARTUP = true;
|
|
613
1057
|
|
|
1058
|
+
/**
|
|
1059
|
+
* Store all settings related to player behavior
|
|
1060
|
+
*/
|
|
614
1061
|
class SettingsData {
|
|
1062
|
+
//------------------------------------------------------------------------//
|
|
1063
|
+
// CONSTRUCTOR
|
|
1064
|
+
//------------------------------------------------------------------------//
|
|
1065
|
+
/**
|
|
1066
|
+
* Constructor
|
|
1067
|
+
* @param config
|
|
1068
|
+
*/
|
|
615
1069
|
constructor(config) {
|
|
1070
|
+
/**
|
|
1071
|
+
* Whenver player should try reconnecting upon its error
|
|
1072
|
+
* @private
|
|
1073
|
+
*/
|
|
616
1074
|
this._restartOnError = true;
|
|
1075
|
+
/**
|
|
1076
|
+
* Number of seconds between player reconnects
|
|
1077
|
+
* @private
|
|
1078
|
+
*/
|
|
617
1079
|
this._reconnectTime = 1;
|
|
1080
|
+
/**
|
|
1081
|
+
* Decides whenver player will automatically start playing content
|
|
1082
|
+
* @private
|
|
1083
|
+
*/
|
|
618
1084
|
this._autoStart = false;
|
|
1085
|
+
/**
|
|
1086
|
+
* Decides whenver player will automatically connect to a server
|
|
1087
|
+
* @private
|
|
1088
|
+
*/
|
|
619
1089
|
this._autoConnect = true;
|
|
1090
|
+
/**
|
|
1091
|
+
* Start player only when DOM is ready
|
|
1092
|
+
*
|
|
1093
|
+
* @private
|
|
1094
|
+
*/
|
|
620
1095
|
this.startOnDOMReady = false;
|
|
1096
|
+
/**
|
|
1097
|
+
* Starts video playback on iOS only once DOM is ready
|
|
1098
|
+
*
|
|
1099
|
+
* @private
|
|
1100
|
+
*
|
|
1101
|
+
*/
|
|
621
1102
|
this.iOSOnDomReadyFix = true;
|
|
1103
|
+
/**
|
|
1104
|
+
* Decides whenever player will restart on focus/blur
|
|
1105
|
+
* @private
|
|
1106
|
+
*/
|
|
622
1107
|
this._restartOnFocus = true;
|
|
1108
|
+
/**
|
|
1109
|
+
* Whenever streamer should preselect some camera and microphone if no was selected prior
|
|
1110
|
+
* @private
|
|
1111
|
+
*/
|
|
623
1112
|
this._preselectDevices = true;
|
|
624
1113
|
this._cancelPublishOnError = true;
|
|
625
1114
|
this.parse(config);
|
|
626
1115
|
}
|
|
1116
|
+
//------------------------------------------------------------------------//
|
|
1117
|
+
// MAIN METHODS
|
|
1118
|
+
//------------------------------------------------------------------------//
|
|
1119
|
+
/**
|
|
1120
|
+
* Parses provided config
|
|
1121
|
+
* @param config
|
|
1122
|
+
*/
|
|
627
1123
|
parse(config) {
|
|
628
1124
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
629
1125
|
this._settingsConfig = config;
|
|
@@ -639,33 +1135,67 @@
|
|
|
639
1135
|
this._storageData = new StorageData((_k = this._settingsConfig.storage) !== null && _k !== void 0 ? _k : null);
|
|
640
1136
|
this._debugData = new DebugData((_l = this._settingsConfig.debug) !== null && _l !== void 0 ? _l : null);
|
|
641
1137
|
}
|
|
1138
|
+
//------------------------------------------------------------------------//
|
|
1139
|
+
// GETS & SETS
|
|
1140
|
+
//------------------------------------------------------------------------//
|
|
1141
|
+
/**
|
|
1142
|
+
* Returns Volume Config
|
|
1143
|
+
*/
|
|
642
1144
|
getAudioData() {
|
|
643
1145
|
return this._audioData;
|
|
644
1146
|
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Returns Video Config
|
|
1149
|
+
*/
|
|
645
1150
|
getVideoData() {
|
|
646
1151
|
return this._videoData;
|
|
647
1152
|
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Returns Storage Data
|
|
1155
|
+
*/
|
|
648
1156
|
getStorageData() {
|
|
649
1157
|
return this._storageData;
|
|
650
1158
|
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Returns if player should reset connection after error
|
|
1161
|
+
*/
|
|
651
1162
|
getIfRestartOnError() {
|
|
652
1163
|
return this._restartOnError;
|
|
653
1164
|
}
|
|
1165
|
+
/**
|
|
1166
|
+
* Returns time (in ms) when player should attempt new connection after error
|
|
1167
|
+
*/
|
|
654
1168
|
getReconnectTime() {
|
|
655
1169
|
return this._reconnectTime;
|
|
656
1170
|
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Returns true whenever autostart is activated
|
|
1173
|
+
*/
|
|
657
1174
|
get autoStart() {
|
|
658
1175
|
return this._autoStart;
|
|
659
1176
|
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Sets autostart value
|
|
1179
|
+
* @param newValue
|
|
1180
|
+
*/
|
|
660
1181
|
set autoStart(newValue) {
|
|
661
1182
|
this._autoStart = newValue;
|
|
662
1183
|
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Returns true/false whenever library is set to auto-connect with a Storm server
|
|
1186
|
+
*/
|
|
663
1187
|
get autoConnect() {
|
|
664
1188
|
return this._autoConnect;
|
|
665
1189
|
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Returns true whenever library should restart the connection on document focus/blur
|
|
1192
|
+
*/
|
|
666
1193
|
get restartOnFocus() {
|
|
667
1194
|
return this._restartOnFocus;
|
|
668
1195
|
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Returns Debug Config
|
|
1198
|
+
*/
|
|
669
1199
|
getDebugData() {
|
|
670
1200
|
return this._debugData;
|
|
671
1201
|
}
|
|
@@ -675,12 +1205,26 @@
|
|
|
675
1205
|
getIfCancelPublishOnError() {
|
|
676
1206
|
return this._cancelPublishOnError;
|
|
677
1207
|
}
|
|
1208
|
+
/**
|
|
1209
|
+
* Returns whenever player should start only after DOM has been initialized
|
|
1210
|
+
*/
|
|
678
1211
|
getIfStartOnDOMReadyEnabled() {
|
|
679
1212
|
return this.startOnDOMReady;
|
|
680
1213
|
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Returns whenever player (ios mode) should start only after DOM has been initialized
|
|
1216
|
+
*/
|
|
681
1217
|
getIfIOSOnDomStartFixEnabled() {
|
|
682
1218
|
return this.iOSOnDomReadyFix;
|
|
683
1219
|
}
|
|
1220
|
+
//------------------------------------------------------------------------//
|
|
1221
|
+
// OTHER
|
|
1222
|
+
//------------------------------------------------------------------------//
|
|
1223
|
+
/**
|
|
1224
|
+
* Prints current settings
|
|
1225
|
+
*
|
|
1226
|
+
* @param logger
|
|
1227
|
+
*/
|
|
684
1228
|
print(logger, force = false) {
|
|
685
1229
|
if (SettingsData.PRINT_ON_STARTUP || force) {
|
|
686
1230
|
let enabledProtocols = "";
|
|
@@ -696,14 +1240,45 @@
|
|
|
696
1240
|
}
|
|
697
1241
|
}
|
|
698
1242
|
}
|
|
1243
|
+
/**
|
|
1244
|
+
* Decides whenever player will print this config data on startup
|
|
1245
|
+
*
|
|
1246
|
+
* @private
|
|
1247
|
+
*/
|
|
699
1248
|
SettingsData.PRINT_ON_STARTUP = true;
|
|
700
1249
|
|
|
1250
|
+
/**
|
|
1251
|
+
* Class responsible for parsing config object.
|
|
1252
|
+
*/
|
|
701
1253
|
class ConfigManager {
|
|
1254
|
+
//------------------------------------------------------------------------//
|
|
1255
|
+
// CONSTRUCTOR
|
|
1256
|
+
//------------------------------------------------------------------------//
|
|
1257
|
+
/**
|
|
1258
|
+
* Constuctor
|
|
1259
|
+
* @param config config object
|
|
1260
|
+
*/
|
|
702
1261
|
constructor(config) {
|
|
1262
|
+
/**
|
|
1263
|
+
* Decides whenever player will print this config data on startup
|
|
1264
|
+
*
|
|
1265
|
+
* @private
|
|
1266
|
+
*/
|
|
703
1267
|
this.PRINT_ON_STARTUP = true;
|
|
1268
|
+
/**
|
|
1269
|
+
* Whenver we're in demo mode
|
|
1270
|
+
* @private
|
|
1271
|
+
*/
|
|
704
1272
|
this.demoMode = false;
|
|
705
1273
|
this.parse(config);
|
|
706
1274
|
}
|
|
1275
|
+
//------------------------------------------------------------------------//
|
|
1276
|
+
// MAIN METHODS
|
|
1277
|
+
//------------------------------------------------------------------------//
|
|
1278
|
+
/**
|
|
1279
|
+
* Parses config objects into smaller chunkes related to their kind.
|
|
1280
|
+
* @private
|
|
1281
|
+
*/
|
|
707
1282
|
parse(config) {
|
|
708
1283
|
var _a, _b;
|
|
709
1284
|
this.configTemplate = config;
|
|
@@ -712,15 +1287,36 @@
|
|
|
712
1287
|
this.settingsData = new SettingsData((_a = this.configTemplate.settings) !== null && _a !== void 0 ? _a : null);
|
|
713
1288
|
this.demoMode = (_b = this.configTemplate.demoMode) !== null && _b !== void 0 ? _b : false;
|
|
714
1289
|
}
|
|
1290
|
+
//------------------------------------------------------------------------//
|
|
1291
|
+
// GETS & SETS
|
|
1292
|
+
//------------------------------------------------------------------------//
|
|
1293
|
+
/**
|
|
1294
|
+
* Returns the part of the config with player stream data (what to play)
|
|
1295
|
+
*/
|
|
715
1296
|
getStreamData() {
|
|
716
1297
|
return this.streamData;
|
|
717
1298
|
}
|
|
1299
|
+
/**
|
|
1300
|
+
* Returns the part of the config with player settings
|
|
1301
|
+
*/
|
|
718
1302
|
getSettingsData() {
|
|
719
1303
|
return this.settingsData;
|
|
720
1304
|
}
|
|
1305
|
+
/**
|
|
1306
|
+
* Returns true/false whenever we're in demo mode or not
|
|
1307
|
+
*/
|
|
721
1308
|
getIfDemoMode() {
|
|
722
1309
|
return this.demoMode;
|
|
723
1310
|
}
|
|
1311
|
+
//------------------------------------------------------------------------//
|
|
1312
|
+
// OTHER
|
|
1313
|
+
//------------------------------------------------------------------------//
|
|
1314
|
+
/**
|
|
1315
|
+
* Prints current settings.
|
|
1316
|
+
*
|
|
1317
|
+
* @param logger reference to logger
|
|
1318
|
+
* @param force if printing is disabled, this parameter can overwrite it
|
|
1319
|
+
*/
|
|
724
1320
|
print(logger, force = false) {
|
|
725
1321
|
if (this.PRINT_ON_STARTUP || force) {
|
|
726
1322
|
this.streamData.print(logger);
|
|
@@ -729,11 +1325,29 @@
|
|
|
729
1325
|
}
|
|
730
1326
|
}
|
|
731
1327
|
|
|
1328
|
+
/**
|
|
1329
|
+
* General class for event-listeners
|
|
1330
|
+
*/
|
|
732
1331
|
class EventDispatcher {
|
|
733
1332
|
constructor() {
|
|
1333
|
+
/**
|
|
1334
|
+
* Whenever instance of this class has been removed
|
|
1335
|
+
* @protected
|
|
1336
|
+
*/
|
|
734
1337
|
this._isRemoved = false;
|
|
1338
|
+
/**
|
|
1339
|
+
* An array storing all the listeners
|
|
1340
|
+
* @private
|
|
1341
|
+
*/
|
|
735
1342
|
this._listeners = {};
|
|
736
|
-
|
|
1343
|
+
// nothing
|
|
1344
|
+
}
|
|
1345
|
+
/**
|
|
1346
|
+
* Method registers event listener with the object
|
|
1347
|
+
* @param eventName name of an event (as a string)
|
|
1348
|
+
* @param listener a reference to a method
|
|
1349
|
+
* @param removable whenever this listener can be removed or not
|
|
1350
|
+
*/
|
|
737
1351
|
addEventListener(eventName, listener, removable = true) {
|
|
738
1352
|
if (!this._listeners[eventName]) this._listeners[eventName] = [];
|
|
739
1353
|
let elementFound = false;
|
|
@@ -754,6 +1368,11 @@
|
|
|
754
1368
|
return true;
|
|
755
1369
|
} else return false;
|
|
756
1370
|
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Method removes a listener from this object based on event name and used method
|
|
1373
|
+
* @param eventName name of an event (as a string)
|
|
1374
|
+
* @param listenera reference to a method (optional)
|
|
1375
|
+
*/
|
|
757
1376
|
removeEventListener(eventName, listener) {
|
|
758
1377
|
let elementFound = false;
|
|
759
1378
|
if (this._listeners[eventName] != undefined) {
|
|
@@ -780,6 +1399,9 @@
|
|
|
780
1399
|
this._logger.success(this, "Removing listener: " + eventName);
|
|
781
1400
|
return elementFound;
|
|
782
1401
|
}
|
|
1402
|
+
/**
|
|
1403
|
+
* Method removes all event listeners
|
|
1404
|
+
*/
|
|
783
1405
|
removeAllEventListeners() {
|
|
784
1406
|
this._logger.success(this, "Removing all listeners!");
|
|
785
1407
|
for (const eventName in this._listeners) {
|
|
@@ -795,6 +1417,11 @@
|
|
|
795
1417
|
}
|
|
796
1418
|
}
|
|
797
1419
|
}
|
|
1420
|
+
/**
|
|
1421
|
+
* Method dispatches an event of a given eventName
|
|
1422
|
+
* @param eventName
|
|
1423
|
+
* @param event
|
|
1424
|
+
*/
|
|
798
1425
|
dispatchEvent(eventName, event) {
|
|
799
1426
|
if (this._isRemoved) return;
|
|
800
1427
|
if (this._listeners[eventName] != undefined) {
|
|
@@ -805,10 +1432,18 @@
|
|
|
805
1432
|
}
|
|
806
1433
|
}
|
|
807
1434
|
}
|
|
1435
|
+
//console.log('%c⏵ Event: '+eventName+' was dispatched: '+count+' times', 'background: yellow; color: black;');
|
|
808
1436
|
}
|
|
809
1437
|
}
|
|
810
1438
|
|
|
1439
|
+
/**
|
|
1440
|
+
* Class responsible for operations on numbers
|
|
1441
|
+
*/
|
|
811
1442
|
class NumberUtilities {
|
|
1443
|
+
/**
|
|
1444
|
+
* Adds leading "zero" before the number and returns it as a string. Example: "1" -> "01"
|
|
1445
|
+
* @param number
|
|
1446
|
+
*/
|
|
812
1447
|
static addLeadingZero(number) {
|
|
813
1448
|
if (number < 10) {
|
|
814
1449
|
return "0" + number;
|
|
@@ -846,9 +1481,27 @@
|
|
|
846
1481
|
};
|
|
847
1482
|
|
|
848
1483
|
class Logger {
|
|
1484
|
+
/**
|
|
1485
|
+
* Constructor
|
|
1486
|
+
*
|
|
1487
|
+
* @param config object containing settings for logger
|
|
1488
|
+
* @param stormLibrary reference to main class
|
|
1489
|
+
*/
|
|
849
1490
|
constructor(config, stormStreamer) {
|
|
1491
|
+
/**
|
|
1492
|
+
* List of colors used for monoColor option
|
|
1493
|
+
* @private
|
|
1494
|
+
*/
|
|
850
1495
|
this.colorOrder = ["red", "green", "blue", "orange", "black", "violet"];
|
|
1496
|
+
/**
|
|
1497
|
+
* Stores all loges within this array
|
|
1498
|
+
* @private
|
|
1499
|
+
*/
|
|
851
1500
|
this._logMemory = [];
|
|
1501
|
+
/**
|
|
1502
|
+
* Main name of the instance
|
|
1503
|
+
* @private
|
|
1504
|
+
*/
|
|
852
1505
|
this._streamerInstanceID = -1;
|
|
853
1506
|
this._debugConfig = config;
|
|
854
1507
|
this._stormStreamer = stormStreamer;
|
|
@@ -856,6 +1509,12 @@
|
|
|
856
1509
|
let colorID = this.colorOrder.length < stormStreamer.getStreamerID() ? this.colorOrder.length - 1 : stormStreamer.getStreamerID();
|
|
857
1510
|
this._monoColor = this.colorOrder[colorID];
|
|
858
1511
|
}
|
|
1512
|
+
/**
|
|
1513
|
+
* Creates new "info" type log
|
|
1514
|
+
*
|
|
1515
|
+
* @param objectName object that called the log
|
|
1516
|
+
* @param message log message
|
|
1517
|
+
*/
|
|
859
1518
|
info(objectName, message) {
|
|
860
1519
|
let output = this.logData(objectName, message);
|
|
861
1520
|
if (this._debugConfig.consoleLogEnabled) {
|
|
@@ -871,6 +1530,12 @@
|
|
|
871
1530
|
}
|
|
872
1531
|
}
|
|
873
1532
|
}
|
|
1533
|
+
/**
|
|
1534
|
+
* Creates new "warning" type log
|
|
1535
|
+
*
|
|
1536
|
+
* @param objectName object that called the log
|
|
1537
|
+
* @param message log message
|
|
1538
|
+
*/
|
|
874
1539
|
warning(objectName, message) {
|
|
875
1540
|
let output = this.logData(objectName, message);
|
|
876
1541
|
if (this._debugConfig.consoleLogEnabled) {
|
|
@@ -899,10 +1564,16 @@
|
|
|
899
1564
|
const id = this._stormStreamer.getStreamerID();
|
|
900
1565
|
const keyCaps = id >= 0 && id < EMOJI_MAP.length ? EMOJI_MAP[id] : `[${id}]`;
|
|
901
1566
|
const color = COLOR_SCHEMES[scheme];
|
|
902
|
-
if (!color) return;
|
|
1567
|
+
if (!color) return; // Early return if invalid scheme
|
|
903
1568
|
const style = `background: black; color: ${color}; border: 1px solid ${color}; padding: 5px 5px 5px 0px`;
|
|
904
1569
|
console.log(`%c 🎦️${keyCaps} ${text}`, style);
|
|
905
1570
|
}
|
|
1571
|
+
/**
|
|
1572
|
+
* Creates new "error" type log
|
|
1573
|
+
*
|
|
1574
|
+
* @param objectName object that called the log
|
|
1575
|
+
* @param message log message
|
|
1576
|
+
*/
|
|
906
1577
|
error(objectName, message) {
|
|
907
1578
|
let output = this.logData(objectName, message);
|
|
908
1579
|
if (this._debugConfig.consoleLogEnabled) {
|
|
@@ -918,6 +1589,12 @@
|
|
|
918
1589
|
}
|
|
919
1590
|
}
|
|
920
1591
|
}
|
|
1592
|
+
/**
|
|
1593
|
+
* Creates new "success" type log
|
|
1594
|
+
*
|
|
1595
|
+
* @param objectName object that called the log
|
|
1596
|
+
* @param message log message
|
|
1597
|
+
*/
|
|
921
1598
|
success(objectName, message) {
|
|
922
1599
|
let output = this.logData(objectName, message);
|
|
923
1600
|
if (this._debugConfig.consoleLogEnabled) {
|
|
@@ -933,6 +1610,12 @@
|
|
|
933
1610
|
}
|
|
934
1611
|
}
|
|
935
1612
|
}
|
|
1613
|
+
/**
|
|
1614
|
+
* Creates new "trace" type log
|
|
1615
|
+
*
|
|
1616
|
+
* @param objectName object that called the log
|
|
1617
|
+
* @param message log message
|
|
1618
|
+
*/
|
|
936
1619
|
trace(objectName, message) {
|
|
937
1620
|
let output = this.logData(objectName, message);
|
|
938
1621
|
if (this._debugConfig.consoleLogEnabled) {
|
|
@@ -948,6 +1631,12 @@
|
|
|
948
1631
|
}
|
|
949
1632
|
}
|
|
950
1633
|
}
|
|
1634
|
+
/**
|
|
1635
|
+
* Prepares console message and formats its text
|
|
1636
|
+
* @param _objectName object that called the log
|
|
1637
|
+
* @param message log message
|
|
1638
|
+
* @private
|
|
1639
|
+
*/
|
|
951
1640
|
logData(_objectName, message) {
|
|
952
1641
|
let date = new Date();
|
|
953
1642
|
let hour = NumberUtilities.addLeadingZero(date.getHours());
|
|
@@ -959,6 +1648,13 @@
|
|
|
959
1648
|
this._logMemory.push(finalString);
|
|
960
1649
|
return finalString;
|
|
961
1650
|
}
|
|
1651
|
+
/**
|
|
1652
|
+
* Writes log to a DOM container
|
|
1653
|
+
*
|
|
1654
|
+
* @param message the message
|
|
1655
|
+
* @param color of the log
|
|
1656
|
+
* @private
|
|
1657
|
+
*/
|
|
962
1658
|
writeToContainer(message, color) {
|
|
963
1659
|
let containerName = this._debugConfig.containerID;
|
|
964
1660
|
if (containerName) {
|
|
@@ -969,28 +1665,67 @@
|
|
|
969
1665
|
container.appendChild(log);
|
|
970
1666
|
}
|
|
971
1667
|
}
|
|
1668
|
+
/**
|
|
1669
|
+
* Sets player id
|
|
1670
|
+
* @param playerID
|
|
1671
|
+
*/
|
|
972
1672
|
setPlayerID(playerID) {
|
|
973
1673
|
this._streamerInstanceID = playerID;
|
|
974
1674
|
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Returns all logs
|
|
1677
|
+
*/
|
|
975
1678
|
getAllLogs() {
|
|
976
1679
|
return this._logMemory;
|
|
977
1680
|
}
|
|
978
1681
|
}
|
|
1682
|
+
/**
|
|
1683
|
+
* Defines what color an info log would be outputted (can be either a color name or #hex)
|
|
1684
|
+
* @private
|
|
1685
|
+
*/
|
|
979
1686
|
Logger.INFO_COLOR = "blue";
|
|
1687
|
+
/**
|
|
1688
|
+
* Defines what color a warning log would be outputted (can be either a color name or #hex)
|
|
1689
|
+
* @private
|
|
1690
|
+
*/
|
|
980
1691
|
Logger.WARNING_COLOR = "orange";
|
|
1692
|
+
/**
|
|
1693
|
+
* Defines what color an error log would be outputted (can be either a color name or #hex)
|
|
1694
|
+
* @private
|
|
1695
|
+
*/
|
|
981
1696
|
Logger.ERROR_COLOR = "red";
|
|
1697
|
+
/**
|
|
1698
|
+
* Defines what color a success log would be outputted (can be either a color name or #hex)
|
|
1699
|
+
* @private
|
|
1700
|
+
*/
|
|
982
1701
|
Logger.SUCCESS_COLOR = "green";
|
|
1702
|
+
/**
|
|
1703
|
+
* Defines what color a success log would be outputted (can be either a color name or #hex)
|
|
1704
|
+
* @private
|
|
1705
|
+
*/
|
|
983
1706
|
Logger.TRACE_COLOR = "black";
|
|
984
1707
|
|
|
1708
|
+
/**
|
|
1709
|
+
* Class for detecting user device, browser, etc.
|
|
1710
|
+
*/
|
|
985
1711
|
class UserCapabilities {
|
|
1712
|
+
/**
|
|
1713
|
+
* Returns true or false depending on availability of WebSockets
|
|
1714
|
+
*/
|
|
986
1715
|
static hasWebSocketsSupport() {
|
|
987
1716
|
return window.WebSocket != null;
|
|
988
1717
|
}
|
|
1718
|
+
/**
|
|
1719
|
+
* Returns true if user is using a mobile browser
|
|
1720
|
+
*/
|
|
989
1721
|
static isMobile() {
|
|
990
1722
|
const mobileCheckString = "Mobile|mini|Fennec|Android|iP(ad|od|hone)";
|
|
991
1723
|
const mobileCheckRegExp = new RegExp(mobileCheckString);
|
|
992
1724
|
return mobileCheckRegExp.test(navigator.userAgent);
|
|
993
1725
|
}
|
|
1726
|
+
/**
|
|
1727
|
+
* Returns true if cookies are enabled for this browser/device
|
|
1728
|
+
*/
|
|
994
1729
|
static isCookieEnabled() {
|
|
995
1730
|
let cookieEnabled = navigator.cookieEnabled ? true : false;
|
|
996
1731
|
if (typeof navigator.cookieEnabled == 'undefined' && !cookieEnabled) {
|
|
@@ -999,6 +1734,9 @@
|
|
|
999
1734
|
}
|
|
1000
1735
|
return cookieEnabled;
|
|
1001
1736
|
}
|
|
1737
|
+
/**
|
|
1738
|
+
* Returns an OS Version
|
|
1739
|
+
*/
|
|
1002
1740
|
static getOSVersion() {
|
|
1003
1741
|
let osVersion = "Unknown version";
|
|
1004
1742
|
let os = UserCapabilities.getOS();
|
|
@@ -1008,7 +1746,9 @@
|
|
|
1008
1746
|
if (windowsCheckRegExp.test(os)) {
|
|
1009
1747
|
const windowsExecString = "Windows (.*)";
|
|
1010
1748
|
const windowsExecRegExp = new RegExp(windowsExecString);
|
|
1749
|
+
// @ts-ignore
|
|
1011
1750
|
osVersion = windowsExecRegExp.exec(os)[1] != null ? windowsExecRegExp.exec(os)[1] : osVersion;
|
|
1751
|
+
// @ts-ignore
|
|
1012
1752
|
os = 'Windows';
|
|
1013
1753
|
}
|
|
1014
1754
|
switch (os) {
|
|
@@ -1017,37 +1757,53 @@
|
|
|
1017
1757
|
case 'Android':
|
|
1018
1758
|
const versionExecString = "(?:Android|Mac OS|Mac OS X|MacPPC|MacIntel|Mac_PowerPC|Macintosh) ([\\.\\_\\d]+)";
|
|
1019
1759
|
const versionExecRegExp = new RegExp(versionExecString);
|
|
1760
|
+
// @ts-ignore
|
|
1020
1761
|
osVersion = versionExecRegExp.exec(navigator.userAgent)[1];
|
|
1021
1762
|
break;
|
|
1022
1763
|
case 'iOS':
|
|
1023
1764
|
const iOSExecString = "OS (\\d+)_(\\d+)_?(\\d+)?";
|
|
1024
1765
|
const iOSExecRegExp = new RegExp(iOSExecString);
|
|
1766
|
+
// @ts-ignore
|
|
1025
1767
|
osVersion = iOSExecRegExp.exec(navigator.userAgent);
|
|
1768
|
+
// @ts-ignore
|
|
1026
1769
|
osVersion = osVersion[1] + '.' + osVersion[2] + '.' + (osVersion[3] | 0);
|
|
1027
1770
|
break;
|
|
1028
1771
|
}
|
|
1029
1772
|
}
|
|
1030
1773
|
return osVersion;
|
|
1031
1774
|
}
|
|
1775
|
+
/**
|
|
1776
|
+
* Returns a browser name
|
|
1777
|
+
*/
|
|
1032
1778
|
static getBrowserName() {
|
|
1033
1779
|
return UserCapabilities.getFullBrowser().name;
|
|
1034
1780
|
}
|
|
1781
|
+
/**
|
|
1782
|
+
* Returns a browser version
|
|
1783
|
+
*/
|
|
1035
1784
|
static getBrowserVersion() {
|
|
1036
1785
|
return UserCapabilities.getFullBrowser().version;
|
|
1037
1786
|
}
|
|
1787
|
+
/**
|
|
1788
|
+
* Returns a full browser name
|
|
1789
|
+
*/
|
|
1038
1790
|
static getFullBrowser() {
|
|
1791
|
+
//browser
|
|
1039
1792
|
let nAgt = navigator.userAgent;
|
|
1040
1793
|
let browser = navigator.appName;
|
|
1041
1794
|
let version = '' + parseFloat(navigator.appVersion);
|
|
1042
1795
|
let majorVersion = parseInt(navigator.appVersion, 10);
|
|
1043
1796
|
let nameOffset, verOffset, ix;
|
|
1797
|
+
// Opera
|
|
1044
1798
|
if ((verOffset = nAgt.indexOf('Opera')) != -1) {
|
|
1045
1799
|
browser = 'Opera';
|
|
1046
1800
|
version = nAgt.substring(verOffset + 6);
|
|
1047
1801
|
if ((verOffset = nAgt.indexOf('Version')) != -1) {
|
|
1048
1802
|
version = nAgt.substring(verOffset + 8);
|
|
1049
1803
|
}
|
|
1050
|
-
}
|
|
1804
|
+
}
|
|
1805
|
+
// MSIE
|
|
1806
|
+
else if ((verOffset = nAgt.indexOf('MSIE')) != -1) {
|
|
1051
1807
|
browser = 'Microsoft Internet Explorer';
|
|
1052
1808
|
version = nAgt.substring(verOffset + 5);
|
|
1053
1809
|
} else if (browser == 'Netscape' && nAgt.indexOf('Trident/') != -1) {
|
|
@@ -1056,34 +1812,50 @@
|
|
|
1056
1812
|
if ((verOffset = nAgt.indexOf('rv:')) != -1) {
|
|
1057
1813
|
version = nAgt.substring(verOffset + 3);
|
|
1058
1814
|
}
|
|
1059
|
-
}
|
|
1815
|
+
}
|
|
1816
|
+
// Chrome
|
|
1817
|
+
else if ((verOffset = nAgt.indexOf('Chrome')) != -1) {
|
|
1060
1818
|
browser = 'Chrome';
|
|
1061
1819
|
if (nAgt.indexOf("FBAV") > -1 || nAgt.indexOf("FBAN") > -1) browser = 'Facebook';
|
|
1062
1820
|
if (nAgt.indexOf("OPR") > -1) browser = 'Opera';
|
|
1063
1821
|
if (nAgt.indexOf("SamsungBrowser") > -1) browser = 'Samsung';
|
|
1064
1822
|
version = nAgt.substring(verOffset + 7);
|
|
1065
|
-
}
|
|
1823
|
+
}
|
|
1824
|
+
// Safari
|
|
1825
|
+
else if ((verOffset = nAgt.indexOf('Safari')) != -1) {
|
|
1066
1826
|
browser = 'Safari';
|
|
1067
1827
|
version = nAgt.substring(verOffset + 7);
|
|
1068
1828
|
if ((verOffset = nAgt.indexOf('Version')) != -1) {
|
|
1069
1829
|
version = nAgt.substring(verOffset + 8);
|
|
1070
1830
|
}
|
|
1831
|
+
// Chrome on iPad identifies itself as Safari. Actual results do not match what Google claims
|
|
1832
|
+
// at: https://developers.google.com/chrome/mobile/docs/user-agent?hl=ja
|
|
1833
|
+
// No mention of chrome in the user agent string. However it does mention CriOS, which presumably
|
|
1834
|
+
// can be keyed on to detect it.
|
|
1071
1835
|
if (nAgt.indexOf('CriOS') != -1) {
|
|
1836
|
+
//Chrome on iPad spoofing Safari...correct it.
|
|
1072
1837
|
browser = 'Chrome';
|
|
1838
|
+
//Don't believe there is a way to grab the accurate version number, so leaving that for now.
|
|
1073
1839
|
}
|
|
1840
|
+
|
|
1074
1841
|
if (nAgt.indexOf('FxiOS') != -1) {
|
|
1075
1842
|
browser = "Firefox";
|
|
1076
1843
|
}
|
|
1077
|
-
}
|
|
1844
|
+
}
|
|
1845
|
+
// Firefox
|
|
1846
|
+
else if ((verOffset = nAgt.indexOf('Firefox')) != -1) {
|
|
1078
1847
|
browser = 'Firefox';
|
|
1079
1848
|
version = nAgt.substring(verOffset + 8);
|
|
1080
|
-
}
|
|
1849
|
+
}
|
|
1850
|
+
// Other browsers
|
|
1851
|
+
else if ((nameOffset = nAgt.lastIndexOf(' ') + 1) < (verOffset = nAgt.lastIndexOf('/'))) {
|
|
1081
1852
|
browser = nAgt.substring(nameOffset, verOffset);
|
|
1082
1853
|
version = nAgt.substring(verOffset + 1);
|
|
1083
1854
|
if (browser.toLowerCase() == browser.toUpperCase()) {
|
|
1084
1855
|
browser = navigator.appName;
|
|
1085
1856
|
}
|
|
1086
1857
|
}
|
|
1858
|
+
// trim the version string
|
|
1087
1859
|
if ((ix = version.indexOf(';')) != -1) version = version.substring(0, ix);
|
|
1088
1860
|
if ((ix = version.indexOf(' ')) != -1) version = version.substring(0, ix);
|
|
1089
1861
|
if ((ix = version.indexOf(')')) != -1) version = version.substring(0, ix);
|
|
@@ -1098,6 +1870,9 @@
|
|
|
1098
1870
|
"version": majorVersion
|
|
1099
1871
|
};
|
|
1100
1872
|
}
|
|
1873
|
+
/**
|
|
1874
|
+
* Returns Operating System name
|
|
1875
|
+
*/
|
|
1101
1876
|
static getOS() {
|
|
1102
1877
|
let os = "Unknown OS";
|
|
1103
1878
|
let oscodes = [{
|
|
@@ -1192,9 +1967,15 @@
|
|
|
1192
1967
|
}
|
|
1193
1968
|
return os;
|
|
1194
1969
|
}
|
|
1970
|
+
/**
|
|
1971
|
+
* Returns true whenever device supports WebRTC
|
|
1972
|
+
*/
|
|
1195
1973
|
static hasWebRTCSupport() {
|
|
1974
|
+
//if(this.getBrowserName() == "Facebook" && this.getOS() == "Android")
|
|
1975
|
+
//return false;
|
|
1196
1976
|
let isSupported = false;
|
|
1197
1977
|
try {
|
|
1978
|
+
// @ts-ignore
|
|
1198
1979
|
let webrtc = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || window.RTCPeerConnection;
|
|
1199
1980
|
isSupported = true;
|
|
1200
1981
|
} catch (error) {
|
|
@@ -1202,47 +1983,99 @@
|
|
|
1202
1983
|
}
|
|
1203
1984
|
return isSupported;
|
|
1204
1985
|
}
|
|
1986
|
+
/**
|
|
1987
|
+
* Checks whenever player support "out-of-box" HLS (mobile browsers mostly do)
|
|
1988
|
+
* @param videoObject html element video
|
|
1989
|
+
*/
|
|
1205
1990
|
static hasHLSSupport(videoObject) {
|
|
1991
|
+
//if(this.getBrowserName() == "Facebook" && this.getOS() == "Android")
|
|
1992
|
+
//return false;
|
|
1206
1993
|
if (videoObject !== null) {
|
|
1207
1994
|
return Boolean(videoObject.canPlayType('application/vnd.apple.mpegURL') || videoObject.canPlayType('audio/mpegurl'));
|
|
1208
1995
|
} else return false;
|
|
1209
1996
|
}
|
|
1997
|
+
/**
|
|
1998
|
+
* Returns true or false depending on availability of Media Source Extensions (MSE)
|
|
1999
|
+
*/
|
|
1210
2000
|
static hasMSESupport() {
|
|
2001
|
+
// @ts-ignore
|
|
1211
2002
|
const mediaSource = window.MediaSource = window.MediaSource || window.WebKitMediaSource;
|
|
2003
|
+
// @ts-ignore
|
|
1212
2004
|
window.SourceBuffer = window.SourceBuffer || window.WebKitSourceBuffer;
|
|
1213
2005
|
return mediaSource && typeof mediaSource.isTypeSupported === 'function';
|
|
1214
2006
|
}
|
|
2007
|
+
/**
|
|
2008
|
+
* Returns true or false depending on availability of Managed Media Source Extensions (MMS).
|
|
2009
|
+
* This API is MacOS / iOS only.
|
|
2010
|
+
*/
|
|
1215
2011
|
static hasMMSSupport() {
|
|
2012
|
+
// @ts-ignore
|
|
1216
2013
|
return window.ManagedMediaSource;
|
|
1217
2014
|
}
|
|
2015
|
+
/**
|
|
2016
|
+
* Returns true whenever user is connected via HTTPS
|
|
2017
|
+
*/
|
|
1218
2018
|
static isSSL() {
|
|
1219
2019
|
if (location.protocol === 'https:') return true;else return false;
|
|
1220
2020
|
}
|
|
1221
2021
|
}
|
|
1222
2022
|
|
|
2023
|
+
/**
|
|
2024
|
+
* Saves and retrieve data from localStorage.
|
|
2025
|
+
*/
|
|
1223
2026
|
class StorageManager {
|
|
2027
|
+
/**
|
|
2028
|
+
* Constructor
|
|
2029
|
+
* @param main
|
|
2030
|
+
* @param prefix
|
|
2031
|
+
*/
|
|
1224
2032
|
constructor(main) {
|
|
1225
2033
|
var _a, _b, _c, _d, _e, _f;
|
|
2034
|
+
/**
|
|
2035
|
+
* Decides whenever logs are being generated by this class
|
|
2036
|
+
* @private
|
|
2037
|
+
*/
|
|
1226
2038
|
this.LOG_ACTIVITY = false;
|
|
2039
|
+
/**
|
|
2040
|
+
* Whenever saving cookies is enabled at all
|
|
2041
|
+
* @private
|
|
2042
|
+
*/
|
|
1227
2043
|
this.isEnabled = true;
|
|
2044
|
+
/**
|
|
2045
|
+
* Prefix for multiple instances
|
|
2046
|
+
* @private
|
|
2047
|
+
*/
|
|
1228
2048
|
this.prefix = "";
|
|
1229
2049
|
this.logger = main.getLogger();
|
|
1230
2050
|
this.isEnabled = (_c = (_b = (_a = main.getConfigManager()) === null || _a === void 0 ? void 0 : _a.getSettingsData()) === null || _b === void 0 ? void 0 : _b.getStorageData().enabled) !== null && _c !== void 0 ? _c : this.isEnabled;
|
|
1231
2051
|
this.prefix = (_f = (_e = (_d = main.getConfigManager()) === null || _d === void 0 ? void 0 : _d.getSettingsData()) === null || _e === void 0 ? void 0 : _e.getStorageData().prefix) !== null && _f !== void 0 ? _f : this.prefix;
|
|
1232
2052
|
if (this.LOG_ACTIVITY) this.logger.info(this, "Creating new StorageManager");
|
|
1233
2053
|
}
|
|
2054
|
+
/**
|
|
2055
|
+
* Saves data a a cookie
|
|
2056
|
+
* @param name name of a field
|
|
2057
|
+
* @param value value of a field
|
|
2058
|
+
*/
|
|
1234
2059
|
saveField(name, value) {
|
|
1235
2060
|
if (this.isEnabled == true) {
|
|
1236
2061
|
if (this.LOG_ACTIVITY) this.logger.info(this, "Saving data: " + name + " | " + value);
|
|
1237
2062
|
localStorage.setItem(this.prefix + name, value);
|
|
1238
2063
|
}
|
|
1239
2064
|
}
|
|
2065
|
+
/**
|
|
2066
|
+
* Removes a field from localStorage
|
|
2067
|
+
* @param name the name of the field to remove
|
|
2068
|
+
*/
|
|
1240
2069
|
removeField(name) {
|
|
1241
2070
|
if (this.isEnabled) {
|
|
1242
2071
|
if (this.LOG_ACTIVITY) this.logger.info(this, "Removing data: " + name);
|
|
1243
2072
|
localStorage.removeItem(this.prefix + name);
|
|
1244
2073
|
}
|
|
1245
2074
|
}
|
|
2075
|
+
/**
|
|
2076
|
+
* Retrieves field from cookie
|
|
2077
|
+
* @param name cookie name
|
|
2078
|
+
*/
|
|
1246
2079
|
getField(name) {
|
|
1247
2080
|
if (this.isEnabled == true) {
|
|
1248
2081
|
const value = localStorage.getItem(this.prefix + name);
|
|
@@ -1638,13 +2471,38 @@
|
|
|
1638
2471
|
|
|
1639
2472
|
var debounce$1 = /*@__PURE__*/getDefaultExportFromCjs(lodash_debounce);
|
|
1640
2473
|
|
|
2474
|
+
/**
|
|
2475
|
+
* Class controls the VideoElement itself
|
|
2476
|
+
*/
|
|
1641
2477
|
class ScreenElement {
|
|
2478
|
+
//------------------------------------------------------------------------//
|
|
2479
|
+
// CONSTRUCTOR
|
|
2480
|
+
//------------------------------------------------------------------------//
|
|
1642
2481
|
constructor(main) {
|
|
1643
2482
|
var _a, _b, _c, _d, _e, _f;
|
|
2483
|
+
/**
|
|
2484
|
+
* Decides whenever logs are being generated by this class
|
|
2485
|
+
* @private
|
|
2486
|
+
*/
|
|
1644
2487
|
this.LOG_ACTIVITY = true;
|
|
2488
|
+
/**
|
|
2489
|
+
* Current volume level
|
|
2490
|
+
* @private
|
|
2491
|
+
*/
|
|
1645
2492
|
this._volume = 100;
|
|
2493
|
+
/**
|
|
2494
|
+
* Whenever video is muted
|
|
2495
|
+
* @private
|
|
2496
|
+
*/
|
|
1646
2497
|
this._isMuted = false;
|
|
2498
|
+
/**
|
|
2499
|
+
* Whenever video is muted by a browser
|
|
2500
|
+
* @private
|
|
2501
|
+
*/
|
|
1647
2502
|
this._isMutedByBrowser = false;
|
|
2503
|
+
/**
|
|
2504
|
+
* Called whenever browser stops playback
|
|
2505
|
+
*/
|
|
1648
2506
|
this.onForceMute = () => {
|
|
1649
2507
|
this._isMuted = true;
|
|
1650
2508
|
this._isMutedByBrowser = true;
|
|
@@ -1677,18 +2535,33 @@
|
|
|
1677
2535
|
});
|
|
1678
2536
|
this.initialize();
|
|
1679
2537
|
}
|
|
2538
|
+
//------------------------------------------------------------------------//
|
|
2539
|
+
// MAIN METHODS
|
|
2540
|
+
//------------------------------------------------------------------------//
|
|
2541
|
+
/**
|
|
2542
|
+
* Initializes and pre-configures main video object
|
|
2543
|
+
*/
|
|
1680
2544
|
initialize() {
|
|
1681
|
-
this._videoElement.onload = function (event) {
|
|
2545
|
+
this._videoElement.onload = function (event) {
|
|
2546
|
+
//console.log('videoElement.onload', event);
|
|
2547
|
+
};
|
|
1682
2548
|
this._videoElement.onstalled = event => {
|
|
1683
2549
|
this._logger.info(this, "VideoElement :: onstalled");
|
|
1684
2550
|
};
|
|
1685
2551
|
this._videoElement.onerror = event => {
|
|
1686
2552
|
this._logger.info(this, "VideoElement :: onerror :: " + JSON.stringify(event));
|
|
1687
2553
|
};
|
|
2554
|
+
/**
|
|
2555
|
+
* Fires whenever something changes video object volume
|
|
2556
|
+
* @param event
|
|
2557
|
+
*/
|
|
2558
|
+
// @ts-ignore
|
|
1688
2559
|
this._videoElement.onvolumechange = () => {
|
|
1689
2560
|
this.dispatchVolumeEvent();
|
|
1690
2561
|
};
|
|
1691
|
-
this._videoElement.onpause = () => {
|
|
2562
|
+
this._videoElement.onpause = () => {
|
|
2563
|
+
// nothing
|
|
2564
|
+
};
|
|
1692
2565
|
this._videoElement.addEventListener('loadedmetadata', () => {
|
|
1693
2566
|
this._main.dispatchEvent("metadata", {
|
|
1694
2567
|
ref: this._main,
|
|
@@ -1696,12 +2569,33 @@
|
|
|
1696
2569
|
videoHeight: this._videoElement.videoHeight
|
|
1697
2570
|
});
|
|
1698
2571
|
});
|
|
1699
|
-
|
|
2572
|
+
/**
|
|
2573
|
+
* Updates every second,
|
|
2574
|
+
* @param event
|
|
2575
|
+
*/
|
|
2576
|
+
this._videoElement.ontimeupdate = function (event) {
|
|
2577
|
+
/*
|
|
2578
|
+
let newWidth: number = self.videoElement.videoWidth;
|
|
2579
|
+
let newHeight: number = self.videoElement.videoHeight;
|
|
2580
|
+
if (newWidth != 0 && newHeight != 0) {
|
|
2581
|
+
if (newWidth !== self.videoWidth || newHeight !== self.videoHeight) {
|
|
2582
|
+
self.videoWidth = newWidth;
|
|
2583
|
+
self.videoHeight = newHeight;
|
|
2584
|
+
self.scaleVideo();
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
*/
|
|
2588
|
+
};
|
|
2589
|
+
// @ts-ignore
|
|
1700
2590
|
this._videoElement.onended = event => {
|
|
1701
2591
|
this._logger.info(this, "VideoElement :: onended");
|
|
1702
2592
|
};
|
|
1703
2593
|
this._videoElement.onplay = () => {};
|
|
1704
2594
|
}
|
|
2595
|
+
/**
|
|
2596
|
+
* Sets new volume for playback. It'll also try to store value in a browser memory
|
|
2597
|
+
* @param value
|
|
2598
|
+
*/
|
|
1705
2599
|
setVolume(value) {
|
|
1706
2600
|
if (this._isMuted && value > 0) this.setMuted(false);
|
|
1707
2601
|
this._volume = value;
|
|
@@ -1712,6 +2606,10 @@
|
|
|
1712
2606
|
getVolume() {
|
|
1713
2607
|
return this._volume;
|
|
1714
2608
|
}
|
|
2609
|
+
/**
|
|
2610
|
+
* Allows to apply mute to a video element
|
|
2611
|
+
* @param isMuted
|
|
2612
|
+
*/
|
|
1715
2613
|
setMuted(isMuted) {
|
|
1716
2614
|
this._isMuted = isMuted;
|
|
1717
2615
|
this._videoElement.muted = isMuted;
|
|
@@ -1719,9 +2617,15 @@
|
|
|
1719
2617
|
this._main.getStorageManager().saveField("muted", String(isMuted));
|
|
1720
2618
|
if (this.getVolume() == 0 && !isMuted) this.setVolume(100);
|
|
1721
2619
|
}
|
|
2620
|
+
/**
|
|
2621
|
+
* Returns true/false whenever video is muted or not
|
|
2622
|
+
*/
|
|
1722
2623
|
getIfMuted() {
|
|
1723
2624
|
return this._isMuted;
|
|
1724
2625
|
}
|
|
2626
|
+
/**
|
|
2627
|
+
* Dispatches event informing about volume chan
|
|
2628
|
+
*/
|
|
1725
2629
|
dispatchVolumeEvent() {
|
|
1726
2630
|
const action = !this._isMutedByBrowser ? "user" : "browser";
|
|
1727
2631
|
const eventObj = {
|
|
@@ -1737,12 +2641,22 @@
|
|
|
1737
2641
|
invokedBy: action
|
|
1738
2642
|
});
|
|
1739
2643
|
}
|
|
2644
|
+
/**
|
|
2645
|
+
* Return VideoElement
|
|
2646
|
+
*/
|
|
1740
2647
|
getVideoElement() {
|
|
1741
2648
|
return this._videoElement;
|
|
1742
2649
|
}
|
|
1743
2650
|
}
|
|
1744
2651
|
|
|
2652
|
+
/**
|
|
2653
|
+
* Class responsible for operations on numbers
|
|
2654
|
+
*/
|
|
1745
2655
|
class DomUtilities {
|
|
2656
|
+
/**
|
|
2657
|
+
* Calculates element dimensions including margins
|
|
2658
|
+
* @param element
|
|
2659
|
+
*/
|
|
1746
2660
|
static calculateDimensionsWithMargins(element) {
|
|
1747
2661
|
const style = window.getComputedStyle(element);
|
|
1748
2662
|
const rect = element.getBoundingClientRect();
|
|
@@ -1763,20 +2677,73 @@
|
|
|
1763
2677
|
}
|
|
1764
2678
|
}
|
|
1765
2679
|
|
|
2680
|
+
/**
|
|
2681
|
+
* Class controls all visual elements of the player
|
|
2682
|
+
*/
|
|
1766
2683
|
class StageController {
|
|
2684
|
+
//------------------------------------------------------------------------//
|
|
2685
|
+
// CONSTRUCTOR
|
|
2686
|
+
//------------------------------------------------------------------------//
|
|
1767
2687
|
constructor(main) {
|
|
2688
|
+
/**
|
|
2689
|
+
* Video width
|
|
2690
|
+
* @private
|
|
2691
|
+
*/
|
|
1768
2692
|
this._containerWidth = 0;
|
|
2693
|
+
/**
|
|
2694
|
+
* Temp container width
|
|
2695
|
+
* @private
|
|
2696
|
+
*/
|
|
1769
2697
|
this._tempContainerWidth = 0;
|
|
2698
|
+
/**
|
|
2699
|
+
* Video height
|
|
2700
|
+
* @private
|
|
2701
|
+
*/
|
|
1770
2702
|
this._containerHeight = 0;
|
|
2703
|
+
/**
|
|
2704
|
+
* Temp container height
|
|
2705
|
+
* @private
|
|
2706
|
+
*/
|
|
1771
2707
|
this._tempContainerHeight = 0;
|
|
2708
|
+
/**
|
|
2709
|
+
* Video width (initally 0, after "onmetadata" event is updated to match the real one
|
|
2710
|
+
* @private
|
|
2711
|
+
*/
|
|
1772
2712
|
this._videoWidth = 0;
|
|
2713
|
+
/**
|
|
2714
|
+
* Video width (initally 0, after "onmetadata" event is updated to match the real one
|
|
2715
|
+
* @private
|
|
2716
|
+
*/
|
|
1773
2717
|
this._videoHeight = 0;
|
|
2718
|
+
/**
|
|
2719
|
+
* Current scaling type
|
|
2720
|
+
* @private
|
|
2721
|
+
*/
|
|
1774
2722
|
this._scalingMode = ScalingType.FILL;
|
|
2723
|
+
/**
|
|
2724
|
+
* If in fullscreen mode
|
|
2725
|
+
* @private
|
|
2726
|
+
*/
|
|
1775
2727
|
this.isInFullScreenMode = false;
|
|
2728
|
+
/**
|
|
2729
|
+
* Whenever we are resizing atm.
|
|
2730
|
+
* @private
|
|
2731
|
+
*/
|
|
1776
2732
|
this._isResizing = false;
|
|
2733
|
+
/**
|
|
2734
|
+
* Deco
|
|
2735
|
+
* @private
|
|
2736
|
+
*/
|
|
1777
2737
|
this._autoResizeEnabled = true;
|
|
2738
|
+
/**
|
|
2739
|
+
* Parameter holds original overflow style
|
|
2740
|
+
* @private
|
|
2741
|
+
*/
|
|
1778
2742
|
this._parentOriginalOverflow = '';
|
|
1779
2743
|
this._debug = false;
|
|
2744
|
+
//------------------------------------------------------------------------//
|
|
2745
|
+
// FULLSCREEN
|
|
2746
|
+
//------------------------------------------------------------------------//
|
|
1780
2747
|
this.onFullScreenChange = () => {
|
|
1781
2748
|
if (document.fullscreenElement == null) {
|
|
1782
2749
|
this.isInFullScreenMode = false;
|
|
@@ -1797,16 +2764,22 @@
|
|
|
1797
2764
|
this._logger.info(this, "Creating new StageController");
|
|
1798
2765
|
this.initialize();
|
|
1799
2766
|
}
|
|
2767
|
+
//------------------------------------------------------------------------//
|
|
2768
|
+
// MAIN METHODS
|
|
2769
|
+
//------------------------------------------------------------------------//
|
|
1800
2770
|
initialize() {
|
|
1801
2771
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2772
|
+
// prepare data
|
|
1802
2773
|
const containerID = (_d = (_c = (_b = (_a = this._main.getConfigManager()) === null || _a === void 0 ? void 0 : _a.getSettingsData()) === null || _b === void 0 ? void 0 : _b.getVideoData()) === null || _c === void 0 ? void 0 : _c.containerID) !== null && _d !== void 0 ? _d : null;
|
|
1803
2774
|
this._scalingMode = (_f = (_e = this._main.getConfigManager()) === null || _e === void 0 ? void 0 : _e.getSettingsData().getVideoData().scalingMode) !== null && _f !== void 0 ? _f : ScalingType.FILL;
|
|
1804
2775
|
this._debug = (_h = (_g = this._main.getConfigManager()) === null || _g === void 0 ? void 0 : _g.getSettingsData().getDebugData().stageControllerDebug) !== null && _h !== void 0 ? _h : this._debug;
|
|
2776
|
+
// pre-configuration for videoContainer
|
|
1805
2777
|
this._videoContainer = document.createElement('div');
|
|
1806
2778
|
this._videoContainer.setAttribute("id", "stormStreamer_" + this._main.getStreamerID());
|
|
1807
2779
|
this._videoContainer.style.overflow = "hidden";
|
|
1808
2780
|
this._videoContainer.style.position = "relative";
|
|
1809
2781
|
this._videoContainer.classList.add("stormStreamer");
|
|
2782
|
+
// pre-configuration for videoElement
|
|
1810
2783
|
this._screenElement = new ScreenElement(this._main);
|
|
1811
2784
|
this._videoContainer.appendChild(this._screenElement.getVideoElement());
|
|
1812
2785
|
const debounceValue = this._main.getConfigManager().getSettingsData().getVideoData().resizeDebounce;
|
|
@@ -1836,9 +2809,16 @@
|
|
|
1836
2809
|
this.attachToParent(containerID);
|
|
1837
2810
|
} else this._logger.warning(this, `Could not create HTMLObject for the library - "containerID" was not provided`);
|
|
1838
2811
|
}
|
|
2812
|
+
/**
|
|
2813
|
+
* Method attaches element to a parent container
|
|
2814
|
+
*
|
|
2815
|
+
* @param container
|
|
2816
|
+
*/
|
|
1839
2817
|
attachToParent(container) {
|
|
1840
|
-
|
|
2818
|
+
// preparing elements
|
|
2819
|
+
let result = false; // To indicate the success of the operation
|
|
1841
2820
|
let tempParentElement = null;
|
|
2821
|
+
// Check if container is either an ID string or an HTMLElement instance
|
|
1842
2822
|
if (typeof container === "string") {
|
|
1843
2823
|
this._logger.info(this, "Attaching container to ID: " + container);
|
|
1844
2824
|
tempParentElement = document.getElementById(container);
|
|
@@ -1846,11 +2826,13 @@
|
|
|
1846
2826
|
this._logger.info(this, "Attaching container to HTMLElement: " + container);
|
|
1847
2827
|
tempParentElement = container;
|
|
1848
2828
|
}
|
|
2829
|
+
// Check if the new container is not the same as the old one
|
|
1849
2830
|
if (tempParentElement === this._parentElement) {
|
|
1850
2831
|
if (this._debug) this._logger.decoratedLog("Attaching Failed (container is the same)", "dark-pink");
|
|
1851
2832
|
this._logger.warning(this, "attachToParent :: container is the same");
|
|
1852
2833
|
return false;
|
|
1853
2834
|
}
|
|
2835
|
+
// If a valid container is found and _videoContainer exists, append it
|
|
1854
2836
|
if (tempParentElement && this._videoContainer) {
|
|
1855
2837
|
if (this._debug) this._logger.decoratedLog("Attach To Parent: " + container + " (success)", "dark-pink");
|
|
1856
2838
|
this._parentElement = tempParentElement;
|
|
@@ -1864,13 +2846,16 @@
|
|
|
1864
2846
|
container: this._parentElement
|
|
1865
2847
|
});
|
|
1866
2848
|
this.handleResize();
|
|
1867
|
-
result = true;
|
|
2849
|
+
result = true; // Operation successful
|
|
1868
2850
|
} else {
|
|
1869
2851
|
if (this._debug) this._logger.decoratedLog("Attach To Parent: " + container + " (failure - container not found)", "dark-pink");
|
|
1870
2852
|
this._logger.warning(this, "attachToParent :: container \"" + container + "\"+ was not found");
|
|
1871
2853
|
}
|
|
1872
|
-
return result;
|
|
2854
|
+
return result; // Return the result of the operation
|
|
1873
2855
|
}
|
|
2856
|
+
/**
|
|
2857
|
+
* Detaches the library from a parent container
|
|
2858
|
+
*/
|
|
1874
2859
|
detachFromParent() {
|
|
1875
2860
|
if (this._debug) this._logger.decoratedLog("Detach From Parent", "dark-pink");
|
|
1876
2861
|
let result = false;
|
|
@@ -1898,7 +2883,9 @@
|
|
|
1898
2883
|
this._isResizing = true;
|
|
1899
2884
|
this._parentOriginalOverflow = this._parentElement.style.overflow;
|
|
1900
2885
|
this._parentElement.style.overflow = 'hidden';
|
|
2886
|
+
// Używamy requestAnimationFrame aby dać przeglądarce czas na zastosowanie overflow
|
|
1901
2887
|
requestAnimationFrame(() => {
|
|
2888
|
+
// Obliczamy nowe wymiary
|
|
1902
2889
|
this.calculateNewDimensions();
|
|
1903
2890
|
this._parentElement.style.overflow = this._parentOriginalOverflow;
|
|
1904
2891
|
this._isResizing = false;
|
|
@@ -1933,6 +2920,10 @@
|
|
|
1933
2920
|
this.resizeVideoContainer();
|
|
1934
2921
|
this.scaleVideo();
|
|
1935
2922
|
}
|
|
2923
|
+
/**
|
|
2924
|
+
* Method resizes video container
|
|
2925
|
+
* @private
|
|
2926
|
+
*/
|
|
1936
2927
|
resizeVideoContainer() {
|
|
1937
2928
|
const isWidthInPX = this._main.getConfigManager().getSettingsData().getVideoData().videoWidthInPixels;
|
|
1938
2929
|
const isHeightInPX = this._main.getConfigManager().getSettingsData().getVideoData().videoHeightInPixels;
|
|
@@ -1979,12 +2970,14 @@
|
|
|
1979
2970
|
let videoWidth = 0;
|
|
1980
2971
|
let videoHeight = 0;
|
|
1981
2972
|
switch (this._scalingMode) {
|
|
2973
|
+
//--- FILL, covers 100% of width & height
|
|
1982
2974
|
case ScalingType.FILL:
|
|
1983
2975
|
{
|
|
1984
2976
|
videoWidth = this._containerWidth;
|
|
1985
2977
|
videoHeight = this._containerHeight;
|
|
1986
2978
|
}
|
|
1987
2979
|
break;
|
|
2980
|
+
//--- CROP
|
|
1988
2981
|
case ScalingType.CROP:
|
|
1989
2982
|
{
|
|
1990
2983
|
videoWidth = this._containerWidth;
|
|
@@ -2000,8 +2993,10 @@
|
|
|
2000
2993
|
}
|
|
2001
2994
|
}
|
|
2002
2995
|
break;
|
|
2996
|
+
//--- LETTER BOX
|
|
2003
2997
|
case ScalingType.LETTER_BOX:
|
|
2004
2998
|
{
|
|
2999
|
+
// jeżeli szerokość
|
|
2005
3000
|
videoWidth = this._containerWidth;
|
|
2006
3001
|
videoHeight = this._videoHeight * this._containerWidth / this._videoWidth;
|
|
2007
3002
|
if (videoHeight <= this._containerHeight) {
|
|
@@ -2021,6 +3016,7 @@
|
|
|
2021
3016
|
}
|
|
2022
3017
|
}
|
|
2023
3018
|
break;
|
|
3019
|
+
//--- ORIGINAL
|
|
2024
3020
|
case ScalingType.ORIGINAL:
|
|
2025
3021
|
{
|
|
2026
3022
|
videoWidth = this._videoWidth;
|
|
@@ -2040,7 +3036,9 @@
|
|
|
2040
3036
|
}
|
|
2041
3037
|
enterFullScreen() {
|
|
2042
3038
|
var _a, _b, _c;
|
|
3039
|
+
// @ts-ignore
|
|
2043
3040
|
if ((_a = this._screenElement) === null || _a === void 0 ? void 0 : _a.getVideoElement().webkitEnterFullScreen) {
|
|
3041
|
+
// @ts-ignore
|
|
2044
3042
|
(_b = this._screenElement) === null || _b === void 0 ? void 0 : _b.getVideoElement().webkitEnterFullScreen();
|
|
2045
3043
|
} else {
|
|
2046
3044
|
(_c = this._screenElement) === null || _c === void 0 ? void 0 : _c.getVideoElement().requestFullscreen();
|
|
@@ -2048,7 +3046,9 @@
|
|
|
2048
3046
|
}
|
|
2049
3047
|
exitFullScreen() {
|
|
2050
3048
|
var _a;
|
|
3049
|
+
// @ts-ignore
|
|
2051
3050
|
if ((_a = this._screenElement) === null || _a === void 0 ? void 0 : _a.getVideoElement().webkitExitFullscreen) {
|
|
3051
|
+
// @ts-ignore
|
|
2052
3052
|
document.webkitExitFullscreen();
|
|
2053
3053
|
} else {
|
|
2054
3054
|
document.exitFullscreen();
|
|
@@ -2057,6 +3057,9 @@
|
|
|
2057
3057
|
isFullScreenMode() {
|
|
2058
3058
|
return this.isInFullScreenMode;
|
|
2059
3059
|
}
|
|
3060
|
+
//------------------------------------------------------------------------//
|
|
3061
|
+
// SETS & GETS
|
|
3062
|
+
//------------------------------------------------------------------------//
|
|
2060
3063
|
setDimension(key, value) {
|
|
2061
3064
|
const dimensionKey = key === 'width' ? 'videoWidth' : 'videoHeight';
|
|
2062
3065
|
let valueInPixels;
|
|
@@ -2138,10 +3141,17 @@
|
|
|
2138
3141
|
getContainer() {
|
|
2139
3142
|
return this._videoContainer;
|
|
2140
3143
|
}
|
|
3144
|
+
//------------------------------------------------------------------------//
|
|
3145
|
+
// CLEANUP
|
|
3146
|
+
//------------------------------------------------------------------------//
|
|
2141
3147
|
destroy() {
|
|
2142
3148
|
this.detachFromParent();
|
|
2143
3149
|
}
|
|
2144
3150
|
}
|
|
3151
|
+
/**
|
|
3152
|
+
* Decides whenever logs are being generated by this class
|
|
3153
|
+
* @private
|
|
3154
|
+
*/
|
|
2145
3155
|
StageController.LOG_ACTIVITY = true;
|
|
2146
3156
|
|
|
2147
3157
|
class MungeSDP {
|
|
@@ -2265,7 +3275,9 @@
|
|
|
2265
3275
|
MungeSDP.audioChoice = mungeData.audioCodec || "opus";
|
|
2266
3276
|
MungeSDP.videoIndex = -1;
|
|
2267
3277
|
MungeSDP.audioIndex = -1;
|
|
3278
|
+
// Zapewniamy, że frame rate jest w odpowiednim zakresie
|
|
2268
3279
|
const frameRate = mungeData.videoFrameRate ? Math.min(Math.max(mungeData.videoFrameRate, 1), 60) : 30;
|
|
3280
|
+
// Pierwszy przebieg - zbieranie informacji o kodekach
|
|
2269
3281
|
const sdpLines = sdpStr.split(/\r\n/);
|
|
2270
3282
|
let sdpStrRet = '';
|
|
2271
3283
|
for (const sdpLine of sdpLines) {
|
|
@@ -2274,23 +3286,26 @@
|
|
|
2274
3286
|
if (!doneCheck) continue;
|
|
2275
3287
|
sdpStrRet += sdpLine + '\r\n';
|
|
2276
3288
|
}
|
|
3289
|
+
// Dodaj linie audio i video
|
|
2277
3290
|
sdpStrRet = this.addAudio(sdpStrRet, this.deliverCheckLine(MungeSDP.audioChoice, "audio"));
|
|
2278
3291
|
sdpStrRet = this.addVideo(sdpStrRet, this.deliverCheckLine(MungeSDP.videoChoice, "video"));
|
|
2279
3292
|
const newSdpLines = sdpStrRet.split(/\r\n/);
|
|
2280
3293
|
sdpStrRet = '';
|
|
2281
3294
|
let sdpSection = 'header';
|
|
2282
3295
|
let hitMID = false;
|
|
3296
|
+
// Dodajemy parametry frame rate dla każdego kodeka video
|
|
2283
3297
|
const addFrameRateParameters = payloadType => {
|
|
2284
3298
|
let params = '';
|
|
2285
3299
|
params += `\r\na=rtcp-fb:${payloadType} ccm fir`;
|
|
2286
3300
|
params += `\r\na=rtcp-fb:${payloadType} nack`;
|
|
2287
3301
|
params += `\r\na=rtcp-fb:${payloadType} nack pli`;
|
|
2288
|
-
params += `\r\na=rtcp-fb:${payloadType} goog-remb`;
|
|
3302
|
+
params += `\r\na=rtcp-fb:${payloadType} goog-remb`; // Dodajemy wsparcie dla REMB
|
|
2289
3303
|
params += `\r\na=fmtp:${payloadType} max-fr=${frameRate};max-fps=${frameRate}`;
|
|
2290
3304
|
return params;
|
|
2291
3305
|
};
|
|
2292
3306
|
for (const sdpLine of newSdpLines) {
|
|
2293
3307
|
if (sdpLine.length <= 0) continue;
|
|
3308
|
+
// Sekcja audio
|
|
2294
3309
|
if (sdpLine.indexOf("m=audio") === 0 && MungeSDP.audioIndex !== -1) {
|
|
2295
3310
|
const audioMLines = sdpLine.split(" ");
|
|
2296
3311
|
sdpStrRet += `${audioMLines[0]} ${audioMLines[1]} ${audioMLines[2]} ${MungeSDP.audioIndex}\r\n`;
|
|
@@ -2298,21 +3313,25 @@
|
|
|
2298
3313
|
hitMID = false;
|
|
2299
3314
|
continue;
|
|
2300
3315
|
}
|
|
3316
|
+
// Sekcja video - tutaj dodajemy podstawowe parametry frame rate
|
|
2301
3317
|
if (sdpLine.indexOf("m=video") === 0 && MungeSDP.videoIndex !== -1) {
|
|
2302
3318
|
const videoMLines = sdpLine.split(" ");
|
|
2303
3319
|
sdpStrRet += `${videoMLines[0]} ${videoMLines[1]} ${videoMLines[2]} ${MungeSDP.videoIndex}\r\n`;
|
|
2304
|
-
|
|
2305
|
-
sdpStrRet += `a=
|
|
2306
|
-
sdpStrRet += `a=max-
|
|
3320
|
+
// Dodajemy kompleksowe parametry frame rate
|
|
3321
|
+
sdpStrRet += `a=framerate:${frameRate}\r\n`; // Standardowy parametr
|
|
3322
|
+
sdpStrRet += `a=x-google-max-framerate:${frameRate}\r\n`; // Chrome
|
|
3323
|
+
sdpStrRet += `a=max-fr:${frameRate}\r\n`; // Dodatkowy parametr
|
|
2307
3324
|
sdpSection = 'video';
|
|
2308
3325
|
hitMID = false;
|
|
2309
3326
|
continue;
|
|
2310
3327
|
}
|
|
2311
3328
|
sdpStrRet += sdpLine;
|
|
3329
|
+
// Obsługa rtpmap i parametrów kodeków
|
|
2312
3330
|
if (sdpLine.indexOf("a=rtpmap") === 0) {
|
|
2313
3331
|
const rtpmapID = this.getrtpMapID(sdpLine);
|
|
2314
3332
|
if (rtpmapID !== null) {
|
|
2315
3333
|
const codecName = rtpmapID[2].toLowerCase();
|
|
3334
|
+
// Parametry dla kodeków video
|
|
2316
3335
|
if (codecName === 'vp9' || codecName === 'vp8' || codecName === 'h264') {
|
|
2317
3336
|
sdpStrRet += addFrameRateParameters(rtpmapID[1]);
|
|
2318
3337
|
}
|
|
@@ -2320,6 +3339,7 @@
|
|
|
2320
3339
|
sdpSection = 'bandwidth';
|
|
2321
3340
|
hitMID = false;
|
|
2322
3341
|
}
|
|
3342
|
+
// Obsługa specyficzna dla przeglądarek
|
|
2323
3343
|
const browser = UserCapabilities.getBrowserName().toLowerCase();
|
|
2324
3344
|
if (browser === 'chrome' || browser === 'safari') {
|
|
2325
3345
|
if (sdpLine.indexOf("a=mid:") === 0 || sdpLine.indexOf("a=rtpmap") === 0) {
|
|
@@ -2332,6 +3352,7 @@
|
|
|
2332
3352
|
sdpStrRet += `\r\na=x-google-max-framerate:${frameRate}`;
|
|
2333
3353
|
hitMID = true;
|
|
2334
3354
|
}
|
|
3355
|
+
// Dodatkowe parametry dla Chrome
|
|
2335
3356
|
if (browser === 'chrome' && sdpSection === 'bandwidth') {
|
|
2336
3357
|
const rtpmapID = this.getrtpMapID(sdpLine);
|
|
2337
3358
|
if (rtpmapID !== null) {
|
|
@@ -2489,8 +3510,9 @@
|
|
|
2489
3510
|
this._analyser = null;
|
|
2490
3511
|
this._microphone = null;
|
|
2491
3512
|
this._lastEventTime = 0;
|
|
2492
|
-
this.THROTTLE_INTERVAL = 100;
|
|
3513
|
+
this.THROTTLE_INTERVAL = 100; // ms between updates
|
|
2493
3514
|
this._isMonitoring = false;
|
|
3515
|
+
// Moving average variables for smoothing
|
|
2494
3516
|
this._instant = 0.0;
|
|
2495
3517
|
this._slow = 0.0;
|
|
2496
3518
|
this._main = main;
|
|
@@ -2500,23 +3522,30 @@
|
|
|
2500
3522
|
console.warn('SoundMeter: Attempted to attach stream without audio tracks');
|
|
2501
3523
|
return;
|
|
2502
3524
|
}
|
|
3525
|
+
// Ensure clean state before attaching
|
|
2503
3526
|
this.detach();
|
|
2504
3527
|
try {
|
|
2505
3528
|
this._audioContext = new AudioContext();
|
|
3529
|
+
// Create and configure nodes
|
|
2506
3530
|
this._microphone = this._audioContext.createMediaStreamSource(stream);
|
|
2507
3531
|
this._analyser = this._audioContext.createAnalyser();
|
|
2508
3532
|
this._analyser.fftSize = 2048;
|
|
2509
3533
|
this._analyser.smoothingTimeConstant = 0.3;
|
|
3534
|
+
// Connect nodes
|
|
2510
3535
|
this._microphone.connect(this._analyser);
|
|
3536
|
+
// Start monitoring
|
|
2511
3537
|
this.startMonitoring();
|
|
2512
3538
|
} catch (error) {
|
|
2513
3539
|
console.error('SoundMeter: Error during attach:', error);
|
|
2514
|
-
this.detach();
|
|
3540
|
+
this.detach(); // Cleanup on error
|
|
2515
3541
|
}
|
|
2516
3542
|
}
|
|
3543
|
+
|
|
2517
3544
|
detach() {
|
|
2518
3545
|
var _a, _b;
|
|
3546
|
+
// Stop monitoring first
|
|
2519
3547
|
this._isMonitoring = false;
|
|
3548
|
+
// Disconnect and cleanup nodes in reverse order
|
|
2520
3549
|
if (this._microphone) {
|
|
2521
3550
|
try {
|
|
2522
3551
|
this._microphone.disconnect();
|
|
@@ -2556,7 +3585,9 @@
|
|
|
2556
3585
|
if (!this._analyser || !this._isMonitoring) return;
|
|
2557
3586
|
const now = Date.now();
|
|
2558
3587
|
try {
|
|
3588
|
+
// Read time-domain data
|
|
2559
3589
|
this._analyser.getFloatTimeDomainData(dataArray);
|
|
3590
|
+
// Calculate levels
|
|
2560
3591
|
let sum = 0.0;
|
|
2561
3592
|
let clipcount = 0;
|
|
2562
3593
|
for (let i = 0; i < dataArray.length; ++i) {
|
|
@@ -2566,8 +3597,10 @@
|
|
|
2566
3597
|
clipcount += 1;
|
|
2567
3598
|
}
|
|
2568
3599
|
}
|
|
3600
|
+
// Update metrics
|
|
2569
3601
|
this._instant = Math.sqrt(sum / dataArray.length);
|
|
2570
3602
|
this._slow = 0.05 * this._instant + 0.95 * this._slow;
|
|
3603
|
+
// Throttle event dispatch
|
|
2571
3604
|
if (now - this._lastEventTime >= this.THROTTLE_INTERVAL) {
|
|
2572
3605
|
this._lastEventTime = now;
|
|
2573
3606
|
this._main.dispatchEvent("soundMeter", {
|
|
@@ -2581,8 +3614,10 @@
|
|
|
2581
3614
|
this._isMonitoring = false;
|
|
2582
3615
|
return;
|
|
2583
3616
|
}
|
|
3617
|
+
// Schedule next analysis
|
|
2584
3618
|
requestAnimationFrame(analyze);
|
|
2585
3619
|
};
|
|
3620
|
+
// Start analysis loop
|
|
2586
3621
|
requestAnimationFrame(analyze);
|
|
2587
3622
|
}
|
|
2588
3623
|
}
|
|
@@ -2607,6 +3642,9 @@
|
|
|
2607
3642
|
DeviceState["STOPPED"] = "STOPPED";
|
|
2608
3643
|
})(exports.DeviceState || (exports.DeviceState = {}));
|
|
2609
3644
|
|
|
3645
|
+
/**
|
|
3646
|
+
* Different connection states
|
|
3647
|
+
*/
|
|
2610
3648
|
var ConnectionState;
|
|
2611
3649
|
(function (ConnectionState) {
|
|
2612
3650
|
ConnectionState[ConnectionState["NOT_INITIALIZED"] = 0] = "NOT_INITIALIZED";
|
|
@@ -2617,16 +3655,56 @@
|
|
|
2617
3655
|
ConnectionState[ConnectionState["FAILED"] = 5] = "FAILED";
|
|
2618
3656
|
})(ConnectionState || (ConnectionState = {}));
|
|
2619
3657
|
|
|
3658
|
+
/**
|
|
3659
|
+
* Base for all classes that use WebSocksts
|
|
3660
|
+
*/
|
|
3661
|
+
/**
|
|
3662
|
+
* Abstract socket connection
|
|
3663
|
+
*/
|
|
2620
3664
|
class AbstractSocket {
|
|
2621
3665
|
constructor() {
|
|
3666
|
+
/**
|
|
3667
|
+
* Connection timeout
|
|
3668
|
+
* @protected
|
|
3669
|
+
*/
|
|
2622
3670
|
this.CONNECTION_TIMEOUT = 5;
|
|
3671
|
+
/**
|
|
3672
|
+
* Whenever it is binary data or not
|
|
3673
|
+
* @protected
|
|
3674
|
+
*/
|
|
2623
3675
|
this.isBinary = true;
|
|
3676
|
+
/**
|
|
3677
|
+
* Current state of the connection
|
|
3678
|
+
* @private
|
|
3679
|
+
*/
|
|
2624
3680
|
this._connectionState = ConnectionState.NOT_INITIALIZED;
|
|
3681
|
+
/**
|
|
3682
|
+
* Number of messages that arrived
|
|
3683
|
+
* @private
|
|
3684
|
+
*/
|
|
2625
3685
|
this._messageCount = 0;
|
|
3686
|
+
/**
|
|
3687
|
+
* Was disconnected by user?
|
|
3688
|
+
* @protected
|
|
3689
|
+
*/
|
|
2626
3690
|
this._disconnectedByUser = false;
|
|
3691
|
+
/**
|
|
3692
|
+
* Whenever we're connected to a server or not
|
|
3693
|
+
* @private
|
|
3694
|
+
*/
|
|
2627
3695
|
this._isConnected = false;
|
|
3696
|
+
/**
|
|
3697
|
+
* Counts connections
|
|
3698
|
+
* @protected
|
|
3699
|
+
*/
|
|
2628
3700
|
this._sequenceNumber = -1;
|
|
2629
3701
|
}
|
|
3702
|
+
/**
|
|
3703
|
+
* Creates and starts new socket connection
|
|
3704
|
+
*
|
|
3705
|
+
* @param socketURL
|
|
3706
|
+
* @private
|
|
3707
|
+
*/
|
|
2630
3708
|
startConnection() {
|
|
2631
3709
|
this._disconnectedByUser = false;
|
|
2632
3710
|
this._messageCount = 0;
|
|
@@ -2660,24 +3738,61 @@
|
|
|
2660
3738
|
if (this._connectionState == ConnectionState.CONNECTED) {
|
|
2661
3739
|
try {
|
|
2662
3740
|
this.socket.close();
|
|
2663
|
-
} catch (error) {
|
|
3741
|
+
} catch (error) {
|
|
3742
|
+
//
|
|
3743
|
+
}
|
|
2664
3744
|
}
|
|
2665
3745
|
};
|
|
2666
3746
|
this._connectionTimeout = setTimeout(() => {
|
|
2667
3747
|
try {
|
|
2668
3748
|
this.socket.close();
|
|
2669
|
-
} catch (error) {
|
|
3749
|
+
} catch (error) {
|
|
3750
|
+
//
|
|
3751
|
+
}
|
|
2670
3752
|
if (this._connectionState == ConnectionState.CONNECTING) {
|
|
2671
3753
|
this._connectionState = ConnectionState.FAILED;
|
|
2672
3754
|
this.onSocketError(new ErrorEvent("connectionTimeout"));
|
|
2673
3755
|
}
|
|
2674
3756
|
}, this.CONNECTION_TIMEOUT * 1000);
|
|
2675
3757
|
}
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
3758
|
+
/**
|
|
3759
|
+
* Method is called once connection with the server is established
|
|
3760
|
+
* @param event
|
|
3761
|
+
*/
|
|
3762
|
+
onSocketOpen(event) {
|
|
3763
|
+
// nothing, for extension only
|
|
3764
|
+
}
|
|
3765
|
+
/**
|
|
3766
|
+
* Method is called once connection with the server is closed (
|
|
3767
|
+
*
|
|
3768
|
+
* @param event
|
|
3769
|
+
*/
|
|
3770
|
+
onSocketClose(event) {
|
|
3771
|
+
// nothing, for extension only
|
|
3772
|
+
}
|
|
3773
|
+
/**
|
|
3774
|
+
* Method is called whenever a new message from socket arrives
|
|
3775
|
+
* @private
|
|
3776
|
+
*/
|
|
3777
|
+
onSocketMessage(event) {
|
|
3778
|
+
// nothing, for extension only
|
|
3779
|
+
}
|
|
3780
|
+
/**
|
|
3781
|
+
* Method is called whenever an error on socket occures
|
|
3782
|
+
*
|
|
3783
|
+
* @param event
|
|
3784
|
+
* @private
|
|
3785
|
+
*/
|
|
3786
|
+
onSocketError(event) {
|
|
3787
|
+
// nothing, for extension only
|
|
3788
|
+
}
|
|
3789
|
+
onError(error) {
|
|
3790
|
+
// nothing, for extension only
|
|
3791
|
+
}
|
|
3792
|
+
/**
|
|
3793
|
+
* Sends data via socket
|
|
3794
|
+
* @param data
|
|
3795
|
+
*/
|
|
2681
3796
|
sendData(data) {
|
|
2682
3797
|
if (this._connectionState == ConnectionState.CONNECTED) {
|
|
2683
3798
|
if (this.socket !== null) {
|
|
@@ -2689,9 +3804,15 @@
|
|
|
2689
3804
|
}
|
|
2690
3805
|
this.onError("socket not connected");
|
|
2691
3806
|
}
|
|
3807
|
+
/**
|
|
3808
|
+
* Returns player state e.g. NOT_INITIALIZED, STARTED, CONNECTED, ENDED
|
|
3809
|
+
*/
|
|
2692
3810
|
getConnectionState() {
|
|
2693
3811
|
return this._connectionState;
|
|
2694
3812
|
}
|
|
3813
|
+
/**
|
|
3814
|
+
* Rozłacza z serwerem
|
|
3815
|
+
*/
|
|
2695
3816
|
disconnect(byUser = true) {
|
|
2696
3817
|
this._isConnected = false;
|
|
2697
3818
|
this._connectionState = ConnectionState.CLOSED;
|
|
@@ -2707,6 +3828,11 @@
|
|
|
2707
3828
|
this.socket.close();
|
|
2708
3829
|
}
|
|
2709
3830
|
}
|
|
3831
|
+
/**
|
|
3832
|
+
* Destroys connection
|
|
3833
|
+
*
|
|
3834
|
+
* @protected
|
|
3835
|
+
*/
|
|
2710
3836
|
destroy() {
|
|
2711
3837
|
if (this.socket !== undefined && this.socket !== null) {
|
|
2712
3838
|
this.socket.onopen = null;
|
|
@@ -2717,6 +3843,10 @@
|
|
|
2717
3843
|
}
|
|
2718
3844
|
this._connectionState = ConnectionState.CLOSED;
|
|
2719
3845
|
}
|
|
3846
|
+
/**
|
|
3847
|
+
* Returns currenly used socketURL
|
|
3848
|
+
* @protected
|
|
3849
|
+
*/
|
|
2720
3850
|
getSocketURL() {
|
|
2721
3851
|
return this.socketURL;
|
|
2722
3852
|
}
|
|
@@ -2790,7 +3920,18 @@
|
|
|
2790
3920
|
}
|
|
2791
3921
|
}
|
|
2792
3922
|
|
|
3923
|
+
/**
|
|
3924
|
+
* Main class for communicating with Storm Streaming Server
|
|
3925
|
+
*/
|
|
2793
3926
|
class WowzaStatusConnection extends AbstractSocket {
|
|
3927
|
+
//------------------------------------------------------------------------//
|
|
3928
|
+
// CONSTRUCTOR
|
|
3929
|
+
//------------------------------------------------------------------------//
|
|
3930
|
+
/**
|
|
3931
|
+
* Constructor
|
|
3932
|
+
* @param main
|
|
3933
|
+
* @constructor
|
|
3934
|
+
*/
|
|
2794
3935
|
constructor(main, server) {
|
|
2795
3936
|
super();
|
|
2796
3937
|
this._logger = main.getLogger();
|
|
@@ -2806,6 +3947,14 @@
|
|
|
2806
3947
|
this.startConnection();
|
|
2807
3948
|
} else this._logger.error(this, "Connection with the server could not be initialized!");
|
|
2808
3949
|
}
|
|
3950
|
+
//------------------------------------------------------------------------//
|
|
3951
|
+
// BASE EVENTS
|
|
3952
|
+
//------------------------------------------------------------------------//
|
|
3953
|
+
/**
|
|
3954
|
+
* On server connection opened;
|
|
3955
|
+
* @param event
|
|
3956
|
+
* @protected
|
|
3957
|
+
*/
|
|
2809
3958
|
onSocketOpen(event) {
|
|
2810
3959
|
this._logger.success(this, `Connection with the server has been established!`);
|
|
2811
3960
|
this._main.dispatchEvent("statusServerConnect", {
|
|
@@ -2815,6 +3964,11 @@
|
|
|
2815
3964
|
});
|
|
2816
3965
|
this._isConnected = true;
|
|
2817
3966
|
}
|
|
3967
|
+
/**
|
|
3968
|
+
* On server connection error
|
|
3969
|
+
* @param event
|
|
3970
|
+
* @protected
|
|
3971
|
+
*/
|
|
2818
3972
|
onSocketError(event) {
|
|
2819
3973
|
this._isConnected = false;
|
|
2820
3974
|
if (!this._disconnectedByUser) {
|
|
@@ -2827,6 +3981,11 @@
|
|
|
2827
3981
|
});
|
|
2828
3982
|
}
|
|
2829
3983
|
}
|
|
3984
|
+
/**
|
|
3985
|
+
* On server connection closed
|
|
3986
|
+
* @param event
|
|
3987
|
+
* @protected
|
|
3988
|
+
*/
|
|
2830
3989
|
onSocketClose(event) {
|
|
2831
3990
|
this._isConnected = false;
|
|
2832
3991
|
if (!this._disconnectedByUser) {
|
|
@@ -2840,6 +3999,10 @@
|
|
|
2840
3999
|
this.initiateReconnect();
|
|
2841
4000
|
} else this._logger.warning(this, `Force disconnect from server!`);
|
|
2842
4001
|
}
|
|
4002
|
+
/**
|
|
4003
|
+
* Method is called whenever a new message from socket arrives
|
|
4004
|
+
* @private
|
|
4005
|
+
*/
|
|
2843
4006
|
onSocketMessage(event) {
|
|
2844
4007
|
if (typeof event.data == "string") {
|
|
2845
4008
|
let msgJSON = JSON.parse(event.data);
|
|
@@ -2864,6 +4027,10 @@
|
|
|
2864
4027
|
}
|
|
2865
4028
|
}
|
|
2866
4029
|
}
|
|
4030
|
+
/**
|
|
4031
|
+
* Initiates reconnection procedure
|
|
4032
|
+
* @private
|
|
4033
|
+
*/
|
|
2867
4034
|
initiateReconnect() {
|
|
2868
4035
|
const shouldReconnect = this._main.getConfigManager().getSettingsData().getIfRestartOnError();
|
|
2869
4036
|
const reconnectTime = this._main.getConfigManager().getSettingsData().getReconnectTime();
|
|
@@ -2884,6 +4051,14 @@
|
|
|
2884
4051
|
}, reconnectTime * 1000);
|
|
2885
4052
|
}
|
|
2886
4053
|
}
|
|
4054
|
+
//------------------------------------------------------------------------//
|
|
4055
|
+
// BASE METHODS
|
|
4056
|
+
//------------------------------------------------------------------------//
|
|
4057
|
+
/**
|
|
4058
|
+
* Creates new URL for WebSockets based on serverItem object
|
|
4059
|
+
* @param serverItem
|
|
4060
|
+
* @private
|
|
4061
|
+
*/
|
|
2887
4062
|
createURL(serverItem) {
|
|
2888
4063
|
let url = "";
|
|
2889
4064
|
url += serverItem.getIfSSL() ? "wss://" : "ws://";
|
|
@@ -2892,12 +4067,18 @@
|
|
|
2892
4067
|
url += "/statuschecker";
|
|
2893
4068
|
return url;
|
|
2894
4069
|
}
|
|
4070
|
+
/**
|
|
4071
|
+
* Returns true/false depending if a connection with a server is active
|
|
4072
|
+
*/
|
|
2895
4073
|
isConnectionActive() {
|
|
2896
4074
|
return this._isConnected;
|
|
2897
4075
|
}
|
|
2898
4076
|
getCurrentServer() {
|
|
2899
4077
|
return this._currServer;
|
|
2900
4078
|
}
|
|
4079
|
+
/**
|
|
4080
|
+
* Destroys object and clean-ups everything that is needed
|
|
4081
|
+
*/
|
|
2901
4082
|
destroy() {
|
|
2902
4083
|
super.destroy();
|
|
2903
4084
|
}
|
|
@@ -2943,16 +4124,51 @@
|
|
|
2943
4124
|
}
|
|
2944
4125
|
}
|
|
2945
4126
|
|
|
4127
|
+
/**
|
|
4128
|
+
* This class (instance) is responsible to controlling video playback. It's the central point of the whole project, where
|
|
4129
|
+
* all components are being managed.
|
|
4130
|
+
*/
|
|
2946
4131
|
class StreamerController {
|
|
4132
|
+
//------------------------------------------------------------------------//
|
|
4133
|
+
// CONSTRUCTOR
|
|
4134
|
+
//------------------------------------------------------------------------//
|
|
4135
|
+
/**
|
|
4136
|
+
* Constructor - requires properly configured config object
|
|
4137
|
+
* @param config
|
|
4138
|
+
*/
|
|
2947
4139
|
constructor(main) {
|
|
2948
4140
|
var _a, _b, _c;
|
|
4141
|
+
/**
|
|
4142
|
+
* Whenever current window is active or not
|
|
4143
|
+
* @private
|
|
4144
|
+
*/
|
|
2949
4145
|
this._isWindowActive = true;
|
|
4146
|
+
/**
|
|
4147
|
+
* Default configuration for ICE-Servers
|
|
4148
|
+
* @private
|
|
4149
|
+
*/
|
|
2950
4150
|
this._peerConnectionConfig = {
|
|
2951
4151
|
'iceServers': []
|
|
2952
4152
|
};
|
|
4153
|
+
/**
|
|
4154
|
+
* Whenever microphone is currenly muted
|
|
4155
|
+
* @private
|
|
4156
|
+
*/
|
|
2953
4157
|
this._isMicrophoneMuted = false;
|
|
4158
|
+
/**
|
|
4159
|
+
* Desired microphone state that should be applied when stream becomes available
|
|
4160
|
+
* @private
|
|
4161
|
+
*/
|
|
2954
4162
|
this._pendingMicrophoneState = null;
|
|
4163
|
+
/**
|
|
4164
|
+
* Whenever we have cheched for permissions
|
|
4165
|
+
* @private
|
|
4166
|
+
*/
|
|
2955
4167
|
this._permissionChecked = false;
|
|
4168
|
+
/**
|
|
4169
|
+
* A default set of permissions
|
|
4170
|
+
* @private
|
|
4171
|
+
*/
|
|
2956
4172
|
this._constraints = {
|
|
2957
4173
|
video: {
|
|
2958
4174
|
width: {
|
|
@@ -2973,17 +4189,45 @@
|
|
|
2973
4189
|
},
|
|
2974
4190
|
audio: true
|
|
2975
4191
|
};
|
|
4192
|
+
/**
|
|
4193
|
+
* Current count for restart, _restartTimerMaxCount is the max number
|
|
4194
|
+
* @private
|
|
4195
|
+
*/
|
|
2976
4196
|
this._restartTimerCount = 0;
|
|
4197
|
+
/**
|
|
4198
|
+
* max
|
|
4199
|
+
* @private
|
|
4200
|
+
*/
|
|
2977
4201
|
this._restartTimerMaxCount = 5;
|
|
4202
|
+
/**
|
|
4203
|
+
* Current streamer state
|
|
4204
|
+
* @protected
|
|
4205
|
+
*/
|
|
2978
4206
|
this._publishState = exports.PublishState.NOT_INITIALIZED;
|
|
2979
4207
|
this._publishTime = 0;
|
|
4208
|
+
/**
|
|
4209
|
+
* General state for streamer
|
|
4210
|
+
* @protected
|
|
4211
|
+
*/
|
|
2980
4212
|
this._inputDeviceState = exports.InputDevicesState.NOT_INITIALIZED;
|
|
4213
|
+
/**
|
|
4214
|
+
* Current Camera state
|
|
4215
|
+
* @protected
|
|
4216
|
+
*/
|
|
2981
4217
|
this._cameraState = exports.DeviceState.NOT_INITIALIZED;
|
|
4218
|
+
/**
|
|
4219
|
+
* Current Microphone state
|
|
4220
|
+
* @protected
|
|
4221
|
+
*/
|
|
2982
4222
|
this._microphoneState = exports.DeviceState.NOT_INITIALIZED;
|
|
2983
4223
|
this._publishTimer = 0;
|
|
2984
4224
|
this._currentOrientation = ((_a = window.screen.orientation) === null || _a === void 0 ? void 0 : _a.type) || '';
|
|
2985
4225
|
this._statusTimer = null;
|
|
2986
4226
|
this._debug = false;
|
|
4227
|
+
/**
|
|
4228
|
+
* Handles device state changes and initiates publishing if appropriate
|
|
4229
|
+
* @private
|
|
4230
|
+
*/
|
|
2987
4231
|
this.onDeviceStateChange = event => {
|
|
2988
4232
|
var _a;
|
|
2989
4233
|
const usedStreamKey = (_a = this._main.getConfigManager()) === null || _a === void 0 ? void 0 : _a.getStreamData().streamKey;
|
|
@@ -2991,15 +4235,21 @@
|
|
|
2991
4235
|
this.publish(usedStreamKey);
|
|
2992
4236
|
}
|
|
2993
4237
|
};
|
|
4238
|
+
/**
|
|
4239
|
+
* This method is responsible for handing orientation changes for mobile devices
|
|
4240
|
+
*/
|
|
2994
4241
|
this.handleOrientationChange = () => __awaiter(this, void 0, void 0, function* () {
|
|
2995
4242
|
var _d, _e;
|
|
4243
|
+
// Dajemy chwilę na ustabilizowanie się orientacji
|
|
2996
4244
|
yield new Promise(resolve => setTimeout(resolve, 500));
|
|
2997
4245
|
const newOrientation = ((_d = window.screen.orientation) === null || _d === void 0 ? void 0 : _d.type) || '';
|
|
2998
4246
|
if (this._currentOrientation !== newOrientation) {
|
|
2999
4247
|
this._logger.info(this, `Orientation changed from ${this._currentOrientation} to ${newOrientation}`);
|
|
3000
4248
|
this._currentOrientation = newOrientation;
|
|
4249
|
+
// Zapamiętaj aktualny stream key i stan publikacji
|
|
3001
4250
|
const streamKey = (_e = this._main.getConfigManager()) === null || _e === void 0 ? void 0 : _e.getStreamData().streamKey;
|
|
3002
4251
|
this._publishState === exports.PublishState.PUBLISHED;
|
|
4252
|
+
// Zamknij istniejące połączenie i stream
|
|
3003
4253
|
this.closeWebRTCConnection();
|
|
3004
4254
|
if (this._stream) {
|
|
3005
4255
|
this._stream.getTracks().forEach(track => {
|
|
@@ -3007,8 +4257,10 @@
|
|
|
3007
4257
|
});
|
|
3008
4258
|
this._stream = null;
|
|
3009
4259
|
}
|
|
4260
|
+
// Rozpocznij wszystko od nowa
|
|
3010
4261
|
try {
|
|
3011
4262
|
yield this.startCamera();
|
|
4263
|
+
// Jeśli stream był opublikowany, publikujemy ponownie
|
|
3012
4264
|
if (streamKey) {
|
|
3013
4265
|
this.publish(streamKey);
|
|
3014
4266
|
}
|
|
@@ -3019,6 +4271,9 @@
|
|
|
3019
4271
|
}
|
|
3020
4272
|
});
|
|
3021
4273
|
this.onServerDisconnect = () => {};
|
|
4274
|
+
/**
|
|
4275
|
+
* Method for handling a situation when a given streamKey is already in use.
|
|
4276
|
+
*/
|
|
3022
4277
|
this.onStreamKeyTaken = () => {
|
|
3023
4278
|
if (this._restartTimer != null) {
|
|
3024
4279
|
clearInterval(this._restartTimer);
|
|
@@ -3053,17 +4308,26 @@
|
|
|
3053
4308
|
}
|
|
3054
4309
|
}, 1000);
|
|
3055
4310
|
};
|
|
4311
|
+
//------------------------------------------------------------------------//
|
|
4312
|
+
// NETWORK AND RTC
|
|
4313
|
+
//------------------------------------------------------------------------//
|
|
4314
|
+
/**
|
|
4315
|
+
* Method fires once a connection with wowza is established. It's the main connection where we exchange
|
|
4316
|
+
* ice-candidates and SDP. We'll start setting up peer connections.
|
|
4317
|
+
*/
|
|
3056
4318
|
this.onServerConnect = () => {
|
|
3057
4319
|
if (this._peerConnection) {
|
|
3058
4320
|
this.closeWebRTCConnection();
|
|
3059
4321
|
}
|
|
3060
4322
|
this._peerConnection = new RTCPeerConnection(this._peerConnectionConfig);
|
|
4323
|
+
// Najpierw dodaj tracki
|
|
3061
4324
|
if (this._stream) {
|
|
3062
4325
|
let localTracks = this._stream.getTracks();
|
|
3063
4326
|
for (let localTrack in localTracks) {
|
|
3064
4327
|
this._peerConnection.addTrack(localTracks[localTrack], this._stream);
|
|
3065
4328
|
}
|
|
3066
4329
|
}
|
|
4330
|
+
// Potem dodaj event handlery
|
|
3067
4331
|
this._peerConnection.onicecandidate = event => {
|
|
3068
4332
|
this.onIceCandidate(event);
|
|
3069
4333
|
};
|
|
@@ -3083,6 +4347,9 @@
|
|
|
3083
4347
|
});
|
|
3084
4348
|
this.createStatusConnection();
|
|
3085
4349
|
};
|
|
4350
|
+
/**
|
|
4351
|
+
* Method fires once a status connection is established. We'll set an interval for monitoring stream status.
|
|
4352
|
+
*/
|
|
3086
4353
|
this.onStatusServerConnect = () => {
|
|
3087
4354
|
const usedStreamKey = this._main.getConfigManager().getStreamData().streamKey;
|
|
3088
4355
|
if (this._statusTimer == null) {
|
|
@@ -3095,13 +4362,20 @@
|
|
|
3095
4362
|
};
|
|
3096
4363
|
this.requestStatusData = () => {
|
|
3097
4364
|
var _a;
|
|
3098
|
-
|
|
3099
|
-
(_a = this._statusConnection) === null || _a === void 0 ? void 0 : _a.sendData('{"packetID":"STREAM_STATUS", "streamKey": "' + usedStreamKey + '"}');
|
|
4365
|
+
(_a = this._statusConnection) === null || _a === void 0 ? void 0 : _a.sendData('{"packetID":"STREAM_STATUS", "streamKey": "' + this._fullStreamName + '"}');
|
|
3100
4366
|
};
|
|
4367
|
+
/**
|
|
4368
|
+
* If for some reason the status connection is disconnected we have to clean the interval
|
|
4369
|
+
*/
|
|
3101
4370
|
this.onStatusServerDisconnect = () => {
|
|
3102
4371
|
if (this._statusTimer != null) clearInterval(this._statusTimer);
|
|
3103
4372
|
this._statusTimer = null;
|
|
3104
4373
|
};
|
|
4374
|
+
/**
|
|
4375
|
+
* This event fires whenever "STREAM_STATUS_RESPONSE" packet form status connection reports stream status along some stream data. This gives
|
|
4376
|
+
* us an insight into whenever our stream is ok (works) or not.
|
|
4377
|
+
* @param event
|
|
4378
|
+
*/
|
|
3105
4379
|
this.onStreamStatsUpdate = event => {
|
|
3106
4380
|
const update = event.streamStatus;
|
|
3107
4381
|
if (this._publishState == exports.PublishState.PUBLISHED && update.publishState != exports.PublishState.PUBLISHED) this.setPublishState(exports.PublishState.UNPUBLISHED);
|
|
@@ -3109,9 +4383,10 @@
|
|
|
3109
4383
|
};
|
|
3110
4384
|
this.onDescriptionSuccess = description => {
|
|
3111
4385
|
var _a, _b, _c;
|
|
4386
|
+
this._fullStreamName = ((_a = this._main.getConfigManager()) === null || _a === void 0 ? void 0 : _a.getStreamData().streamKey) + "_" + new Date().getTime();
|
|
3112
4387
|
const streamInfo = {
|
|
3113
|
-
applicationName: (
|
|
3114
|
-
streamName:
|
|
4388
|
+
applicationName: (_c = (_b = this._main.getNetworkController()) === null || _b === void 0 ? void 0 : _b.getConnection().getCurrentServer()) === null || _c === void 0 ? void 0 : _c.getApplication(),
|
|
4389
|
+
streamName: this._fullStreamName,
|
|
3115
4390
|
sessionId: "[empty]"
|
|
3116
4391
|
};
|
|
3117
4392
|
description.sdp = this._mungeSDP.mungeSDPPublish(description.sdp, {
|
|
@@ -3127,9 +4402,16 @@
|
|
|
3127
4402
|
(_a = this._main.getNetworkController()) === null || _a === void 0 ? void 0 : _a.sendMessage('{"direction":"publish", "command":"sendOffer", "streamInfo":' + JSON.stringify(streamInfo) + ', "sdp":' + JSON.stringify(description) + '}');
|
|
3128
4403
|
}).catch(error => {
|
|
3129
4404
|
console.log(error);
|
|
4405
|
+
//this.onWebRTCError(error, self);
|
|
3130
4406
|
});
|
|
3131
4407
|
}
|
|
3132
4408
|
};
|
|
4409
|
+
//------------------------------------------------------------------------//
|
|
4410
|
+
// BLUR & FOCUS
|
|
4411
|
+
//------------------------------------------------------------------------//
|
|
4412
|
+
/**
|
|
4413
|
+
* Methods handles visibility change events
|
|
4414
|
+
*/
|
|
3133
4415
|
this.visibilityChange = () => {
|
|
3134
4416
|
if (document.visibilityState === 'hidden') {
|
|
3135
4417
|
this.onWindowBlur();
|
|
@@ -3137,12 +4419,18 @@
|
|
|
3137
4419
|
this.onWindowFocus();
|
|
3138
4420
|
}
|
|
3139
4421
|
};
|
|
4422
|
+
/**
|
|
4423
|
+
* Reacts to browser changing visibility of the document (or blur)
|
|
4424
|
+
*/
|
|
3140
4425
|
this.onWindowBlur = () => {
|
|
3141
4426
|
if (this._isWindowActive) {
|
|
3142
4427
|
this._logger.warning(this, "Player window is no longer in focus!");
|
|
3143
4428
|
}
|
|
3144
4429
|
this._isWindowActive = false;
|
|
3145
4430
|
};
|
|
4431
|
+
/**
|
|
4432
|
+
* Reacts to browser changing visibility of the document (or focus)
|
|
4433
|
+
*/
|
|
3146
4434
|
this.onWindowFocus = () => {
|
|
3147
4435
|
if (!this._isWindowActive) {
|
|
3148
4436
|
this._logger.info(this, "Player window is focused again!");
|
|
@@ -3154,8 +4442,18 @@
|
|
|
3154
4442
|
this._mungeSDP = new MungeSDP();
|
|
3155
4443
|
this._soundMeter = new SoundMeter(this._main);
|
|
3156
4444
|
this._debug = (_c = (_b = this._main.getConfigManager()) === null || _b === void 0 ? void 0 : _b.getSettingsData().getDebugData().streamerControllerDebug) !== null && _c !== void 0 ? _c : this._debug;
|
|
4445
|
+
// Start initialization process
|
|
3157
4446
|
this.initialize();
|
|
3158
4447
|
}
|
|
4448
|
+
//------------------------------------------------------------------------//
|
|
4449
|
+
// MAIN METHODS
|
|
4450
|
+
//------------------------------------------------------------------------//
|
|
4451
|
+
/**
|
|
4452
|
+
* Initializes the PlaybackController by setting up event listeners and device handling
|
|
4453
|
+
* This method orchestrates the initialization process by first checking device availability
|
|
4454
|
+
* and permissions, then setting up necessary event listeners and configurations
|
|
4455
|
+
* @private
|
|
4456
|
+
*/
|
|
3159
4457
|
initialize() {
|
|
3160
4458
|
var _a, _b;
|
|
3161
4459
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -3177,6 +4475,10 @@
|
|
|
3177
4475
|
}
|
|
3178
4476
|
});
|
|
3179
4477
|
}
|
|
4478
|
+
/**
|
|
4479
|
+
* Sets up core event listeners for the controller
|
|
4480
|
+
* @private
|
|
4481
|
+
*/
|
|
3180
4482
|
setupEventListeners() {
|
|
3181
4483
|
this._main.addEventListener("serverConnect", this.onServerConnect, false);
|
|
3182
4484
|
this._main.addEventListener("serverDisconnect", this.onServerDisconnect, false);
|
|
@@ -3189,14 +4491,21 @@
|
|
|
3189
4491
|
window.addEventListener("blur", this.onWindowBlur);
|
|
3190
4492
|
window.addEventListener("focus", this.onWindowFocus);
|
|
3191
4493
|
}
|
|
4494
|
+
/**
|
|
4495
|
+
* Initializes media devices by checking permissions and setting up initial device lists
|
|
4496
|
+
* @private
|
|
4497
|
+
*/
|
|
3192
4498
|
initializeDevices() {
|
|
3193
4499
|
return __awaiter(this, void 0, void 0, function* () {
|
|
3194
4500
|
try {
|
|
4501
|
+
// Request initial device permissions
|
|
3195
4502
|
const stream = yield navigator.mediaDevices.getUserMedia({
|
|
3196
4503
|
video: true,
|
|
3197
4504
|
audio: true
|
|
3198
4505
|
});
|
|
4506
|
+
// Stop the test stream
|
|
3199
4507
|
stream.getTracks().forEach(track => track.stop());
|
|
4508
|
+
// Initialize device lists
|
|
3200
4509
|
yield this.grabDevices();
|
|
3201
4510
|
} catch (error) {
|
|
3202
4511
|
this._logger.error(this, "Error initializing devices: " + JSON.stringify(error));
|
|
@@ -3204,6 +4513,10 @@
|
|
|
3204
4513
|
}
|
|
3205
4514
|
});
|
|
3206
4515
|
}
|
|
4516
|
+
/**
|
|
4517
|
+
* Initializes the media stream if a camera or microphone is selected
|
|
4518
|
+
* @private
|
|
4519
|
+
*/
|
|
3207
4520
|
initializeStream() {
|
|
3208
4521
|
if (this._selectedCamera || this._selectedMicrophone) {
|
|
3209
4522
|
this.startCamera();
|
|
@@ -3243,8 +4556,12 @@
|
|
|
3243
4556
|
}
|
|
3244
4557
|
});
|
|
3245
4558
|
}
|
|
4559
|
+
/**
|
|
4560
|
+
* Handles successful camera stream initialization
|
|
4561
|
+
*/
|
|
3246
4562
|
onCameraStreamSuccess(stream) {
|
|
3247
4563
|
this._logger.success(this, "Camera stream successfully retrieved");
|
|
4564
|
+
// Get actual stream dimensions
|
|
3248
4565
|
const videoTrack = stream.getVideoTracks()[0];
|
|
3249
4566
|
const audioTrack = stream.getAudioTracks()[0];
|
|
3250
4567
|
const streamData = new PublishMetadata();
|
|
@@ -3252,6 +4569,7 @@
|
|
|
3252
4569
|
const settings = videoTrack.getSettings();
|
|
3253
4570
|
let width = settings.width;
|
|
3254
4571
|
let height = settings.height;
|
|
4572
|
+
// Na urządzeniach mobilnych potrzebujemy skorygować wymiary
|
|
3255
4573
|
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
3256
4574
|
if (isMobile) {
|
|
3257
4575
|
if (width > height && window.innerWidth < window.innerHeight || width < height && window.innerWidth > window.innerHeight) {
|
|
@@ -3261,10 +4579,12 @@
|
|
|
3261
4579
|
streamData.streamWidth = width;
|
|
3262
4580
|
streamData.streamHeight = height;
|
|
3263
4581
|
streamData.videoTrackPresent = true;
|
|
4582
|
+
// Obliczanie proporcji i konwersja na string
|
|
3264
4583
|
const gcd = (a, b) => b ? gcd(b, a % b) : a;
|
|
3265
4584
|
const divisor = gcd(width, height);
|
|
3266
4585
|
const widthRatio = width / divisor;
|
|
3267
4586
|
const heightRatio = height / divisor;
|
|
4587
|
+
// Sprawdzamy typowe proporcje z pewną tolerancją
|
|
3268
4588
|
const ratio = width / height;
|
|
3269
4589
|
let aspectRatioString = `${widthRatio}:${heightRatio}`;
|
|
3270
4590
|
if (Math.abs(ratio - 16 / 9) < 0.1) {
|
|
@@ -3278,6 +4598,7 @@
|
|
|
3278
4598
|
}
|
|
3279
4599
|
streamData.audioTrackPresent = !!audioTrack;
|
|
3280
4600
|
this._logger.info(this, `Publish MetaData :: Resolution: ${streamData.streamWidth}x${streamData.streamHeight} | ` + `Aspect ratio: ${streamData.aspectRatio}, ` + `Video track: ${streamData.videoTrackPresent} | Audio track: ${streamData.audioTrackPresent}`);
|
|
4601
|
+
// Dispatch event with stream data
|
|
3281
4602
|
this._main.dispatchEvent("publishMetadataUpdate", {
|
|
3282
4603
|
ref: this._main,
|
|
3283
4604
|
metadata: streamData
|
|
@@ -3304,6 +4625,9 @@
|
|
|
3304
4625
|
videoElement.muted = true;
|
|
3305
4626
|
this.setPublishState(exports.PublishState.INITIALIZED);
|
|
3306
4627
|
}
|
|
4628
|
+
/**
|
|
4629
|
+
* Initializes WebRTC connection
|
|
4630
|
+
*/
|
|
3307
4631
|
initializeWebRTC() {
|
|
3308
4632
|
var _a;
|
|
3309
4633
|
if (!this._stream) {
|
|
@@ -3318,6 +4642,12 @@
|
|
|
3318
4642
|
(_a = this._main.getNetworkController()) === null || _a === void 0 ? void 0 : _a.start();
|
|
3319
4643
|
}
|
|
3320
4644
|
}
|
|
4645
|
+
/**
|
|
4646
|
+
* Modified publish method to handle both camera and WebRTC
|
|
4647
|
+
*
|
|
4648
|
+
* @param streamKey - klucz streamu
|
|
4649
|
+
* @returns {boolean} - true jeśli udało się rozpocząć publikowanie
|
|
4650
|
+
*/
|
|
3321
4651
|
publish(streamKey) {
|
|
3322
4652
|
if (this._statusTimer != null) clearInterval(this._statusTimer);
|
|
3323
4653
|
if (this._main.getConfigManager().getStreamData().streamKey == streamKey && this._publishState == exports.PublishState.CONNECTED) {
|
|
@@ -3357,21 +4687,40 @@
|
|
|
3357
4687
|
});
|
|
3358
4688
|
this.closeStream();
|
|
3359
4689
|
}
|
|
4690
|
+
/**
|
|
4691
|
+
* This method
|
|
4692
|
+
* @private
|
|
4693
|
+
*/
|
|
3360
4694
|
setupOrientationListener() {
|
|
4695
|
+
// Sprawdzamy czy urządzenie wspiera event orientationchange
|
|
3361
4696
|
if (window.screen && window.screen.orientation) {
|
|
3362
4697
|
window.screen.orientation.addEventListener('change', this.handleOrientationChange);
|
|
3363
4698
|
} else {
|
|
4699
|
+
// Fallback dla starszych urządzeń
|
|
3364
4700
|
window.addEventListener('orientationchange', this.handleOrientationChange);
|
|
3365
4701
|
}
|
|
3366
4702
|
}
|
|
4703
|
+
//------------------------------------------------------------------------//
|
|
4704
|
+
// USER MEDIA
|
|
4705
|
+
//------------------------------------------------------------------------//
|
|
4706
|
+
/**
|
|
4707
|
+
* Error on trying to grab video stream (it usually means that browser does not support WebRTC streaming)
|
|
4708
|
+
*
|
|
4709
|
+
* @param error
|
|
4710
|
+
*/
|
|
3367
4711
|
onUserMediaError(error) {
|
|
3368
4712
|
return __awaiter(this, void 0, void 0, function* () {
|
|
3369
4713
|
yield this.grabDevices();
|
|
4714
|
+
// Dodatkowa obsługa specyficznych błędów getUserMedia, jeśli potrzebna
|
|
3370
4715
|
if (error.name === "OverconstrainedError") {
|
|
3371
4716
|
this._logger.warning(this, "Device constraints not satisfied");
|
|
3372
4717
|
}
|
|
3373
4718
|
});
|
|
3374
4719
|
}
|
|
4720
|
+
/**
|
|
4721
|
+
* This method is used for checking individual access to output devices
|
|
4722
|
+
* @private
|
|
4723
|
+
*/
|
|
3375
4724
|
checkIndividualDeviceAccess() {
|
|
3376
4725
|
return __awaiter(this, void 0, void 0, function* () {
|
|
3377
4726
|
const results = {
|
|
@@ -3384,27 +4733,35 @@
|
|
|
3384
4733
|
available: false
|
|
3385
4734
|
}
|
|
3386
4735
|
};
|
|
4736
|
+
// Sprawdzamy fizyczną dostępność urządzeń
|
|
3387
4737
|
try {
|
|
3388
4738
|
const devices = yield navigator.mediaDevices.enumerateDevices();
|
|
3389
4739
|
results.camera.available = devices.some(device => device.kind === 'videoinput');
|
|
3390
4740
|
results.microphone.available = devices.some(device => device.kind === 'audioinput');
|
|
4741
|
+
// Sprawdzamy czy mamy etykiety urządzeń - ich brak może oznaczać brak uprawnień
|
|
3391
4742
|
const hasLabels = devices.some(device => device.label !== '');
|
|
3392
4743
|
if (!hasLabels) {
|
|
4744
|
+
// Jeśli nie mamy etykiet, wymuszamy pytanie o uprawnienia
|
|
3393
4745
|
try {
|
|
3394
4746
|
const stream = yield navigator.mediaDevices.getUserMedia({
|
|
3395
4747
|
video: results.camera.available,
|
|
3396
4748
|
audio: results.microphone.available
|
|
3397
4749
|
});
|
|
4750
|
+
// Jeśli udało się uzyskać strumień, mamy uprawnienia
|
|
3398
4751
|
results.camera.allowed = stream.getVideoTracks().length > 0;
|
|
3399
4752
|
results.microphone.allowed = stream.getAudioTracks().length > 0;
|
|
4753
|
+
// Zatrzymujemy strumień testowy
|
|
3400
4754
|
stream.getTracks().forEach(track => track.stop());
|
|
4755
|
+
// Aktualizujemy listę urządzeń po uzyskaniu uprawnień
|
|
3401
4756
|
yield this.grabDevices();
|
|
3402
4757
|
} catch (error) {
|
|
3403
4758
|
console.error('Error requesting permissions:', error);
|
|
4759
|
+
// Nie udało się uzyskać uprawnień
|
|
3404
4760
|
results.camera.allowed = false;
|
|
3405
4761
|
results.microphone.allowed = false;
|
|
3406
4762
|
}
|
|
3407
4763
|
} else {
|
|
4764
|
+
// Jeśli mamy etykiety, prawdopodobnie mamy już uprawnienia
|
|
3408
4765
|
results.camera.allowed = devices.some(device => device.kind === 'videoinput' && device.label !== '');
|
|
3409
4766
|
results.microphone.allowed = devices.some(device => device.kind === 'audioinput' && device.label !== '');
|
|
3410
4767
|
}
|
|
@@ -3418,15 +4775,25 @@
|
|
|
3418
4775
|
return results;
|
|
3419
4776
|
});
|
|
3420
4777
|
}
|
|
4778
|
+
//------------------------------------------------------------------------//
|
|
4779
|
+
// SOCKETS & SDP
|
|
4780
|
+
//------------------------------------------------------------------------//
|
|
4781
|
+
/**
|
|
4782
|
+
* This method handles basic SDP/ICE-Candidate exchange with a Wowza Server
|
|
4783
|
+
*
|
|
4784
|
+
* @param data
|
|
4785
|
+
*/
|
|
3421
4786
|
onSocketMessage(data) {
|
|
3422
4787
|
var _a;
|
|
3423
4788
|
let msgJSON = JSON.parse(data);
|
|
3424
4789
|
let msgStatus = Number(msgJSON["status"]);
|
|
3425
4790
|
switch (msgStatus) {
|
|
3426
4791
|
case 200:
|
|
4792
|
+
// OK
|
|
3427
4793
|
this._logger.info(this, "SDP Exchange Successful");
|
|
3428
4794
|
let sdpData = msgJSON['sdp'];
|
|
3429
4795
|
if (sdpData !== undefined) {
|
|
4796
|
+
// @ts-ignore
|
|
3430
4797
|
this._peerConnection.setRemoteDescription(new RTCSessionDescription(sdpData), () => {}, () => {});
|
|
3431
4798
|
}
|
|
3432
4799
|
let iceCandidates = msgJSON['iceCandidates'];
|
|
@@ -3437,6 +4804,7 @@
|
|
|
3437
4804
|
}
|
|
3438
4805
|
break;
|
|
3439
4806
|
case 503:
|
|
4807
|
+
// NOT OK
|
|
3440
4808
|
this._logger.error(this, "StreamKey already use");
|
|
3441
4809
|
const usedStreamKey = (_a = this._main.getConfigManager().getStreamData().streamKey) !== null && _a !== void 0 ? _a : "unknown";
|
|
3442
4810
|
this._main.dispatchEvent("streamKeyInUse", {
|
|
@@ -3447,6 +4815,16 @@
|
|
|
3447
4815
|
break;
|
|
3448
4816
|
}
|
|
3449
4817
|
}
|
|
4818
|
+
//------------------------------------------------------------------------//
|
|
4819
|
+
// EVENTS
|
|
4820
|
+
//------------------------------------------------------------------------//
|
|
4821
|
+
/**
|
|
4822
|
+
* Recives events related to peerConnection (change of state)
|
|
4823
|
+
*
|
|
4824
|
+
* @param event event with its data
|
|
4825
|
+
* @param thisRef reference to player classonConnectionStateChange
|
|
4826
|
+
* @private
|
|
4827
|
+
*/
|
|
3450
4828
|
onConnectionStateChange(event) {
|
|
3451
4829
|
this._logger.info(this, "Connection State Change: " + JSON.stringify(event));
|
|
3452
4830
|
if (event !== null) {
|
|
@@ -3474,12 +4852,20 @@
|
|
|
3474
4852
|
}
|
|
3475
4853
|
}
|
|
3476
4854
|
}
|
|
4855
|
+
//------------------------------------------------------------------------//
|
|
4856
|
+
// DEVICES
|
|
4857
|
+
//------------------------------------------------------------------------//
|
|
4858
|
+
/**
|
|
4859
|
+
* Returns list od devices (cameras, microphones) available for user's device
|
|
4860
|
+
*/
|
|
3477
4861
|
grabDevices() {
|
|
3478
4862
|
return __awaiter(this, void 0, void 0, function* () {
|
|
3479
4863
|
try {
|
|
3480
4864
|
const deviceAccess = yield this.checkIndividualDeviceAccess();
|
|
3481
4865
|
this._cameraList = new InputDeviceList();
|
|
3482
4866
|
this._microphoneList = new InputDeviceList();
|
|
4867
|
+
// Wysyłamy eventy tylko jeśli nie sprawdzaliśmy wcześniej uprawnień
|
|
4868
|
+
// lub jeśli zmienił się stan uprawnień (resetowana flaga)
|
|
3483
4869
|
if (!this._permissionChecked) {
|
|
3484
4870
|
if (!deviceAccess.camera.allowed) {
|
|
3485
4871
|
this._main.dispatchEvent("cameraAccessDenied", {
|
|
@@ -3508,6 +4894,7 @@
|
|
|
3508
4894
|
this.setInputDeviceState(exports.InputDevicesState.INVALID);
|
|
3509
4895
|
}
|
|
3510
4896
|
}
|
|
4897
|
+
// Wypełnianie list dostępnymi urządzeniami
|
|
3511
4898
|
const devices = yield navigator.mediaDevices.enumerateDevices();
|
|
3512
4899
|
for (const device of devices) {
|
|
3513
4900
|
if (device.deviceId && device.label) {
|
|
@@ -3521,6 +4908,7 @@
|
|
|
3521
4908
|
}
|
|
3522
4909
|
}
|
|
3523
4910
|
try {
|
|
4911
|
+
// Aktualizacja wybranych urządzeń
|
|
3524
4912
|
if (deviceAccess.camera.allowed) {
|
|
3525
4913
|
this._selectedCamera = this.pickCamera();
|
|
3526
4914
|
}
|
|
@@ -3531,6 +4919,7 @@
|
|
|
3531
4919
|
this.setInputDeviceState(exports.InputDevicesState.INVALID);
|
|
3532
4920
|
this._logger.error(this, "Errror on grab devices: " + JSON.stringify(error));
|
|
3533
4921
|
}
|
|
4922
|
+
// Zawsze wysyłamy aktualizację list urządzeń
|
|
3534
4923
|
this._main.dispatchEvent("deviceListUpdate", {
|
|
3535
4924
|
ref: this._main,
|
|
3536
4925
|
cameraList: this._cameraList.getArray(),
|
|
@@ -3552,6 +4941,10 @@
|
|
|
3552
4941
|
}
|
|
3553
4942
|
});
|
|
3554
4943
|
}
|
|
4944
|
+
/**
|
|
4945
|
+
* Selects camera based on camera device ID;
|
|
4946
|
+
* @param cameraID
|
|
4947
|
+
*/
|
|
3555
4948
|
selectCamera(cameraID) {
|
|
3556
4949
|
var _a, _b;
|
|
3557
4950
|
for (let i = 0; i < this._cameraList.getSize(); i++) {
|
|
@@ -3560,6 +4953,7 @@
|
|
|
3560
4953
|
this._selectedCamera = null;
|
|
3561
4954
|
this.setInputDeviceState(exports.InputDevicesState.UPDATING);
|
|
3562
4955
|
this.setCameraState(exports.DeviceState.NOT_INITIALIZED);
|
|
4956
|
+
// Zapamiętaj aktualny stream key i stan publikacji
|
|
3563
4957
|
const streamKey = (_a = this._main.getConfigManager()) === null || _a === void 0 ? void 0 : _a.getStreamData().streamKey;
|
|
3564
4958
|
const wasPublished = this._publishState === exports.PublishState.CONNECTED;
|
|
3565
4959
|
for (let i = 0; i < this._cameraList.getSize(); i++) {
|
|
@@ -3577,8 +4971,11 @@
|
|
|
3577
4971
|
});
|
|
3578
4972
|
this.stopCameraStream();
|
|
3579
4973
|
if (this._selectedCamera != null) {
|
|
4974
|
+
// Update constraints with new device
|
|
3580
4975
|
this._constraints.video.deviceId = this._selectedCamera.id;
|
|
4976
|
+
// Restart camera stream
|
|
3581
4977
|
this.startCamera().then(() => {
|
|
4978
|
+
// Jeśli stream był opublikowany, publikujemy ponownie
|
|
3582
4979
|
this.setCameraState(exports.DeviceState.ENABLED);
|
|
3583
4980
|
if (this._cameraState == exports.DeviceState.ENABLED && this._microphoneState == exports.DeviceState.ENABLED) this.setInputDeviceState(exports.InputDevicesState.READY);else this.setInputDeviceState(exports.InputDevicesState.INVALID);
|
|
3584
4981
|
if (wasPublished && streamKey) {
|
|
@@ -3589,6 +4986,10 @@
|
|
|
3589
4986
|
this.setInputDeviceState(exports.InputDevicesState.INVALID);
|
|
3590
4987
|
}
|
|
3591
4988
|
}
|
|
4989
|
+
/**
|
|
4990
|
+
* Method tries to select (change) microphone based on its system ID
|
|
4991
|
+
* @param micID
|
|
4992
|
+
*/
|
|
3592
4993
|
selectMicrophone(micID) {
|
|
3593
4994
|
var _a, _b;
|
|
3594
4995
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -3599,8 +5000,10 @@
|
|
|
3599
5000
|
this.setInputDeviceState(exports.InputDevicesState.UPDATING);
|
|
3600
5001
|
this.setMicrophoneState(exports.DeviceState.NOT_INITIALIZED);
|
|
3601
5002
|
this._logger.info(this, "Selecting microphone: " + micID);
|
|
5003
|
+
// Zapamiętaj aktualny stream key i stan publikacji
|
|
3602
5004
|
const streamKey = (_a = this._main.getConfigManager()) === null || _a === void 0 ? void 0 : _a.getStreamData().streamKey;
|
|
3603
5005
|
const wasPublished = this._publishState === exports.PublishState.CONNECTED;
|
|
5006
|
+
// Znajdź i zapisz wybrany mikrofon
|
|
3604
5007
|
for (let i = 0; i < this._microphoneList.getSize(); i++) {
|
|
3605
5008
|
if (this._microphoneList.get(i).id == micID) {
|
|
3606
5009
|
this._selectedMicrophone = this._microphoneList.get(i);
|
|
@@ -3609,13 +5012,17 @@
|
|
|
3609
5012
|
break;
|
|
3610
5013
|
}
|
|
3611
5014
|
}
|
|
5015
|
+
// Zawsze wysyłamy aktualizację list urządzeń
|
|
3612
5016
|
this._main.dispatchEvent("deviceListUpdate", {
|
|
3613
5017
|
ref: this._main,
|
|
3614
5018
|
cameraList: this._cameraList.getArray(),
|
|
3615
5019
|
microphoneList: this._microphoneList.getArray()
|
|
3616
5020
|
});
|
|
5021
|
+
// Odłącz SoundMeter przed zmianą strumienia
|
|
3617
5022
|
this._soundMeter.detach();
|
|
5023
|
+
// Zamknij istniejące połączenie WebRTC
|
|
3618
5024
|
this.closeWebRTCConnection();
|
|
5025
|
+
// Zatrzymaj obecny strumień
|
|
3619
5026
|
if (this._stream) {
|
|
3620
5027
|
this._stream.getTracks().forEach(track => {
|
|
3621
5028
|
track.stop();
|
|
@@ -3623,6 +5030,7 @@
|
|
|
3623
5030
|
this._stream = null;
|
|
3624
5031
|
}
|
|
3625
5032
|
try {
|
|
5033
|
+
// Rozpocznij wszystko od nowa
|
|
3626
5034
|
yield this.startCamera();
|
|
3627
5035
|
this.setMicrophoneState(exports.DeviceState.ENABLED);
|
|
3628
5036
|
if (this._cameraState == exports.DeviceState.ENABLED && this._microphoneState == exports.DeviceState.ENABLED) {
|
|
@@ -3630,6 +5038,7 @@
|
|
|
3630
5038
|
} else {
|
|
3631
5039
|
this.setInputDeviceState(exports.InputDevicesState.INVALID);
|
|
3632
5040
|
}
|
|
5041
|
+
// Jeśli stream był opublikowany, publikujemy ponownie
|
|
3633
5042
|
if (wasPublished && streamKey) {
|
|
3634
5043
|
this.publish(streamKey);
|
|
3635
5044
|
}
|
|
@@ -3642,6 +5051,11 @@
|
|
|
3642
5051
|
}
|
|
3643
5052
|
});
|
|
3644
5053
|
}
|
|
5054
|
+
/**
|
|
5055
|
+
* This method tries to start a camera.
|
|
5056
|
+
*
|
|
5057
|
+
* @private
|
|
5058
|
+
*/
|
|
3645
5059
|
startCamera() {
|
|
3646
5060
|
return __awaiter(this, void 0, void 0, function* () {
|
|
3647
5061
|
if (this._stream) {
|
|
@@ -3690,24 +5104,37 @@
|
|
|
3690
5104
|
}
|
|
3691
5105
|
});
|
|
3692
5106
|
}
|
|
5107
|
+
/**
|
|
5108
|
+
* Updates WebRTC connection with new stream
|
|
5109
|
+
*/
|
|
3693
5110
|
updateWebRTCStream() {
|
|
3694
5111
|
if (!this._peerConnection || !this._stream) {
|
|
3695
5112
|
return;
|
|
3696
5113
|
}
|
|
5114
|
+
// Remove all existing tracks from the peer connection
|
|
3697
5115
|
const senders = this._peerConnection.getSenders();
|
|
3698
5116
|
senders.forEach(sender => {
|
|
3699
5117
|
if (this._peerConnection) this._peerConnection.removeTrack(sender);
|
|
3700
5118
|
});
|
|
5119
|
+
// Add new tracks
|
|
3701
5120
|
this._stream.getTracks().forEach(track => {
|
|
3702
5121
|
if (this._stream != null && this._peerConnection) {
|
|
3703
5122
|
this._peerConnection.addTrack(track, this._stream);
|
|
3704
5123
|
}
|
|
3705
5124
|
});
|
|
3706
5125
|
}
|
|
5126
|
+
/**
|
|
5127
|
+
* Modified closeStream to handle both camera and WebRTC completely
|
|
5128
|
+
*/
|
|
3707
5129
|
closeStream() {
|
|
3708
5130
|
if (this._peerConnection !== undefined && this._peerConnection !== null) this._peerConnection.close();
|
|
3709
5131
|
this.setPublishState(exports.PublishState.UNPUBLISHED);
|
|
3710
5132
|
}
|
|
5133
|
+
/**
|
|
5134
|
+
* This method selects a camera based on previous uses or saved IDs
|
|
5135
|
+
*
|
|
5136
|
+
* @private
|
|
5137
|
+
*/
|
|
3711
5138
|
pickCamera() {
|
|
3712
5139
|
var _a, _b, _c, _d, _e, _f;
|
|
3713
5140
|
for (let i = 0; i < this._cameraList.getSize(); i++) {
|
|
@@ -3716,12 +5143,14 @@
|
|
|
3716
5143
|
let savedCameraID = (_b = (_a = this._main.getStorageManager()) === null || _a === void 0 ? void 0 : _a.getField("cameraID")) !== null && _b !== void 0 ? _b : null;
|
|
3717
5144
|
if (this._cameraList.getSize() > 0) {
|
|
3718
5145
|
if (savedCameraID) {
|
|
5146
|
+
// Szukamy zapisanej kamery
|
|
3719
5147
|
let found = false;
|
|
3720
5148
|
for (let i = 0; i < this._cameraList.getSize(); i++) {
|
|
3721
5149
|
if (this._cameraList.get(i).id === savedCameraID) {
|
|
3722
5150
|
this._selectedCamera = this._cameraList.get(i);
|
|
3723
5151
|
this._selectedCamera.isSelected = true;
|
|
3724
5152
|
this.setCameraState(exports.DeviceState.ENABLED);
|
|
5153
|
+
// Ustaw deviceId w constraints
|
|
3725
5154
|
found = true;
|
|
3726
5155
|
this._constraints.video.deviceId = this._selectedCamera.id;
|
|
3727
5156
|
break;
|
|
@@ -3741,6 +5170,7 @@
|
|
|
3741
5170
|
return null;
|
|
3742
5171
|
}
|
|
3743
5172
|
}
|
|
5173
|
+
// Jeśli nie znaleziono zapisanej kamery, używamy pierwszej
|
|
3744
5174
|
if (!this._selectedCamera) {
|
|
3745
5175
|
this._main.dispatchEvent("savedCameraNotFound", {
|
|
3746
5176
|
ref: this._main,
|
|
@@ -3770,6 +5200,11 @@
|
|
|
3770
5200
|
});
|
|
3771
5201
|
return this._selectedCamera;
|
|
3772
5202
|
}
|
|
5203
|
+
/**
|
|
5204
|
+
* This method selects a microphone based on previous uses or saved IDs
|
|
5205
|
+
*
|
|
5206
|
+
* @private
|
|
5207
|
+
*/
|
|
3773
5208
|
pickMicrophone() {
|
|
3774
5209
|
var _a, _b, _c, _d, _e, _f;
|
|
3775
5210
|
for (let i = 0; i < this._microphoneList.getSize(); i++) {
|
|
@@ -3827,32 +5262,51 @@
|
|
|
3827
5262
|
}
|
|
3828
5263
|
return this._selectedMicrophone;
|
|
3829
5264
|
}
|
|
5265
|
+
/**
|
|
5266
|
+
* Cleans all saved cameras and microphones IDs.
|
|
5267
|
+
*/
|
|
3830
5268
|
clearSavedDevices() {
|
|
3831
5269
|
var _a, _b;
|
|
3832
5270
|
(_a = this._main.getStorageManager()) === null || _a === void 0 ? void 0 : _a.removeField("cameraID");
|
|
3833
5271
|
(_b = this._main.getStorageManager()) === null || _b === void 0 ? void 0 : _b.removeField("microphoneID");
|
|
3834
5272
|
}
|
|
5273
|
+
/**
|
|
5274
|
+
* Messes up camera's and microphone's id (for testing only)
|
|
5275
|
+
*/
|
|
3835
5276
|
messSavedDevices() {
|
|
3836
5277
|
var _a, _b;
|
|
3837
5278
|
(_a = this._main.getStorageManager()) === null || _a === void 0 ? void 0 : _a.saveField("cameraID", "a");
|
|
3838
5279
|
(_b = this._main.getStorageManager()) === null || _b === void 0 ? void 0 : _b.saveField("microphoneID", "b");
|
|
3839
5280
|
}
|
|
5281
|
+
/**
|
|
5282
|
+
* Handles microphone muting state
|
|
5283
|
+
* @param microphoneState true to unmute, false to mute
|
|
5284
|
+
*/
|
|
3840
5285
|
muteMicrophone(shouldMute) {
|
|
3841
5286
|
if (this._isMicrophoneMuted === shouldMute) {
|
|
5287
|
+
// State hasn't changed, no need to do anything
|
|
3842
5288
|
return;
|
|
3843
5289
|
}
|
|
3844
5290
|
this._isMicrophoneMuted = shouldMute;
|
|
3845
5291
|
if (this._stream) {
|
|
3846
|
-
this.applyMicrophoneState(!shouldMute);
|
|
5292
|
+
this.applyMicrophoneState(!shouldMute); // Odwracamy wartość dla track.enabled
|
|
3847
5293
|
} else {
|
|
3848
|
-
|
|
5294
|
+
// Store the desired state to be applied when stream becomes available
|
|
5295
|
+
this._pendingMicrophoneState = !shouldMute; // Odwracamy wartość dla przyszłego track.enabled
|
|
3849
5296
|
this._logger.info(this, `WebRTCStreamer :: Stream not yet available, storing microphone state (muted: ${shouldMute})`);
|
|
3850
5297
|
}
|
|
5298
|
+
// Always dispatch the event to keep UI in sync
|
|
3851
5299
|
this._main.dispatchEvent("microphoneStateChange", {
|
|
3852
5300
|
ref: this._main,
|
|
3853
5301
|
isMuted: this._isMicrophoneMuted
|
|
3854
5302
|
});
|
|
3855
5303
|
}
|
|
5304
|
+
/**
|
|
5305
|
+
* Applies the microphone state to the actual stream tracks
|
|
5306
|
+
*
|
|
5307
|
+
* @param enabled true to enable tracks, false to disable
|
|
5308
|
+
* @private
|
|
5309
|
+
*/
|
|
3856
5310
|
applyMicrophoneState(enabled) {
|
|
3857
5311
|
if (!this._stream) {
|
|
3858
5312
|
this._logger.warning(this, "WebRTCStreamer :: Cannot apply microphone state - stream not available");
|
|
@@ -3866,6 +5320,13 @@
|
|
|
3866
5320
|
this._logger.warning(this, "WebRTCStreamer :: No audio tracks found in stream");
|
|
3867
5321
|
}
|
|
3868
5322
|
}
|
|
5323
|
+
/**
|
|
5324
|
+
* This methods is a final check whenever we're ready to publish a stream
|
|
5325
|
+
*
|
|
5326
|
+
* @param requireVideo - whenever video track is required
|
|
5327
|
+
* @param requireAudio - whenever audio track is required
|
|
5328
|
+
* @returns {boolean} true if stream is ready for publishing
|
|
5329
|
+
*/
|
|
3869
5330
|
isStreamReady(requireVideo = true, requireAudio = true) {
|
|
3870
5331
|
if (!this._stream) {
|
|
3871
5332
|
return false;
|
|
@@ -3888,6 +5349,9 @@
|
|
|
3888
5349
|
onIceCandidate(event) {
|
|
3889
5350
|
if (event.candidate !== null) ;
|
|
3890
5351
|
}
|
|
5352
|
+
//------------------------------------------------------------------------//
|
|
5353
|
+
// SETS & GETS
|
|
5354
|
+
//------------------------------------------------------------------------//
|
|
3891
5355
|
createStatusConnection() {
|
|
3892
5356
|
var _a, _b, _c;
|
|
3893
5357
|
const serverItem = (_c = (_b = (_a = this._main) === null || _a === void 0 ? void 0 : _a.getNetworkController()) === null || _b === void 0 ? void 0 : _b.getConnection()) === null || _c === void 0 ? void 0 : _c.getCurrentServer();
|
|
@@ -3922,6 +5386,7 @@
|
|
|
3922
5386
|
getPublishTime() {
|
|
3923
5387
|
return this._publishState == exports.PublishState.PUBLISHED ? this._publishTime : 0;
|
|
3924
5388
|
}
|
|
5389
|
+
// DEVICE STATE
|
|
3925
5390
|
setInputDeviceState(newState) {
|
|
3926
5391
|
if (this._inputDeviceState == newState) return;
|
|
3927
5392
|
this._inputDeviceState = newState;
|
|
@@ -3935,6 +5400,7 @@
|
|
|
3935
5400
|
getInputDeviceState() {
|
|
3936
5401
|
return this._inputDeviceState;
|
|
3937
5402
|
}
|
|
5403
|
+
// CAMERA STATE
|
|
3938
5404
|
setCameraState(newState) {
|
|
3939
5405
|
if (this._cameraState == newState) return;
|
|
3940
5406
|
this._cameraState = newState;
|
|
@@ -3944,9 +5410,10 @@
|
|
|
3944
5410
|
selectedCamera: this._selectedCamera
|
|
3945
5411
|
});
|
|
3946
5412
|
}
|
|
3947
|
-
|
|
5413
|
+
getCameraState() {
|
|
3948
5414
|
return this._cameraState;
|
|
3949
5415
|
}
|
|
5416
|
+
// MICROPHONE STATE
|
|
3950
5417
|
setMicrophoneState(newState) {
|
|
3951
5418
|
if (this._microphoneState == newState) return;
|
|
3952
5419
|
this._microphoneState = newState;
|
|
@@ -3968,6 +5435,13 @@
|
|
|
3968
5435
|
getPublishState() {
|
|
3969
5436
|
return this._publishState;
|
|
3970
5437
|
}
|
|
5438
|
+
//------------------------------------------------------------------------//
|
|
5439
|
+
// DESTROY & DELETE
|
|
5440
|
+
//------------------------------------------------------------------------//
|
|
5441
|
+
/**
|
|
5442
|
+
* Method used to stop camera from streaming
|
|
5443
|
+
* @private
|
|
5444
|
+
*/
|
|
3971
5445
|
stopCameraStream() {
|
|
3972
5446
|
var _a, _b;
|
|
3973
5447
|
if (this._stream) {
|
|
@@ -3980,66 +5454,112 @@
|
|
|
3980
5454
|
this._stream = null;
|
|
3981
5455
|
}
|
|
3982
5456
|
}
|
|
5457
|
+
/**
|
|
5458
|
+
* Method stops streaming for all streams
|
|
5459
|
+
* @private
|
|
5460
|
+
*/
|
|
3983
5461
|
forceStopAllStreams() {
|
|
3984
5462
|
var _a, _b;
|
|
3985
|
-
|
|
5463
|
+
// 1. First, detach the sound meter
|
|
5464
|
+
if (this._soundMeter) {
|
|
5465
|
+
this._soundMeter.detach();
|
|
5466
|
+
}
|
|
5467
|
+
// 2. Stop the main stream if it exists
|
|
5468
|
+
if (this._stream) {
|
|
3986
5469
|
try {
|
|
3987
|
-
const
|
|
3988
|
-
|
|
3989
|
-
|
|
5470
|
+
const tracks = this._stream.getTracks();
|
|
5471
|
+
this._logger.info(this, `Stopping ${tracks.length} tracks from main stream`);
|
|
5472
|
+
tracks.forEach(track => {
|
|
3990
5473
|
try {
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
(_a = this._peerConnection) === null || _a === void 0 ? void 0 : _a.removeTrack(sender);
|
|
3995
|
-
}
|
|
5474
|
+
track.enabled = false;
|
|
5475
|
+
track.stop();
|
|
5476
|
+
this._logger.info(this, `Stopped ${track.kind} track: ${track.id}`);
|
|
3996
5477
|
} catch (e) {
|
|
3997
|
-
|
|
5478
|
+
this._logger.error(this, `Error stopping ${track.kind} track: ${e}`);
|
|
3998
5479
|
}
|
|
3999
5480
|
});
|
|
4000
|
-
this.
|
|
4001
|
-
this._peerConnection = null;
|
|
5481
|
+
this._stream = null;
|
|
4002
5482
|
} catch (e) {
|
|
4003
|
-
|
|
5483
|
+
this._logger.error(this, 'Error stopping main stream');
|
|
4004
5484
|
}
|
|
4005
5485
|
}
|
|
5486
|
+
// 3. Clean up video element
|
|
4006
5487
|
try {
|
|
4007
5488
|
const videoElement = (_b = (_a = this._main.getStageController()) === null || _a === void 0 ? void 0 : _a.getScreenElement()) === null || _b === void 0 ? void 0 : _b.getVideoElement();
|
|
4008
5489
|
if (videoElement && videoElement.srcObject instanceof MediaStream) {
|
|
4009
5490
|
const videoTracks = videoElement.srcObject.getTracks();
|
|
4010
|
-
videoTracks.
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
5491
|
+
if (videoTracks.length > 0) {
|
|
5492
|
+
this._logger.info(this, `Stopping ${videoTracks.length} tracks from video element`);
|
|
5493
|
+
videoTracks.forEach(track => {
|
|
5494
|
+
try {
|
|
5495
|
+
track.enabled = false;
|
|
5496
|
+
track.stop();
|
|
5497
|
+
} catch (e) {
|
|
5498
|
+
this._logger.error(this, `Error stopping video element track: ${e}`);
|
|
5499
|
+
}
|
|
5500
|
+
});
|
|
5501
|
+
}
|
|
4018
5502
|
videoElement.srcObject = null;
|
|
4019
5503
|
videoElement.removeAttribute('src');
|
|
4020
5504
|
videoElement.load();
|
|
4021
5505
|
}
|
|
4022
5506
|
} catch (e) {
|
|
4023
|
-
|
|
5507
|
+
this._logger.error(this, 'Error cleaning video element');
|
|
4024
5508
|
}
|
|
4025
|
-
|
|
5509
|
+
// 4. Handle RTCPeerConnection last, with proper state checking
|
|
5510
|
+
if (this._peerConnection) {
|
|
4026
5511
|
try {
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
5512
|
+
// Only try to remove tracks if the connection isn't already closed
|
|
5513
|
+
if (this._peerConnection.signalingState !== 'closed') {
|
|
5514
|
+
const senders = this._peerConnection.getSenders();
|
|
5515
|
+
this._logger.info(this, `Cleaning up ${senders.length} senders from peer connection`);
|
|
5516
|
+
senders.forEach(sender => {
|
|
5517
|
+
try {
|
|
5518
|
+
if (sender.track) {
|
|
5519
|
+
sender.track.enabled = false;
|
|
5520
|
+
sender.track.stop();
|
|
5521
|
+
// Only try to remove the track if connection is still open
|
|
5522
|
+
if (this._peerConnection && this._peerConnection.signalingState !== 'closed') {
|
|
5523
|
+
this._peerConnection.removeTrack(sender);
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5526
|
+
} catch (e) {
|
|
5527
|
+
this._logger.error(this, `Error stopping sender track: ${e}`);
|
|
5528
|
+
}
|
|
5529
|
+
});
|
|
5530
|
+
}
|
|
5531
|
+
// Now close the peer connection
|
|
5532
|
+
this._peerConnection.close();
|
|
5533
|
+
this._peerConnection = null;
|
|
4037
5534
|
} catch (e) {
|
|
4038
|
-
|
|
5535
|
+
this._logger.error(this, 'Error closing peer connection');
|
|
4039
5536
|
}
|
|
4040
5537
|
}
|
|
5538
|
+
// 5. Ensure we properly null out our device references
|
|
5539
|
+
this._selectedCamera = null;
|
|
5540
|
+
this._selectedMicrophone = null;
|
|
5541
|
+
// 6. Make a final check for any active tracks at the global level
|
|
5542
|
+
try {
|
|
5543
|
+
const allTracks = [];
|
|
5544
|
+
// Try to find any tracks that might still be active by querying devices
|
|
5545
|
+
navigator.mediaDevices.getUserMedia({
|
|
5546
|
+
audio: false,
|
|
5547
|
+
video: false
|
|
5548
|
+
}).then(() => {
|
|
5549
|
+
// This is just to trigger a device check
|
|
5550
|
+
this._logger.info(this, "Performed final device check");
|
|
5551
|
+
}).catch(() => {
|
|
5552
|
+
// Ignore errors from this check
|
|
5553
|
+
});
|
|
5554
|
+
} catch (e) {
|
|
5555
|
+
// Ignore errors from final check
|
|
5556
|
+
}
|
|
4041
5557
|
}
|
|
5558
|
+
/**
|
|
5559
|
+
* Stops all streaming operations and cleans up resources
|
|
5560
|
+
*/
|
|
4042
5561
|
stop() {
|
|
5562
|
+
// Stop status connection and clear timer
|
|
4043
5563
|
if (this._statusConnection) {
|
|
4044
5564
|
this._statusConnection.destroy();
|
|
4045
5565
|
this._statusConnection = null;
|
|
@@ -4049,12 +5569,16 @@
|
|
|
4049
5569
|
this._statusTimer = null;
|
|
4050
5570
|
}
|
|
4051
5571
|
this._main.getConfigManager().getStreamData().streamKey = null;
|
|
5572
|
+
// Close WebRTC connection
|
|
4052
5573
|
this.closeWebRTCConnection();
|
|
5574
|
+
// Stop all media streams
|
|
4053
5575
|
this.stopCameraStream();
|
|
5576
|
+
// Reset states
|
|
4054
5577
|
this.setPublishState(exports.PublishState.STOPPED);
|
|
4055
5578
|
this.setInputDeviceState(exports.InputDevicesState.STOPPED);
|
|
4056
5579
|
this.setCameraState(exports.DeviceState.STOPPED);
|
|
4057
5580
|
this.setMicrophoneState(exports.DeviceState.STOPPED);
|
|
5581
|
+
// Clear restart timer if exists
|
|
4058
5582
|
if (this._restartTimer) {
|
|
4059
5583
|
clearInterval(this._restartTimer);
|
|
4060
5584
|
this._restartTimer = null;
|
|
@@ -4062,19 +5586,26 @@
|
|
|
4062
5586
|
this._restartTimerCount = 0;
|
|
4063
5587
|
clearTimeout(this._publishTimer);
|
|
4064
5588
|
}
|
|
5589
|
+
/**
|
|
5590
|
+
* Reinitializes the streaming setup
|
|
5591
|
+
*/
|
|
4065
5592
|
start() {
|
|
4066
5593
|
var _a, _b, _c;
|
|
4067
5594
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4068
5595
|
try {
|
|
5596
|
+
// Reset states
|
|
4069
5597
|
this._publishState = exports.PublishState.NOT_INITIALIZED;
|
|
4070
5598
|
this._inputDeviceState = exports.InputDevicesState.NOT_INITIALIZED;
|
|
4071
5599
|
this._cameraState = exports.DeviceState.NOT_INITIALIZED;
|
|
4072
5600
|
this._microphoneState = exports.DeviceState.NOT_INITIALIZED;
|
|
5601
|
+
// Reinitialize devices and stream
|
|
4073
5602
|
yield this.initializeDevices();
|
|
4074
5603
|
yield this.startCamera();
|
|
5604
|
+
// If autoConnect is enabled, initialize network
|
|
4075
5605
|
if ((_a = this._main.getConfigManager()) === null || _a === void 0 ? void 0 : _a.getSettingsData().autoConnect) {
|
|
4076
5606
|
(_b = this._main.getNetworkController()) === null || _b === void 0 ? void 0 : _b.initialize();
|
|
4077
5607
|
}
|
|
5608
|
+
// Reinitialize status connection if needed
|
|
4078
5609
|
if ((_c = this._main.getConfigManager()) === null || _c === void 0 ? void 0 : _c.getStreamData().streamKey) {
|
|
4079
5610
|
this.createStatusConnection();
|
|
4080
5611
|
}
|
|
@@ -4085,38 +5616,76 @@
|
|
|
4085
5616
|
}
|
|
4086
5617
|
});
|
|
4087
5618
|
}
|
|
5619
|
+
/**
|
|
5620
|
+
* Method used for destroying everything (one-time use)
|
|
5621
|
+
*/
|
|
4088
5622
|
destroy() {
|
|
5623
|
+
// Stop any ongoing timers and intervals first
|
|
5624
|
+
if (this._statusTimer != null) {
|
|
5625
|
+
clearInterval(this._statusTimer);
|
|
5626
|
+
this._statusTimer = null;
|
|
5627
|
+
}
|
|
5628
|
+
if (this._restartTimer != null) {
|
|
5629
|
+
clearInterval(this._restartTimer);
|
|
5630
|
+
this._restartTimer = null;
|
|
5631
|
+
}
|
|
5632
|
+
clearTimeout(this._publishTimer);
|
|
5633
|
+
// Remove orientation change listeners
|
|
4089
5634
|
if (window.screen && window.screen.orientation) {
|
|
4090
5635
|
window.screen.orientation.removeEventListener('change', this.handleOrientationChange);
|
|
4091
5636
|
} else {
|
|
4092
5637
|
window.removeEventListener('orientationchange', this.handleOrientationChange);
|
|
4093
5638
|
}
|
|
4094
|
-
|
|
4095
|
-
if (this._soundMeter) {
|
|
4096
|
-
this._soundMeter.detach();
|
|
4097
|
-
}
|
|
4098
|
-
clearTimeout(this._publishTimer);
|
|
4099
|
-
this._pendingMicrophoneState = null;
|
|
4100
|
-
this._cameraList = new InputDeviceList();
|
|
4101
|
-
this._microphoneList = new InputDeviceList();
|
|
4102
|
-
this._permissionChecked = false;
|
|
4103
|
-
this._isWindowActive = false;
|
|
4104
|
-
this._isMicrophoneMuted = false;
|
|
5639
|
+
// Remove other event listeners
|
|
4105
5640
|
try {
|
|
4106
5641
|
this._main.removeEventListener("serverConnect", this.onServerConnect);
|
|
4107
5642
|
this._main.removeEventListener("serverDisconnect", this.onServerDisconnect);
|
|
5643
|
+
this._main.removeEventListener("streamKeyInUse", this.onStreamKeyTaken);
|
|
5644
|
+
this._main.removeEventListener("statusServerConnect", this.onStatusServerConnect);
|
|
5645
|
+
this._main.removeEventListener("statusServerDisconnect", this.onStatusServerDisconnect);
|
|
5646
|
+
this._main.removeEventListener("streamStatusUpdate", this.onStreamStatsUpdate);
|
|
5647
|
+
this._main.removeEventListener("deviceStateChange", this.onDeviceStateChange);
|
|
4108
5648
|
document.removeEventListener("visibilitychange", this.visibilityChange);
|
|
4109
5649
|
window.removeEventListener("blur", this.onWindowBlur);
|
|
4110
5650
|
window.removeEventListener("focus", this.onWindowFocus);
|
|
4111
5651
|
} catch (e) {
|
|
4112
|
-
|
|
5652
|
+
this._logger.error(this, 'Error removing event listeners');
|
|
4113
5653
|
}
|
|
5654
|
+
// Make sure we destroy the status connection
|
|
5655
|
+
if (this._statusConnection) {
|
|
5656
|
+
this._statusConnection.destroy();
|
|
5657
|
+
this._statusConnection = null;
|
|
5658
|
+
}
|
|
5659
|
+
// Stop all media streams and clean up the WebRTC connection
|
|
5660
|
+
this.forceStopAllStreams();
|
|
5661
|
+
// Reset all state variables
|
|
5662
|
+
this._pendingMicrophoneState = null;
|
|
5663
|
+
this._cameraList = new InputDeviceList();
|
|
5664
|
+
this._microphoneList = new InputDeviceList();
|
|
5665
|
+
this._permissionChecked = false;
|
|
5666
|
+
this._isWindowActive = false;
|
|
5667
|
+
this._isMicrophoneMuted = false;
|
|
4114
5668
|
this._publishState = exports.PublishState.NOT_INITIALIZED;
|
|
4115
|
-
|
|
5669
|
+
this._inputDeviceState = exports.InputDevicesState.NOT_INITIALIZED;
|
|
5670
|
+
this._cameraState = exports.DeviceState.NOT_INITIALIZED;
|
|
5671
|
+
this._microphoneState = exports.DeviceState.NOT_INITIALIZED;
|
|
5672
|
+
// Log completion
|
|
5673
|
+
this._logger.success(this, "StreamerController successfully destroyed and all resources released");
|
|
4116
5674
|
}
|
|
4117
5675
|
}
|
|
4118
5676
|
|
|
5677
|
+
/**
|
|
5678
|
+
* Main class for communicating with Storm Streaming Server
|
|
5679
|
+
*/
|
|
4119
5680
|
class WowzaConnection extends AbstractSocket {
|
|
5681
|
+
//------------------------------------------------------------------------//
|
|
5682
|
+
// CONSTRUCTOR
|
|
5683
|
+
//------------------------------------------------------------------------//
|
|
5684
|
+
/**
|
|
5685
|
+
* Constructor
|
|
5686
|
+
* @param main
|
|
5687
|
+
* @constructor
|
|
5688
|
+
*/
|
|
4120
5689
|
constructor(main, networkController) {
|
|
4121
5690
|
super();
|
|
4122
5691
|
this._logger = main.getLogger();
|
|
@@ -4144,6 +5713,14 @@
|
|
|
4144
5713
|
this.startConnection();
|
|
4145
5714
|
} else this._logger.error(this, "Connection with the server could not be initialized!");
|
|
4146
5715
|
}
|
|
5716
|
+
//------------------------------------------------------------------------//
|
|
5717
|
+
// BASE EVENTS
|
|
5718
|
+
//------------------------------------------------------------------------//
|
|
5719
|
+
/**
|
|
5720
|
+
* On server connection opened;
|
|
5721
|
+
* @param event
|
|
5722
|
+
* @protected
|
|
5723
|
+
*/
|
|
4147
5724
|
onSocketOpen(event) {
|
|
4148
5725
|
this._logger.success(this, `Connection with the server has been established!`);
|
|
4149
5726
|
this._main.dispatchEvent("serverConnect", {
|
|
@@ -4153,6 +5730,11 @@
|
|
|
4153
5730
|
});
|
|
4154
5731
|
this._isConnected = true;
|
|
4155
5732
|
}
|
|
5733
|
+
/**
|
|
5734
|
+
* On server connection error
|
|
5735
|
+
* @param event
|
|
5736
|
+
* @protected
|
|
5737
|
+
*/
|
|
4156
5738
|
onSocketError(event) {
|
|
4157
5739
|
this._isConnected = false;
|
|
4158
5740
|
if (!this._disconnectedByUser) {
|
|
@@ -4169,6 +5751,11 @@
|
|
|
4169
5751
|
}
|
|
4170
5752
|
}
|
|
4171
5753
|
}
|
|
5754
|
+
/**
|
|
5755
|
+
* On server connection closed
|
|
5756
|
+
* @param event
|
|
5757
|
+
* @protected
|
|
5758
|
+
*/
|
|
4172
5759
|
onSocketClose(event) {
|
|
4173
5760
|
this._isConnected = false;
|
|
4174
5761
|
if (!this._disconnectedByUser) {
|
|
@@ -4182,9 +5769,21 @@
|
|
|
4182
5769
|
this.initiateReconnect();
|
|
4183
5770
|
} else this._logger.warning(this, `Force disconnect from server!`);
|
|
4184
5771
|
}
|
|
5772
|
+
/**
|
|
5773
|
+
* Method is called whenever a new message from socket arrives
|
|
5774
|
+
* @private
|
|
5775
|
+
*/
|
|
4185
5776
|
onSocketMessage(event) {
|
|
4186
5777
|
this._networkController.onMessage(event);
|
|
4187
5778
|
}
|
|
5779
|
+
//------------------------------------------------------------------------//
|
|
5780
|
+
// BASE METHODS
|
|
5781
|
+
//------------------------------------------------------------------------//
|
|
5782
|
+
/**
|
|
5783
|
+
* Creates new URL for WebSockets based on serverItem object
|
|
5784
|
+
* @param serverItem
|
|
5785
|
+
* @private
|
|
5786
|
+
*/
|
|
4188
5787
|
createURL(serverItem) {
|
|
4189
5788
|
let url = "";
|
|
4190
5789
|
url += serverItem.getIfSSL() ? "wss://" : "ws://";
|
|
@@ -4193,6 +5792,10 @@
|
|
|
4193
5792
|
url += "/webrtc-session.json";
|
|
4194
5793
|
return url;
|
|
4195
5794
|
}
|
|
5795
|
+
/**
|
|
5796
|
+
* Initiates reconnection procedure
|
|
5797
|
+
* @private
|
|
5798
|
+
*/
|
|
4196
5799
|
initiateReconnect() {
|
|
4197
5800
|
const shouldReconnect = this._main.getConfigManager().getSettingsData().getIfRestartOnError();
|
|
4198
5801
|
const reconnectTime = this._main.getConfigManager().getSettingsData().getReconnectTime();
|
|
@@ -4216,6 +5819,11 @@
|
|
|
4216
5819
|
}, reconnectTime * 1000);
|
|
4217
5820
|
}
|
|
4218
5821
|
}
|
|
5822
|
+
/**
|
|
5823
|
+
* Picks new server from this list of available ones
|
|
5824
|
+
* @param serverList
|
|
5825
|
+
* @private
|
|
5826
|
+
*/
|
|
4219
5827
|
pickServerFromList(serverList) {
|
|
4220
5828
|
let server = null;
|
|
4221
5829
|
for (let i = 0; i < serverList.length; i++) {
|
|
@@ -4236,23 +5844,52 @@
|
|
|
4236
5844
|
this._currServer = server;
|
|
4237
5845
|
}
|
|
4238
5846
|
}
|
|
5847
|
+
/**
|
|
5848
|
+
* Returns true/false depending if a connection with a server is active
|
|
5849
|
+
*/
|
|
4239
5850
|
isConnectionActive() {
|
|
4240
5851
|
return this._isConnected;
|
|
4241
5852
|
}
|
|
4242
5853
|
getCurrentServer() {
|
|
4243
5854
|
return this._currServer;
|
|
4244
5855
|
}
|
|
5856
|
+
/**
|
|
5857
|
+
* Destroys object and clean-ups everything that is needed
|
|
5858
|
+
*/
|
|
4245
5859
|
destroy() {
|
|
4246
5860
|
super.destroy();
|
|
4247
5861
|
if (this._reconnectTimer != null) clearTimeout(this._reconnectTimer);
|
|
4248
5862
|
}
|
|
4249
5863
|
}
|
|
4250
5864
|
|
|
5865
|
+
/**
|
|
5866
|
+
* Main class for managing socket connections (only one per instance) and parsing packets.
|
|
5867
|
+
*/
|
|
4251
5868
|
class NetworkController {
|
|
5869
|
+
//------------------------------------------------------------------------//
|
|
5870
|
+
// CONSTRUCTOR
|
|
5871
|
+
//------------------------------------------------------------------------//
|
|
5872
|
+
/**
|
|
5873
|
+
* Constructor
|
|
5874
|
+
* @param main reference to the main class
|
|
5875
|
+
*/
|
|
4252
5876
|
constructor(main) {
|
|
5877
|
+
/**
|
|
5878
|
+
* Current streamKey
|
|
5879
|
+
* @private
|
|
5880
|
+
*/
|
|
4253
5881
|
this._currentStreamKey = "none";
|
|
5882
|
+
/**
|
|
5883
|
+
* Last state
|
|
5884
|
+
* @private
|
|
5885
|
+
*/
|
|
4254
5886
|
this._lastState = "";
|
|
4255
|
-
|
|
5887
|
+
//------------------------------------------------------------------------//
|
|
5888
|
+
// CONNECTION-RELATED METHODS
|
|
5889
|
+
//------------------------------------------------------------------------//
|
|
5890
|
+
this.onServerConnect = () => {
|
|
5891
|
+
// nothing
|
|
5892
|
+
};
|
|
4256
5893
|
this.onServerDisconnect = () => {
|
|
4257
5894
|
this._lastState = "none";
|
|
4258
5895
|
};
|
|
@@ -4265,6 +5902,9 @@
|
|
|
4265
5902
|
this._main.addEventListener("serverConnect", this.onServerConnect, false);
|
|
4266
5903
|
this._main.addEventListener("serverDisconnect", this.onServerDisconnect, false);
|
|
4267
5904
|
}
|
|
5905
|
+
//------------------------------------------------------------------------//
|
|
5906
|
+
// MAIN METHODS
|
|
5907
|
+
//------------------------------------------------------------------------//
|
|
4268
5908
|
initialize() {
|
|
4269
5909
|
if (this._connection != null) {
|
|
4270
5910
|
if (this._connection.getConnectionState() == ConnectionState.CONNECTING || this._connection.getConnectionState() == ConnectionState.CONNECTED) {
|
|
@@ -4287,9 +5927,18 @@
|
|
|
4287
5927
|
this._connection.sendData(message);
|
|
4288
5928
|
}
|
|
4289
5929
|
}
|
|
5930
|
+
//------------------------------------------------------------------------//
|
|
5931
|
+
// SETS & GETS
|
|
5932
|
+
//------------------------------------------------------------------------//
|
|
5933
|
+
/**
|
|
5934
|
+
* Returns current SocketConnection object
|
|
5935
|
+
*/
|
|
4290
5936
|
getConnection() {
|
|
4291
5937
|
return this._connection;
|
|
4292
5938
|
}
|
|
5939
|
+
/**
|
|
5940
|
+
* Returns streamKey that is currently being used
|
|
5941
|
+
*/
|
|
4293
5942
|
getCurrentStreamKey() {
|
|
4294
5943
|
return this._currentStreamKey;
|
|
4295
5944
|
}
|
|
@@ -4356,18 +6005,22 @@
|
|
|
4356
6005
|
this._lastTimestamp = null;
|
|
4357
6006
|
this._isTimemarkLine = false;
|
|
4358
6007
|
this._borderWidth = 1;
|
|
6008
|
+
// Validate input arrays
|
|
4359
6009
|
if (colors.length !== valueRanges.length + 1) {
|
|
4360
6010
|
throw new Error(`Colors array must have exactly ${valueRanges.length + 1} elements (one more than valueRanges)`);
|
|
4361
6011
|
}
|
|
6012
|
+
// Validate that valueRanges are in ascending order
|
|
4362
6013
|
for (let i = 1; i < valueRanges.length; i++) {
|
|
4363
6014
|
if (valueRanges[i] <= valueRanges[i - 1]) {
|
|
4364
6015
|
throw new Error('ValueRanges must be in ascending order');
|
|
4365
6016
|
}
|
|
4366
6017
|
}
|
|
6018
|
+
// Validate colors format
|
|
4367
6019
|
const hexColorRegex = /^#[0-9A-Fa-f]{6}$/;
|
|
4368
6020
|
if (!colors.every(color => hexColorRegex.test(color))) {
|
|
4369
6021
|
throw new Error('All colors must be in valid hex format (e.g., #FF0000)');
|
|
4370
6022
|
}
|
|
6023
|
+
// Find container
|
|
4371
6024
|
let container;
|
|
4372
6025
|
if (typeof containerIdOrElement === 'string') {
|
|
4373
6026
|
const foundElement = document.getElementById(containerIdOrElement);
|
|
@@ -4378,13 +6031,17 @@
|
|
|
4378
6031
|
} else {
|
|
4379
6032
|
container = containerIdOrElement;
|
|
4380
6033
|
}
|
|
6034
|
+
// Get container dimensions
|
|
4381
6035
|
const containerRect = container.getBoundingClientRect();
|
|
4382
6036
|
this._width = Math.floor(containerRect.width);
|
|
4383
6037
|
this._height = Math.floor(containerRect.height);
|
|
6038
|
+
// Calculate effective dimensions (accounting for border)
|
|
4384
6039
|
this._effectiveWidth = this._width - this._borderWidth * 2;
|
|
4385
6040
|
this._effectiveHeight = this._height - this._borderWidth * 2;
|
|
6041
|
+
// Create canvas element
|
|
4386
6042
|
this._canvas = document.createElement('canvas');
|
|
4387
6043
|
container.appendChild(this._canvas);
|
|
6044
|
+
// Get context
|
|
4388
6045
|
const context = this._canvas.getContext('2d', {
|
|
4389
6046
|
willReadFrequently: true
|
|
4390
6047
|
});
|
|
@@ -4392,13 +6049,16 @@
|
|
|
4392
6049
|
throw new Error('Failed to get canvas context');
|
|
4393
6050
|
}
|
|
4394
6051
|
this._ctx = context;
|
|
4395
|
-
this._valueRanges = [0, ...valueRanges];
|
|
6052
|
+
this._valueRanges = [0, ...valueRanges]; // Add 0 at the beginning
|
|
4396
6053
|
this._colors = colors;
|
|
4397
6054
|
this._lineWidth = lineWidth;
|
|
6055
|
+
// Set canvas size
|
|
4398
6056
|
this._canvas.width = this._width;
|
|
4399
6057
|
this._canvas.height = this._height;
|
|
6058
|
+
// Set canvas style to ensure it displays at the correct size
|
|
4400
6059
|
this._canvas.style.width = `${this._width}px`;
|
|
4401
6060
|
this._canvas.style.height = `${this._height}px`;
|
|
6061
|
+
// Initial background and border
|
|
4402
6062
|
this.clear();
|
|
4403
6063
|
}
|
|
4404
6064
|
drawBorder() {
|
|
@@ -4407,12 +6067,15 @@
|
|
|
4407
6067
|
this._ctx.strokeRect(this._borderWidth / 2, this._borderWidth / 2, this._width - this._borderWidth, this._height - this._borderWidth);
|
|
4408
6068
|
}
|
|
4409
6069
|
clear() {
|
|
6070
|
+
// Clear entire canvas
|
|
4410
6071
|
this._ctx.clearRect(0, 0, this._width, this._height);
|
|
6072
|
+
// Fill background within border
|
|
4411
6073
|
this._ctx.fillStyle = this._colors[0];
|
|
4412
6074
|
this._ctx.fillRect(this._borderWidth, this._borderWidth, this._effectiveWidth, this._effectiveHeight);
|
|
6075
|
+
// Draw border
|
|
4413
6076
|
this.drawBorder();
|
|
4414
6077
|
this._isFullyDrawn = false;
|
|
4415
|
-
this._currentX = this._borderWidth;
|
|
6078
|
+
this._currentX = this._borderWidth; // Start after left border
|
|
4416
6079
|
this._lastTimestamp = null;
|
|
4417
6080
|
this._isTimemarkLine = false;
|
|
4418
6081
|
}
|
|
@@ -4425,6 +6088,7 @@
|
|
|
4425
6088
|
};
|
|
4426
6089
|
}
|
|
4427
6090
|
}
|
|
6091
|
+
// If value is greater than the last range
|
|
4428
6092
|
return {
|
|
4429
6093
|
lowerIndex: this._valueRanges.length - 2,
|
|
4430
6094
|
upperIndex: this._valueRanges.length - 1
|
|
@@ -4434,10 +6098,14 @@
|
|
|
4434
6098
|
return (value - lowerBound) / (upperBound - lowerBound);
|
|
4435
6099
|
}
|
|
4436
6100
|
shiftCanvasLeft(shiftAmount) {
|
|
6101
|
+
// Get the content within the borders
|
|
4437
6102
|
const imageData = this._ctx.getImageData(this._borderWidth + shiftAmount, this._borderWidth, this._effectiveWidth - shiftAmount, this._effectiveHeight);
|
|
6103
|
+
// Clear the area within borders
|
|
4438
6104
|
this._ctx.fillStyle = this._colors[0];
|
|
4439
6105
|
this._ctx.fillRect(this._borderWidth, this._borderWidth, this._effectiveWidth, this._effectiveHeight);
|
|
6106
|
+
// Draw shifted content
|
|
4440
6107
|
this._ctx.putImageData(imageData, this._borderWidth, this._borderWidth);
|
|
6108
|
+
// Redraw border as it might have been affected
|
|
4441
6109
|
this.drawBorder();
|
|
4442
6110
|
}
|
|
4443
6111
|
applyOverlayEffect(baseColor, overlayOpacity = 0.5) {
|
|
@@ -4502,15 +6170,18 @@
|
|
|
4502
6170
|
lowerColor = this.applyOverlayEffect(lowerColor, 0.3);
|
|
4503
6171
|
upperColor = this.applyOverlayEffect(upperColor, 0.3);
|
|
4504
6172
|
}
|
|
6173
|
+
// Calculate heights accounting for borders
|
|
4505
6174
|
const upperHeight = Math.round(this._effectiveHeight * ratio);
|
|
4506
6175
|
const lowerHeight = this._effectiveHeight - upperHeight;
|
|
6176
|
+
// Draw lower part
|
|
4507
6177
|
this._ctx.fillStyle = lowerColor;
|
|
4508
6178
|
this._ctx.fillRect(x, this._height - this._borderWidth - lowerHeight, width, lowerHeight);
|
|
6179
|
+
// Draw upper part
|
|
4509
6180
|
this._ctx.fillStyle = upperColor;
|
|
4510
6181
|
this._ctx.fillRect(x, this._borderWidth, width, upperHeight);
|
|
4511
6182
|
}
|
|
4512
6183
|
clearGraph() {
|
|
4513
|
-
this._currentX = this._borderWidth;
|
|
6184
|
+
this._currentX = this._borderWidth; // Reset to after left border
|
|
4514
6185
|
this._isFullyDrawn = false;
|
|
4515
6186
|
this._lastTimestamp = null;
|
|
4516
6187
|
this._isTimemarkLine = false;
|
|
@@ -4536,8 +6207,10 @@
|
|
|
4536
6207
|
start() {
|
|
4537
6208
|
if (this._graph != null) stop();
|
|
4538
6209
|
const valueRanges = [1000000, 2000000, 3000000, 5000000, 6000000, 7000000];
|
|
4539
|
-
const colors = ['#000000', '#0a3980', '#2793dd', '#3bc39c', '#c3df3e', '#f89539', '#f83f3f'
|
|
4540
|
-
|
|
6210
|
+
const colors = ['#000000', '#0a3980', '#2793dd', '#3bc39c', '#c3df3e', '#f89539', '#f83f3f' // MaxBuffer - End
|
|
6211
|
+
];
|
|
6212
|
+
|
|
6213
|
+
this._graph = new GraphDrawer(this._object, valueRanges, colors, 5);
|
|
4541
6214
|
this._main.addEventListener("streamStatusUpdate", this.onStreamStatsUpdate);
|
|
4542
6215
|
return this;
|
|
4543
6216
|
}
|
|
@@ -4562,8 +6235,10 @@
|
|
|
4562
6235
|
start() {
|
|
4563
6236
|
if (this._graph != null) stop();
|
|
4564
6237
|
const valueRanges = [25, 26, 27, 28, 29, 30];
|
|
4565
|
-
const colors = ['#000000', '#0a3980', '#2793dd', '#3bc39c', '#c3df3e', '#f89539', '#f83f3f'
|
|
4566
|
-
|
|
6238
|
+
const colors = ['#000000', '#0a3980', '#2793dd', '#3bc39c', '#c3df3e', '#f89539', '#f83f3f' // MaxBuffer - End
|
|
6239
|
+
];
|
|
6240
|
+
|
|
6241
|
+
this._graph = new GraphDrawer(this._object, valueRanges, colors, 5);
|
|
4567
6242
|
this._main.addEventListener("streamStatusUpdate", this.onStreamStatsUpdate);
|
|
4568
6243
|
return this;
|
|
4569
6244
|
}
|
|
@@ -4575,19 +6250,85 @@
|
|
|
4575
6250
|
}
|
|
4576
6251
|
}
|
|
4577
6252
|
|
|
6253
|
+
class MicrophoneGraph {
|
|
6254
|
+
constructor(main, container) {
|
|
6255
|
+
this.onStreamStatsUpdate = event => {
|
|
6256
|
+
var _a;
|
|
6257
|
+
(_a = this._graph) === null || _a === void 0 ? void 0 : _a.addEntry(event.high * 500);
|
|
6258
|
+
console.log(event.high * 200);
|
|
6259
|
+
};
|
|
6260
|
+
this._main = main;
|
|
6261
|
+
this._object = container;
|
|
6262
|
+
this._main.addGraph(this);
|
|
6263
|
+
}
|
|
6264
|
+
start() {
|
|
6265
|
+
if (this._graph != null) stop();
|
|
6266
|
+
const valueRanges = [0, 20, 40, 60, 80, 100];
|
|
6267
|
+
const colors = ['#000000', '#0a3980', '#2793dd', '#3bc39c', '#c3df3e', '#f89539', '#f83f3f' // MaxBuffer - End
|
|
6268
|
+
];
|
|
6269
|
+
|
|
6270
|
+
this._graph = new GraphDrawer(this._object, valueRanges, colors, 2);
|
|
6271
|
+
this._main.addEventListener("soundMeter", this.onStreamStatsUpdate);
|
|
6272
|
+
return this;
|
|
6273
|
+
}
|
|
6274
|
+
stop() {
|
|
6275
|
+
this._main.removeEventListener("soundMeter", this.onStreamStatsUpdate);
|
|
6276
|
+
if (this._graph != null) this._graph.destroy();
|
|
6277
|
+
this._graph = null;
|
|
6278
|
+
return this;
|
|
6279
|
+
}
|
|
6280
|
+
}
|
|
6281
|
+
|
|
6282
|
+
/**
|
|
6283
|
+
* Main class of the player. The player itself has no GUI, but can be controlled via provided API.
|
|
6284
|
+
*/
|
|
4578
6285
|
class StormStreamer extends EventDispatcher {
|
|
6286
|
+
//------------------------------------------------------------------------//
|
|
6287
|
+
// CONSTRUCTOR
|
|
6288
|
+
//------------------------------------------------------------------------//
|
|
6289
|
+
/**
|
|
6290
|
+
* Constructor - creates a new StormStreamer instance
|
|
6291
|
+
*
|
|
6292
|
+
* @param streamConfig - Configuration object for the streamer
|
|
6293
|
+
* @param autoInitialize - Whether to automatically initialize the streamer after creation
|
|
6294
|
+
*/
|
|
4579
6295
|
constructor(streamConfig, autoInitialize = false) {
|
|
4580
6296
|
super();
|
|
6297
|
+
/**
|
|
6298
|
+
* Indicates whether the streamer object is in development mode (provides more debug options)
|
|
6299
|
+
* @private
|
|
6300
|
+
*/
|
|
4581
6301
|
this.DEV_MODE = true;
|
|
4582
|
-
|
|
4583
|
-
|
|
6302
|
+
/**
|
|
6303
|
+
* Version of this streamer in SemVer format (Major.Minor.Patch).
|
|
6304
|
+
* @private
|
|
6305
|
+
*/
|
|
6306
|
+
this.STREAMER_VERSION = "0.9.3-beta.0";
|
|
6307
|
+
/**
|
|
6308
|
+
* Compile date for this streamer
|
|
6309
|
+
* @private
|
|
6310
|
+
*/
|
|
6311
|
+
this.COMPILE_DATE = "3/8/2025, 11:51:35 PM";
|
|
6312
|
+
/**
|
|
6313
|
+
* Defines from which branch this streamer comes from e.g. "Main", "Experimental"
|
|
6314
|
+
* @private
|
|
6315
|
+
*/
|
|
4584
6316
|
this.STREAMER_BRANCH = "Experimental";
|
|
6317
|
+
/**
|
|
6318
|
+
* Defines number of streamer protocol that is required on server-side
|
|
6319
|
+
* @private
|
|
6320
|
+
*/
|
|
4585
6321
|
this.STREAMER_PROTOCOL_VERSION = 1;
|
|
6322
|
+
/**
|
|
6323
|
+
* Indicates whether streamer was initialized or not
|
|
6324
|
+
* @private
|
|
6325
|
+
*/
|
|
4586
6326
|
this._initialized = false;
|
|
4587
6327
|
if (typeof window === 'undefined' || !window.document || !window.document.createElement) {
|
|
4588
6328
|
console.error(`StormStreamer Creation Error - No "window" element in the provided context!`);
|
|
4589
6329
|
return;
|
|
4590
6330
|
}
|
|
6331
|
+
// WINDOW.StormStreamerArray
|
|
4591
6332
|
if (this.DEV_MODE && !('StormStreamerArray' in window)) {
|
|
4592
6333
|
window.StormStreamerArray = [];
|
|
4593
6334
|
}
|
|
@@ -4597,13 +6338,17 @@
|
|
|
4597
6338
|
this.setStreamConfig(streamConfig);
|
|
4598
6339
|
if (autoInitialize) this.initialize();
|
|
4599
6340
|
}
|
|
6341
|
+
/**
|
|
6342
|
+
* Initializes the streamer object. From this point, a connection to the server is established and authentication occurs.
|
|
6343
|
+
* It is recommended to add all event listeners before calling this method to ensure they can be properly captured.
|
|
6344
|
+
*/
|
|
4600
6345
|
initialize() {
|
|
4601
6346
|
if (this._isRemoved) return;
|
|
4602
6347
|
if (this._configManager == null) throw Error("Stream Config was not provided for this streamer! A properly configured object must be provided through the constructor or via the setConfig method before using the initialize() method.");
|
|
4603
|
-
this._storageManager = new StorageManager(this);
|
|
4604
|
-
this._stageController = new StageController(this);
|
|
4605
|
-
this._networkController = new NetworkController(this);
|
|
4606
|
-
this._streamerController = new StreamerController(this);
|
|
6348
|
+
this._storageManager = new StorageManager(this); // Storing user data
|
|
6349
|
+
this._stageController = new StageController(this); // Visual elements like VideoElement
|
|
6350
|
+
this._networkController = new NetworkController(this); // Networking and connection with a server
|
|
6351
|
+
this._streamerController = new StreamerController(this); // Video Playback
|
|
4607
6352
|
this._statsController = new StatsController(this);
|
|
4608
6353
|
this._graphs = [];
|
|
4609
6354
|
this._initialized = true;
|
|
@@ -4611,8 +6356,16 @@
|
|
|
4611
6356
|
ref: this
|
|
4612
6357
|
});
|
|
4613
6358
|
}
|
|
6359
|
+
/**
|
|
6360
|
+
* Sets stream config for the streamer (or overwrites an existing one).
|
|
6361
|
+
*
|
|
6362
|
+
* @param streamConfig - New configuration object for the streamer
|
|
6363
|
+
*/
|
|
4614
6364
|
setStreamConfig(streamConfig) {
|
|
4615
6365
|
if (this._isRemoved) return;
|
|
6366
|
+
/**
|
|
6367
|
+
* In case the original streamConfig is modified elsewhere we have to create a separate copy and store it ourselves
|
|
6368
|
+
*/
|
|
4616
6369
|
const copiedStreamConfig = JSON.parse(JSON.stringify(streamConfig));
|
|
4617
6370
|
if (this._configManager == null) {
|
|
4618
6371
|
this._configManager = new ConfigManager(copiedStreamConfig);
|
|
@@ -4636,10 +6389,21 @@
|
|
|
4636
6389
|
});
|
|
4637
6390
|
}
|
|
4638
6391
|
}
|
|
6392
|
+
//------------------------------------------------------------------------//
|
|
6393
|
+
// PLAYBACK / STREAMING
|
|
6394
|
+
//------------------------------------------------------------------------//
|
|
6395
|
+
/**
|
|
6396
|
+
* Returns true if this streamer instance is currently connected to a Storm Server/Cloud instance.
|
|
6397
|
+
*
|
|
6398
|
+
* @returns Boolean indicating connection status
|
|
6399
|
+
*/
|
|
4639
6400
|
isConnected() {
|
|
4640
6401
|
var _a, _b;
|
|
4641
6402
|
return (_b = (_a = this._networkController) === null || _a === void 0 ? void 0 : _a.getConnection().isConnectionActive()) !== null && _b !== void 0 ? _b : false;
|
|
4642
6403
|
}
|
|
6404
|
+
/**
|
|
6405
|
+
* Mutes the streamer's video object. Audio output will be silenced.
|
|
6406
|
+
*/
|
|
4643
6407
|
mute() {
|
|
4644
6408
|
if (this._stageController != null) {
|
|
4645
6409
|
if (this._stageController.getScreenElement() != null) {
|
|
@@ -4649,6 +6413,9 @@
|
|
|
4649
6413
|
}
|
|
4650
6414
|
this._configManager.getSettingsData().getAudioData().muted = true;
|
|
4651
6415
|
}
|
|
6416
|
+
/**
|
|
6417
|
+
* Unmutes the streamer's video object. Audio output will be restored.
|
|
6418
|
+
*/
|
|
4652
6419
|
unmute() {
|
|
4653
6420
|
if (this._stageController != null) {
|
|
4654
6421
|
if (this._stageController.getScreenElement() != null) {
|
|
@@ -4658,10 +6425,20 @@
|
|
|
4658
6425
|
}
|
|
4659
6426
|
this._configManager.getSettingsData().getAudioData().muted = false;
|
|
4660
6427
|
}
|
|
6428
|
+
/**
|
|
6429
|
+
* Checks whether the streamer audio is currently muted.
|
|
6430
|
+
*
|
|
6431
|
+
* @returns Boolean indicating mute status
|
|
6432
|
+
*/
|
|
4661
6433
|
isMute() {
|
|
4662
6434
|
var _a, _b, _c, _d;
|
|
4663
6435
|
return (_d = (_c = (_b = (_a = this._stageController) === null || _a === void 0 ? void 0 : _a.getScreenElement()) === null || _b === void 0 ? void 0 : _b.getIfMuted()) !== null && _c !== void 0 ? _c : this._configManager.getSettingsData().getAudioData().muted) !== null && _d !== void 0 ? _d : false;
|
|
4664
6436
|
}
|
|
6437
|
+
/**
|
|
6438
|
+
* Toggles between mute and unmute states. Returns the new mute state.
|
|
6439
|
+
*
|
|
6440
|
+
* @returns New mute state (true = muted, false = unmuted)
|
|
6441
|
+
*/
|
|
4665
6442
|
toggleMute() {
|
|
4666
6443
|
const isMuted = this.isMute();
|
|
4667
6444
|
if (isMuted) {
|
|
@@ -4671,6 +6448,12 @@
|
|
|
4671
6448
|
}
|
|
4672
6449
|
return !isMuted;
|
|
4673
6450
|
}
|
|
6451
|
+
/**
|
|
6452
|
+
* Sets new volume for the streamer (0-100). Once the method is performed, the volumeChange event will be triggered.
|
|
6453
|
+
* If the video was muted prior to the volume change, it will be automatically unmuted.
|
|
6454
|
+
*
|
|
6455
|
+
* @param newVolume - Volume level (0-100)
|
|
6456
|
+
*/
|
|
4674
6457
|
setVolume(newVolume) {
|
|
4675
6458
|
var _a, _b;
|
|
4676
6459
|
if (((_b = (_a = this._stageController) === null || _a === void 0 ? void 0 : _a.getScreenElement()) === null || _b === void 0 ? void 0 : _b.setVolume(newVolume)) !== undefined) {
|
|
@@ -4678,96 +6461,217 @@
|
|
|
4678
6461
|
}
|
|
4679
6462
|
this._configManager.getSettingsData().getAudioData().startVolume = newVolume;
|
|
4680
6463
|
}
|
|
6464
|
+
/**
|
|
6465
|
+
* Returns current streamer volume (0-100).
|
|
6466
|
+
*
|
|
6467
|
+
* @returns Current volume level
|
|
6468
|
+
*/
|
|
4681
6469
|
getVolume() {
|
|
4682
6470
|
var _a, _b, _c;
|
|
4683
6471
|
return (_c = (_b = (_a = this._stageController) === null || _a === void 0 ? void 0 : _a.getScreenElement()) === null || _b === void 0 ? void 0 : _b.getVolume()) !== null && _c !== void 0 ? _c : this._configManager.getSettingsData().getAudioData().startVolume;
|
|
4684
6472
|
}
|
|
6473
|
+
/**
|
|
6474
|
+
* Returns the list of available camera devices.
|
|
6475
|
+
*
|
|
6476
|
+
* @returns Array of camera input devices
|
|
6477
|
+
*/
|
|
4685
6478
|
getCameraList() {
|
|
4686
6479
|
var _a, _b;
|
|
4687
6480
|
return (_b = (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.getCameraList()) !== null && _b !== void 0 ? _b : [];
|
|
4688
6481
|
}
|
|
6482
|
+
/**
|
|
6483
|
+
* Returns the list of available microphone devices.
|
|
6484
|
+
*
|
|
6485
|
+
* @returns Array of microphone input devices
|
|
6486
|
+
*/
|
|
4689
6487
|
getMicrophoneList() {
|
|
4690
6488
|
var _a, _b;
|
|
4691
6489
|
return (_b = (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.getMicrophoneList()) !== null && _b !== void 0 ? _b : [];
|
|
4692
6490
|
}
|
|
6491
|
+
/**
|
|
6492
|
+
* Sets the active camera device by ID.
|
|
6493
|
+
*
|
|
6494
|
+
* @param cameraID - ID of the camera device to use
|
|
6495
|
+
*/
|
|
4693
6496
|
setCamera(cameraID) {
|
|
4694
6497
|
var _a;
|
|
4695
6498
|
(_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.selectCamera(cameraID);
|
|
4696
6499
|
}
|
|
6500
|
+
/**
|
|
6501
|
+
* Sets the active microphone device by ID.
|
|
6502
|
+
*
|
|
6503
|
+
* @param microphoneID - ID of the microphone device to use
|
|
6504
|
+
*/
|
|
4697
6505
|
setMicrophone(microphoneID) {
|
|
4698
6506
|
var _a;
|
|
4699
6507
|
(_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.selectMicrophone(microphoneID);
|
|
4700
6508
|
}
|
|
6509
|
+
/**
|
|
6510
|
+
* Returns the currently active camera device.
|
|
6511
|
+
*
|
|
6512
|
+
* @returns Current camera device or null if none is active
|
|
6513
|
+
*/
|
|
4701
6514
|
getCurrentCamera() {
|
|
4702
6515
|
return this._streamerController.getCurrentCamera();
|
|
4703
6516
|
}
|
|
6517
|
+
/**
|
|
6518
|
+
* Returns the currently active microphone device.
|
|
6519
|
+
*
|
|
6520
|
+
* @returns Current microphone device or null if none is active
|
|
6521
|
+
*/
|
|
4704
6522
|
getCurrentMicrophone() {
|
|
4705
6523
|
return this._streamerController.getCurrentMicrophone();
|
|
4706
6524
|
}
|
|
6525
|
+
/**
|
|
6526
|
+
* Mutes or unmutes the microphone.
|
|
6527
|
+
*
|
|
6528
|
+
* @param microphoneState - True to mute, false to unmute
|
|
6529
|
+
*/
|
|
4707
6530
|
muteMicrophone(microphoneState) {
|
|
4708
6531
|
var _a;
|
|
4709
6532
|
(_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.muteMicrophone(microphoneState);
|
|
4710
6533
|
}
|
|
6534
|
+
/**
|
|
6535
|
+
* Checks if the microphone is currently muted.
|
|
6536
|
+
*
|
|
6537
|
+
* @returns Boolean indicating if microphone is muted
|
|
6538
|
+
*/
|
|
4711
6539
|
isMicrophoneMuted() {
|
|
4712
6540
|
var _a, _b;
|
|
4713
6541
|
return (_b = (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.isMicrophoneMuted()) !== null && _b !== void 0 ? _b : false;
|
|
4714
6542
|
}
|
|
6543
|
+
/**
|
|
6544
|
+
* Returns the current publishing state of the streamer.
|
|
6545
|
+
*
|
|
6546
|
+
* @returns Current publishing state
|
|
6547
|
+
*/
|
|
4715
6548
|
getPublishState() {
|
|
4716
6549
|
var _a, _b;
|
|
4717
6550
|
return (_b = (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.getPublishState()) !== null && _b !== void 0 ? _b : exports.PublishState.NOT_INITIALIZED;
|
|
4718
6551
|
}
|
|
6552
|
+
/**
|
|
6553
|
+
* Returns the total time the stream has been publishing in milliseconds.
|
|
6554
|
+
*
|
|
6555
|
+
* @returns Publishing time in milliseconds
|
|
6556
|
+
*/
|
|
4719
6557
|
getPublishTime() {
|
|
4720
6558
|
var _a, _b;
|
|
4721
6559
|
return (_b = (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.getPublishTime()) !== null && _b !== void 0 ? _b : 0;
|
|
4722
6560
|
}
|
|
6561
|
+
/**
|
|
6562
|
+
* Starts publishing a stream with the given stream key.
|
|
6563
|
+
*
|
|
6564
|
+
* @param streamKey - Key identifying the stream to publish
|
|
6565
|
+
* @returns Boolean indicating if publishing was successfully initiated
|
|
6566
|
+
*/
|
|
4723
6567
|
publish(streamKey) {
|
|
4724
6568
|
var _a, _b;
|
|
4725
6569
|
return (_b = (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.publish(streamKey)) !== null && _b !== void 0 ? _b : false;
|
|
4726
6570
|
}
|
|
6571
|
+
/**
|
|
6572
|
+
* Stops publishing the current stream.
|
|
6573
|
+
*/
|
|
6574
|
+
unpublish() {
|
|
6575
|
+
var _a;
|
|
6576
|
+
(_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.unpublish();
|
|
6577
|
+
}
|
|
6578
|
+
/**
|
|
6579
|
+
* Returns the current state of input devices (camera and microphone).
|
|
6580
|
+
*
|
|
6581
|
+
* @returns Current state of input devices
|
|
6582
|
+
*/
|
|
4727
6583
|
getInputDevicesState() {
|
|
4728
6584
|
var _a, _b;
|
|
4729
6585
|
return (_b = (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.getInputDeviceState()) !== null && _b !== void 0 ? _b : exports.InputDevicesState.NOT_INITIALIZED;
|
|
4730
6586
|
}
|
|
4731
|
-
|
|
6587
|
+
/**
|
|
6588
|
+
* Returns the current state of the camera device.
|
|
6589
|
+
*
|
|
6590
|
+
* @returns Current camera device state
|
|
6591
|
+
*/
|
|
6592
|
+
getCameraState() {
|
|
4732
6593
|
var _a, _b;
|
|
4733
|
-
return (_b = (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.
|
|
6594
|
+
return (_b = (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.getCameraState()) !== null && _b !== void 0 ? _b : exports.DeviceState.NOT_INITIALIZED;
|
|
4734
6595
|
}
|
|
6596
|
+
/**
|
|
6597
|
+
* Returns the current state of the microphone device.
|
|
6598
|
+
*
|
|
6599
|
+
* @returns Current microphone device state
|
|
6600
|
+
*/
|
|
4735
6601
|
getMicrophoneState() {
|
|
4736
6602
|
var _a, _b;
|
|
4737
6603
|
return (_b = (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.getMicrophoneState()) !== null && _b !== void 0 ? _b : exports.DeviceState.NOT_INITIALIZED;
|
|
4738
6604
|
}
|
|
6605
|
+
/**
|
|
6606
|
+
* Clears saved device preferences from storage.
|
|
6607
|
+
*/
|
|
4739
6608
|
clearSavedDevices() {
|
|
4740
6609
|
var _a;
|
|
4741
6610
|
return (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.clearSavedDevices();
|
|
4742
6611
|
}
|
|
6612
|
+
/**
|
|
6613
|
+
* Randomizes saved device preferences (for testing purposes).
|
|
6614
|
+
*/
|
|
4743
6615
|
messSavedDevices() {
|
|
4744
6616
|
var _a;
|
|
4745
6617
|
return (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.messSavedDevices();
|
|
4746
6618
|
}
|
|
6619
|
+
/**
|
|
6620
|
+
* Checks if the stream is ready for publishing.
|
|
6621
|
+
*
|
|
6622
|
+
* @returns Boolean indicating if stream is ready
|
|
6623
|
+
*/
|
|
4747
6624
|
isStreamReady() {
|
|
4748
6625
|
var _a, _b;
|
|
4749
6626
|
return (_b = (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.isStreamReady()) !== null && _b !== void 0 ? _b : false;
|
|
4750
6627
|
}
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
6628
|
+
//------------------------------------------------------------------------//
|
|
6629
|
+
// CONTAINER
|
|
6630
|
+
//------------------------------------------------------------------------//
|
|
6631
|
+
/**
|
|
6632
|
+
* Attaches the streamer to a new parent container using either a container ID (string) or a reference to an HTMLElement.
|
|
6633
|
+
* If the instance is already attached, it will be moved to a new parent.
|
|
6634
|
+
*
|
|
6635
|
+
* @param container - Container ID (string) or HTMLElement reference
|
|
6636
|
+
* @returns Boolean indicating if attachment was successful
|
|
6637
|
+
*/
|
|
4755
6638
|
attachToContainer(container) {
|
|
4756
6639
|
var _a, _b;
|
|
4757
6640
|
let result = false;
|
|
4758
6641
|
if (this._initialized) return (_b = (_a = this._stageController) === null || _a === void 0 ? void 0 : _a.attachToParent(container)) !== null && _b !== void 0 ? _b : false;
|
|
4759
6642
|
return result;
|
|
4760
6643
|
}
|
|
6644
|
+
/**
|
|
6645
|
+
* Detaches the streamer from the current parent element, if possible.
|
|
6646
|
+
*
|
|
6647
|
+
* @returns Boolean indicating if detachment was successful
|
|
6648
|
+
*/
|
|
4761
6649
|
detachFromContainer() {
|
|
4762
6650
|
var _a, _b;
|
|
4763
6651
|
let result = false;
|
|
4764
6652
|
if (this._initialized) return (_b = (_a = this._stageController) === null || _a === void 0 ? void 0 : _a.detachFromParent()) !== null && _b !== void 0 ? _b : false;
|
|
4765
6653
|
return result;
|
|
4766
6654
|
}
|
|
6655
|
+
/**
|
|
6656
|
+
* Returns the current parent element of the streamer, or null if none exists.
|
|
6657
|
+
*
|
|
6658
|
+
* @returns Current container element or null
|
|
6659
|
+
*/
|
|
4767
6660
|
getContainer() {
|
|
4768
6661
|
var _a, _b;
|
|
4769
6662
|
return (_b = (_a = this._stageController) === null || _a === void 0 ? void 0 : _a.getParentElement()) !== null && _b !== void 0 ? _b : null;
|
|
4770
6663
|
}
|
|
6664
|
+
//------------------------------------------------------------------------//
|
|
6665
|
+
// SIZE & RESIZE
|
|
6666
|
+
//------------------------------------------------------------------------//
|
|
6667
|
+
/**
|
|
6668
|
+
* Sets a new width and height for the streamer. The values can be given as a number (in which case they are
|
|
6669
|
+
* treated as the number of pixels), or as a string ending with "px" (this will also be the number of pixels) or "%",
|
|
6670
|
+
* where the number is treated as a percentage of the parent container's value.
|
|
6671
|
+
*
|
|
6672
|
+
* @param width - Can be provided as number or a string with "%" or "px" suffix
|
|
6673
|
+
* @param height - Can be provided as number or a string with "%" or "px" suffix
|
|
6674
|
+
*/
|
|
4771
6675
|
setSize(width, height) {
|
|
4772
6676
|
if (this._initialized) this._stageController.setSize(width, height);else {
|
|
4773
6677
|
const parsedWidth = NumberUtilities.parseValue(width);
|
|
@@ -4778,6 +6682,13 @@
|
|
|
4778
6682
|
this._configManager.getSettingsData().getVideoData().videoHeightInPixels = parsedHeight.isPixels;
|
|
4779
6683
|
}
|
|
4780
6684
|
}
|
|
6685
|
+
/**
|
|
6686
|
+
* Sets a new width for the streamer. The value can be given as a number (in which case it is treated as the
|
|
6687
|
+
* number of pixels), or as a string ending with "px" (this will also be the number of pixels) or "%", where the
|
|
6688
|
+
* number is treated as a percentage of the parent container's value.
|
|
6689
|
+
*
|
|
6690
|
+
* @param width - Can be provided as number or a string with "%" or "px" suffix
|
|
6691
|
+
*/
|
|
4781
6692
|
setWidth(width) {
|
|
4782
6693
|
if (this._initialized) this._stageController.setWidth(width);else {
|
|
4783
6694
|
const parsedWidth = NumberUtilities.parseValue(width);
|
|
@@ -4785,6 +6696,13 @@
|
|
|
4785
6696
|
this._configManager.getSettingsData().getVideoData().videoWidthInPixels = parsedWidth.isPixels;
|
|
4786
6697
|
}
|
|
4787
6698
|
}
|
|
6699
|
+
/**
|
|
6700
|
+
* Sets a new height for the streamer. The value can be given as a number (in which case it is treated as the
|
|
6701
|
+
* number of pixels), or as a string ending with "px" (this will also be the number of pixels) or "%", where the
|
|
6702
|
+
* number is treated as a percentage of the parent container's value.
|
|
6703
|
+
*
|
|
6704
|
+
* @param height - Can be provided as number or a string with "%" or "px" suffix
|
|
6705
|
+
*/
|
|
4788
6706
|
setHeight(height) {
|
|
4789
6707
|
if (this._initialized) this._stageController.setHeight(height);else {
|
|
4790
6708
|
const parsedHeight = NumberUtilities.parseValue(height);
|
|
@@ -4792,18 +6710,33 @@
|
|
|
4792
6710
|
this._configManager.getSettingsData().getVideoData().videoHeightInPixels = parsedHeight.isPixels;
|
|
4793
6711
|
}
|
|
4794
6712
|
}
|
|
6713
|
+
/**
|
|
6714
|
+
* Returns current streamer width in pixels.
|
|
6715
|
+
*
|
|
6716
|
+
* @returns Current width in pixels
|
|
6717
|
+
*/
|
|
4795
6718
|
getWidth() {
|
|
4796
6719
|
if (this._initialized) return this._stageController.getContainerWidth();else {
|
|
4797
6720
|
if (this._configManager.getSettingsData().getVideoData().videoWidthInPixels) return this._configManager.getSettingsData().getVideoData().videoWidthValue;
|
|
4798
6721
|
}
|
|
4799
6722
|
return 0;
|
|
4800
6723
|
}
|
|
6724
|
+
/**
|
|
6725
|
+
* Returns current streamer height in pixels.
|
|
6726
|
+
*
|
|
6727
|
+
* @returns Current height in pixels
|
|
6728
|
+
*/
|
|
4801
6729
|
getHeight() {
|
|
4802
6730
|
if (this._initialized) return this._stageController.getContainerHeight();else {
|
|
4803
6731
|
if (this._configManager.getSettingsData().getVideoData().videoHeightInPixels) return this._configManager.getSettingsData().getVideoData().videoHeightValue;
|
|
4804
6732
|
}
|
|
4805
6733
|
return 0;
|
|
4806
6734
|
}
|
|
6735
|
+
/**
|
|
6736
|
+
* Changes the streamer scaling mode. Available modes include fill, letterbox, original, and crop.
|
|
6737
|
+
*
|
|
6738
|
+
* @param newMode - New scaling mode name (fill, letterbox, original, crop)
|
|
6739
|
+
*/
|
|
4807
6740
|
setScalingMode(newMode) {
|
|
4808
6741
|
if (this._stageController) {
|
|
4809
6742
|
this._stageController.setScalingMode(newMode);
|
|
@@ -4811,6 +6744,11 @@
|
|
|
4811
6744
|
this._configManager.getSettingsData().getVideoData().scalingMode = newMode;
|
|
4812
6745
|
}
|
|
4813
6746
|
}
|
|
6747
|
+
/**
|
|
6748
|
+
* Returns the current streamer scaling mode.
|
|
6749
|
+
*
|
|
6750
|
+
* @returns Current scaling mode
|
|
6751
|
+
*/
|
|
4814
6752
|
getScalingMode() {
|
|
4815
6753
|
if (this._stageController) {
|
|
4816
6754
|
return this._stageController.getScalingMode();
|
|
@@ -4818,11 +6756,20 @@
|
|
|
4818
6756
|
return this._configManager.getSettingsData().getVideoData().scalingMode;
|
|
4819
6757
|
}
|
|
4820
6758
|
}
|
|
6759
|
+
/**
|
|
6760
|
+
* Forces the streamer to recalculate its size based on parent internal dimensions.
|
|
6761
|
+
*/
|
|
4821
6762
|
updateToSize() {
|
|
4822
6763
|
if (this._initialized) {
|
|
4823
6764
|
this._stageController.handleResize();
|
|
4824
6765
|
}
|
|
4825
6766
|
}
|
|
6767
|
+
/**
|
|
6768
|
+
* Returns a promise that resolves with a screenshot of the video element as a blob, or null if taking the
|
|
6769
|
+
* screenshot was not possible.
|
|
6770
|
+
*
|
|
6771
|
+
* @returns Promise resolving to a Blob containing the screenshot or null
|
|
6772
|
+
*/
|
|
4826
6773
|
makeScreenshot() {
|
|
4827
6774
|
let canvas = document.createElement('canvas');
|
|
4828
6775
|
let context = canvas.getContext('2d');
|
|
@@ -4844,15 +6791,53 @@
|
|
|
4844
6791
|
}
|
|
4845
6792
|
});
|
|
4846
6793
|
}
|
|
6794
|
+
//------------------------------------------------------------------------//
|
|
6795
|
+
// GRAPHS
|
|
6796
|
+
//------------------------------------------------------------------------//
|
|
6797
|
+
/**
|
|
6798
|
+
* Creates a FPS performance graph in the specified location (container ID or reference). The graph is a
|
|
6799
|
+
* separate object that must be started using its start() method and stopped using its stop() method. The dimensions
|
|
6800
|
+
* of the graph depend on the dimensions of the specified container.
|
|
6801
|
+
*
|
|
6802
|
+
* @param container - Element ID or reference to HTMLElement
|
|
6803
|
+
* @returns FPS graph instance
|
|
6804
|
+
*/
|
|
4847
6805
|
createFPSGraph(container) {
|
|
4848
6806
|
return new FPSGraph(this, container);
|
|
4849
6807
|
}
|
|
6808
|
+
/**
|
|
6809
|
+
* Creates a bitrate performance graph in the specified location (container ID or reference). The graph is a
|
|
6810
|
+
* separate object that must be started using its start() method and stopped using its stop() method. The dimensions
|
|
6811
|
+
* of the graph depend on the dimensions of the specified container.
|
|
6812
|
+
*
|
|
6813
|
+
* @param container - Element ID or reference to HTMLElement
|
|
6814
|
+
* @returns Bitrate graph instance
|
|
6815
|
+
*/
|
|
4850
6816
|
createBitrateGraph(container) {
|
|
4851
6817
|
return new BitrateGraph(this, container);
|
|
4852
6818
|
}
|
|
6819
|
+
/**
|
|
6820
|
+
* Creates a microphone graph in the specified location (container ID or reference). The graph is a
|
|
6821
|
+
* separate object that must be started using its start() method and stopped using its stop() method. The dimensions
|
|
6822
|
+
* of the graph depend on the dimensions of the specified container.
|
|
6823
|
+
*
|
|
6824
|
+
* @param container - Element ID or reference to HTMLElement
|
|
6825
|
+
* @returns Bitrate graph instance
|
|
6826
|
+
*/
|
|
6827
|
+
createMicrophoneGraph(container) {
|
|
6828
|
+
return new MicrophoneGraph(this, container);
|
|
6829
|
+
}
|
|
6830
|
+
/**
|
|
6831
|
+
* Adds new graph to the internal collection of active graphs.
|
|
6832
|
+
*
|
|
6833
|
+
* @param newGraph - Graph instance to add
|
|
6834
|
+
*/
|
|
4853
6835
|
addGraph(newGraph) {
|
|
4854
6836
|
if (this._graphs != null) this._graphs.push(newGraph);
|
|
4855
6837
|
}
|
|
6838
|
+
/**
|
|
6839
|
+
* Stops all active performance graphs.
|
|
6840
|
+
*/
|
|
4856
6841
|
stopAllGraphs() {
|
|
4857
6842
|
if (this._graphs != null && this._graphs.length > 0) {
|
|
4858
6843
|
for (let i = 0; i < this._graphs.length; i++) {
|
|
@@ -4860,82 +6845,198 @@
|
|
|
4860
6845
|
}
|
|
4861
6846
|
}
|
|
4862
6847
|
}
|
|
6848
|
+
//------------------------------------------------------------------------//
|
|
6849
|
+
// FULLSCREEN
|
|
6850
|
+
//------------------------------------------------------------------------//
|
|
6851
|
+
/**
|
|
6852
|
+
* Enters fullscreen mode for the streamer container.
|
|
6853
|
+
*/
|
|
4863
6854
|
enterFullScreen() {
|
|
4864
6855
|
if (this._initialized && this._stageController) this._stageController.enterFullScreen();
|
|
4865
6856
|
}
|
|
6857
|
+
/**
|
|
6858
|
+
* Exits fullscreen mode.
|
|
6859
|
+
*/
|
|
4866
6860
|
exitFullScreen() {
|
|
4867
6861
|
if (this._initialized && this._stageController) this._stageController.exitFullScreen();
|
|
4868
6862
|
}
|
|
6863
|
+
/**
|
|
6864
|
+
* Returns true if the streamer is currently in fullscreen mode.
|
|
6865
|
+
*
|
|
6866
|
+
* @returns Boolean indicating fullscreen status
|
|
6867
|
+
*/
|
|
4869
6868
|
isFullScreenMode() {
|
|
4870
6869
|
if (this._initialized && this._stageController) return this._stageController.isFullScreenMode();
|
|
4871
6870
|
return false;
|
|
4872
6871
|
}
|
|
6872
|
+
//------------------------------------------------------------------------//
|
|
6873
|
+
// SIMPLE GETS & SETS
|
|
6874
|
+
//------------------------------------------------------------------------//
|
|
6875
|
+
/**
|
|
6876
|
+
* Returns the current stream key or null if none is set.
|
|
6877
|
+
*
|
|
6878
|
+
* @returns Current stream key or null
|
|
6879
|
+
*/
|
|
4873
6880
|
getStreamKey() {
|
|
4874
6881
|
var _a, _b, _c;
|
|
4875
6882
|
return (_c = (_b = (_a = this.getConfigManager()) === null || _a === void 0 ? void 0 : _a.getStreamData()) === null || _b === void 0 ? void 0 : _b.streamKey) !== null && _c !== void 0 ? _c : null;
|
|
4876
6883
|
}
|
|
6884
|
+
/**
|
|
6885
|
+
* Returns the Stats Controller instance which contains statistical data about streaming performance.
|
|
6886
|
+
*
|
|
6887
|
+
* @returns Stats controller instance or null
|
|
6888
|
+
*/
|
|
4877
6889
|
getStatsController() {
|
|
4878
6890
|
return this._statsController;
|
|
4879
6891
|
}
|
|
6892
|
+
/**
|
|
6893
|
+
* Returns the unique ID of this streamer instance. Each subsequent instance has a higher number.
|
|
6894
|
+
*
|
|
6895
|
+
* @returns Streamer instance ID
|
|
6896
|
+
*/
|
|
4880
6897
|
getStreamerID() {
|
|
4881
6898
|
return this._streamerID;
|
|
4882
6899
|
}
|
|
6900
|
+
/**
|
|
6901
|
+
* Returns the logger instance used by this streamer.
|
|
6902
|
+
*
|
|
6903
|
+
* @returns Logger instance
|
|
6904
|
+
*/
|
|
4883
6905
|
getLogger() {
|
|
4884
6906
|
return this._logger;
|
|
4885
6907
|
}
|
|
6908
|
+
/**
|
|
6909
|
+
* Returns the configuration manager for this streamer.
|
|
6910
|
+
*
|
|
6911
|
+
* @returns Config manager instance or null
|
|
6912
|
+
*/
|
|
4886
6913
|
getConfigManager() {
|
|
4887
6914
|
return this._configManager;
|
|
4888
6915
|
}
|
|
6916
|
+
/**
|
|
6917
|
+
* Returns the network controller which manages all server communication.
|
|
6918
|
+
*
|
|
6919
|
+
* @returns Network controller instance or null
|
|
6920
|
+
*/
|
|
4889
6921
|
getNetworkController() {
|
|
4890
6922
|
return this._networkController;
|
|
4891
6923
|
}
|
|
6924
|
+
/**
|
|
6925
|
+
* Returns the streamer controller which manages media stream operations.
|
|
6926
|
+
*
|
|
6927
|
+
* @returns Streamer controller instance or null
|
|
6928
|
+
*/
|
|
4892
6929
|
getStreamerController() {
|
|
4893
6930
|
return this._streamerController;
|
|
4894
6931
|
}
|
|
6932
|
+
/**
|
|
6933
|
+
* Returns the stage controller which manages visual presentation.
|
|
6934
|
+
*
|
|
6935
|
+
* @returns Stage controller instance or null
|
|
6936
|
+
*/
|
|
4895
6937
|
getStageController() {
|
|
4896
6938
|
return this._stageController;
|
|
4897
6939
|
}
|
|
6940
|
+
/**
|
|
6941
|
+
* Returns the storage manager which handles persistent data storage.
|
|
6942
|
+
*
|
|
6943
|
+
* @returns Storage manager instance or null
|
|
6944
|
+
*/
|
|
6945
|
+
getStorageManager() {
|
|
6946
|
+
return this._storageManager;
|
|
6947
|
+
}
|
|
6948
|
+
/**
|
|
6949
|
+
* Returns the HTML video element used by this streamer instance.
|
|
6950
|
+
*
|
|
6951
|
+
* @returns Video element or null
|
|
6952
|
+
*/
|
|
4898
6953
|
getVideoElement() {
|
|
4899
6954
|
var _a, _b, _c;
|
|
4900
6955
|
return (_c = (_b = (_a = this._stageController) === null || _a === void 0 ? void 0 : _a.getScreenElement()) === null || _b === void 0 ? void 0 : _b.getVideoElement()) !== null && _c !== void 0 ? _c : null;
|
|
4901
6956
|
}
|
|
6957
|
+
/**
|
|
6958
|
+
* Returns true if this streamer instance has already been initialized.
|
|
6959
|
+
*
|
|
6960
|
+
* @returns Boolean indicating initialization status
|
|
6961
|
+
*/
|
|
4902
6962
|
isInitialized() {
|
|
4903
6963
|
return this._initialized;
|
|
4904
6964
|
}
|
|
6965
|
+
/**
|
|
6966
|
+
* Returns the version of this streamer instance. The version is returned in the SemVer format (Major.Minor.Patch).
|
|
6967
|
+
*
|
|
6968
|
+
* @returns Streamer version string
|
|
6969
|
+
*/
|
|
4905
6970
|
getVersion() {
|
|
4906
6971
|
return this.STREAMER_VERSION;
|
|
4907
6972
|
}
|
|
6973
|
+
/**
|
|
6974
|
+
* Returns the development branch of this streamer (e.g., main, experimental).
|
|
6975
|
+
*
|
|
6976
|
+
* @returns Branch name string
|
|
6977
|
+
*/
|
|
4908
6978
|
getBranch() {
|
|
4909
6979
|
return this.STREAMER_BRANCH;
|
|
4910
6980
|
}
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
6981
|
+
//------------------------------------------------------------------------//
|
|
6982
|
+
// EVENT
|
|
6983
|
+
//------------------------------------------------------------------------//
|
|
6984
|
+
/**
|
|
6985
|
+
* Dispatches an event with the specified name and data.
|
|
6986
|
+
*
|
|
6987
|
+
* @param eventName - Name of the event to dispatch
|
|
6988
|
+
* @param event - Object containing event data
|
|
6989
|
+
*/
|
|
4914
6990
|
dispatchEvent(eventName, event) {
|
|
4915
6991
|
super.dispatchEvent(eventName, event);
|
|
4916
6992
|
}
|
|
6993
|
+
//------------------------------------------------------------------------//
|
|
6994
|
+
// CLEAN UP
|
|
6995
|
+
//------------------------------------------------------------------------//
|
|
6996
|
+
/**
|
|
6997
|
+
* Starts the streaming process.
|
|
6998
|
+
*
|
|
6999
|
+
* @returns Promise that resolves when streaming has started
|
|
7000
|
+
*/
|
|
4917
7001
|
start() {
|
|
4918
7002
|
var _a;
|
|
4919
7003
|
return __awaiter(this, void 0, void 0, function* () {
|
|
4920
7004
|
return (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.start();
|
|
4921
7005
|
});
|
|
4922
7006
|
}
|
|
7007
|
+
/**
|
|
7008
|
+
* Stops the streaming process.
|
|
7009
|
+
*/
|
|
4923
7010
|
stop() {
|
|
4924
7011
|
var _a;
|
|
4925
7012
|
return (_a = this._streamerController) === null || _a === void 0 ? void 0 : _a.stop();
|
|
4926
7013
|
}
|
|
7014
|
+
//------------------------------------------------------------------------//
|
|
7015
|
+
// CLEAN UP
|
|
7016
|
+
//------------------------------------------------------------------------//
|
|
7017
|
+
/**
|
|
7018
|
+
* Destroys this instance of StormStreamer, releasing all resources and disconnecting from the server.
|
|
7019
|
+
* After calling this method, the instance should not be used anymore.
|
|
7020
|
+
*/
|
|
4927
7021
|
destroy() {
|
|
4928
7022
|
var _a, _b, _c, _d;
|
|
4929
7023
|
this._logger.warning(this, "Destroying streamer instance, bye, bye!");
|
|
4930
7024
|
if (this.DEV_MODE && 'StormStreamerArray' in window) window.StormStreamerArray[this._streamerID] = null;
|
|
7025
|
+
// part1
|
|
4931
7026
|
this._initialized = false;
|
|
4932
7027
|
this._isRemoved = true;
|
|
7028
|
+
// part3
|
|
4933
7029
|
(_b = (_a = this._networkController) === null || _a === void 0 ? void 0 : _a.getConnection()) === null || _b === void 0 ? void 0 : _b.destroy();
|
|
4934
7030
|
(_c = this._streamerController) === null || _c === void 0 ? void 0 : _c.destroy();
|
|
4935
7031
|
(_d = this._stageController) === null || _d === void 0 ? void 0 : _d.destroy();
|
|
7032
|
+
// part2
|
|
4936
7033
|
this.removeAllEventListeners();
|
|
4937
7034
|
}
|
|
4938
7035
|
}
|
|
7036
|
+
/**
|
|
7037
|
+
* Next ID for the streamer instance. Each subsequent instance has a higher number.
|
|
7038
|
+
* @private
|
|
7039
|
+
*/
|
|
4939
7040
|
StormStreamer.NEXT_STREAMER_ID = 0;
|
|
4940
7041
|
|
|
4941
7042
|
function create(config) {
|