mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-14 15:56:38 +03:00
8232c600ce
Fixes https://github.com/shaka-project/shaka-player/issues/6527 Fixes https://github.com/shaka-project/shaka-player/issues/6355 This reverts commit https://github.com/shaka-project/shaka-player/commit/6156dced6bddc5e2cd0cc52071295cff63cadfcd.
197 lines
5.2 KiB
JavaScript
197 lines
5.2 KiB
JavaScript
/*! @license
|
|
* Shaka Player
|
|
* Copyright 2016 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
goog.provide('shaka.media.PlayRateController');
|
|
|
|
goog.require('goog.asserts');
|
|
goog.require('shaka.log');
|
|
goog.require('shaka.util.IReleasable');
|
|
goog.require('shaka.util.Timer');
|
|
|
|
/**
|
|
* The play rate controller controls the playback rate on the media element.
|
|
* This provides some missing functionality (e.g. negative playback rate). If
|
|
* the playback rate on the media element can change outside of the controller,
|
|
* the playback controller will need to be updated to stay in-sync.
|
|
*
|
|
* @implements {shaka.util.IReleasable}
|
|
* @final
|
|
*/
|
|
shaka.media.PlayRateController = class {
|
|
/**
|
|
* @param {shaka.media.PlayRateController.Harness} harness
|
|
*/
|
|
constructor(harness) {
|
|
/** @private {?shaka.media.PlayRateController.Harness} */
|
|
this.harness_ = harness;
|
|
|
|
/** @private {boolean} */
|
|
this.isBuffering_ = false;
|
|
|
|
/** @private {number} */
|
|
this.rate_ = this.harness_.getRate();
|
|
|
|
/** @private {number} */
|
|
this.pollRate_ = 0.25;
|
|
|
|
/** @private {shaka.util.Timer} */
|
|
this.timer_ = new shaka.util.Timer(() => {
|
|
this.harness_.movePlayhead(this.rate_ * this.pollRate_);
|
|
});
|
|
}
|
|
|
|
/** @override */
|
|
release() {
|
|
this.set(this.getDefaultRate());
|
|
if (this.timer_) {
|
|
this.timer_.stop();
|
|
this.timer_ = null;
|
|
}
|
|
|
|
this.harness_ = null;
|
|
}
|
|
|
|
/**
|
|
* Sets the buffering flag, which controls the effective playback rate.
|
|
*
|
|
* @param {boolean} isBuffering If true, forces playback rate to 0 internally.
|
|
*/
|
|
setBuffering(isBuffering) {
|
|
this.isBuffering_ = isBuffering;
|
|
this.apply_();
|
|
}
|
|
|
|
/**
|
|
* Set the playback rate. This rate will only be used as provided when the
|
|
* player is not buffering. You should never set the rate to 0.
|
|
*
|
|
* @param {number} rate
|
|
*/
|
|
set(rate) {
|
|
goog.asserts.assert(rate != 0, 'Should never set rate of 0 explicitly!');
|
|
this.rate_ = rate;
|
|
this.apply_();
|
|
}
|
|
|
|
/**
|
|
* Get the real rate of the playback. This means that if we are using trick
|
|
* play, this will report the trick play rate. If playback is occurring as
|
|
* normal, this will report 1.
|
|
*
|
|
* @return {number}
|
|
*/
|
|
getRealRate() {
|
|
return this.rate_;
|
|
}
|
|
|
|
/**
|
|
* Get the default play rate of the playback.
|
|
*
|
|
* @return {number}
|
|
*/
|
|
getDefaultRate() {
|
|
return this.harness_.getDefaultRate();
|
|
}
|
|
|
|
/**
|
|
* Reapply the effects of |this.rate_| and |this.active_| to the media
|
|
* element. This will only update the rate via the harness if the desired rate
|
|
* has changed.
|
|
*
|
|
* @private
|
|
*/
|
|
apply_() {
|
|
// Always stop the timer. We may not start it again.
|
|
this.timer_.stop();
|
|
|
|
/** @type {number} */
|
|
const rate = this.calculateCurrentRate_();
|
|
|
|
shaka.log.v1('Changing effective playback rate to', rate);
|
|
|
|
if (rate >= 0) {
|
|
try {
|
|
this.applyRate_(rate);
|
|
return;
|
|
} catch (e) {
|
|
// Fall through to the next clause.
|
|
//
|
|
// Fast forward is accomplished through setting video.playbackRate.
|
|
// If the play rate value is not supported by the browser (too big),
|
|
// the browsers will throw.
|
|
// Use this as a cue to fall back to fast forward through repeated
|
|
// seeking, which is what we do for rewind as well.
|
|
}
|
|
}
|
|
|
|
// When moving backwards or forwards in large steps,
|
|
// set the playback rate to 0 so that we can manually
|
|
// seek backwards with out fighting the playhead.
|
|
this.timer_.tickEvery(this.pollRate_);
|
|
this.applyRate_(0);
|
|
}
|
|
|
|
/**
|
|
* Calculate the rate that the controller wants the media element to have
|
|
* based on the current state of the controller.
|
|
*
|
|
* @return {number}
|
|
* @private
|
|
*/
|
|
calculateCurrentRate_() {
|
|
return this.isBuffering_ ? 0 : this.rate_;
|
|
}
|
|
|
|
/**
|
|
* If the new rate is different than the media element's playback rate, this
|
|
* will change the playback rate. If the rate does not need to change, it will
|
|
* not be set. This will avoid unnecessary ratechange events.
|
|
*
|
|
* @param {number} newRate
|
|
* @return {boolean}
|
|
* @private
|
|
*/
|
|
applyRate_(newRate) {
|
|
const oldRate = this.harness_.getRate();
|
|
|
|
if (oldRate != newRate) {
|
|
this.harness_.setRate(newRate);
|
|
}
|
|
|
|
return oldRate != newRate;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* @typedef {{
|
|
* getRate: function():number,
|
|
* getDefaultRate: function():number,
|
|
* setRate: function(number),
|
|
* movePlayhead: function(number)
|
|
* }}
|
|
*
|
|
* @description
|
|
* A layer of abstraction between the controller and what it is controlling.
|
|
* In tests this will be implemented with spies. In production this will be
|
|
* implemented using a media element.
|
|
*
|
|
* @property {function():number} getRate
|
|
* Get the current playback rate being seen by the user.
|
|
*
|
|
* @property {function():number} getDefaultRate
|
|
* Get the default playback rate that the user should see.
|
|
*
|
|
* @property {function(number)} setRate
|
|
* Set the playback rate that the user should see.
|
|
*
|
|
* @property {function(number)} movePlayhead
|
|
* Move the playhead N seconds. If N is positive, the playhead will move
|
|
* forward abs(N) seconds. If N is negative, the playhead will move backwards
|
|
* abs(N) seconds.
|
|
*/
|
|
shaka.media.PlayRateController.Harness;
|