Could anyone explain the difference between the two SourceBuffer
events and when to use one over the other? The W3C spec is confusing to me because it reads like the same thing ("completed" vs "ended"):
Testing with the following code below. Chrome fires the error
event, Firefox does not:
const tests = {
// 64K of invalid bytes
'Invalid Bytes': new Int8Array(1024 * 64),
// valid WebM Opus header bytes (from a random file)
'Valid Header Bytes': new Uint8Array([26,69,223,163,1,0,0,0,0,0,0,31,66,134,129,1,66,247,129,1,66,242,129,4,66,243,129,8,66,130,132,119,101,98,109,66,135,129,4,66,133,129,2,24,83,128,103,1,0,0,0,0,0,217,18,17,77,155,116,64,29,77,187,139,83,171,132,21,73,169,102,83,172,129,223,77,187,140,83,171,132,22,84,174,107,83,172,130,1,48,236,1,0,0,0,0,0,0,179,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,73,169,102,1,0,0,0,0,0,0,69,42,215,177,131,15,66,64,77,128,141,76,97,118,102,53,54,46,52,48,46,49,48,49,87,65,141,76,97,118,102,53,54,46,52,48,46,49,48,49,115,164,144,52,234,234,126,227,12,45,154,239,221,105,21,212,101,42,213,68,137,136,64,184,70,0,0,0,0,0,22,84,174,107,1,0,0,0,0,0,0,98,174,1,0,0,0,0,0,0,89,215,129,1,115,197,129,1,156,129,0,34,181,156,131,117,110,100,134,134,65,95,79,80,85,83,86,170,131,99,46,160,86,187,132,4,196,180,0,131,129,2,225,1,0,0,0,0,0,0,17,159,129,2,181,136,64,231,112,0,0,0,0,0,98,100,129,16,99,162,147,79,112,117,115,72,101,97,100,1,2,56,1,128,187,0,0,0,0,0])
};
(async () => {
for (let testName of Object.keys(tests)) {
console.group(testName);
await testSourceBuffer(tests[testName])
console.groupEnd();
};
console.log('All tests done!');
})()
async function testSourceBuffer(byteArray) {
return new Promise(resolve => {
const audio = new Audio();
const mediaSource = new MediaSource();
// debug other MediaSource Events
['sourceended', 'sourceclose'].forEach(name => {
mediaSource.addEventListener(name, e => {
console.log('MediaSource', e.type);
if (e.type === 'sourceended') {
resolve();
}
})
})
mediaSource.onsourceopen = e => {
console.log('MediaSource', e.type);
URL.revokeObjectURL(audio.src);
const sourceBuffer = mediaSource.addSourceBuffer('audio/webm; codecs=opus');
// debug SoruceBuffer events
['abort', 'error', 'update', 'updateend', 'updatestart'].forEach(name => {
sourceBuffer.addEventListener(name, e => {
const color = e.type === 'error'? 'color: red' : ''
console.log(`%cSourceBuffer ${name}`, color);
if (e.type === 'updateend') {
if (mediaSource.readyState === 'open') {
mediaSource.endOfStream();
}
}
})
})
sourceBuffer.appendBuffer(byteArray);
}
audio.src = URL.createObjectURL(mediaSource)
});
}
The difference lies in the success of the completion.
The update
event is only fired when either the append or removal operations did succeed, while updateend
is also fired when there has been an error while appending, or when the operation has been aborted.