@stormstreaming/stormstreamer 1.0.0-rc.0 → 1.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stormstreaming/stormstreamer",
3
- "version": "1.0.0-rc.0",
3
+ "version": "1.0.0",
4
4
  "description": "A JavaScript library containing core webrtc streamer functionality for embedding live-video streams on a website. Part of StormStreaming Suite.",
5
5
  "author": "Web-Anatomy s.c. <contact@web-anatomy.com>",
6
6
  "main": "dist/iife/index.js",
@@ -0,0 +1,50 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Storm Streamer - AMD Test Page</title>
6
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>
7
+ </head>
8
+ <body>
9
+
10
+ <div id="storm_player_0">
11
+ <h1>Storm Streamer AMD - TestPage</h1>
12
+ <div id="videoContainer"></div>
13
+ </div>
14
+
15
+ <script>
16
+
17
+ const config = {
18
+ stream: {
19
+ serverList: [
20
+ {
21
+ host: "127.0.0.1",
22
+ application:"live",
23
+ port: 8080,
24
+ ssl: false
25
+ },
26
+ ],
27
+ streamKey:"test",
28
+ },
29
+ settings: {
30
+ autoStart: true,
31
+ video: {
32
+ scalingMode: "letterbox",
33
+ containerID: "videoContainer",
34
+ width:"1280px",
35
+ height:"720px",
36
+ },
37
+ }
38
+ }
39
+
40
+ requirejs(['../../../dist/amd/index'], function (storm) {
41
+
42
+ const stormInstance = new storm.create(config);
43
+ stormInstance.initialize();
44
+
45
+ });
46
+
47
+ </script>
48
+
49
+ </body>
50
+ </html>
@@ -0,0 +1,46 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <title>Storm Streamer - ESM TestPage</title>
5
+ <meta charset="UTF-8">
6
+ </head>
7
+ <body>
8
+
9
+ <div id="storm_player_0">
10
+ <h1>Storm Streamer ESM - TestPage</h1>
11
+ <div id="videoContainer"></div>
12
+ </div>
13
+
14
+ <script type="module">
15
+
16
+ const config = {
17
+ stream: {
18
+ serverList: [
19
+ {
20
+ host: "127.0.0.1",
21
+ application:"live",
22
+ port: 8080,
23
+ ssl: false
24
+ },
25
+ ],
26
+ streamKey:"test",
27
+ },
28
+ settings: {
29
+ autoStart: true,
30
+ video: {
31
+ scalingMode: "letterbox",
32
+ containerID: "videoContainer",
33
+ width:"1280px",
34
+ height:"720px",
35
+ },
36
+ }
37
+ }
38
+
39
+ import {StormStreamer} from "../../../dist/esm/index.js";
40
+
41
+ const storm = new StormStreamer(config)
42
+ storm.initialize();
43
+
44
+ </script>
45
+ </body>
46
+ </html>
@@ -0,0 +1,45 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <title>Storm Streamer - IIFE TestPage</title>
5
+ <meta charset="UTF-8">
6
+ <script src="../../dist/iife/index.js"></script>
7
+ </head>
8
+ <body>
9
+
10
+ <div id="storm_player_0">
11
+ <h1>Storm Streamer IIFE - TestPage</h1>
12
+ <div id="videoContainer"></div>
13
+ </div>
14
+
15
+ <script>
16
+
17
+ const config = {
18
+ stream: {
19
+ serverList: [
20
+ {
21
+ host: "127.0.0.1",
22
+ application:"live",
23
+ port: 8080,
24
+ ssl: false
25
+ },
26
+ ],
27
+ streamKey:"test",
28
+ },
29
+ settings: {
30
+ autoStart: true,
31
+ video: {
32
+ scalingMode: "letterbox",
33
+ containerID: "videoContainer",
34
+ width:"1280px",
35
+ height:"720px",
36
+ },
37
+ }
38
+ }
39
+
40
+ const storm = stormStreamer(config);
41
+ storm.initialize();
42
+
43
+ </script>
44
+ </body>
45
+ </html>
@@ -0,0 +1,492 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Storm Streamer DEVELOPER PAGE</title>
6
+ <script src="../dist/iife/index.js"></script>
7
+ </head>
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Courier+Prime:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
11
+ <style>
12
+ body {font-family: "Courier Prime", monospace;}
13
+ span {width:100%;float:left; font-size:10px}
14
+ button {margin:5px;padding:3px 6px; font-family: "Courier Prime", monospace;}
15
+ label {margin:-20px 0 -20px 0;position:absolute;display: block;background:white;padding-left:10px;padding-right:10px; font-family: "Courier Prime", monospace;font-style: italic;}
16
+ .selectWrapper {display: flex}
17
+ .selectWrapper label {position: relative;margin: 0;padding-top: 4px;float:left;font-size: 12px;font-style:normal;}
18
+ .selectWrapper select {float:left;position: relative}
19
+ .toolbox {padding:10px;margin-left:10px;position: relative;margin-top:20px;border:2px dashed grey}
20
+ .toolbox-wrapper {display:flex}
21
+ ul {margin-right:10px;display: block}
22
+ li { display: flex; flex-wrap: nowrap; align-items: center;font-size: 14px;font-style: normal;padding-bottom: 10px;}
23
+ li span { display: inline;font-size: 14px; font-weight: 600;}
24
+ .value {margin-left:7px}
25
+ </style>
26
+ <body>
27
+
28
+ <div id="storm_player_0">
29
+ <h1>Storm Streamer - DEVELOPER PAGE</h1>
30
+ <div id="main" style="width:1280px;height:720px;background:grey">
31
+ <div id="vContainer" style="background:red"></div>
32
+ </div>
33
+ </div>
34
+
35
+ <div id="vContainer2" style="position:fixed;left:0;top:0;width:30%;z-index:2;background:red"></div>
36
+ <div id="screenshotSample"></div>
37
+
38
+ <div class="toolbox-wrapper">
39
+ <div class="toolbox" style="width:100%;display: flex">
40
+ <label>Streamer</label>
41
+ <ul>
42
+ <li>StreamKey: <span id="streamKeyValue" class="value"></span></li>
43
+ <li>PublishState: <span id="publishStateValue" class="value"></span></li>
44
+ <li>DeviceState: <span id="deviceStateValue" class="value"></span></li>
45
+ <li>PublishDuration: <span id="publishDurationValue" class="value"></span></li>
46
+ <li>VideoWidth: <span id="videoWidthValue" class="value"></span></li>
47
+ <li>VideoHeight: <span id="videoHeightValue" class="value"></span></li>
48
+ </ul>
49
+ </div>
50
+ <div class="toolbox" style="width:100%;display: flex">
51
+ <label>Devices</label>
52
+ <ul>
53
+ <li>CameraState: <span id="cameraStateValue" class="value"></span></li>
54
+ <li>MicrophoneState: <span id="microphoneStateValue" class="value"></span></li>
55
+ <li>Selected Camera: <span id="cameraValue" class="value"></span></li>
56
+ <li>Selected Microphone: <span id="microphoneValue" class="value"></span></li>
57
+ <li>Microphone Muted: <span id="microphoneMutedValue" class="value"></span></li>
58
+ </ul>
59
+ </div>
60
+ <div class="toolbox" style="width:100%;display: flex">
61
+ <label>STREAM</label>
62
+ <ul>
63
+ <li>currentFPS: <span id="currentFPSValue" class="value"></span></li>
64
+ <li>currentFPS Graph: <div id="currentFPSGraph" style="width:100px;height:20px"></div></li>
65
+ <li>currentBitrate: <span id="currentBitrateValue" class="value"></span></li>
66
+ <li>currentBitrate Graph: <div id="currentBitrateGraph" style="width:100px;height:20px"></div></span></li>
67
+ <li>videoFrames: <span id="videoFramesCountValue" class="value"></span></li>
68
+ <li>audioFrames: <span id="audioFramesCountValue" class="value"></span></li>
69
+ </ul>
70
+ </div>
71
+ <div class="toolbox" style="width:100%;display: flex">
72
+ <label>INFO</label>
73
+ <ul>
74
+ <li>publishVBitrate: <span id="publishVBitrateValue" class="value"></span></li>
75
+ <li>publishABitrate: <span id="publishABitrateValue" class="value"></span></li>
76
+ <li>Microphone Graph: <div id="micGraph" style="width:100px;height:20px"></div></li>
77
+ </ul>
78
+ </div>
79
+ </div>
80
+
81
+ <div class="toolbox-wrapper">
82
+ <div class="toolbox">
83
+ <label>Publish</label>
84
+ <button onclick="storm.publish('test')">publish('test')</button>
85
+ <button onclick="storm.publish('test2')">publish('test2')</button>
86
+ <button onclick="storm.unpublish()">unpublish()</button>
87
+ <button onclick="storm.start()">start()</button>
88
+ <button onclick="storm.stop()">stop()</button>
89
+ <button onclick="storm.destroy()">destroy()</button>
90
+ <button onclick="console.log(storm.getPublishState())">getPublishState()</button>
91
+ <button onclick="console.log(storm.getDeviceState())">getDeviceState()</button>
92
+ </div>
93
+
94
+ <div class="toolbox">
95
+ <label>Sound</label>
96
+ <button onclick="storm.muteMicrophone(true)">muteMicrophone(true)</button>
97
+ <button onclick="storm.muteMicrophone(false)">muteMicrophone(false)</button>
98
+ <button onclick="storm.mute()">muteSound()</button>
99
+ <button onclick="storm.unmute()">unmuteSound()</button>
100
+ <meter id="low_sound" min="0" low="50" high="80" max="100" value="0"></meter>
101
+ <meter id="high_sound" min="0" low="50" high="80" max="100" value="0"></meter>
102
+ </div>
103
+
104
+ <div class="toolbox">
105
+ <label>Resize</label>
106
+ <button onclick="storm.setSize(640, 360)">resize(640, 360)</button>
107
+ <button onclick="storm.setSize(854, 480)">resize(854, 480)</button>
108
+ <button onclick="storm.setSize(1280, 720)">resize(1280, 720)</button>
109
+ <button onclick="storm.setWidth(360)">setWidth(360)</button>
110
+ <button onclick="storm.setWidth('50%')">setWidth('50%')</button>
111
+ <button onclick="storm.setWidth('100%')">setWidth('100%')</button>
112
+ <button onclick="storm.setHeight(180)">setHeight(180)</button>
113
+ <button onclick="storm.setHeight('50%')">setHeight('50%')</button>
114
+ <button onclick="storm.setHeight('100%')">setHeight('100%')</button>
115
+ <button onclick="console.log(storm.getWidth())">getWidth()</button>
116
+ <button onclick="console.log(storm.getHeight())">getHeight()</button>
117
+ <button onclick="storm.attachToContainer('vContainer')">attachToContainer('vContainer')</button>
118
+ <button onclick="storm.attachToContainer('vContainer2')">attachToContainer('vContainer2')</button>
119
+ <button onclick="storm.detachFromContainer()">detachFromContainer()</button>
120
+ </div>
121
+
122
+ <div class="toolbox">
123
+ <label>Camera List</label>
124
+ <button onclick="console.log(storm.getCurrentCamera())">getCurrentCamera()</button>
125
+ <button onclick="console.log(storm.getCurrentMicrophone())">getCurrentMicrophone()</button>
126
+ <button onclick="console.log(storm.getCameraList())">getCameraList()</button>
127
+ <button onclick="console.log(storm.getMicrophoneList())">getMicrophoneList()</button>
128
+ <button onclick="console.log(storm.getCamerState())">getCamerState()</button>
129
+ <button onclick="console.log(storm.getMicrophoneState())">getMicrophoneState()</button>
130
+ <button onclick="storm.clearSavedDevices()">clearSavedDevices()</button>
131
+ <button onclick="storm.messSavedDevices()">messSavedDevices()</button>
132
+ <div class="selectWrapper">
133
+ <label for="cameraList">Select Camera: </label>
134
+ <select id="cameraList"></select>
135
+ </div>
136
+ <div class="selectWrapper">
137
+ <label for="microphoneList">Select Microphone: </label>
138
+ <select id="microphoneList"></select>
139
+ </div>
140
+ </div>
141
+
142
+ </div>
143
+
144
+ <div class="toolbox-wrapper">
145
+ <div class="toolbox" style="width:50%">
146
+ <label>Player Log</label>
147
+ <div id="logContainer"></div>
148
+ </div>
149
+ <div class="toolbox" style="width:50%">
150
+ <label>Events recording</label>
151
+ <textarea id="events" rows="30" style="padding:10px;width: calc(100% - 20px)">Events:</textarea>
152
+ </div>
153
+ </div>
154
+
155
+ <script>
156
+
157
+ let config = {
158
+ stream: {
159
+ serverList: [ // list of streaming server, 2nd, 3rd etc. will be used as backup
160
+ {
161
+ host: "localhost", // host or ip to the streaming server
162
+ application:"webrtc", // application
163
+ port: 443, // server port
164
+ ssl: true // whenever SSL connection should be used or not
165
+ },
166
+ ],
167
+ },
168
+ settings: {
169
+ autoStart: true,
170
+ video: {
171
+ scalingMode: "letterbox",
172
+ containerID:"vContainer",
173
+ width:"100%",
174
+ aspectRatio:"16:9",
175
+ resizeDebounce:0,
176
+ },
177
+ audio: {
178
+ startVolume:50,
179
+ },
180
+ debug: {
181
+ console: {
182
+ enabled: true,
183
+ logTypes: ["INFO","ERROR", "TRACE", "WARNING", "SUCCESS"],
184
+ monoColor: false
185
+ },
186
+ container: {
187
+ enabled: true,
188
+ containerID: "logContainer",
189
+ logTypes: ["ERROR", "INFO", "TRACE", "WARNING","SUCCESS"],
190
+ monoColor: false
191
+ }
192
+ }
193
+ }
194
+ }
195
+
196
+ let storm = stormStreamer(config);
197
+
198
+ storm.addEventListener("streamKeyInUseInterval", function(event){
199
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - StreamKey already in use, restarting... ${event.count}/${event.maxCount}`);
200
+ })
201
+
202
+ storm.addEventListener("streamKeyInUse", function(event){
203
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - StreamKey already in use, restarting...`);
204
+ })
205
+
206
+ storm.addEventListener("publishMetadataUpdate", function(event){
207
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - Publish : ${event.metadata.streamWidth}x${event.metadata.streamHeight}`);
208
+ })
209
+
210
+ storm.addEventListener("inputDevicesInitialized", function(event){
211
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - Devices initialized successfully`);
212
+ })
213
+
214
+ storm.addEventListener("savedCameraNotFound", function(event){
215
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - Access to saved camera devices was denied, last device id: ${event.savedDeviceID}`);
216
+ })
217
+
218
+ storm.addEventListener("savedMicrophoneNotFound", function(event){
219
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - Access to saved microphone devices was denied, last device id: ${event.savedDeviceID}`);
220
+ })
221
+
222
+ storm.addEventListener("cameraAccessDenied", function(event){
223
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - Access to camera devices was denied`);
224
+ })
225
+
226
+ storm.addEventListener("microphoneAccessDenied", function(event){
227
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - Access to all microphone devices was denied`);
228
+ })
229
+
230
+ storm.addEventListener("inputAccessDenied", function(event){
231
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - Access to all input devices was denied`);
232
+ })
233
+
234
+ storm.addEventListener("publish", function(event){
235
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - Publish set to: `+event.streamKey);
236
+ document.getElementById("streamKeyValue").innerHTML = event.streamKey;
237
+ })
238
+
239
+ storm.addEventListener("publish", function(event){
240
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - Publish set to: `+event.streamKey);
241
+ document.getElementById("streamKeyValue").innerHTML = event.streamKey;
242
+ })
243
+
244
+ storm.addEventListener("unpublish", function(event){
245
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - Stream was unpublished`);
246
+ document.getElementById("streamKeyValue").innerHTML = "";
247
+ })
248
+
249
+ storm.addEventListener("noCameraFound", function(event){
250
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - No Camera has been found`);
251
+ })
252
+
253
+ storm.addEventListener("noMicrophoneFound", function(event){
254
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - No Microphone has been found`);
255
+ })
256
+
257
+ storm.addEventListener("playerReady", function(event){
258
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - Core Player is ready for interaction!`);
259
+ })
260
+
261
+ storm.addEventListener("microphoneStateChange", function(event){
262
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - Mute State Changed: ${event.isMuted}` );
263
+ })
264
+
265
+ storm.addEventListener("serverConnectionInitiate", function(event){
266
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - (serverConnectionInitiate) Starting connection to: ${event.serverURL}`);
267
+ })
268
+
269
+ storm.addEventListener("serverConnect", function(event){
270
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - (serverConnect) Successfully connected to: ${event.serverURL} | seqNum: ${event.sequenceNum} `);
271
+ })
272
+
273
+ storm.addEventListener("serverDisconnect", function(event){
274
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - serverDisconnect: ${event.serverURL} | seqNum: ${event.sequenceNum} ` );
275
+ })
276
+
277
+ storm.addEventListener("serverConnectionError", function(event){
278
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - (serverConnectionError) Could not connect to server: ${event.serverURL}`);
279
+ })
280
+
281
+ storm.addEventListener("allConnectionsFailed", function(event){
282
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - All servers failed!`);
283
+ })
284
+
285
+ storm.addEventListener("videoElementCreate", function(event){
286
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - videoElementCreate!`);
287
+ })
288
+
289
+ storm.addEventListener("fullScreenEnter", function(event){
290
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - fullScreenEnter!`);
291
+ })
292
+
293
+ storm.addEventListener("fullScreenExit", function(event){
294
+ functionAppend(`Streamer ID: ${event.ref.getStreamerID()} - fullScreenExit!`);
295
+ })
296
+
297
+ storm.addEventListener("soundMeter", function(event){
298
+
299
+ const lowSoundMeter = document.getElementById('low_sound');
300
+ const highSoundMeter = document.getElementById('high_sound');
301
+
302
+ lowSoundMeter.value = event.low*100;
303
+ highSoundMeter.value = event.high*100;
304
+
305
+ })
306
+
307
+ storm.addEventListener("deviceListUpdate", function(event){
308
+ console.log(event);
309
+ updateCameraList(event.cameraList);
310
+ updateMicrophoneList(event.microphoneList);
311
+
312
+ })
313
+
314
+ storm.initialize();
315
+ storm.publish("test");
316
+
317
+ const graph1 = storm.createBitrateGraph("currentBitrateGraph").start();
318
+ const graph2 = storm.createFPSGraph("currentFPSGraph").start();
319
+ const graph3 = storm.createMicrophoneGraph("micGraph").start();
320
+
321
+ function functionAppend(appender){
322
+ let allText = document.getElementById("events").value;
323
+ document.getElementById("events").value = appender+ "\r\n\r\n" +allText
324
+ }
325
+
326
+ document.getElementById('cameraList').addEventListener('change', () => {
327
+ console.log("setCamera: "+document.getElementById('cameraList').value);
328
+ storm.setCamera(document.getElementById('cameraList').value);
329
+ });
330
+
331
+ document.getElementById('microphoneList').addEventListener('change', () => {
332
+ storm.setMicrophone(document.getElementById('microphoneList').value);
333
+ });
334
+
335
+ function updateCameraList(cameras) {
336
+
337
+ const cameraList = document.getElementById('cameraList');
338
+ cameraList.innerHTML = '';
339
+
340
+ cameras.forEach(camera => {
341
+ const option = document.createElement('option');
342
+ option.value = camera.id;
343
+ option.textContent = camera.label;
344
+ cameraList.appendChild(option);
345
+ if(camera.isSelected){
346
+ document.getElementById("cameraValue").innerHTML = camera.label;
347
+ cameraList.value = camera.id;
348
+ }
349
+ });
350
+
351
+ }
352
+
353
+ function updateMicrophoneList(microphones) {
354
+
355
+ const micList = document.getElementById('microphoneList');
356
+ micList.innerHTML = '';
357
+
358
+ microphones.forEach(mic => {
359
+ const option = document.createElement('option');
360
+ option.value = mic.id;
361
+ option.textContent = mic.label;
362
+ micList.appendChild(option);
363
+ if(mic.isSelected){
364
+ document.getElementById("microphoneValue").innerHTML = mic.label;
365
+ micList.value = mic.id;
366
+ }
367
+ });
368
+
369
+ }
370
+
371
+ function formatSecondsWithMilliseconds(milliseconds) {
372
+
373
+ const hours = Math.floor(milliseconds / 3600000);
374
+ milliseconds %= 3600000;
375
+ const minutes = Math.floor(milliseconds / 60000);
376
+ milliseconds %= 60000;
377
+ const seconds = Math.floor(milliseconds / 1000);
378
+ const milisecondsLeft = milliseconds % 1000;
379
+
380
+ const formattedHours = hours < 10 ? '0' + hours : hours;
381
+ const formattedMinutes = minutes < 10 ? '0' + minutes : minutes;
382
+ const formattedSeconds = seconds < 10 ? '0' + seconds : seconds;
383
+ const formattedMilliseconds = milisecondsLeft.toString().padStart(3, '0');
384
+
385
+ return `${formattedHours}:${formattedMinutes}:${formattedSeconds}.${formattedMilliseconds}`;
386
+ }
387
+
388
+ setInterval(() => {
389
+
390
+ // STREAMER
391
+
392
+ // Stream Key (daj tutaj INPUT)
393
+ const streamKey = storm?.getStreamKey() ?? "None";
394
+ document.getElementById("streamKeyValue").innerHTML = streamKey;
395
+
396
+ // Publish State
397
+ const publishState = storm?.getPublishState() ?? "Unknown";
398
+ document.getElementById("publishStateValue").innerHTML = publishState;
399
+
400
+ // Device State
401
+ const deviceState = storm?.getInputDevicesState() ?? "Unknown";
402
+ document.getElementById("deviceStateValue").innerHTML = deviceState;
403
+
404
+ // Publish Duration
405
+ const now = new Date().getTime();
406
+ const publishTime = storm?.getPublishTime() ?? 0;
407
+ const publishDuration = formatSecondsWithMilliseconds(((publishTime === 0) ? 0 : now - publishTime));
408
+ document.getElementById("publishDurationValue").innerHTML = publishDuration;
409
+
410
+ // Video Width
411
+ const videoWidth = storm?.getStatsController().publishVideoWidth;
412
+ document.getElementById("videoWidthValue").innerHTML = videoWidth;
413
+
414
+ // Video Height
415
+ const videoHeight = storm?.getStatsController().publishVideoHeight;
416
+ document.getElementById("videoHeightValue").innerHTML = videoHeight;
417
+
418
+
419
+ // DEVICES
420
+
421
+
422
+ // Camera State
423
+ const cameraState = storm?.getCameraState() ?? "Unknown";
424
+ document.getElementById("cameraStateValue").innerHTML = cameraState;
425
+
426
+ // Microphone State
427
+ const microphoneState = storm?.getMicrophoneState() ?? "Unknown";
428
+ document.getElementById("microphoneStateValue").innerHTML = microphoneState;
429
+
430
+ // Selected Camera (daj tutaj INPUT jak w Stream Key)
431
+ const selectedCamera = storm?.getCurrentCamera()?.label ?? "None";
432
+ document.getElementById("cameraValue").innerHTML = selectedCamera;
433
+
434
+ // Selected Microphone (daj tutaj INPUT jak w Stream Key)
435
+ const selectedMicrophone = storm?.getCurrentMicrophone()?.label ?? "None";
436
+ document.getElementById("microphoneValue").innerHTML = selectedMicrophone;
437
+
438
+ // Is Muted
439
+ const isMicrophoneMuted = storm?.isMicrophoneMuted() ?? false;
440
+ document.getElementById("microphoneMutedValue").innerHTML = isMicrophoneMuted;
441
+
442
+ // STREAM
443
+
444
+ // Current FPS
445
+ const videoFPS = storm?.getStatsController().currentFPS ?? 0;
446
+ document.getElementById("currentFPSValue").innerHTML = videoFPS.toFixed(2);
447
+
448
+ // Current Bitrate
449
+ const bitrate = storm?.getStatsController().currentBitrate ?? 0;
450
+ document.getElementById("currentBitrateValue").innerHTML = bitrate;
451
+
452
+ // Delivered Video Frames
453
+ const videoFrames = storm?.getStatsController().deliveredVideoFrames ?? 0;
454
+ document.getElementById("videoFramesCountValue").innerHTML = videoFrames;
455
+
456
+ // Delivered Audio Frames
457
+ const audioFrames = storm?.getStatsController().deliveredAudioFrames ?? 0;
458
+ document.getElementById("audioFramesCountValue").innerHTML = audioFrames;
459
+
460
+
461
+ // INFO
462
+
463
+ // Publish VBitrate
464
+ const publishVBitrate = storm?.getStatsController().publishVideoBitrate ?? 0;
465
+ document.getElementById("publishVBitrateValue").innerHTML = publishVBitrate;
466
+
467
+ // Publish VBitrate
468
+ const publishABitrate = storm?.getStatsController().publishAudioBitrate ?? 0;
469
+ document.getElementById("publishABitrateValue").innerHTML = publishABitrate;
470
+
471
+
472
+ },100)
473
+
474
+
475
+ async function embedScreenshot() {
476
+ const blob = await storm.makeScreenshot(); // Używamy metody makeScreenshot z obiektu storm
477
+ const screenshotDiv = document.getElementById('screenshotSample');
478
+
479
+ if (blob) {
480
+ const imageUrl = URL.createObjectURL(blob); // Tworzymy URL z bloba
481
+ const imgElement = document.createElement('img'); // Tworzymy nowy element img
482
+ imgElement.src = imageUrl; // Ustawiamy źródło obrazu
483
+ screenshotDiv.innerHTML = ''; // Czyścimy poprzednią zawartość diva
484
+ screenshotDiv.appendChild(imgElement); // Dodajemy img do diva
485
+ } else {
486
+ screenshotDiv.innerHTML = '<p>Nie udało się uzyskać zrzutu ekranu.</p>'; // Informacja, gdy zrzut ekranu się nie powiedzie
487
+ }
488
+ }
489
+
490
+ </script>
491
+ </body>
492
+ </html>