From c360b4effb82935dc8386e27ef0ca8b51b19710d Mon Sep 17 00:00:00 2001 From: muhammad-ammar <mammar@gmail.com> Date: Thu, 3 May 2018 17:34:02 +0500 Subject: [PATCH] fix poster display issue with hls EDUCATOR-2606 another approach --- .../js/src/video/02_html5_hls_video.js | 31 +++++++++++++- .../xmodule/js/src/video/02_html5_video.js | 42 +++++++++++++++++-- .../xmodule/js/src/video/03_video_player.js | 6 +++ .../tests/video/test_video_module.py | 9 +++- 4 files changed, 83 insertions(+), 5 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/video/02_html5_hls_video.js b/common/lib/xmodule/xmodule/js/src/video/02_html5_hls_video.js index 4df4794043e..f2124c06431 100644 --- a/common/lib/xmodule/xmodule/js/src/video/02_html5_hls_video.js +++ b/common/lib/xmodule/xmodule/js/src/video/02_html5_hls_video.js @@ -20,23 +20,40 @@ function Player(el, config) { var self = this; + this.config = config; + // do common initialization independent of player type this.init(el, config); + _.bindAll(this, 'playVideo', 'onReady'); + // If we have only HLS sources and browser doesn't support HLS then show error message. if (config.HLSOnlySources && !config.canPlayHLS) { this.showErrorMessage(null, '.video-hls-error'); return; } + this.config.state.el.on('initialize', _.once(function() { + console.log('[HLS Video]: HLS Player initialized'); + self.showPlayButton(); + })); + // Safari has native support to play HLS videos if (config.browserIsSafari) { this.videoEl.attr('src', config.videoSources[0]); } else { - this.hls = new HLS(); + this.hls = new HLS({autoStartLoad: false}); this.hls.loadSource(config.videoSources[0]); this.hls.attachMedia(this.video); + this.showLoadingOnce = _.once(function() { + HTML5Video.Player.prototype.updatePlayerLoadingState.apply(self, ['show']); + }); + + this.hideLoadingOnce = _.once(function() { + HTML5Video.Player.prototype.updatePlayerLoadingState.apply(self, ['hide']); + }); + this.hls.on(HLS.Events.ERROR, this.onError.bind(this)); this.hls.on(HLS.Events.MANIFEST_PARSED, function(event, data) { @@ -49,6 +66,7 @@ }; }) ); + self.config.onReadyHLS(); }); this.hls.on(HLS.Events.LEVEL_SWITCHED, function(event, data) { var level = self.hls.levels[data.level]; @@ -59,6 +77,7 @@ resolution: level.width + 'x' + level.height } ); + self.hideLoadingOnce(); }); } } @@ -66,6 +85,16 @@ Player.prototype = Object.create(HTML5Video.Player.prototype); Player.prototype.constructor = Player; + Player.prototype.playVideo = function() { + this.hls.startLoad(); + this.video.play(); + this.showLoadingOnce(); + }; + + Player.prototype.onReady = function() { + this.config.events.onReady(null); + }; + /** * Handler for HLS video errors. This only takes care of fatal erros, non-fatal errors * are automatically handled by hls.js diff --git a/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js b/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js index 367939e21a7..f24a08b5fba 100644 --- a/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js +++ b/common/lib/xmodule/xmodule/js/src/video/02_html5_video.js @@ -95,6 +95,38 @@ function(_) { this.videoEl.on('error', this.onError.bind(this)); } + Player.prototype.showPlayButton = function() { + this.videoOverlayEl.removeClass('is-hidden'); + }; + + Player.prototype.hidePlayButton = function() { + this.videoOverlayEl.addClass('is-hidden'); + }; + + Player.prototype.showLoading = function() { + this.el + .removeClass('is-initialized') + .find('.spinner') + .removeAttr('tabindex') + .attr({'aria-hidden': 'false'}); + }; + + Player.prototype.hideLoading = function() { + this.el + .addClass('is-initialized') + .find('.spinner') + .attr({'aria-hidden': 'false', 'tabindex': -1}); + }; + + Player.prototype.updatePlayerLoadingState = function(state) { + if (state === 'show') { + this.hidePlayButton(); + this.showLoading(); + } else if (state === 'hide') { + this.hideLoading(); + } + }; + Player.prototype.callStateChangeCallback = function() { if ($.isFunction(this.config.events.onStateChange)) { this.config.events.onStateChange({ @@ -211,11 +243,15 @@ function(_) { this.videoEl.remove(); }; + Player.prototype.onReady = function() { + this.config.events.onReady(null); + this.showPlayButton(); + }; + Player.prototype.onLoadedMetadata = function() { this.playerState = HTML5Video.PlayerState.PAUSED; if ($.isFunction(this.config.events.onReady)) { - this.config.events.onReady(null); - this.videoOverlayEl.removeClass('is-hidden'); + this.onReady(); } }; @@ -234,7 +270,7 @@ function(_) { Player.prototype.onPause = function() { this.playerState = HTML5Video.PlayerState.PAUSED; this.callStateChangeCallback(); - this.videoOverlayEl.removeClass('is-hidden'); + this.showPlayButton(); }; Player.prototype.onEnded = function() { diff --git a/common/lib/xmodule/xmodule/js/src/video/03_video_player.js b/common/lib/xmodule/xmodule/js/src/video/03_video_player.js index fee8806aa93..44b54d82f81 100644 --- a/common/lib/xmodule/xmodule/js/src/video/03_video_player.js +++ b/common/lib/xmodule/xmodule/js/src/video/03_video_player.js @@ -179,6 +179,8 @@ function(HTML5Video, HTML5HLSVideo, Resizer, HLS, _, Time) { state.videoPlayer.player = new HTML5HLSVideo.Player( state.el, _.extend({}, commonPlayerConfig, { + state: state, + onReadyHLS: onReadyHLS, videoSources: state.HLSVideoSources, canPlayHLS: state.canPlayHLS, HLSOnlySources: state.HLSOnlySources @@ -559,6 +561,10 @@ function(HTML5Video, HTML5HLSVideo, Resizer, HLS, _, Time) { this.el.trigger('qualitychange', arguments); } + function onReadyHLS() { + dfd.resolve(); + } + function onReady() { var _this = this, availablePlaybackRates, baseSpeedSubs, diff --git a/common/test/acceptance/tests/video/test_video_module.py b/common/test/acceptance/tests/video/test_video_module.py index a9350804f8c..bd1a9f5a5b1 100644 --- a/common/test/acceptance/tests/video/test_video_module.py +++ b/common/test/acceptance/tests/video/test_video_module.py @@ -1142,7 +1142,7 @@ class HLSVideoTest(VideoBaseTest): self.navigate_to_video() self.video.click_player_button('play') - self.assertEqual(self.video.state, 'playing') + self.assertIn(self.video.state, ['buffering', 'playing']) self.video.click_player_button('pause') self.assertEqual(self.video.state, 'pause') @@ -1231,6 +1231,7 @@ class HLSVideoTest(VideoBaseTest): Given the course has a Video component with "HLS" video only And I have defined a transcript for the video Then I see the correct text in the captions for transcript + Then I play, pause and seek to 0:00 Then I click on a caption line And video position should be updated accordingly Then I change video position @@ -1243,6 +1244,12 @@ class HLSVideoTest(VideoBaseTest): self.assertIn("Hi, edX welcomes you0.", self.video.captions_text) + # This is required to load the video + self.video.click_player_button('play') + # Below 2 steps are required to test the caption line click scenario + self.video.click_player_button('pause') + self.video.seek('0:00') + for line_no in range(5): self.video.click_transcript_line(line_no=line_no) self.video.wait_for_position('0:0{}'.format(line_no)) -- GitLab