@flashphoner/websdk 2.0.243 → 2.0.245

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.
@@ -7,16 +7,29 @@ const LIVE_THRESHOLD = 5;
7
7
  const LIVE_TOLERANCE = 5;
8
8
  const LIVE_UI_INTERVAL = 1000;
9
9
  const STATS_INTERVAL = 1000;
10
+ const QUALITY_COLORS = {
11
+ NONE: "",
12
+ AVAILABLE: "black",
13
+ SELECTED: "blue"
14
+ };
15
+ const QUALITY_AUTO = "Auto";
10
16
  let player = null;
11
17
  let liveUITimer = null;
12
18
  let videojsVersion = getUrlParam("version");
19
+ let playSrc = getUrlParam("src");
20
+ let autoplay = eval(getUrlParam("autoplay")) || false;
13
21
  let playbackStats = null;
22
+ let qualityLevels = [];
14
23
 
15
24
  const loadPlayerPage = function() {
16
25
  if (videojsVersion) {
17
26
  hideItem("videojsInputForm");
18
- loadVideoJS("videojs" + videojsVersion);
27
+ loadVideoJS(videojsVersion);
19
28
  } else {
29
+ if (autoplay) {
30
+ console.warn("No VideoJS version set, autoplay disabled");
31
+ autoplay = false;
32
+ }
20
33
  let videojsInput = document.getElementById("videojsInput");
21
34
  for (videojsType in VIDEOJS_VERSION_TYPE) {
22
35
  let option = document.createElement("option");
@@ -38,24 +51,17 @@ const loadPlayerPage = function() {
38
51
  }
39
52
  }
40
53
 
41
- const onVideojsBtnClick = function () {
54
+ const onVideojsBtnClick = function() {
42
55
  loadVideoJS(getValue("videojsInput"));
43
56
  }
44
57
 
45
- const loadVideoJS = function (version) {
58
+ const loadVideoJS = function(version) {
46
59
  if (version) {
60
+ videojsVersion = version;
47
61
  let playerPage = document.getElementById("playerPage");
48
62
  loadFile(version + "/video.js", "text/javascript").then( data => {
49
63
  console.log("HLS library loaded successfully", data);
50
- loadFile(version + "/video-js.css", "stylesheet").then ( data => {
51
- console.log("HLS library stylesheet loaded successfully", data);
52
- hideItem("videojsInputForm");
53
- loadPage("player-page.html", "playerPage", initPage );
54
- }).catch( err => {
55
- playerPage.innerHTML = "Can't load VideoJS library stylesheet";
56
- playerPage.setAttribute("class", "text-danger");
57
- console.error(err);
58
- })
64
+ loadStyles(version, playerPage);
59
65
  }).catch( err => {
60
66
  setText("videojsError", "Can't load VideoJS library");
61
67
  console.error(err);
@@ -63,6 +69,37 @@ const loadVideoJS = function (version) {
63
69
  }
64
70
  }
65
71
 
72
+ const loadStyles = function(version, playerPage) {
73
+ if (version) {
74
+ loadFile(version + "/video-js.css", "stylesheet").then ( data => {
75
+ console.log("HLS library stylesheet loaded successfully", data);
76
+ if (version === VIDEOJS_VERSION_TYPE.VIDEOJS7) {
77
+ loadQualityPlugin(version, playerPage);
78
+ } else {
79
+ hideItem("videojsInputForm");
80
+ loadPage("player-page.html", "playerPage", initPage);
81
+ }
82
+ }).catch( err => {
83
+ playerPage.innerHTML = "Can't load VideoJS library stylesheet";
84
+ playerPage.setAttribute("class", "text-danger");
85
+ console.error(err);
86
+ });
87
+ }
88
+ }
89
+
90
+ const loadQualityPlugin = function(version, playerPage) {
91
+ if (version) {
92
+ loadFile(version + "/videojs-contrib-quality-levels.js", "text/javascript").then( data => {
93
+ console.log("HLS quality levels plugin loaded successfully", data);
94
+ hideItem("videojsInputForm");
95
+ loadPage("player-page.html", "playerPage", initPage);
96
+ }).catch( err => {
97
+ setText("videojsError", "Can't load VideoJS quality levels plugin");
98
+ console.error(err);
99
+ });
100
+ }
101
+ }
102
+
66
103
  const loadFile = function(url, type) {
67
104
  return new Promise((resolve, reject) => {
68
105
  try {
@@ -117,31 +154,37 @@ const loadPage = function(page, containerId, onLoad) {
117
154
  }
118
155
 
119
156
  const initPage = function() {
120
- setText("header", "HLS VideoJS Player Minimal");
121
- setValue("urlServer", getHLSUrl());
122
- enableItem("applyBtn");
123
- setText("applyBtn", "Play");
124
- setHandler("applyBtn", "click", playBtnClick);
125
- setHandler("backBtn10", "click", backBtnClick);
126
- setHandler("backBtn30", "click", backBtnClick);
127
- setHandler("backBtnMax", "click", backBtnClick);
128
- setHandler("liveBtn", "click", liveBtnClick);
157
+ if (playSrc) {
158
+ setValue("fullLink", decodeURIComponent(playSrc));
159
+ } else if (autoplay) {
160
+ console.warn("No HLS URL set, autoplay disabled");
161
+ autoplay = false;
162
+ }
129
163
  let remoteVideo = document.getElementById('remoteVideo');
130
- remoteVideo.className = "video-js vjs-default-skin";
131
- player = initVideoJsPlayer(remoteVideo);
132
- playbackStats = PlaybackStats(STATS_INTERVAL);
164
+ if (autoplay) {
165
+ // There should not be any visible item on the page unless player
166
+ hideAllToAutoplay();
167
+ // The player should use all available page width
168
+ setUpPlayerItem(true);
169
+ // The player should be muted to automatically start playback
170
+ player = initVideoJsPlayer(remoteVideo, true);
171
+ playBtnClick();
172
+ } else {
173
+ // No autoplay, all the forms and buttons should be visible
174
+ setText("header", "HLS VideoJS Player Minimal");
175
+ displayCommonItems();
176
+ setUpButtons();
177
+ enablePlaybackStats();
178
+ // The player should have a maximum fixed size
179
+ setUpPlayerItem(false);
180
+ // The player can be unmuted because user should click Play button
181
+ player = initVideoJsPlayer(remoteVideo, false);
182
+ }
133
183
  }
134
184
 
135
185
  const playBtnClick = function() {
136
- if (validateForm()) {
137
- let streamName = getValue('playStream');
138
- streamName = encodeURIComponent(streamName);
139
- let videoSrc = getValue("urlServer") + '/' + streamName + '/' + streamName + '.m3u8';
140
- let key = getValue('key');
141
- let token = getValue("token");
142
- if (key.length > 0 && token.length > 0) {
143
- videoSrc += "?" + key + "=" + token;
144
- }
186
+ let videoSrc = getVideoSrc(getValue("fullLink"));
187
+ if (videoSrc) {
145
188
  player.on('loadedmetadata', function() {
146
189
  console.log("Play with VideoJs");
147
190
  player.play();
@@ -157,6 +200,7 @@ const playBtnClick = function() {
157
200
  });
158
201
  player.on('playing', function() {
159
202
  console.log("playing event fired");
203
+ displayPermalink(videoSrc);
160
204
  if (player.liveTracker) {
161
205
  if (!player.liveTracker.isLive()) {
162
206
  // A cratch to display live UI for the first subscriber
@@ -169,6 +213,8 @@ const playBtnClick = function() {
169
213
  stopLiveUITimer();
170
214
  }
171
215
  }
216
+ initQualityLevels(player);
217
+ displayQualitySwitch();
172
218
  });
173
219
  player.src({
174
220
  src: videoSrc,
@@ -231,23 +277,30 @@ const liveBtnClick = function() {
231
277
  }
232
278
 
233
279
  const onStarted = function() {
234
- toggleInputs(false);
235
- enableItem("applyBtn");
236
- showItem("backward");
237
- toggleBackButtons(true);
238
- setText("applyBtn", "Stop");
239
- setHandler("applyBtn", "click", stopBtnClick, playBtnClick);
240
- playbackStats.start();
280
+ if (!autoplay) {
281
+ toggleInputs(false);
282
+ enableItem("applyBtn");
283
+ hideItem("permalink");
284
+ showItem("backward");
285
+ setText("applyBtn", "Stop");
286
+ setHandler("applyBtn", "click", stopBtnClick, playBtnClick);
287
+ startPlaybackStats();
288
+ hideItem("quality");
289
+ }
241
290
  }
242
291
 
243
292
 
244
293
  const onStopped = function() {
245
- toggleInputs(true);
246
- enableItem("applyBtn");
247
- hideItem("backward");
248
- setText("applyBtn", "Play");
249
- setHandler("applyBtn", "click", playBtnClick, stopBtnClick);
250
- playbackStats.stop();
294
+ if (!autoplay) {
295
+ toggleInputs(true);
296
+ enableItem("applyBtn");
297
+ hideItem("backward");
298
+ setText("applyBtn", "Play");
299
+ setHandler("applyBtn", "click", playBtnClick, stopBtnClick);
300
+ stopPlaybackStats();
301
+ hideItem("quality");
302
+ disposeQualityLevels();
303
+ }
251
304
  if(!document.getElementById('remoteVideo')) {
252
305
  createRemoteVideo(document.getElementById('videoContainer'));
253
306
  }
@@ -264,7 +317,7 @@ const createRemoteVideo = function(parent) {
264
317
  remoteVideo.setAttribute("playsinline","");
265
318
  remoteVideo.setAttribute("webkit-playsinline","");
266
319
  parent.appendChild(remoteVideo);
267
- player = initVideoJsPlayer(remoteVideo);
320
+ player = initVideoJsPlayer(remoteVideo, autoplay);
268
321
  }
269
322
 
270
323
 
@@ -309,23 +362,33 @@ const removeHighlight = function(input) {
309
362
  }
310
363
  }
311
364
 
312
- const initVideoJsPlayer = function(video) {
313
- let videoJsPlayer = videojs(video, {
314
- playsinline: true,
315
- playbackRates: [0.1, 0.25, 0.5, 1, 1.5, 2],
316
- liveui: true,
317
- liveTracker: {
318
- trackingThreshold: LIVE_THRESHOLD,
319
- liveTolerance: LIVE_TOLERANCE
320
- },
321
- fill: true
322
- });
323
- console.log("Using VideoJs " + videojs.VERSION);
324
- if (Browser.isSafariWebRTC() && Browser.isiOS()) {
325
- // iOS hack when using standard controls to leave fullscreen mode
326
- let videoTag = getActualVideoTag();
327
- if(videoTag) {
328
- setWebkitFullscreenHandlers(videoTag, false);
365
+ const initVideoJsPlayer = function(video, muted) {
366
+ let videoJsPlayer = null;
367
+ if (video) {
368
+ video.className = "video-js vjs-default-skin";
369
+ videoJsPlayer = videojs(video, {
370
+ playsinline: true,
371
+ playbackRates: [0.1, 0.25, 0.5, 1, 1.5, 2],
372
+ liveui: true,
373
+ liveTracker: {
374
+ trackingThreshold: LIVE_THRESHOLD,
375
+ liveTolerance: LIVE_TOLERANCE
376
+ },
377
+ fill: true,
378
+ muted: muted,
379
+ html5: {
380
+ vhs: {
381
+ limitRenditionByPlayerDimensions: false
382
+ }
383
+ }
384
+ });
385
+ console.log("Using VideoJs " + videojs.VERSION);
386
+ if (Browser.isSafariWebRTC() && Browser.isiOS()) {
387
+ // iOS hack when using standard controls to leave fullscreen mode
388
+ let videoTag = getActualVideoTag();
389
+ if(videoTag) {
390
+ setWebkitFullscreenHandlers(videoTag, false);
391
+ }
329
392
  }
330
393
  }
331
394
  return videoJsPlayer;
@@ -339,15 +402,25 @@ const getActualVideoTag = function() {
339
402
  return null;
340
403
  }
341
404
 
405
+ const setUpButtons = function() {
406
+ setHandler("applyBtn", "click", playBtnClick);
407
+ setHandler("backBtn10", "click", backBtnClick);
408
+ setHandler("backBtn30", "click", backBtnClick);
409
+ setHandler("backBtnMax", "click", backBtnClick);
410
+ setHandler("liveBtn", "click", liveBtnClick);
411
+ }
412
+
342
413
  const toggleBackButtons = function(enable) {
343
- if (enable) {
344
- enableItem("backBtn10");
345
- enableItem("backBtn30");
346
- enableItem("backBtnMax");
347
- } else {
348
- disableItem("backBtn10");
349
- disableItem("backBtn30");
350
- disableItem("backBtnMax");
414
+ if (!autoplay) {
415
+ if (enable) {
416
+ enableItem("backBtn10");
417
+ enableItem("backBtn30");
418
+ enableItem("backBtnMax");
419
+ } else {
420
+ disableItem("backBtn10");
421
+ disableItem("backBtn30");
422
+ disableItem("backBtnMax");
423
+ }
351
424
  }
352
425
  }
353
426
 
@@ -367,6 +440,88 @@ const toggleInputs = function(enable) {
367
440
  }
368
441
  }
369
442
 
443
+ const getVideoSrc = function(src) {
444
+ let videoSrc = src;
445
+ if (validateForm()) {
446
+ let streamName = getValue('playStream');
447
+ streamName = encodeURIComponent(streamName);
448
+ videoSrc = getValue("urlServer") + '/' + streamName + '/' + streamName + '.m3u8';
449
+ let key = getValue('key');
450
+ let token = getValue("token");
451
+ if (key.length > 0 && token.length > 0) {
452
+ videoSrc += "?" + key + "=" + token;
453
+ }
454
+ }
455
+ setValue("fullLink", videoSrc);
456
+ return videoSrc;
457
+ }
458
+
459
+ const displayPermalink = function(src) {
460
+ if (!autoplay) {
461
+ const permalinkId = "permalink";
462
+ let videoSrc = encodeURIComponent(src);
463
+ let linkObject = document.getElementById(permalinkId);
464
+ let href = window.location.href.split("?")[0] + "?version=" + videojsVersion + "&src=" + videoSrc;
465
+ linkObject.href = href;
466
+ showItem(permalinkId);
467
+ }
468
+ }
469
+
470
+ const displayQualitySwitch = function() {
471
+ if (!autoplay && qualityLevels.length) {
472
+ showItem("quality")
473
+ }
474
+ }
475
+
476
+ const hideAllToAutoplay = function() {
477
+ hideItem("header");
478
+ hideItem("notifyFlash");
479
+ hideItem("fieldset");
480
+ hideItem("stats");
481
+ }
482
+
483
+ const displayCommonItems = function() {
484
+ setValue("urlServer", getHLSUrl());
485
+ hideItem("permalink");
486
+ enableItem("applyBtn");
487
+ setText("applyBtn", "Play");
488
+ }
489
+
490
+ const setUpPlayerItem = function(fillPage) {
491
+ let videoContainer = document.getElementById('videoContainer');
492
+ let playerPage = document.getElementById('playerPage');
493
+
494
+ if (fillPage) {
495
+ playerPage.classList.remove("container");
496
+ videoContainer.style.marginTop = "0px";
497
+ videoContainer.style.width = "100vw";
498
+ videoContainer.style.height = "100vh";
499
+ videoContainer.style.maxWidth = "available";
500
+ videoContainer.style.maxHeight = "available";
501
+ } else {
502
+ videoContainer.style.maxWidth = "852px";
503
+ videoContainer.style.maxHeight = "480px";
504
+ }
505
+ }
506
+
507
+ const enablePlaybackStats = function() {
508
+ if (!autoplay && !playbackStats) {
509
+ playbackStats = PlaybackStats(STATS_INTERVAL);
510
+ }
511
+ }
512
+
513
+ const startPlaybackStats = function() {
514
+ if (!autoplay && playbackStats) {
515
+ playbackStats.start();
516
+ }
517
+ }
518
+
519
+ const stopPlaybackStats = function() {
520
+ if (!autoplay && playbackStats) {
521
+ playbackStats.stop();
522
+ }
523
+ }
524
+
370
525
  const PlaybackStats = function(interval) {
371
526
  const playbackStats = {
372
527
  interval: interval || STATS_INTERVAL,
@@ -374,7 +529,6 @@ const PlaybackStats = function(interval) {
374
529
  stats: null,
375
530
  start: function() {
376
531
  let video = getActualVideoTag();
377
-
378
532
  playbackStats.stop();
379
533
  stats = HTML5Stats(video);
380
534
  playbackStats.timer = setInterval(playbackStats.displayStats, playbackStats.interval);
@@ -412,4 +566,81 @@ const PlaybackStats = function(interval) {
412
566
  }
413
567
  };
414
568
  return playbackStats;
415
- }
569
+ }
570
+
571
+ const initQualityLevels = function(player) {
572
+ if (player && !qualityLevels.length) {
573
+ let playerQualityLevels = player.qualityLevels();
574
+ if (playerQualityLevels) {
575
+ let qualityDiv = document.getElementById("qualityBtns");
576
+ let qualityLevel;
577
+ for (let i = 0; i < playerQualityLevels.length; i++) {
578
+ qualityLevel = QualityLevel(playerQualityLevels, playerQualityLevels[i].height, i, qualityDiv);
579
+ qualityLevels.push(qualityLevel);
580
+ }
581
+ if (qualityLevels.length) {
582
+ qualityLevel = QualityLevel(playerQualityLevels, QUALITY_AUTO, -1, qualityDiv);
583
+ qualityLevels.push(qualityLevel);
584
+ }
585
+ }
586
+ }
587
+ }
588
+
589
+ const disposeQualityLevels = function() {
590
+ qualityLevels.forEach(level => {
591
+ if (level.button) {
592
+ level.button.remove();
593
+ }
594
+ });
595
+ qualityLevels = [];
596
+ }
597
+
598
+ const qualityBtnClick = function(button, playerQualityLevels, index) {
599
+ if (playerQualityLevels && playerQualityLevels.length) {
600
+ let currentIndex = playerQualityLevels.selectedIndex_;
601
+ for (let i = 0; i < playerQualityLevels.length; i++) {
602
+ let qualityLevel = playerQualityLevels[i];
603
+ if (index === -1 || i === index) {
604
+ qualityLevel.enabled = true;
605
+ } else if (i === index) {
606
+ qualityLevel.enabled = true;
607
+ currentIndex = index;
608
+ } else {
609
+ qualityLevel.enabled = false;
610
+ }
611
+ }
612
+ playerQualityLevels.selectedIndex_ = currentIndex;
613
+ playerQualityLevels.trigger({ type: 'change', selectedIndex: currentIndex });
614
+ }
615
+ button.style.color = QUALITY_COLORS.SELECTED;
616
+ qualityLevels.forEach(item => {
617
+ if (item.button.id !== button.id) {
618
+ item.button.style.color = QUALITY_COLORS.AVAILABLE
619
+ }
620
+ });
621
+ }
622
+
623
+ const QualityLevel = function(object, levelId, index, btnParent) {
624
+ const btnId = "qualityBtn";
625
+ let button = document.createElement("button");
626
+ if (levelId === QUALITY_AUTO && index === -1) {
627
+ button.id = btnId + QUALITY_AUTO;
628
+ button.innerHTML = QUALITY_AUTO;
629
+ } else {
630
+ button.id = btnId + index;
631
+ button.innerHTML = levelId;
632
+ }
633
+ button.type = "button";
634
+ button.className = "btn btn-default";
635
+ button.style.color = QUALITY_COLORS.AVAILABLE;
636
+ button.onclick = (event) => {
637
+ qualityBtnClick(button, object, index);
638
+ };
639
+ btnParent.appendChild(button);
640
+ const qualityLevel = {
641
+ level: levelId,
642
+ index: index,
643
+ button: button
644
+ };
645
+ return qualityLevel;
646
+ }
@@ -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="playStream">Auth</label>
33
+ for="key">Auth</label>
34
34
 
35
35
  <div class="col-sm-12">
36
36
  <div class="col-sm-4 nopadding">
@@ -43,16 +43,52 @@
43
43
  </div>
44
44
  </div>
45
45
  </div>
46
- <div class="row" style="margin-top: 20px">
47
- <div class="col-sm-4 text-left">
48
- <div id="llHlsMode" style="display: none;">
49
- <input id="llHlsEnabled" class="form-check-input" type="checkbox" value="">
50
- <label class="form-check-label" for="llHlsEnabled">Low latency HLS</label>
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"/>
51
54
  </div>
52
55
  </div>
53
- <div class="col-sm-5">
54
- <div id="backward" style="display: none;">
55
- <label class="form-check-label text-right" for="backBtnMax">&lt;&lt; seconds</label>
56
+ </div>
57
+
58
+ <div class="row" style="margin-top: 10px">
59
+ <div class="col-sm-4 text-left" id="llHlsMode" style="display: none;">
60
+ <input id="llHlsEnabled" class="form-check-input" type="checkbox" value="">
61
+ <label class="form-check-label" for="llHlsEnabled">Low latency HLS</label>
62
+ </div>
63
+ </div>
64
+ <div class="row" style="margin-top: 5px">
65
+ <div class="col-sm-12 text-center">
66
+ <a id="permalink" href="#">Permalink</a>
67
+ </div>
68
+ </div>
69
+ <div class="row" style="margin-top: 10px">
70
+ <div class="col-sm-12 text-center">
71
+ <button id="applyBtn" type="button" class="btn btn-default">Play</button>
72
+ </div>
73
+ </div>
74
+
75
+ <div class="row" style="margin-top: 10px">
76
+ <div class="col-sm-12" id="quality" style="display: none;">
77
+ <div class="col-sm-4 text-right">
78
+ <label class="form-check-label" for="qualityBtns">Quality</label>
79
+ </div>
80
+ <div class="col-sm-8 text-center">
81
+ <div class="input-group-btn" id="qualityBtns">
82
+ </div>
83
+ </div>
84
+ </div>
85
+ </div>
86
+ <div class="row" style="margin-top: 10px">
87
+ <div class="col-sm-12" id="backward" style="display: none;">
88
+ <div class="col-sm-4 text-right">
89
+ <label class="form-check-label" for="backBtnMax">Rewind back</label>
90
+ </div>
91
+ <div class="col-sm-8 text-center">
56
92
  <div class="input-group-btn">
57
93
  <button id="backBtnMax" type="button" class="btn btn-default">Max</button>
58
94
  <button id="backBtn30" type="button" class="btn btn-default">30</button>
@@ -61,15 +97,12 @@
61
97
  </div>
62
98
  </div>
63
99
  </div>
64
- <div class="col-sm-3 text-right">
65
- <button id="applyBtn" type="button" class="btn btn-default">Play</button>
66
- </div>
67
100
  </div>
68
101
  </fieldset>
69
102
  </div>
70
103
  </div>
71
104
  <div class="row">
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">
105
+ <div id="videoContainer" style="margin-top: 20px; width: available; height: 56.25vw">
73
106
  <video id="remoteVideo"
74
107
  width="100%"
75
108
  height="100%"