Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: exceeding the buffering quota #75

Merged
merged 2 commits into from
Apr 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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}