This week I didn’t write too much code, but did some fixes nonetheless.
Management of the volume of an audio stream on Windows
I started the week with an in-depth exploration of volume handling for an audio output stream on Windows. There are four volume stages when you play anything on Windows, that’s maybe a bit much, but there is:
- Often software developer implement a “volume” slider in their program. Usually this is simply a multiplication between the audio frames and a number between 0 and 1 (or 1.25 in the case of VLC, and that’s really convenient)
- Then there is a server-side input gain in the Windows mixer. This is what an
program should use, instead of the step in 1. 1 This is the
IAudioStreamVolumeinterface. This volume is per stream.
- Then there is a session volume, which is the volume of all stream of a
particular program. For example, Firefox is multiprocess, for security
reasons, but there is only one volume slider in the Windows panel
SndVol.exe), that controls the volumes of all streams being played back. This is
ISimpleAudioVolume. I’m not entirely sure why it’s simple.
- There there is the global system volume (that you adjust in the systray or with your media keys).
All this to change the volume of an audio stream. The more you know 🙃.
What happens when you forget a pair of brackets
Another interesting point this week was that I had written a
web-platform-test with this line of code,
Uint8Array of a few megabytes, maybe from a
call or something:
var url = URL.createObjectURL(new Blob(b, ["audio/ogg"]));
Fairly straightforward, this creates a
Blob from a bit of memory. Except it
doesn’t, it crashes Firefox and Chrome with an
Out Of Memory error.
What happens is that the
Blob constructor is supposed to be an array of parts
that will compose the
Blob. If you pass directly an iterable, then it will
concatenate all the elements of this iterable, and return a
b is iterable (it’s a
Uint8Array after all), and because of type
coercion of WebIDL, that describes how conversion should happen, this
Uint8Array is first converted to an array of
Strings of a single character,
which is the ASCII value for this byte. Because string objects are more than a
byte in size (they include the size, etc.), this is already a waste of memory.
Chrome and Firefox don’t concatenate eagerly (Safari seem to), so you have
thousands of those
Strings. Later the browser creates objects to read from
Strings, again one per byte of the initial array, and
those objects are quite a bit bigger than a single byte again, and this crashes
Out of Memory error.
In the end, I was trying to make a
Blob from a 500kB buffer, and this froze
the browser and used about 350MB (megabytes!) of memory. You don’t even get the
correct result in the end. All the details are in
https://bugzilla.mozilla.org/show_bug.cgi?id=1702447#c6, and the correct code
var url = URL.createObjectURL(new Blob([b], ["audio/ogg"]));
the pair of
 being the key here. Quite a big footgun.
Lots of work on Web Codecs and the Web Audio API this week. The former is cruising along nicely at a rather high speed. I’ve continued my work around timestamps and memory of the last week, this time diving into system APIs for cross-process memory sharing, possibly backed by GPU buffers, which is a space that is moving rather often apparently.
I’ve merged the very last PR to the Web Audio API, here is a short clip of that:
Apparently we’ve done those steps about 946 times since we started using GitHub, but it’s now functionally done. I assume some editorial pull-requests will follow but the normative text won’t change.
The video is not very interesting, but I felt like recording this moment. I will probably print a hard copy of the final version of this specification, keep it on a shelf, and have a look at it when I retire or something.
Not much again. This times, France is in lock-down for real, but apparently not quite? Unclear again.
I bought a ton of music because it was Bandcamp Friday and my budget for music, usually dominated by concert tickets, is going back into records and buying releases on Bandcamp. What I’ve bought this time (and all previous times), is available at https://bandcamp.com/padenot, it’s fairly diverse but mostly electronic music, with some black metal and other types of metal. The beauty of it is that you can listen to all the releases and then maybe buy a couple that you like. Most of the money goes to the label and artists, in between 80% and 93%, and quite a few labels are not taking their cut during those Bandcamp Fridays, so even more go to artists, that can’t really do shows to earn a living.
I’ve bought quite a few releases of Egyptian music, especially from Cairo, and quite a few Gqom releases from Japan and South Africa, some footwork stuff, and then the traditional (for me) techno/jungle/uk things/dubstep releases. Have a listen to All Caps by ZULI if you like a good chopped amen break:
and flashes in time by Fauzia if you don’t:
I like both.
2is really better than
1, in the case of you pause the audio stream, change the volume or mute, and then unpause. With
1you have a short period with the old volume and then the new volume is reflected, because there is frequently some data in the sound server with the old volume that has been pushed already. With
2the volume is applied by the mixer so you potentially save some CPU and touch less memory, and you don’t have this problem. ↩︎