@gumlet/insights-js-core 1.0.3 → 1.1.1

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 (54) hide show
  1. package/.github/workflows/main.yml +87 -0
  2. package/.gitlab-ci.yml +54 -0
  3. package/LICENSE +21 -0
  4. package/README.md +30 -0
  5. package/bitbucket-pipelines.yml +35 -0
  6. package/docs/payload-documentation.md +72 -0
  7. package/html/bitmovin.html +82 -0
  8. package/html/dashjs.html +55 -0
  9. package/html/hlsjs.html +72 -0
  10. package/html/html5.html +59 -0
  11. package/html/shaka.html +102 -0
  12. package/html/videojs.html +67 -0
  13. package/index.html +73 -0
  14. package/jest.config.js +187 -0
  15. package/js/adapters/Bitmovin7Adapter.js +352 -0
  16. package/js/adapters/BitmovinAdapter.js +198 -0
  17. package/js/adapters/DashjsAdapter.js +140 -0
  18. package/js/adapters/HTML5Adapter.js +774 -0
  19. package/js/adapters/HlsjsAdapter.js +152 -0
  20. package/js/adapters/ShakaAdapter.js +81 -0
  21. package/js/adapters/VideoJsAdapter.js +455 -0
  22. package/js/analyticsStateMachines/Bitmovin7AnalyticsStateMachine.js +471 -0
  23. package/js/analyticsStateMachines/BitmovinAnalyticsStateMachine.js +299 -0
  24. package/js/analyticsStateMachines/HTML5AnalyticsStateMachine.js +443 -0
  25. package/js/analyticsStateMachines/VideoJsAnalyticsStateMachine.js +503 -0
  26. package/js/cast/CastClient.js +50 -0
  27. package/js/cast/CastReceiver.js +37 -0
  28. package/js/core/AdapterFactory.js +41 -0
  29. package/js/core/Analytics.js +1364 -0
  30. package/js/core/AnalyticsStateMachineFactory.js +36 -0
  31. package/js/core/GumletInsightsExport.js +75 -0
  32. package/js/enums/CDNProviders.js +11 -0
  33. package/js/enums/Events.js +32 -0
  34. package/js/enums/GumletEnum.js +19 -0
  35. package/js/enums/MIMETypes.js +30 -0
  36. package/js/enums/Players.js +11 -0
  37. package/js/enums/StreamTypes.js +15 -0
  38. package/js/utils/EventsCall.js +22 -0
  39. package/js/utils/HttpCall.js +57 -0
  40. package/js/utils/LicenseCall.js +18 -0
  41. package/js/utils/Logger.js +40 -0
  42. package/js/utils/PlayerDetector.js +75 -0
  43. package/js/utils/PlayerInitCall.js +22 -0
  44. package/js/utils/SessionCreationCall.js +22 -0
  45. package/js/utils/Settings.js +3 -0
  46. package/js/utils/Utils.js +195 -0
  47. package/package.json +62 -1
  48. package/precommit.bash +8 -0
  49. package/tests/stage1.test.js +50 -0
  50. package/webpack.config.debug.js +34 -0
  51. package/webpack.config.js +40 -0
  52. package/webpack.config.release.js +62 -0
  53. package/gumlet-insights.min.js +0 -2
  54. package/gumlet-insights.min.js.LICENSE.txt +0 -10
