Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

bitmovin-player-ui

Package Overview
Dependencies
Maintainers
1
Versions
141
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bitmovin-player-ui - npm Package Compare versions

Comparing version 3.31.0 to 3.32.0

dist/js/framework/components/seekbarbufferlevel.d.ts

15

CHANGELOG.md

@@ -7,8 +7,14 @@ # Change Log

## [3.31.0]
## [3.32.0] - 2021-12-21 - 2021-12-21
### Fixed
- The scrubber could jump to an old position during a seek operation when it was dragged.
- The Seekbar scrubber could jump to an old position on touch devices when the buffer updates during a seek operation.
## [3.31.0] - 2021-10-12
### Added
- Style reset for subtitle overlay element to prevent undesired CSS rules collisions.
## [3.30.0]
## [3.30.0] - 2021-09-14

@@ -18,3 +24,3 @@ ### Added

## [3.29.0]
## [3.29.0] - 2021-08-19

@@ -24,3 +30,3 @@ ### Fixed

## [3.28.1]
## [3.28.1] - 2021-06-25

@@ -760,2 +766,3 @@ ### Fixed

[3.32.0]: https://github.com/bitmovin/bitmovin-player-ui/compare/v3.31.0...v3.32.0
[3.31.0]: https://github.com/bitmovin/bitmovin-player-ui/compare/v3.30.0...v3.31.0

@@ -762,0 +769,0 @@ [3.30.0]: https://github.com/bitmovin/bitmovin-player-ui/compare/v3.29.0...v3.30.0

@@ -96,2 +96,4 @@ import { Component, ComponentConfig } from './component';

private setAriaSliderValues;
private getPlaybackPositionPercentage;
private updateBufferLevel;
configure(player: PlayerAPI, uimanager: UIInstanceManager, configureSeek?: boolean): void;

@@ -98,0 +100,0 @@ private initializeTimelineMarkers;

@@ -27,2 +27,3 @@ "use strict";

