Source: lib/media/time_ranges_utils.js

  1. /**
  2. * @license
  3. * Copyright 2016 Google Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. goog.provide('shaka.media.TimeRangesUtils');
  18. /**
  19. * @namespace shaka.media.TimeRangesUtils
  20. * @summary A set of utility functions for dealing with TimeRanges objects.
  21. */
  22. /**
  23. * Gets the first timestamp in buffer.
  24. *
  25. * @param {TimeRanges} b
  26. * @return {?number} The first buffered timestamp, in seconds, if |buffered|
  27. * is non-empty; otherwise, return null.
  28. */
  29. shaka.media.TimeRangesUtils.bufferStart = function(b) {
  30. if (!b) return null;
  31. // Workaround Safari bug: https://goo.gl/EDRCoZ
  32. if (b.length == 1 && b.end(0) - b.start(0) < 1e-6) return null;
  33. // Workaround Edge bug: https://goo.gl/BtxKgb
  34. if (b.length == 1 && b.start(0) < 0) return 0;
  35. return b.length ? b.start(0) : null;
  36. };
  37. /**
  38. * Gets the last timestamp in buffer.
  39. *
  40. * @param {TimeRanges} b
  41. * @return {?number} The last buffered timestamp, in seconds, if |buffered|
  42. * is non-empty; otherwise, return null.
  43. */
  44. shaka.media.TimeRangesUtils.bufferEnd = function(b) {
  45. if (!b) return null;
  46. // Workaround Safari bug: https://goo.gl/EDRCoZ
  47. if (b.length == 1 && b.end(0) - b.start(0) < 1e-6) return null;
  48. return b.length ? b.end(b.length - 1) : null;
  49. };
  50. /**
  51. * Determines if the given time is inside a buffered range. This includes gaps,
  52. * meaning if the playhead is in a gap, it is considered buffered.
  53. *
  54. * @param {TimeRanges} b
  55. * @param {number} time
  56. * @return {boolean}
  57. */
  58. shaka.media.TimeRangesUtils.isBuffered = function(b, time) {
  59. if (!b || !b.length) return false;
  60. // Workaround Safari bug: https://goo.gl/EDRCoZ
  61. if (b.length == 1 && b.end(0) - b.start(0) < 1e-6) return false;
  62. return time >= b.start(0) && time <= b.end(b.length - 1);
  63. };
  64. /**
  65. * Computes how far ahead of the given timestamp is buffered. To provide smooth
  66. * playback while jumping gaps, we don't include the gaps when calculating this.
  67. * This only includes the amount of content that is buffered.
  68. *
  69. * @param {TimeRanges} b
  70. * @param {number} time
  71. * @return {number} The number of seconds buffered, in seconds, ahead of the
  72. * given time.
  73. */
  74. shaka.media.TimeRangesUtils.bufferedAheadOf = function(b, time) {
  75. if (!b || !b.length) return 0;
  76. // Workaround Safari bug: https://goo.gl/EDRCoZ
  77. if (b.length == 1 && b.end(0) - b.start(0) < 1e-6) return 0;
  78. // NOTE: On IE11, buffered ranges may show appended data before the associated
  79. // append operation is complete.
  80. // We calculate buffered amount by ONLY accounting for the content buffered
  81. // (i.e. we ignore the times of the gaps). We also buffer through all gaps.
  82. // So start at the end and add up all buffers until |time|.
  83. var result = 0;
  84. for (var i = b.length - 1; i >= 0 && b.end(i) > time; --i) {
  85. result += b.end(i) - Math.max(b.start(i), time);
  86. }
  87. return result;
  88. };
  89. /**
  90. * Determines if the given time is inside a gap between buffered ranges. If it
  91. * is, this returns the index of the buffer that is *ahead* of the gap.
  92. *
  93. * @param {TimeRanges} b
  94. * @param {number} time
  95. * @return {?number} The index of the buffer after the gap, or null if not in a
  96. * gap.
  97. */
  98. shaka.media.TimeRangesUtils.getGapIndex = function(b, time) {
  99. if (!b || !b.length) return null;
  100. // Workaround Safari bug: https://goo.gl/EDRCoZ
  101. if (b.length == 1 && b.end(0) - b.start(0) < 1e-6) return null;
  102. // IE/Edge stops 0.5 seconds before a gap, so it needs a much larger
  103. // threshold, but we don't want to punish other browsers that stop closer.
  104. // See: https://goo.gl/cuAcYd
  105. var threshold = 0.1;
  106. if (/(Edge\/|Trident\/|Tizen)/.test(navigator.userAgent))
  107. threshold = 0.5;
  108. for (var i = 0; i < b.length; i++) {
  109. if (b.start(i) > time && (i == 0 || b.end(i - 1) - time <= threshold)) {
  110. return i;
  111. }
  112. }
  113. return null;
  114. };