ovenplayer 0.10.49 → 0.10.51

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.
Files changed (34) hide show
  1. package/dist/ovenplayer.js +1 -1
  2. package/dist/ovenplayer.js.map +1 -1
  3. package/package.json +49 -49
  4. package/src/js/api/Configurator.js +1 -1
  5. package/src/js/api/ads/vast/Ad.js +237 -237
  6. package/src/js/api/caption/Loader.js +1 -1
  7. package/src/js/api/caption/Manager.js +1 -1
  8. package/src/js/api/caption/parser/VttParser.js +1541 -1542
  9. package/src/js/api/playlist/Manager.js +229 -229
  10. package/src/js/api/provider/html5/providers/Dash.js +286 -286
  11. package/src/js/api/provider/html5/providers/Hls.js +110 -2
  12. package/src/js/api/provider/html5/providers/WebRTC.js +2 -1
  13. package/src/js/api/provider/html5/providers/WebRTCLoader.js +35 -2
  14. package/src/js/api/provider/utils.js +69 -69
  15. package/src/js/ovenplayer.sdk.js +143 -143
  16. package/src/js/utils/likeA$.js +241 -242
  17. package/src/js/utils/resize-sensor.js +145 -168
  18. package/src/js/utils/strings.js +104 -104
  19. package/src/js/view/components/controls/settingPanel/audioTrackPanel.js +57 -57
  20. package/src/js/view/components/controls/settingPanel/main.js +1 -1
  21. package/src/js/view/components/controls/settingPanel/mainTemplate.js +29 -29
  22. package/src/js/view/components/controls/settingPanel/qualityPanel.js +68 -68
  23. package/src/js/view/components/controls/settingPanel/subtitleTrackPanel.js +56 -56
  24. package/src/js/view/components/helpers/captionViewer.js +97 -15
  25. package/src/js/view/components/helpers/captionViewerTemplate.js +1 -2
  26. package/src/js/view/components/helpers/waterMark.js +69 -69
  27. package/src/js/view/engine/OvenTemplate.js +158 -158
  28. package/src/js/view/global/PanelManager.js +47 -47
  29. package/src/stylesheet/ovenplayer.less +52 -21
  30. package/src/js/utils/adapter.js +0 -4944
  31. package/src/js/utils/captions/vttCue.js +0 -308
  32. package/src/js/utils/captions/vttRegion.js +0 -136
  33. package/src/js/utils/polyfills/dom.js +0 -634
  34. package/src/js/utils/underscore.js +0 -6
@@ -16,7 +16,11 @@ import {
16
16
  PLAYER_NOT_ACCEPTABLE_ERROR,
17
17
  CONTENT_LEVEL_CHANGED,
18
18
  AUDIO_TRACK_CHANGED,
19
- SUBTITLE_TRACK_CHANGED
19
+ SUBTITLE_TRACK_CHANGED,
20
+ CONTENT_CAPTION_CHANGED,
21
+ CONTENT_CAPTION_CUE_CHANGED,
22
+ CONTENT_TIME,
23
+ CONTENT_SEEKED
20
24
  } from "api/constants";
21
25
 
22
26
  import sizeHumanizer from "utils/sizeHumanizer";