var timelinemarkershandler_1 = require("./timelinemarkershandler");
var seekbarbufferlevel_1 = require("./seekbarbufferlevel");
/**

@@ -117,2 +118,19 @@ * A seek bar to seek within the player's media. It displays the current playback position, amount of buffed data, seek

};
SeekBar.prototype.getPlaybackPositionPercentage = function () {
if (this.player.isLive()) {
return 100 - (100 / this.player.getMaxTimeShift() * this.player.getTimeShift());
}
return 100 / this.player.getDuration() * this.getRelativeCurrentTime();
};
SeekBar.prototype.updateBufferLevel = function (playbackPositionPercentage) {
var bufferLoadedPercentageLevel;
if (this.player.isLive()) {
// Always show full buffer for live streams
bufferLoadedPercentageLevel = 100;
}
else {
bufferLoadedPercentageLevel = playbackPositionPercentage + seekbarbufferlevel_1.getMinBufferLevel(this.player);
}
this.setBufferPosition(bufferLoadedPercentageLevel);
};
SeekBar.prototype.configure = function (player, uimanager, configureSeek) {

@@ -144,2 +162,3 @@ var _this = this;

var isPlaying = false;
var scrubbing = false;
var isUserSeeking = false;

@@ -155,2 +174,11 @@ var isPlayerSeeking = false;

}
var playbackPositionPercentage = _this.getPlaybackPositionPercentage();
_this.updateBufferLevel(playbackPositionPercentage);
// The segment request finished is used to help the playback position move, when the smooth playback position is not enabled.
// At the same time when the user is scrubbing, we also move the position of the seekbar to display a preview during scrubbing.
// When the user is scrubbing we do not record this as a user seek operation, as the user has yet to finish their seek,
// but we should not move the playback position to not create a jumping behaviour.
if (scrubbing && event.type === player.exports.PlayerEvent.SegmentRequestFinished && playbackPositionPercentage !== _this.playbackPositionPercentage) {
playbackPositionPercentage = _this.playbackPositionPercentage;
}
if (player.isLive()) {

@@ -162,31 +190,18 @@ if (player.getMaxTimeShift() === 0) {

else {
var playbackPositionPercentage = 100 - (100 / player.getMaxTimeShift() * player.getTimeShift());
_this.setPlaybackPosition(playbackPositionPercentage);
if (!_this.isSeeking()) {
_this.setPlaybackPosition(playbackPositionPercentage);
}
_this.setAriaSliderMinMax(player.getMaxTimeShift().toString(), '0');
}
// Always show full buffer for live streams
_this.setBufferPosition(100);
}
else {
var playerDuration = player.getDuration();
var playbackPositionPercentage = 100 / playerDuration * _this.getRelativeCurrentTime();
var videoBufferLength = player.getVideoBufferLength();
var audioBufferLength = player.getAudioBufferLength();
// Calculate the buffer length which is the smaller length of the audio and video buffers. If one of these
// buffers is not available, we set it's value to MAX_VALUE to make sure that the other real value is taken
// as the buffer length.
var bufferLength = Math.min(videoBufferLength != null ? videoBufferLength : Number.MAX_VALUE, audioBufferLength != null ? audioBufferLength : Number.MAX_VALUE);
// If both buffer lengths are missing, we set the buffer length to zero
if (bufferLength === Number.MAX_VALUE) {
bufferLength = 0;
}
var bufferPercentage = 100 / playerDuration * bufferLength;
// Update playback position only in paused state or in the initial startup state where player is neither
// paused nor playing. Playback updates are handled in the Timeout below.
if (_this.config.smoothPlaybackPositionUpdateIntervalMs === SeekBar.SMOOTH_PLAYBACK_POSITION_UPDATE_DISABLED
|| forceUpdate || player.isPaused() || (player.isPaused() === player.isPlaying())) {
var isInInitialStartupState = _this.config.smoothPlaybackPositionUpdateIntervalMs === SeekBar.SMOOTH_PLAYBACK_POSITION_UPDATE_DISABLED
|| forceUpdate || player.isPaused();
var isNeitherPausedNorPlaying = player.isPaused() === player.isPlaying();
if ((isInInitialStartupState || isNeitherPausedNorPlaying) && !_this.isSeeking()) {
_this.setPlaybackPosition(playbackPositionPercentage);
}
_this.setBufferPosition(playbackPositionPercentage + bufferPercentage);
_this.setAriaSliderMinMax('0', playerDuration.toString());
_this.setAriaSliderMinMax('0', player.getDuration().toString());
}

@@ -204,4 +219,2 @@ if (_this.isUiShown) {

player.on(player.exports.PlayerEvent.StallEnded, playbackPositionHandler);
// update playback position when a seek has finished
player.on(player.exports.PlayerEvent.Seeked, playbackPositionHandler);
// update playback position when a timeshift has finished

@@ -216,6 +229,11 @@ player.on(player.exports.PlayerEvent.TimeShifted, playbackPositionHandler);

_this.setSeeking(true);
scrubbing = false;
};
var onPlayerSeeked = function () {
var onPlayerSeeked = function (event, forceUpdate) {
if (event === void 0) { event = null; }
if (forceUpdate === void 0) { forceUpdate = false; }
isPlayerSeeking = false;
_this.setSeeking(false);
// update playback position when a seek has finished
playbackPositionHandler(event, forceUpdate);
};

@@ -250,2 +268,3 @@ var restorePlayingState = function () {

uimanager.onSeekPreview.dispatch(sender, args);
scrubbing = args.scrubbing;
});

@@ -373,2 +392,5 @@ // Rate-limited scrubbing seek

this.smoothPlaybackPositionUpdater = new timeout_1.Timeout(updateIntervalMs, function () {
if (_this.isSeeking()) {
return;
}
currentTimeSeekBar += currentTimeUpdateDeltaSecs;

@@ -375,0 +397,0 @@ try {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.version = void 0;
exports.version = '3.31.0';
exports.version = '3.32.0';
// Management

@@ -6,0 +6,0 @@ var uimanager_1 = require("./uimanager");

{
"name": "bitmovin-player-ui",
"version": "3.31.0",
"version": "3.32.0",
"description": "Bitmovin Player UI Framework",

@@ -5,0 +5,0 @@ "main": "./dist/js/framework/main.js",

@@ -55,2 +55,112 @@ import { MockHelper, TestingPlayerAPI } from '../helper/MockHelper';

});
describe('playback position', () => {
let setPlaybackPositionSpy: jest.SpyInstance;
beforeEach(() => {
jest.spyOn(playerMock, 'getDuration').mockReturnValue(20);
seekbar.configure(playerMock, uiInstanceManagerMock);
setPlaybackPositionSpy = jest.spyOn(seekbar, 'setPlaybackPosition');
})
test.each`
isLive | isSeeking | timesCalled
${false} | ${true} | ${0}
${true} | ${true} | ${0}
${false} | ${false} | ${1}
${true} | ${false} | ${1}
`('will not be set when isLive=$isLive, isSeeking=$isSeeking and a stall ended event is fired',
({isLive, isSeeking, timesCalled}) => {
if (isLive) {
jest.spyOn(playerMock, 'getMaxTimeShift').mockReturnValue(-60);
}
jest.spyOn(seekbar, 'isSeeking').mockReturnValue(isSeeking);
jest.spyOn(playerMock, 'isLive').mockReturnValue(isLive);
playerMock.eventEmitter.fireStallEndedEvent();
expect(setPlaybackPositionSpy).toHaveBeenCalledTimes(timesCalled);
})
it('will be moved after a successful seeked event', () => {
playerMock.eventEmitter.fireSeekedEvent();
expect(setPlaybackPositionSpy).toHaveBeenCalledTimes(1);
});
it('will move after a successful segment request download', () => {
playerMock.eventEmitter.fireSegmentRequestFinished();
expect(setPlaybackPositionSpy).toHaveBeenCalledTimes(1);
});
describe('vod event tracking', () => {
let setBufferPositionSpy: jest.SpyInstance;
beforeEach(() => {
setBufferPositionSpy = jest.spyOn(seekbar, 'setBufferPosition');
jest.spyOn(playerMock, 'getDuration').mockReturnValue(50);
jest.spyOn(playerMock, 'getSeekableRange').mockImplementation(() => ({start: 30, end: 40}));
const currentTime = 35;
jest.spyOn(playerMock, 'getCurrentTime').mockReturnValue(currentTime);
playerMock.eventEmitter.fireSeekEvent(currentTime);
playerMock.eventEmitter.fireSeekedEvent();
})
it('will use the last known playback position location after a successful segment request download and the user is scrubbing', () => {
const firstPlaybackPercentage = seekbar['playbackPositionPercentage'];
jest.spyOn(playerMock, 'getSeekableRange').mockImplementation(() => ({start: 26, end: 30}));
seekbar['onSeekPreviewEvent'](40, true)
playerMock.eventEmitter.fireSegmentRequestFinished();
expect(setPlaybackPositionSpy).toHaveBeenLastCalledWith(firstPlaybackPercentage);
const expectedPlaybackPercentage = 18;
expect(setBufferPositionSpy).toHaveBeenLastCalledWith(expectedPlaybackPercentage)
});
it('will update the scrubber location after a successful segment request download and the user is not scrubbing', () => {
jest.spyOn(playerMock, 'getSeekableRange').mockImplementation(() => ({start: 26, end: 30}));
seekbar['onSeekPreviewEvent'](18, false)
playerMock.eventEmitter.fireSegmentRequestFinished();
expect(setPlaybackPositionSpy).toHaveBeenLastCalledWith(18);
expect(setBufferPositionSpy).toHaveBeenLastCalledWith(18)
});
});
})
describe('buffer levels', () => {
beforeEach(() => {
jest.spyOn(playerMock, 'getDuration').mockReturnValue(20);
jest.spyOn(playerMock, 'getMaxTimeShift').mockReturnValue(-60);
seekbar.configure(playerMock, uiInstanceManagerMock);
})
test.each`
isLive
${true}
${false}
`('should get updated accordingly when a request has finished and isLive=$isLive', ({isLive}) => {
const setBufferPositionSpy = jest.spyOn(seekbar, 'setBufferPosition');
jest.spyOn(playerMock, 'isLive').mockReturnValue(isLive);
jest.spyOn(playerMock, 'getCurrentTime').mockReturnValue(35);
jest.spyOn(playerMock, 'getSeekableRange').mockReturnValue({start:30, end: 40});
playerMock.eventEmitter.fireSegmentRequestFinished();
expect(setBufferPositionSpy).toHaveBeenCalledTimes(1);
expect(setBufferPositionSpy).toHaveBeenCalledWith(isLive ? 100 : 25);
})
});
});

@@ -108,2 +108,3 @@ import { PlayerAPI, PlayerEvent } from 'bitmovin-player';

isViewModeAvailable: jest.fn(),
seek: jest.fn(),

@@ -110,0 +111,0 @@ // Event faker

@@ -16,2 +16,3 @@ import {

SeekEvent,
SegmentRequestFinishedEvent,
SubtitleCueEvent,

@@ -66,2 +67,17 @@ SubtitleEvent,

public fireSegmentRequestFinished() {
this.fireEvent<SegmentRequestFinishedEvent>({
timestamp: Date.now(),
type: PlayerEvent.SegmentRequestFinished,
httpStatus: 200,
downloadTime: 0,
mimeType: 'video/mp4',
success: true,
uid: 'unique-id',
size: 1,
duration: 1,
isInit: false,
});
}
fireAdBreakFinishedEvent(): void {

@@ -68,0 +84,0 @@ this.fireEvent<AdBreakEvent>({

@@ -17,2 +17,3 @@ import { Component, ComponentConfig } from './component';

import { TimelineMarkersHandler } from './timelinemarkershandler';
import { getMinBufferLevel } from './seekbarbufferlevel';

@@ -175,2 +176,23 @@ /**

private getPlaybackPositionPercentage(): number {
if (this.player.isLive()) {
return 100 - (100 / this.player.getMaxTimeShift() * this.player.getTimeShift());
}
return 100 / this.player.getDuration() * this.getRelativeCurrentTime();
}
private updateBufferLevel(playbackPositionPercentage: number): void {
let bufferLoadedPercentageLevel: number;
if (this.player.isLive()) {
// Always show full buffer for live streams
bufferLoadedPercentageLevel = 100;
} else {
bufferLoadedPercentageLevel = playbackPositionPercentage + getMinBufferLevel(this.player);
}
this.setBufferPosition(bufferLoadedPercentageLevel);
}
configure(player: PlayerAPI, uimanager: UIInstanceManager, configureSeek: boolean = true): void {

@@ -209,2 +231,3 @@ super.configure(player, uimanager);

let isPlaying = false;
let scrubbing = false;
let isUserSeeking = false;

@@ -220,2 +243,14 @@ let isPlayerSeeking = false;

let playbackPositionPercentage = this.getPlaybackPositionPercentage();
this.updateBufferLevel(playbackPositionPercentage);
// The segment request finished is used to help the playback position move, when the smooth playback position is not enabled.
// At the same time when the user is scrubbing, we also move the position of the seekbar to display a preview during scrubbing.
// When the user is scrubbing we do not record this as a user seek operation, as the user has yet to finish their seek,
// but we should not move the playback position to not create a jumping behaviour.
if (scrubbing && event.type === player.exports.PlayerEvent.SegmentRequestFinished && playbackPositionPercentage !== this.playbackPositionPercentage) {
playbackPositionPercentage = this.playbackPositionPercentage;
}
if (player.isLive()) {

@@ -226,38 +261,20 @@ if (player.getMaxTimeShift() === 0) {

} else {
let playbackPositionPercentage = 100 - (100 / player.getMaxTimeShift() * player.getTimeShift());
this.setPlaybackPosition(playbackPositionPercentage);
if (!this.isSeeking()) {
this.setPlaybackPosition(playbackPositionPercentage);
}
this.setAriaSliderMinMax(player.getMaxTimeShift().toString(), '0');
}
// Always show full buffer for live streams
this.setBufferPosition(100);
} else {
const playerDuration = player.getDuration();
let playbackPositionPercentage = 100 / playerDuration * this.getRelativeCurrentTime();
let videoBufferLength = player.getVideoBufferLength();
let audioBufferLength = player.getAudioBufferLength();
// Calculate the buffer length which is the smaller length of the audio and video buffers. If one of these
// buffers is not available, we set it's value to MAX_VALUE to make sure that the other real value is taken
// as the buffer length.
let bufferLength = Math.min(
videoBufferLength != null ? videoBufferLength : Number.MAX_VALUE,
audioBufferLength != null ? audioBufferLength : Number.MAX_VALUE);
// If both buffer lengths are missing, we set the buffer length to zero
if (bufferLength === Number.MAX_VALUE) {
bufferLength = 0;
}
let bufferPercentage = 100 / playerDuration * bufferLength;
// Update playback position only in paused state or in the initial startup state where player is neither
// paused nor playing. Playback updates are handled in the Timeout below.
if (this.config.smoothPlaybackPositionUpdateIntervalMs === SeekBar.SMOOTH_PLAYBACK_POSITION_UPDATE_DISABLED
|| forceUpdate || player.isPaused() || (player.isPaused() === player.isPlaying())) {
const isInInitialStartupState = this.config.smoothPlaybackPositionUpdateIntervalMs === SeekBar.SMOOTH_PLAYBACK_POSITION_UPDATE_DISABLED
|| forceUpdate || player.isPaused();
const isNeitherPausedNorPlaying = player.isPaused() === player.isPlaying();
if ((isInInitialStartupState || isNeitherPausedNorPlaying) && !this.isSeeking()) {
this.setPlaybackPosition(playbackPositionPercentage);
}
this.setBufferPosition(playbackPositionPercentage + bufferPercentage);
this.setAriaSliderMinMax('0', playerDuration.toString());
this.setAriaSliderMinMax('0', player.getDuration().toString());
}

@@ -277,4 +294,2 @@

player.on(player.exports.PlayerEvent.StallEnded, playbackPositionHandler);
// update playback position when a seek has finished
player.on(player.exports.PlayerEvent.Seeked, playbackPositionHandler);
// update playback position when a timeshift has finished

@@ -291,7 +306,11 @@ player.on(player.exports.PlayerEvent.TimeShifted, playbackPositionHandler);

this.setSeeking(true);
scrubbing = false;
};
let onPlayerSeeked = () => {
let onPlayerSeeked = (event: PlayerEventBase = null, forceUpdate: boolean = false ) => {
isPlayerSeeking = false;
this.setSeeking(false);
// update playback position when a seek has finished
playbackPositionHandler(event, forceUpdate);
};

@@ -333,2 +352,3 @@

uimanager.onSeekPreview.dispatch(sender, args);
scrubbing = args.scrubbing;
});

@@ -489,2 +509,6 @@

this.smoothPlaybackPositionUpdater = new Timeout(updateIntervalMs, () => {
if (this.isSeeking()) {
return;
}
currentTimeSeekBar += currentTimeUpdateDeltaSecs;

@@ -491,0 +515,0 @@

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc