@newrelic/video-videojs 4.1.0 → 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.
@@ -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
- return (
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;
@@ -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
  }
@@ -13,7 +13,8 @@ export default class ShakaTech {
13
13
 
14
14
  getRenditionBitrate(tech) {
15
15
  try {
16
- return this.tech.getStats().streamBandwidth;
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
- return (
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
- return techWrapper.getBitrate();
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
- return techWrapper.getManifestBitrate();
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
- return techWrapper.getSegmentDownloadBitrate();
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
- return techWrapper.getNetworkDownloadBitrate();
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
  };