diff --git a/README.md b/README.md index c3d6435..b232547 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A [clappr](https://github.com/clappr/clappr) playback to play dash based on the amazing [shaka-player](https://github.com/google/shaka-player). -> CDN JSDELIVR: https://cdn.jsdelivr.net/gh/clappr/dash-shaka-playback@latest/dist/dash-shaka-playback.js +> CDN JSDELIVR: https://cdn.jsdelivr.net/npm/dash-shaka-playback@latest/dist/dash-shaka-playback.min.js > > CDNJS: https://cdnjs.cloudflare.com/ajax/libs/dash-shaka-playback/2.0.5/dash-shaka-playback.js > @@ -24,8 +24,8 @@ A [clappr](https://github.com/clappr/clappr) playback to play dash based on the ```html
- - + + diff --git a/public/index.html b/public/index.html index 7417573..4b0720f 100644 --- a/public/index.html +++ b/public/index.html @@ -44,8 +44,8 @@ }) } - + + - diff --git a/src/clappr-dash-shaka-playback.js b/src/clappr-dash-shaka-playback.js index 2d53266..f377160 100644 --- a/src/clappr-dash-shaka-playback.js +++ b/src/clappr-dash-shaka-playback.js @@ -73,7 +73,9 @@ class DashShakaPlayback extends HTML5Video { } getCurrentTime() { - return this.shakaPlayerInstance.getMediaElement().currentTime - this.seekRange.start + return this.shakaPlayerInstance + ? this.shakaPlayerInstance.getMediaElement().currentTime - this.seekRange.start + : 0 } get _startTime() { @@ -81,7 +83,14 @@ class DashShakaPlayback extends HTML5Video { } get presentationTimeline() { - return this.shakaPlayerInstance.getManifest().presentationTimeline + // Manifest may equals null (for example, source load failure) + let manifest = this.shakaPlayerInstance + ? this.shakaPlayerInstance.getManifest() + : null + + return manifest + ? manifest.presentationTimeline + : null } get bandwidthEstimate() { @@ -99,7 +108,11 @@ class DashShakaPlayback extends HTML5Video { } getProgramDateTime() { - return new Date((this.presentationTimeline.getPresentationStartTime() + this.seekRange.start) * 1000) + let presentationStartTime = this.presentationTimeline + ? this.presentationTimeline.getPresentationStartTime() + : null + + return new Date((presentationStartTime + this.seekRange.start) * 1000) } _updateDvr(status) { @@ -127,7 +140,10 @@ class DashShakaPlayback extends HTML5Video { play () { if (!this._player) { - this._setup() + // User interaction is lost when Shaka instance load() fetch the manifest + // Calling consent() before setup Shaka instance fix this issue (Safari browser on macOS) + this.consent() + process.nextTick(() => this._setup()) } if (!this.isReady) { @@ -155,15 +171,13 @@ class DashShakaPlayback extends HTML5Video { // skipping HTML5Video `_setupSrc` (on tag video) _setupSrc () {} - // skipping ready event on video tag in favor of ready on shaka _ready () { - // override with no-op + this.trigger(Events.PLAYBACK_READY, this.name) } _onShakaReady() { this._isShakaReadyState = true this.trigger(DashShakaPlayback.Events.SHAKA_READY) - this.trigger(Events.PLAYBACK_READY, this.name) } get isReady () { @@ -385,11 +399,46 @@ class DashShakaPlayback extends HTML5Video { this._checkForClosedCaptions() } - _fillLevels () { - if (this._levels.length === 0) { - this._levels = this.videoTracks.map((videoTrack) => { return {id: videoTrack.id, label: `${videoTrack.height}p`} }).reverse() - this.trigger(Events.PLAYBACK_LEVELS_AVAILABLE, this.levels) + _hasMultipleLanguages() { + let lang + let tracks = this.videoTracks + + for (let i = 0; i < tracks.length; ++i) { + if (i === 0) { + lang = tracks[i].language + continue + } + + if (lang !== tracks[i].language) + return true } + + return false + } + + _fillLevels () { + if (this._levels.length !== 0) + return + + // If multiple language available, add it to label + let labelWithLanguage = this._hasMultipleLanguages() + + this._levels = this.videoTracks.map((videoTrack) => { + return { + id: videoTrack.id, + level: videoTrack, + label: labelWithLanguage ? `${videoTrack.bandwidth/1000}Kbps - ${videoTrack.language}` : `${videoTrack.bandwidth/1000}Kbps`, + } + }) + + if (labelWithLanguage) + // Sort by language ASC, bandwidth DESC + this._levels.sort((a, b) => (a.level.language > b.level.language) ? 1 : (a.level.language === b.level.language) ? ((a.level.bandwidth < b.level.bandwidth) ? 1 : -1) : -1 ) + else + // Sort by bandwidth DESC + this._levels.sort((a, b) => (a.level.bandwidth < b.level.bandwidth) ? 1 : -1) + + this.trigger(Events.PLAYBACK_LEVELS_AVAILABLE, this.levels) } _startToSendStats () {