@newrelic/video-core 3.1.1 → 3.2.0-beta-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.
- package/CHANGELOG.md +7 -2
- package/README.md +15 -2
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/index.js.LICENSE.txt +1 -1
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/index.js +3 -1
- package/dist/esm/index.js.LICENSE.txt +1 -1
- package/dist/esm/index.js.map +1 -0
- package/dist/umd/nrvideo.min.js +3 -1
- package/dist/umd/nrvideo.min.js.LICENSE.txt +1 -1
- package/dist/umd/nrvideo.min.js.map +1 -0
- package/package.json +5 -5
- package/src/agent.js +6 -0
- package/src/authConfiguration.js +138 -0
- package/src/chrono.js +78 -0
- package/src/constants.js +43 -0
- package/src/core.js +100 -0
- package/src/emitter.js +81 -0
- package/src/eventAggregator.js +66 -0
- package/src/harvester.js +171 -0
- package/src/index.js +22 -0
- package/src/log.js +323 -0
- package/src/recordEvent.js +68 -0
- package/src/tracker.js +281 -0
- package/src/utils.js +101 -0
- package/src/videotracker.js +1060 -0
- package/src/videotrackerstate.js +574 -0
|
@@ -0,0 +1,1060 @@
|
|
|
1
|
+
import Log from "./log";
|
|
2
|
+
import Tracker from "./tracker";
|
|
3
|
+
import TrackerState from "./videotrackerstate";
|
|
4
|
+
import pkg from "../package.json";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Base video tracker class provides extensible tracking over video elements. See {@link Tracker}.
|
|
8
|
+
* Extend this class to create your own video tracker class. Override getter methods and
|
|
9
|
+
* registerListeners/unregisterListeners to provide full integration with your video experience.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* Tracker instances should be added to Core library to start sending data:
|
|
13
|
+
* nrvideo.Core.addTracker(new Tracker())
|
|
14
|
+
*
|
|
15
|
+
* @extends Tracker
|
|
16
|
+
*/
|
|
17
|
+
class VideoTracker extends Tracker {
|
|
18
|
+
/**
|
|
19
|
+
* Constructor, receives player and options.
|
|
20
|
+
* Lifecycle: constructor > {@link setOptions} > {@link setPlayer} > {@link registerListeners}.
|
|
21
|
+
*
|
|
22
|
+
* @param {Object} [player] Player to track. See {@link setPlayer}.
|
|
23
|
+
* @param {Object} [options] Options for the tracker. See {@link setOptions}.
|
|
24
|
+
*/
|
|
25
|
+
constructor(player, options) {
|
|
26
|
+
super();
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* TrackerState instance. Stores the state of the view. Tracker will automatically update the
|
|
30
|
+
* state of its instance, so there's no need to modify/interact with it manually.
|
|
31
|
+
* @type TrackerState
|
|
32
|
+
*/
|
|
33
|
+
this.state = new TrackerState();
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Another Tracker instance to track ads.
|
|
37
|
+
* @type Tracker
|
|
38
|
+
*/
|
|
39
|
+
this.adsTracker = null;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Last bufferType value.
|
|
43
|
+
* @private
|
|
44
|
+
*/
|
|
45
|
+
this._lastBufferType = null;
|
|
46
|
+
this._userId = null;
|
|
47
|
+
|
|
48
|
+
options = options || {};
|
|
49
|
+
this.setOptions(options);
|
|
50
|
+
if (player) this.setPlayer(player, options.tag);
|
|
51
|
+
|
|
52
|
+
Log.notice(
|
|
53
|
+
"Tracker " +
|
|
54
|
+
this.getTrackerName() +
|
|
55
|
+
" v" +
|
|
56
|
+
this.getTrackerVersion() +
|
|
57
|
+
" is ready."
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* user can set the user Id */
|
|
62
|
+
|
|
63
|
+
setUserId(userId) {
|
|
64
|
+
this._userId = userId;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Set options for the Tracker.
|
|
69
|
+
*
|
|
70
|
+
* @param {Object} [options] Options for the tracker.
|
|
71
|
+
* @param {Boolean} [options.isAd] True if the tracker is tracking ads. See {@link setIsAd}.
|
|
72
|
+
* @param {number} [options.heartbeat] Set time between heartbeats. See {@link heartbeat}.
|
|
73
|
+
* @param {Object} [options.customData] Set custom data. See {@link customData}.
|
|
74
|
+
* @param {Tracker} [options.parentTracker] Set parent tracker. See {@link parentTracker}.
|
|
75
|
+
* @param {Tracker} [options.adsTracker] Set ads tracker. See {@link adsTracker}.
|
|
76
|
+
* @param {Object} [options.tag] DOM element to track. See {@link setPlayer}.
|
|
77
|
+
*/
|
|
78
|
+
setOptions(options) {
|
|
79
|
+
if (options) {
|
|
80
|
+
if (options.adsTracker) {
|
|
81
|
+
this.setAdsTracker(options.adsTracker);
|
|
82
|
+
}
|
|
83
|
+
if (typeof options.isAd === "boolean") {
|
|
84
|
+
this.setIsAd(options.isAd);
|
|
85
|
+
}
|
|
86
|
+
Tracker.prototype.setOptions.apply(this, arguments);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Set a player and/or a tag. If there was one already defined, it will call dispose() first.
|
|
92
|
+
* Will call this.registerListeners() afterwards.
|
|
93
|
+
*
|
|
94
|
+
* @param {Object|string} player New player to save as this.player. If a string is passed,
|
|
95
|
+
* document.getElementById will be called.
|
|
96
|
+
* @param {DOMObject|string} [tag] Optional DOMElement to save as this.tag. If a string is passed,
|
|
97
|
+
* document.getElementById will be called.
|
|
98
|
+
*/
|
|
99
|
+
|
|
100
|
+
setPlayer(player, tag) {
|
|
101
|
+
if (this.player || this.tag) this.dispose();
|
|
102
|
+
|
|
103
|
+
if (typeof document !== "undefined" && document.getElementById) {
|
|
104
|
+
if (typeof player === "string") player = document.getElementById(player);
|
|
105
|
+
if (typeof tag === "string") tag = document.getElementById(tag);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
tag = tag || player; // if no tag is passed, use player as both.
|
|
109
|
+
|
|
110
|
+
this.player = player;
|
|
111
|
+
this.tag = tag;
|
|
112
|
+
this.registerListeners();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Returns true if the tracker is currently on ads. */
|
|
116
|
+
isAd() {
|
|
117
|
+
return this.state.isAd();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Sets if the tracker is currenlty tracking ads */
|
|
121
|
+
setIsAd(isAd) {
|
|
122
|
+
this.state.setIsAd(isAd);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Use this function to set up a child ad tracker. You will be able to access it using
|
|
127
|
+
* this.adsTracker.
|
|
128
|
+
*
|
|
129
|
+
* @param {Tracker} tracker Ad tracker to add
|
|
130
|
+
*/
|
|
131
|
+
setAdsTracker(tracker) {
|
|
132
|
+
this.disposeAdsTracker(); // dispose current one
|
|
133
|
+
if (tracker) {
|
|
134
|
+
this.adsTracker = tracker;
|
|
135
|
+
this.adsTracker.setIsAd(true);
|
|
136
|
+
this.adsTracker.parentTracker = this;
|
|
137
|
+
this.adsTracker.on("*", funnelAdEvents.bind(this));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Dispose current adsTracker.
|
|
143
|
+
*/
|
|
144
|
+
disposeAdsTracker() {
|
|
145
|
+
if (this.adsTracker) {
|
|
146
|
+
this.adsTracker.off("*", funnelAdEvents);
|
|
147
|
+
this.adsTracker.dispose();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Prepares tracker to dispose. Calls unregisterListener and drops references to player and tag.
|
|
153
|
+
*/
|
|
154
|
+
dispose() {
|
|
155
|
+
this.stopHeartbeat();
|
|
156
|
+
this.disposeAdsTracker();
|
|
157
|
+
this.unregisterListeners();
|
|
158
|
+
this.player = null;
|
|
159
|
+
this.tag = null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Override this method to register listeners to player/tag.
|
|
164
|
+
* @example
|
|
165
|
+
* class SpecificTracker extends Tracker {
|
|
166
|
+
* registerListeners() {
|
|
167
|
+
* this.player.on('play', () => this.playHandler)
|
|
168
|
+
* }
|
|
169
|
+
*
|
|
170
|
+
* playHandler() {
|
|
171
|
+
* this.send(VideoTracker.Events.REQUESTED)
|
|
172
|
+
* }
|
|
173
|
+
* }
|
|
174
|
+
*/
|
|
175
|
+
registerListeners() {}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Override this method to unregister listeners to player/tag created in registerListeners
|
|
179
|
+
* @example
|
|
180
|
+
* class SpecificTracker extends Tracker {
|
|
181
|
+
* registerListeners() {
|
|
182
|
+
* this.player.on('play', () => this.playHandler)
|
|
183
|
+
* }
|
|
184
|
+
*
|
|
185
|
+
* unregisterListeners() {
|
|
186
|
+
* this.player.off('play', () => this.playHandler)
|
|
187
|
+
* }
|
|
188
|
+
*
|
|
189
|
+
* playHandler() {
|
|
190
|
+
* this.send(VideoTracker.Events.REQUESTED)
|
|
191
|
+
* }
|
|
192
|
+
* }
|
|
193
|
+
*/
|
|
194
|
+
unregisterListeners() {}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Trackers will generate unique id's for every new video iteration. If you have your own unique
|
|
198
|
+
* view value, you can override this method to return it.
|
|
199
|
+
* If the tracker has a parentTracker defined, parent viewId will be used.
|
|
200
|
+
*/
|
|
201
|
+
getViewId() {
|
|
202
|
+
if (this.parentTracker) {
|
|
203
|
+
return this.parentTracker.getViewId();
|
|
204
|
+
} else {
|
|
205
|
+
return this.state.getViewId();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Trackers will generate unique id's for every new video session. If you have your own unique
|
|
211
|
+
* view value, you can override this method to return it.
|
|
212
|
+
* If the tracker has a parentTracker defined, parent viewId will be used.
|
|
213
|
+
*/
|
|
214
|
+
getViewSession() {
|
|
215
|
+
if (this.parentTracker) {
|
|
216
|
+
return this.parentTracker.getViewSession();
|
|
217
|
+
} else {
|
|
218
|
+
return this.state.getViewSession();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Override to return the Id of the video. */
|
|
223
|
+
getVideoId() {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Override to return Title of the video. */
|
|
228
|
+
getTitle() {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** Override to return True if the video is live. */
|
|
233
|
+
isLive() {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Override to return Bitrate (in bits) of the video. */
|
|
238
|
+
getBitrate() {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Calculates consumed bitrate using webkitVideoDecodedByteCount. */
|
|
243
|
+
getWebkitBitrate() {
|
|
244
|
+
if (this.tag && this.tag.webkitVideoDecodedByteCount) {
|
|
245
|
+
let bitrate;
|
|
246
|
+
if (this._lastWebkitBitrate) {
|
|
247
|
+
bitrate = this.tag.webkitVideoDecodedByteCount;
|
|
248
|
+
let delta = bitrate - this._lastWebkitBitrate;
|
|
249
|
+
let seconds = this.getHeartbeat() / 1000;
|
|
250
|
+
bitrate = Math.round((delta / seconds) * 8);
|
|
251
|
+
}
|
|
252
|
+
this._lastWebkitBitrate = this.tag.webkitVideoDecodedByteCount;
|
|
253
|
+
return bitrate || null;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** Override to return Name of the rendition (ie: 1080p). */
|
|
258
|
+
getRenditionName() {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Override to return Target Bitrate of the rendition. */
|
|
263
|
+
getRenditionBitrate() {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* This method will return 'up', 'down' or null depending on if the bitrate of the rendition
|
|
269
|
+
* have changed from the last time it was called.
|
|
270
|
+
*
|
|
271
|
+
* @param {boolean} [saveNewRendition=false] If true, current rendition will be stored to be used
|
|
272
|
+
* the next time this method is called. This allows you to call this.getRenditionShift() without
|
|
273
|
+
* saving the current rendition and thus preventing interferences with RENDITION_CHANGE events.
|
|
274
|
+
*/
|
|
275
|
+
getRenditionShift(saveNewRendition) {
|
|
276
|
+
let current = this.getRenditionBitrate();
|
|
277
|
+
let last;
|
|
278
|
+
if (this.isAd()) {
|
|
279
|
+
last = this._lastAdRendition;
|
|
280
|
+
if (saveNewRendition) this._lastAdRendition = current;
|
|
281
|
+
} else {
|
|
282
|
+
last = this._lastRendition;
|
|
283
|
+
if (saveNewRendition) this._lastRendition = current;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (!current || !last) {
|
|
287
|
+
return null;
|
|
288
|
+
} else {
|
|
289
|
+
if (current > last) {
|
|
290
|
+
return "up";
|
|
291
|
+
} else if (current < last) {
|
|
292
|
+
return "down";
|
|
293
|
+
} else {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** Override to return renidtion actual Height (before re-scaling). */
|
|
300
|
+
getRenditionHeight() {
|
|
301
|
+
return this.tag ? this.tag.videoHeight : null;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Override to return rendition actual Width (before re-scaling). */
|
|
305
|
+
getRenditionWidth() {
|
|
306
|
+
return this.tag ? this.tag.videoWidth : null;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** Override to return Duration of the video, in ms. */
|
|
310
|
+
getDuration() {
|
|
311
|
+
return this.tag ? this.tag.duration : null;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** Override to return Playhead (currentTime) of the video, in ms. */
|
|
315
|
+
getPlayhead() {
|
|
316
|
+
return this.tag ? this.tag.currentTime : null;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Override to return Language of the video. We recommend using locale notation, ie: en_US.
|
|
321
|
+
* {@see https://gist.github.com/jacobbubu/1836273}
|
|
322
|
+
*/
|
|
323
|
+
getLanguage() {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/** Override to return URL of the resource being played. */
|
|
328
|
+
getSrc() {
|
|
329
|
+
return this.tag ? this.tag.currentSrc : null;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** Override to return Playrate (speed) of the video. ie: 1.0, 0.5, 1.25... */
|
|
333
|
+
getPlayrate() {
|
|
334
|
+
return this.tag ? this.tag.playbackRate : null;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** Override to return True if the video is currently muted. */
|
|
338
|
+
isMuted() {
|
|
339
|
+
return this.tag ? this.tag.muted : null;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** Override to return True if the video is currently fullscreen. */
|
|
343
|
+
isFullscreen() {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/** Override to return the CDN serving the content. */
|
|
348
|
+
getCdn() {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Override to return the Name of the player. */
|
|
353
|
+
getPlayerName() {
|
|
354
|
+
return this.getTrackerName();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** Override to return the Version of the player. */
|
|
358
|
+
getPlayerVersion() {
|
|
359
|
+
return pkg.version;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/** Override to return current FPS (Frames per second). */
|
|
363
|
+
getFps() {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Override to return if the player was autoplayed. By default: this.tag.autoplay
|
|
369
|
+
*/
|
|
370
|
+
isAutoplayed() {
|
|
371
|
+
return this.tag ? this.tag.autoplay : null;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Override to return the player preload attribute. By default: this.tag.preload
|
|
376
|
+
*/
|
|
377
|
+
getPreload() {
|
|
378
|
+
return this.tag ? this.tag.preload : null;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Only for ads
|
|
382
|
+
/**
|
|
383
|
+
* Override to return Quartile of the ad. 0 before first, 1 after first quartile, 2 after
|
|
384
|
+
* midpoint, 3 after third quartile, 4 when completed.
|
|
385
|
+
*/
|
|
386
|
+
getAdQuartile() {
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Override to return the position of the ad. Use {@link Constants.AdPositions} enum
|
|
392
|
+
* to fill this data.
|
|
393
|
+
*/
|
|
394
|
+
getAdPosition() {
|
|
395
|
+
if (this.parentTracker) {
|
|
396
|
+
return this.parentTracker.state.isStarted ? "mid" : "pre";
|
|
397
|
+
} else {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Override to return the ad partner. ie: ima, freewheel...
|
|
404
|
+
*/
|
|
405
|
+
getAdPartner() {
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Override to return the creative id of the ad.
|
|
411
|
+
*/
|
|
412
|
+
getAdCreativeId() {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Override to return the instrumentation of the player.
|
|
418
|
+
*/
|
|
419
|
+
|
|
420
|
+
getInstrumentationProvider() {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
getInstrumentationName() {
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
getInstrumentationVersion() {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Do NOT override. This method fills all the appropiate attributes for tracked video.
|
|
434
|
+
*
|
|
435
|
+
* @param {object} [att] Collection of key value attributes
|
|
436
|
+
* @return {object} Filled attributes
|
|
437
|
+
* @final
|
|
438
|
+
*/
|
|
439
|
+
getAttributes(att, type) {
|
|
440
|
+
att = Tracker.prototype.getAttributes.apply(this, arguments);
|
|
441
|
+
|
|
442
|
+
if (typeof att.isAd === "undefined") att.isAd = this.isAd();
|
|
443
|
+
|
|
444
|
+
att.viewSession = this.getViewSession();
|
|
445
|
+
att.viewId = this.getViewId();
|
|
446
|
+
att.playerName = this.getPlayerName();
|
|
447
|
+
att.playerVersion = this.getPlayerVersion();
|
|
448
|
+
att["instrumentation.provider"] = this.getInstrumentationProvider();
|
|
449
|
+
att["instrumentation.name"] = this.getInstrumentationName();
|
|
450
|
+
att["instrumentation.version"] = this.getInstrumentationVersion();
|
|
451
|
+
att["enduser.id"] = this._userId;
|
|
452
|
+
att["src"] = "Browser";
|
|
453
|
+
|
|
454
|
+
if (type === "customAction") return att;
|
|
455
|
+
|
|
456
|
+
try {
|
|
457
|
+
att.pageUrl = window.location.href;
|
|
458
|
+
} catch (err) {
|
|
459
|
+
/* skip */
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (this.isAd()) {
|
|
463
|
+
// Ads
|
|
464
|
+
att.adId = this.getVideoId();
|
|
465
|
+
att.adTitle = this.getTitle();
|
|
466
|
+
att.adSrc = this.getSrc();
|
|
467
|
+
att.adCdn = this.getCdn();
|
|
468
|
+
att.adBitrate =
|
|
469
|
+
this.getBitrate() ||
|
|
470
|
+
this.getWebkitBitrate() ||
|
|
471
|
+
this.getRenditionBitrate();
|
|
472
|
+
att.adRenditionName = this.getRenditionName();
|
|
473
|
+
att.adRenditionBitrate = this.getRenditionBitrate();
|
|
474
|
+
att.adRenditionHeight = this.getRenditionHeight();
|
|
475
|
+
att.adRenditionWidth = this.getRenditionWidth();
|
|
476
|
+
att.adDuration = this.getDuration();
|
|
477
|
+
att.adPlayhead = this.getPlayhead();
|
|
478
|
+
att.adLanguage = this.getLanguage();
|
|
479
|
+
att.adIsMuted = this.isMuted();
|
|
480
|
+
att.adFps = this.getFps();
|
|
481
|
+
// ad exclusives
|
|
482
|
+
//att.adQuartile = this.getAdQuartile();
|
|
483
|
+
att.adPosition = this.getAdPosition();
|
|
484
|
+
att.adCreativeId = this.getAdCreativeId();
|
|
485
|
+
att.adPartner = this.getAdPartner();
|
|
486
|
+
} else {
|
|
487
|
+
// no ads
|
|
488
|
+
att.contentId = this.getVideoId();
|
|
489
|
+
att.contentTitle = this.getTitle();
|
|
490
|
+
att.contentSrc = this.getSrc();
|
|
491
|
+
att.contentCdn = this.getCdn();
|
|
492
|
+
att.contentPlayhead = this.getPlayhead();
|
|
493
|
+
|
|
494
|
+
att.contentIsLive = this.isLive();
|
|
495
|
+
att.contentBitrate =
|
|
496
|
+
this.getBitrate() ||
|
|
497
|
+
this.getWebkitBitrate() ||
|
|
498
|
+
this.getRenditionBitrate();
|
|
499
|
+
att.contentRenditionName = this.getRenditionName();
|
|
500
|
+
att.contentRenditionBitrate = this.getRenditionBitrate();
|
|
501
|
+
att.contentRenditionHeight = this.getRenditionHeight();
|
|
502
|
+
att.contentRenditionWidth = this.getRenditionWidth();
|
|
503
|
+
att.contentDuration = this.getDuration();
|
|
504
|
+
|
|
505
|
+
att.contentLanguage = this.getLanguage();
|
|
506
|
+
att.contentPlayrate = this.getPlayrate();
|
|
507
|
+
att.contentIsFullscreen = this.isFullscreen();
|
|
508
|
+
att.contentIsMuted = this.isMuted();
|
|
509
|
+
att.contentIsAutoplayed = this.isAutoplayed();
|
|
510
|
+
att.contentPreload = this.getPreload();
|
|
511
|
+
att.contentFps = this.getFps();
|
|
512
|
+
|
|
513
|
+
if (
|
|
514
|
+
this.adsTracker != null &&
|
|
515
|
+
this.adsTracker.state.totalAdPlaytime > 0
|
|
516
|
+
) {
|
|
517
|
+
att.totalAdPlaytime = this.adsTracker.state.totalAdPlaytime;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
this.state.getStateAttributes(att);
|
|
522
|
+
|
|
523
|
+
for (let key in this.customData) {
|
|
524
|
+
att[key] = this.customData[key];
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return att;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Sends custom event and registers a timeSince attribute.
|
|
532
|
+
* @param {Object} [actionName] Custom action name.
|
|
533
|
+
* @param {Object} [timeSinceAttName] Custom timeSince attribute name.
|
|
534
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
535
|
+
*/
|
|
536
|
+
sendCustom(actionName, timeSinceAttName, att) {
|
|
537
|
+
att = att || {};
|
|
538
|
+
this.sendVideoCustomAction(actionName, att);
|
|
539
|
+
this.state.setTimeSinceAttribute(timeSinceAttName);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
544
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
545
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
546
|
+
*/
|
|
547
|
+
sendPlayerReady(att) {
|
|
548
|
+
if (this.state.goPlayerReady()) {
|
|
549
|
+
att = att || {};
|
|
550
|
+
this.sendVideoAction(VideoTracker.Events.PLAYER_READY, att);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
556
|
+
* duplicated events. Should be associated to an event using registerListeners. Calls
|
|
557
|
+
* {@link startHeartbeat}.
|
|
558
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
559
|
+
*/
|
|
560
|
+
sendRequest(att) {
|
|
561
|
+
if (this.state.goRequest()) {
|
|
562
|
+
let ev;
|
|
563
|
+
if (this.isAd()) {
|
|
564
|
+
ev = VideoTracker.Events.AD_REQUEST;
|
|
565
|
+
this.sendVideoAdAction(ev, att);
|
|
566
|
+
} else {
|
|
567
|
+
ev = VideoTracker.Events.CONTENT_REQUEST;
|
|
568
|
+
this.sendVideoAction(ev, att);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// this.startHeartbeat();
|
|
572
|
+
// this.state.goHeartbeat();
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
578
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
579
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
580
|
+
*/
|
|
581
|
+
sendStart(att) {
|
|
582
|
+
if (this.state.goStart()) {
|
|
583
|
+
let ev;
|
|
584
|
+
if (this.isAd()) {
|
|
585
|
+
ev = VideoTracker.Events.AD_START;
|
|
586
|
+
if (this.parentTracker) this.parentTracker.state.isPlaying = false;
|
|
587
|
+
this.sendVideoAdAction(ev, att);
|
|
588
|
+
} else {
|
|
589
|
+
ev = VideoTracker.Events.CONTENT_START;
|
|
590
|
+
this.sendVideoAction(ev, att);
|
|
591
|
+
}
|
|
592
|
+
//this.send(ev, att);
|
|
593
|
+
this.startHeartbeat();
|
|
594
|
+
this.state.goHeartbeat();
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
600
|
+
* duplicated events. Should be associated to an event using registerListeners. Calls
|
|
601
|
+
* {@link stopHeartbeat}.
|
|
602
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
603
|
+
*/
|
|
604
|
+
sendEnd(att) {
|
|
605
|
+
if (this.state.goEnd()) {
|
|
606
|
+
att = att || {};
|
|
607
|
+
let ev;
|
|
608
|
+
if (this.isAd()) {
|
|
609
|
+
ev = VideoTracker.Events.AD_END;
|
|
610
|
+
att.timeSinceAdRequested = this.state.timeSinceRequested.getDeltaTime();
|
|
611
|
+
att.timeSinceAdStarted = this.state.timeSinceStarted.getDeltaTime();
|
|
612
|
+
if (this.parentTracker) this.parentTracker.state.isPlaying = true;
|
|
613
|
+
} else {
|
|
614
|
+
ev = VideoTracker.Events.CONTENT_END;
|
|
615
|
+
att.timeSinceRequested = this.state.timeSinceRequested.getDeltaTime();
|
|
616
|
+
att.timeSinceStarted = this.state.timeSinceStarted.getDeltaTime();
|
|
617
|
+
}
|
|
618
|
+
this.stopHeartbeat();
|
|
619
|
+
//this.send(ev, att);
|
|
620
|
+
this.isAd()
|
|
621
|
+
? this.sendVideoAdAction(ev, att)
|
|
622
|
+
: this.sendVideoAction(ev, att);
|
|
623
|
+
|
|
624
|
+
if (this.parentTracker && this.isAd())
|
|
625
|
+
this.parentTracker.state.goLastAd();
|
|
626
|
+
this.state.goViewCountUp();
|
|
627
|
+
this.state.totalPlaytime = 0;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
633
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
634
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
635
|
+
*/
|
|
636
|
+
sendPause(att) {
|
|
637
|
+
if (this.state.goPause()) {
|
|
638
|
+
let ev = this.isAd()
|
|
639
|
+
? VideoTracker.Events.AD_PAUSE
|
|
640
|
+
: VideoTracker.Events.CONTENT_PAUSE;
|
|
641
|
+
|
|
642
|
+
this.isAd()
|
|
643
|
+
? this.sendVideoAdAction(ev, att)
|
|
644
|
+
: this.sendVideoAction(ev, att);
|
|
645
|
+
|
|
646
|
+
//this.send(ev, att);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
652
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
653
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
654
|
+
*/
|
|
655
|
+
sendResume(att) {
|
|
656
|
+
if (this.state.goResume()) {
|
|
657
|
+
att = att || {};
|
|
658
|
+
let ev;
|
|
659
|
+
if (this.isAd()) {
|
|
660
|
+
ev = VideoTracker.Events.AD_RESUME;
|
|
661
|
+
att.timeSinceAdPaused = this.state.timeSincePaused.getDeltaTime();
|
|
662
|
+
} else {
|
|
663
|
+
ev = VideoTracker.Events.CONTENT_RESUME;
|
|
664
|
+
att.timeSincePaused = this.state.timeSincePaused.getDeltaTime();
|
|
665
|
+
}
|
|
666
|
+
//this.send(ev, att);
|
|
667
|
+
this.isAd()
|
|
668
|
+
? this.sendVideoAdAction(ev, att)
|
|
669
|
+
: this.sendVideoAction(ev, att);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
675
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
676
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
677
|
+
*/
|
|
678
|
+
sendBufferStart(att) {
|
|
679
|
+
if (this.state.goBufferStart()) {
|
|
680
|
+
att = att || {};
|
|
681
|
+
let ev;
|
|
682
|
+
if (this.isAd()) {
|
|
683
|
+
ev = VideoTracker.Events.AD_BUFFER_START;
|
|
684
|
+
} else {
|
|
685
|
+
ev = VideoTracker.Events.CONTENT_BUFFER_START;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
att = this.buildBufferAttributes(att);
|
|
689
|
+
this._lastBufferType = att.bufferType;
|
|
690
|
+
|
|
691
|
+
//this.send(ev, att);
|
|
692
|
+
this.isAd()
|
|
693
|
+
? this.sendVideoAdAction(ev, att)
|
|
694
|
+
: this.sendVideoAction(ev, att);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
700
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
701
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
702
|
+
*/
|
|
703
|
+
sendBufferEnd(att) {
|
|
704
|
+
if (this.state.goBufferEnd()) {
|
|
705
|
+
att = att || {};
|
|
706
|
+
let ev;
|
|
707
|
+
if (this.isAd()) {
|
|
708
|
+
ev = VideoTracker.Events.AD_BUFFER_END;
|
|
709
|
+
att.timeSinceAdBufferBegin =
|
|
710
|
+
this.state.timeSinceBufferBegin.getDeltaTime();
|
|
711
|
+
} else {
|
|
712
|
+
ev = VideoTracker.Events.CONTENT_BUFFER_END;
|
|
713
|
+
att.timeSinceBufferBegin =
|
|
714
|
+
this.state.timeSinceBufferBegin.getDeltaTime();
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
att = this.buildBufferAttributes(att);
|
|
718
|
+
// Set the bufferType attribute of the last BUFFER_START
|
|
719
|
+
if (this._lastBufferType != null) {
|
|
720
|
+
att.bufferType = this._lastBufferType;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// this.send(ev, att);
|
|
724
|
+
this.isAd()
|
|
725
|
+
? this.sendVideoAdAction(ev, att)
|
|
726
|
+
: this.sendVideoAction(ev, att);
|
|
727
|
+
this.state.initialBufferingHappened = true;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
buildBufferAttributes(att) {
|
|
732
|
+
if (att.timeSinceStarted == undefined || att.timeSinceStarted < 100) {
|
|
733
|
+
att.isInitialBuffering = !this.state.initialBufferingHappened;
|
|
734
|
+
} else {
|
|
735
|
+
att.isInitialBuffering = false;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
att.bufferType = this.state.calculateBufferType(att.isInitialBuffering);
|
|
739
|
+
|
|
740
|
+
att.timeSinceResumed = this.state.timeSinceResumed.getDeltaTime();
|
|
741
|
+
att.timeSinceSeekEnd = this.state.timeSinceSeekEnd.getDeltaTime();
|
|
742
|
+
|
|
743
|
+
return att;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
748
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
749
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
750
|
+
*/
|
|
751
|
+
sendSeekStart(att) {
|
|
752
|
+
if (this.state.goSeekStart()) {
|
|
753
|
+
let ev;
|
|
754
|
+
if (this.isAd()) {
|
|
755
|
+
ev = VideoTracker.Events.AD_SEEK_START;
|
|
756
|
+
} else {
|
|
757
|
+
ev = VideoTracker.Events.CONTENT_SEEK_START;
|
|
758
|
+
}
|
|
759
|
+
// this.send(ev, att);
|
|
760
|
+
|
|
761
|
+
this.isAd()
|
|
762
|
+
? this.sendVideoAdAction(ev, att)
|
|
763
|
+
: this.sendVideoAction(ev, att);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
769
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
770
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
771
|
+
*/
|
|
772
|
+
sendSeekEnd(att) {
|
|
773
|
+
if (this.state.goSeekEnd()) {
|
|
774
|
+
att = att || {};
|
|
775
|
+
let ev;
|
|
776
|
+
if (this.isAd()) {
|
|
777
|
+
ev = VideoTracker.Events.AD_SEEK_END;
|
|
778
|
+
att.timeSinceAdSeekBegin = this.state.timeSinceSeekBegin.getDeltaTime();
|
|
779
|
+
} else {
|
|
780
|
+
ev = VideoTracker.Events.CONTENT_SEEK_END;
|
|
781
|
+
att.timeSinceSeekBegin = this.state.timeSinceSeekBegin.getDeltaTime();
|
|
782
|
+
}
|
|
783
|
+
// this.send(ev, att);
|
|
784
|
+
|
|
785
|
+
this.isAd()
|
|
786
|
+
? this.sendVideoAdAction(ev, att)
|
|
787
|
+
: this.sendVideoAction(ev, att);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
793
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
794
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
795
|
+
* @param {String} att.state Download requires a string to distinguish different states.
|
|
796
|
+
*/
|
|
797
|
+
sendDownload(att) {
|
|
798
|
+
att = att || {};
|
|
799
|
+
if (!att.state) Log.warn("Called sendDownload without { state: xxxxx }.");
|
|
800
|
+
this.sendVideoAction(VideoTracker.Events.DOWNLOAD, att);
|
|
801
|
+
this.state.goDownload();
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
806
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
807
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
808
|
+
*/
|
|
809
|
+
sendError(att) {
|
|
810
|
+
att = att || {};
|
|
811
|
+
|
|
812
|
+
att.isAd = this.isAd();
|
|
813
|
+
this.state.goError();
|
|
814
|
+
let ev = this.isAd()
|
|
815
|
+
? VideoTracker.Events.AD_ERROR
|
|
816
|
+
: VideoTracker.Events.CONTENT_ERROR;
|
|
817
|
+
//this.send(ev, att);
|
|
818
|
+
|
|
819
|
+
this.sendVideoErrorAction(ev, att);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
824
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
825
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
826
|
+
*/
|
|
827
|
+
sendRenditionChanged(att) {
|
|
828
|
+
att = att || {};
|
|
829
|
+
att.timeSinceLastRenditionChange =
|
|
830
|
+
this.state.timeSinceLastRenditionChange.getDeltaTime();
|
|
831
|
+
att.shift = this.getRenditionShift(true);
|
|
832
|
+
let ev;
|
|
833
|
+
if (this.isAd()) {
|
|
834
|
+
ev = VideoTracker.Events.AD_RENDITION_CHANGE;
|
|
835
|
+
} else {
|
|
836
|
+
ev = VideoTracker.Events.CONTENT_RENDITION_CHANGE;
|
|
837
|
+
}
|
|
838
|
+
//this.send(ev, att);
|
|
839
|
+
|
|
840
|
+
this.isAd()
|
|
841
|
+
? this.sendVideoAdAction(ev, att)
|
|
842
|
+
: this.sendVideoAction(ev, att);
|
|
843
|
+
|
|
844
|
+
this.state.goRenditionChange();
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Sends associated event and changes view state. Heartbeat will automatically be sent every
|
|
849
|
+
* 10 seconds. There's no need to call this manually.
|
|
850
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
851
|
+
* @param {number} att.url Url of the clicked ad.
|
|
852
|
+
*
|
|
853
|
+
*/
|
|
854
|
+
sendHeartbeat(att) {
|
|
855
|
+
if (this.state.isRequested) {
|
|
856
|
+
let ev;
|
|
857
|
+
|
|
858
|
+
let elapsedTime = this.getHeartbeat();
|
|
859
|
+
this.state._hb = true;
|
|
860
|
+
elapsedTime = this.adjustElapsedTimeForPause(elapsedTime);
|
|
861
|
+
|
|
862
|
+
if (this.isAd()) {
|
|
863
|
+
ev = VideoTracker.Events.AD_HEARTBEAT;
|
|
864
|
+
if (this.getPlayerName() === "bitmovin-ads") {
|
|
865
|
+
this.sendVideoAdAction(ev, att);
|
|
866
|
+
} else {
|
|
867
|
+
this.sendVideoAdAction(ev, { elapsedTime, ...att });
|
|
868
|
+
}
|
|
869
|
+
} else {
|
|
870
|
+
ev = VideoTracker.Events.CONTENT_HEARTBEAT;
|
|
871
|
+
this.sendVideoAction(ev, { elapsedTime, ...att });
|
|
872
|
+
}
|
|
873
|
+
this.state.goHeartbeat();
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
adjustElapsedTimeForPause(elapsedTime) {
|
|
878
|
+
if (this.state._acc) {
|
|
879
|
+
elapsedTime -= this.state._acc;
|
|
880
|
+
this.state._acc = 0;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
if (this.state.isPaused) {
|
|
884
|
+
elapsedTime -= this.state.elapsedTime.getDeltaTime();
|
|
885
|
+
if (elapsedTime < 10) elapsedTime = 0;
|
|
886
|
+
this.state.elapsedTime.start();
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
if (this.state._bufferAcc) {
|
|
890
|
+
elapsedTime -= this.state._bufferAcc;
|
|
891
|
+
this.state._bufferAcc = 0;
|
|
892
|
+
} else if (this.state.isBuffering) {
|
|
893
|
+
elapsedTime -= this.state.bufferElapsedTime.getDeltaTime();
|
|
894
|
+
if (elapsedTime < 5) {
|
|
895
|
+
elapsedTime = 0;
|
|
896
|
+
}
|
|
897
|
+
this.state.bufferElapsedTime.start();
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
return Math.max(0, elapsedTime);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// Only ads
|
|
904
|
+
/**
|
|
905
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
906
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
907
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
908
|
+
*/
|
|
909
|
+
sendAdBreakStart(att) {
|
|
910
|
+
if (this.isAd() && this.state.goAdBreakStart()) {
|
|
911
|
+
this.state.totalAdPlaytime = 0;
|
|
912
|
+
if (this.parentTracker) this.parentTracker.state.isPlaying = false;
|
|
913
|
+
// this.send(VideoTracker.Events.AD_BREAK_START, att);
|
|
914
|
+
this.sendVideoAdAction(VideoTracker.Events.AD_BREAK_START, att);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
920
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
921
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
922
|
+
*/
|
|
923
|
+
sendAdBreakEnd(att) {
|
|
924
|
+
if (this.isAd() && this.state.goAdBreakEnd()) {
|
|
925
|
+
att = att || {};
|
|
926
|
+
att.timeSinceAdBreakBegin =
|
|
927
|
+
this.state.timeSinceAdBreakStart.getDeltaTime();
|
|
928
|
+
//this.send(VideoTracker.Events.AD_BREAK_END, att);
|
|
929
|
+
this.sendVideoAdAction(VideoTracker.Events.AD_BREAK_END, att);
|
|
930
|
+
// Just in case AD_END not arriving, because of an AD_ERROR
|
|
931
|
+
if (this.parentTracker) this.parentTracker.state.isPlaying = true;
|
|
932
|
+
this.stopHeartbeat();
|
|
933
|
+
if (this.parentTracker && this.isAd())
|
|
934
|
+
this.parentTracker.state.goLastAd();
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
940
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
941
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
942
|
+
* @param {number} att.quartile Number of the quartile.
|
|
943
|
+
*/
|
|
944
|
+
sendAdQuartile(att) {
|
|
945
|
+
if (this.isAd()) {
|
|
946
|
+
att = att || {};
|
|
947
|
+
if (!att.quartile)
|
|
948
|
+
Log.warn("Called sendAdQuartile without { quartile: xxxxx }.");
|
|
949
|
+
att.timeSinceLastAdQuartile =
|
|
950
|
+
this.state.timeSinceLastAdQuartile.getDeltaTime();
|
|
951
|
+
//this.send(VideoTracker.Events.AD_QUARTILE, att);
|
|
952
|
+
|
|
953
|
+
this.sendVideoAdAction(VideoTracker.Events.AD_QUARTILE, att);
|
|
954
|
+
this.state.goAdQuartile();
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
/**
|
|
959
|
+
* Sends associated event and changes view state. An internal state machine will prevent
|
|
960
|
+
* duplicated events. Should be associated to an event using registerListeners.
|
|
961
|
+
* @param {Object} [att] Collection of key:value attributes to send with the request.
|
|
962
|
+
* @param {number} att.url Url of the clicked ad.
|
|
963
|
+
*/
|
|
964
|
+
sendAdClick(att) {
|
|
965
|
+
if (this.isAd()) {
|
|
966
|
+
att = att || {};
|
|
967
|
+
if (!att.url) Log.warn("Called sendAdClick without { url: xxxxx }.");
|
|
968
|
+
//this.send(VideoTracker.Events.AD_CLICK, att);
|
|
969
|
+
this.sendVideoAdAction(VideoTracker.Events.AD_CLICK, att);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Enumeration of events fired by this class.
|
|
976
|
+
*
|
|
977
|
+
* @static
|
|
978
|
+
* @memberof VideoTracker
|
|
979
|
+
* @enum {String}
|
|
980
|
+
*/
|
|
981
|
+
VideoTracker.Events = {
|
|
982
|
+
// Player
|
|
983
|
+
/** The player is ready to start sending events. */
|
|
984
|
+
PLAYER_READY: "PLAYER_READY",
|
|
985
|
+
/** Downloading data. */
|
|
986
|
+
DOWNLOAD: "DOWNLOAD",
|
|
987
|
+
/** An error happened */
|
|
988
|
+
ERROR: "ERROR",
|
|
989
|
+
|
|
990
|
+
// Video
|
|
991
|
+
/** Content video has been requested. */
|
|
992
|
+
CONTENT_REQUEST: "CONTENT_REQUEST",
|
|
993
|
+
/** Content video started (first frame shown). */
|
|
994
|
+
CONTENT_START: "CONTENT_START",
|
|
995
|
+
/** Content video ended. */
|
|
996
|
+
CONTENT_END: "CONTENT_END",
|
|
997
|
+
/** Content video paused. */
|
|
998
|
+
CONTENT_PAUSE: "CONTENT_PAUSE",
|
|
999
|
+
/** Content video resumed. */
|
|
1000
|
+
CONTENT_RESUME: "CONTENT_RESUME",
|
|
1001
|
+
/** Content video seek started */
|
|
1002
|
+
CONTENT_SEEK_START: "CONTENT_SEEK_START",
|
|
1003
|
+
/** Content video seek ended. */
|
|
1004
|
+
CONTENT_SEEK_END: "CONTENT_SEEK_END",
|
|
1005
|
+
/** Content video beffering started */
|
|
1006
|
+
CONTENT_BUFFER_START: "CONTENT_BUFFER_START",
|
|
1007
|
+
/** Content video buffering ended */
|
|
1008
|
+
CONTENT_BUFFER_END: "CONTENT_BUFFER_END",
|
|
1009
|
+
/** Content video heartbeat, en event that happens once every 30 seconds while the video is playing. */
|
|
1010
|
+
CONTENT_HEARTBEAT: "CONTENT_HEARTBEAT",
|
|
1011
|
+
/** Content video stream qwuality changed. */
|
|
1012
|
+
CONTENT_RENDITION_CHANGE: "CONTENT_RENDITION_CHANGE",
|
|
1013
|
+
/** Content video error. */
|
|
1014
|
+
CONTENT_ERROR: "CONTENT_ERROR",
|
|
1015
|
+
|
|
1016
|
+
// Ads only
|
|
1017
|
+
/** Ad video has been requested. */
|
|
1018
|
+
AD_REQUEST: "AD_REQUEST",
|
|
1019
|
+
/** Ad video started (first frame shown). */
|
|
1020
|
+
AD_START: "AD_START",
|
|
1021
|
+
/** Ad video ended. */
|
|
1022
|
+
AD_END: "AD_END",
|
|
1023
|
+
/** Ad video paused. */
|
|
1024
|
+
AD_PAUSE: "AD_PAUSE",
|
|
1025
|
+
/** Ad video resumed. */
|
|
1026
|
+
AD_RESUME: "AD_RESUME",
|
|
1027
|
+
/** Ad video seek started */
|
|
1028
|
+
AD_SEEK_START: "AD_SEEK_START",
|
|
1029
|
+
/** Ad video seek ended */
|
|
1030
|
+
AD_SEEK_END: "AD_SEEK_END",
|
|
1031
|
+
/** Ad video beffering started */
|
|
1032
|
+
AD_BUFFER_START: "AD_BUFFER_START",
|
|
1033
|
+
/** Ad video beffering ended */
|
|
1034
|
+
AD_BUFFER_END: "AD_BUFFER_END",
|
|
1035
|
+
/** Ad video heartbeat, en event that happens once every 30 seconds while the video is playing. */
|
|
1036
|
+
AD_HEARTBEAT: "AD_HEARTBEAT",
|
|
1037
|
+
/** Ad video stream qwuality changed. */
|
|
1038
|
+
AD_RENDITION_CHANGE: "AD_RENDITION_CHANGE",
|
|
1039
|
+
/** Ad video error. */
|
|
1040
|
+
AD_ERROR: "AD_ERROR",
|
|
1041
|
+
/** Ad break (a block of ads) started. */
|
|
1042
|
+
AD_BREAK_START: "AD_BREAK_START",
|
|
1043
|
+
/** Ad break ended. */
|
|
1044
|
+
AD_BREAK_END: "AD_BREAK_END",
|
|
1045
|
+
/** Ad quartile happened. */
|
|
1046
|
+
AD_QUARTILE: "AD_QUARTILE",
|
|
1047
|
+
/** Ad has been clicked. */
|
|
1048
|
+
AD_CLICK: "AD_CLICK",
|
|
1049
|
+
};
|
|
1050
|
+
|
|
1051
|
+
// Private members
|
|
1052
|
+
function funnelAdEvents(e) {
|
|
1053
|
+
if (e.type === VideoTracker.Events.AD_ERROR) {
|
|
1054
|
+
this.sendVideoErrorAction(e.type, e.data);
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
this.sendVideoAdAction(e.type, e.data);
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
export default VideoTracker;
|