bigscreen-player 5.0.1 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -221
- package/dist/esm/{imscsubtitles-dcaea2e6.js → imscsubtitles-3d139d9a.js} +1 -1
- package/dist/esm/{legacysubtitles-87c46bcc.js → legacysubtitles-bd87e09b.js} +1 -1
- package/dist/esm/{main-dea9f359.js → main-fd918769.js} +237 -29
- package/dist/esm/main.js +1 -1
- package/dist/esm/{msestrategy-f7df73a1.js → msestrategy-af831822.js} +8 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -8,248 +8,45 @@
|
|
|
8
8
|
|
|
9
9
|
*Bigscreen Player* is an open source project developed by the BBC to simplify video and audio playback on a wide range of 'bigscreen' devices (TVs, set-top boxes, games consoles, and streaming devices).
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
For documentation on using this library, please see our [Getting Started guide](https://bbc.github.io/bigscreen-player/api/tutorial-Getting%20Started.html).
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Running Locally
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
The player will render itself into a supplied parent element, and playback will begin as soon as enough data has buffered.
|
|
21
|
-
|
|
22
|
-
```javascript
|
|
23
|
-
import { BigscreenPlayer, MediaKinds, WindowTypes } from 'bigscreen-player'
|
|
24
|
-
|
|
25
|
-
// configure the media player that will be used before loading
|
|
26
|
-
// see below for further details of ths config
|
|
27
|
-
|
|
28
|
-
// options are: msestrategy, nativestrategy, hybridstrategy
|
|
29
|
-
window.bigscreenPlayer.playbackStrategy = 'msestrategy'
|
|
30
|
-
|
|
31
|
-
const bigscreenPlayer = BigscreenPlayer()
|
|
32
|
-
const playbackElement = document.createElement('div')
|
|
33
|
-
const body = document.getElementByTagName('body')[0]
|
|
34
|
-
|
|
35
|
-
playbackElement.id = 'BigscreenPlayback'
|
|
36
|
-
body.appendChild(playbackElement)
|
|
37
|
-
|
|
38
|
-
const minimalData = {
|
|
39
|
-
media: {
|
|
40
|
-
type: 'application/dash+xml',
|
|
41
|
-
urls: [
|
|
42
|
-
{
|
|
43
|
-
url: 'https://example.com/video.mpd'
|
|
44
|
-
}
|
|
45
|
-
]
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const optionalData = {
|
|
50
|
-
initialPlaybackTime: 0, // Time (in seconds) to begin playback from
|
|
51
|
-
media: {
|
|
52
|
-
type: 'application/dash+xml',
|
|
53
|
-
kind: MediaKinds.VIDEO, // Can be VIDEO, or AUDIO
|
|
54
|
-
urls: [
|
|
55
|
-
// Multiple urls offer the ability to fail-over to another CDN if required
|
|
56
|
-
{
|
|
57
|
-
url: 'https://example.com/video.mpd',
|
|
58
|
-
cdn: 'origin' // For Debug Tool reference
|
|
59
|
-
}, {
|
|
60
|
-
url: 'https://failover.example.com/video.mpd',
|
|
61
|
-
cdn: 'failover'
|
|
62
|
-
}
|
|
63
|
-
],
|
|
64
|
-
captions: [{
|
|
65
|
-
url: 'https://example.com/captions/$segment$', // $segment$ required for replacement for live subtitle segments
|
|
66
|
-
segmentLength: 3.84, // Required to calculate live subtitle segment to fetch & live subtitle URL.
|
|
67
|
-
cdn: 'origin' // Displayed by Debug Tool
|
|
68
|
-
}, {
|
|
69
|
-
url: 'https://failover.example.com/captions/$segment$',
|
|
70
|
-
segmentLength: 3.84,
|
|
71
|
-
cdn: 'failover'
|
|
72
|
-
}
|
|
73
|
-
],
|
|
74
|
-
captionsUrl: 'https://example.com/imsc-doc.xml', // NB This parameter is being deprecated in favour of the captions array shown above.
|
|
75
|
-
subtitlesRequestTimeout: 5000, // Optional override for the XHR timeout on sidecar loaded subtitles
|
|
76
|
-
subtitleCustomisation: {
|
|
77
|
-
size: 0.75,
|
|
78
|
-
lineHeight: 1.10,
|
|
79
|
-
fontFamily: 'Arial',
|
|
80
|
-
backgroundColour: 'black' // (css colour, hex)
|
|
81
|
-
},
|
|
82
|
-
playerSettings: { // This currently can be used to customise settings for the msestrategy. It is a pass through of all the dash.js player settings.
|
|
83
|
-
failoverSort: failoverSort, // Post failover custom sorting algorithm
|
|
84
|
-
failoverResetTime: 60000,
|
|
85
|
-
streaming: {
|
|
86
|
-
bufferToKeep: 8
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// STATIC for VOD content, GROWING/SLIDING for LIVE content
|
|
93
|
-
const windowType = WindowTypes.STATIC
|
|
94
|
-
const enableSubtitles = false
|
|
95
|
-
|
|
96
|
-
bigscreenPlayer.init(playbackElement, optionalData, windowType, enableSubtitles)
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
### Configuration
|
|
100
|
-
|
|
101
|
-
Bigscreen Player has some global configuration that is needed before initialisation. A *playback strategy* may be configured, or defaulted to the native Html5 strategy:
|
|
102
|
-
|
|
103
|
-
```javascript
|
|
104
|
-
window.bigscreenPlayer.playbackStrategy = 'msestrategy' // OR 'nativestrategy' OR 'hybridstrategy'
|
|
15
|
+
Install dependencies:
|
|
16
|
+
```bash
|
|
17
|
+
$ npm install
|
|
105
18
|
```
|
|
106
19
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
State changes which are emitted from the player can be acted upon to by registering a callback. The callback will receive all of the following state changes as the `state` property of the event:
|
|
112
|
-
- `MediaState.STOPPED`
|
|
113
|
-
- `MediaState.PAUSED`
|
|
114
|
-
- `MediaState.PLAYING`
|
|
115
|
-
- `MediaState.WAITING`
|
|
116
|
-
- `MediaState.ENDED`
|
|
117
|
-
- `MediaState.FATAL_ERROR`
|
|
118
|
-
|
|
119
|
-
State changes may be registered for before initialisation and will automatically be cleared upon `tearDown()` of the player.
|
|
120
|
-
|
|
121
|
-
```javascript
|
|
122
|
-
const bigscreenPlayer = BigscreenPlayer()
|
|
123
|
-
|
|
124
|
-
// The token is only required in the case where the function is anonymous, a reference to the function can be stored and used to unregister otherwise.
|
|
125
|
-
var stateChangeToken = bigscreenPlayer.registerForStateChanges(function (event) {
|
|
126
|
-
if(event.state == MediaState.PLAYING) {
|
|
127
|
-
console.log('Playing')
|
|
128
|
-
// handle playing event
|
|
129
|
-
}
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
bigscreenPlayer.unregisterForStateChanges(stateChangeToken)
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Reacting to time updates
|
|
136
|
-
|
|
137
|
-
Time updates are emitted multiple times a second. Your application can register to receive these updates. The emitted object contains the `currentTime` and `endOfStream` properties.
|
|
138
|
-
|
|
139
|
-
Time updates may be registered for before initialisation and will automatically be cleared upon `tearDown()` of the player.
|
|
140
|
-
|
|
141
|
-
```javascript
|
|
142
|
-
var bigscreenPlayer = BigscreenPlayer();
|
|
143
|
-
|
|
144
|
-
// The token is only required in the case where the function is anonymous, a reference to the function can be stored and used to unregister otherwise.
|
|
145
|
-
var timeUpdateToken = bigscreenPlayer.registerForTimeUpdates(function (event) {
|
|
146
|
-
console.log('Current Time: ' + event.currentTime);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
bigscreenPlayer.unRegisterForTimeUpdates(timeUpdateToken);
|
|
20
|
+
You can run Bigscreen Player locally in a dev environment by running:
|
|
21
|
+
```bash
|
|
22
|
+
$ npm run start
|
|
150
23
|
```
|
|
151
24
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
This is emitted on every `setSubtitlesEnabled` call. The emitted object contains an `enabled` property.
|
|
155
|
-
|
|
156
|
-
This may be registered for before initialisation and will automatically be cleared upon `tearDown()` of the player.
|
|
157
|
-
|
|
158
|
-
```javascript
|
|
159
|
-
var bigscreenPlayer = BigscreenPlayer();
|
|
160
|
-
|
|
161
|
-
// The token is only required in the case where the function is anonymous, a reference to the function can be stored and used to unregister otherwise.
|
|
162
|
-
var subtitleChangeToken = bigscreenPlayer.registerForSubtitleChanges(function (event) {
|
|
163
|
-
console.log('Subttiles enabled: ' + event.enabled);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
bigscreenPlayer.unregisterForSubtitleChanges(subtitleChangeToken);
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
### Creating a plugin
|
|
170
|
-
|
|
171
|
-
Plugins can be created to extend the functionality of the Bigscreen Player by adhering to an interface which propagates non state change events from the player. For example, when an error is raised or cleared.
|
|
172
|
-
|
|
173
|
-
The full interface is as follows:
|
|
174
|
-
- `onError`
|
|
175
|
-
- `onFatalError`
|
|
176
|
-
- `onErrorCleared`
|
|
177
|
-
- `onErrorHandled`
|
|
178
|
-
- `onBuffering`
|
|
179
|
-
- `onBufferingCleared`
|
|
180
|
-
- `onScreenCapabilityDetermined`
|
|
181
|
-
|
|
182
|
-
An example plugin may look like:
|
|
183
|
-
|
|
184
|
-
```javascript
|
|
185
|
-
function ExamplePlugin (appName) {
|
|
186
|
-
|
|
187
|
-
var name = appName;
|
|
188
|
-
|
|
189
|
-
function onFatalError (evt) {
|
|
190
|
-
console.log('A fatal error has occured in the app: ' + name);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function onErrorHandled (evt) {
|
|
194
|
-
console.log('The ' + name + ' app is handling a playback error');
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return {
|
|
198
|
-
onFatalError: onFatalError,
|
|
199
|
-
onErrorHandled: onErrorHandled
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
```javascript
|
|
205
|
-
var bigscreenPlayer = BigscreenPlayer();
|
|
206
|
-
|
|
207
|
-
var examplePlugin = ExamplePlugin('myApp');
|
|
208
|
-
|
|
209
|
-
bigscreenPlayer.registerPlugin(examplePlugin);
|
|
210
|
-
|
|
211
|
-
// initialise bigscreenPlayer - see above
|
|
212
|
-
|
|
213
|
-
// you should unregister your plugins as part of your playback cleanup
|
|
214
|
-
|
|
215
|
-
// calling with no argument will unregister all plugins
|
|
216
|
-
bigscreenPlayer.unregisterPlugin(examplePlugin);
|
|
217
|
-
|
|
218
|
-
```
|
|
25
|
+
This will open a web page at `localhost:8080`.
|
|
219
26
|
|
|
220
27
|
## Testing
|
|
221
28
|
|
|
222
29
|
The project is unit tested using [Jest](https://jestjs.io/). To run the tests:
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
30
|
+
```bash
|
|
31
|
+
$ npm test
|
|
32
|
+
```
|
|
226
33
|
This project currently has unit test coverage but no integration test suite. This is on our Roadmap to address.
|
|
227
34
|
|
|
228
|
-
### Mocking media playback
|
|
229
|
-
|
|
230
|
-
When writing tests for your application it may be useful to use the mocking functions provided. This creates a fake player with mocking hook functions to simulate real world scenarios.
|
|
231
|
-
|
|
232
|
-
See [here](https://github.com/bbc/bigscreen-player/wiki/Mocking-Bigscreen-Player) for example usage.
|
|
233
|
-
|
|
234
35
|
## Releasing
|
|
235
36
|
|
|
236
37
|
1. Create a PR.
|
|
237
|
-
2. Label the PR with one of these labels
|
|
238
|
-
- `semver prerelease`
|
|
239
|
-
- `semver patch`
|
|
240
|
-
- `semver minor`
|
|
241
|
-
- `semver major`
|
|
242
|
-
|
|
38
|
+
2. Label the PR with one of these labels; `semver prerelease`, `semver patch`, `semver minor` or `semver major`
|
|
243
39
|
3. Get a review from the core team.
|
|
244
40
|
4. If the PR checks are green. The core team can merge to master.
|
|
245
41
|
5. Automation takes care of the package versioning.
|
|
246
42
|
6. Publishing to NPM is handled with our [GitHub Actions CI integration](https://github.com/bbc/bigscreen-player/blob/master/.github/workflows/npm-publish.yml).
|
|
247
43
|
|
|
44
|
+
## Documentation
|
|
248
45
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
46
|
+
Bigscreen Player uses JSDocs to autogenerate API documentation. To regenerate the documentation run:
|
|
47
|
+
```bash
|
|
48
|
+
$ npm run docs
|
|
49
|
+
```
|
|
253
50
|
|
|
254
51
|
## Contributing
|
|
255
52
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { fromXML, generateISD, renderHTML } from 'smp-imsc';
|
|
2
|
-
import { b as TimeUtils, L as LoadUrl, a as DebugTool, P as Plugins, U as Utils, D as DOMHelpers } from './main-
|
|
2
|
+
import { b as TimeUtils, L as LoadUrl, a as DebugTool, P as Plugins, U as Utils, D as DOMHelpers } from './main-fd918769.js';
|
|
3
3
|
|
|
4
4
|
function IMSCSubtitles (mediaPlayer, autoStart, parentElement, mediaSources, defaultStyleOpts) {
|
|
5
5
|
const SEGMENTS_TO_KEEP = 3;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DOMHelpers, a as DebugTool, P as Plugins, L as LoadUrl, T as TransportControlPosition } from './main-
|
|
1
|
+
import { D as DOMHelpers, a as DebugTool, P as Plugins, L as LoadUrl, T as TransportControlPosition } from './main-fd918769.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Safely checks if an attribute exists on an element.
|
|
@@ -13,9 +13,17 @@ const MediaState = {
|
|
|
13
13
|
FATAL_ERROR: 6
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Enums for WindowTypes
|
|
18
|
+
* @readonly
|
|
19
|
+
* @enum {string}
|
|
20
|
+
*/
|
|
16
21
|
const WindowTypes = {
|
|
22
|
+
/** Media with a duration */
|
|
17
23
|
STATIC: 'staticWindow',
|
|
24
|
+
/** Media with a start time but without a duration until an indeterminate time in the future */
|
|
18
25
|
GROWING: 'growingWindow',
|
|
26
|
+
/** Media with a rewind window that progresses through a media timeline */
|
|
19
27
|
SLIDING: 'slidingWindow'
|
|
20
28
|
};
|
|
21
29
|
|
|
@@ -236,11 +244,14 @@ var Plugins = {
|
|
|
236
244
|
onBufferingCleared: (evt) => callOnAllPlugins('onBufferingCleared', evt),
|
|
237
245
|
onScreenCapabilityDetermined: (tvInfo) => callOnAllPlugins('onScreenCapabilityDetermined', tvInfo),
|
|
238
246
|
onPlayerInfoUpdated: (evt) => callOnAllPlugins('onPlayerInfoUpdated', evt),
|
|
247
|
+
onManifestLoaded: (manifest) => callOnAllPlugins('onManifestLoaded', manifest),
|
|
248
|
+
onQualityChangedRendered: (evt) => callOnAllPlugins('onQualityChangedRendered', evt),
|
|
239
249
|
onSubtitlesLoadError: (evt) => callOnAllPlugins('onSubtitlesLoadError', evt),
|
|
240
250
|
onSubtitlesTimeout: (evt) => callOnAllPlugins('onSubtitlesTimeout', evt),
|
|
241
251
|
onSubtitlesXMLError: (evt) => callOnAllPlugins('onSubtitlesXMLError', evt),
|
|
242
252
|
onSubtitlesTransformError: (evt) => callOnAllPlugins('onSubtitlesTransformError', evt),
|
|
243
|
-
onSubtitlesRenderError: (evt) => callOnAllPlugins('onSubtitlesRenderError', evt)
|
|
253
|
+
onSubtitlesRenderError: (evt) => callOnAllPlugins('onSubtitlesRenderError', evt),
|
|
254
|
+
onSubtitlesDynamicLoadError: (evt) => callOnAllPlugins('onSubtitlesDynamicLoadError', evt)
|
|
244
255
|
}
|
|
245
256
|
};
|
|
246
257
|
|
|
@@ -835,21 +846,7 @@ if (instance === undefined) {
|
|
|
835
846
|
|
|
836
847
|
var DebugTool$1 = instance;
|
|
837
848
|
|
|
838
|
-
function PlaybackSpinner () {
|
|
839
|
-
const spinnerContainer = document.createElement('div');
|
|
840
|
-
spinnerContainer.id = 'loadingSpinner';
|
|
841
|
-
spinnerContainer.className = 'loadingSpinner loadingSpinner--large ';
|
|
842
|
-
|
|
843
|
-
const spinner = document.createElement('div');
|
|
844
|
-
spinner.className = 'loadingSpinner__spinner';
|
|
845
|
-
|
|
846
|
-
spinnerContainer.appendChild(spinner);
|
|
847
|
-
|
|
848
|
-
return spinnerContainer
|
|
849
|
-
}
|
|
850
|
-
|
|
851
849
|
function LiveGlitchCurtain (parentElement) {
|
|
852
|
-
let spinner = new PlaybackSpinner();
|
|
853
850
|
let curtain = document.createElement('div');
|
|
854
851
|
|
|
855
852
|
curtain.id = 'liveGlitchCurtain';
|
|
@@ -861,8 +858,6 @@ function LiveGlitchCurtain (parentElement) {
|
|
|
861
858
|
curtain.style.bottom = 0;
|
|
862
859
|
curtain.style.backgroundColor = '#3c3c3c';
|
|
863
860
|
|
|
864
|
-
curtain.appendChild(spinner);
|
|
865
|
-
|
|
866
861
|
return {
|
|
867
862
|
showCurtain: () => {
|
|
868
863
|
curtain.style.display = 'block';
|
|
@@ -871,15 +866,10 @@ function LiveGlitchCurtain (parentElement) {
|
|
|
871
866
|
|
|
872
867
|
hideCurtain: () => {
|
|
873
868
|
curtain.style.display = 'none';
|
|
874
|
-
DOMHelpers.safeRemoveElement(spinner);
|
|
875
869
|
},
|
|
876
870
|
|
|
877
871
|
tearDown: () => {
|
|
878
872
|
DOMHelpers.safeRemoveElement(curtain);
|
|
879
|
-
|
|
880
|
-
if (spinner) {
|
|
881
|
-
spinner = undefined;
|
|
882
|
-
}
|
|
883
873
|
}
|
|
884
874
|
}
|
|
885
875
|
}
|
|
@@ -5683,12 +5673,12 @@ function StrategyPicker (windowType, isUHD) {
|
|
|
5683
5673
|
return resolve(NativeStrategy)
|
|
5684
5674
|
}
|
|
5685
5675
|
|
|
5686
|
-
return import('./msestrategy-
|
|
5676
|
+
return import('./msestrategy-af831822.js').then(({default: MSEStrategy}) => resolve(MSEStrategy))
|
|
5687
5677
|
.catch(() => {
|
|
5688
5678
|
reject({error: 'strategyDynamicLoadError'});
|
|
5689
5679
|
})
|
|
5690
5680
|
} else if (window.bigscreenPlayer.playbackStrategy === PlaybackStrategy.MSE) {
|
|
5691
|
-
return import('./msestrategy-
|
|
5681
|
+
return import('./msestrategy-af831822.js').then(({default: MSEStrategy}) => resolve(MSEStrategy))
|
|
5692
5682
|
.catch(() => {
|
|
5693
5683
|
reject({error: 'strategyDynamicLoadError'});
|
|
5694
5684
|
})
|
|
@@ -6068,7 +6058,7 @@ function CallCallbacks (callbacks, data) {
|
|
|
6068
6058
|
callbacks.forEach((callback) => DeferExceptions(() => callback(data)));
|
|
6069
6059
|
}
|
|
6070
6060
|
|
|
6071
|
-
var version = "5.0
|
|
6061
|
+
var version = "5.2.0";
|
|
6072
6062
|
|
|
6073
6063
|
var sourceList;
|
|
6074
6064
|
var source;
|
|
@@ -7254,14 +7244,18 @@ function Subtitles (mediaPlayer, autoStart, playbackElement, defaultStyleOpts, m
|
|
|
7254
7244
|
let subtitlesContainer;
|
|
7255
7245
|
|
|
7256
7246
|
if (useLegacySubs) {
|
|
7257
|
-
import('./legacysubtitles-
|
|
7247
|
+
import('./legacysubtitles-bd87e09b.js').then(({default: LegacySubtitles}) => {
|
|
7258
7248
|
subtitlesContainer = LegacySubtitles(mediaPlayer, autoStart, playbackElement, mediaSources, defaultStyleOpts);
|
|
7259
7249
|
callback(subtitlesEnabled);
|
|
7250
|
+
}).catch(() => {
|
|
7251
|
+
Plugins.interface.onSubtitlesDynamicLoadError();
|
|
7260
7252
|
});
|
|
7261
7253
|
} else {
|
|
7262
|
-
import('./imscsubtitles-
|
|
7254
|
+
import('./imscsubtitles-3d139d9a.js').then(({default: IMSCSubtitles}) => {
|
|
7263
7255
|
subtitlesContainer = IMSCSubtitles(mediaPlayer, autoStart, playbackElement, mediaSources, defaultStyleOpts);
|
|
7264
7256
|
callback(subtitlesEnabled);
|
|
7257
|
+
}).catch(() => {
|
|
7258
|
+
Plugins.interface.onSubtitlesDynamicLoadError();
|
|
7265
7259
|
});
|
|
7266
7260
|
}
|
|
7267
7261
|
|
|
@@ -7332,6 +7326,10 @@ function Subtitles (mediaPlayer, autoStart, playbackElement, defaultStyleOpts, m
|
|
|
7332
7326
|
}
|
|
7333
7327
|
}
|
|
7334
7328
|
|
|
7329
|
+
/**
|
|
7330
|
+
* @module bigscreenplayer/bigscreenplayer
|
|
7331
|
+
*/
|
|
7332
|
+
|
|
7335
7333
|
function BigscreenPlayer () {
|
|
7336
7334
|
let stateChangeCallbacks = [];
|
|
7337
7335
|
let timeUpdateCallbacks = [];
|
|
@@ -7489,7 +7487,19 @@ function BigscreenPlayer () {
|
|
|
7489
7487
|
return subtitles ? subtitles.available() : false
|
|
7490
7488
|
}
|
|
7491
7489
|
|
|
7492
|
-
return {
|
|
7490
|
+
return /** @alias module:bigscreenplayer/bigscreenplayer */{
|
|
7491
|
+
|
|
7492
|
+
/**
|
|
7493
|
+
* Call first to initialise bigscreen player for playback.
|
|
7494
|
+
* @function
|
|
7495
|
+
* @name init
|
|
7496
|
+
* @param {HTMLDivElement} playbackElement - The Div element where content elements should be rendered
|
|
7497
|
+
* @param {BigscreenPlayerData} bigscreenPlayerData
|
|
7498
|
+
* @param {WindowTypes} newWindowType
|
|
7499
|
+
* @param {boolean} enableSubtitles - Enable subtitles on initialisation
|
|
7500
|
+
* @param {TALDevice} newDevice - An optional TAL device object
|
|
7501
|
+
* @param {InitCallbacks} callbacks
|
|
7502
|
+
*/
|
|
7493
7503
|
init: (newPlaybackElement, bigscreenPlayerData, newWindowType, enableSubtitles, callbacks) => {
|
|
7494
7504
|
playbackElement = newPlaybackElement;
|
|
7495
7505
|
Chronicle.init();
|
|
@@ -7526,6 +7536,11 @@ function BigscreenPlayer () {
|
|
|
7526
7536
|
mediaSources.init(bigscreenPlayerData.media, serverDate, windowType, getLiveSupport(), mediaSourceCallbacks);
|
|
7527
7537
|
},
|
|
7528
7538
|
|
|
7539
|
+
/**
|
|
7540
|
+
* Should be called at the end of all playback sessions. Resets state and clears any UI.
|
|
7541
|
+
* @function
|
|
7542
|
+
* @name tearDown
|
|
7543
|
+
*/
|
|
7529
7544
|
tearDown: function () {
|
|
7530
7545
|
if (subtitles) {
|
|
7531
7546
|
subtitles.tearDown();
|
|
@@ -7555,11 +7570,22 @@ function BigscreenPlayer () {
|
|
|
7555
7570
|
Chronicle.tearDown();
|
|
7556
7571
|
},
|
|
7557
7572
|
|
|
7573
|
+
/**
|
|
7574
|
+
* Pass a function to call whenever the player transitions state.
|
|
7575
|
+
* @see {@link module:models/mediastate}
|
|
7576
|
+
* @function
|
|
7577
|
+
* @param {Function} callback
|
|
7578
|
+
*/
|
|
7558
7579
|
registerForStateChanges: (callback) => {
|
|
7559
7580
|
stateChangeCallbacks.push(callback);
|
|
7560
7581
|
return callback
|
|
7561
7582
|
},
|
|
7562
7583
|
|
|
7584
|
+
/**
|
|
7585
|
+
* Unregisters a previously registered callback.
|
|
7586
|
+
* @function
|
|
7587
|
+
* @param {Function} callback
|
|
7588
|
+
*/
|
|
7563
7589
|
unregisterForStateChanges: (callback) => {
|
|
7564
7590
|
const indexOf = stateChangeCallbacks.indexOf(callback);
|
|
7565
7591
|
if (indexOf !== -1) {
|
|
@@ -7567,11 +7593,21 @@ function BigscreenPlayer () {
|
|
|
7567
7593
|
}
|
|
7568
7594
|
},
|
|
7569
7595
|
|
|
7596
|
+
/**
|
|
7597
|
+
* Pass a function to call whenever the player issues a time update.
|
|
7598
|
+
* @function
|
|
7599
|
+
* @param {Function} callback
|
|
7600
|
+
*/
|
|
7570
7601
|
registerForTimeUpdates: (callback) => {
|
|
7571
7602
|
timeUpdateCallbacks.push(callback);
|
|
7572
7603
|
return callback
|
|
7573
7604
|
},
|
|
7574
7605
|
|
|
7606
|
+
/**
|
|
7607
|
+
* Unregisters a previously registered callback.
|
|
7608
|
+
* @function
|
|
7609
|
+
* @param {Function} callback
|
|
7610
|
+
*/
|
|
7575
7611
|
unregisterForTimeUpdates: (callback) => {
|
|
7576
7612
|
const indexOf = timeUpdateCallbacks.indexOf(callback);
|
|
7577
7613
|
|
|
@@ -7580,11 +7616,21 @@ function BigscreenPlayer () {
|
|
|
7580
7616
|
}
|
|
7581
7617
|
},
|
|
7582
7618
|
|
|
7619
|
+
/**
|
|
7620
|
+
* Pass a function to be called whenever subtitles are enabled or disabled.
|
|
7621
|
+
* @function
|
|
7622
|
+
* @param {Function} callback
|
|
7623
|
+
*/
|
|
7583
7624
|
registerForSubtitleChanges: (callback) => {
|
|
7584
7625
|
subtitleCallbacks.push(callback);
|
|
7585
7626
|
return callback
|
|
7586
7627
|
},
|
|
7587
7628
|
|
|
7629
|
+
/**
|
|
7630
|
+
* Unregisters a previously registered callback for changes to subtitles.
|
|
7631
|
+
* @function
|
|
7632
|
+
* @param {Function} callback
|
|
7633
|
+
*/
|
|
7588
7634
|
unregisterForSubtitleChanges: (callback) => {
|
|
7589
7635
|
const indexOf = subtitleCallbacks.indexOf(callback);
|
|
7590
7636
|
if (indexOf !== -1) {
|
|
@@ -7592,6 +7638,11 @@ function BigscreenPlayer () {
|
|
|
7592
7638
|
}
|
|
7593
7639
|
},
|
|
7594
7640
|
|
|
7641
|
+
/**
|
|
7642
|
+
* Sets the current time of the media asset.
|
|
7643
|
+
* @function
|
|
7644
|
+
* @param {Number} time - In seconds
|
|
7645
|
+
*/
|
|
7595
7646
|
setCurrentTime: function (time) {
|
|
7596
7647
|
DebugTool$1.apicall('setCurrentTime');
|
|
7597
7648
|
if (playerComponent) {
|
|
@@ -7609,15 +7660,46 @@ function BigscreenPlayer () {
|
|
|
7609
7660
|
},
|
|
7610
7661
|
|
|
7611
7662
|
getPlaybackRate: () => playerComponent && playerComponent.getPlaybackRate(),
|
|
7663
|
+
|
|
7664
|
+
/**
|
|
7665
|
+
* Returns the media asset's current time in seconds.
|
|
7666
|
+
* @function
|
|
7667
|
+
*/
|
|
7612
7668
|
getCurrentTime: () => playerComponent && playerComponent.getCurrentTime() || 0,
|
|
7669
|
+
|
|
7670
|
+
/**
|
|
7671
|
+
* Returns the current media kind.
|
|
7672
|
+
* 'audio' or 'video'
|
|
7673
|
+
* @function
|
|
7674
|
+
*/
|
|
7613
7675
|
getMediaKind: () => mediaKind,
|
|
7676
|
+
|
|
7677
|
+
/**
|
|
7678
|
+
* Returns the current window type.
|
|
7679
|
+
* @see {@link module:bigscreenplayer/models/windowtypes}
|
|
7680
|
+
* @function
|
|
7681
|
+
*/
|
|
7614
7682
|
getWindowType: () => windowType,
|
|
7683
|
+
|
|
7684
|
+
/**
|
|
7685
|
+
* Returns an object including the current start and end times.
|
|
7686
|
+
* @function
|
|
7687
|
+
* @returns {Object} {start: Number, end: Number}
|
|
7688
|
+
*/
|
|
7615
7689
|
getSeekableRange: () => playerComponent ? playerComponent.getSeekableRange() : {},
|
|
7616
7690
|
|
|
7691
|
+
/**
|
|
7692
|
+
* @function
|
|
7693
|
+
* @returns {boolean} Returns true if media is initialised and playing a live stream within a tolerance of the end of the seekable range (10 seconds).
|
|
7694
|
+
*/
|
|
7617
7695
|
isPlayingAtLiveEdge: function () {
|
|
7618
7696
|
return !!playerComponent && windowType !== WindowTypes.STATIC && Math.abs(this.getSeekableRange().end - this.getCurrentTime()) < END_OF_STREAM_TOLERANCE
|
|
7619
7697
|
},
|
|
7620
7698
|
|
|
7699
|
+
/**
|
|
7700
|
+
* @function
|
|
7701
|
+
* @return {Object} An object of the shape {windowStartTime: Number, windowEndTime: Number, initialPlaybackTime: Number, serverDate: Date}
|
|
7702
|
+
*/
|
|
7621
7703
|
getLiveWindowData: () => {
|
|
7622
7704
|
if (windowType === WindowTypes.STATIC) {
|
|
7623
7705
|
return {}
|
|
@@ -7631,15 +7713,39 @@ function BigscreenPlayer () {
|
|
|
7631
7713
|
}
|
|
7632
7714
|
},
|
|
7633
7715
|
|
|
7716
|
+
/**
|
|
7717
|
+
* @function
|
|
7718
|
+
* @returns the duration of the media asset.
|
|
7719
|
+
*/
|
|
7634
7720
|
getDuration: () => playerComponent && playerComponent.getDuration(),
|
|
7721
|
+
|
|
7722
|
+
/**
|
|
7723
|
+
* @function
|
|
7724
|
+
* @returns if the player is paused.
|
|
7725
|
+
*/
|
|
7635
7726
|
isPaused: () => playerComponent ? playerComponent.isPaused() : true,
|
|
7727
|
+
|
|
7728
|
+
/**
|
|
7729
|
+
* @function
|
|
7730
|
+
* @returns if the media asset has ended.
|
|
7731
|
+
*/
|
|
7636
7732
|
isEnded: () => playerComponent ? playerComponent.isEnded() : false,
|
|
7637
7733
|
|
|
7734
|
+
/**
|
|
7735
|
+
* Play the media assest from the current point in time.
|
|
7736
|
+
* @function
|
|
7737
|
+
*/
|
|
7638
7738
|
play: () => {
|
|
7639
7739
|
DebugTool$1.apicall('play');
|
|
7640
7740
|
playerComponent.play();
|
|
7641
7741
|
},
|
|
7642
|
-
|
|
7742
|
+
/**
|
|
7743
|
+
* Pause the media asset.
|
|
7744
|
+
* @function
|
|
7745
|
+
* @param {*} opts
|
|
7746
|
+
* @param {boolean} opts.userPause
|
|
7747
|
+
* @param {boolean} opts.disableAutoResume
|
|
7748
|
+
*/
|
|
7643
7749
|
pause: (opts) => {
|
|
7644
7750
|
DebugTool$1.apicall('pause');
|
|
7645
7751
|
pauseTrigger = opts && opts.userPause === false ? PauseTriggers.APP : PauseTriggers.USER;
|
|
@@ -7660,8 +7766,23 @@ function BigscreenPlayer () {
|
|
|
7660
7766
|
resizer.clear(playbackElement);
|
|
7661
7767
|
},
|
|
7662
7768
|
|
|
7769
|
+
/**
|
|
7770
|
+
* Set whether or not subtitles should be enabled.
|
|
7771
|
+
* @function
|
|
7772
|
+
* @param {boolean} value
|
|
7773
|
+
*/
|
|
7663
7774
|
setSubtitlesEnabled: setSubtitlesEnabled,
|
|
7775
|
+
|
|
7776
|
+
/**
|
|
7777
|
+
* @function
|
|
7778
|
+
* @return if subtitles are currently enabled.
|
|
7779
|
+
*/
|
|
7664
7780
|
isSubtitlesEnabled: isSubtitlesEnabled,
|
|
7781
|
+
|
|
7782
|
+
/**
|
|
7783
|
+
* @function
|
|
7784
|
+
* @return Returns whether or not subtitles are currently enabled.
|
|
7785
|
+
*/
|
|
7665
7786
|
isSubtitlesAvailable: isSubtitlesAvailable,
|
|
7666
7787
|
|
|
7667
7788
|
areSubtitlesCustomisable: () => {
|
|
@@ -7686,45 +7807,132 @@ function BigscreenPlayer () {
|
|
|
7686
7807
|
}
|
|
7687
7808
|
},
|
|
7688
7809
|
|
|
7810
|
+
/**
|
|
7811
|
+
*
|
|
7812
|
+
* An enum may be used to set the on-screen position of any transport controls
|
|
7813
|
+
* (work in progress to remove this - UI concern).
|
|
7814
|
+
* @function
|
|
7815
|
+
* @param {*} position
|
|
7816
|
+
*/
|
|
7689
7817
|
setTransportControlsPosition: (position) => {
|
|
7690
7818
|
if (subtitles) {
|
|
7691
7819
|
subtitles.setPosition(position);
|
|
7692
7820
|
}
|
|
7693
7821
|
},
|
|
7694
7822
|
|
|
7823
|
+
/**
|
|
7824
|
+
* @function
|
|
7825
|
+
* @return Returns whether the current media asset is seekable.
|
|
7826
|
+
*/
|
|
7695
7827
|
canSeek: function () {
|
|
7696
7828
|
return windowType === WindowTypes.STATIC || DynamicWindowUtils.canSeek(getWindowStartTime(), getWindowEndTime(), getLiveSupport(), this.getSeekableRange())
|
|
7697
7829
|
},
|
|
7698
7830
|
|
|
7831
|
+
/**
|
|
7832
|
+
* @function
|
|
7833
|
+
* @return Returns whether the current media asset is pausable.
|
|
7834
|
+
*/
|
|
7699
7835
|
canPause: () => {
|
|
7700
7836
|
return windowType === WindowTypes.STATIC || DynamicWindowUtils.canPause(getWindowStartTime(), getWindowEndTime(), getLiveSupport())
|
|
7701
7837
|
},
|
|
7702
7838
|
|
|
7839
|
+
/**
|
|
7840
|
+
* Return a mock for in place testing.
|
|
7841
|
+
* @function
|
|
7842
|
+
* @param {*} opts
|
|
7843
|
+
*/
|
|
7703
7844
|
mock: function (opts) { MockBigscreenPlayer.mock(this, opts); },
|
|
7845
|
+
|
|
7846
|
+
/**
|
|
7847
|
+
* Unmock the player.
|
|
7848
|
+
* @function
|
|
7849
|
+
*/
|
|
7704
7850
|
unmock: function () { MockBigscreenPlayer.unmock(this); },
|
|
7851
|
+
|
|
7852
|
+
/**
|
|
7853
|
+
* Return a mock for unit tests.
|
|
7854
|
+
* @function
|
|
7855
|
+
* @param {*} opts
|
|
7856
|
+
*/
|
|
7705
7857
|
mockJasmine: function (opts) { MockBigscreenPlayer.mockJasmine(this, opts); },
|
|
7706
7858
|
|
|
7859
|
+
/**
|
|
7860
|
+
* Register a plugin for extended events.
|
|
7861
|
+
* @function
|
|
7862
|
+
* @param {*} plugin
|
|
7863
|
+
*/
|
|
7707
7864
|
registerPlugin: (plugin) => Plugins.registerPlugin(plugin),
|
|
7865
|
+
|
|
7866
|
+
/**
|
|
7867
|
+
* Unregister a previously registered plugin.
|
|
7868
|
+
* @function
|
|
7869
|
+
* @param {*} plugin
|
|
7870
|
+
*/
|
|
7708
7871
|
unregisterPlugin: (plugin) => Plugins.unregisterPlugin(plugin),
|
|
7872
|
+
|
|
7873
|
+
/**
|
|
7874
|
+
* Returns an object with a number of functions related to the ability to transition state
|
|
7875
|
+
* given the current state and the playback strategy in use.
|
|
7876
|
+
* @function
|
|
7877
|
+
*/
|
|
7709
7878
|
transitions: () => playerComponent ? playerComponent.transitions() : {},
|
|
7879
|
+
|
|
7880
|
+
/**
|
|
7881
|
+
* @function
|
|
7882
|
+
* @return The media element currently being used.
|
|
7883
|
+
*/
|
|
7710
7884
|
getPlayerElement: () => playerComponent && playerComponent.getPlayerElement(),
|
|
7711
7885
|
|
|
7886
|
+
/**
|
|
7887
|
+
* @function
|
|
7888
|
+
* @param {Number} epochTime - Unix Epoch based time in milliseconds.
|
|
7889
|
+
* @return the time in seconds within the current sliding window.
|
|
7890
|
+
*/
|
|
7712
7891
|
convertEpochMsToVideoTimeSeconds: (epochTime) => {
|
|
7713
7892
|
return getWindowStartTime() ? Math.floor((epochTime - getWindowStartTime()) / 1000) : undefined
|
|
7714
7893
|
},
|
|
7715
7894
|
|
|
7895
|
+
/**
|
|
7896
|
+
* @function
|
|
7897
|
+
* @return The runtime version of the library.
|
|
7898
|
+
*/
|
|
7716
7899
|
getFrameworkVersion: () => {
|
|
7717
7900
|
return version
|
|
7718
7901
|
},
|
|
7719
7902
|
|
|
7903
|
+
/**
|
|
7904
|
+
* @function
|
|
7905
|
+
* @param {Number} time - Seconds
|
|
7906
|
+
* @return the time in milliseconds within the current sliding window.
|
|
7907
|
+
*/
|
|
7720
7908
|
convertVideoTimeSecondsToEpochMs: convertVideoTimeSecondsToEpochMs,
|
|
7909
|
+
|
|
7910
|
+
/**
|
|
7911
|
+
* Toggle the visibility of the debug tool overlay.
|
|
7912
|
+
* @function
|
|
7913
|
+
*/
|
|
7721
7914
|
toggleDebug: toggleDebug,
|
|
7915
|
+
|
|
7916
|
+
/**
|
|
7917
|
+
* @function
|
|
7918
|
+
* @return {Object} - Key value pairs of available log levels
|
|
7919
|
+
*/
|
|
7722
7920
|
getLogLevels: () => DebugTool$1.logLevels,
|
|
7921
|
+
|
|
7922
|
+
/**
|
|
7923
|
+
* @function
|
|
7924
|
+
* @param logLevel - log level to display @see getLogLevels
|
|
7925
|
+
*/
|
|
7723
7926
|
setLogLevel: DebugTool$1.setLogLevel,
|
|
7724
7927
|
getDebugLogs: () => Chronicle.retrieve()
|
|
7725
7928
|
}
|
|
7726
7929
|
}
|
|
7727
7930
|
|
|
7931
|
+
/**
|
|
7932
|
+
* @function
|
|
7933
|
+
* @param {TALDevice} device
|
|
7934
|
+
* @return the live support of the device.
|
|
7935
|
+
*/
|
|
7728
7936
|
function getLiveSupport () {
|
|
7729
7937
|
return PlayerComponent.getLiveSupport()
|
|
7730
7938
|
}
|
package/dist/esm/main.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { B as BigscreenPlayer, c as LiveSupport, d as MediaKinds, M as MediaState, f as MockBigscreenPlayer, g as PauseTriggers, h as PlaybackStrategy, i as TransferFormat, T as TransportControlPosition, W as WindowTypes } from './main-
|
|
1
|
+
export { B as BigscreenPlayer, c as LiveSupport, d as MediaKinds, M as MediaState, f as MockBigscreenPlayer, g as PauseTriggers, h as PlaybackStrategy, i as TransferFormat, T as TransportControlPosition, W as WindowTypes } from './main-fd918769.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DOMHelpers, W as WindowTypes, c as LiveSupport, M as MediaState, a as DebugTool,
|
|
1
|
+
import { D as DOMHelpers, W as WindowTypes, c as LiveSupport, M as MediaState, a as DebugTool, P as Plugins, d as MediaKinds, U as Utils, b as TimeUtils, e as DynamicWindowUtils } from './main-fd918769.js';
|
|
2
2
|
import { MediaPlayer } from 'dashjs/index_mediaplayerOnly';
|
|
3
3
|
|
|
4
4
|
function filter (manifest, representationOptions) {
|
|
@@ -259,9 +259,15 @@ function MSEStrategy (mediaSources, windowType, mediaKind, playbackElement, isUH
|
|
|
259
259
|
|
|
260
260
|
ManifestModifier.filter(manifest, representationOptions);
|
|
261
261
|
ManifestModifier.generateBaseUrls(manifest, mediaSources.availableSources());
|
|
262
|
+
|
|
263
|
+
emitManifestInfo(manifest);
|
|
262
264
|
}
|
|
263
265
|
}
|
|
264
266
|
|
|
267
|
+
function emitManifestInfo (manifest) {
|
|
268
|
+
Plugins.interface.onManifestLoaded(manifest);
|
|
269
|
+
}
|
|
270
|
+
|
|
265
271
|
function onManifestValidityChange (event) {
|
|
266
272
|
DebugTool.info('Manifest validity changed. Duration is: ' + event.newDuration);
|
|
267
273
|
}
|
|
@@ -325,6 +331,7 @@ function MSEStrategy (mediaSources, windowType, mediaKind, playbackElement, isUH
|
|
|
325
331
|
}
|
|
326
332
|
|
|
327
333
|
emitPlayerInfo();
|
|
334
|
+
Plugins.interface.onQualityChangedRendered(event);
|
|
328
335
|
}
|
|
329
336
|
|
|
330
337
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bigscreen-player",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "Simplified media playback for bigscreen devices.",
|
|
5
5
|
"main": "dist/esm/main.js",
|
|
6
6
|
"browser": "dist/esm/main.js",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
],
|
|
16
16
|
"scripts": {
|
|
17
17
|
"prepare": "[ ! -d dist/ ] && npm run build || exit 0",
|
|
18
|
+
"docs": "npx jsdoc -c jsdoc.conf.json",
|
|
18
19
|
"build": "rollup -c rollup.config.js",
|
|
19
20
|
"start": "rollup -c rollup.dev.config.js -w",
|
|
20
21
|
"test": "jest",
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
"@rollup/plugin-json": "^4.1.0",
|
|
38
39
|
"@rollup/plugin-node-resolve": "^13.0.4",
|
|
39
40
|
"babel-jest": "^27.0.6",
|
|
41
|
+
"clean-jsdoc-theme": "^3.2.7",
|
|
40
42
|
"eslint": "^7.2.0",
|
|
41
43
|
"eslint-plugin-es5": "1.3.1",
|
|
42
44
|
"eslint-plugin-jest": "^24.4.0",
|
|
@@ -45,6 +47,7 @@
|
|
|
45
47
|
"eslint-plugin-standard": "4.0.0",
|
|
46
48
|
"husky": "^4.2.5",
|
|
47
49
|
"jest": "^27.0.6",
|
|
50
|
+
"jsdoc": "^3.6.4",
|
|
48
51
|
"rollup": "^2.54.0",
|
|
49
52
|
"rollup-plugin-livereload": "^2.0.5",
|
|
50
53
|
"rollup-plugin-polyfill-node": "^0.7.0",
|