@gcorevideo/player 0.0.5 → 0.2.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/lib/types.js CHANGED
@@ -1 +1,8 @@
1
- export {};
1
+ export var PlayerEvent;
2
+ (function (PlayerEvent) {
3
+ PlayerEvent["Ready"] = "ready";
4
+ PlayerEvent["Play"] = "play";
5
+ PlayerEvent["Pause"] = "pause";
6
+ PlayerEvent["Stop"] = "stop";
7
+ PlayerEvent["Ended"] = "ended";
8
+ })(PlayerEvent || (PlayerEvent = {}));
@@ -1,7 +1,3 @@
1
1
  export declare function getLocation(href: string): HTMLAnchorElement;
2
2
  export declare function strtimeToMiliseconds(str: string): number;
3
- export declare function isFullscreen(el: HTMLElement): boolean;
4
- export declare const FullscreenIOS: {
5
- isFullscreen: (el: HTMLVideoElement) => boolean;
6
- };
7
3
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,qBAMvC;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAyBxD;AAGD,wBAAgB,YAAY,CAAC,EAAE,EAAE,WAAW,GAAG,OAAO,CAQrD;AAED,eAAO,MAAM,aAAa;uBACI,gBAAgB,KAAG,OAAO;CAYvD,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,qBAMvC;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAyBxD"}
@@ -1,6 +1,3 @@
1
- // import LogManager from './LogManager';
2
- import { Browser } from '@clappr/core';
3
- import assert from 'assert';
4
1
  export function getLocation(href) {
5
2
  const l = document.createElement('a');
6
3
  l.href = href;
@@ -32,26 +29,3 @@ export function strtimeToMiliseconds(str) {
32
29
  }
33
30
  return (h + m + s);
34
31
  }
