Priming has side effects:
Creating a VoiceProcessingIO unit will automatically configure the
default devices for voice processing, which can have these side effects:
- builtin mic as default input switches from one channel to three
- bluetooth device as input switches its profile to handsfree, making
output mono
This makes us avoid getting raw (non-vpio) data from devices that may
sound bad when they are hooked up to vpio elsewhere on the system (by us
or other apps). Case in point: 14" M2 Macbook Pro built-in mic exposes
three channels instead of one in the setup described above, all channels
with very low volume compared to a vpio setup, or to a raw setup with no
vpio present elsewhere.
Creating the vpio unit takes a long time. This commit lets clients
create the shared vpio unit async on a background thread ahead of time,
so that when they need it it is already available for reuse.
It allows at most one vpio duplex stream per context, which is hopefully
enough for all real-world use cases.
Note that Gecko could create at most one duplex stream per document, and
there could in theory be multiple documents per context, which is a
content process singleton.
With vpio priming devices may be queried for channel count with a vpio
unit around, where they previously wouldn't. The vpio unit existing
means output devices may list an extra (input) tap stream. This patch
filters out away streams having anything but the most common input
terminal types.
This is to avoid platform bugs resulting in deadlocks and races.
It tries to serialize all operations on top of a single serial queue,
though probably doesn't cover all. One notable exception is operations
in tests that expect a panic, since panics are not forwarded to the
calling thread.
Per the Apple docs:
> As a performance optimization, this function executes blocks on the
> current thread whenever possible, with one exception: Blocks submitted
> to the main dispatch queue always run on the main thread.
This allows nesting serial queues to ensure all operations are
serialized (the top queue) while also ensuring a stream- or
context-specific queue cannot run any tasks once its owner has been
dropped.