Source: lib/media/region_timeline.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.media.RegionTimeline');
  7. goog.require('shaka.util.FakeEvent');
  8. goog.require('shaka.util.FakeEventTarget');
  9. goog.require('shaka.util.IReleasable');
  10. goog.require('shaka.util.Timer');
  11. /**
  12. * The region timeline is a set of unique timeline region info entries. When
  13. * a new entry is added, the 'regionadd' event will be fired. When an entry is
  14. * deleted, the 'regionremove' event will be fired.
  15. *
  16. * @implements {shaka.util.IReleasable}
  17. * @final
  18. */
  19. shaka.media.RegionTimeline = class extends shaka.util.FakeEventTarget {
  20. /**
  21. * @param {!function():{start: number, end: number}} getSeekRange
  22. */
  23. constructor(getSeekRange) {
  24. super();
  25. /** @private {!Set.<shaka.extern.TimelineRegionInfo>} */
  26. this.regions_ = new Set();
  27. /** @private {!function():{start: number, end: number}} */
  28. this.getSeekRange_ = getSeekRange;
  29. /**
  30. * Make sure all of the regions we're tracking are within the
  31. * seek range or further in the future. We don't want to store
  32. * regions that fall before the start of the seek range.
  33. *
  34. * @private {shaka.util.Timer}
  35. */
  36. this.filterTimer_ = new shaka.util.Timer(() => {
  37. this.filterBySeekRange_();
  38. }).tickEvery(
  39. /* seconds= */ shaka.media.RegionTimeline.REGION_FILTER_INTERVAL);
  40. }
  41. /** @override */
  42. release() {
  43. this.regions_.clear();
  44. this.filterTimer_.stop();
  45. super.release();
  46. }
  47. /**
  48. * @param {shaka.extern.TimelineRegionInfo} region
  49. */
  50. addRegion(region) {
  51. const similarRegion = this.findSimilarRegion_(region);
  52. // Make sure we don't add duplicate regions. We keep track of this here
  53. // instead of making the parser track it.
  54. if (similarRegion == null) {
  55. this.regions_.add(region);
  56. const event = new shaka.util.FakeEvent('regionadd', new Map([
  57. ['region', region],
  58. ]));
  59. this.dispatchEvent(event);
  60. }
  61. }
  62. /**
  63. * @private
  64. */
  65. filterBySeekRange_() {
  66. const seekRange = this.getSeekRange_();
  67. for (const region of this.regions_) {
  68. // Only consider the seek range start here.
  69. // Future regions might become relevant eventually,
  70. // but regions that are in the past and can't ever be
  71. // seeked to will never come up again, and there's no
  72. // reson to store or process them.
  73. if (region.endTime < seekRange.start) {
  74. this.regions_.delete(region);
  75. const event = new shaka.util.FakeEvent('regionremove', new Map([
  76. ['region', region],
  77. ]));
  78. this.dispatchEvent(event);
  79. }
  80. }
  81. }
  82. /**
  83. * Find a region in the timeline that has the same scheme id uri, event id,
  84. * start time and end time. If these four parameters match, we assume it
  85. * to be the same region. If no similar region can be found, |null| will be
  86. * returned.
  87. *
  88. * @param {shaka.extern.TimelineRegionInfo} region
  89. * @return {?shaka.extern.TimelineRegionInfo}
  90. * @private
  91. */
  92. findSimilarRegion_(region) {
  93. for (const existing of this.regions_) {
  94. // The same scheme ID and time range means that it is similar-enough to
  95. // be the same region.
  96. const isSimilar = existing.schemeIdUri == region.schemeIdUri &&
  97. existing.id == region.id &&
  98. existing.startTime == region.startTime &&
  99. existing.endTime == region.endTime;
  100. if (isSimilar) {
  101. return existing;
  102. }
  103. }
  104. return null;
  105. }
  106. /**
  107. * Get an iterable for all the regions in the timeline. This will allow
  108. * others to see what regions are in the timeline while not being able to
  109. * change the collection.
  110. *
  111. * @return {!Iterable.<shaka.extern.TimelineRegionInfo>}
  112. */
  113. regions() {
  114. return this.regions_;
  115. }
  116. };
  117. /** @const {number} */
  118. shaka.media.RegionTimeline.REGION_FILTER_INTERVAL = 2; // in seconds