@flashphoner/websdk 2.0.242 → 2.0.243

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.243
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,35 +1,54 @@
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 playbackStats = null;
6
+
7
+ const loadPlayerPage = function() {
8
+ loadPage("../hls-player/player-page.html", "playerPage", initPage );
9
+ }
4
10
 
5
- function loadPlayerPage() {
6
- $("#playerPage").load("../hls-player/player-page.html", initPage );
11
+ const loadPage = function(page, containerId, onLoad) {
12
+ fetch(page).then(function (response) {
13
+ if (response.ok) {
14
+ return response.text();
15
+ }
16
+ throw response;
17
+ }).then(function (text) {
18
+ let container = document.getElementById(containerId);
19
+ container.innerHTML = text;
20
+ onLoad();
21
+ });
7
22
  }
8
23
 
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);
24
+ const initPage = function() {
25
+ setText("header", "HLS.JS Player Minimal");
26
+ setValue("urlServer", getHLSUrl());
27
+ setText("applyBtn", "Play");
28
+ setHandler("applyBtn", "click", playBtnClick);
29
+ remoteVideo = document.getElementById('remoteVideo');
30
+ remoteVideo.style ="background-color: lightgrey;";
13
31
  if (Hls.isSupported()) {
14
32
  console.log("Using HLS.JS " + Hls.version);
15
- $("#applyBtn").prop('disabled', false);
33
+ enableItem("applyBtn");
34
+ showItem("llHlsMode");
35
+ playbackStats = PlaybackStats(STATS_INTERVAL);
16
36
  } else {
17
- $("#notifyFlash").text("Your browser doesn't support MSE technology required to play video");
37
+ setText("notifyFlash", "Your browser doesn't support MSE technology required to play video");
38
+ disableItem("applyBtn");
39
+ toggleInputs(false);
18
40
  }
19
- remoteVideo = document.getElementById('remoteVideo');
20
- remoteVideo.style ="background-color: lightgrey;";
21
- $('#llHlsMode').show();
22
41
  }
23
42
 
24
43
 
