Note that `pa_buffer_attr.tlength` is in bytes, not frames (see
`/usr/include/pulse/def.h`). I think the previous code asked for a
buffer that is 1/8 what the latency calculation wants (for float32
stereo), resulting in too frequent write callbacks, higher wakeup/CPU
churn, higher risk of crackles under load.
There's no guarantee that the PlaybackStream will always live as long
as the control thread, but we don't actually need the PlaybackStream in
any of the tasks.
This is an attempt to fix a null deref in test-web, but the issue is
very rare, so it is unconfirmed. The call to InternalState->exit()
should most likely prevent such a UAF, but it's not correct to hold
a weak reference to the PlaybackStream anyway.
Since the UAF happens either rarely or not at all due to the mutexes
involved, testing this doesn't appear to be possible.
Implement PlaybackStream using WASAPI. The design is similar to
PlaybackStreamAudioUnit in that it uses a task queue. A high priority
thread is used to render the stream. All the stream controls save for
the exit being requested which happens on destruction of the stream are
managed by the render thread.
Due to the design of the windows audio mixer the audio we receive must
be resampled to match the sample rate of the mixer. We use a float based
interleaved PCM stream which matches both our existing code and the
audio mixer which internally usues floats.
Having to use a mutex around a queue for the task queue is suboptimal,
in a future PR a MPSC queue could be added to AK and used instead.
Instead of specifying the sample rate, channel count/map, etc. to the
PlaybackStream, we'll now use the output device's sample specification
whenever possible. If necessary, the stream will fall back to sane
default.
This hugely simplifies AudioMixingSink, since it no longer has to take
care of reinitializing the stream with a new sample specification when
it encounters a track with a higher sample rate or more channels. We
wouldn't be likely to benefit from this anyway, since it turns out that
at least Windows's virtual surround doesn't work through WASAPI at all,
and WASAPI likely wouldn't support downmixing.
This commit breaks playback of audio files that don't match the system
default audio device's sample rate and channel count. The next commit
introduces a converter into the pipeline to allow mixing of any sample
specification.
We were already assuming that our streams were using floats, we may as
well hardcode this. If we ever encounter a platform API that doesn't
support or convert from float, we can always bring this back.
Also, since we don't support big-endian systems, remove that check in
PulseAudioWrappers.
The Android build is likely bitrotted, and breaking changes need to be
made to the PlaybackStream interface. This should be reverted and the
implementation updated if the Android build is maintained again.
Audio blocks now contain a sample specification with the sample rate
and channel map for the audio data they contain. This will facilitate
conversion from one sample specification to another in order to allow
playback on devices with more or less speakers than the audio data
contains.
We can't control whether the instantiation mutex is held when
~Weakable() is called, so we need to implement this via a static raw
pointer instead to ensure that all operations on it are effectively
atomic.
We should be fine to just fall back to zero or the last returned value
if we encounter an error in PlaybackStream::total_time_played(), and
this also simplifies the using code.
The SharedSingleProducerCircularQueue used here has dubious value, This
queue is used to pass commands to the audio thread, such as play/pause/
seek/volume change/etc. We can make do with a simple locked vector, as
we were blocking to enqueue tasks anyways. We can also use an atomic
bool to tell the audio thread when it needs to take a lock on the task
queue, to keep the thread lock-free most of the time.
Instead of having to duplicate the audio stream backend conditions, just
define PlaybackStream::create in each audio backend implementation file.
We provide a weak definition in PlaybackStream.cpp as the fallback.