@@ -36,11 +40,17 @@ const HlsProvider = function (element, playerConfig, adTagUrl) {
36
40
  let loadRetryer = null;
37
41
  let isManifestLoaded = false;
38
42
  let firstLoaded = false;
43
+ let subtitleCuesMap = {}; // { [trackId: number]: VTTCue[] }
44
+ let activeSubtitleTrackId = -1;
45
+ let _lastActiveCue = null;
46
+ let _subtitleDebugTimer = 0;
47
+ const SUBTITLE_CUES_MAX = 200; // sliding window limit per track (live stream guard)
39
48
 
40
49
  try {
41
50
 
42
51
  let hlsConfig = {
43
- debug: false
52
+ debug: false,
53
+ renderTextTracksNatively: false // Disable native TextTrack rendering so subtitles are drawn via DOM
44
54
  };
45
55
 
46
56
  let hlsConfigFromPlayerConfig = playerConfig.getConfig().hlsConfig;
@@ -182,10 +192,104 @@ const HlsProvider = function (element, playerConfig, adTagUrl) {
182
192
  });
183
193
 
184
194
  hls.on(Hls.Events.SUBTITLE_TRACK_SWITCH, function (event, data) {
195
+ activeSubtitleTrackId = data.id;
185
196
  spec.currentSubtitleTrack = data.id;
197
+ _lastActiveCue = null; // reset so the new track's cue fires immediately
198
+ // Discard cues from tracks no longer in use to free memory
199
+ var keepId = data.id;
200
+ Object.keys(subtitleCuesMap).forEach(function (key) {
201
+ if (Number(key) !== keepId) {
202
+ delete subtitleCuesMap[key];
203
+ }
204
+ });
186
205
  that.trigger(SUBTITLE_TRACK_CHANGED, {
187
206
  currentSubtitleTrack: spec.currentSubtitleTrack
188
207
  });
208
+ // Enable or clear the DOM caption viewer based on track selection
209
+ that.trigger(CONTENT_CAPTION_CHANGED, data.id >= 0 ? 0 : -1);
210
+ });
211
+
212
+ hls.on(Hls.Events.CUES_PARSED, function (event, data) {
213
+ // Use the numeric index from hls.subtitleTrack as the key,
214
+ // because data.track can be a string like "default" while
215
+ // hls.subtitleTrack is always the numeric index (e.g. 0).
216
+ var trackId = hls ? hls.subtitleTrack : data.track;
217
+ if (!subtitleCuesMap[trackId]) {
218
+ subtitleCuesMap[trackId] = [];
219
+ }
220
+ data.cues.forEach(function (cue) {
221
+ var exists = subtitleCuesMap[trackId].some(function (c) {
222
+ return c.startTime === cue.startTime && c.text === cue.text;
223
+ });
224
+ if (!exists) {
225
+ subtitleCuesMap[trackId].push(cue);
226
+ }
227
+ });
228
+ // Sliding window: drop oldest cues beyond limit to prevent
229
+ // unbounded growth during long live streams.
230
+ if (subtitleCuesMap[trackId].length > SUBTITLE_CUES_MAX) {
231
+ subtitleCuesMap[trackId].splice(0,
232
+ subtitleCuesMap[trackId].length - SUBTITLE_CUES_MAX);
233
+ }
234
+ });
235
+
236
+ // Reset on seek so that:
237
+ // (a) the same cue re-fires after seeking back into its range, and
238
+ // (b) deleteTimer is recalculated from the new position.
239
+ that.on(CONTENT_SEEKED, function () {
240
+ _lastActiveCue = null;
241
+ });
242
+
243
+ that.on(CONTENT_TIME, function (data) {
244
+ // Read the active track directly from hls.js (more reliable than event-based tracking)
245
+ var currentTrackId = hls ? hls.subtitleTrack : -1;
246
+
247
+ if (currentTrackId < 0) {
248
+ return;
249
+ }
250
+
251
+ var cues = subtitleCuesMap[currentTrackId] || [];
252
+
253
+ if (!cues.length) { return; }
254
+ // Use raw video element time to match against hls.js cue timestamps.
255
+ // data.position may be offset by sectionStart, causing a mismatch.
256
+ var position = element.currentTime;
257
+
258
+ // Collect ALL cues active at this position (handles simultaneous & overlapping cues)
259
+ var activeCueObjects = [];
260
+ var maxEndTime = 0;
261
+ for (var i = 0; i < cues.length; i++) {
262
+ if (position >= cues[i].startTime && position < cues[i].endTime) {
263
+ activeCueObjects.push({
264
+ text: cues[i].text,
265
+ line: cues[i].line,
266
+ snapToLines: cues[i].snapToLines,
267
+ position: cues[i].position,
268
+ size: cues[i].size,
269
+ align: cues[i].align,
270
+ vertical: cues[i].vertical
271
+ });
272
+ if (cues[i].endTime > maxEndTime) {
273
+ maxEndTime = cues[i].endTime;
274
+ }
275
+ }
276
+ }
277
+
278
+ if (activeCueObjects.length === 0) {
279
+ _lastActiveCue = null;
280
+ return;
281
+ }
282
+
283
+ var combinedText = activeCueObjects.map(function(c) { return c.text; }).join('\n');
284
+ if (_lastActiveCue !== combinedText) {
285
+ _lastActiveCue = combinedText;
286
+ that.trigger(CONTENT_CAPTION_CUE_CHANGED, {
287
+ text: combinedText,
288
+ cues: activeCueObjects,
289
+ startTime: position,
290
+ endTime: maxEndTime
291
+ });
292
+ }
189
293
  });
190
294
 
191
295
  hls.on(Hls.Events.LEVEL_UPDATED, function (event, data) {
@@ -305,6 +409,10 @@ const HlsProvider = function (element, playerConfig, adTagUrl) {
305
409
  hls.stopLoad();
306
410
  }
307
411
 
412
+ subtitleCuesMap = {};
413
+ activeSubtitleTrackId = -1;
414
+ _lastActiveCue = null;
415
+
308
416
  superStop_func();
309
417
  };
310
418
 
@@ -201,6 +201,7 @@ const WebRTC = function (element, playerConfig, adTagUrl) {
201
201
  that.once(ERROR, function () {
202
202
 
203
203
  connected = false;
204
+ destroyWebRtcLoader();
204
205
  });
205
206
 
206
207
  connectionCheckTimer = setTimeout(function () {
@@ -281,7 +282,7 @@ const WebRTC = function (element, playerConfig, adTagUrl) {
281
282
 
282
283
  that.play = () => {
283
284
 
284
- if (!webrtcLoader || (timeoutMaxRetry > 0 && !connected)) {
285
+ if (!webrtcLoader) {
285
286
  loadWebRTCLoader();
286
287
  }
287
288
 
@@ -1,4 +1,4 @@
1
- import _ from "utils/underscore";
1
+ import _ from "underscore";
2
2
  import { analUserAgent } from "utils/browser";
3
3
  import {
4
4
  ERRORS,
@@ -34,6 +34,8 @@ const WebRTCLoader = function (provider,
34
34
  let ws = null;
35
35
  let wsConnected = false;
36
36
 
37
+ let transportPolicy = getTransportQuery(webSocketUrl);
38
+
37
39
  let mainStream = null;
38
40
 
39
41
  // used for getting media stream from OME or host peer
@@ -81,6 +83,24 @@ const WebRTCLoader = function (provider,
81
83
  }
82
84
  })();
83
85
 
86
+ function getTransportQuery(webSocketUrl) {
87
+
88
+ try {
89
+ const url = new URL(webSocketUrl);
90
+ const transport = url.searchParams.get('transport');
91
+
92
+ if (transport === null) {
93
+ return undefined;
94
+ }
95
+
96
+ const normalized = transport.toLowerCase();
97
+
98
+ return normalized;
99
+
100
+ } catch (e) {
101
+ return undefined;
102
+ }
103
+ }
84
104
 
85
105
  function getPeerConnectionById(id) {
86
106
 
@@ -257,6 +277,7 @@ const WebRTCLoader = function (provider,
257
277
  } else if (iceServers) {
258
278
 
259
279
  // second priority using ice servers from ome and force using TCP
280
+
260
281
  peerConnectionConfig.iceServers = [];
261
282
 
262
283
  for (let i = 0; i < iceServers.length; i++) {
@@ -299,8 +320,20 @@ const WebRTCLoader = function (provider,
299
320
  peerConnectionConfig.iceServers.push(regIceServer);
300
321
  }
301
322
 
302
- peerConnectionConfig.iceTransportPolicy = 'relay';
323
+ // webrtcConfig.iceTransportPolicy has first priority than transport query for iceTransportPolicy because it is more specific setting for player.
324
+ if (playerConfig.getConfig().webrtcConfig &&
325
+ playerConfig.getConfig().webrtcConfig.iceTransportPolicy) {
326
+ peerConnectionConfig.iceTransportPolicy = playerConfig.getConfig().webrtcConfig.iceTransportPolicy;
327
+ } else {
328
+
329
+ let iceTransportPolicy = 'relay';
330
+
331
+ if (transportPolicy === 'all') {
332
+ iceTransportPolicy = 'all';
333
+ }
303
334
 
335
+ peerConnectionConfig.iceTransportPolicy = iceTransportPolicy;
336
+ }
304
337
  } else {
305
338
 
306
339
  // last priority using default ice servers.
@@ -1,69 +1,69 @@
1
- /**
2
- * Created by hoho on 2018. 11. 12..
3
- */
4
- import { ERROR, STATE_ERROR } from "api/constants";
5
- import _ from "utils/underscore";
6
-
7
- export const extractVideoElement = function (elementOrMse) {
8
- if (_.isElement(elementOrMse)) {
9
- return elementOrMse;
10
- }
11
- if (elementOrMse.getVideoElement) {
12
- return elementOrMse.getVideoElement();
13
- } else if (elementOrMse.media) {
14
- return elementOrMse.media;
15
- }
16
- return null;
17
- };
18
-
19
- export const separateLive = function (mse) {
20
- //ToDo : You consider hlsjs. But not now because we don't support hlsjs.
21
-
22
- if (mse && mse.isDynamic) {
23
- return mse.isDynamic();
24
- } else {
25
- return false;
26
- }
27
- };
28
-
29
- export const errorTrigger = function (error, provider) {
30
- if (provider) {
31
- provider.setState(STATE_ERROR);
32
- provider.pause();
33
- provider.trigger(ERROR, error);
34
- }
35
-
36
- };
37
-
38
- export const pickCurrentSource = (sources, playerConfig) => {
39
-
40
- let sourceIndex = 0;
41
-
42
- if (sources) {
43
-
44
- if (playerConfig.getSourceIndex() === -1) {
45
-
46
- for (var i = 0; i < sources.length; i++) {
47
- if (sources[i].default) {
48
- sourceIndex = i;
49
- break;
50
- }
51
- }
52
- } else {
53
-
54
- sourceIndex = playerConfig.getSourceIndex();
55
- }
56
-
57
- }
58
-
59
- return sourceIndex;
60
- }
61
-
62
- export function getSeekableStartEnd(mediaElement) {
63
- let start = mediaElement.seekable.start(0);
64
- let end = mediaElement.seekable.end(mediaElement.seekable.length - 1);
65
- return {
66
- start: start,
67
- end: end
68
- };
69
- }
1
+ /**
2
+ * Created by hoho on 2018. 11. 12..
3
+ */
4
+ import { ERROR, STATE_ERROR } from "api/constants";
5
+ import _ from "underscore";
6
+
7
+ export const extractVideoElement = function (elementOrMse) {
8
+ if (_.isElement(elementOrMse)) {
9
+ return elementOrMse;
10
+ }
11
+ if (elementOrMse.getVideoElement) {
12
+ return elementOrMse.getVideoElement();
13
+ } else if (elementOrMse.media) {
14
+ return elementOrMse.media;
15
+ }
16
+ return null;
17
+ };
18
+
19
+ export const separateLive = function (mse) {
20
+ //ToDo : You consider hlsjs. But not now because we don't support hlsjs.
21
+
22
+ if (mse && mse.isDynamic) {
23
+ return mse.isDynamic();
24
+ } else {
25
+ return false;
26
+ }
27
+ };
28
+
29
+ export const errorTrigger = function (error, provider) {
30
+ if (provider) {
31
+ provider.setState(STATE_ERROR);
32
+ provider.pause();
33
+ provider.trigger(ERROR, error);
34
+ }
35
+
36
+ };
37
+
38
+ export const pickCurrentSource = (sources, playerConfig) => {
39
+
40
+ let sourceIndex = 0;
41
+
42
+ if (sources) {
43
+
44
+ if (playerConfig.getSourceIndex() === -1) {
45
+
46
+ for (var i = 0; i < sources.length; i++) {
47
+ if (sources[i].default) {
48
+ sourceIndex = i;
49
+ break;
50
+ }
51
+ }
52
+ } else {
53
+
54
+ sourceIndex = playerConfig.getSourceIndex();
55
+ }
56
+
57
+ }
58
+
59
+ return sourceIndex;
60
+ }
61
+
62
+ export function getSeekableStartEnd(mediaElement) {
63
+ let start = mediaElement.seekable.start(0);
64
+ let end = mediaElement.seekable.end(mediaElement.seekable.length - 1);
65
+ return {
66
+ start: start,
67
+ end: end
68
+ };
69
+ }
@@ -1,143 +1,143 @@
1
- import API from 'api/Api';
2
- import {isWebRTC, checkAndGetContainerElement} from 'utils/validator';
3
- import _ from "utils/underscore";
4
-
5
- /**
6
- * Main OvenPlayerSDK object
7
- */
8
- function ovenPlayerFactory() {
9
-
10
- const OvenPlayerSDK = {};
11
-
12
- const playerList = OvenPlayerSDK.playerList = [];
13
-
14
- /**
15
- * Create player instance and return it.
16
- *
17
- * @param {string | dom element} container Id of container element or container element
18
- * @param {object} options The options
19
- */
20
- OvenPlayerSDK.create = function (container, options) {
21
-
22
- if (!window.OvenPlayerConsole || Object.keys(window.OvenPlayerConsole).length === 0) {
23
- window.OvenPlayerConsole = {};
24
- OvenPlayerConsole['log'] = function () {
25
- };
26
- }
27
-
28
- let containerElement = checkAndGetContainerElement(container);
29
-
30
- const playerInstance = API(containerElement);
31
- playerInstance.init(options);
32
-
33
- playerList.push(playerInstance);
34
-
35
- return playerInstance;
36
- };
37
-
38
- /**
39
- * Gets the player instance list.
40
- *
41
- * @return {array} The player list.
42
- */
43
- OvenPlayerSDK.getPlayerList = function () {
44
-
45
- return playerList;
46
- };
47
-
48
- /**
49
- * Gets the player instance by container id.
50
- *
51
- * @param {string} containerId The container identifier
52
- * @return {obeject | null} The player instance.
53
- */
54
- OvenPlayerSDK.getPlayerByContainerId = function (containerId) {
55
-
56
- for (let i = 0; i < playerList.length; i++) {
57
-
58
- if (playerList[i].getContainerId() === containerId) {
59
-
60
- return playerList[i];
61
- }
62
- }
63
-
64
- return null;
65
- };
66
-
67
- /**
68
- * Gets the player instance by index.
69
- *
70
- * @param {number} index The index
71
- * @return {object | null} The player instance.
72
- */
73
- OvenPlayerSDK.getPlayerByIndex = function (index) {
74
-
75
- const playerInstance = playerList[index];
76
-
77
- if (playerInstance) {
78
-
79
- return playerInstance;
80
- } else {
81
-
82
- return null;
83
- }
84
- };
85
-
86
- /**
87
- * Remove the player instance by playerInstance.
88
- *
89
- * @param {playerInstance} playerInstance
90
- * @return {null}
91
- */
92
- OvenPlayerSDK.removePlayer = function (playerInstance) {
93
-
94
- for (let i = 0; i < playerList.length; i++) {
95
-
96
- if (playerList[i] === playerInstance) {
97
- playerList.splice(i, 1);
98
- }
99
- }
100
- };
101
-
102
- /**
103
- * Generate webrtc source for player source type.
104
- *
105
- * @param {Object | Array} source webrtc source
106
- * @return {Array} Player source Object.
107
- */
108
- OvenPlayerSDK.generateWebrtcUrls = function (sources) {
109
- return (_.isArray(sources) ? sources : [sources]).map(function (source, index) {
110
- if (source.host && isWebRTC(source.host) && source.application && source.stream) {
111
- return {
112
- file: source.host + "/" + source.application + "/" + source.stream,
113
- type: "webrtc",
114
- label: source.label ? source.label : "webrtc-" + (index + 1)
115
- };
116
- }
117
- });
118
- };
119
-
120
- /**
121
- * Whether show the player core log or not.
122
- *
123
- * @param {boolean} boolean run debug mode or not.
124
- * @return {boolean} run debug mode or not.
125
- */
126
- OvenPlayerSDK.debug = function (isDebugMode) {
127
-
128
- if (isDebugMode) {
129
- window.OvenPlayerConsole = {log: window['console']['log']};
130
- } else {
131
- window.OvenPlayerConsole = {
132
- log: function () {
133
- }
134
- };
135
- }
136
- return isDebugMode;
137
- };
138
-
139
- return OvenPlayerSDK;
140
- }
141
-
142
-
143
- export default ovenPlayerFactory();
1
+ import API from 'api/Api';
2
+ import {isWebRTC, checkAndGetContainerElement} from 'utils/validator';
3
+ import _ from "underscore";
4
+
5
+ /**
6
+ * Main OvenPlayerSDK object
7
+ */
8
+ function ovenPlayerFactory() {
9
+
10
+ const OvenPlayerSDK = {};
11
+
12
+ const playerList = OvenPlayerSDK.playerList = [];
13
+
14
+ /**
15
+ * Create player instance and return it.
16
+ *
17
+ * @param {string | dom element} container Id of container element or container element
18
+ * @param {object} options The options
19
+ */
20
+ OvenPlayerSDK.create = function (container, options) {
21
+
22
+ if (!window.OvenPlayerConsole || Object.keys(window.OvenPlayerConsole).length === 0) {
23
+ window.OvenPlayerConsole = {};
24
+ OvenPlayerConsole['log'] = function () {
25
+ };
26
+ }
27
+
28
+ let containerElement = checkAndGetContainerElement(container);
29
+
30
+ const playerInstance = API(containerElement);
31
+ playerInstance.init(options);
32
+
33
+ playerList.push(playerInstance);
34
+
35
+ return playerInstance;
36
+ };
37
+
38
+ /**
39
+ * Gets the player instance list.
40
+ *
41
+ * @return {array} The player list.
42
+ */
43
+ OvenPlayerSDK.getPlayerList = function () {
44
+
45
+ return playerList;
46
+ };
47
+
48
+ /**
49
+ * Gets the player instance by container id.
50
+ *
51
+ * @param {string} containerId The container identifier
52
+ * @return {obeject | null} The player instance.
53
+ */
54
+ OvenPlayerSDK.getPlayerByContainerId = function (containerId) {
55
+
56
+ for (let i = 0; i < playerList.length; i++) {
57
+
58
+ if (playerList[i].getContainerId() === containerId) {
59
+
60
+ return playerList[i];
61
+ }
62
+ }
63
+
64
+ return null;
65
+ };
66
+
67
+ /**
68
+ * Gets the player instance by index.
69
+ *
70
+ * @param {number} index The index
71
+ * @return {object | null} The player instance.
72
+ */
73
+ OvenPlayerSDK.getPlayerByIndex = function (index) {
74
+
75
+ const playerInstance = playerList[index];
76
+
77
+ if (playerInstance) {
78
+
79
+ return playerInstance;
80
+ } else {
81
+
82
+ return null;
83
+ }
84
+ };
85
+
86
+ /**
87
+ * Remove the player instance by playerInstance.
88
+ *
89
+ * @param {playerInstance} playerInstance
90
+ * @return {null}
91
+ */
92
+ OvenPlayerSDK.removePlayer = function (playerInstance) {
93
+
94
+ for (let i = 0; i < playerList.length; i++) {
95
+
96
+ if (playerList[i] === playerInstance) {
97
+ playerList.splice(i, 1);
98
+ }
99
+ }
100
+ };
101
+
102
+ /**
103
+ * Generate webrtc source for player source type.
104
+ *
105
+ * @param {Object | Array} source webrtc source
106
+ * @return {Array} Player source Object.
107
+ */
108
+ OvenPlayerSDK.generateWebrtcUrls = function (sources) {
109
+ return (_.isArray(sources) ? sources : [sources]).map(function (source, index) {
110
+ if (source.host && isWebRTC(source.host) && source.application && source.stream) {
111
+ return {
112
+ file: source.host + "/" + source.application + "/" + source.stream,
113
+ type: "webrtc",
114
+ label: source.label ? source.label : "webrtc-" + (index + 1)
115
+ };
116
+ }
117
+ });
118
+ };
119
+
120
+ /**
121
+ * Whether show the player core log or not.
122
+ *
123
+ * @param {boolean} boolean run debug mode or not.
124
+ * @return {boolean} run debug mode or not.
125
+ */
126
+ OvenPlayerSDK.debug = function (isDebugMode) {
127
+
128
+ if (isDebugMode) {
129
+ window.OvenPlayerConsole = {log: window['console']['log']};
130
+ } else {
131
+ window.OvenPlayerConsole = {
132
+ log: function () {
133
+ }
134
+ };
135
+ }
136
+ return isDebugMode;
137
+ };
138
+
139
+ return OvenPlayerSDK;
140
+ }
141
+
142
+
143
+ export default ovenPlayerFactory();