Skip to content

Commit

Permalink
fix: exceeding the buffering quota (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoyuhen authored Apr 18, 2019
1 parent 5f3c621 commit 01134f1
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 9 deletions.
60 changes: 51 additions & 9 deletions packages/griffith-mp4/src/mse/controller.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {ua} from 'griffith-utils'
import FragmentFetch from '../fetch'
import MP4Parse from '../mp4/mp4Parse'
import MP4Probe from '../mp4/mp4Probe'
import FMP4 from '../fmp4/fmp4Generator'
import {concatTypedArray} from '../fmp4/utils'
import {abortPolyfill} from './polyfill'

const MAGIC_NUMBER = 20000

Expand Down Expand Up @@ -60,7 +62,16 @@ export default class MSE {

handleAppendBuffer = (buffer, type) => {
if (this.mediaSource.readyState === 'open') {
this.sourceBuffers[type].appendBuffer(buffer)
try {
this.sourceBuffers[type].appendBuffer(buffer)
} catch (error) {
// see https://developers.google.com/web/updates/2017/10/quotaexceedederror
if (error.name === 'QuotaExceededError') {
this.handleQuotaExceededError(buffer, type)
} else {
throw error
}
}
} else {
this[`${type}Queue`].push(buffer)
}
Expand Down Expand Up @@ -201,22 +212,41 @@ export default class MSE {
changeQuality(newSrc) {
this.src = newSrc
this.qualityChangeFlag = true
this.removeBuffer()

this.init().then(() => {
this.video.currentTime = this.video.currentTime
})
}

removeBuffer() {
// remove old quality buffer before append new quality buffer
for (const key in this.sourceBuffers) {
const track = this.sourceBuffers[key]
const length = track.buffered.length

if (length > 0) {
track.remove(track.buffered.start(0), track.buffered.end(length - 1))
this.removeBuffer(
track.buffered.start(0),
track.buffered.end(length - 1),
key
)
}
}

this.init().then(() => {
this.video.currentTime = this.video.currentTime
})
}

removeBuffer(start, end, type) {
const track = this.sourceBuffers[type]
if (track.updating) {
const {isSafari} = ua

if (isSafari) {
// Safari 9/10/11/12 does not correctly implement abort() on SourceBuffer.
// Calling abort() before appending a segment causes that segment to be
// incomplete in buffer.
// Bug filed: https://bugs.webkit.org/show_bug.cgi?id=165342
abortPolyfill()
}
track.abort()
}
track.remove(start, end)
}

loadData(start = 0, end = MAGIC_NUMBER) {
Expand Down Expand Up @@ -271,4 +301,16 @@ export default class MSE {
this.mediaSource.endOfStream()
}
}

handleQuotaExceededError = (buffer, type) => {
for (const key in this.sourceBuffers) {
const track = this.sourceBuffers[key]

const currentTime = this.video.currentTime
this.removeBuffer(track.buffered.start(0) + 10, currentTime - 10, key)
}

// re-append(maybe should lower the playback resolution)
this.handleAppendBuffer(buffer, type)
}
}
11 changes: 11 additions & 0 deletions packages/griffith-mp4/src/mse/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// copy from https://github.com/google/shaka-player/blob/master/lib/polyfill/mediasource.js#L125
function abortPolyfill() {
const addSourceBuffer = MediaSource.prototype.addSourceBuffer
MediaSource.prototype.addSourceBuffer = function(...varArgs) {
const sourceBuffer = addSourceBuffer.apply(this, varArgs)
sourceBuffer.abort = function() {} // Stub out for buggy implementations.
return sourceBuffer
}
}

export {abortPolyfill}

0 comments on commit 01134f1

Please sign in to comment.