UNPKG

shaka-player

Version:
280 lines (254 loc) 7.7 kB
/*! @license * Shaka Player * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ goog.provide('shaka.queue.QueueManager'); goog.require('goog.asserts'); goog.require('shaka.Player'); goog.require('shaka.config.RepeatMode'); goog.require('shaka.util.Error'); goog.require('shaka.util.EventManager'); goog.require('shaka.util.FakeEvent'); goog.require('shaka.util.FakeEventTarget'); goog.require('shaka.util.IDestroyable'); goog.requireType('shaka.media.PreloadManager'); /** * @implements {shaka.extern.IQueueManager} * @implements {shaka.util.IDestroyable} * @export */ shaka.queue.QueueManager = class extends shaka.util.FakeEventTarget { /** * @param {shaka.Player} player */ constructor(player) { super(); /** @private {?shaka.Player} */ this.player_ = player; /** @private {?shaka.extern.QueueConfiguration} */ this.config_ = null; /** @private {!Array<shaka.extern.QueueItem>} */ this.items_ = []; /** @private {number} */ this.currentItemIndex_ = -1; /** * @private {?{item: shaka.extern.QueueItem, * preloadManager: ?shaka.media.PreloadManager}} */ this.preloadNext_ = null; /** @private {shaka.util.EventManager} */ this.eventManager_ = new shaka.util.EventManager(); } /** * @override * @export */ async destroy() { await this.removeAllItems(); this.player_ = null; if (this.eventManager_) { this.eventManager_.release(); this.eventManager_ = null; } // FakeEventTarget implements IReleasable super.release(); } /** * @override * @export */ configure(config) { this.config_ = config; } /** * @override * @export */ getConfiguration() { return this.config_; } /** * @override * @export */ getCurrentItem() { if (this.items_.length && this.currentItemIndex_ >= 0 && this.currentItemIndex_ < this.items_.length) { return this.items_[this.currentItemIndex_]; } return null; } /** * @override * @export */ getCurrentItemIndex() { return this.currentItemIndex_; } /** * @override * @export */ getItems() { return this.items_.slice(); } /** * @override * @export */ insertItems(items) { this.items_.push(...items); this.dispatchEvent(new shaka.util.FakeEvent( shaka.util.FakeEvent.EventName.ItemsInserted)); } /** * @override * @export */ async removeAllItems() { this.eventManager_.removeAll(); if (this.items_.length && this.currentItemIndex_ >= 0) { await this.player_.unload(); } if (this.preloadNext_) { if (!this.preloadNext_.preloadManager.isDestroyed()) { await this.preloadNext_.preloadManager.destroy(); } this.preloadNext_ = null; } this.items_ = []; this.currentItemIndex_ = -1; this.dispatchEvent(new shaka.util.FakeEvent( shaka.util.FakeEvent.EventName.ItemsRemoved)); } /** * @override * @export */ async playItem(itemIndex) { goog.asserts.assert(this.player_, 'We should have player'); this.eventManager_.removeAll(); if (!this.items_.length || itemIndex >= this.items_.length) { throw new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.PLAYER, shaka.util.Error.Code.QUEUE_INDEX_OUT_OF_BOUNDS); } const item = this.items_[itemIndex]; if (this.currentItemIndex_ != itemIndex) { this.currentItemIndex_ = itemIndex; this.dispatchEvent(new shaka.util.FakeEvent( shaka.util.FakeEvent.EventName.CurrentItemChanged)); } const mediaElement = this.player_.getMediaElement(); const preloadNextUrlWindow = this.config_ ? this.config_.preloadNextUrlWindow : 0; if (preloadNextUrlWindow > 0) { let preloadInProcess = false; this.eventManager_.listen(mediaElement, 'timeupdate', async () => { if (this.preloadNext_ || this.items_.length <= 1 || preloadInProcess || this.player_.isLive() || !mediaElement.duration) { return; } const timeToEnd = this.player_.seekRange().end - mediaElement.currentTime; if (!isNaN(timeToEnd)) { if (timeToEnd <= preloadNextUrlWindow) { const repeatMode = this.config_ && this.config_.repeatMode; let nextItem = null; if ((this.currentItemIndex_ + 1) < this.items_.length) { nextItem = this.items_[this.currentItemIndex_ + 1]; } else if (repeatMode == shaka.config.RepeatMode.ALL) { nextItem = this.items_[0]; } if (nextItem) { preloadInProcess = true; let preloadManager = null; try { preloadManager = await this.player_.preload( nextItem.manifestUri, nextItem.startTime, nextItem.mimeType, nextItem.config); } catch (error) { preloadManager = null; // Ignore errors. } this.preloadNext_ = { item: nextItem, preloadManager, }; preloadInProcess = false; } } } }); } this.eventManager_.listen(this.player_, 'complete', () => { const repeatMode = this.config_ && this.config_.repeatMode; let playAgain = false; if (repeatMode == shaka.config.RepeatMode.SINGLE) { playAgain = true; } else { const nextItemIndex = this.currentItemIndex_ + 1; if (nextItemIndex < this.items_.length) { this.playItem(nextItemIndex); } else if (repeatMode == shaka.config.RepeatMode.ALL) { if (this.items_.length == 1) { playAgain = true; } else { this.playItem(0); } } } if (playAgain) { if (mediaElement.paused) { mediaElement.currentTime = this.player_.seekRange().start; mediaElement.play(); } else { this.eventManager_.listen(mediaElement, 'paused', () => { mediaElement.currentTime = this.player_.seekRange().start; mediaElement.play(); }); } } }); if (item.config) { this.player_.resetConfiguration(); this.player_.configure(item.config); } let assetUriOrPreloader = item.manifestUri; if (this.preloadNext_ && this.preloadNext_.item == item && this.preloadNext_.preloadManager) { assetUriOrPreloader = this.preloadNext_.preloadManager; } await this.player_.load(assetUriOrPreloader, item.startTime, item.mimeType); this.preloadNext_ = null; if (item.extraText) { for (const extraText of item.extraText) { if (extraText.mime) { this.player_.addTextTrackAsync(extraText.uri, extraText.language, extraText.kind, extraText.mime, extraText.codecs); } else { this.player_.addTextTrackAsync(extraText.uri, extraText.language, extraText.kind); } } } if (item.extraThumbnail) { for (const extraThumbnail of item.extraThumbnail) { this.player_.addThumbnailsTrack(extraThumbnail); } } if (item.extraChapter) { for (const extraChapter of item.extraChapter) { this.player_.addChaptersTrack( extraChapter.uri, extraChapter.language, extraChapter.mime); } } } }; shaka.Player.setQueueManagerFactory((player) => { return new shaka.queue.QueueManager(player); });