@newrelic/video-videojs 4.1.1 → 4.1.2
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 +28 -0
- package/README.md +68 -3
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.LICENSE.txt +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.LICENSE.txt +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/umd/newrelic-video-videojs.min.js +1 -1
- package/dist/umd/newrelic-video-videojs.min.js.LICENSE.txt +3 -1
- package/dist/umd/newrelic-video-videojs.min.js.map +1 -1
- package/package.json +9 -2
- package/src/ads/dai.js +6 -3
- package/src/ads/ima.js +3 -2
- package/src/ads/media-tailor.js +1246 -0
- package/src/ads/utils/mt-constants.js +82 -0
- package/src/ads/utils/mt.js +792 -0
- package/src/techs/contrib-hls.js +7 -8
- package/src/techs/hls-js.js +5 -5
- package/src/techs/shaka.js +7 -6
- package/src/tracker.js +64 -12
package/src/techs/contrib-hls.js
CHANGED
|
@@ -15,7 +15,7 @@ export default class ContribHlsTech {
|
|
|
15
15
|
getRenditionBitrate() {
|
|
16
16
|
try {
|
|
17
17
|
var media = this.tech.playlists.media();
|
|
18
|
-
if (media && media.attributes) return media.attributes.BANDWIDTH;
|
|
18
|
+
if (media && media.attributes) return Math.round(media.attributes.BANDWIDTH);
|
|
19
19
|
} catch (err) {}
|
|
20
20
|
return null;
|
|
21
21
|
}
|
|
@@ -50,7 +50,7 @@ export default class ContribHlsTech {
|
|
|
50
50
|
// Return highest available bitrate from all renditions
|
|
51
51
|
const playlists = this.tech.playlists.master.playlists;
|
|
52
52
|
if (playlists && playlists.length > 0) {
|
|
53
|
-
return Math.max(...playlists.map((p) => p.attributes.BANDWIDTH));
|
|
53
|
+
return Math.round(Math.max(...playlists.map((p) => p.attributes.BANDWIDTH)));
|
|
54
54
|
}
|
|
55
55
|
} catch (err) {}
|
|
56
56
|
return null;
|
|
@@ -61,14 +61,14 @@ export default class ContribHlsTech {
|
|
|
61
61
|
this.tech.stats?.bandwidth !== undefined &&
|
|
62
62
|
this.tech.stats.bandwidth > 0
|
|
63
63
|
) {
|
|
64
|
-
return this.tech.stats.bandwidth;
|
|
64
|
+
return Math.round(this.tech.stats.bandwidth);
|
|
65
65
|
}
|
|
66
66
|
return null;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
getNetworkDownloadBitrate() {
|
|
70
70
|
if (this.tech.throughput !== undefined && this.tech.throughput > 0) {
|
|
71
|
-
return this.tech.throughput;
|
|
71
|
+
return Math.round(this.tech.throughput);
|
|
72
72
|
}
|
|
73
73
|
return null;
|
|
74
74
|
}
|
|
@@ -79,11 +79,10 @@ export default class ContribHlsTech {
|
|
|
79
79
|
const media = this.tech.playlists.media();
|
|
80
80
|
if (media && media.attributes) {
|
|
81
81
|
// Use AVERAGE-BANDWIDTH if available, fallback to BANDWIDTH
|
|
82
|
-
|
|
83
|
-
media.attributes['AVERAGE-BANDWIDTH'] ||
|
|
82
|
+
const bitrate = media.attributes['AVERAGE-BANDWIDTH'] ||
|
|
84
83
|
media.attributes.BANDWIDTH ||
|
|
85
|
-
null
|
|
86
|
-
);
|
|
84
|
+
null;
|
|
85
|
+
return bitrate !== null ? Math.round(bitrate) : null;
|
|
87
86
|
}
|
|
88
87
|
} catch (err) {}
|
|
89
88
|
return null;
|
package/src/techs/hls-js.js
CHANGED
|
@@ -19,7 +19,7 @@ export default class HlsJs {
|
|
|
19
19
|
getRenditionBitrate(tech) {
|
|
20
20
|
try {
|
|
21
21
|
var level = this.tech.levels[this.tech.currentLevel];
|
|
22
|
-
if (level && level.bitrate) return level.bitrate;
|
|
22
|
+
if (level && level.bitrate) return Math.round(level.bitrate);
|
|
23
23
|
} catch (err) {}
|
|
24
24
|
return null;
|
|
25
25
|
}
|
|
@@ -50,7 +50,7 @@ export default class HlsJs {
|
|
|
50
50
|
// Get the current active level's bitrate from manifest
|
|
51
51
|
const level = this.tech.levels[this.tech.currentLevel];
|
|
52
52
|
if (level && level.bitrate) {
|
|
53
|
-
return level.bitrate;
|
|
53
|
+
return Math.round(level.bitrate);
|
|
54
54
|
}
|
|
55
55
|
} catch (err) {}
|
|
56
56
|
return null;
|
|
@@ -60,7 +60,7 @@ export default class HlsJs {
|
|
|
60
60
|
try {
|
|
61
61
|
// Return highest available bitrate from all renditions
|
|
62
62
|
if (this.tech.levels && this.tech.levels.length > 0) {
|
|
63
|
-
return Math.max(...this.tech.levels.map(l => l.bitrate));
|
|
63
|
+
return Math.round(Math.max(...this.tech.levels.map(l => l.bitrate)));
|
|
64
64
|
}
|
|
65
65
|
} catch (err) {}
|
|
66
66
|
return null;
|
|
@@ -70,14 +70,14 @@ export default class HlsJs {
|
|
|
70
70
|
try {
|
|
71
71
|
// VHS stats.bandwidth
|
|
72
72
|
if (this.tech.stats && this.tech.stats.bandwidth > 0)
|
|
73
|
-
return this.tech.stats.bandwidth;
|
|
73
|
+
return Math.round(this.tech.stats.bandwidth);
|
|
74
74
|
} catch (err) {}
|
|
75
75
|
return null;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
getNetworkDownloadBitrate() {
|
|
79
79
|
if (this.tech.throughput && this.tech.throughput > 0) {
|
|
80
|
-
return this.tech.throughput;
|
|
80
|
+
return Math.round(this.tech.throughput);
|
|
81
81
|
}
|
|
82
82
|
return null;
|
|
83
83
|
}
|
package/src/techs/shaka.js
CHANGED
|
@@ -13,7 +13,8 @@ export default class ShakaTech {
|
|
|
13
13
|
|
|
14
14
|
getRenditionBitrate(tech) {
|
|
15
15
|
try {
|
|
16
|
-
|
|
16
|
+
const bitrate = this.tech.getStats().streamBandwidth;
|
|
17
|
+
return bitrate ? Math.round(bitrate) : null;
|
|
17
18
|
} catch (err) {}
|
|
18
19
|
return null;
|
|
19
20
|
}
|
|
@@ -23,9 +24,9 @@ export default class ShakaTech {
|
|
|
23
24
|
// Return highest available bitrate from all variants
|
|
24
25
|
const tracks = this.tech.getVariantTracks();
|
|
25
26
|
if (tracks && tracks.length > 0) {
|
|
26
|
-
return Math.max(
|
|
27
|
+
return Math.round(Math.max(
|
|
27
28
|
...tracks.map((t) => t.videoBandwidth + (t.audioBandwidth || 0)),
|
|
28
|
-
);
|
|
29
|
+
));
|
|
29
30
|
}
|
|
30
31
|
} catch (err) {}
|
|
31
32
|
return null;
|
|
@@ -67,7 +68,7 @@ export default class ShakaTech {
|
|
|
67
68
|
// Get the current variant's bitrate from manifest (streamBandwidth)
|
|
68
69
|
var stats = this.tech.getStats();
|
|
69
70
|
if (stats && stats.streamBandwidth && stats.streamBandwidth > 0) {
|
|
70
|
-
return stats.streamBandwidth;
|
|
71
|
+
return Math.round(stats.streamBandwidth);
|
|
71
72
|
}
|
|
72
73
|
} catch (err) {}
|
|
73
74
|
return null;
|
|
@@ -78,7 +79,7 @@ export default class ShakaTech {
|
|
|
78
79
|
// Use estimatedBandwidth for measured bitrate
|
|
79
80
|
var stats = this.tech.getStats();
|
|
80
81
|
if (stats && stats.estimatedBandwidth > 0) {
|
|
81
|
-
return stats.estimatedBandwidth;
|
|
82
|
+
return Math.round(stats.estimatedBandwidth);
|
|
82
83
|
}
|
|
83
84
|
} catch (err) {}
|
|
84
85
|
return null;
|
|
@@ -89,7 +90,7 @@ export default class ShakaTech {
|
|
|
89
90
|
// Shaka: use estimatedBandwidth for download bitrate (no separate property)
|
|
90
91
|
var stats = this.tech.getStats();
|
|
91
92
|
if (stats && stats.estimatedBandwidth > 0) {
|
|
92
|
-
return stats.estimatedBandwidth;
|
|
93
|
+
return Math.round(stats.estimatedBandwidth);
|
|
93
94
|
}
|
|
94
95
|
} catch (err) {}
|
|
95
96
|
return null;
|
package/src/tracker.js
CHANGED
|
@@ -8,11 +8,12 @@ import ImaAdsTracker from './ads/ima';
|
|
|
8
8
|
import BrightcoveImaAdsTracker from './ads/brightcove-ima';
|
|
9
9
|
import FreewheelAdsTracker from './ads/freewheel';
|
|
10
10
|
import DaiAdsTracker from './ads/dai';
|
|
11
|
+
import MediaTailorAdsTracker from './ads/media-tailor';
|
|
11
12
|
|
|
12
13
|
export default class VideojsTracker extends nrvideo.VideoTracker {
|
|
13
14
|
constructor(player, options) {
|
|
14
15
|
super(player, options);
|
|
15
|
-
|
|
16
|
+
this.options = options;
|
|
16
17
|
this.isContentEnd = false;
|
|
17
18
|
this.imaAdCuePoints = '';
|
|
18
19
|
this.daiInitialized = false;
|
|
@@ -125,17 +126,17 @@ export default class VideojsTracker extends nrvideo.VideoTracker {
|
|
|
125
126
|
if (tech?.vhs?.playlists?.media()) {
|
|
126
127
|
const activePlaylist = tech.vhs.playlists.media();
|
|
127
128
|
// Use AVERAGE-BANDWIDTH if available, fallback to BANDWIDTH
|
|
128
|
-
|
|
129
|
-
activePlaylist.attributes['AVERAGE-BANDWIDTH'] ||
|
|
129
|
+
const bitrate = activePlaylist.attributes['AVERAGE-BANDWIDTH'] ||
|
|
130
130
|
activePlaylist.attributes.BANDWIDTH ||
|
|
131
|
-
null
|
|
132
|
-
);
|
|
131
|
+
null;
|
|
132
|
+
return bitrate !== null ? Math.round(bitrate) : null;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
// 2. Fallback to tech wrappers (Shaka/Hls.js) if they have a getBitrate method
|
|
136
136
|
const techWrapper = this.getTech();
|
|
137
137
|
if (techWrapper?.getBitrate) {
|
|
138
|
-
|
|
138
|
+
const bitrate = techWrapper.getBitrate();
|
|
139
|
+
return bitrate !== null ? Math.round(bitrate) : null;
|
|
139
140
|
}
|
|
140
141
|
} catch (err) {
|
|
141
142
|
/* ignore */
|
|
@@ -161,13 +162,14 @@ export default class VideojsTracker extends nrvideo.VideoTracker {
|
|
|
161
162
|
const maxBitrate = Math.max(
|
|
162
163
|
...allRenditions.map((p) => p.attributes.BANDWIDTH || 0),
|
|
163
164
|
);
|
|
164
|
-
return maxBitrate > 0 ? maxBitrate : null;
|
|
165
|
+
return maxBitrate > 0 ? Math.round(maxBitrate) : null;
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
// Fallback to tech wrappers (Shaka/Hls.js)
|
|
168
169
|
const techWrapper = this.getTech();
|
|
169
170
|
if (techWrapper?.getManifestBitrate) {
|
|
170
|
-
|
|
171
|
+
const bitrate = techWrapper.getManifestBitrate();
|
|
172
|
+
return bitrate !== null ? Math.round(bitrate) : null;
|
|
171
173
|
}
|
|
172
174
|
} catch (e) {
|
|
173
175
|
/* ignore */
|
|
@@ -181,13 +183,14 @@ export default class VideojsTracker extends nrvideo.VideoTracker {
|
|
|
181
183
|
|
|
182
184
|
// VHS stats.bandwidth
|
|
183
185
|
if (tech?.vhs?.stats?.bandwidth && tech.vhs.stats.bandwidth > 0) {
|
|
184
|
-
return tech.vhs.stats.bandwidth;
|
|
186
|
+
return Math.round(tech.vhs.stats.bandwidth);
|
|
185
187
|
}
|
|
186
188
|
|
|
187
189
|
// Fallback to tech wrappers (Shaka/Hls.js)
|
|
188
190
|
const techWrapper = this.getTech();
|
|
189
191
|
if (techWrapper?.getSegmentDownloadBitrate) {
|
|
190
|
-
|
|
192
|
+
const bitrate = techWrapper.getSegmentDownloadBitrate();
|
|
193
|
+
return bitrate !== null ? Math.round(bitrate) : null;
|
|
191
194
|
}
|
|
192
195
|
} catch (err) {
|
|
193
196
|
/* ignore */
|
|
@@ -199,13 +202,14 @@ export default class VideojsTracker extends nrvideo.VideoTracker {
|
|
|
199
202
|
const tech = this.player.tech({ IWillNotUseThisInPlugins: true });
|
|
200
203
|
|
|
201
204
|
if (tech?.vhs?.throughput && tech.vhs.throughput > 0) {
|
|
202
|
-
return tech.vhs.throughput;
|
|
205
|
+
return Math.round(tech.vhs.throughput);
|
|
203
206
|
}
|
|
204
207
|
|
|
205
208
|
// Fallback to tech wrapper implementation
|
|
206
209
|
const techWrapper = this.getTech();
|
|
207
210
|
if (techWrapper?.getNetworkDownloadBitrate) {
|
|
208
|
-
|
|
211
|
+
const bitrate = techWrapper.getNetworkDownloadBitrate();
|
|
212
|
+
return bitrate !== null ? Math.round(bitrate) : null;
|
|
209
213
|
}
|
|
210
214
|
|
|
211
215
|
return null;
|
|
@@ -318,6 +322,21 @@ export default class VideojsTracker extends nrvideo.VideoTracker {
|
|
|
318
322
|
|
|
319
323
|
onDownload(e) {
|
|
320
324
|
this.sendDownload({ state: e.type });
|
|
325
|
+
|
|
326
|
+
// Check if MediaTailor should be used after the source is loaded
|
|
327
|
+
// Only check on 'loadstart' to avoid multiple checks
|
|
328
|
+
if (
|
|
329
|
+
!this.adsTracker &&
|
|
330
|
+
e.type === 'loadstart' &&
|
|
331
|
+
MediaTailorAdsTracker.isUsing(this.player)
|
|
332
|
+
) {
|
|
333
|
+
console.log(
|
|
334
|
+
'VideojsTracker: Creating MediaTailorAdsTracker after source load'
|
|
335
|
+
);
|
|
336
|
+
this.setAdsTracker(new MediaTailorAdsTracker(this.player, this.options));
|
|
337
|
+
// MediaTailor SSAI starts with content, not ads (unlike client-side ad frameworks)
|
|
338
|
+
this.adsTracker.setIsAd(false);
|
|
339
|
+
}
|
|
321
340
|
}
|
|
322
341
|
|
|
323
342
|
// DAI methods
|
|
@@ -369,15 +388,35 @@ export default class VideojsTracker extends nrvideo.VideoTracker {
|
|
|
369
388
|
this.FreewheelAdsCompleted = true;
|
|
370
389
|
}
|
|
371
390
|
|
|
391
|
+
/**
|
|
392
|
+
* Check if ads tracker is currently in ad mode
|
|
393
|
+
* @returns {boolean} True if ads are playing
|
|
394
|
+
*/
|
|
395
|
+
isAdsTrackerActive() {
|
|
396
|
+
return this.adsTracker && this.adsTracker.isAd && this.adsTracker.isAd();
|
|
397
|
+
}
|
|
398
|
+
|
|
372
399
|
onPlay() {
|
|
373
400
|
this.sendRequest();
|
|
374
401
|
}
|
|
375
402
|
|
|
376
403
|
onPause() {
|
|
404
|
+
// Don't send CONTENT_PAUSE if ads are playing (ads tracker handles it)
|
|
405
|
+
if (this.isAdsTrackerActive()) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
// Don't send CONTENT_PAUSE if video has ended (CONTENT_END will be sent instead)
|
|
409
|
+
if (this.player.ended()) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
377
412
|
this.sendPause();
|
|
378
413
|
}
|
|
379
414
|
|
|
380
415
|
onPlaying() {
|
|
416
|
+
// Don't send CONTENT_RESUME if ads are playing (ads tracker handles it)
|
|
417
|
+
if (this.isAdsTrackerActive()) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
381
420
|
this.sendResume();
|
|
382
421
|
this.sendBufferEnd();
|
|
383
422
|
}
|
|
@@ -402,10 +441,18 @@ export default class VideojsTracker extends nrvideo.VideoTracker {
|
|
|
402
441
|
}
|
|
403
442
|
|
|
404
443
|
onSeeking() {
|
|
444
|
+
// Don't send CONTENT_SEEK_START if ads are playing (ads tracker handles it)
|
|
445
|
+
if (this.isAdsTrackerActive()) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
405
448
|
this.sendSeekStart();
|
|
406
449
|
}
|
|
407
450
|
|
|
408
451
|
onSeeked() {
|
|
452
|
+
// Don't send CONTENT_SEEK_END if ads are playing (ads tracker handles it)
|
|
453
|
+
if (this.isAdsTrackerActive()) {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
409
456
|
this.sendSeekEnd();
|
|
410
457
|
}
|
|
411
458
|
|
|
@@ -420,6 +467,10 @@ export default class VideojsTracker extends nrvideo.VideoTracker {
|
|
|
420
467
|
}
|
|
421
468
|
|
|
422
469
|
onWaiting(e) {
|
|
470
|
+
// Don't send CONTENT_BUFFER_START if ads are playing (ads tracker handles it)
|
|
471
|
+
if (this.isAdsTrackerActive()) {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
423
474
|
this.sendBufferStart();
|
|
424
475
|
}
|
|
425
476
|
|
|
@@ -439,4 +490,5 @@ export {
|
|
|
439
490
|
ImaAdsTracker,
|
|
440
491
|
BrightcoveImaAdsTracker,
|
|
441
492
|
FreewheelAdsTracker,
|
|
493
|
+
MediaTailorAdsTracker,
|
|
442
494
|
};
|