@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.
- package/docTemplate/README.md +1 -1
- package/examples/demo/dependencies/js/stats.js +105 -0
- package/examples/demo/dependencies/js/utils.js +95 -6
- package/examples/demo/streaming/hls-js-player/hls-js-player.html +1 -4
- package/examples/demo/streaming/hls-js-player/hls-js-player.js +263 -58
- package/examples/demo/streaming/hls-native/hls-native.html +1 -4
- package/examples/demo/streaming/hls-native/hls-native.js +264 -63
- package/examples/demo/streaming/hls-player/hls-player.html +1 -4
- package/examples/demo/streaming/hls-player/hls-player.js +220 -61
- package/examples/demo/streaming/hls-player/player-page.html +53 -5
- package/package.json +1 -1
|
@@ -6,15 +6,23 @@ 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 playSrc = getUrlParam("src");
|
|
14
|
+
let autoplay = eval(getUrlParam("autoplay")) || false;
|
|
15
|
+
let playbackStats = null;
|
|
12
16
|
|
|
13
17
|
const loadPlayerPage = function() {
|
|
14
18
|
if (videojsVersion) {
|
|
15
19
|
hideItem("videojsInputForm");
|
|
16
|
-
loadVideoJS(
|
|
20
|
+
loadVideoJS(videojsVersion);
|
|
17
21
|
} else {
|
|
22
|
+
if (autoplay) {
|
|
23
|
+
console.warn("No VideoJS version set, autoplay disabled");
|
|
24
|
+
autoplay = false;
|
|
25
|
+
}
|
|
18
26
|
let videojsInput = document.getElementById("videojsInput");
|
|
19
27
|
for (videojsType in VIDEOJS_VERSION_TYPE) {
|
|
20
28
|
let option = document.createElement("option");
|
|
@@ -42,13 +50,14 @@ const onVideojsBtnClick = function () {
|
|
|
42
50
|
|
|
43
51
|
const loadVideoJS = function (version) {
|
|
44
52
|
if (version) {
|
|
53
|
+
videojsVersion = version;
|
|
45
54
|
let playerPage = document.getElementById("playerPage");
|
|
46
55
|
loadFile(version + "/video.js", "text/javascript").then( data => {
|
|
47
56
|
console.log("HLS library loaded successfully", data);
|
|
48
57
|
loadFile(version + "/video-js.css", "stylesheet").then ( data => {
|
|
49
58
|
console.log("HLS library stylesheet loaded successfully", data);
|
|
50
59
|
hideItem("videojsInputForm");
|
|
51
|
-
loadPage("player-page.html", "playerPage", initPage
|
|
60
|
+
loadPage("player-page.html", "playerPage", initPage);
|
|
52
61
|
}).catch( err => {
|
|
53
62
|
playerPage.innerHTML = "Can't load VideoJS library stylesheet";
|
|
54
63
|
playerPage.setAttribute("class", "text-danger");
|
|
@@ -115,30 +124,37 @@ const loadPage = function(page, containerId, onLoad) {
|
|
|
115
124
|
}
|
|
116
125
|
|
|
117
126
|
const initPage = function() {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
setHandler("backBtn30", "click", backBtnClick);
|
|
125
|
-
setHandler("backBtnMax", "click", backBtnClick);
|
|
126
|
-
setHandler("liveBtn", "click", liveBtnClick);
|
|
127
|
+
if (playSrc) {
|
|
128
|
+
setValue("fullLink", decodeURIComponent(playSrc));
|
|
129
|
+
} else if (autoplay) {
|
|
130
|
+
console.warn("No HLS URL set, autoplay disabled");
|
|
131
|
+
autoplay = false;
|
|
132
|
+
}
|
|
127
133
|
let remoteVideo = document.getElementById('remoteVideo');
|
|
128
|
-
|
|
129
|
-
|
|
134
|
+
if (autoplay) {
|
|
135
|
+
// There should not be any visible item on the page unless player
|
|
136
|
+
hideAllToAutoplay();
|
|
137
|
+
// The player should use all available page width
|
|
138
|
+
setUpPlayerItem(true);
|
|
139
|
+
// The player should be muted to automatically start playback
|
|
140
|
+
player = initVideoJsPlayer(remoteVideo, true);
|
|
141
|
+
playBtnClick();
|
|
142
|
+
} else {
|
|
143
|
+
// No autoplay, all the forms and buttons should be visible
|
|
144
|
+
setText("header", "HLS VideoJS Player Minimal");
|
|
145
|
+
displayCommonItems();
|
|
146
|
+
setUpButtons();
|
|
147
|
+
enablePlaybackStats();
|
|
148
|
+
// The player should have a maximum fixed size
|
|
149
|
+
setUpPlayerItem(false);
|
|
150
|
+
// The player can be unmuted because user should click Play button
|
|
151
|
+
player = initVideoJsPlayer(remoteVideo, false);
|
|
152
|
+
}
|
|
130
153
|
}
|
|
131
154
|
|
|
132
155
|
const playBtnClick = function() {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
streamName = encodeURIComponent(streamName);
|
|
136
|
-
let videoSrc = getValue("urlServer") + '/' + streamName + '/' + streamName + '.m3u8';
|
|
137
|
-
let key = getValue('key');
|
|
138
|
-
let token = getValue("token");
|
|
139
|
-
if (key.length > 0 && token.length > 0) {
|
|
140
|
-
videoSrc += "?" + key + "=" + token;
|
|
141
|
-
}
|
|
156
|
+
let videoSrc = getVideoSrc(getValue("fullLink"));
|
|
157
|
+
if (videoSrc) {
|
|
142
158
|
player.on('loadedmetadata', function() {
|
|
143
159
|
console.log("Play with VideoJs");
|
|
144
160
|
player.play();
|
|
@@ -154,6 +170,7 @@ const playBtnClick = function() {
|
|
|
154
170
|
});
|
|
155
171
|
player.on('playing', function() {
|
|
156
172
|
console.log("playing event fired");
|
|
173
|
+
displayPermalink(videoSrc);
|
|
157
174
|
if (player.liveTracker) {
|
|
158
175
|
if (!player.liveTracker.isLive()) {
|
|
159
176
|
// A cratch to display live UI for the first subscriber
|
|
@@ -228,21 +245,27 @@ const liveBtnClick = function() {
|
|
|
228
245
|
}
|
|
229
246
|
|
|
230
247
|
const onStarted = function() {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
248
|
+
if (!autoplay) {
|
|
249
|
+
toggleInputs(false);
|
|
250
|
+
enableItem("applyBtn");
|
|
251
|
+
hideItem("permalink");
|
|
252
|
+
showItem("backward");
|
|
253
|
+
setText("applyBtn", "Stop");
|
|
254
|
+
setHandler("applyBtn", "click", stopBtnClick, playBtnClick);
|
|
255
|
+
startPlaybackStats();
|
|
256
|
+
}
|
|
237
257
|
}
|
|
238
258
|
|
|
239
259
|
|
|
240
260
|
const onStopped = function() {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
261
|
+
if (!autoplay) {
|
|
262
|
+
toggleInputs(true);
|
|
263
|
+
enableItem("applyBtn");
|
|
264
|
+
hideItem("backward");
|
|
265
|
+
setText("applyBtn", "Play");
|
|
266
|
+
setHandler("applyBtn", "click", playBtnClick, stopBtnClick);
|
|
267
|
+
stopPlaybackStats();
|
|
268
|
+
}
|
|
246
269
|
if(!document.getElementById('remoteVideo')) {
|
|
247
270
|
createRemoteVideo(document.getElementById('videoContainer'));
|
|
248
271
|
}
|
|
@@ -250,10 +273,8 @@ const onStopped = function() {
|
|
|
250
273
|
|
|
251
274
|
|
|
252
275
|
const createRemoteVideo = function(parent) {
|
|
253
|
-
remoteVideo = document.createElement("video");
|
|
276
|
+
let remoteVideo = document.createElement("video");
|
|
254
277
|
remoteVideo.id = "remoteVideo";
|
|
255
|
-
remoteVideo.width=852;
|
|
256
|
-
remoteVideo.height=480;
|
|
257
278
|
remoteVideo.controls="controls";
|
|
258
279
|
remoteVideo.autoplay="autoplay";
|
|
259
280
|
remoteVideo.type="application/vnd.apple.mpegurl";
|
|
@@ -261,7 +282,7 @@ const createRemoteVideo = function(parent) {
|
|
|
261
282
|
remoteVideo.setAttribute("playsinline","");
|
|
262
283
|
remoteVideo.setAttribute("webkit-playsinline","");
|
|
263
284
|
parent.appendChild(remoteVideo);
|
|
264
|
-
player = initVideoJsPlayer(remoteVideo);
|
|
285
|
+
player = initVideoJsPlayer(remoteVideo, autoplay);
|
|
265
286
|
}
|
|
266
287
|
|
|
267
288
|
|
|
@@ -306,22 +327,28 @@ const removeHighlight = function(input) {
|
|
|
306
327
|
}
|
|
307
328
|
}
|
|
308
329
|
|
|
309
|
-
const initVideoJsPlayer = function(video) {
|
|
310
|
-
let videoJsPlayer =
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
330
|
+
const initVideoJsPlayer = function(video, muted) {
|
|
331
|
+
let videoJsPlayer = null;
|
|
332
|
+
if (video) {
|
|
333
|
+
video.className = "video-js vjs-default-skin";
|
|
334
|
+
videoJsPlayer = videojs(video, {
|
|
335
|
+
playsinline: true,
|
|
336
|
+
playbackRates: [0.1, 0.25, 0.5, 1, 1.5, 2],
|
|
337
|
+
liveui: true,
|
|
338
|
+
liveTracker: {
|
|
339
|
+
trackingThreshold: LIVE_THRESHOLD,
|
|
340
|
+
liveTolerance: LIVE_TOLERANCE
|
|
341
|
+
},
|
|
342
|
+
fill: true,
|
|
343
|
+
muted: muted
|
|
344
|
+
});
|
|
345
|
+
console.log("Using VideoJs " + videojs.VERSION);
|
|
346
|
+
if (Browser.isSafariWebRTC() && Browser.isiOS()) {
|
|
347
|
+
// iOS hack when using standard controls to leave fullscreen mode
|
|
348
|
+
let videoTag = getActualVideoTag();
|
|
349
|
+
if(videoTag) {
|
|
350
|
+
setWebkitFullscreenHandlers(videoTag, false);
|
|
351
|
+
}
|
|
325
352
|
}
|
|
326
353
|
}
|
|
327
354
|
return videoJsPlayer;
|
|
@@ -335,15 +362,25 @@ const getActualVideoTag = function() {
|
|
|
335
362
|
return null;
|
|
336
363
|
}
|
|
337
364
|
|
|
365
|
+
const setUpButtons = function() {
|
|
366
|
+
setHandler("applyBtn", "click", playBtnClick);
|
|
367
|
+
setHandler("backBtn10", "click", backBtnClick);
|
|
368
|
+
setHandler("backBtn30", "click", backBtnClick);
|
|
369
|
+
setHandler("backBtnMax", "click", backBtnClick);
|
|
370
|
+
setHandler("liveBtn", "click", liveBtnClick);
|
|
371
|
+
}
|
|
372
|
+
|
|
338
373
|
const toggleBackButtons = function(enable) {
|
|
339
|
-
if (
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
374
|
+
if (!autoplay) {
|
|
375
|
+
if (enable) {
|
|
376
|
+
enableItem("backBtn10");
|
|
377
|
+
enableItem("backBtn30");
|
|
378
|
+
enableItem("backBtnMax");
|
|
379
|
+
} else {
|
|
380
|
+
disableItem("backBtn10");
|
|
381
|
+
disableItem("backBtn30");
|
|
382
|
+
disableItem("backBtnMax");
|
|
383
|
+
}
|
|
347
384
|
}
|
|
348
385
|
}
|
|
349
386
|
|
|
@@ -361,4 +398,126 @@ const toggleInputs = function(enable) {
|
|
|
361
398
|
disableItem("token");
|
|
362
399
|
disableItem("player");
|
|
363
400
|
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const getVideoSrc = function(src) {
|
|
404
|
+
let videoSrc = src;
|
|
405
|
+
if (validateForm()) {
|
|
406
|
+
let streamName = getValue('playStream');
|
|
407
|
+
streamName = encodeURIComponent(streamName);
|
|
408
|
+
videoSrc = getValue("urlServer") + '/' + streamName + '/' + streamName + '.m3u8';
|
|
409
|
+
let key = getValue('key');
|
|
410
|
+
let token = getValue("token");
|
|
411
|
+
if (key.length > 0 && token.length > 0) {
|
|
412
|
+
videoSrc += "?" + key + "=" + token;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
setValue("fullLink", videoSrc);
|
|
416
|
+
return videoSrc;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const displayPermalink = function(src) {
|
|
420
|
+
if (!autoplay) {
|
|
421
|
+
const permalinkId = "permalink";
|
|
422
|
+
let videoSrc = encodeURIComponent(src);
|
|
423
|
+
let linkObject = document.getElementById(permalinkId);
|
|
424
|
+
let href = window.location.href.split("?")[0] + "?version=" + videojsVersion + "&src=" + videoSrc;
|
|
425
|
+
linkObject.href = href;
|
|
426
|
+
showItem(permalinkId);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const hideAllToAutoplay = function() {
|
|
431
|
+
hideItem("header");
|
|
432
|
+
hideItem("notifyFlash");
|
|
433
|
+
hideItem("fieldset");
|
|
434
|
+
hideItem("stats");
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const displayCommonItems = function() {
|
|
438
|
+
setValue("urlServer", getHLSUrl());
|
|
439
|
+
hideItem("permalink");
|
|
440
|
+
enableItem("applyBtn");
|
|
441
|
+
setText("applyBtn", "Play");
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const setUpPlayerItem = function(fillPage) {
|
|
445
|
+
let videoContainer = document.getElementById('videoContainer');
|
|
446
|
+
let playerPage = document.getElementById('playerPage');
|
|
447
|
+
|
|
448
|
+
if (fillPage) {
|
|
449
|
+
playerPage.classList.remove("container");
|
|
450
|
+
videoContainer.style.marginTop = "0px";
|
|
451
|
+
videoContainer.style.width = "100vw";
|
|
452
|
+
videoContainer.style.height = "100vh";
|
|
453
|
+
videoContainer.style.maxWidth = "available";
|
|
454
|
+
videoContainer.style.maxHeight = "available";
|
|
455
|
+
} else {
|
|
456
|
+
videoContainer.style.maxWidth = "852px";
|
|
457
|
+
videoContainer.style.maxHeight = "480px";
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const enablePlaybackStats = function() {
|
|
462
|
+
if (!autoplay && !playbackStats) {
|
|
463
|
+
playbackStats = PlaybackStats(STATS_INTERVAL);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const startPlaybackStats = function() {
|
|
468
|
+
if (!autoplay && playbackStats) {
|
|
469
|
+
playbackStats.start();
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const stopPlaybackStats = function() {
|
|
474
|
+
if (!autoplay && playbackStats) {
|
|
475
|
+
playbackStats.stop();
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const PlaybackStats = function(interval) {
|
|
480
|
+
const playbackStats = {
|
|
481
|
+
interval: interval || STATS_INTERVAL,
|
|
482
|
+
timer: null,
|
|
483
|
+
stats: null,
|
|
484
|
+
start: function() {
|
|
485
|
+
let video = getActualVideoTag();
|
|
486
|
+
playbackStats.stop();
|
|
487
|
+
stats = HTML5Stats(video);
|
|
488
|
+
playbackStats.timer = setInterval(playbackStats.displayStats, playbackStats.interval);
|
|
489
|
+
setText("videoWidth", "N/A");
|
|
490
|
+
setText("videoHeight", "N/A");
|
|
491
|
+
setText("videoRate", "N/A");
|
|
492
|
+
setText("videoFps", "N/A");
|
|
493
|
+
showItem("stats");
|
|
494
|
+
},
|
|
495
|
+
stop: function() {
|
|
496
|
+
if (playbackStats.timer) {
|
|
497
|
+
clearInterval(playbackStats.timer);
|
|
498
|
+
playbackStats.timer = null;
|
|
499
|
+
}
|
|
500
|
+
playbackStats.stats = null;
|
|
501
|
+
hideItem("stats");
|
|
502
|
+
},
|
|
503
|
+
displayStats: function() {
|
|
504
|
+
if (stats.collect()) {
|
|
505
|
+
let width = stats.getWidth();
|
|
506
|
+
let height = stats.getHeight();
|
|
507
|
+
let bitrate = stats.getBitrate();
|
|
508
|
+
let fps = stats.getFps();
|
|
509
|
+
|
|
510
|
+
setText("videoWidth", width);
|
|
511
|
+
setText("videoHeight", height);
|
|
512
|
+
|
|
513
|
+
if (bitrate !== undefined) {
|
|
514
|
+
setText("videoRate", Math.round(bitrate));
|
|
515
|
+
}
|
|
516
|
+
if (fps !== undefined) {
|
|
517
|
+
setText("videoFps", fps.toFixed(1));
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
return playbackStats;
|
|
364
523
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div class="row">
|
|
2
|
-
<div class="col-sm-12 text-center" style="max-width:
|
|
2
|
+
<div class="col-sm-12 text-center" style="max-width: 500px">
|
|
3
3
|
|
|
4
4
|
<h2 id="header"></h2>
|
|
5
5
|
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
</div>
|
|
29
29
|
|
|
30
30
|
<div class="row" style="margin-top:10px">
|
|
31
|
-
<div class="form-group">
|
|
31
|
+
<div id="authForm" class="form-group">
|
|
32
32
|
<label class="control-label col-sm-1 fp-buttonVerticalAlign text-left"
|
|
33
|
-
for="
|
|
33
|
+
for="key">Auth</label>
|
|
34
34
|
|
|
35
35
|
<div class="col-sm-12">
|
|
36
36
|
<div class="col-sm-4 nopadding">
|
|
@@ -43,6 +43,24 @@
|
|
|
43
43
|
</div>
|
|
44
44
|
</div>
|
|
45
45
|
</div>
|
|
46
|
+
|
|
47
|
+
<div class="row" style="margin-top:10px">
|
|
48
|
+
<div id="linkForm" class="form-group">
|
|
49
|
+
<label class="control-label col-sm-12 fp-buttonVerticalAlign text-left"
|
|
50
|
+
for="fullLink">Or set a full HLS stream URL</label>
|
|
51
|
+
|
|
52
|
+
<div class="col-sm-12">
|
|
53
|
+
<input type="text" class="form-control" id="fullLink" placeholder="Full HLS link"/>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div class="row" style="margin-top:10px">
|
|
59
|
+
<div class="col-sm-12 text-center">
|
|
60
|
+
<a id="permalink" href="#">Permalink</a>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
46
64
|
<div class="row" style="margin-top: 20px">
|
|
47
65
|
<div class="col-sm-4 text-left">
|
|
48
66
|
<div id="llHlsMode" style="display: none;">
|
|
@@ -69,12 +87,42 @@
|
|
|
69
87
|
</div>
|
|
70
88
|
</div>
|
|
71
89
|
<div class="row">
|
|
72
|
-
<div id="videoContainer"
|
|
73
|
-
<video id="remoteVideo"
|
|
90
|
+
<div id="videoContainer" style="margin-top: 20px; width: available; height: 56.25vw">
|
|
91
|
+
<video id="remoteVideo"
|
|
92
|
+
width="100%"
|
|
93
|
+
height="100%"
|
|
74
94
|
controls="controls"
|
|
75
95
|
autoplay="autoplay"
|
|
76
96
|
playsinline="playsinline"
|
|
77
97
|
webkit-playsinline="webkit-playsinline"
|
|
78
98
|
type="application/vnd.apple.mpegurl"></video>
|
|
79
99
|
</div>
|
|
100
|
+
</div>
|
|
101
|
+
<div id="stats" class="row" style="display: none;">
|
|
102
|
+
<div class="col-sm-12">
|
|
103
|
+
<div class="row" style="margin-top: 20px">
|
|
104
|
+
<div class="col-sm-2">
|
|
105
|
+
<label class="form-check-label" for="videoWidth">Video width</label>
|
|
106
|
+
</div>
|
|
107
|
+
<div class="col-sm-2" id="videoWidth"></div>
|
|
108
|
+
</div>
|
|
109
|
+
<div class="row" style="margin-top: 10px">
|
|
110
|
+
<div class="col-sm-2">
|
|
111
|
+
<label class="form-check-label" for="videoHeight">Video height</label>
|
|
112
|
+
</div>
|
|
113
|
+
<div class="col-sm-2" id="videoHeight"></div>
|
|
114
|
+
</div>
|
|
115
|
+
<div class="row" style="margin-top: 10px">
|
|
116
|
+
<div class="col-sm-2">
|
|
117
|
+
<label class="form-check-label" for="videoRate">Bitrate, bps</label>
|
|
118
|
+
</div>
|
|
119
|
+
<div class="col-sm-2" id="videoRate"></div>
|
|
120
|
+
</div>
|
|
121
|
+
<div class="row" style="margin-top: 10px">
|
|
122
|
+
<div class="col-sm-2">
|
|
123
|
+
<label class="form-check-label" for="videoFps">Framerate</label>
|
|
124
|
+
</div>
|
|
125
|
+
<div class="col-sm-2" id="videoFps"></div>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
80
128
|
</div>
|