@gumlet/insights-js-core 1.0.1 → 1.1.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.
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 +1357 -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,471 @@
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 Bitmovin7AnalyticsStateMachine {
7
+ static PAUSE_SEEK_DELAY = 200;
8
+ static SEEKED_PAUSE_DELAY = 300;
9
+
10
+ constructor(stateMachineCallbacks, opts = {}) {
11
+ this.stateMachineCallbacks = stateMachineCallbacks;
12
+
13
+ this.pausedTimestamp = null;
14
+ this.seekTimestamp = 0;
15
+ this.seekedTimestamp = 0;
16
+ this.seekedTimeout = 0;
17
+ this.seekedFrom = 0;
18
+ this.onEnterStateTimestamp = 0;
19
+ this.lastPlayHeadDuration = 0;
20
+
21
+ this.States = {
22
+ SETUP : 'SETUP',
23
+ STARTUP : 'STARTUP',
24
+ READY : 'READY',
25
+ PLAYING : 'PLAYING',
26
+ REBUFFERING : 'REBUFFERING',
27
+ PAUSE : 'PAUSE',
28
+ QUALITYCHANGE : 'QUALITYCHANGE',
29
+ PAUSED_SEEKING : 'PAUSED_SEEKING',
30
+ PLAY_SEEKING : 'PLAY_SEEKING',
31
+ END_PLAY_SEEKING : 'END_PLAY_SEEKING',
32
+ QUALITYCHANGE_PAUSE : 'QUALITYCHANGE_PAUSE',
33
+ QUALITYCHANGE_REBUFFERING: 'QUALITYCHANGE_REBUFFERING',
34
+ END : 'END',
35
+ ERROR : 'ERROR',
36
+ AD : 'AD',
37
+ MUTING_READY : 'MUTING_READY',
38
+ MUTING_PLAY : 'MUTING_PLAY',
39
+ MUTING_PAUSE : 'MUTING_PAUSE',
40
+ CASTING : 'CASTING',
41
+ SOURCE_CHANGING : 'SOURCE_CHANGING'
42
+ };
43
+
44
+ this.createStateMachine(opts);
45
+ }
46
+
47
+ getAllStates() {
48
+ return [
49
+ ...Object.keys(this.States).map(key => this.States[key]),
50
+ 'FINISH_PLAY_SEEKING',
51
+ 'PLAY_SEEK',
52
+ 'FINISH_QUALITYCHANGE_PAUSE',
53
+ 'FINISH_QUALITYCHANGE',
54
+ 'FINISH_QUALITYCHANGE_REBUFFERING'];
55
+ }
56
+
57
+ createStateMachine(opts = {}) {
58
+ this.stateMachine = StateMachine.create({
59
+ initial : this.States.SETUP,
60
+ error: (eventName, from, to, args, errorCode, errorMessage) => {
61
+ logger.error('Error in statemachine: ' + errorMessage);
62
+ },
63
+ events : [
64
+ {name: Events.READY, from: [this.States.SETUP, this.States.ERROR], to: this.States.READY},
65
+ {name: Events.PLAY, from: this.States.READY, to: this.States.STARTUP},
66
+
67
+ {name: Events.START_BUFFERING, from: this.States.STARTUP, to: this.States.STARTUP},
68
+ {name: Events.END_BUFFERING, from: this.States.STARTUP, to: this.States.STARTUP},
69
+ {name: Events.VIDEO_CHANGE, from: this.States.STARTUP, to: this.States.STARTUP},
70
+ {name: Events.AUDIO_CHANGE, from: this.States.STARTUP, to: this.States.STARTUP},
71
+ // {name: Events.PLAYBACK_PLAYING, from: this.States.STARTUP, to: this.States.PLAYING},
72
+ {name: Events.TIMECHANGED, from: this.States.STARTUP, to: this.States.PLAYING},
73
+
74
+ {name: Events.TIMECHANGED, from: this.States.PLAYING, to: this.States.PLAYING},
75
+ {name: Events.END_BUFFERING, from: this.States.PLAYING, to: this.States.PLAYING},
76
+ {name: Events.START_BUFFERING, from: this.States.PLAYING, to: this.States.REBUFFERING},
77
+ {name: Events.END_BUFFERING, from: this.States.REBUFFERING, to: this.States.PLAYING},
78
+ {name: Events.TIMECHANGED, from: this.States.REBUFFERING, to: this.States.REBUFFERING},
79
+
80
+ {name: Events.PAUSE, from: this.States.PLAYING, to: this.States.PAUSE},
81
+ {name: Events.PAUSE, from: this.States.REBUFFERING, to: this.States.PAUSE},
82
+ {name: Events.PLAY, from: this.States.PAUSE, to: this.States.PLAYING},
83
+
84
+ {name: Events.VIDEO_CHANGE, from: this.States.PLAYING, to: this.States.QUALITYCHANGE},
85
+ {name: Events.AUDIO_CHANGE, from: this.States.PLAYING, to: this.States.QUALITYCHANGE},
86
+ {name: Events.VIDEO_CHANGE, from: this.States.QUALITYCHANGE, to: this.States.QUALITYCHANGE},
87
+ {name: Events.AUDIO_CHANGE, from: this.States.QUALITYCHANGE, to: this.States.QUALITYCHANGE},
88
+ {name: 'FINISH_QUALITYCHANGE', from: this.States.QUALITYCHANGE, to: this.States.PLAYING},
89
+
90
+ {name: Events.VIDEO_CHANGE, from: this.States.PAUSE, to: this.States.QUALITYCHANGE_PAUSE},
91
+ {name: Events.AUDIO_CHANGE, from: this.States.PAUSE, to: this.States.QUALITYCHANGE_PAUSE},
92
+ {
93
+ name: Events.VIDEO_CHANGE,
94
+ from: this.States.QUALITYCHANGE_PAUSE,
95
+ to : this.States.QUALITYCHANGE_PAUSE
96
+ },
97
+ {
98
+ name: Events.AUDIO_CHANGE,
99
+ from: this.States.QUALITYCHANGE_PAUSE,
100
+ to : this.States.QUALITYCHANGE_PAUSE
101
+ },
102
+ {name: 'FINISH_QUALITYCHANGE_PAUSE', from: this.States.QUALITYCHANGE_PAUSE, to: this.States.PAUSE},
103
+
104
+ {name: Events.SEEK, from: this.States.PAUSE, to: this.States.PAUSED_SEEKING},
105
+ {name: Events.SEEK, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
106
+ {name: Events.AUDIO_CHANGE, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
107
+ {name: Events.VIDEO_CHANGE, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
108
+ {name: Events.START_BUFFERING, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
109
+ {name: Events.END_BUFFERING, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
110
+ {name: Events.SEEKED, from: this.States.PAUSED_SEEKING, to: this.States.PAUSE},
111
+ {name: Events.PLAY, from: this.States.PAUSED_SEEKING, to: this.States.PLAYING},
112
+ {name: Events.PAUSE, from: this.States.PAUSED_SEEKING, to: this.States.PAUSE},
113
+
114
+ {name: 'PLAY_SEEK', from: this.States.PAUSE, to: this.States.PLAY_SEEKING},
115
+ {name: 'PLAY_SEEK', from: this.States.PAUSED_SEEKING, to: this.States.PLAY_SEEKING},
116
+ {name: 'PLAY_SEEK', from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
117
+ {name: Events.SEEK, from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
118
+ {name: Events.AUDIO_CHANGE, from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
119
+ {name: Events.VIDEO_CHANGE, from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
120
+ {name: Events.START_BUFFERING, from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
121
+ {name: Events.END_BUFFERING, from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
122
+ {name: Events.SEEKED, from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
123
+
124
+ // We are ending the seek
125
+ {name: Events.PLAY, from: this.States.PLAY_SEEKING, to: this.States.END_PLAY_SEEKING},
126
+
127
+ {name: Events.START_BUFFERING, from: this.States.END_PLAY_SEEKING, to: this.States.END_PLAY_SEEKING},
128
+ {name: Events.END_BUFFERING, from: this.States.END_PLAY_SEEKING, to: this.States.END_PLAY_SEEKING},
129
+ {name: Events.SEEKED, from: this.States.END_PLAY_SEEKING, to: this.States.END_PLAY_SEEKING},
130
+ {name: Events.TIMECHANGED, from: this.States.END_PLAY_SEEKING, to: this.States.PLAYING},
131
+
132
+ {name: Events.END, from: this.States.PLAY_SEEKING, to: this.States.END},
133
+ {name: Events.END, from: this.States.PAUSED_SEEKING, to: this.States.END},
134
+ {name: Events.END, from: this.States.PLAYING, to: this.States.END},
135
+ {name: Events.END, from: this.States.PAUSE, to: this.States.END},
136
+ {name: Events.SEEK, from: this.States.END, to: this.States.END},
137
+ {name: Events.SEEKED, from: this.States.END, to: this.States.END},
138
+ {name: Events.TIMECHANGED, from: this.States.END, to: this.States.END},
139
+ {name: Events.END_BUFFERING, from: this.States.END, to: this.States.END},
140
+ {name: Events.START_BUFFERING, from: this.States.END, to: this.States.END},
141
+ {name: Events.END, from: this.States.END, to: this.States.END},
142
+
143
+ {name: Events.PLAY, from: this.States.END, to: this.States.PLAYING},
144
+
145
+ {name: Events.ERROR, from: this.getAllStates(), to: this.States.ERROR},
146
+
147
+ {name: Events.SEEK, from: this.States.END_PLAY_SEEKING, to: this.States.PLAY_SEEKING},
148
+ {name: 'FINISH_PLAY_SEEKING', from: this.States.END_PLAY_SEEKING, to: this.States.PLAYING},
149
+
150
+ {name: Events.UNLOAD, from: this.getAllStates(), to: this.States.END},
151
+
152
+ {name: Events.START_AD, from: this.States.PLAYING, to: this.States.AD},
153
+ {name: Events.END_AD, from: this.States.AD, to: this.States.PLAYING},
154
+
155
+ {name: Events.MUTE, from: this.States.READY, to: this.States.MUTING_READY},
156
+ {name: Events.UN_MUTE, from: this.States.READY, to: this.States.MUTING_READY},
157
+ {name: 'FINISH_MUTING', from: this.States.MUTING_READY, to: this.States.READY},
158
+
159
+ {name: Events.MUTE, from: this.States.PLAYING, to: this.States.MUTING_PLAY},
160
+ {name: Events.UN_MUTE, from: this.States.PLAYING, to: this.States.MUTING_PLAY},
161
+ {name: 'FINISH_MUTING', from: this.States.MUTING_PLAY, to: this.States.PLAYING},
162
+
163
+ {name: Events.MUTE, from: this.States.PAUSE, to: this.States.MUTING_PAUSE},
164
+ {name: Events.UN_MUTE, from: this.States.PAUSE, to: this.States.MUTING_PAUSE},
165
+ {name: 'FINISH_MUTING', from: this.States.MUTING_PAUSE, to: this.States.PAUSE},
166
+
167
+ {name: Events.START_CAST, from: [this.States.READY, this.States.PAUSE], to: this.States.CASTING},
168
+ {name: Events.PAUSE, from: this.States.CASTING, to: this.States.CASTING},
169
+ {name: Events.PLAY, from: this.States.CASTING, to: this.States.CASTING},
170
+ {name: Events.TIMECHANGED, from: this.States.CASTING, to: this.States.CASTING},
171
+ {name: Events.MUTE, from: this.States.CASTING, to: this.States.CASTING},
172
+ {name: Events.SEEK, from: this.States.CASTING, to: this.States.CASTING},
173
+ {name: Events.SEEKED, from: this.States.CASTING, to: this.States.CASTING},
174
+ {name: Events.END_CAST, from: this.States.CASTING, to: this.States.READY},
175
+
176
+ {name: Events.SEEK, from: this.States.READY, to: this.States.READY},
177
+ {name: Events.SEEKED, from: this.States.READY, to: this.States.READY},
178
+ {name: Events.SEEKED, from: this.States.STARTUP, to: this.States.STARTUP},
179
+
180
+ {name: Events.SOURCE_UNLOADED, from: this.getAllStates(), to: this.States.SOURCE_CHANGING },
181
+
182
+ {name: Events.READY, from: this.States.SOURCE_CHANGING, to: this.States.READY },
183
+
184
+ {name: Events.SOURCE_LOADED, from: this.States.SETUP, to: this.States.SETUP},
185
+ {name: Events.SOURCE_LOADED, from: this.States.READY, to: this.States.READY},
186
+
187
+ {name: Events.VIDEO_CHANGE, from: this.States.REBUFFERING, to: this.States.QUALITYCHANGE_REBUFFERING},
188
+ {name: Events.AUDIO_CHANGE, from: this.States.REBUFFERING, to: this.States.QUALITYCHANGE_REBUFFERING},
189
+ {name: Events.VIDEO_CHANGE, from: this.States.QUALITYCHANGE_REBUFFERING, to: this.States.QUALITYCHANGE_REBUFFERING},
190
+ {name: Events.AUDIO_CHANGE, from: this.States.QUALITYCHANGE_REBUFFERING, to: this.States.QUALITYCHANGE_REBUFFERING},
191
+ {name: 'FINISH_QUALITYCHANGE_REBUFFERING', from: this.States.QUALITYCHANGE_REBUFFERING, to: this.States.REBUFFERING},
192
+ ],
193
+ callbacks: {
194
+ onpause : (event, from, to, timestamp) => {
195
+ if (from === this.States.PLAYING) {
196
+ this.pausedTimestamp = timestamp;
197
+ }
198
+ },
199
+ onbeforeevent: (event, from, to, timestamp, eventObject) => {
200
+ if (event === Events.SEEK && from === this.States.PAUSE) {
201
+ this.seekedFrom = this.lastPlayHeadDuration;
202
+ this.seekTimestamp = timestamp;
203
+ if (timestamp - this.pausedTimestamp < Bitmovin7AnalyticsStateMachine.PAUSE_SEEK_DELAY) {
204
+ this.stateMachine.PLAY_SEEK(timestamp);
205
+ return false;
206
+ }
207
+ }
208
+
209
+ if (event === Events.SEEK) {
210
+ clearTimeout(this.seekedTimeout);
211
+ }
212
+
213
+
214
+ if (event === Events.SOURCE_LOADED) {
215
+ // event = sourceLoaded
216
+ // from = Ready/Setup
217
+ // to = Ready/Setup i.e. current event
218
+ // timestamp is current Timestamp
219
+ // eventObject = {} event obbject is there
220
+
221
+ this.stateMachineCallbacks.loaded(timestamp, this.States.READY, eventObject);
222
+ return;
223
+ }
224
+
225
+ if (event === Events.SEEKED && from === this.States.PAUSED_SEEKING) {
226
+ this.seekedTimestamp = timestamp;
227
+ this.seekedTimeout = setTimeout(() => {
228
+ this.stateMachine.pause(timestamp, eventObject);
229
+ }, Bitmovin7AnalyticsStateMachine.SEEKED_PAUSE_DELAY);
230
+ return false;
231
+ }
232
+
233
+ if (from === this.States.REBUFFERING && to === this.States.QUALITYCHANGE_REBUFFERING) {
234
+ return false;
235
+ }
236
+
237
+ if (eventObject) {
238
+ this.lastPlayHeadDuration = eventObject.currentTime*1000;
239
+ }
240
+
241
+ },
242
+ onafterevent : (event, from, to, timestamp) => {
243
+ // logger.log(Bitmovin7AnalyticsStateMachine.pad(timestamp, 20) + 'EVENT: ' + Bitmovin7AnalyticsStateMachine.pad(event, 20) + ' from ' + Bitmovin7AnalyticsStateMachine.pad(from, 14) + '-> ' + Bitmovin7AnalyticsStateMachine.pad(to, 14));
244
+ if (to === this.States.QUALITYCHANGE_PAUSE) {
245
+ this.stateMachine.FINISH_QUALITYCHANGE_PAUSE(timestamp);
246
+ }
247
+ if (to === this.States.QUALITYCHANGE) {
248
+ this.stateMachine.FINISH_QUALITYCHANGE(timestamp);
249
+ }
250
+ if (to === this.States.QUALITYCHANGE_REBUFFERING) {
251
+ this.stateMachine.FINISH_QUALITYCHANGE_REBUFFERING(timestamp);
252
+ }
253
+ if (to === this.States.MUTING_READY || to === this.States.MUTING_PLAY || to === this.States.MUTING_PAUSE) {
254
+ this.stateMachine.FINISH_MUTING(timestamp);
255
+ }
256
+ },
257
+ onenterstate : (event, from, to, timestamp, eventObject) => {
258
+ if (to === this.States.SETUP) {
259
+ // event = startup
260
+ // from = none as it is the initial/first event
261
+ // to = SETUP
262
+ // timestamp is undefined
263
+ // eventObject is undefined
264
+ this.stateMachineCallbacks.setup(timestamp, this.States.SETUP, eventObject);
265
+ }
266
+ else if (to === this.States.READY) {
267
+ // event = ready
268
+ // from = SETUP
269
+ // to = Ready i.e. current event
270
+ // timestamp is current Timestamp
271
+ // eventObject = {} event obbject is there
272
+ eventObject.playerSoftware = "Bitmovin"
273
+ this.stateMachineCallbacks.ready(timestamp, this.States.READY, eventObject);
274
+ }
275
+ else if (event === "play" && to === this.States.STARTUP) {
276
+ // Video is played for the first time after player iinitialisation
277
+
278
+ // event = play
279
+ // from = READY
280
+ // to = STARTUP i.e. current event
281
+ // timestamp is current Timestamp
282
+ // eventObject = {} event obbject is there
283
+
284
+ this.stateMachineCallbacks.first_play(timestamp, this.States.PLAY, eventObject);
285
+ }
286
+ else if (event === "play" && from === this.States.PAUSE) {
287
+ // Video is played after being paused
288
+
289
+ // event = play
290
+ // from = PAUSE
291
+ // to = PLAYING i.e. current event
292
+ // timestamp is current Timestamp
293
+ // eventObject = {} event obbject is there
294
+
295
+ this.stateMachineCallbacks.play(timestamp, this.States.PLAY, eventObject);
296
+ this.stateMachineCallbacks.playing(timestamp, this.States.PLAYING, eventObject);
297
+ }
298
+ else if (event === "timechanged" && from === this.States.STARTUP && to === this.States.PLAYING) {
299
+ // Video has started playing for the first time after player initialisation
300
+
301
+ // event = timechanged
302
+ // from = STARTUP
303
+ // to = PLAYING i.e. current event
304
+ // timestamp is current Timestamp
305
+ // eventObject = {} event obbject is there
306
+
307
+ this.stateMachineCallbacks.playing(timestamp, this.States.PLAYING, eventObject);
308
+ this.stateMachineCallbacks.playback_started(eventObject);
309
+ }
310
+ else if (to === this.States.PAUSE && from === this.States.PLAYING) {
311
+ // Only fire pause event if the the video was playing
312
+
313
+ // event = pause
314
+ // from = PLAYING
315
+ // to = PAUSE i.e. current event
316
+ // timestamp is current Timestamp
317
+ // eventObject = {} event obbject is there
318
+ this.stateMachineCallbacks.pause(timestamp, this.States.PAUSE, eventObject);
319
+ }
320
+ else if (to === this.States.END) {
321
+ // event = end
322
+ // from = PLAYING
323
+ // to = END i.e. current event
324
+ // timestamp is current Timestamp
325
+ // eventObject = {} event obbject is there
326
+
327
+ this.stateMachineCallbacks.end(timestamp, this.States.END, eventObject);
328
+ }
329
+ else if (to === this.States.END) {
330
+ // event = mute
331
+ // from = PLAYING/PAUSE etc
332
+ // to = MUTING_PAUSE/etc i.e. current event
333
+ // timestamp is current Timestamp
334
+ // eventObject = {} event obbject is there
335
+
336
+ this.stateMachineCallbacks.mute(timestamp, eventObject);
337
+ }
338
+ else if (event === Events.START_BUFFERING) {
339
+ // event = startBuffering
340
+ // from = PLAYING etc
341
+ // to = REBUFFERING/etc i.e. current event
342
+ // timestamp is current Timestamp
343
+ // eventObject = {} event obbject is there
344
+
345
+ this.stateMachineCallbacks.start_rebuffer(timestamp, this.States.REBUFFERING, eventObject);
346
+ }
347
+ else if (event === Events.END_BUFFERING) {
348
+ // event = endBuffering
349
+ // from = REBUFFERING
350
+ // to = PLAYING/etc i.e. current event
351
+ // timestamp is current Timestamp
352
+ // eventObject = {} event obbject is there
353
+
354
+ this.stateMachineCallbacks.end_rebuffer(timestamp, this.States.REBUFFERING, eventObject);
355
+ }
356
+
357
+ if (from === 'none' && opts.starttime) {
358
+ this.onEnterStateTimestamp = opts.starttime;
359
+ } else {
360
+ this.onEnterStateTimestamp = timestamp || new Date().getTime();
361
+ }
362
+
363
+ // logger.log('Entering State ' + to + ' with ' + event);
364
+ if (eventObject && to !== this.States.PAUSED_SEEKING && to !== this.States.PLAY_SEEKING && to !== this.States.END_PLAY_SEEKING) {
365
+ // logger.log('Setting video time start to ' + eventObject.currentTime + ', going to ' + to);
366
+ this.stateMachineCallbacks.setVideoTimeStartFromEvent(eventObject);
367
+ }
368
+
369
+ if (event === 'PLAY_SEEK' && to === this.States.PLAY_SEEKING && to !== this.States.PLAY_SEEKING && to !== this.States.END_PLAY_SEEKING) {
370
+ this.seekTimestamp = this.onEnterStateTimestamp;
371
+ }
372
+ //
373
+ // if (event === Events.START_CAST && to === this.States.CASTING) {
374
+ // this.stateMachineCallbacks.startCasting(timestamp, eventObject);
375
+ // }
376
+ },
377
+ onleavestate : (event, from, to, timestamp, eventObject) => {
378
+ if (!timestamp) {
379
+ return;
380
+ }
381
+
382
+ const stateDuration = timestamp - this.onEnterStateTimestamp;
383
+ // logger.log('State ' + from + ' was ' + stateDuration + ' ms event:' + event);
384
+ //
385
+ if (eventObject && to !== this.States.PAUSED_SEEKING && to !== this.States.PLAY_SEEKING && to !== this.States.END_PLAY_SEEKING) {
386
+ logger.log('Setting video time end to ' + eventObject.currentTime + ', going to ' + to);
387
+ this.stateMachineCallbacks.setVideoTimeEndFromEvent(eventObject);
388
+ }
389
+
390
+ if (event === 'PLAY_SEEK' && from === this.States.PAUSE) {
391
+ return true;
392
+ }
393
+
394
+ const fnName = from.toLowerCase();
395
+ if (from === this.States.END_PLAY_SEEKING || from === this.States.PAUSED_SEEKING) {
396
+ const seekDuration = this.seekedTimestamp - this.seekTimestamp;
397
+ this.stateMachineCallbacks.playback_seeked(this.seekedFrom, eventObject.currentTime*1000, seekDuration, to);
398
+ logger.log('Seek was ' + seekDuration + 'ms');
399
+ }
400
+ else if (event === Events.UNLOAD && from === this.States.PLAYING) {
401
+ this.stateMachineCallbacks.playingAndBye(stateDuration, fnName, eventObject);
402
+ } else if (from === this.States.PAUSE && to !== this.States.PAUSED_SEEKING) {
403
+ this.stateMachineCallbacks.setVideoTimeStartFromEvent(event);
404
+ // this.stateMachineCallbacks.pause(stateDuration, fnName, eventObject);
405
+ } else {
406
+ // const callbackFunction = this.stateMachineCallbacks[fnName];
407
+ // if (typeof callbackFunction === 'function') {
408
+ // callbackFunction(stateDuration, fnName, eventObject);
409
+ // } else {
410
+ // logger.error('Could not find callback function for ' + fnName);
411
+ // }
412
+ }
413
+ //
414
+ // if (eventObject && to !== this.States.PAUSED_SEEKING && to !== this.States.PLAY_SEEKING && to !== this.States.END_PLAY_SEEKING) {
415
+ // logger.log('Setting video time start to ' + eventObject.currentTime + ', going to ' + to);
416
+ // this.stateMachineCallbacks.setVideoTimeStartFromEvent(eventObject);
417
+ // }
418
+ //
419
+
420
+ if (event === Events.VIDEO_CHANGE) {
421
+ this.stateMachineCallbacks.videoChange(eventObject);
422
+ } else if (event === Events.AUDIO_CHANGE) {
423
+ this.stateMachineCallbacks.audioChange(eventObject);
424
+ } else if (event === Events.MUTE) {
425
+ logger.log('Setting sample to muted');
426
+ this.stateMachineCallbacks.mute();
427
+ } else if (event === Events.UN_MUTE) {
428
+ logger.log('Setting sample to unmuted');
429
+ this.stateMachineCallbacks.unMute();
430
+ }
431
+ },
432
+ onseek : (event, from, to, timestamp) => {
433
+ this.seekTimestamp = timestamp;
434
+ },
435
+ onseeked : (event, from, to, timestamp) => {
436
+ this.seekedTimestamp = timestamp;
437
+ },
438
+ ontimechanged: (event, from, to, timestamp, eventObject) => {
439
+ const stateDuration = timestamp - this.onEnterStateTimestamp;
440
+ if (stateDuration > {HEARTBEAT_THRESHOLD}) {
441
+ this.stateMachineCallbacks.setVideoTimeEndFromEvent(eventObject);
442
+
443
+ logger.log('Sending heartbeat');
444
+ this.stateMachineCallbacks.heartbeat(stateDuration, from.toLowerCase(), eventObject);
445
+ this.onEnterStateTimestamp = timestamp;
446
+
447
+ this.stateMachineCallbacks.setVideoTimeStartFromEvent(eventObject);
448
+ }
449
+ },
450
+ onplayerError: (event, from, to, timestamp, eventObject) => {
451
+ this.stateMachineCallbacks.error(eventObject);
452
+ }
453
+ }
454
+ });
455
+ }
456
+
457
+ callEvent(eventType, eventObject, timestamp) {
458
+ const exec = this.stateMachine[eventType];
459
+
460
+ if (exec) {
461
+ exec.call(this.stateMachine, timestamp, eventObject);
462
+ } else {
463
+ logger.log('Ignored Event: ' + eventType);
464
+ }
465
+ }
466
+
467
+ static pad(str, length) {
468
+ const padStr = new Array(length).join(' ');
469
+ return (str + padStr).slice(0, length);
470
+ }
471
+ }