The Apple AGC has been observed to not amplify an overall low-volume
input signal (e.g. when the device has a volume control in hw). Perhaps
that is good enough for most cases. We'd rather make sure that if AGC is
requested we only apply one AGC algorithm, and if no AGC is requested we
do not apply any AGC algorithm.
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
--> src/backend/tests/parallel.rs:456:44
|
456 | let context = unsafe { &mut *(context_ptr_value as *mut AudioUnitContext) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
= note: even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get`
= note: `#[deny(invalid_reference_casting)]` on by default
Instead of allowing only explicitly recognized terminal types, this
patch makes INPUT_UNDEFINED explicitly ignored and everything else
allowed. Unrecognized terminal types will still be logged as before.
Background for this change is https://bugzilla.mozilla.org/show_bug.cgi?id=1870678
To avoid limiting non-voice duplex cases to MONO output, only use the
VPIO AudioUnit when the VOICE stream pref is specified for the input
stream.
This makes non-voice cases (in Firefox this is cases where getUserMedia
was called for audio with all processing constraints set to false)
susceptible to the "robotic voice" drift issue, but non-voice should be
a corner case, so impact is deemed low.
Range.enumerate() cannot go backwards, so with this patch we use a
forwards range instead, and reverse it.
Also, to ensure the upmixed audio fits in the internal buffer, this
patch ensures we resize it to the output format instead of the stored
format (pre-upmix).
With VPIO, all output streams other than the one of the VPIO AudioUnit
itself, on the VPIO output device, are ducked, i.e., their volume is
statically reduced.
From manual testing on MacOS 14 it seems creation of the VPIO AudioUnit
causes ducking of all output streams across all devices. After setting
the output device on the VPIO AudioUnit, ducking is automatically undone
on all output streams except for those on the VPIO output device.
On MacOS 10.15, system logs show the same ducking on creation, and an
additional ducking being applied when initializing the VPIO AudioUnit.
With no control surface to control ducking for now, manually undo it on
the VPIO output device after the VPIO AudioUnit has been initialized.
The cubeb API must not put a restriction on the output stream's channel
count. This is also ensured by the cubeb repo's gtests. This commit
adds an equivalent of the stream_init bit of the relevant test there,
to cubeb-coreaudio-rs.
test_suspend_duplex_stream_by_unplugging_a_nondefault_input_device has
been around a while but wasn't run because it was marked with #[ignore].
It seems like the intention was that it should run, so this patch
enables it.
Tap streams can create additional input streams on devices, leading
to higher-than-expected channels on the audio unit stream format. Use
the already filtered get_channel_count instead.
The VoiceProcessingIO audio unit cannot return the channel layout
for its output device. With this patch, in case we are using vpio,
we try to use a dedicated AudioUnit for the output device and query
that, like we would have queried the regular output unit.
With VPIO, output devices may get a Tap stream, basically adding an
input AudioStream to the output device. To avoid enumerating
output-only devices as input devices, we ignore these channels.
The drift correction provided by aggregate devices has proven unreliable
as a usb input paired with builtin or connected analog speakers often
underruns within a few minutes, depending on clock drift.
The VoiceProcessingIO AudioUnit handles drift properly.
This patch will try to set up the VoiceProcessingIO AudioUnit whenever
we're in duplex. This patch also sets up a failover path so that if setting up
the VoiceProcessingIO AudioUnit fails, we try an aggregate device or a plain
AudioUnit, in that order.
For now, always in bypass mode, as we don't yet have an api to toggle
audio processing features dynamically. Note that the VoiceProcessingIO
AudioUnit will implicitly enable audio ducking in the platform.
This patch is needed because of a race where some tests init a stream
with a null data callback and immediately destroy the stream. With VPIO
a race is triggered where sometimes there would occur a data callback.
The resampler however, cannot handle a null data callback, so it crashes
on a nullptr deref.
This patch also rejects stream_init when no stream parameters are passed
in, and adjusts tests to exercise all these code paths.
This commit does not change behavior of get_channel_count. But it
changes it from counting channels on a device's stream configuration,
which is essentially a list of stream descriptions, to counting channels
by enumerating streams and querying them for their format. This will
help filter out Tap input streams from output devices in a future
commit.
Per CoreAudio/AudioHardwareBase.h:
> AudioStream is a subclass of AudioObject and has only the single scope,
> kAudioObjectPropertyScopeGlobal. They have a main element and an element for
> each channel in the stream numbered upward from 1.
The output callback reads self.input_unit, whereas close() writes
self.input_unit before stopping the output unit (and its callback).
This commit defers any write operations on self's unit members until
both units have been stopped.
Some device-change tests are prone to intermittents as they rely on
waiting for async events by sleeping the current thread for some
arbitrary time.
This patch rewrites Watcher<T> and friends to use a Mutex and a Condvar
instead of an atomic. The new pattern is that the signaling bit of the
code, typically a callback, grabs the mutex, changes some state and
notifies the test thread through the condvar. This means the test thread
can block on the mutex, and wait on the condvar as needed. The watcher
uses existing condvar functions to support waiting until a predicate is
no longer true, and doing the same thing with a timeout. One has to be
wary of deadlocks, but this is test-only non-critical code so generally
speaking fine.
Without this patch if we try to make a device the default input device,
while that does not have an effect, we'll hang waiting for a
device-change event that never comes.
This is possible because with VPIO and Taps there is no fully
deterministic way to determine what is a valid input device.
Testing locally on MacOS 14 there appears to be no devicechange events
when the pluggable (aggregate) device used for tests is private.
It seems logical that there are no devicechange events for a device that
does not get exposed to other apps, and the app that created/destroyed
it should know that it did, indeed, create or destroy it.