25
- function playBtnClick() {
44
+ const playBtnClick = function() {
26
45
  if (validateForm()) {
27
- var llHlsEnabled = $('#llHlsEnabled').is(":checked");
28
- var streamName = $('#playStream').val();
46
+ let llHlsEnabled = getCheckbox("llHlsEnabled");
47
+ let streamName = getValue("playStream");
29
48
  streamName = encodeURIComponent(streamName);
30
- var videoSrc = $("#urlServer").val() + '/' + streamName + '/' + streamName + '.m3u8';
31
- var key = $('#key').val();
32
- var token = $("#token").val();
49
+ let videoSrc = getValue("urlServer") + '/' + streamName + '/' + streamName + '.m3u8';
50
+ let key = getValue('key');
51
+ let token = getValue("token");
33
52
  if (key.length > 0 && token.length > 0) {
34
53
  videoSrc += "?" + key + "=" + token;
35
54
  }
@@ -45,8 +64,8 @@ function playBtnClick() {
45
64
  }
46
65
 
47
66
 
48
- function getHlsConfig(llHlsEnabled) {
49
- var config = {
67
+ const getHlsConfig = function(llHlsEnabled) {
68
+ let config = {
50
69
  lowLatencyMode: false,
51
70
  enableWorker: true,
52
71
  backBufferLength: 90,
@@ -71,7 +90,7 @@ function getHlsConfig(llHlsEnabled) {
71
90
  }
72
91
 
73
92
 
74
- function stopBtnClick() {
93
+ const stopBtnClick = function() {
75
94
  if (hlsPlayer != null) {
76
95
  console.log("Stop HLS segments loading");
77
96
  hlsPlayer.stopLoad();
@@ -88,53 +107,126 @@ function stopBtnClick() {
88
107
  }
89
108
 
90
109
 
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);
110
+ const onStarted = function() {
111
+ toggleInputs(false);
112
+ enableItem("applyBtn");
113
+ setText("applyBtn", "Stop");
114
+ setHandler("applyBtn", "click", stopBtnClick, playBtnClick);
115
+ playbackStats.start();
99
116
  }
100
117
 
101
118
 
102
119
  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);
120
+ toggleInputs(true);
121
+ enableItem("applyBtn");
122
+ setText("applyBtn", "Play");
123
+ setHandler("applyBtn", "click", playBtnClick, stopBtnClick);
124
+ playbackStats.stop();
110
125
  }
111
126
 
112
127
 
113
- function validateForm() {
114
- var valid = true;
115
- if (!$("#urlServer").val().length) {
116
- highlightInput($("#urlServer"));
117
- valid = false;
118
- } else {
119
- removeHighlight($("#urlServer"));
128
+ const validateForm = function() {
129
+ let valid = validateInput("urlServer");
130
+ if (valid) {
131
+ valid = validateInput("playStream");
120
132
  }
121
- if (!$("#playStream").val().length) {
122
- highlightInput($("#playStream"));
133
+ return valid;
134
+ }
135
+
136
+ const validateInput = function(id) {
137
+ let value = getValue(id);
138
+ let valid = true;
139
+ if (!value || !value.length) {
140
+ highlightInput(id);
123
141
  valid = false;
124
142
  } else {
125
- removeHighlight($("#playStream"));
143
+ removeHighlight(id);
126
144
  }
127
-
128
145
  return valid;
129
-
130
146
  }
131
147
 
132
-
133
- function highlightInput(input) {
134
- input.closest('.form-group').addClass("has-error");
148
+ const highlightInput = function(input) {
149
+ let item = document.getElementById(input);
150
+ if (item) {
151
+ let parent = closest(input,'.form-group');
152
+ if (parent) {
153
+ parent.classList.add("has-error");
154
+ }
155
+ }
135
156
  }
136
157
 
137
158
 
138
- function removeHighlight(input) {
139
- input.closest('.form-group').removeClass("has-error");
159
+ const removeHighlight = function(input) {
160
+ let item = document.getElementById(input);
161
+ if (item) {
162
+ let parent = closest(input,'.form-group');
163
+ if (parent) {
164
+ parent.classList.remove("has-error");
165
+ }
166
+ }
167
+ }
168
+
169
+ const toggleInputs = function(enable) {
170
+ if (enable) {
171
+ enableItem("urlServer");
172
+ enableItem("playStream");
173
+ enableItem("key");
174
+ enableItem("token");
175
+ enableItem("player");
176
+ enableItem("llHlsEnabled");
177
+ } else {
178
+ disableItem("urlServer");
179
+ disableItem("playStream");
180
+ disableItem("key");
181
+ disableItem("token");
182
+ disableItem("player");
183
+ disableItem("llHlsEnabled");
184
+ }
140
185
  }
186
+
187
+ const PlaybackStats = function(interval) {
188
+ const playbackStats = {
189
+ interval: interval || STATS_INTERVAL,
190
+ timer: null,
191
+ stats: null,
192
+ start: function() {
193
+ let video = remoteVideo;
194
+
195
+ playbackStats.stop();
196
+ stats = HTML5Stats(video);
197
+ playbackStats.timer = setInterval(playbackStats.displayStats, playbackStats.interval);
198
+ setText("videoWidth", "N/A");
199
+ setText("videoHeight", "N/A");
200
+ setText("videoRate", "N/A");
201
+ setText("videoFps", "N/A");
202
+ showItem("stats");
203
+ },
204
+ stop: function() {
205
+ if (playbackStats.timer) {
206
+ clearInterval(playbackStats.timer);
207
+ playbackStats.timer = null;
208
+ }
209
+ playbackStats.stats = null;
210
+ hideItem("stats");
211
+ },
212
+ displayStats: function() {
213
+ if (stats.collect()) {
214
+ let width = stats.getWidth();
215
+ let height = stats.getHeight();
216
+ let bitrate = stats.getBitrate();
217
+ let fps = stats.getFps();
218
+
219
+ setText("videoWidth", width);
220
+ setText("videoHeight", height);
221
+
222
+ if (bitrate !== undefined) {
223
+ setText("videoRate", Math.round(bitrate));
224
+ }
225
+ if (fps !== undefined) {
226
+ setText("videoFps", fps.toFixed(1));
227
+ }
228
+ }
229
+ }
230
+ };
231
+ return playbackStats;
232
+ }
@@ -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">
@@ -1,48 +1,67 @@
1
- var Browser = Flashphoner.Browser;
2
- var remoteVideo = null;
1
+ const Browser = Flashphoner.Browser;
2
+ const STATS_INTERVAL = 1000;
3
+ let remoteVideo = null;
4
+ let playbackStats = null;
3
5
 
4
- function loadPlayerPage() {
5
- $("#playerPage").load("../hls-player/player-page.html", initPage );
6
+ const loadPlayerPage = function() {
7
+ loadPage("../hls-player/player-page.html", "playerPage", initPage );
6
8
  }
7
9
 
8
- function initPage() {
9
- $("#header").text("HLS Native Player Minimal");
10
- $("#urlServer").val(getHLSUrl());
11
- $("#applyBtn").prop('disabled', false).text("Play").off('click').click(playBtnClick);
10
+ const loadPage = function(page, containerId, onLoad) {
11
+ fetch(page).then(function (response) {
12
+ if (response.ok) {
13
+ return response.text();
14
+ }
15
+ throw response;
16
+ }).then(function (text) {
17
+ let container = document.getElementById(containerId);
18
+ container.innerHTML = text;
19
+ onLoad();
20
+ });
21
+ }
22
+
23
+ const initPage = function() {
24
+ setText("header", "HLS Native Player Minimal");
25
+ setValue("urlServer", getHLSUrl());
26
+ setText("applyBtn", "Play");
27
+ setHandler("applyBtn", "click", playBtnClick);
12
28
  remoteVideo = document.getElementById('remoteVideo');
13
29
  remoteVideo.style ="background-color: lightgrey;";
14
30
  if (Browser.isSafariWebRTC() && Browser.isiOS()) {
15
31
  // iOS hack when using standard controls to leave fullscreen mode
16
32
  setWebkitFullscreenHandlers(remoteVideo);
17
33
  }
34
+ if (remoteVideo.canPlayType('application/vnd.apple.mpegurl') && Browser.isSafariWebRTC()) {
35
+ enableItem("applyBtn");
36
+ playbackStats = PlaybackStats(STATS_INTERVAL);
37
+ } else {
38
+ setText("notifyFlash", "Your browser doesn't support native HLS playback");
39
+ disableItem("applyBtn");
40
+ toggleInputs(false);
41
+ }
18
42
  }
19
43
 
20
- function playBtnClick() {
44
+ const playBtnClick = function() {
21
45
  if (validateForm()) {
22
- var streamName = $('#playStream').val();
46
+ let streamName = getValue("playStream");
23
47
  streamName = encodeURIComponent(streamName);
24
- var videoSrc = $("#urlServer").val() + '/' + streamName + '/' + streamName + '.m3u8';
25
- var key = $('#key').val();
26
- var token = $("#token").val();
48
+ let videoSrc = getValue("urlServer") + '/' + streamName + '/' + streamName + '.m3u8';
49
+ let key = getValue('key');
50
+ let token = getValue("token");
27
51
  if (key.length > 0 && token.length > 0) {
28
52
  videoSrc += "?" + key + "=" + token;
29
53
  }
30
- if (remoteVideo.canPlayType('application/vnd.apple.mpegurl')) {
31
- remoteVideo.src = videoSrc;
32
- remoteVideo.addEventListener('loadedmetadata', function() {
33
- console.log("Play native HLS");
34
- remoteVideo.play();
35
- onStarted();
36
- });
37
- }
38
- else {
39
- $("#notifyFlash").text("Your browser doesn't support native HLS playback");
40
- }
54
+ remoteVideo.src = videoSrc;
55
+ remoteVideo.addEventListener('loadedmetadata', function() {
56
+ console.log("Play native HLS");
57
+ remoteVideo.play();
58
+ onStarted();
59
+ });
41
60
  }
42
61
  }
43
62
 
44
63
 
45
- function stopBtnClick() {
64
+ const stopBtnClick = function() {
46
65
  if (remoteVideo != null) {
47
66
  console.log("Stop HTML5 player");
48
67
  remoteVideo.pause();
@@ -54,51 +73,124 @@ function stopBtnClick() {
54
73
  }
55
74
 
56
75
 
57
- function onStarted() {
58
- $("#urlServer").prop('disabled', true);
59
- $("#playStream").prop('disabled', true);
60
- $("#key").prop('disabled', true);
61
- $("#token").prop('disabled', true);
62
- $("#player").prop('disabled', true);
63
- $("#applyBtn").prop('disabled', false).text("Stop").off('click').click(stopBtnClick);
76
+ const onStarted = function() {
77
+ toggleInputs(false);
78
+ enableItem("applyBtn");
79
+ setText("applyBtn", "Stop");
80
+ setHandler("applyBtn", "click", stopBtnClick, playBtnClick);
81
+ playbackStats.start();
64
82
  }
65
83
 
66
84
 
67
- function onStopped() {
68
- $("#urlServer").prop('disabled', false);
69
- $("#playStream").prop('disabled', false);
70
- $("#key").prop('disabled', false);
71
- $("#token").prop('disabled', false);
72
- $("#player").prop('disabled', false);
73
- $("#applyBtn").prop('disabled', false).text("Play").off('click').click(playBtnClick);
85
+ const onStopped = function() {
86
+ toggleInputs(true);
87
+ enableItem("applyBtn");
88
+ setText("applyBtn", "Play");
89
+ setHandler("applyBtn", "click", playBtnClick, stopBtnClick);
90
+ playbackStats.stop();
74
91
  }
75
92
 
76
93
 
77
- function validateForm() {
78
- var valid = true;
79
- if (!$("#urlServer").val().length) {
80
- highlightInput($("#urlServer"));
81
- valid = false;
82
- } else {
83
- removeHighlight($("#urlServer"));
94
+ const validateForm = function() {
95
+ let valid = validateInput("urlServer");
96
+ if (valid) {
97
+ valid = validateInput("playStream");
84
98
  }
85
- if (!$("#playStream").val().length) {
86
- highlightInput($("#playStream"));
99
+ return valid;
100
+ }
101
+
102
+ const validateInput = function(id) {
103
+ let value = getValue(id);
104
+ let valid = true;
105
+ if (!value || !value.length) {
106
+ highlightInput(id);
87
107
  valid = false;
88
108
  } else {
89
- removeHighlight($("#playStream"));
109
+ removeHighlight(id);
90
110
  }
91
-
92
111
  return valid;
93
-
94
112
  }
95
113
 
96
-
97
- function highlightInput(input) {
98
- input.closest('.form-group').addClass("has-error");
114
+ const highlightInput = function(input) {
115
+ let item = document.getElementById(input);
116
+ if (item) {
117
+ let parent = closest(input,'.form-group');
118
+ if (parent) {
119
+ parent.classList.add("has-error");
120
+ }
121
+ }
99
122
  }
100
123
 
101
124
 
102
- function removeHighlight(input) {
103
- input.closest('.form-group').removeClass("has-error");
125
+ const removeHighlight = function(input) {
126
+ let item = document.getElementById(input);
127
+ if (item) {
128
+ let parent = closest(input,'.form-group');
129
+ if (parent) {
130
+ parent.classList.remove("has-error");
131
+ }
132
+ }
133
+ }
134
+
135
+ const toggleInputs = function(enable) {
136
+ if (enable) {
137
+ enableItem("urlServer");
138
+ enableItem("playStream");
139
+ enableItem("key");
140
+ enableItem("token");
141
+ enableItem("player");
142
+ } else {
143
+ disableItem("urlServer");
144
+ disableItem("playStream");
145
+ disableItem("key");
146
+ disableItem("token");
147
+ disableItem("player");
148
+ }
104
149
  }
150
+
151
+ const PlaybackStats = function(interval) {
152
+ const playbackStats = {
153
+ interval: interval || STATS_INTERVAL,
154
+ timer: null,
155
+ stats: null,
156
+ start: function() {
157
+ let video = remoteVideo;
158
+
159
+ playbackStats.stop();
160
+ stats = HTML5Stats(video);
161
+ playbackStats.timer = setInterval(playbackStats.displayStats, playbackStats.interval);
162
+ setText("videoWidth", "N/A");
163
+ setText("videoHeight", "N/A");
164
+ setText("videoRate", "N/A");
165
+ setText("videoFps", "N/A");
166
+ showItem("stats");
167
+ },
168
+ stop: function() {
169
+ if (playbackStats.timer) {
170
+ clearInterval(playbackStats.timer);
171
+ playbackStats.timer = null;
172
+ }
173
+ playbackStats.stats = null;
174
+ hideItem("stats");
175
+ },
176
+ displayStats: function() {
177
+ if (stats.collect()) {
178
+ let width = stats.getWidth();
179
+ let height = stats.getHeight();
180
+ let bitrate = stats.getBitrate();
181
+ let fps = stats.getFps();
182
+
183
+ setText("videoWidth", width);
184
+ setText("videoHeight", height);
185
+
186
+ if (bitrate !== undefined) {
187
+ setText("videoRate", Math.round(bitrate));
188
+ }
189
+ if (fps !== undefined) {
190
+ setText("videoFps", fps.toFixed(1));
191
+ }
192
+ }
193
+ }
194
+ };
195
+ return playbackStats;
196
+ }
@@ -5,14 +5,11 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <link rel="stylesheet" href="../../dependencies/bootstrap/css/bootstrap.css">
7
7
  <link rel="stylesheet" href="hls-player.css">
8
- <!-- <link rel="stylesheet" href="video-js.css"> -->
9
8
  <title>HLS VideoJS Player Minimal</title>
10
9
  <script type="text/javascript" src="../../../../flashphoner.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
10
  <script type="text/javascript" src="../../dependencies/js/utils.js"></script>
11
+ <script type="text/javascript" src="../../dependencies/js/stats.js"></script>
14
12
  <script type="text/javascript" src="hls-player.js"></script>
15
- <!-- <script type="text/javascript" src="video.js"></script> -->
16
13
  </head>
17
14
  <body onload="loadPlayerPage()">
18
15
  <div class="row form-group" id="videojsInputForm">
@@ -6,9 +6,11 @@ const VIDEOJS_VERSION_TYPE = {
6
6
  const LIVE_THRESHOLD = 5;
7
7
  const LIVE_TOLERANCE = 5;
8
8
  const LIVE_UI_INTERVAL = 1000;
9
+ const STATS_INTERVAL = 1000;
9
10
  let player = null;
10
11
  let liveUITimer = null;
11
12
  let videojsVersion = getUrlParam("version");
13
+ let playbackStats = null;
12
14
 
13
15
  const loadPlayerPage = function() {
14
16
  if (videojsVersion) {
@@ -127,6 +129,7 @@ const initPage = function() {
127
129
  let remoteVideo = document.getElementById('remoteVideo');
128
130
  remoteVideo.className = "video-js vjs-default-skin";
129
131
  player = initVideoJsPlayer(remoteVideo);
132
+ playbackStats = PlaybackStats(STATS_INTERVAL);
130
133
  }
131
134
 
132
135
  const playBtnClick = function() {
@@ -234,6 +237,7 @@ const onStarted = function() {
234
237
  toggleBackButtons(true);
235
238
  setText("applyBtn", "Stop");
236
239
  setHandler("applyBtn", "click", stopBtnClick, playBtnClick);
240
+ playbackStats.start();
237
241
  }
238
242
 
239
243
 
@@ -243,6 +247,7 @@ const onStopped = function() {
243
247
  hideItem("backward");
244
248
  setText("applyBtn", "Play");
245
249
  setHandler("applyBtn", "click", playBtnClick, stopBtnClick);
250
+ playbackStats.stop();
246
251
  if(!document.getElementById('remoteVideo')) {
247
252
  createRemoteVideo(document.getElementById('videoContainer'));
248
253
  }
@@ -250,10 +255,8 @@ const onStopped = function() {
250
255
 
251
256
 
252
257
  const createRemoteVideo = function(parent) {
253
- remoteVideo = document.createElement("video");
258
+ let remoteVideo = document.createElement("video");
254
259
  remoteVideo.id = "remoteVideo";
255
- remoteVideo.width=852;
256
- remoteVideo.height=480;
257
260
  remoteVideo.controls="controls";
258
261
  remoteVideo.autoplay="autoplay";
259
262
  remoteVideo.type="application/vnd.apple.mpegurl";
@@ -314,7 +317,8 @@ const initVideoJsPlayer = function(video) {
314
317
  liveTracker: {
315
318
  trackingThreshold: LIVE_THRESHOLD,
316
319
  liveTolerance: LIVE_TOLERANCE
317
- }
320
+ },
321
+ fill: true
318
322
  });
319
323
  console.log("Using VideoJs " + videojs.VERSION);
320
324
  if (Browser.isSafariWebRTC() && Browser.isiOS()) {
@@ -361,4 +365,51 @@ const toggleInputs = function(enable) {
361
365
  disableItem("token");
362
366
  disableItem("player");
363
367
  }
368
+ }
369
+
370
+ const PlaybackStats = function(interval) {
371
+ const playbackStats = {
372
+ interval: interval || STATS_INTERVAL,
373
+ timer: null,
374
+ stats: null,
375
+ start: function() {
376
+ let video = getActualVideoTag();
377
+
378
+ playbackStats.stop();
379
+ stats = HTML5Stats(video);
380
+ playbackStats.timer = setInterval(playbackStats.displayStats, playbackStats.interval);
381
+ setText("videoWidth", "N/A");
382
+ setText("videoHeight", "N/A");
383
+ setText("videoRate", "N/A");
384
+ setText("videoFps", "N/A");
385
+ showItem("stats");
386
+ },
387
+ stop: function() {
388
+ if (playbackStats.timer) {
389
+ clearInterval(playbackStats.timer);
390
+ playbackStats.timer = null;
391
+ }
392
+ playbackStats.stats = null;
393
+ hideItem("stats");
394
+ },
395
+ displayStats: function() {
396
+ if (stats.collect()) {
397
+ let width = stats.getWidth();
398
+ let height = stats.getHeight();
399
+ let bitrate = stats.getBitrate();
400
+ let fps = stats.getFps();
401
+
402
+ setText("videoWidth", width);
403
+ setText("videoHeight", height);
404
+
405
+ if (bitrate !== undefined) {
406
+ setText("videoRate", Math.round(bitrate));
407
+ }
408
+ if (fps !== undefined) {
409
+ setText("videoFps", fps.toFixed(1));
410
+ }
411
+ }
412
+ }
413
+ };
414
+ return playbackStats;
364
415
  }
@@ -1,5 +1,5 @@
1
1
  <div class="row">
2
- <div class="col-sm-12 text-center" style="max-width: 525px">
2
+ <div class="col-sm-12 text-center" style="max-width: 500px">
3
3
 
4
4
  <h2 id="header"></h2>
5
5
 
@@ -69,12 +69,42 @@
69
69
  </div>
70
70
  </div>
71
71
  <div class="row">
72
- <div id="videoContainer" class="col-sm-12 text-center" style="margin-top: 20px; max-width: 852px">
73
- <video id="remoteVideo" width="852" height="480"
72
+ <div id="videoContainer" class="col-sm-12 text-center" style="margin-top: 20px; max-width: 852px; width: available; max-height: 480px; height: 56.25vw">
73
+ <video id="remoteVideo"
74
+ width="100%"
75
+ height="100%"
74
76
  controls="controls"
75
77
  autoplay="autoplay"
76
78
  playsinline="playsinline"
77
79
  webkit-playsinline="webkit-playsinline"
78
80
  type="application/vnd.apple.mpegurl"></video>
79
81
  </div>
82
+ </div>
83
+ <div id="stats" class="row" style="display: none;">
84
+ <div class="col-sm-12">
85
+ <div class="row" style="margin-top: 20px">
86
+ <div class="col-sm-2">
87
+ <label class="form-check-label" for="videoWidth">Video width</label>
88
+ </div>
89
+ <div class="col-sm-2" id="videoWidth"></div>
90
+ </div>
91
+ <div class="row" style="margin-top: 10px">
92
+ <div class="col-sm-2">
93
+ <label class="form-check-label" for="videoHeight">Video height</label>
94
+ </div>
95
+ <div class="col-sm-2" id="videoHeight"></div>
96
+ </div>
97
+ <div class="row" style="margin-top: 10px">
98
+ <div class="col-sm-2">
99
+ <label class="form-check-label" for="videoRate">Bitrate, bps</label>
100
+ </div>
101
+ <div class="col-sm-2" id="videoRate"></div>
102
+ </div>
103
+ <div class="row" style="margin-top: 10px">
104
+ <div class="col-sm-2">
105
+ <label class="form-check-label" for="videoFps">Framerate</label>
106
+ </div>
107
+ <div class="col-sm-2" id="videoFps"></div>
108
+ </div>
109
+ </div>
80
110
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flashphoner/websdk",
3
- "version": "2.0.242",
3
+ "version": "2.0.243",
4
4
  "description": "Official Flashphoner WebCallServer WebSDK package",
5
5
  "main": "./src/flashphoner-core.js",
6
6
  "types": "./src/flashphoner-core.d.ts",