-
Notifications
You must be signed in to change notification settings - Fork 5
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
Render the audio #1
Conversation
It's not served with the necessary headers for SAB use.
I was using the wrong |
Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: require-corp Simply run `node server.js`, it binds to 8888 by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great. I had some questions, but feel free to submit whenever you're happy.
if (this.audioContext.outputLatency == undefined) { | ||
// Put appropriate values for Chromium here, not sure what latencies are | ||
// used. Likely OS-dependent, certainly hardware dependant. Assume 40ms. | ||
totalOutputLatency += 0.04; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand the requirement correctly this https://guest271314.github.io/webcodecs/ is how I serialize and deserialize audio with WebCodecs. It is non-trivial resampling the fixed 48000 sample rate that Chromium has hardcoded, especially when the input file is 22050, 1 channel, and I never set Opus encoder sample rate to 48000. |
The rescheduling part can be problematic re glitches and gaps between schedules. One option is to utilize
|
This pushed interleaved data to the ring buffer, and, for now, requires copies, because it's not possible to copy and interleave in one call. The AudioWorkletProcessor then simply deinterleaves into its planar arrays.
…r local development only.
The following adjustments are made: - Don't attempt to fill the ring buffer when not playing - When the ring buffer is full enough, schedule the next decoding attempt in half the time of the remaining audio in the buffer.
What's left to do is to check A/V sync on various OSes, I have only been testing on a Linux desktop with a USB DAC. |
This works well for me in Chrome 94 beta with Web Codecs enabled on my Linux box, here's how it goes:
SharedArrayBuffer
-based ring buffer is given to a very simpleAudioWorkletProcessor
(that reads from it) and the control thread (for now the main thread, but we'll be able to move that to a Web Worker)AudioRenderer
pre-buffers some audio and writes the PCM to this ring buffer, on initialization.AudioContext
starts, theAudioWorkletProcessor
starts to read from this ring buffer to output the audio.AudioRenderer
sees that the ring buffer becomes empty and crosses its threshold for decoding -- it then proceeds to decode some compressed audio and pushes the PCM to the ring buffer. If the threshold isn't reached, it simply re-schedules itself in the future.AudioRenderer
is made viasuspend
ing theAudioContext
, so pause/play is supportedGainNode
and an<input type=range>
-- we get smooth volume ramps for free :-).AudioContext.currentTime
, offset by the output latency, converted to microseconds.But it is only a first cut, this is what I'm planning to fix:
copyTo
variants already, and[AllowShared]
, but in any case I have code lying around to interleave/deinterleave if necessaryAudioContext.outputLatency
in Chrome, see https://blog.paul.cx/post/audio-video-synchronization-with-the-web-audio-api/ for details. For now, I picked a number that was kind of OK for my Linux workstation with my sound card, but YMMV. We'll do something fancier, per platform, in a second step, so it looks goodAudioContext
: no need for extreme low latency here.All the code is in PR is from me originally so no license issue. The ring buffer and the server are from https://github.com/padenot/ringbuf.js, but I've just copied/tweaked the necessary files for this demo.