Make use of the sosso library to handle the low-level operation of
OSS devices on FreeBSD. Further separate this part into the
JackOSSChannel class, which should make it easier to reuse the code
for JackOSSAdapter (not planned yet).
JackOSSChannel features an additional assist thread which helps to
process the OSS device when the driver thread is busy with the JACK
dependency graph.
Combined with the improvements of the sosso library, these changes
bring JACK into the realm of real-time audio processing on FreeBSD,
for select PCI sound cards (4-6ms round trip latency).
As a header-only C++ library, synced OSS operation (sosso) is used to
clean up and separate the low-level handling of FreeBSD OSS devices
in JACK. Features include:
* Supports both read() / write() and mmap() IO operation.
* Adaptive polling, better suited for low-latency requirements.
* Internal double buffer to avoid troubles with OSS buffer resize.
* Closely monitors progress and drift for each channel (+/- 1ms).
* Facilitates drift correction through buffer offsets.
* Depends on C++ standard library and system headers, nothing else.
Although the sosso library is somewhat tailored to the needs of JACK,
it was developed separately and will eventually be published and / or
used in other projects. Therefore the headers follow a different
formatting style and are more liberally licensed (ISC).
Including C headers inside of extern "C" breaks use from C++. Hoist
the includes of standard C headers above the block so we don't try
to mangle the stdlib.
See https://gitlab.freedesktop.org/pipewire/pipewire/-/merge_requests/2377 in
PipeWire where they bundle some JACK headers, so came across this.
Per POSIX definition, pthread_cond_timedwait() re-acquires the mutex
when a timeout occurs and ETIMEDOUT is returned. In that case also
mark the waiting thread as owner again, for consistency.
Otherwise subsequent attempts to unlock the mutex will fail, leaving
the mutex locked forever.
This makes waf compatible with Python 3.12 again.
Also, apply modifications needed for MacOS and add as a patch file (see
commits 0f2e3b2 and dc6c995).
Signed-off-by: Nils Philippsen <nils@tiptoe.de>
* Rework the seqmidi aliases.
- The 1st alias is now the Jack1 MIDI port name with alsa_midi prefix.
- This 2nd alias is basically the same as the 1st alias with the
alsa_midi prefix stripped, so that devices are listed under the ALSA
names.
Also fixed the "capture" and "playback" port type names which were the
wrong way round.
* Rework the rawmidi alias.
Like in alsa_seqmidi.c, the 1st alias is now the Jack1 MIDI port name
with alsa_midi prefix.
* Rework pretty-name metadata.
The rawmidi and seqmidi pretty-name metadata now uses the same Jack1
port name as the 1st alias, without the alsa_midi: prefix.
* rework and cleanup CI setup
Signed-off-by: falkTX <falktx@falktx.com>
* continue CI cleanup
Signed-off-by: falkTX <falktx@falktx.com>
* Only use --mixed for win64
Signed-off-by: falkTX <falktx@falktx.com>
---------
Signed-off-by: falkTX <falktx@falktx.com>
* fix ringbuffer thread safety on ARM. fix#715#388
This patch addresses the thread safety problem of `jack_ringbuffer_t`
mentioned in #715 and #388. The overbound read bug caused by this problem
is impossible to reproduce on x86 due to its strong memory ordering, but
it is a problem on ARM and other weakly ordered architectures.
Basically, the main problem is that, on a weakly ordered architecture,
it is possible that the pointer increment after `memcpy` becomes visible
to the other thread before `memcpy` finishes:
memcpy (&(rb->buf[rb->write_ptr]), src, n1);
// vvv can be visible to reading thread before memcpy finishes
rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask;
If this happens, the other thread can read the remaining garbage values
in `rb->buf` due to be overwritten by the unfinished `memcpy`.
To fix this, an explicit pair of release/acquire memory fences [1] is
used to ensure the copy on the other thread *happens after* the `memcpy`
finishes so no garbage values can be read.
[1]: https://preshing.com/20130922/acquire-and-release-fences/
* remove volatile qualifier on ringbuf r/w pointers
The volatile constraints are excess when compiler barriers are present.
It generates unnecessary `mov` instructions when pointers aren't going
to be updated.
* simplify read/write space calculations
This optimization is possible because the buffer size is always a power
of 2. See [1] for details.
[1]: https://github.com/drobilla/zix/pull/1#issuecomment-1212687196
* move acq fences to separate lines
Reduce the base latencies for capture and playback by half a period,
and let the update method account for the additional playback latency
introduced by OSS buffer management.
This fits actual OSS latencies better, so the same settings for the
extra input-latency and output-latency parameters should apply to
different period lengths.
Beware that this change invalidates current input-latency and
output-latency values, they have to be measured again.