Support audio worklets
This commit is contained in:
parent
9c26df784d
commit
880fd39ea9
81
blarf.js
81
blarf.js
@ -16,47 +16,65 @@
|
|||||||
var CanvCtx = Canvus.getContext("2d")
|
var CanvCtx = Canvus.getContext("2d")
|
||||||
|
|
||||||
var AudCtx
|
var AudCtx
|
||||||
var AudScript
|
var AudScript, AudWorklet
|
||||||
var AudHz
|
var AudHz
|
||||||
|
|
||||||
function create_audio(hz, channels) {
|
function create_audio(hz, channels) {
|
||||||
if(AudCtx) {
|
if(AudCtx) {
|
||||||
AudCtx.close()
|
AudCtx.close()
|
||||||
|
AudScript = null
|
||||||
|
AudWorklet = null
|
||||||
}
|
}
|
||||||
|
|
||||||
AudHz = hz
|
AudHz = hz
|
||||||
|
|
||||||
|
var DebugSine = 0
|
||||||
|
|
||||||
AudCtx = new AudioContext({sampleRate: hz})
|
AudCtx = new AudioContext({sampleRate: hz})
|
||||||
AudScript = AudCtx.createScriptProcessor(1024, channels, channels)
|
|
||||||
AudScript.onaudioprocess = function(e) {
|
if(AudCtx.audioWorklet) {
|
||||||
var outL = e.outputBuffer.getChannelData(0)
|
AudCtx.audioWorklet.addModule("rawpcmworklet.js").then(function() {
|
||||||
var outR = channels > 1 ? e.outputBuffer.getChannelData(1) : null
|
AudWorklet = new AudioWorkletNode(AudCtx, "rawpcmworklet", {
|
||||||
|
outputChannelCount: [2]
|
||||||
var leftToWrite = outL.length
|
})
|
||||||
var offset = 0
|
AudWorklet.connect(AudCtx.destination)
|
||||||
|
})
|
||||||
while(AudioQueue.length && leftToWrite) {
|
} else {
|
||||||
var amount = Math.min(leftToWrite, AudioQueue[0].left.length)
|
AudScript = AudCtx.createScriptProcessor(4096, channels, channels)
|
||||||
|
AudScript.onaudioprocess = function(e) {
|
||||||
|
var outL = e.outputBuffer.getChannelData(0)
|
||||||
|
var outR = channels > 1 ? e.outputBuffer.getChannelData(1) : null
|
||||||
|
|
||||||
outL.set(AudioQueue[0].left.subarray(0, amount), offset)
|
/*for(var i = 0; i < outL.length; i++) {
|
||||||
if(outR) outR.set(AudioQueue[0].right.subarray(0, amount), offset)
|
outL[i] = Math.sin(440 * 2 * 3.14159 * (DebugSine / AudHz))
|
||||||
|
DebugSine++
|
||||||
AudioQueue[0].left = AudioQueue[0].left.subarray(amount)
|
|
||||||
if(outR) AudioQueue[0].right = AudioQueue[0].right.subarray(amount)
|
|
||||||
|
|
||||||
if(AudioQueue[0].left.length == 0) {
|
|
||||||
AudioQueue.shift()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
leftToWrite -= amount
|
AudioQueue = []
|
||||||
offset += amount
|
return*/
|
||||||
}
|
|
||||||
|
var leftToWrite = outL.length
|
||||||
if(RenderStartTime && leftToWrite) {
|
var offset = 0
|
||||||
buffering(1000)
|
|
||||||
|
while(AudioQueue.length && leftToWrite) {
|
||||||
|
var amount = Math.min(leftToWrite, AudioQueue[0].left.length)
|
||||||
|
|
||||||
|
outL.set(AudioQueue[0].left.subarray(0, amount), offset)
|
||||||
|
if(outR) outR.set(AudioQueue[0].right.subarray(0, amount), offset)
|
||||||
|
|
||||||
|
AudioQueue[0].left = AudioQueue[0].left.subarray(amount)
|
||||||
|
if(outR) AudioQueue[0].right = AudioQueue[0].right.subarray(amount)
|
||||||
|
|
||||||
|
if(AudioQueue[0].left.length == 0) {
|
||||||
|
AudioQueue.shift()
|
||||||
|
}
|
||||||
|
|
||||||
|
leftToWrite -= amount
|
||||||
|
offset += amount
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
AudScript.connect(AudCtx.destination)
|
||||||
}
|
}
|
||||||
AudScript.connect(AudCtx.destination)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var LastControlsInterrupt
|
var LastControlsInterrupt
|
||||||
@ -149,11 +167,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var VideoBufferingOffset = 0
|
var VideoBufferingOffset = 0
|
||||||
function buffering(millis) {
|
|
||||||
//var silence = new Float32Array(millis * 48);
|
|
||||||
//AudioQueue.push({left: silence, right: silence})
|
|
||||||
//VideoBufferingOffset += millis
|
|
||||||
}
|
|
||||||
|
|
||||||
function toHex(buffer) {
|
function toHex(buffer) {
|
||||||
return Array.prototype.map.call(buffer, x => ('00' + x.toString(16)).slice(-2)).join('');
|
return Array.prototype.map.call(buffer, x => ('00' + x.toString(16)).slice(-2)).join('');
|
||||||
@ -386,6 +399,12 @@
|
|||||||
ws.onmessage = function(ev) {
|
ws.onmessage = function(ev) {
|
||||||
ebml.poosh(new Uint8Array(ev.data))
|
ebml.poosh(new Uint8Array(ev.data))
|
||||||
ebml.parse()
|
ebml.parse()
|
||||||
|
|
||||||
|
// It would make more sense for this to be in `render` but we need the guarantee that this will run when the tab is out of focus
|
||||||
|
if(AudCtx.state == "running" && AudWorklet && AudioQueue.length) {
|
||||||
|
AudWorklet.port.postMessage({msg: "data", audio: AudioQueue})
|
||||||
|
AudioQueue.length = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ws.onclose = function(ev) {
|
ws.onclose = function(ev) {
|
||||||
setTimeout(reconnect_ws, 5000)
|
setTimeout(reconnect_ws, 5000)
|
||||||
|
47
rawpcmworklet.js
Normal file
47
rawpcmworklet.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// To explain succinctly, the people who designed AudioWorklet and
|
||||||
|
// deprecated ScriptProcessorNode are retarded and we need a worklet
|
||||||
|
// that does basically nothing to get glitchless audio.
|
||||||
|
|
||||||
|
class RawPCMWorklet extends AudioWorkletProcessor {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
|
||||||
|
this.left = new Float32Array()
|
||||||
|
this.right = new Float32Array()
|
||||||
|
|
||||||
|
this.port.onmessage = (event) => {
|
||||||
|
var newaudioframes = event.data.audio
|
||||||
|
|
||||||
|
for(var i = 0; i < newaudioframes.length; i++) {
|
||||||
|
var newleft = new Float32Array(this.left.length + newaudioframes[i].left.length)
|
||||||
|
newleft.set(this.left, 0)
|
||||||
|
newleft.set(newaudioframes[i].left, this.left.length)
|
||||||
|
this.left = newleft
|
||||||
|
|
||||||
|
var newright = new Float32Array(this.right.length + newaudioframes[i].right.length)
|
||||||
|
newright.set(this.right, 0)
|
||||||
|
newright.set(newaudioframes[i].right, this.right.length)
|
||||||
|
this.right = newright
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process(inputs, outputs, parameters) {
|
||||||
|
const output = outputs[0]
|
||||||
|
|
||||||
|
var left = output[0]
|
||||||
|
var right = output[1]
|
||||||
|
|
||||||
|
var available = Math.min(left.length, this.left.length)
|
||||||
|
|
||||||
|
left.set(this.left.slice(0, available))
|
||||||
|
right.set(this.right.slice(0, available))
|
||||||
|
|
||||||
|
this.left = this.left.slice(available)
|
||||||
|
this.right = this.right.slice(available)
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerProcessor('rawpcmworklet', RawPCMWorklet);
|
Loading…
Reference in New Issue
Block a user