@gumlet/insights-js-core 1.0.3 → 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,299 @@
1
+ import logger from '../utils/Logger';
2
+ import StateMachine from 'javascript-state-machine';
3
+ import Events from '../enums/Events';
4
+
5
+ export class BitmovinAnalyticsStateMachine {
6
+ static PAUSE_SEEK_DELAY = 60;
7
+ static SEEKED_PAUSE_DELAY = 120;
8
+
9
+ constructor(stateMachineCallbacks) {
10
+ this.stateMachineCallbacks = stateMachineCallbacks;
11
+
12
+ this.pausedTimestamp = null;
13
+ this.seekTimestamp = 0;
14
+ this.seekedTimestamp = 0;
15
+ this.seekedTimeout = 0;
16
+ this.onEnterStateTimestamp = 0;
17
+
18
+ this.States = {
19
+ SETUP : 'SETUP',
20
+ STARTUP : 'STARTUP',
21
+ READY : 'READY',
22
+ PLAYING : 'PLAYING',
23
+ REBUFFERING : 'REBUFFERING',
24
+ PAUSE : 'PAUSE',
25
+ QUALITYCHANGE : 'QUALITYCHANGE',
26
+ PAUSED_SEEKING : 'PAUSED_SEEKING',
27
+ PLAY_SEEKING : 'PLAY_SEEKING',
28
+ END_PLAY_SEEKING : 'END_PLAY_SEEKING',
29
+ QUALITYCHANGE_PAUSE: 'QUALITYCHANGE_PAUSE',
30
+ END : 'END',
31
+ ERROR : 'ERROR',
32
+ AD : 'AD',
33
+ MUTING_READY : 'MUTING_READY',
34
+ MUTING_PLAY : 'MUTING_PLAY',
35
+ MUTING_PAUSE : 'MUTING_PAUSE'
36
+ };
37
+
38
+ this.createStateMachine();
39
+ }
40
+
41
+ createStateMachine() {
42
+ this.stateMachine = StateMachine.create({
43
+ initial : this.States.SETUP,
44
+ error: (eventName, from, to, args, errorCode, errorMessage, originalException) => {
45
+ logger.error(errorMessage);
46
+ },
47
+ events : [
48
+ {name: Events.READY, from: [this.States.SETUP, this.States.ERROR], to: this.States.READY},
49
+ {name: Events.PLAY, from: this.States.READY, to: this.States.STARTUP},
50
+
51
+ {name: Events.START_BUFFERING, from: this.States.STARTUP, to: this.States.STARTUP},
52
+ {name: Events.END_BUFFERING, from: this.States.STARTUP, to: this.States.STARTUP},
53
+ {name: Events.TIMECHANGED, from: this.States.STARTUP, to: this.States.PLAYING},
54
+
55
+ {name: Events.TIMECHANGED, from: this.States.PLAYING, to: this.States.PLAYING},
56
+ {name: Events.END_BUFFERING, from: this.States.PLAYING, to: this.States.PLAYING},
57
+ {name: Events.START_BUFFERING, from: this.States.PLAYING, to: this.States.REBUFFERING},
58
+ {name: Events.END_BUFFERING, from: this.States.REBUFFERING, to: this.States.PLAYING},
59
+ {name: Events.TIMECHANGED, from: this.States.REBUFFERING, to: this.States.REBUFFERING},
60
+
61
+ {name: Events.PAUSE, from: this.States.PLAYING, to: this.States.PAUSE},
62
+ {name: Events.PAUSE, from: this.States.REBUFFERING, to: this.States.PAUSE},
63
+ {name: Events.PLAY, from: this.States.PAUSE, to: this.States.PLAYING},
64
+
65
+ {name: Events.VIDEO_CHANGE, from: this.States.PLAYING, to: this.States.QUALITYCHANGE},
66
+ {name: Events.AUDIO_CHANGE, from: this.States.PLAYING, to: this.States.QUALITYCHANGE},
67
+ {name: Events.VIDEO_CHANGE, from: this.States.QUALITYCHANGE, to: this.States.QUALITYCHANGE},
68
+ {name: Events.AUDIO_CHANGE, from: this.States.QUALITYCHANGE, to: this.States.QUALITYCHANGE},
69
+ {name: 'FINISH_QUALITYCHANGE', from: this.States.QUALITYCHANGE, to: this.States.PLAYING},
70
+
71
+ {name: Events.VIDEO_CHANGE, from: this.States.PAUSE, to: this.States.QUALITYCHANGE_PAUSE},
72
+ {name: Events.AUDIO_CHANGE, from: this.States.PAUSE, to: this.States.QUALITYCHANGE_PAUSE},
73
+ {
74
+ name: Events.VIDEO_CHANGE,
75
+ from: this.States.QUALITYCHANGE_PAUSE,
76
+ to : this.States.QUALITYCHANGE_PAUSE
77
+ },
78
+ {
79
+ name: Events.AUDIO_CHANGE,
80
+ from: this.States.QUALITYCHANGE_PAUSE,
81
+ to : this.States.QUALITYCHANGE_PAUSE
82
+ },
83
+ {name: 'FINISH_QUALITYCHANGE_PAUSE', from: this.States.QUALITYCHANGE_PAUSE, to: this.States.PAUSE},
84
+
85
+ {name: Events.SEEK, from: this.States.PAUSE, to: this.States.PAUSED_SEEKING},
86
+ {name: Events.SEEK, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
87
+ {name: Events.AUDIO_CHANGE, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
88
+ {name: Events.VIDEO_CHANGE, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
89
+ {name: Events.START_BUFFERING, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
90
+ {name: Events.END_BUFFERING, from: this.States.PAUSED_SEEKING, to: this.States.PAUSED_SEEKING},
91
+ {name: Events.SEEKED, from: this.States.PAUSED_SEEKING, to: this.States.PAUSE},
92
+ {name: Events.PLAY, from: this.States.PAUSED_SEEKING, to: this.States.PLAYING},
93
+ {name: Events.PAUSE, from: this.States.PAUSED_SEEKING, to: this.States.PAUSE},
94
+
95
+ {name: 'PLAY_SEEK', from: this.States.PAUSE, to: this.States.PLAY_SEEKING},
96
+ {name: 'PLAY_SEEK', from: this.States.PAUSED_SEEKING, to: this.States.PLAY_SEEKING},
97
+ {name: 'PLAY_SEEK', from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
98
+ {name: Events.SEEK, from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
99
+ {name: Events.AUDIO_CHANGE, from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
100
+ {name: Events.VIDEO_CHANGE, from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
101
+ {name: Events.START_BUFFERING, from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
102
+ {name: Events.END_BUFFERING, from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
103
+ {name: Events.SEEKED, from: this.States.PLAY_SEEKING, to: this.States.PLAY_SEEKING},
104
+
105
+ // We are ending the seek
106
+ {name: Events.PLAY, from: this.States.PLAY_SEEKING, to: this.States.END_PLAY_SEEKING},
107
+
108
+ {name: Events.START_BUFFERING, from: this.States.END_PLAY_SEEKING, to: this.States.END_PLAY_SEEKING},
109
+ {name: Events.END_BUFFERING, from: this.States.END_PLAY_SEEKING, to: this.States.END_PLAY_SEEKING},
110
+ {name: Events.SEEKED, from: this.States.END_PLAY_SEEKING, to: this.States.END_PLAY_SEEKING},
111
+ {name: Events.TIMECHANGED, from: this.States.END_PLAY_SEEKING, to: this.States.PLAYING},
112
+
113
+ {name: Events.END, from: this.States.PLAY_SEEKING, to: this.States.END},
114
+ {name: Events.END, from: this.States.PAUSED_SEEKING, to: this.States.END},
115
+ {name: Events.END, from: this.States.PLAYING, to: this.States.END},
116
+ {name: Events.END, from: this.States.PAUSE, to: this.States.END},
117
+ {name: Events.SEEK, from: this.States.END, to: this.States.END},
118
+ {name: Events.SEEKED, from: this.States.END, to: this.States.END},
119
+ {name: Events.TIMECHANGED, from: this.States.END, to: this.States.END},
120
+ {name: Events.END_BUFFERING, from: this.States.END, to: this.States.END},
121
+ {name: Events.START_BUFFERING, from: this.States.END, to: this.States.END},
122
+ {name: Events.END, from: this.States.END, to: this.States.END},
123
+
124
+ {name: Events.PLAY, from: this.States.END, to: this.States.PLAYING},
125
+
126
+ {
127
+ name : Events.ERROR, from: [
128
+ this.States.SETUP,
129
+ this.States.STARTUP,
130
+ this.States.READY,
131
+ this.States.PLAYING,
132
+ this.States.REBUFFERING,
133
+ this.States.PAUSE,
134
+ this.States.QUALITYCHANGE,
135
+ this.States.PAUSED_SEEKING,
136
+ this.States.PLAY_SEEKING,
137
+ this.States.END_PLAY_SEEKING,
138
+ this.States.QUALITYCHANGE_PAUSE,
139
+ 'FINISH_PLAY_SEEKING',
140
+ 'PLAY_SEEK',
141
+ 'FINISH_QUALITYCHANGE_PAUSE',
142
+ 'FINISH_QUALITYCHANGE',
143
+ this.States.END,
144
+ this.States.ERROR], to: this.States.ERROR
145
+ },
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.States.PLAYING, this.States.PAUSE], 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
+ callbacks: {
168
+ onpause : (event, from, to, timestamp) => {
169
+ if (from === this.States.PLAYING) {
170
+ this.pausedTimestamp = timestamp;
171
+ }
172
+ },
173
+ onbeforeevent: (event, from, to, timestamp, eventObject) => {
174
+ if (event === Events.SEEK && from === this.States.PAUSE) {
175
+ if (timestamp - this.pausedTimestamp < BitmovinAnalyticsStateMachine.PAUSE_SEEK_DELAY) {
176
+ this.stateMachine.PLAY_SEEK(timestamp);
177
+ return false;
178
+ }
179
+ }
180
+ if (event === Events.SEEK) {
181
+ clearTimeout(this.seekedTimeout);
182
+ }
183
+
184
+ if (event === Events.SEEKED && from === this.States.PAUSED_SEEKING) {
185
+ this.seekedTimestamp = timestamp;
186
+ this.seekedTimeout = setTimeout(() => {
187
+ this.stateMachine.pause(timestamp, eventObject);
188
+ }, BitmovinAnalyticsStateMachine.SEEKED_PAUSE_DELAY);
189
+ return false;
190
+ }
191
+ },
192
+ onafterevent : (event, from, to, timestamp) => {
193
+ logger.log(BitmovinAnalyticsStateMachine.pad(timestamp, 20) + 'EVENT: ' + BitmovinAnalyticsStateMachine.pad(event, 20) + ' from ' + BitmovinAnalyticsStateMachine.pad(from, 14) + '-> ' + BitmovinAnalyticsStateMachine.pad(to, 14));
194
+ if (to === this.States.QUALITYCHANGE_PAUSE) {
195
+ this.stateMachine.FINISH_QUALITYCHANGE_PAUSE(timestamp);
196
+ }
197
+ if (to === this.States.QUALITYCHANGE) {
198
+ this.stateMachine.FINISH_QUALITYCHANGE(timestamp);
199
+ }
200
+ if (to === this.States.MUTING_READY || to === this.States.MUTING_PLAY || to === this.States.MUTING_PAUSE) {
201
+ this.stateMachine.FINISH_MUTING(timestamp);
202
+ }
203
+ },
204
+ onenterstate : (event, from, to, timestamp, eventObject) => {
205
+ this.onEnterStateTimestamp = timestamp || new Date().getTime();
206
+
207
+ logger.log('Entering State ' + to + ' with ' + event);
208
+ if (eventObject && to !== this.States.PAUSED_SEEKING) {
209
+ this.stateMachineCallbacks.setVideoTimeStartFromEvent(eventObject);
210
+ }
211
+ },
212
+ onleavestate : (event, from, to, timestamp, eventObject) => {
213
+ if (!timestamp) {
214
+ return;
215
+ }
216
+
217
+ const stateDuration = timestamp - this.onEnterStateTimestamp;
218
+ logger.log('State ' + from + ' was ' + stateDuration + ' ms event:' + event);
219
+
220
+ if (eventObject && to !== this.States.PAUSED_SEEKING) {
221
+ this.stateMachineCallbacks.setVideoTimeEndFromEvent(eventObject);
222
+ }
223
+
224
+ const fnName = from.toLowerCase();
225
+ if (from === this.States.END_PLAY_SEEKING || from === this.States.PAUSED_SEEKING) {
226
+ const seekDuration = this.seekedTimestamp - this.seekTimestamp;
227
+ this.stateMachineCallbacks[fnName](seekDuration, fnName, eventObject);
228
+ logger.log('Seek was ' + seekDuration + 'ms');
229
+ } else if (event === Events.UNLOAD && from === this.States.PLAYING) {
230
+ this.stateMachineCallbacks.playingAndBye(stateDuration, fnName, eventObject);
231
+ } else if (from === this.States.PAUSE && to !== this.States.PAUSED_SEEKING) {
232
+ this.stateMachineCallbacks.setVideoTimeStartFromEvent(event);
233
+ this.stateMachineCallbacks.pause(stateDuration, fnName, eventObject);
234
+ } else {
235
+ const callbackFunction = this.stateMachineCallbacks[fnName];
236
+ if (typeof callbackFunction === 'function') {
237
+ callbackFunction(stateDuration, fnName, eventObject);
238
+ } else {
239
+ logger.error('Could not find callback function for ' + fnName);
240
+ }
241
+ }
242
+
243
+ if (eventObject && to !== this.States.PAUSED_SEEKING) {
244
+ this.stateMachineCallbacks.setVideoTimeStartFromEvent(eventObject);
245
+ }
246
+
247
+ if (event === Events.VIDEO_CHANGE) {
248
+ this.stateMachineCallbacks.videoChange(eventObject);
249
+ } else if (event === Events.AUDIO_CHANGE) {
250
+ this.stateMachineCallbacks.audioChange(eventObject);
251
+ } else if (event === Events.MUTE) {
252
+ logger.log('Setting sample to muted');
253
+ this.stateMachineCallbacks.mute();
254
+ } else if (event === Events.UN_MUTE) {
255
+ logger.log('Setting sample to unmuted');
256
+ this.stateMachineCallbacks.unMute();
257
+ }
258
+ },
259
+ onseek : (event, from, to, timestamp) => {
260
+ this.seekTimestamp = timestamp;
261
+ },
262
+ onseeked : (event, from, to, timestamp) => {
263
+ this.seekedTimestamp = timestamp;
264
+ },
265
+ ontimechanged: (event, from, to, timestamp, eventObject) => {
266
+ const stateDuration = timestamp - this.onEnterStateTimestamp;
267
+
268
+ if (stateDuration > 59700) {
269
+ this.stateMachineCallbacks.setVideoTimeEndFromEvent(eventObject);
270
+
271
+ logger.log('Sending heartbeat');
272
+ this.stateMachineCallbacks.heartbeat(stateDuration, from.toLowerCase(), eventObject);
273
+ this.onEnterStateTimestamp = timestamp;
274
+
275
+ this.stateMachineCallbacks.setVideoTimeStartFromEvent(eventObject);
276
+ }
277
+ },
278
+ onplayerError: (event, from, to, timestamp, eventObject) => {
279
+ this.stateMachineCallbacks.error(eventObject);
280
+ }
281
+ }
282
+ });
283
+ }
284
+
285
+ callEvent(eventType, eventObject, timestamp) {
286
+ const exec = this.stateMachine[eventType];
287
+
288
+ if (exec) {
289
+ exec.call(this.stateMachine, timestamp, eventObject);
290
+ } else {
291
+ logger.log('Ignored Event: ' + eventType);
292
+ }
293
+ }
294
+
295
+ static pad(str, length) {
296
+ const padStr = new Array(length).join(' ');
297
+ return (str + padStr).slice(0, length);
298
+ }
299
+ }