@flashphoner/websdk 2.0.242 → 2.0.244

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.
@@ -1,4 +1,4 @@
1
- Web SDK - 2.0.242
1
+ Web SDK - 2.0.244
2
2
 
3
3
  [Download builds](https://docs.flashphoner.com/display/WEBSDK2EN/Web+SDK+release+notes)
4
4
 
@@ -0,0 +1,105 @@
1
+ /**
2
+ * HTML5 video playback statistics
3
+ */
4
+
5
+ /**
6
+ * HTML5 statistics item
7
+ *
8
+ * @returns {object}
9
+ * @constructor
10
+ */
11
+ const HTML5StatsItem = function() {
12
+ const statsItem = {
13
+ value: 0,
14
+ lastData: 0,
15
+ timestamp: 0,
16
+ init: function(value, data) {
17
+ statsItem.setValue(value);
18
+ statsItem.setLastData(data);
19
+ },
20
+ setValue: function(value) {
21
+ statsItem.value = value;
22
+ },
23
+ getValue: function() {
24
+ return statsItem.value;
25
+ },
26
+ setLastData: function(data, timestamp) {
27
+ statsItem.lastData = data;
28
+ statsItem.setTimestamp(timestamp);
29
+ },
30
+ getLastData: function() {
31
+ return statsItem.lastData;
32
+ },
33
+ setTimestamp: function(timestamp) {
34
+ statsItem.timestamp = timestamp || Date.now();
35
+ },
36
+ getTimestamp: function() {
37
+ return statsItem.timestamp;
38
+ },
39
+ elapsedSecs: function(timestamp) {
40
+ let now = timestamp || Date.now();
41
+ return (now - statsItem.timestamp) / 1000;
42
+ }
43
+ };
44
+ return statsItem;
45
+ }
46
+
47
+ const HTML5Stats = function(video) {
48
+ const stats = {
49
+ video: video || null,
50
+ width: 0,
51
+ height: 0,
52
+ bitrate: HTML5StatsItem(),
53
+ fps: HTML5StatsItem(),
54
+ init: function(video) {
55
+ stats.video = video;
56
+ stats.width = 0;
57
+ stats.height = 0;
58
+ stats.bitrate.init(0);
59
+ stats.fps.init(0);
60
+ },
61
+ collect: function() {
62
+ if (stats.video) {
63
+ let now = Date.now();
64
+ let quality = video.getVideoPlaybackQuality();
65
+
66
+ if (quality) {
67
+ let played = quality.totalVideoFrames - quality.droppedVideoFrames;
68
+ if (played !== stats.fps.getLastData()) {
69
+ stats.fps.setValue((played - stats.fps.getLastData()) / stats.fps.elapsedSecs(now));
70
+ stats.fps.setLastData(played, now);
71
+ }
72
+ } else {
73
+ stats.fps.setValue(undefined);
74
+ }
75
+
76
+ if (stats.video.webkitVideoDecodedByteCount !== undefined) {
77
+ let decoded = stats.video.webkitVideoDecodedByteCount;
78
+ stats.bitrate.setValue(Math.round((decoded - stats.bitrate.getLastData()) * 8 / stats.bitrate.elapsedSecs(now)));
79
+ stats.bitrate.setLastData(decoded, now);
80
+ } else {
81
+ stats.bitrate.setValue(undefined);
82
+ }
83
+
84
+ stats.width = stats.video.videoWidth;
85
+ stats.height = stats.video.videoHeight;
86
+
87
+ return true;
88
+ }
89
+ return false;
90
+ },
91
+ getWidth: function() {
92
+ return stats.width;
93
+ },
94
+ getHeight: function() {
95
+ return stats.height;
96
+ },
97
+ getFps: function() {
98
+ return stats.fps.getValue();
99
+ },
100
+ getBitrate: function() {
101
+ return stats.bitrate.getValue();
102
+ }
103
+ };
104
+ return stats;
105
+ }
@@ -457,7 +457,12 @@ function canWebkitFullScreen(video) {
457
457
  return canFullscreen;
458
458
  }
459
459
 
460
- // Helper function to set item text
460
+ /**
461
+ * Helper function to set item text
462
+ *
463
+ * @param id
464
+ * @param text
465
+ */
461
466
  const setText = function (id, text) {
462
467
  let item = document.getElementById(id);
463
468
  if (item) {
@@ -465,7 +470,12 @@ const setText = function (id, text) {
465
470
  }
466
471
  }
467
472
 
468
- // Helper functions to set/get an item value
473
+ /**
474
+ * Helper function to set an item value
475
+ *
476
+ * @param id
477
+ * @param value
478
+ */
469
479
  const setValue = function (id, value) {
470
480
  let item = document.getElementById(id);
471
481
  if (item) {
@@ -473,6 +483,12 @@ const setValue = function (id, value) {
473
483
  }
474
484
  }
475
485
 
486
+ /**
487
+ * Helper function to get an item value
488
+ *
489
+ * @param id
490
+ * @returns value
491
+ */
476
492
  const getValue = function (id) {
477
493
  let item = document.getElementById(id);
478
494
  if (item) {
@@ -481,7 +497,39 @@ const getValue = function (id) {
481
497
  return null;
482
498
  }
483
499
 
484
- // Helper functions to display/hide an item
500
+ /**
501
+ * Helper function to set/unset a checkbox
502
+ *
503
+ * @param id
504
+ * @param value
505
+ */
506
+ const setCheckbox = function (id, value) {
507
+ let item = document.getElementById(id);
508
+ if (item) {
509
+ item.checked = value;
510
+ }
511
+ }
512
+
513
+ /**
514
+ * Helper function to get a checkbox state
515
+ *
516
+ * @param id
517
+ * @returns value
518
+ */
519
+ const getCheckbox = function (id) {
520
+ let item = document.getElementById(id);
521
+ if (item) {
522
+ return item.checked;
523
+ }
524
+ return null;
525
+ }
526
+
527
+
528
+ /**
529
+ * Helper function to display an item
530
+ *
531
+ * @param id
532
+ */
485
533
  const showItem = function(id) {
486
534
  let item = document.getElementById(id);
487
535
  if (item) {
@@ -489,6 +537,11 @@ const showItem = function(id) {
489
537
  }
490
538
  }
491
539
 
540
+ /**
541
+ * Helper function to hide an item
542
+ *
543
+ * @param id
544
+ */
492
545
  const hideItem = function(id) {
493
546
  let item = document.getElementById(id);
494
547
  if (item) {
@@ -496,7 +549,11 @@ const hideItem = function(id) {
496
549
  }
497
550
  }
498
551
 
499
- // Helper functions to disable/enable an item
552
+ /**
553
+ * Helper function to disable an item
554
+ *
555
+ * @param id
556
+ */
500
557
  const disableItem = function(id) {
501
558
  let item = document.getElementById(id);
502
559
  if (item) {
@@ -504,6 +561,11 @@ const disableItem = function(id) {
504
561
  }
505
562
  }
506
563
 
564
+ /**
565
+ * Helper function to enable an item
566
+ *
567
+ * @param id
568
+ */
507
569
  const enableItem = function(id) {
508
570
  let item = document.getElementById(id);
509
571
  if (item) {
@@ -511,7 +573,14 @@ const enableItem = function(id) {
511
573
  }
512
574
  }
513
575
 
514
- // Set an event handler
576
+ /**
577
+ * Set an event handler
578
+ *
579
+ * @param id
580
+ * @param event
581
+ * @param handler
582
+ * @param previous
583
+ */
515
584
  const setHandler = function (id, event, handler, previous = null) {
516
585
  let item = document.getElementById(id);
517
586
  if (item) {
@@ -522,7 +591,13 @@ const setHandler = function (id, event, handler, previous = null) {
522
591
  }
523
592
  }
524
593
 
525
- // Find a closest item
594
+ /**
595
+ * Find a closest item
596
+ *
597
+ * @param id
598
+ * @param selector
599
+ * @returns {null}
600
+ */
526
601
  const closest = function (id, selector) {
527
602
  let currentElement = document.getElementById(id);
528
603
  let returnElement = null;
@@ -534,3 +609,17 @@ const closest = function (id, selector) {
534
609
 
535
610
  return returnElement;
536
611
  }
612
+
613
+ /**
614
+ * Display object properties fro debugging purposes
615
+ *
616
+ * @param object
617
+ */
618
+ const showProps = function (object) {
619
+ console.log("-------------------------------object begin");
620
+ for (const property in object) {
621
+ console.log(`${property}: ${object[property]}`);
622
+ }
623
+ console.log("-------------------------------object end");
624
+
625
+ }
@@ -8,12 +8,9 @@
8
8
  <title>HLS.JS Player Minimal</title>
9
9
  <script type="text/javascript" src="../../../../flashphoner.js"></script>
10
10
  <script type="text/javascript" src="hls.min.js"></script>
11
- <script type="text/javascript" src="../../dependencies/jquery/jquery-1.12.0.js"></script>
12
- <script type="text/javascript" src="../../dependencies/jquery/jquery-ui.js"></script>
13
11
  <script type="text/javascript" src="../../dependencies/js/utils.js"></script>
12
+ <script type="text/javascript" src="../../dependencies/js/stats.js"></script>
14
13
  <script type="text/javascript" src="hls-js-player.js"></script>
15
- <!-- Bootstrap JS -->
16
- <script src="../../dependencies/bootstrap/js/bootstrap.js"></script>
17
14
  </head>
18
15
  <body onload="loadPlayerPage()">
19
16
  <div id="playerPage" class="container">
@@ -1,43 +1,82 @@
1
- var Browser = Flashphoner.Browser;
2
- var remoteVideo = null;
3
- var hlsPlayer = null;
1
+ const Browser = Flashphoner.Browser;
2
+ const STATS_INTERVAL = 1000;
3
+ let remoteVideo = null;
4
+ let hlsPlayer = null;
5
+ let playSrc = getUrlParam("src");
6
+ let autoplay = eval(getUrlParam("autoplay")) || false;
7
+ let llHlsEnabled = eval(getUrlParam("llhls")) || false;
8
+ let playbackStats = null;
4
9
 
5
- function loadPlayerPage() {
6
- $("#playerPage").load("../hls-player/player-page.html", initPage );
10
+ const loadPlayerPage = function() {
11
+ loadPage("../hls-player/player-page.html", "playerPage", initPage );
7
12
  }
8
13
 
9
- function initPage() {
10
- $("#header").text("HLS.JS Player Minimal");
11
- $("#urlServer").val(getHLSUrl());
12
- $("#applyBtn").prop('disabled', true).text("Play").off('click').click(playBtnClick);
14
+ const loadPage = function(page, containerId, onLoad) {
15
+ fetch(page).then(function (response) {
16
+ if (response.ok) {
17
+ return response.text();
18
+ }
19
+ throw response;
20
+ }).then(function (text) {
21
+ let container = document.getElementById(containerId);
22
+ container.innerHTML = text;
23
+ onLoad();
24
+ });
25
+ }
26
+
27
+ const initPage = function() {
28
+ if (playSrc) {
29
+ setValue("fullLink", decodeURIComponent(playSrc));
30
+ } else if (autoplay) {
31
+ console.warn("No HLS URL set, autoplay disabled");
32
+ autoplay = false;
33
+ }
34
+ if (llHlsEnabled) {
35
+ setCheckbox("llHlsEnabled", llHlsEnabled);
36
+ }
37
+ remoteVideo = document.getElementById('remoteVideo');
13
38
  if (Hls.isSupported()) {
14
39
  console.log("Using HLS.JS " + Hls.version);
15
- $("#applyBtn").prop('disabled', false);
40
+ if (autoplay) {
41
+ // There should not be any visible item on the page unless player
42
+ hideAllToAutoplay();
43
+ // The player should use all available page width
44
+ setUpPlayerItem(true);
45
+ // The player should be muted to automatically start playback
46
+ initVideoPlayer(remoteVideo, true);
47
+ playBtnClick();
48
+ } else {
49
+ setText("header", "HLS.JS Player Minimal");
50
+ showItem("llHlsMode");
51
+ displayCommonItems();
52
+ setUpButtons();
53
+ enablePlaybackStats();
54
+ // The player should have a maximum fixed size
55
+ setUpPlayerItem(false);
56
+ // The player can be unmuted because user should click Play button
57
+ initVideoPlayer(remoteVideo, false);
58
+ }
16
59
  } else {
17
- $("#notifyFlash").text("Your browser doesn't support MSE technology required to play video");
60
+ setText("notifyFlash", "Your browser doesn't support MSE technology required to play video");
61
+ disableItem("applyBtn");
62
+ toggleInputs(false);
18
63
  }
19
- remoteVideo = document.getElementById('remoteVideo');
20
- remoteVideo.style ="background-color: lightgrey;";
21
- $('#llHlsMode').show();
22
64
  }
23
65
 
24
66
 
25
- function playBtnClick() {
26
- if (validateForm()) {
27
- var llHlsEnabled = $('#llHlsEnabled').is(":checked");
28
- var streamName = $('#playStream').val();
29
- streamName = encodeURIComponent(streamName);
30
- var videoSrc = $("#urlServer").val() + '/' + streamName + '/' + streamName + '.m3u8';
31
- var key = $('#key').val();
32
- var token = $("#token").val();
33
- if (key.length > 0 && token.length > 0) {
34
- videoSrc += "?" + key + "=" + token;
35
- }
67
+ const playBtnClick = function() {
68
+ let videoSrc = getVideoSrc(getValue("fullLink"));
69
+ if (videoSrc) {
70
+ llHlsEnabled = getCheckbox("llHlsEnabled");
36
71
  hlsPlayer = new Hls(getHlsConfig(llHlsEnabled));
37
72
  hlsPlayer.on(Hls.Events.MANIFEST_PARSED, function() {
38
73
  console.log("Play with HLS.js");
39
74
  remoteVideo.play();
40
75
  });
76
+ remoteVideo.onplaying = () => {
77
+ console.log("playing event fired");
78
+ displayPermalink(videoSrc);
79
+ }
41
80
  hlsPlayer.loadSource(videoSrc);
42
81
  hlsPlayer.attachMedia(remoteVideo);
43
82
  onStarted();
@@ -45,8 +84,8 @@ function playBtnClick() {
45
84
  }
46
85
 
47
86
 
48
- function getHlsConfig(llHlsEnabled) {
49
- var config = {
87
+ const getHlsConfig = function(llHlsEnabled) {
88
+ let config = {
50
89
  lowLatencyMode: false,
51
90
  enableWorker: true,
52
91
  backBufferLength: 90,
@@ -71,7 +110,7 @@ function getHlsConfig(llHlsEnabled) {
71
110
  }
72
111
 
73
112
 
74
- function stopBtnClick() {
113
+ const stopBtnClick = function() {
75
114
  if (hlsPlayer != null) {
76
115
  console.log("Stop HLS segments loading");
77
116
  hlsPlayer.stopLoad();
@@ -88,53 +127,219 @@ function stopBtnClick() {
88
127
  }
89
128
 
90
129
 
91
- function onStarted() {
92
- $("#urlServer").prop('disabled', true);
93
- $("#playStream").prop('disabled', true);
94
- $("#key").prop('disabled', true);
95
- $("#token").prop('disabled', true);
96
- $("#player").prop('disabled', true);
97
- $('#llHlsEnabled').prop('disabled', true);
98
- $("#applyBtn").prop('disabled', false).text("Stop").off('click').click(stopBtnClick);
130
+ const onStarted = function() {
131
+ if (!autoplay) {
132
+ toggleInputs(false);
133
+ enableItem("applyBtn");
134
+ hideItem("permalink");
135
+ setText("applyBtn", "Stop");
136
+ setHandler("applyBtn", "click", stopBtnClick, playBtnClick);
137
+ startPlaybackStats();
138
+ }
99
139
  }
100
140
 
101
141
 
102
142
  function onStopped() {
103
- $("#urlServer").prop('disabled', false);
104
- $("#playStream").prop('disabled', false);
105
- $("#key").prop('disabled', false);
106
- $("#token").prop('disabled', false);
107
- $("#player").prop('disabled', false);
108
- $('#llHlsEnabled').prop('disabled', false);
109
- $("#applyBtn").prop('disabled', false).text("Play").off('click').click(playBtnClick);
143
+ if (!autoplay) {
144
+ toggleInputs(true);
145
+ enableItem("applyBtn");
146
+ setText("applyBtn", "Play");
147
+ setHandler("applyBtn", "click", playBtnClick, stopBtnClick);
148
+ stopPlaybackStats();
149
+ }
110
150
  }
111
151
 
112
152
 
113
- function validateForm() {
114
- var valid = true;
115
- if (!$("#urlServer").val().length) {
116
- highlightInput($("#urlServer"));
153
+ const validateForm = function() {
154
+ let valid = validateInput("urlServer");
155
+ if (valid) {
156
+ valid = validateInput("playStream");
157
+ }
158
+ return valid;
159
+ }
160
+
161
+ const validateInput = function(id) {
162
+ let value = getValue(id);
163
+ let valid = true;
164
+ if (!value || !value.length) {
165
+ highlightInput(id);
117
166
  valid = false;
118
167
  } else {
119
- removeHighlight($("#urlServer"));
168
+ removeHighlight(id);
120
169
  }
121
- if (!$("#playStream").val().length) {
122
- highlightInput($("#playStream"));
123
- valid = false;
170
+ return valid;
171
+ }
172
+
173
+ const highlightInput = function(input) {
174
+ let item = document.getElementById(input);
175
+ if (item) {
176
+ let parent = closest(input,'.form-group');
177
+ if (parent) {
178
+ parent.classList.add("has-error");
179
+ }
180
+ }
181
+ }
182
+
183
+
184
+ const removeHighlight = function(input) {
185
+ let item = document.getElementById(input);
186
+ if (item) {
187
+ let parent = closest(input,'.form-group');
188
+ if (parent) {
189
+ parent.classList.remove("has-error");
190
+ }
191
+ }
192
+ }
193
+
194
+ const initVideoPlayer = function(video, muted) {
195
+ if (video) {
196
+ video.style.backgroundColor = "black";
197
+ video.muted = muted;
198
+ }
199
+ }
200
+
201
+ const setUpButtons = function() {
202
+ setHandler("applyBtn", "click", playBtnClick);
203
+ }
204
+
205
+
206
+ const toggleInputs = function(enable) {
207
+ if (enable) {
208
+ enableItem("urlServer");
209
+ enableItem("playStream");
210
+ enableItem("key");
211
+ enableItem("token");
212
+ enableItem("player");
213
+ enableItem("llHlsEnabled");
124
214
  } else {
125
- removeHighlight($("#playStream"));
215
+ disableItem("urlServer");
216
+ disableItem("playStream");
217
+ disableItem("key");
218
+ disableItem("token");
219
+ disableItem("player");
220
+ disableItem("llHlsEnabled");
126
221
  }
222
+ }
127
223
 
128
- return valid;
129
-
224
+ const getVideoSrc = function(src) {
225
+ let videoSrc = src;
226
+ if (validateForm()) {
227
+ let streamName = getValue('playStream');
228
+ streamName = encodeURIComponent(streamName);
229
+ videoSrc = getValue("urlServer") + '/' + streamName + '/' + streamName + '.m3u8';
230
+ let key = getValue('key');
231
+ let token = getValue("token");
232
+ if (key.length > 0 && token.length > 0) {
233
+ videoSrc += "?" + key + "=" + token;
234
+ }
235
+ }
236
+ setValue("fullLink", videoSrc);
237
+ return videoSrc;
238
+ }
239
+
240
+ const displayPermalink = function(src) {
241
+ if (!autoplay) {
242
+ const permalinkId = "permalink";
243
+ let videoSrc = encodeURIComponent(src);
244
+ let linkObject = document.getElementById(permalinkId);
245
+ let href = window.location.href.split("?")[0] + "?llhls=" + llHlsEnabled + "&src=" + videoSrc;
246
+ linkObject.href = href;
247
+ showItem(permalinkId);
248
+ }
249
+ }
250
+
251
+ const hideAllToAutoplay = function() {
252
+ hideItem("header");
253
+ hideItem("notifyFlash");
254
+ hideItem("fieldset");
255
+ hideItem("stats");
256
+ }
257
+
258
+ const displayCommonItems = function() {
259
+ setValue("urlServer", getHLSUrl());
260
+ hideItem("permalink");
261
+ enableItem("applyBtn");
262
+ setText("applyBtn", "Play");
130
263
  }
131
264
 
265
+ const setUpPlayerItem = function(fillPage) {
266
+ let videoContainer = document.getElementById('videoContainer');
267
+ let playerPage = document.getElementById('playerPage');
132
268
 
133
- function highlightInput(input) {
134
- input.closest('.form-group').addClass("has-error");
269
+ if (fillPage) {
270
+ playerPage.classList.remove("container");
271
+ videoContainer.style.marginTop = "0px";
272
+ videoContainer.style.width = "100vw";
273
+ videoContainer.style.height = "100vh";
274
+ videoContainer.style.maxWidth = "available";
275
+ videoContainer.style.maxHeight = "available";
276
+ } else {
277
+ videoContainer.style.maxWidth = "852px";
278
+ videoContainer.style.maxHeight = "480px";
279
+ }
135
280
  }
136
281
 
282
+ const enablePlaybackStats = function() {
283
+ if (!autoplay && !playbackStats) {
284
+ playbackStats = PlaybackStats(STATS_INTERVAL);
285
+ }
286
+ }
137
287
 
138
- function removeHighlight(input) {
139
- input.closest('.form-group').removeClass("has-error");
288
+ const startPlaybackStats = function() {
289
+ if (!autoplay && playbackStats) {
290
+ playbackStats.start();
291
+ }
140
292
  }
293
+
294
+ const stopPlaybackStats = function() {
295
+ if (!autoplay && playbackStats) {
296
+ playbackStats.stop();
297
+ }
298
+ }
299
+
300
+ const PlaybackStats = function(interval) {
301
+ const playbackStats = {
302
+ interval: interval || STATS_INTERVAL,
303
+ timer: null,
304
+ stats: null,
305
+ start: function() {
306
+ let video = remoteVideo;
307
+
308
+ playbackStats.stop();
309
+ stats = HTML5Stats(video);
310
+ playbackStats.timer = setInterval(playbackStats.displayStats, playbackStats.interval);
311
+ setText("videoWidth", "N/A");
312
+ setText("videoHeight", "N/A");
313
+ setText("videoRate", "N/A");
314
+ setText("videoFps", "N/A");
315
+ showItem("stats");
316
+ },
317
+ stop: function() {
318
+ if (playbackStats.timer) {
319
+ clearInterval(playbackStats.timer);
320
+ playbackStats.timer = null;
321
+ }
322
+ playbackStats.stats = null;
323
+ hideItem("stats");
324
+ },
325
+ displayStats: function() {
326
+ if (stats.collect()) {
327
+ let width = stats.getWidth();
328
+ let height = stats.getHeight();
329
+ let bitrate = stats.getBitrate();
330
+ let fps = stats.getFps();
331
+
332
+ setText("videoWidth", width);
333
+ setText("videoHeight", height);
334
+
335
+ if (bitrate !== undefined) {
336
+ setText("videoRate", Math.round(bitrate));
337
+ }
338
+ if (fps !== undefined) {
339
+ setText("videoFps", fps.toFixed(1));
340
+ }
341
+ }
342
+ }
343
+ };
344
+ return playbackStats;
345
+ }
@@ -7,12 +7,9 @@
7
7
  <link rel="stylesheet" href="hls-native.css">
8
8
  <title>HLS Native Player Minimal</title>
9
9
  <script type="text/javascript" src="../../../../flashphoner.js"></script>
10
- <script type="text/javascript" src="../../dependencies/jquery/jquery-1.12.0.js"></script>
11
- <script type="text/javascript" src="../../dependencies/jquery/jquery-ui.js"></script>
12
10
  <script type="text/javascript" src="../../dependencies/js/utils.js"></script>
11
+ <script type="text/javascript" src="../../dependencies/js/stats.js"></script>
13
12
  <script type="text/javascript" src="hls-native.js"></script>
14
- <!-- Bootstrap JS -->
15
- <script src="../../dependencies/bootstrap/js/bootstrap.js"></script>
16
13
  </head>
17
14
  <body onload="loadPlayerPage()">
18
15
  <div id="playerPage" class="container">