35
- // TODO refactor
36
- export function isFullscreen(el) {
37
- const video = el.nodeName === "video" ? el : el.querySelector('video');
38
- assert.ok(video, 'element must be a video or contain a video element');
39
- if (Browser.isiOS) {
40
- return FullscreenIOS.isFullscreen(video);
41
- }
42
- return !!(document.fullscreenElement);
43
- }
44
- export const FullscreenIOS = {
45
- isFullscreen: function (el) {
46
- try {
47
- if (el.webkitDisplayingFullscreen !== undefined) {
48
- return !!(el.webkitDisplayingFullscreen);
49
- }
50
- }
51
- catch (e) {
52
- // LogManager.exception(error);
53
- reportError(e);
54
- }
55
- return false;
56
- }
57
- };
@@ -0,0 +1,5 @@
1
+ export declare function version(): {
2
+ gplayer: string;
3
+ clappr: string;
4
+ };
5
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAGA,wBAAgB,OAAO;;;EAKtB"}
package/lib/version.js ADDED
@@ -0,0 +1,8 @@
1
+ import * as pkg from '../package.json' with { "type": "json" };
2
+ import * as lock from '../package-lock.json' with { "type": "json" };
3
+ export function version() {
4
+ return {
5
+ gplayer: pkg.version,
6
+ clappr: lock.packages['node_modules/@clappr/core'].version,
7
+ };
8
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gcorevideo/player",
3
- "version": "0.0.5",
3
+ "version": "0.2.3",
4
4
  "description": "Gcore JavaScript video player",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -31,6 +31,7 @@
31
31
  "homepage": "https://github.com/G-Core/gcore-videoplayer-js#readme",
32
32
  "devDependencies": {
33
33
  "@rollup/plugin-commonjs": "^28.0.1",
34
+ "@rollup/plugin-json": "^6.1.0",
34
35
  "@rollup/plugin-node-resolve": "^15.3.0",
35
36
  "@types/node": "^22.10.1",
36
37
  "assert": "^2.1.0",
package/rollup.config.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // https://github.com/rollup/rollup-starter-lib
2
- import resolve from '@rollup/plugin-node-resolve';
3
2
  import commonjs from '@rollup/plugin-commonjs';
3
+ import json from '@rollup/plugin-json';
4
+ import resolve from '@rollup/plugin-node-resolve';
4
5
  import sass from 'rollup-plugin-sass';
5
6
  import { string } from 'rollup-plugin-string';
6
7
  import polyfillNode from 'rollup-plugin-polyfill-node';
@@ -15,6 +16,7 @@ export default [
15
16
  }),
16
17
  resolve(),
17
18
  commonjs(),
19
+ json(),
18
20
  string({
19
21
  include: [
20
22
  '**/*.ejs',
package/src/Player.ts CHANGED
@@ -1,16 +1,15 @@
1
1
  import {
2
2
  Browser,
3
+ Events as ClapprEvents,
4
+ HTML5Video,
3
5
  Log,
4
6
  Player as PlayerClappr,
5
7
  $,
6
8
  Loader,
7
9
  } from '@clappr/core';
8
10
  import assert from 'assert';
9
- import Hls from 'hls.js';
10
11
  import EventLite from "event-lite";
11
12
 
12
- import '../assets/style/main.scss'; // TODO check if needed
13
-
14
13
  import type {
15
14
  CorePlayerEvents,
16
15
  CoreOptions,
@@ -18,30 +17,26 @@ import type {
18
17
  PlayerMediaSource,
19
18
  } from "./internal.types.js";
20
19
  import type {
20
+ BitrateInfo,
21
+ PlaybackType,
21
22
  PlayerPlugin,
22
23
  StreamMediaSource,
23
- } from "./types";
24
-
25
- import { reportError, trace } from "./trace/index.js";
24
+ } from "./types.js";
25
+ import { reportError } from "./trace/index.js";
26
26
  import {
27
27
  PlayerConfig,
28
- MediaTransport,
29
- TransportPreference,
28
+ PlayerEvent,
30
29
  } from "./types.js";
30
+ import DashPlayback from './plugins/dash-playback/DashPlayback.js';
31
+ import HlsPlayback from './plugins/hls-playback/HlsPlayback.js';
31
32
 
32
- export enum PlayerEvent {
33
- Ready = 'ready',
34
- Play = 'play',
35
- Pause = 'pause',
36
- Stop = 'stop',
37
- Ended = 'ended',
38
- }
33
+ import '../assets/style/main.scss'; // TODO check if needed
39
34
 
40
35
  // TODO implement transport retry/failover and fallback logic
41
36
 
42
37
  type PlayerEventHandler<T extends PlayerEvent> = () => void;
43
38
 
44
- const T = "Player";
39
+ const T = "GPlayer";
45
40
 
46
41
  const DEFAULT_OPTIONS: Partial<PlayerConfig> = {
47
42
  autoPlay: false,
@@ -49,6 +44,8 @@ const DEFAULT_OPTIONS: Partial<PlayerConfig> = {
49
44
  loop: false,
50
45
  }
51
46
 
47
+ export type PlaybackModule = 'dash' | 'hls' | 'native';
48
+
52
49
  type PluginOptions = Record<string, unknown>;
53
50
 
54
51
  /**
@@ -67,10 +64,36 @@ export class Player {
67
64
 
68
65
  private tuneInEntered = false;
69
66
 
70
- private supportedMediaTransports: MediaTransport[] = [];
71
-
72
67
  private config: PlayerConfig;
73
68
 
69
+ private bitrateInfo: BitrateInfo | null = null;
70
+
71
+ get activePlayback(): PlaybackModule | null {
72
+ if (!this.player?.core.activePlayback) {
73
+ return null;
74
+ }
75
+ switch (this.player.core.activePlayback.name) {
76
+ case 'dash':
77
+ return 'dash';
78
+ case 'hls':
79
+ return 'hls';
80
+ default:
81
+ return 'native';
82
+ }
83
+ }
84
+
85
+ get bitrate(): BitrateInfo | null {
86
+ return this.bitrateInfo;
87
+ }
88
+
89
+ get hd() {
90
+ return this.player?.core.activePlayback?.isHighDefinitionInUse || false;
91
+ }
92
+
93
+ get playbackType(): PlaybackType | undefined{
94
+ return this.player?.core.activePlayback?.getPlaybackType();
95
+ }
96
+
74
97
  get playing() {
75
98
  return this.player ? this.player.isPlaying() : false;
76
99
  }
@@ -93,9 +116,13 @@ export class Player {
93
116
  this.emitter.off(event, handler);
94
117
  }
95
118
 
119
+ configure(config: Partial<PlayerConfig>) {
120
+ $.extend(true, this.config, config);
121
+ }
122
+
96
123
  async init(playerElement: HTMLElement) {
97
124
  assert.ok(!this.player, 'Player already initialized');
98
- assert.ok(playerElement, 'Player element is required');
125
+ assert.ok(playerElement, 'Player container element is required');
99
126
  if (
100
127
  this.config.debug === 'all' ||
101
128
  this.config.debug === 'clappr'
@@ -103,27 +130,25 @@ export class Player {
103
130
  Log.setLevel(0);
104
131
  }
105
132
 
106
- Log.debug('Config', this.config);
107
-
108
- this.configurePlugins();
109
- return this.loadPlugins().then(async () => {
110
- const coreOpts = this.buildCoreOptions(playerElement);
111
- const {
112
- core,
113
- container,
114
- } = Loader.registeredPlugins;
115
- coreOpts.plugins = {
116
- core: Object.values(core),
117
- container: Object.values(container),
118
- playback: Loader.registeredPlaybacks,
119
- } as CorePluginOptions;
120
- console.log('plugins', coreOpts.plugins);
121
- return this.initPlayer(coreOpts);
122
- });
133
+ Log.debug(T, 'Config', this.config);
134
+
135
+ this.configurePlaybacks();
136
+ const coreOpts = this.buildCoreOptions(playerElement);
137
+ const {
138
+ core,
139
+ container,
140
+ } = Loader.registeredPlugins;
141
+ coreOpts.plugins = {
142
+ core: Object.values(core),
143
+ container: Object.values(container),
144
+ playback: Loader.registeredPlaybacks,
145
+ } as CorePluginOptions;
146
+ Log.debug(T, 'coreOpts', coreOpts);
147
+ return this.initPlayer(coreOpts);
123
148
  }
124
149
 
125
150
  destroy() {
126
- trace(`${T} destroy`, { player: !!this.player });
151
+ Log.debug(T, 'destroy', { player: !!this.player });
127
152
  if (this.player) {
128
153
  this.player.destroy();
129
154
  this.player = null;
@@ -154,8 +179,8 @@ export class Player {
154
179
  Loader.registerPlugin(plugin);
155
180
  }
156
181
 
157
- private loadPlugins(): Promise<void> {
158
- return Promise.all(this.pluginLoaders.map((loader) => loader())).then(() => { });
182
+ static unregisterPlugin(plugin: PlayerPlugin) {
183
+ Loader.unregisterPlugin(plugin);
159
184
  }
160
185
 
161
186
  private initPlayer(coreOptions: CoreOptions) {
@@ -186,7 +211,7 @@ export class Player {
186
211
  // TODO sort this out
187
212
  private async tuneIn() {
188
213
  assert.ok(this.player);
189
- trace(`${T} tuneIn enter`, {
214
+ Log.debug(T, 'tuneIn enter', {
190
215
  ready: this.clapprReady,
191
216
  tuneInEntered: this.tuneInEntered,
192
217
  });
@@ -195,6 +220,17 @@ export class Player {
195
220
  }
196
221
  this.tuneInEntered = true;
197
222
  const player = this.player;
223
+ try {
224
+ this.emitter.emit(PlayerEvent.Ready);
225
+ } catch (e) {
226
+ reportError(e);
227
+ }
228
+ if (player.core.activeContainer) {
229
+ this.bindBitrateChangeHandler();
230
+ }
231
+ player.core.on(ClapprEvents.CORE_ACTIVE_CONTAINER_CHANGED, () => {
232
+ this.bindBitrateChangeHandler();
233
+ }, null);
198
234
  if (
199
235
  Browser.isiOS &&
200
236
  player.core.activePlayback
@@ -212,40 +248,19 @@ export class Player {
212
248
  }
213
249
  }
214
250
 
215
- private configurePlugins() {
216
- if (!Browser.isiOS && this.config.multisources.some((el) => el.sourceDash)) {
217
- this.scheduleLoad(async () => {
218
- const module = await import('./plugins/dash-playback/DashPlayback.js');
219
- Loader.registerPlayback(module.default);
220
- })
221
- }
222
- // TODO remove !isiOS?
223
- // if (!Browser.isiOS && this.config.multisources.some((el) => el.hls_mpegts_url)) {
224
- if (this.config.multisources.some((el) => el.hlsMpegtsUrl || el.hlsCmafUrl || el.source.endsWith('.m3u8'))) {
225
- this.scheduleLoad(async () => {
226
- const module = await import('./plugins/hls-playback/HlsPlayback.js');
227
- Loader.registerPlayback(module.default);
228
- })
229
- }
230
- }
231
-
232
251
  private events: CorePlayerEvents = {
233
252
  onReady: () => {
253
+ Log.debug(T, 'onReady', { clapprReady: this.clapprReady, player: !!this.player, core: !!this.player?.core, activeContainer: !!this.player?.core.activeContainer });
234
254
  if (this.clapprReady) {
235
255
  return;
236
256
  }
237
257
  this.clapprReady = true;
258
+ // TODO figure out what's for
238
259
  if (this.timer) {
239
260
  clearTimeout(this.timer);
240
261
  this.timer = null;
241
262
  }
242
- trace(`${T} onReady`);
243
263
  setTimeout(() => this.tuneIn(), 0);
244
- try {
245
- this.emitter.emit(PlayerEvent.Ready);
246
- } catch (e) {
247
- reportError(e);
248
- }
249
264
  },
250
265
  onPlay: () => {
251
266
  try {
@@ -278,20 +293,21 @@ export class Player {
278
293
  };
279
294
 
280
295
  private buildCoreOptions(playerElement: HTMLElement): CoreOptions {
281
- this.checkMediaTransportsSupport();
282
- const multisources = this.processMultisources(this.config.priorityTransport);
283
- const mediaSources = multisources.map(ms => ms.source);
284
- const mainSource = this.findMainSource();
285
- const mainSourceUrl = unwrapSource(mainSource ? this.selectMediaTransport(mainSource, this.config.priorityTransport) : undefined);
296
+ const multisources = this.config.multisources;
297
+ const mainSource = this.config.playbackType === 'live' ? multisources.find(ms => ms.live !== false) : multisources[0];
298
+ const mediaSources = mainSource ? this.buildMediaSourcesList(mainSource): [];
299
+ const mainSourceUrl = mediaSources[0];
286
300
  const poster = mainSource?.poster ?? this.config.poster;
287
301
 
288
302
  const coreOptions: CoreOptions & PluginOptions = {
303
+ ...this.config.pluginSettings,
289
304
  autoPlay: this.config.autoPlay,
290
305
  debug: this.config.debug || 'none',
291
306
  events: this.events,
307
+ height: playerElement.clientHeight,
308
+ loop: this.config.loop,
292
309
  multisources,
293
310
  mute: this.config.mute,
294
- ...this.config.pluginSettings,
295
311
  playback: {
296
312
  controls: false,
297
313
  preload: Browser.isiOS ? 'metadata' : 'none',
@@ -305,86 +321,62 @@ export class Player {
305
321
  playbackType: this.config.playbackType,
306
322
  poster,
307
323
  width: playerElement.clientWidth,
308
- height: playerElement.clientHeight,
309
- loop: this.config.loop,
310
- strings: this.config.strings,
311
324
  source: mainSourceUrl,
312
325
  sources: mediaSources,
326
+ strings: this.config.strings,
313
327
  };
314
- trace(`${T} buildCoreOptions`, coreOptions);
315
328
  return coreOptions;
316
329
  }
317
330
 
318
- private findMainSource(): StreamMediaSource | undefined {
319
- return this.config.multisources.find(ms => ms.live !== false);
331
+ private configurePlaybacks() {
332
+ Loader.registerPlayback(DashPlayback);
333
+ Loader.registerPlayback(HlsPlayback);
334
+ Loader.registerPlayback(HTML5Video);
320
335
  }
321
336
 
322
- private scheduleLoad(cb: () => Promise<void>) {
323
- this.pluginLoaders.push(cb);
337
+ private bindBitrateChangeHandler() {
338
+ this.player?.core.activeContainer.on(ClapprEvents.CONTAINER_BITRATE, (bitrate: BitrateInfo) => {
339
+ this.bitrateInfo = bitrate;
340
+ });
324
341
  }
325
342
 
326
- private selectMediaTransport(ms: StreamMediaSource, priorityTransport: TransportPreference = ms.priorityTransport): string {
327
- const cmafUrl = ms.hlsCmafUrl || ms.source; // source is default url for hls
328
- const mpegtsUrl = ms.hlsMpegtsUrl; // no-low-latency HLS
329
- const dashUrl = ms.sourceDash;
330
- const masterSource = ms.source;
331
-
332
- const mts = this.getAvailableTransportsPreference(priorityTransport);
333
- for (const mt of mts) {
334
- switch (mt) {
335
- case 'dash':
336
- if (dashUrl) {
337
- return dashUrl;
338
- }
339
- break;
340
- case 'hls':
341
- if (cmafUrl) {
342
- return cmafUrl;
343
- }
344
- break;
345
- default:
346
- return mpegtsUrl || masterSource;
347
- }
343
+ private buildMediaSourcesList(ms: StreamMediaSource): string[] {
344
+ const msl: string[] = [];
345
+ const sources: Record<'dash' | 'master' | 'hls' | 'mpegts', string | null> = {
346
+ dash: ms.sourceDash,
347
+ master: ms.source,
348
+ hls: ms.hlsCmafUrl,
349
+ mpegts: ms.hlsMpegtsUrl,
348
350
  }
349
- // no supported transport found
350
- return '';
351
- }
352
-
353
- private getAvailableTransportsPreference(priorityTransport: TransportPreference): MediaTransport[] {
354
- const mtp: MediaTransport[] = [];
355
- if (priorityTransport !== 'auto' && this.supportedMediaTransports.includes(priorityTransport)) {
356
- mtp.push(priorityTransport);
351
+ switch (this.config.priorityTransport) {
352
+ case 'dash':
353
+ if (sources.dash) {
354
+ msl.push(sources.dash);
355
+ sources.dash = null;
356
+ }
357
+ break;
358
+ case 'hls':
359
+ if (sources.hls) {
360
+ msl.push(sources.hls);
361
+ sources.hls = null;
362
+ }
363
+ if (sources.master?.endsWith('.m3u8')) {
364
+ msl.push(sources.master);
365
+ sources.master = null;
366
+ }
367
+ break;
368
+ case 'mpegts':
369
+ if (sources.mpegts) {
370
+ msl.push(sources.mpegts);
371
+ sources.mpegts = null
372
+ }
373
+ break;
357
374
  }
358
- for (const mt of this.supportedMediaTransports) {
359
- if (mt !== priorityTransport) {
360
- mtp.push(mt);
375
+ Object.values(sources).forEach(s => {
376
+ if (s) {
377
+ msl.push(s);
361
378
  }
362
- }
363
- return mtp;
364
- }
365
-
366
- private checkMediaTransportsSupport() {
367
- const isDashSupported = typeof (globalThis.MediaSource || (globalThis as any).WebKitMediaSource) === 'function';
368
- if (isDashSupported) {
369
- this.supportedMediaTransports.push('dash');
370
- }
371
- if (Hls.isSupported()) {
372
- this.supportedMediaTransports.push('hls');
373
- }
374
- this.supportedMediaTransports.push('mpegts');
375
- }
376
-
377
- private processMultisources(transport?: TransportPreference): StreamMediaSource[] {
378
- return this.config.multisources.map((ms: StreamMediaSource): StreamMediaSource => ({
379
- ...ms,
380
- source: this.selectMediaTransport(ms, transport),
381
- })).filter((el): el is StreamMediaSource => !!el.source);
382
- }
383
- }
384
-
385
- function unwrapSource(s: PlayerMediaSource | undefined): string | undefined {
386
- if (!s) {
387
- return;
379
+ });
380
+ return msl;
388
381
  }
389
- return typeof s === "string" ? s : s.source;
390
382
  }
package/src/backend.ts CHANGED
@@ -3,8 +3,8 @@ import { StreamMediaSource, StreamMediaSourceDto } from "./types";
3
3
  export function fromStreamMediaSourceDto(s: StreamMediaSourceDto): StreamMediaSource {
4
4
  return ({
5
5
  ...s,
6
- hlsCmafUrl: s.hls_cmaf_url,
7
- hlsMpegtsUrl: s.hls_mpegts_url,
6
+ hlsCmafUrl: s.hls_cmaf_url ?? null,
7
+ hlsMpegtsUrl: s.hls_mpegts_url ?? null,
8
8
  priorityTransport: s.priority_transport,
9
9
  sourceDash: s.source_dash,
10
10
  vtt: s.vtt,
package/src/index.ts CHANGED
@@ -7,3 +7,4 @@ export * from "./trace/index.js";
7
7
  export * from "./trace/types.js";
8
8
  export * from "./types.js";
9
9
  export * from "./utils/Logger.js";
10
+ export * from "./version.js";
@@ -1,11 +1,17 @@
1
1
  import type {
2
2
  CorePlugin,
3
3
  ContainerPlugin,
4
- Playback as PlaybackPlugin,
5
- ExternalTrack,
4
+ Playback as ClapprPlayback,
6
5
  } from "@clappr/core";
7
6
  import { PlaybackType, PlayerDebugTag, StreamMediaSource } from "./types";
8
7
 
8
+ type ExternalTrack = {
9
+ kind?: "subtitles" | "captions";
10
+ src: string;
11
+ label: string;
12
+ lang: string;
13
+ }
14
+
9
15
  type MediacontrolStyles = {
10
16
  // TODO
11
17
  seekbar?: string;
@@ -76,10 +82,12 @@ export type ClapprVersionSpec = {
76
82
  // TODO
77
83
  }
78
84
 
85
+ export type PlaybackPluginFactory = typeof ClapprPlayback;
86
+
79
87
  export type CorePluginOptions = {
80
88
  core?: CorePlugin[];
81
89
  container?: ContainerPlugin[];
82
- playback?: PlaybackPlugin[];
90
+ playback?: PlaybackPluginFactory[];
83
91
  loadExternalPluginsFirst?: boolean;
84
92
  loadExternalPlaybacksFirst?: boolean;
85
93
  }
@@ -12,7 +12,6 @@ import DASHJS, {
12
12
  IManifestInfo
13
13
  } from 'dashjs';
14
14
 
15
- import { trace } from '../../trace/index.js';
16
15
  import { Duration, TimePosition, TimeValue } from '../../playback.types.js';
17
16
 
18
17
  const AUTO = -1;
@@ -243,7 +242,6 @@ export default class DashPlayback extends HTML5Video {
243
242
  }
244
243
 
245
244
  _setup() {
246
- trace(`${T} _setup`, { el: this.el });
247
245
  const dash = DASHJS.MediaPlayer().create();
248
246
  this._dash = dash;
249
247
  this._dash.initialize();
@@ -265,7 +263,6 @@ export default class DashPlayback extends HTML5Video {
265
263
 
266
264
  this._dash.on(DASHJS.MediaPlayer.events.STREAM_INITIALIZED, () => {
267
265
  const bitrates = dash.getBitrateInfoListFor('video');
268
- trace(`${T} STREAM_INITIALIZED`, { bitrates });
269
266
 
270
267
  this._updatePlaybackType();
271
268
  this._fillLevels(bitrates);
@@ -279,13 +276,10 @@ export default class DashPlayback extends HTML5Video {
279
276
  });
280
277
 
281
278
  this._dash.on(DASHJS.MediaPlayer.events.METRIC_ADDED, (e: DashMetricEvent) => {
282
- // console.log(`${T} onMetricAdded`, e);
283
- // TODO
284
279
  // Listen for the first manifest request in order to update player UI
285
280
  if ((e.metric as string) === 'DVRInfo') { // TODO fix typings
286
281
  assert.ok(this._dash, 'An instance of dashjs MediaPlayer is required to get metrics');
287
282
  const dvrInfo = this._dash.getDashMetrics().getCurrentDVRInfo('video');
288
- // trace(`${T} onMetricAdded DVRInfo`, {metric: e.metric, dvrInfo});
289
283
  if (dvrInfo) {
290
284
  // Extract time info
291
285
  this.manifestInfo = dvrInfo.manifestInfo;
@@ -578,7 +572,6 @@ export default class DashPlayback extends HTML5Video {
578
572
  }
579
573
 
580
574
  play() {
581
- trace(`${T} play`, { dash: !!this._dash });
582
575
  if (!this._dash) {
583
576
  this._setup();
584
577
  }
@@ -622,13 +615,9 @@ export default class DashPlayback extends HTML5Video {
622
615
  _updatePlaybackType() {
623
616
  assert.ok(this._dash, 'An instance of dashjs MediaPlayer is required to update the playback type');
624
617
  this._playbackType = this._dash.isDynamic() ? Playback.LIVE : Playback.VOD;
625
- trace(`${T} _updatePlaybackType`, {
626
- playbackType: this._playbackType,
627
- });
628
618
  }
629
619
 
630
620
  _fillLevels(levels: BitrateInfo[]) {
631
- // trace(`${T} _fillLevels`, {levels});
632
621
  // TOOD check that levels[i].qualityIndex === i
633
622
  this._levels = levels.map((level) => {
634
623
  return { id: level.qualityIndex, level: level };
@@ -778,7 +767,6 @@ export default class DashPlayback extends HTML5Video {
778
767
  // }
779
768
 
780
769
  private onLevelSwitch(currentLevel: BitrateInfo) {
781
- trace(`${T} onLevelSwitch`, {currentLevel});
782
770
  this.trigger(Events.PLAYBACK_BITRATE, {
783
771
  height: currentLevel.height,
784
772
  width: currentLevel.width,
@@ -797,12 +785,11 @@ export default class DashPlayback extends HTML5Video {
797
785
  }
798
786
 
799
787
  DashPlayback.canPlay = function (resource, mimeType) {
800
- console.log(`${T} canPlay resource:%s mimeType:%s`, resource, mimeType);
801
788
  const resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || [];
802
789
  const isDash = ((resourceParts.length > 1 && resourceParts[1].toLowerCase() === 'mpd') ||
803
790
  mimeType === 'application/dash+xml' || mimeType === 'video/mp4');
804
791
  const ctor = window.MediaSource || ('WebKitMediaSource' in window ? window.WebKitMediaSource : undefined);
805
- const isSupportByBrowser = typeof ctor === 'function';
806
- console.log(`${T} canPlay isSupportByBrowser:%s isDash:%s`, isSupportByBrowser, isDash);
807
- return !!(isSupportByBrowser && isDash);
792
+ const hasBrowserSupport = typeof ctor === 'function';
793
+ Log.debug(T, 'canPlay', {hasBrowserSupport, isDash});
794
+ return !!(hasBrowserSupport && isDash);
808
795
  };