@@ -0,0 +1,443 @@
1
+ import logger from '../utils/Logger';
2
+ import StateMachine from 'javascript-state-machine';
3
+ import Events from '../enums/Events';
4
+ import {HEARTBEAT_THRESHOLD} from '../utils/Settings';
5
+
6
+ export class HTML5AnalyticsStateMachine {
7
+ constructor(stateMachineCallbacks, opts = {}) {
8
+ this.stateMachineCallbacks = stateMachineCallbacks;
9
+
10
+ this.pausedTimestamp = null;
11
+ this.onEnterStateTimestamp = 0;
12
+ this.seekStartedAt = null;
13
+ this.seekTimestamp = 0;
14
+ this.seekedTimestamp = 0;
15
+ this.seekedFrom = 0;
16
+ this.lastPlayHeadDuration = 0;
17
+
18
+ this.playTimeStamp = null;
19
+
20
+ this.States = {
21
+ SETUP : 'SETUP',
22
+ STARTUP : 'STARTUP',
23
+ READY : 'READY',
24
+ PLAYING : 'PLAYING',
25
+ REBUFFERING : 'REBUFFERING',
26
+ PAUSE : 'PAUSE',
27
+ QUALITYCHANGE : 'QUALITYCHANGE',
28
+ PAUSED_SEEKING : 'PAUSED_SEEKING',
29
+ QUALITYCHANGE_PAUSE : 'QUALITYCHANGE_PAUSE',
30
+ QUALITYCHANGE_REBUFFERING: 'QUALITYCHANGE_REBUFFERING',
31
+ END : 'END',
32
+ ERROR : 'ERROR',
33
+ MUTING_READY : 'MUTING_READY',
34
+ MUTING_PLAY : 'MUTING_PLAY',
35
+ MUTING_PAUSE : 'MUTING_PAUSE',
36
+ CASTING : 'CASTING'
37
+ };
38
+
39
+ this.createStateMachine(opts);
40
+ }
41
+
42
+ getAllStates() {
43
+ return [
44
+ ...Object.keys(this.States).map(key => this.States[key]),
45
+ 'FINISH_QUALITYCHANGE_PAUSE',
46
+ 'FINISH_QUALITYCHANGE',
47
+ 'FINISH_QUALITYCHANGE_REBUFFERING'];
48
+ }
49
+
50
+ createStateMachine(opts = {}) {
51
+ this.stateMachine = StateMachine.create({
52
+ initial : this.States.SETUP,
53
+ error: (eventName, from, to, args, errorCode, errorMessage) => {
54
+ logger.error('Error in statemachine: ' + errorMessage);
55
+ },
56
+ events : [
57
+ {name: Events.TIMECHANGED, from: this.States.SETUP, to: this.States.SETUP},
58
+ {name: Events.READY, from: [this.States.SETUP, this.States.ERROR], to: this.States.READY},
59
+
60
+ {name: Events.PLAY, from: this.States.READY, to: this.States.STARTUP},
61
+
62
+ {name: Events.START_BUFFERING, from: this.States.STARTUP, to: this.States.STARTUP},
63
+ {name: Events.END_BUFFERING, from: this.States.STARTUP, to: this.States.STARTUP},
64
+ {name: Events.VIDEO_CHANGE, from: this.States.STARTUP, to: this.States.STARTUP},
65
+ {name: Events.AUDIO_CHANGE, from: this.States.STARTUP, to: this.States.STARTUP},
66
+
67
+ {name: Events.TIMECHANGED, from: this.States.STARTUP, to: this.States.PLAYING},
68
+ {name: Events.TIMECHANGED, from: this.States.PLAYING, to: this.States.PLAYING},
69
+ {name: Events.TIMECHANGED, from: this.States.PAUSE, to: this.States.PAUSE},
70
+
71
+ {name: Events.SEEKED, from: this.States.PAUSE, to: this.States.PAUSE},
72
+
73
+ {name: Events.END_BUFFERING, from: this.States.PLAYING, to: this.States.PLAYING},
74
+ {name: Events.START_BUFFERING, from: this.States.PLAYING, to: this.States.REBUFFERING},
75
+ {name: Events.START_BUFFERING, from: this.States.REBUFFERING, to: this.States.REBUFFERING},
76
+
77
+ {name: Events.PLAY, from: this.States.REBUFFERING, to: this.States.PLAYING},
78
+ {name: Events.TIMECHANGED, from: this.States.REBUFFERING, to: this.States.PLAYING},
79
+
80
+ // Ignoring since it's pushed in a live stream
81
+ {name: Events.SEEK, from: this.States.STARTUP, to: this.States.STARTUP},
82
+ {name: Events.PLAY, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING },
83
+
84
+ {name: Events.PAUSE, from: this.States.PLAYING, to: this.States.PAUSE},
85
+ {name: Events.PAUSE, from: this.States.REBUFFERING, to: this.States.PAUSE},
86
+
87
+ {name: Events.PLAY, from: this.States.PAUSE, to: this.States.PLAYING},
88
+ {name: Events.TIMECHANGED, from: this.States.PAUSE, to: this.States.PLAYING},
89
+
90
+ {name: Events.VIDEO_CHANGE, from: this.States.PLAYING, to: this.States.QUALITYCHANGE},
91
+ {name: Events.AUDIO_CHANGE, from: this.States.PLAYING, to: this.States.QUALITYCHANGE},
92
+ {name: Events.VIDEO_CHANGE, from: this.States.QUALITYCHANGE, to: this.States.QUALITYCHANGE},
93
+ {name: Events.AUDIO_CHANGE, from: this.States.QUALITYCHANGE, to: this.States.QUALITYCHANGE},
94
+ {name: 'FINISH_QUALITYCHANGE', from: this.States.QUALITYCHANGE, to: this.States.PLAYING},
95
+
96
+ {name: Events.VIDEO_CHANGE, from: this.States.PAUSE, to: this.States.QUALITYCHANGE_PAUSE},
97
+ {name: Events.AUDIO_CHANGE, from: this.States.PAUSE, to: this.States.QUALITYCHANGE_PAUSE},
98
+ {
99
+ name: Events.VIDEO_CHANGE,
100
+ from: this.States.QUALITYCHANGE_PAUSE,
101
+ to : this.States.QUALITYCHANGE_PAUSE
102
+ },
103
+ {
104
+ name: Events.AUDIO_CHANGE,
105
+ from: this.States.QUALITYCHANGE_PAUSE,
106
+ to : this.States.QUALITYCHANGE_PAUSE
107
+ },
108
+ {name: 'FINISH_QUALITYCHANGE_PAUSE', from: this.States.QUALITYCHANGE_PAUSE, to: this.States.PAUSE},
109
+
110
+ {name: Events.SEEK, from: this.States.PAUSE, to: this.States.PAUSED_SEEKING},
111
+ {name: Events.SEEK, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
112
+ {name: Events.AUDIO_CHANGE, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
113
+ {name: Events.VIDEO_CHANGE, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
114
+ {name: Events.START_BUFFERING, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
115
+ {name: Events.END_BUFFERING, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
116
+ {name: Events.SEEKED, from: this.States.PAUSED_SEEKING, to: this.States.PAUSE},
117
+ {name: Events.TIMECHANGED, from: this.States.PAUSED_SEEKING, to: this.States.PLAYING},
118
+ {name: Events.PAUSE, from: this.States.PAUSED_SEEKING, to: this.States.PAUSE},
119
+
120
+ {name: Events.END, from: this.States.PAUSED_SEEKING, to: this.States.END},
121
+ {name: Events.END, from: this.States.PLAYING, to: this.States.END},
122
+ {name: Events.END, from: this.States.PAUSE, to: this.States.END},
123
+ {name: Events.SEEK, from: this.States.END, to: this.States.END},
124
+ {name: Events.SEEKED, from: this.States.END, to: this.States.END},
125
+ {name: Events.TIMECHANGED, from: this.States.END, to: this.States.END},
126
+ {name: Events.END_BUFFERING, from: this.States.END, to: this.States.END},
127
+ {name: Events.START_BUFFERING, from: this.States.END, to: this.States.END},
128
+ {name: Events.END, from: this.States.END, to: this.States.END},
129
+
130
+ //Ignored - Livestreams do a Seek during startup and SEEKED once playback started
131
+ {name: Events.SEEKED, from: this.States.PLAYING, to: this.States.PLAYING},
132
+
133
+ {name: Events.PLAY, from: this.States.END, to: this.States.PLAYING},
134
+
135
+ {name: Events.ERROR, from: this.getAllStates(), to: this.States.ERROR},
136
+ {name: Events.PAUSE, from: this.States.ERROR, to: this.States.ERROR},
137
+
138
+ {name: Events.UNLOAD, from: this.getAllStates(), to: this.States.END},
139
+
140
+ {name: Events.START_AD, from: this.States.PLAYING, to: this.States.AD},
141
+ {name: Events.END_AD, from: this.States.AD, to: this.States.PLAYING},
142
+
143
+ {name: Events.MUTE, from: this.States.READY, to: this.States.MUTING_READY},
144
+ {name: Events.UN_MUTE, from: this.States.READY, to: this.States.MUTING_READY},
145
+ {name: 'FINISH_MUTING', from: this.States.MUTING_READY, to: this.States.READY},
146
+
147
+ {name: Events.MUTE, from: this.States.PLAYING, to: this.States.MUTING_PLAY},
148
+ {name: Events.UN_MUTE, from: this.States.PLAYING, to: this.States.MUTING_PLAY},
149
+ {name: 'FINISH_MUTING', from: this.States.MUTING_PLAY, to: this.States.PLAYING},
150
+
151
+ {name: Events.MUTE, from: this.States.PAUSE, to: this.States.MUTING_PAUSE},
152
+ {name: Events.UN_MUTE, from: this.States.PAUSE, to: this.States.MUTING_PAUSE},
153
+ {name: 'FINISH_MUTING', from: this.States.MUTING_PAUSE, to: this.States.PAUSE},
154
+
155
+ {name: Events.START_CAST, from: [this.States.READY, this.States.PAUSE], to: this.States.CASTING},
156
+ {name: Events.PAUSE, from: this.States.CASTING, to: this.States.CASTING},
157
+ {name: Events.PLAY, from: this.States.CASTING, to: this.States.CASTING},
158
+ {name: Events.TIMECHANGED, from: this.States.CASTING, to: this.States.CASTING},
159
+ {name: Events.MUTE, from: this.States.CASTING, to: this.States.CASTING},
160
+ {name: Events.SEEK, from: this.States.CASTING, to: this.States.CASTING},
161
+ {name: Events.SEEKED, from: this.States.CASTING, to: this.States.CASTING},
162
+ {name: Events.END_CAST, from: this.States.CASTING, to: this.States.READY},
163
+
164
+ {name: Events.SEEK, from: this.States.READY, to: this.States.READY},
165
+ {name: Events.SEEKED, from: this.States.READY, to: this.States.READY},
166
+ {name: Events.SEEKED, from: this.States.STARTUP, to: this.States.STARTUP},
167
+
168
+ {name: Events.SOURCE_LOADED, from: this.States.SETUP, to: this.States.SETUP},
169
+ {name: Events.SOURCE_LOADED, from: this.States.READY, to: this.States.READY},
170
+ {name: Events.SOURCE_LOADED, from: this.States.STARTUP, to: this.States.STARTUP},
171
+ {name: Events.SOURCE_LOADED, from: this.States.PLAYING, to: this.States.PLAYING},
172
+
173
+ {name: Events.VIDEO_CHANGE, from: this.States.REBUFFERING, to: this.States.QUALITYCHANGE_REBUFFERING},
174
+ {name: Events.AUDIO_CHANGE, from: this.States.REBUFFERING, to: this.States.QUALITYCHANGE_REBUFFERING},
175
+ {name: Events.VIDEO_CHANGE, from: this.States.QUALITYCHANGE_REBUFFERING, to: this.States.QUALITYCHANGE_REBUFFERING},
176
+ {name: Events.AUDIO_CHANGE, from: this.States.QUALITYCHANGE_REBUFFERING, to: this.States.QUALITYCHANGE_REBUFFERING},
177
+ {name: 'FINISH_QUALITYCHANGE_REBUFFERING', from: this.States.QUALITYCHANGE_REBUFFERING, to: this.States.REBUFFERING},
178
+ ],
179
+ callbacks: {
180
+ onbeforeevent: (event, from, to, timestamp, eventObject) => {
181
+ if (event === Events.SEEK && from === this.States.PAUSE) {
182
+ this.seekedFrom = this.lastPlayHeadDuration;
183
+ }
184
+
185
+ if (event === Events.SOURCE_LOADED) {
186
+ // event = sourceLoaded
187
+ // from = Ready/Setup
188
+ // to = Ready/Setup i.e. current event
189
+ // timestamp is current Timestamp
190
+ // eventObject = {} event obbject is there
191
+
192
+ // To manage HTML5 autload false where video is loaded after play event is clicked.
193
+ // Should we pass older client timestamp here as well? to insert the record before play event
194
+ let latency = null;
195
+ if (from === this.States.PLAYING) {
196
+ let currentTime = new Date();
197
+ latency = currentTime.getTime() - this.playTimeStamp.getTime();
198
+ }
199
+
200
+ this.stateMachineCallbacks.loaded(timestamp, this.States.READY, eventObject, latency);
201
+ return;
202
+ }
203
+
204
+ if (eventObject) {
205
+ this.lastPlayHeadDuration = eventObject.currentTime*1000;
206
+ }
207
+
208
+ },
209
+ onenterstate : (event, from, to, timestamp, eventObject) => {
210
+ if (to === this.States.SETUP && from === "none") {
211
+ // event = startup
212
+ // from = none as it is the initial/first event
213
+ // to = SETUP
214
+ // timestamp is undefined
215
+ // eventObject is undefined
216
+ this.stateMachineCallbacks.setup(timestamp, this.States.SETUP, eventObject);
217
+ }
218
+ else if (to === this.States.READY && from === this.States.SETUP) {
219
+ // event = ready
220
+ // from = SETUP
221
+ // to = Ready i.e. current event
222
+ // timestamp is current Timestamp
223
+ // eventObject = {} event obbject is there
224
+ this.stateMachineCallbacks.ready(timestamp, this.States.READY, eventObject);
225
+ }
226
+ else if (event === "play" && to === this.States.STARTUP) {
227
+ // Video is played for the first time after player initialisation
228
+
229
+ // event = play
230
+ // from = READY
231
+ // to = STARTUP i.e. current event
232
+ // timestamp is current Timestamp
233
+ // eventObject = {} event obbject is there
234
+ this.playTimeStamp = new Date();
235
+ this.stateMachineCallbacks.first_play(timestamp, this.States.PLAY, eventObject);
236
+ }
237
+ else if (event === "play" && from === this.States.PAUSE) {
238
+ // Video is played after being paused
239
+
240
+ // event = play
241
+ // from = PAUSE
242
+ // to = PLAYING i.e. current event
243
+ // timestamp is current Timestamp
244
+ // eventObject = {} event obbject is there
245
+
246
+ this.stateMachineCallbacks.play(timestamp, this.States.PLAY, eventObject);
247
+ this.stateMachineCallbacks.playing(timestamp, this.States.PLAYING, eventObject);
248
+ }
249
+ else if (event === "timechanged" && from === this.States.STARTUP && to === this.States.PLAYING) {
250
+ // Video has started playing for the first time after player initialisation
251
+
252
+ // event = timechanged
253
+ // from = STARTUP
254
+ // to = PLAYING i.e. current event
255
+ // timestamp is current Timestamp
256
+ // eventObject = {} event obbject is there
257
+
258
+ this.stateMachineCallbacks.playing(timestamp, this.States.PLAYING, eventObject);
259
+ this.stateMachineCallbacks.playback_started(eventObject);
260
+ }
261
+ else if (event === "timechanged" && from === this.States.PAUSE && to === this.States.PLAYING) {
262
+ // Video has started playing for the first time after player initialisation
263
+
264
+ // event = timechanged
265
+ // from = STARTUP
266
+ // to = PLAYING i.e. current event
267
+ // timestamp is current Timestamp
268
+ // eventObject = {} event obbject is there
269
+
270
+ this.stateMachineCallbacks.playing(timestamp, this.States.PLAYING, eventObject);
271
+ }
272
+ else if (to === this.States.PAUSE && from === this.States.PLAYING) {
273
+ // Only fire pause event if the the video was playing
274
+
275
+ // event = pause
276
+ // from = PLAYING
277
+ // to = PAUSE i.e. current event
278
+ // timestamp is current Timestamp
279
+ // eventObject = {} event obbject is there
280
+ this.stateMachineCallbacks.pause(timestamp, this.States.PAUSE, eventObject);
281
+ }
282
+ else if (to === this.States.END) {
283
+ // event = end
284
+ // from = PLAYING
285
+ // to = END i.e. current event
286
+ // timestamp is current Timestamp
287
+ // eventObject = {} event obbject is there
288
+
289
+ this.stateMachineCallbacks.end(timestamp, this.States.END, eventObject);
290
+ }
291
+ // else if (to === this.States.MUTING_PAUSE || to === this.States.MUTING_PLAY || to === this.States.MUTING_READY) {
292
+ // // event = mute
293
+ // // from = PLAYING/PAUSE etc
294
+ // // to = MUTING_PAUSE/etc i.e. current event
295
+ // // timestamp is current Timestamp
296
+ // // eventObject = {} event obbject is there
297
+ // console.log("Muting-----");
298
+ // this.stateMachineCallbacks.mute(timestamp, eventObject);
299
+ // }
300
+ else if (event === Events.START_BUFFERING) {
301
+ // event = startBuffering
302
+ // from = PLAYING etc
303
+ // to = REBUFFERING/etc i.e. current event
304
+ // timestamp is current Timestamp
305
+ // eventObject = {} event obbject is there
306
+
307
+ this.stateMachineCallbacks.start_rebuffer(timestamp, this.States.REBUFFERING, eventObject);
308
+ }
309
+ else if (event === "timechanged" && from === this.States.REBUFFERING && to === this.States.PLAYING) {
310
+ // event = endBuffering
311
+ // from = REBUFFERING
312
+ // to = PLAYING/etc i.e. current event
313
+ // timestamp is current Timestamp
314
+ // eventObject = {} event obbject is there
315
+
316
+ this.stateMachineCallbacks.end_rebuffer(timestamp, this.States.REBUFFERING, eventObject);
317
+ }
318
+
319
+ if (from === 'none' && opts.starttime) {
320
+ this.onEnterStateTimestamp = opts.starttime;
321
+ } else {
322
+ this.onEnterStateTimestamp = timestamp || new Date().getTime();
323
+ }
324
+
325
+ // logger.log('[' + from + '] => ' + event + ' => [' + to + '] (timestamp: ' + timestamp + ')');
326
+ //logger.log('Entering State ' + to + ' with ' + event + ' from ' + from);
327
+ if (eventObject && to !== this.States.PAUSED_SEEKING) {
328
+ // logger.log('Setting video time start to ' + eventObject.currentTime + ', going to ' + to);
329
+ this.stateMachineCallbacks.setVideoTimeStartFromEvent(eventObject);
330
+ }
331
+
332
+ // if (event === Events.START_CAST && to === this.States.CASTING) {
333
+ // this.stateMachineCallbacks.startCasting(timestamp, eventObject);
334
+ // }
335
+ },
336
+ onafterevent : (event, from, to, timestamp) => {
337
+ if (to === this.States.QUALITYCHANGE) {
338
+ this.stateMachine.FINISH_QUALITYCHANGE(timestamp);
339
+ }
340
+ if (to === this.States.MUTING_READY || to === this.States.MUTING_PLAY || to === this.States.MUTING_PAUSE) {
341
+ this.stateMachine.FINISH_MUTING(timestamp);
342
+ }
343
+ },
344
+ onleavestate : (event, from, to, timestamp, eventObject) => {
345
+ this.stateMachineCallbacks.resetSessionExpiry();
346
+
347
+ if (!timestamp) {
348
+ return;
349
+ }
350
+
351
+ const stateDuration = timestamp - this.onEnterStateTimestamp;
352
+ //logger.log('State ' + from + ' was ' + stateDuration + ' ms event:' + event);
353
+
354
+ if (eventObject && to !== this.States.PAUSED_SEEKING) {
355
+ logger.log('Setting video time end to ' + eventObject.currentTime + ', going to ' + to);
356
+ this.stateMachineCallbacks.setVideoTimeEndFromEvent(eventObject);
357
+ }
358
+
359
+ const fnName = from.toLowerCase();
360
+ // TODO: MUDIT: Handle seek here
361
+ if (from === this.States.PAUSED_SEEKING) {
362
+ const seekDuration = timestamp - this.seekStartedAt;
363
+ this.seekStartedAt = null;
364
+
365
+ this.stateMachineCallbacks.playback_seeked(this.seekedFrom, eventObject.currentTime*1000, seekDuration, to);
366
+ logger.log('Seek was ' + seekDuration + 'ms');
367
+ } else if (event === Events.UNLOAD && from === this.States.PLAYING) {
368
+ this.stateMachineCallbacks.playingAndBye(stateDuration, fnName, eventObject);
369
+ } else if (from === this.States.PAUSE && to !== this.States.PAUSED_SEEKING && to !== this.States.PLAYING) {
370
+ this.stateMachineCallbacks.setVideoTimeStartFromEvent(event);
371
+ this.stateMachineCallbacks.pause(stateDuration, fnName, eventObject);
372
+ } else {
373
+ // const callbackFunction = this.stateMachineCallbacks[fnName];
374
+ // if (typeof callbackFunction === 'function') {
375
+ // callbackFunction(stateDuration, fnName, eventObject);
376
+ // } else {
377
+ // logger.error('Could not find callback function for ' + fnName);
378
+ // }
379
+ }
380
+
381
+ // if (eventObject && to !== this.States.PAUSED_SEEKING) {
382
+ // //logger.log('Setting video time start to ' + eventObject.currentTime + ', going to ' + to);
383
+ // this.stateMachineCallbacks.setVideoTimeStartFromEvent(eventObject);
384
+ // }
385
+
386
+ if (event === Events.VIDEO_CHANGE) {
387
+ this.stateMachineCallbacks.videoChange(eventObject);
388
+ } else if (event === Events.AUDIO_CHANGE) {
389
+ this.stateMachineCallbacks.audioChange(eventObject);
390
+ }
391
+ else if (event === Events.MUTE) {
392
+ logger.log('Setting sample to muted');
393
+ this.stateMachineCallbacks.mute(timestamp, eventObject);
394
+ } else if (event === Events.UN_MUTE) {
395
+ logger.log('Setting sample to unmuted');
396
+ this.stateMachineCallbacks.unMute(timestamp, eventObject);
397
+ }
398
+ },
399
+ onseek: (event, from, to, timestamp) => {
400
+ this.seekStartedAt = this.seekStartedAt || timestamp;
401
+ },
402
+ onseeked : (event, from, to, timestamp) => {
403
+ this.seekedTimestamp = timestamp;
404
+ },
405
+ ontimechanged: (event, from, to, timestamp, eventObject) => {
406
+ const stateDuration = timestamp - this.onEnterStateTimestamp;
407
+
408
+ if (stateDuration > HEARTBEAT_THRESHOLD) {
409
+ this.stateMachineCallbacks.setVideoTimeEndFromEvent(eventObject);
410
+
411
+ logger.log('Sending heartbeat');
412
+ this.stateMachineCallbacks.heartbeat(stateDuration, from.toLowerCase(), eventObject);
413
+ this.onEnterStateTimestamp = timestamp;
414
+
415
+ this.stateMachineCallbacks.setVideoTimeStartFromEvent(eventObject);
416
+ this.stateMachineCallbacks.resetSessionExpiry();
417
+ }
418
+ },
419
+ onplayerError: (event, from, to, timestamp, eventObject) => {
420
+ this.stateMachineCallbacks.error(eventObject);
421
+ }
422
+ }
423
+ });
424
+ }
425
+
426
+ callEvent(eventType, eventObject, timestamp) {
427
+ const exec = this.stateMachine[eventType];
428
+ if (exec) {
429
+ exec.call(this.stateMachine, timestamp, eventObject);
430
+ } else {
431
+ logger.log('Ignored Event: ' + eventType);
432
+ }
433
+ }
434
+
435
+ updateMetadata(metadata) {
436
+ this.stateMachineCallbacks.updateSample(metadata);
437
+ }
438
+
439
+ static pad(str, length) {
440
+ const padStr = new Array(length).join(' ');
441
+ return (str + padStr).slice(0, length);
442
+ }
443
+ }