Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package cava for openSUSE:Factory checked in 
at 2024-02-04 19:07:44
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/cava (Old)
 and      /work/SRC/openSUSE:Factory/.cava.new.1815 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "cava"

Sun Feb  4 19:07:44 2024 rev:18 rq:1143715 version:0.10.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/cava/cava.changes        2024-01-10 
21:52:14.772074691 +0100
+++ /work/SRC/openSUSE:Factory/.cava.new.1815/cava.changes      2024-02-04 
19:07:55.745857351 +0100
@@ -1,0 +2,7 @@
+Fri Feb  2 17:50:51 UTC 2024 - Michael Vetter <mvet...@suse.com>
+
+- Update to 0.10.1:
+  * JACK support
+  * default to pulseaudio before sndio
+
+-------------------------------------------------------------------

Old:
----
  0.10.0.tar.gz

New:
----
  0.10.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ cava.spec ++++++
--- /var/tmp/diff_new_pack.RI6WpD/_old  2024-02-04 19:07:56.281876666 +0100
+++ /var/tmp/diff_new_pack.RI6WpD/_new  2024-02-04 19:07:56.281876666 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           cava
-Version:        0.10.0
+Version:        0.10.1
 Release:        0
 Summary:        Console-based Audio Visualizer for Alsa
 License:        MIT

++++++ 0.10.0.tar.gz -> 0.10.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/Makefile.am new/cava-0.10.1/Makefile.am
--- old/cava-0.10.0/Makefile.am 2024-01-09 19:26:04.000000000 +0100
+++ new/cava-0.10.1/Makefile.am 2024-02-02 18:47:27.000000000 +0100
@@ -53,6 +53,10 @@
     cava_SOURCES += input/oss.c
 endif
 
+if JACK
+    cava_SOURCES += input/jack.c
+endif
+
 if NCURSES
     cava_SOURCES += output/terminal_ncurses.c
 endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/README.md new/cava-0.10.1/README.md
--- old/cava-0.10.0/README.md   2024-01-09 19:26:04.000000000 +0100
+++ new/cava-0.10.1/README.md   2024-02-02 18:47:27.000000000 +0100
@@ -20,8 +20,9 @@
   - [Pipewire](#pipewire)
   - [ALSA](#alsa)
   - [MPD](#mpd)
-  - [sndio](#sndio)
+  - [Sndio](#sndio)
   - [OSS](#oss)
+  - [JACK](#jack)
   - [squeezelite](#squeezelite)
   - [macOS](#macos-1)
   - [Windows](#windows)
@@ -69,7 +70,6 @@
 
 
 Recomended components:
-* [ncursesw dev files](http://www.gnu.org/software/ncurses/) (bundled in 
ncurses in arch)
 
 The development lib of one of these audio frameworks, depending on your distro:
 * ALSA
@@ -77,24 +77,32 @@
 * Pipewire
 * Portaudio
 * Sndio
+* JACK
+
 
 Optional components:
 * SDL2 dev files
+* [ncursesw dev files](http://www.gnu.org/software/ncurses/) (bundled in 
ncurses in arch)
 
-Only FFTW and the other build tools are actually required for CAVA to compile, 
but this will only give you the ability to read from fifo files. To more easly 
grab audio from your system pulseaudio, alsa, sndio or portaudio dev files are 
recommended (depending on what audio system you are using). Not sure how to get 
the pulseaudio dev files for other distros than debian/ubuntu or if they are 
bundled in pulseaudio. 
-
+Only FFTW, iniparser and the build tools are actually required for CAVA to 
compile, but this will only give you the ability to read from fifo files. To 
capture audio directlty from your system pipewire, pulseaudio, alsa, sndio, 
jack or portaudio dev files are required (depending on what audio system you 
are using).
 
-For better a better visual experience ncurses is also recomended.
+Ncurses can be used as an alternative output method if you have issues with 
the default one. But it is not required.
 
 All the requirements can be installed easily in all major distros:
 
 FreeBSD
 
-    pkg install autoconf-archive autotools fftw3 iniparser pkgconf psftools 
sdl2 sndio
+    pkg install autoconf autoconf-archive automake fftw3 iniparser jackit 
libglvnd libtool pkgconf psftools sdl2 sndio
+
+Additionally, run these commands on FreeBSD before building:
+
+    export CFLAGS="-I/usr/local/include"
+    export LDFLAGS="-L/usr/local/lib"
+
 
 Debian/Ubuntu:
 
-    sudo apt install build-essential libfftw3-dev libasound2-dev 
libncursesw5-dev libpulse-dev libtool automake autoconf-archive 
libiniparser-dev libsdl2-2.0-0 libsdl2-dev libpipewire-0.3-dev pkgconf
+    sudo apt install build-essential libfftw3-dev libasound2-dev 
libncursesw5-dev libpulse-dev libtool automake autoconf-archive 
libiniparser-dev libsdl2-2.0-0 libsdl2-dev libpipewire-0.3-dev 
libjack-jackd2-dev pkgconf
 
 
 ArchLinux:
@@ -323,26 +331,78 @@
             buffer_time     "50000"   # (50ms); default is 500000 microseconds 
(0.5s)
     }
 
-### sndio
+### Sndio
 
-sndio is the audio framework used on OpenBSD, but it's also available on
-FreeBSD and Linux. So far this is only tested on FreeBSD.
+Set
+
+    method = sndio
 
-To test it
-```bash
-# Start sndiod with a monitor sub-device
-$ sndiod -dd -s default -m mon -s monitor
-
-# Set the AUDIODEVICE environment variable to override the default
-# sndio device and run cava
-$ AUDIODEVICE=snd/0.monitor cava
+Sndio is the audio framework used on OpenBSD, but it's also available on 
FreeBSD, NetBSD and Linux.
+So far this is only tested on FreeBSD, but it's probably very similar on other 
operating systems. The
+following example demonstrates how to setup CAVA for sndio on FreeBSD (please 
consult the [OSS](#oss)
+section for a deeper explanation of the various `pcmX` sound devices and the 
corresponding `/dev/dspX`
+audio devices in this example).
+```sh
+$ cat /dev/sndstat
+Installed devices:
+pcm0: <Realtek ALC1220 (Rear Analog)> (play/rec) default
+pcm1: <Realtek ALC1220 (Front Analog Mic)> (rec)
+pcm2: <USB audio> (play/rec)
+No devices installed from userspace.
 ```
+Sndio operates on device descriptors. In general for every `/dev/dspX` audio 
device there is a corresponding
+`rsnd/X` sndio raw device descriptor. In this example there are `rsnd/0`, 
`rsnd/1` and `rsnd/2` (they
+are not listed in `/dev`, sndio uses these descriptors to access the 
corresponding audio devices internally).
+Sndio also handles the implicit `default` device descriptor, which acts like a 
symlink to the raw device
+descriptor corresponding to the default audio device `/dev/dsp`. In this 
example it acts like a symlink
+to `rsnd/0` because the default audio device `/dev/dsp` symlinks to 
`/dev/dsp0`. Sndio also evaluates
+the environment variables `AUDIODEVICE` and `AUDIORECDEVICE`. If one of these 
is set (`AUDIORECDEVICE`
+overrides `AUDIODEVICE` if both are set) and a sndio-aware program tries to 
open the `default` device
+descriptor or an unspecified device descriptor, then the program will use the 
device descriptor specified
+in the environment variable.
+
+Now in order to visualize the mic input in CAVA, the `source` value in the 
configuration file must
+be set to the corresponding audio descriptor:
+
+    source = default    # default; symlink to rsnd/0 in this example; 
AUDIORECDEVICE and AUDIODEVICE evaluation
+    source =            # unspecified device descriptor; same as default above
+    source = rsnd/0     # for the pcm0 mic on the rear
+    source = rsnd/1     # for the pcm1 mic on the front
+    source = rsnd/2     # for the pcm2 mic on the USB headset
+
+With `source = default` one can switch the visualization on the commandline 
without changing the configuration
+file again:
+```sh
+$ AUDIODEVICE=rsnd/0 cava
+$ AUDIODEVICE=rsnd/1 cava
+$ AUDIODEVICE=rsnd/2 cava
+```
+Sndio can't record the played back audio with just the raw device descriptors, 
i.e. the sounds from
+a music player or a browser which play on the external stereo speakers through 
`rsnd/0` are not visualized
+in CAVA. For this to work the sndio server has to be started and a monitoring 
sub-device has to be
+created. The following example shows how to start the server and create a 
monitoring sub-device `snd/0`
+from `rsnd/0` and then start CAVA with `AUDIODEVICE` pointing to the new 
monitoring sub-device:
+```sh
+$ sndiod -f rsnd/0 -m play,mon
+$ AUDIODEVICE=snd/0 cava
+```
+Switch between the speakers and the USB headset:
+```sh
+$ sndiod -f rsnd/2 -m play,mon -s usb -f rsnd/0 -m play,mon -s speakers
+$ AUDIODEVICE=snd/usb cava
+$ AUDIODEVICE=snd/speakers cava
+```
+Consult the manpage `sndiod(8)` for further information regarding 
configuration and startup of a sndio
+server.
 
 ### OSS
 
+Set
+
+    method = oss
+
 The audio system used on FreeBSD is the Open Sound System (OSS).
 The following example demonstrates how to setup CAVA for OSS on FreeBSD:
-
 ```sh
 $ cat /dev/sndstat
 Installed devices:
@@ -351,45 +411,35 @@
 pcm2: <USB audio> (play/rec)
 No devices installed from userspace.
 ```
-
 The system has three `pcm` sound devices, `pcm0`, `pcm1` and `pcm2`. `pcm0` 
corresponds to the analog
 output jack on the rear, in which external stereo speakers are plugged in, and 
the analog input jack,
 in which one could plug in a microphone. Because it encapsulates both, output 
and input, it is marked
 as `play/rec`. It is also set as the `default` sound device. `pcm1` 
corresponds to another analog input
-jack for a mic on the front side and is marked `rec`. A USB headset which an 
integrated mic is plugged
+jack for a mic on the front side and is marked `rec`. A USB headset with an 
integrated mic is plugged
 in an USB port and the system has created the `pcm2` sound device with 
`play/rec` capabilities for
 it.
 
 In general for every `pcmX` device there is a corresponding `/dev/dspX` audio 
device. In this example
 there are `/dev/dsp0`, `/dev/dsp1` and `/dev/dsp2` (the system creates them 
when needed, they are not
-listet via `ls /dev` if they are currently not in use). The system also 
creates an implicit `/dev/dsp`,
+listed via `ls /dev` if they are currently not in use). The system also 
creates an implicit `/dev/dsp`,
 which acts like a symlink to the `default` audio device, in this example to 
`/dev/dsp0`.
 
 Now in order to visualize the mic input in CAVA, the `source` value in the 
configuration file must
-be set to the corresponding audio device, i.e.
-```sh
-[input]
-source = /dev/dsp    # or /dev/dsp0 for which /dev/dsp is a symlink in this 
example
-```
-(which is already the default for CAVA) for the `pcm0` mic on the rear, or
-```sh
-[input]
-source = /dev/dsp1
-```
-for the `pcm1` mic on the front, or
-```sh
-[input]
-source = /dev/dsp2
-```
-for the `pcm2` mic on the USB headset.
+be set to the corresponding audio device:
+
+    source = /dev/dsp     # default; symlink to /dev/dsp0 in this example
+    source = /dev/dsp0    # for the pcm0 mic on the rear
+    source = /dev/dsp1    # for the pcm1 mic on the front
+    source = /dev/dsp2    # for the pcm2 mic on the USB headset
 
 OSS can't record the outgoing audio on its own, i.e. the sounds from a music 
player or a browser which
 play on the external stereo speakers through `/dev/dsp0` are not visualized in 
CAVA. A solution is
-to use Virtual OSS. It can create virtual audio devices from existing audio 
devices and from which
-the played back audio can be fed into CAVA:
+to use Virtual OSS. It can create virtual audio devices from existing audio 
devices, in particular
+it can create a loopback audio device from `/dev/dsp0` and from which the 
played back audio can be
+fed into CAVA:
 ```sh
 $ doas pkg install virtual_oss
-$ doas virtual_oss -Q0 -C2 -c2 -r48000 -b16 -s2048 -P /dev/dsp0 -R /dev/null 
-w vdsp.wav -t vdsp.ctl -T /dev/sndstat -l dsp
+$ doas virtual_oss -r44100 -b16 -c2 -s4ms -O /dev/dsp0 -R /dev/null -T 
/dev/sndstat -l dsp.cava
 
 $ cat /dev/sndstat
 Installed devices:
@@ -397,12 +447,95 @@
 pcm1: <Realtek ALC1220 (Front Analog Mic)> (rec)
 pcm2: <USB audio> (play/rec)
 Installed devices from userspace:
-dsp: <Virtual OSS> (play/rec)
+dsp.cava: <Virtual OSS> (play/rec)
 ```
-It created a virtual device `dsp` from `/dev/dsp0`. Now the audio is 
visualized in CAVA with the default
-`source = /dev/dsp` in the configuration file. Virtual OSS can be configured 
and started as a service
-on FreeBSD.
+It created a virtual loopback device `/dev/dsp.cava` from `/dev/dsp0`. Now the 
audio is visualized
+in CAVA with `source = /dev/dsp.cava` in the configuration file. The playback 
program must have a configuration
+to use the `/dev/dsp.cava` device. For programs where this is not possible, 
e.g. which always use `/dev/dsp`,
+replace `-l dsp.cava` with `-l dsp`. Virtual OSS can be configured and started 
as a service on FreeBSD.
+
+### JACK
+
+Set
+
+    method = jack
+
+The JACK Audio Connection Kit (JACK) is a professional sound server API which 
is available on several
+operating systems, e.g. FreeBSD and Linux.
 
+CAVA is a JACK client with the base client name `cava` and adheres to the 
standard server start and
+stop behaviour, i.e. CAVA starts a JACK server if none is already running and 
the environment variable
+`JACK_START_SERVER` is defined, in which case the server also stops when all 
clients have exited. The
+`source` in the CAVA configuration file specifies the name of the JACK server 
to which CAVA tries to
+connect to. The default value is `default`, which is also the default JACK 
server name. The value can
+be empty, in which case it implies `default`. Therefore the following three 
entries are equivalent:
+
+    ; source = default
+    source = default
+    source =
+
+One exception is the combination of an empty `source` entry and the 
environment variable `JACK_DEFAULT_SERVER`.
+If the environment variable is defined, e.g. `export JACK_DEFAULT_SERVER=foo`, 
then the following entries
+are equivalent:
+
+    source = foo
+    source =
+
+Consult the manpage `jackd(1)` for further information regarding configuration 
and startup of a JACK
+server.
+
+CAVA creates terminal audio-typed (so no MIDI support) input ports. These 
ports can connect to output
+ports of other JACK clients, e.g. connect to the output ports of a music 
player and CAVA will visualize
+the music. Currently CAVA supports up to two input ports, i.e. it supports 
mono and stereo. The number
+of input ports can be controlled via the `channels` option in the input 
section of the configuration
+file:
+
+    channels = 1    # one input port, mono
+    channels = 2    # two input ports, stereo (default)
+
+The port's short name is simply `M` for mono, and `L` and `R` for stereo. The 
full name of the input
+port according to the base client name is `cava:M` for mono, and `cava:L` and 
`cava:R` for stereo.
+
+The option `autoconnect` controls the connection strategy for CAVA's ports to 
other client's ports:
+
+    autoconnect = 0    # don't connect to other ports automatically
+    autoconnect = 1    # only connect to other ports during startup
+    autoconnect = 2    # reconnect to new ports regularly (default)
+
+The automatic connection strategies scan the physical terminal input-ports, 
i.e. the real audio device
+which actually outputs the sound, and applies the same connections to CAVA's 
ports. In this way CAVA
+visualizes the played back audio from JACK clients by default.
+
+In order to control and manage the connection between CAVA's ports and ports 
of other client programs,
+there are connection management programs for JACK. Some well known connection 
managers with a graphical
+user interface are QjackCtl and Cadence. The JACK package itself often comes 
with CLI tools. Depending
+on the operating system it could be necessary to install them separately, e.g. 
on FreeBSD:
+```sh
+$ doas pkg install jack-example-tools
+```
+Among the tools are the programs `jack_lsp` and `jack_connect`. These two 
tools are enough to list
+and connect ports on the commandline. The following example demonstrates how 
to setup connections with
+these tools:
+```sh
+$ jack_lsp
+system:capture_1
+system:capture_2
+system:playback_1
+system:playback_2
+cava:L
+moc:output0
+moc:output1
+cava:R
+```
+This listing shows all full port names that are currently available. These 
correspond to two external
+JACK clients, `cava` and `moc`, and one internal JACK client `system`. The 
types and current active
+connections between the ports can be listed with the `-p` and `-c` switches 
for `jack_lsp`. In order
+to connect the ports of CAVA and MOC, `jack_connect` is used:
+```sh
+$ jack_connect cava:L moc:output0
+$ jack_connect cava:R moc:output1
+```
+Now CAVA visualizes the outgoing audio from MOC.
 
 ### squeezelite
 [squeezelite](https://en.wikipedia.org/wiki/Squeezelite) is one of several 
software clients available for the Logitech Media Server. Squeezelite can 
export its audio data as shared memory, which is what this input module uses.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/autogen.sh new/cava-0.10.1/autogen.sh
--- old/cava-0.10.0/autogen.sh  2024-01-09 19:26:04.000000000 +0100
+++ new/cava-0.10.1/autogen.sh  2024-02-02 18:47:27.000000000 +0100
@@ -3,7 +3,7 @@
 if [ -d .git ]; then
   git describe --always --tags --dirty > version # get version from git
 else
-  echo 0.10.0 > version # hard coded versions
+  echo 0.10.1 > version # hard coded versions
 fi
 
 libtoolize
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/cava.c new/cava-0.10.1/cava.c
--- old/cava-0.10.0/cava.c      2024-01-09 19:26:04.000000000 +0100
+++ new/cava-0.10.1/cava.c      2024-02-02 18:47:27.000000000 +0100
@@ -70,6 +70,7 @@
 
 #include "input/alsa.h"
 #include "input/fifo.h"
+#include "input/jack.h"
 #include "input/oss.h"
 #include "input/pipewire.h"
 #include "input/portaudio.h"
@@ -354,6 +355,7 @@
         audio.samples_counter = 0;
         audio.channels = 2;
         audio.IEEE_FLOAT = 0;
+        audio.autoconnect = 0;
 
         audio.input_buffer_size = BUFFER_SIZE * audio.channels;
         audio.cava_buffer_size = audio.input_buffer_size * 8;
@@ -413,8 +415,10 @@
 #endif
 #ifdef SNDIO
         case INPUT_SNDIO:
-            audio.format = 16;
-            audio.rate = 44100;
+            audio.format = p.samplebits;
+            audio.rate = p.samplerate;
+            audio.channels = p.channels;
+            audio.threadparams = 1; // Sndio can adjust parameters
             thr_id = pthread_create(&p_thread, NULL, input_sndio, (void 
*)&audio);
             break;
 #endif
@@ -422,10 +426,19 @@
         case INPUT_OSS:
             audio.format = p.samplebits;
             audio.rate = p.samplerate;
+            audio.channels = p.channels;
             audio.threadparams = 1; // OSS can adjust parameters
             thr_id = pthread_create(&p_thread, NULL, input_oss, (void 
*)&audio);
             break;
 #endif
+#ifdef JACK
+        case INPUT_JACK:
+            audio.channels = p.channels;
+            audio.autoconnect = p.autoconnect;
+            audio.threadparams = 1; // JACK server provides parameters
+            thr_id = pthread_create(&p_thread, NULL, input_jack, (void 
*)&audio);
+            break;
+#endif
         case INPUT_SHMEM:
             audio.format = 16;
             thr_id = pthread_create(&p_thread, NULL, input_shmem, (void 
*)&audio);
@@ -481,7 +494,7 @@
 
         if (p.upper_cut_off > audio.rate / 2) {
             cleanup();
-            fprintf(stderr, "higher cuttoff frequency can't be higher than 
sample rate / 2");
+            fprintf(stderr, "higher cutoff frequency can't be higher than 
sample rate / 2");
             exit(EXIT_FAILURE);
         }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/config.c new/cava-0.10.1/config.c
--- old/cava-0.10.0/config.c    2024-01-09 19:26:04.000000000 +0100
+++ new/cava-0.10.1/config.c    2024-02-02 18:47:27.000000000 +0100
@@ -45,20 +45,21 @@
 double smoothDef[5] = {1, 1, 1, 1, 1};
 
 enum input_method default_methods[] = {
-    INPUT_FIFO,     INPUT_PORTAUDIO, INPUT_ALSA,  INPUT_PULSE,
-    INPUT_PIPEWIRE, INPUT_WINSCAP,   INPUT_SNDIO, INPUT_OSS,
+    INPUT_FIFO,  INPUT_PORTAUDIO, INPUT_ALSA,    INPUT_SNDIO, INPUT_JACK,
+    INPUT_PULSE, INPUT_PIPEWIRE,  INPUT_WINSCAP, INPUT_OSS,
 };
 
 char *outputMethod, *orientation, *channels, *xaxisScale, *monoOption, 
*fragmentShader,
     *vertexShader;
 
 const char *input_method_names[] = {
-    "fifo", "portaudio", "pipewire", "alsa", "pulse", "sndio", "oss", "shmem", 
"winscap",
+    "fifo", "portaudio", "pipewire", "alsa", "pulse", "sndio", "oss", "jack", 
"shmem", "winscap",
 };
 
 const bool has_input_method[] = {
     HAS_FIFO, /** Always have at least FIFO and shmem input. */
-    HAS_PORTAUDIO, HAS_PIPEWIRE, HAS_ALSA, HAS_PULSE, HAS_SNDIO, HAS_OSS, 
HAS_SHMEM, HAS_WINSCAP,
+    HAS_PORTAUDIO, HAS_PIPEWIRE, HAS_ALSA,  HAS_PULSE,   HAS_SNDIO,
+    HAS_OSS,       HAS_JACK,     HAS_SHMEM, HAS_WINSCAP,
 };
 
 enum input_method input_method_by_name(const char *str) {
@@ -328,7 +329,7 @@
     if (p->stereo == -1) {
         write_errorf(
             error,
-            "output channels %s is not supported, supported channelss are: 
'mono' and 'stereo'\n",
+            "output channels %s is not supported, supported channels are: 
'mono' and 'stereo'\n",
             channels);
         return false;
     }
@@ -389,6 +390,12 @@
     }
     p->sens = p->sens / 100;
 
+    // validate: channels
+    if (p->channels <= 1)
+        p->channels = 1;
+    else
+        p->channels = 2;
+
     return validate_colors(p, error);
 }
 
@@ -546,7 +553,6 @@
     monoOption = malloc(sizeof(char) * 32);
     p->raw_target = malloc(sizeof(char) * 129);
     p->data_format = malloc(sizeof(char) * 32);
-    channels = malloc(sizeof(char) * 32);
     orientation = malloc(sizeof(char) * 32);
     vertexShader = malloc(sizeof(char) * PATH_MAX / 2);
     fragmentShader = malloc(sizeof(char) * PATH_MAX / 2);
@@ -677,6 +683,8 @@
 
     p->samplerate = iniparser_getint(ini, "input:sample_rate", 44100);
     p->samplebits = iniparser_getint(ini, "input:sample_bits", 16);
+    p->channels = iniparser_getint(ini, "input:channels", 2);
+    p->autoconnect = iniparser_getint(ini, "input:autoconnect", 2);
 
     enum input_method default_input = INPUT_FIFO;
     for (size_t i = 0; i < ARRAY_SIZE(default_methods); i++) {
@@ -717,6 +725,11 @@
         p->audio_source = strdup(iniparser_getstring(ini, "input:source", 
"/dev/dsp"));
         break;
 #endif
+#ifdef JACK
+    case INPUT_JACK:
+        p->audio_source = strdup(iniparser_getstring(ini, "input:source", 
"default"));
+        break;
+#endif
     case INPUT_SHMEM:
         p->audio_source =
             strdup(iniparser_getstring(ini, "input:source", 
"/squeezelite-00:00:00:00:00:00"));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/config.h new/cava-0.10.1/config.h
--- old/cava-0.10.0/config.h    2024-01-09 19:26:04.000000000 +0100
+++ new/cava-0.10.1/config.h    2024-02-02 18:47:27.000000000 +0100
@@ -43,6 +43,12 @@
 #define HAS_OSS false
 #endif
 
+#ifdef JACK
+#define HAS_JACK true
+#else
+#define HAS_JACK false
+#endif
+
 #ifdef _MSC_VER
 #define HAS_WINSCAP true
 #define SDL true
@@ -66,6 +72,7 @@
     INPUT_PULSE,
     INPUT_SNDIO,
     INPUT_OSS,
+    INPUT_JACK,
     INPUT_SHMEM,
     INPUT_WINSCAP,
     INPUT_MAX,
@@ -104,9 +111,9 @@
     enum orientation orientation;
     int userEQ_keys, userEQ_enabled, col, bgcol, autobars, stereo, raw_format, 
ascii_range,
         bit_format, gradient, gradient_count, fixedbars, framerate, bar_width, 
bar_spacing,
-        bar_height, autosens, overshoot, waves, samplerate, samplebits, 
sleep_timer, sdl_width,
-        sdl_height, sdl_x, sdl_y, sdl_full_screen, draw_and_quit, zero_test, 
non_zero_test, reverse,
-        sync_updates, continuous_rendering, disable_blanking;
+        bar_height, autosens, overshoot, waves, samplerate, samplebits, 
channels, autoconnect,
+        sleep_timer, sdl_width, sdl_height, sdl_x, sdl_y, sdl_full_screen, 
draw_and_quit, zero_test,
+        non_zero_test, reverse, sync_updates, continuous_rendering, 
disable_blanking;
 };
 
 struct error_s {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/configure.ac new/cava-0.10.1/configure.ac
--- old/cava-0.10.0/configure.ac        2024-01-09 19:26:04.000000000 +0100
+++ new/cava-0.10.1/configure.ac        2024-02-02 18:47:27.000000000 +0100
@@ -249,6 +249,29 @@
 AM_CONDITIONAL([OSS], [test "x$have_oss" = "xyes"])
 
 dnl ######################
+dnl checking for jack dev
+dnl ######################
+AC_ARG_ENABLE([input_jack],
+  AS_HELP_STRING([--disable-input-jack],
+    [do not include support for input from jack])
+)
+
+AS_IF([test "x$enable_input_jack" != "xno"], [
+  PKG_CHECK_MODULES(JACK, jack, have_jack=yes, have_jack=no)
+  if [[ $have_jack = "yes" ]] ; then
+    LIBS="$LIBS $JACK_LIBS"
+    CPPFLAGS="$CPPFLAGS -DJACK $JACK_CFLAGS"
+  fi
+
+  if [[ $have_jack = "no" ]] ; then
+    AC_MSG_NOTICE([WARNING: No jack dev files found building without jack 
support])
+  fi],
+  [have_jack=no]
+)
+
+AM_CONDITIONAL([JACK], [test "x$have_jack" = "xyes"])
+
+dnl ######################
 dnl checking for math lib
 dnl ######################
 AC_CHECK_LIB(m, sqrt, have_m=yes, have_m=no)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/example_files/config 
new/cava-0.10.1/example_files/config
--- old/cava-0.10.0/example_files/config        2024-01-09 19:26:04.000000000 
+0100
+++ new/cava-0.10.1/example_files/config        2024-02-02 18:47:27.000000000 
+0100
@@ -52,8 +52,8 @@
 
 [input]
 
-# Audio capturing method. Possible methods are: 'fifo', 'portaudio', 
'pipewire', 'alsa', 'pulse', 'sndio', 'oss' or 'shmem'
-# Defaults to 'oss', 'sndio', 'pipewire', 'pulse', 'alsa', 'portaudio' or 
'fifo', in that order, dependent on what support cava was built with.
+# Audio capturing method. Possible methods are: 'fifo', 'portaudio', 
'pipewire', 'alsa', 'pulse', 'sndio', 'oss', 'jack' or 'shmem'
+# Defaults to 'oss', 'pipewire', 'sndio', 'jack', 'pulse', 'alsa', 'portaudio' 
or 'fifo', in that order, dependent on what support cava was built with.
 # On Mac it defaults to 'portaudio' or 'fifo'
 # On windows this is automatic and no input settings are needed.
 #
@@ -70,12 +70,15 @@
 # For fifo 'source' will be the path to fifo-file.
 # For shmem 'source' will be /squeezelite-AA:BB:CC:DD:EE:FF where 
'AA:BB:CC:DD:EE:FF' will be squeezelite's MAC address
 #
-# For sndio 'source' will be a monitor sub-device, e.g. 'snd/0.monitor'. 
Default: 'default', in which case a device
-# should be specified with the environment variable AUDIODEVICE, e.g. on the 
commandline: AUDIODEVICE=snd/0.monitor cava.
+# For sndio 'source' will be a raw recording audio descriptor or a monitoring 
sub-device, e.g. 'rsnd/2' or 'snd/1'. Default: 'default'.
+# README.md contains further information on how to setup CAVA for sndio.
 #
 # For oss 'source' will be the path to a audio device, e.g. '/dev/dsp2'. 
Default: '/dev/dsp', i.e. the default audio device.
 # README.md contains further information on how to setup CAVA for OSS on 
FreeBSD.
 #
+# For jack 'source' will be the name of the JACK server to connect to, e.g. 
'foobar'. Default: 'default'.
+# README.md contains further information on how to setup CAVA for JACK.
+#
 ; method = pulse
 ; source = auto
 
@@ -100,17 +103,25 @@
 ; method = oss
 ; source = /dev/dsp
 
-# The sample rate and format can be configured for some input methods. 
Currently
-# the following methods support such a configuration: 'fifo', 'pipewire' and 
'oss'.
+; method = jack
+; source = default
+
+# The options 'sample_rate', 'sample_bits', 'channels' and 'autoconnect' can 
be configured for some input methods:
+#   sample_rate: fifo, pipewire, sndio, oss
+#   sample_bits: fifo, pipewire, sndio, oss
+#   channels:    sndio, oss, jack
+#   autoconnect: jack
 # Other methods ignore these settings.
 #
-# For 'oss' they are only preferred values, i.e. if the values are not 
supported
+# For 'sndio' and 'oss' they are only preferred values, i.e. if the values are 
not supported
 # by the chosen audio device, the device will use other supported values 
instead.
-# Example: 48000 and 32, but the device only supports 44100 and 16, then it 
will
-# use 44100 and 16.
+# Example: 48000, 32 and 2, but the device only supports 44100, 16 and 1, then 
it
+# will use 44100, 16 and 1.
 #
 ; sample_rate = 44100
 ; sample_bits = 16
+; channels = 2
+; autoconnect = 2
 
 
 [output]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/input/common.c 
new/cava-0.10.1/input/common.c
--- old/cava-0.10.0/input/common.c      2024-01-09 19:26:04.000000000 +0100
+++ new/cava-0.10.1/input/common.c      2024-02-02 18:47:27.000000000 +0100
@@ -52,4 +52,16 @@
         audio->cava_in[n] = 0;
     }
     pthread_mutex_unlock(&audio->lock);
-}
\ No newline at end of file
+}
+
+void signal_threadparams(struct audio_data *audio) {
+    pthread_mutex_lock(&audio->lock);
+    audio->threadparams = 0;
+    pthread_mutex_unlock(&audio->lock);
+}
+
+void signal_terminate(struct audio_data *audio) {
+    pthread_mutex_lock(&audio->lock);
+    audio->terminate = 1;
+    pthread_mutex_unlock(&audio->lock);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/input/common.h 
new/cava-0.10.1/input/common.h
--- old/cava-0.10.0/input/common.h      2024-01-09 19:26:04.000000000 +0100
+++ new/cava-0.10.1/input/common.h      2024-02-02 18:47:27.000000000 +0100
@@ -25,17 +25,20 @@
     unsigned int rate;
     unsigned int channels;
     int threadparams; // shared variable used to prevent main thread from 
cava_init before input
-                      // threads have finalized parameters
+                      // threads have finalized parameters (0=allow cava_init, 
1=disallow)
     char *source;     // alsa device, fifo path or pulse source
     int im;           // input mode alsa, fifo, pulse, portaudio, shmem or 
sndio
     int terminate;    // shared variable used to terminate audio thread
     char error_message[1024];
     int samples_counter;
-    int IEEE_FLOAT;
+    int IEEE_FLOAT;  // format for 32bit (0=int, 1=float)
+    int autoconnect; // auto connect to audio source (0=off, 1=once at 
startup, 2=regularly)
     pthread_mutex_t lock;
 };
 
 void reset_output_buffers(struct audio_data *data);
+void signal_threadparams(struct audio_data *data);
+void signal_terminate(struct audio_data *data);
 
 int write_to_cava_input_buffers(int16_t size, unsigned char *buf, void *data);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/input/jack.c new/cava-0.10.1/input/jack.c
--- old/cava-0.10.0/input/jack.c        1970-01-01 01:00:00.000000000 +0100
+++ new/cava-0.10.1/input/jack.c        2024-02-02 18:47:27.000000000 +0100
@@ -0,0 +1,392 @@
+#include <stdbool.h>
+#include <time.h>
+
+#include <jack/jack.h>
+
+#include "input/common.h"
+#include "input/jack.h"
+
+// CAVA is hard-coded to a maximum of 2 channels, i.e. stereo.
+#define MAX_CHANNELS 2
+
+typedef jack_default_audio_sample_t sample_t;
+
+struct jack_data {
+    struct audio_data *audio; // CAVA ctx
+
+    jack_client_t *client;           // JACK client
+    jack_port_t *port[MAX_CHANNELS]; // input ports
+    jack_nframes_t nframes;          // number of samples per port
+    sample_t *buf;                   // samples buffer
+
+    int graphorder; // JACK graph ordering signal (0=unchanged, 1=changed)
+    int shutdown;   // JACK shutdown signal (0=keep, 1=shutdown)
+};
+
+static bool set_rate(struct jack_data *jack) {
+    // Query sample rate from JACK server. If CAVA doesn't support the final 
value then it will
+    // complain later.
+    jack_nframes_t rate = jack_get_sample_rate(jack->client);
+
+    if (rate <= 0) {
+        fprintf(stderr, __FILE__ ": jack_get_sample_rate() failed.\n");
+        return false;
+    }
+
+    jack->audio->rate = rate;
+
+    return true;
+}
+
+static bool set_format(struct jack_data *jack) {
+    // JACK returns 32bit float data.
+    jack->audio->format = 32;
+    jack->audio->IEEE_FLOAT = 1;
+    return true;
+}
+
+static bool set_channels(struct jack_data *jack) {
+    // Try to create terminal audio-typed input ports for the requested number 
of channels. These
+    // ports can receive the audio data from other JACK clients.
+    static const char *port_name[MAX_CHANNELS][MAX_CHANNELS] = {/* mono */ 
{"M", NULL},
+                                                                /* stereo */ 
{"L", "R"}};
+    static const char port_type[] = JACK_DEFAULT_AUDIO_TYPE;
+    static const unsigned long flags = JackPortIsInput | JackPortIsTerminal;
+
+    int channels;
+    int chtype;
+    int ch;
+
+    // Limit the requested channels in case CAVA becomes surround-aware and 
MAX_CHANNELS hasn't
+    // adapted yet.
+    channels = jack->audio->channels > MAX_CHANNELS ? MAX_CHANNELS : 
jack->audio->channels;
+
+    // Determines the row in the 'port_name' table, i.e. mono, stereo, etc...
+    chtype = channels - 1;
+
+    // Try to create a port for every requested channel. After the for-loop 
the variable 'ch' holds
+    // the number of actual created ports.
+    for (ch = 0; ch < channels; ++ch) {
+        if ((jack->port[ch] = jack_port_register(jack->client, 
port_name[chtype][ch], port_type,
+                                                 flags, 0)) == NULL)
+            break;
+    }
+
+    // If not even one port was created, then there was a deeper problem.
+    if (ch == 0) {
+        fprintf(stderr, __FILE__ ": jack_port_register('%s') failed.\n", 
port_name[chtype][0]);
+        return false;
+    }
+
+    // If less ports were created than channels requested, then the JACK 
server is probably not
+    // configured for the requested channels, e.g. we requested stereo but the 
server only provides
+    // mono. In this case we rename the created ports according to the 
resulting table row.
+    if (ch < channels) {
+        int chtype_new;
+
+        channels = ch;
+        chtype_new = channels - 1;
+
+        for (ch = 0; ch < channels; ++ch) {
+            int err;
+
+            if ((err = jack_port_rename(jack->client, jack->port[ch], 
port_name[chtype_new][ch])) !=
+                0) {
+                fprintf(stderr, __FILE__ ": jack_port_rename('%s', '%s') 
failed: 0x%x\n",
+                        port_name[chtype][ch], port_name[chtype_new][ch], err);
+                return false;
+            }
+        }
+    }
+
+    jack->audio->channels = channels;
+
+    return true;
+}
+
+static int on_buffer_size(jack_nframes_t nframes, void *arg) {
+    // Buffersize changes should never happen in CAVA!
+    struct jack_data *jack = arg;
+
+    if ((jack->shutdown == 1) || (jack->audio->terminate == 1))
+        return 0;
+
+    if (jack->nframes != nframes) {
+        fprintf(stderr, __FILE__ ": Unexpected change of JACK port buffersize! 
Aborting!\n");
+        jack->shutdown = 1;
+        return 1;
+    }
+
+    return 0;
+}
+
+static int on_graph_order(void *arg) {
+    ((struct jack_data *)arg)->graphorder = 1;
+    return 0;
+}
+
+static int on_process(jack_nframes_t nframes, void *arg) {
+    // Interleave samples from separate ports and feed them to CAVA.
+    struct jack_data *jack = arg;
+    sample_t *buf[MAX_CHANNELS];
+    unsigned char *buf_cava;
+
+    if ((jack->shutdown == 1) || (jack->audio->terminate == 1))
+        return 0;
+
+    for (unsigned int i = 0; i < jack->audio->channels; ++i) {
+        if ((buf[i] = jack_port_get_buffer(jack->port[i], nframes)) == NULL) {
+            fprintf(stderr, __FILE__ ": jack_port_get_buffer('%s') failed.\n",
+                    jack_port_name(jack->port[i]));
+            jack->shutdown = 1;
+            return 1;
+        }
+    }
+
+    switch (jack->audio->channels) {
+    case 1:
+        // If mono then no interleaving needed, feed into CAVA directly.
+        buf_cava = (unsigned char *)buf[0];
+        break;
+    case 2:
+        // If stereo then unroll interleaving manually.
+        for (jack_nframes_t i = 0; i < nframes; ++i) {
+            jack->buf[2 * i + 0] = buf[0][i];
+            jack->buf[2 * i + 1] = buf[1][i];
+        }
+
+        buf_cava = (unsigned char *)jack->buf;
+        break;
+    default:
+        // Else to the loops.
+        for (jack_nframes_t i = 0; i < nframes; ++i) {
+            for (unsigned int j = 0; j < jack->audio->channels; ++j)
+                jack->buf[jack->audio->channels * i + j] = buf[j][i];
+        }
+
+        buf_cava = (unsigned char *)jack->buf;
+        break;
+    }
+
+    write_to_cava_input_buffers(nframes * jack->audio->channels, buf_cava, 
jack->audio);
+
+    return 0;
+}
+
+static int on_sample_rate(jack_nframes_t nframes, void *arg) {
+    // Sample rate changes are not supported in CAVA!
+    struct jack_data *jack = arg;
+
+    if ((jack->shutdown == 1) || (jack->audio->terminate == 1))
+        return 0;
+
+    if (jack->audio->rate != nframes) {
+        fprintf(stderr, __FILE__ ": Unexpected change of JACK sample rate! 
Aborting!\n");
+        jack->shutdown = 1;
+        return 1;
+    }
+
+    return 0;
+}
+
+static void on_shutdown(void *arg) { ((struct jack_data *)arg)->shutdown = 1; }
+
+static bool auto_connect(struct jack_data *jack) {
+    // Get all physical terminal input-ports and mirror their connections to 
CAVA.
+    static const char type_name_pattern[] = JACK_DEFAULT_AUDIO_TYPE;
+    static const unsigned long flags = JackPortIsInput | JackPortIsPhysical | 
JackPortIsTerminal;
+
+    unsigned int channels;
+
+    const char **ports = NULL;
+
+    bool success = false;
+
+    if ((jack->shutdown == 1) || (jack->audio->terminate == 1))
+        return true;
+
+    if ((ports = jack_get_ports(jack->client, NULL, type_name_pattern, flags)) 
== NULL) {
+        fprintf(stderr,
+                __FILE__ ": jack_get_ports() failed: No physical terminal 
input-ports found!\n");
+        goto cleanup;
+    }
+
+    // If CAVA is configured for mono, then we connect everything to the one 
mono port. If we have
+    // more channels, then we limit the number of connection ports to the 
number of channels.
+    for (channels = 0; ports[channels] != NULL; ++channels)
+        ;
+
+    if ((jack->audio->channels > 1) && (channels > jack->audio->channels))
+        channels = jack->audio->channels;
+
+    // Visit the physical terminal input-ports, get their connections and 
apply them to CAVA's
+    // input-ports.
+    for (unsigned int i = 0; i < channels; ++i) {
+        const char **connections;
+        jack_port_t *port;
+        const char *port_name;
+
+        if ((connections = jack_port_get_all_connections(
+                 jack->client, jack_port_by_name(jack->client, ports[i]))) == 
NULL)
+            continue;
+
+        if (jack->audio->channels == 1)
+            port = jack->port[0];
+        else
+            port = jack->port[i];
+
+        port_name = jack_port_name(port);
+
+        for (int j = 0; connections[j] != NULL; ++j) {
+            if (jack_port_connected_to(port, connections[j]) == 0)
+                jack_connect(jack->client, connections[j], port_name);
+        }
+
+        jack_free(connections);
+    }
+
+    success = true;
+
+cleanup:
+    if (!success)
+        jack->shutdown = 1;
+
+    jack_free(ports);
+
+    return success;
+}
+
+void *input_jack(void *data) {
+    static const char client_name[] = "cava";
+    static const jack_options_t options = JackNullOption | JackServerName;
+    static const struct timespec rqtp = {.tv_sec = 0, .tv_nsec = 1000000}; // 
1ms nsleep
+
+    struct audio_data *audio = data;
+    char *server_name;
+    jack_status_t status;
+    int err;
+
+    struct jack_data jack = {0};
+
+    bool is_jack_activated = false;
+    bool success = false;
+
+    jack.audio = audio;
+
+    // JACK server selection by source or implicit default.
+    if (strlen(audio->source) == 0)
+        server_name = NULL;
+    else
+        server_name = audio->source;
+
+    if ((jack.client = jack_client_open(client_name, options, &status, 
server_name)) == NULL) {
+        fprintf(stderr, __FILE__ ": Could not open JACK source '%s': 0x%x\n", 
server_name, status);
+        goto cleanup;
+    }
+
+    if (!set_rate(&jack) || !set_format(&jack) || !set_channels(&jack))
+        goto cleanup;
+
+    // Parameters finalized. Signal main thread.
+    signal_threadparams(audio);
+
+    // JACK returns samples per channel. Adjust its buffersize to fit within 
CAVA.
+    // Must be a power of 2.
+    jack.nframes = 1 << 31;
+
+    while (jack.nframes > audio->input_buffer_size / audio->channels)
+        jack.nframes >>= 1;
+
+    if ((err = jack_set_buffer_size(jack.client, jack.nframes)) != 0) {
+        fprintf(stderr, __FILE__ ": jack_set_buffer_size() failed: 0x%x\n", 
err);
+        goto cleanup;
+    }
+
+    // Work buffer for interleaving if not mono.
+    if ((audio->channels > 1) &&
+        ((jack.buf = malloc(jack.nframes * audio->channels * 
sizeof(sample_t))) == NULL)) {
+        fprintf(stderr, __FILE__ ": malloc() failed: %s\n", strerror(errno));
+        goto cleanup;
+    }
+
+    // Set JACK callbacks before JACK activation.
+    if ((err = jack_set_buffer_size_callback(jack.client, on_buffer_size, 
&jack)) != 0) {
+        fprintf(stderr, __FILE__ ": jack_set_buffer_size_callback() failed: 
0x%x\n", err);
+        goto cleanup;
+    }
+
+    if (audio->autoconnect > 0) {
+        if (audio->autoconnect == 1)
+            jack.graphorder = 1;
+        else {
+            if ((err = jack_set_graph_order_callback(jack.client, 
on_graph_order, &jack)) != 0) {
+                fprintf(stderr, __FILE__ ": jack_set_graph_order_callback() 
failed: 0x%x\n", err);
+                goto cleanup;
+            }
+        }
+    }
+
+    if ((err = jack_set_process_callback(jack.client, on_process, &jack)) != 
0) {
+        fprintf(stderr, __FILE__ ": jack_set_process_callback() failed: 
0x%x\n", err);
+        goto cleanup;
+    }
+
+    if ((err = jack_set_sample_rate_callback(jack.client, on_sample_rate, 
&jack)) != 0) {
+        fprintf(stderr, __FILE__ ": jack_set_sample_rate_callback() failed: 
0x%x\n", err);
+        goto cleanup;
+    }
+
+    jack_on_shutdown(jack.client, on_shutdown, &jack);
+
+    if ((err = jack_activate(jack.client)) != 0) {
+        fprintf(stderr, __FILE__ ": jack_activate() failed: 0x%x\n", err);
+        goto cleanup;
+    }
+
+    is_jack_activated = true;
+
+    while (audio->terminate != 1) {
+        if (jack.shutdown == 1)
+            signal_terminate(audio);
+        else if (jack.graphorder == 1) {
+            if (!auto_connect(&jack))
+                goto cleanup;
+
+            jack.graphorder = 0;
+        }
+
+        nanosleep(&rqtp, NULL);
+    }
+
+    success = true;
+
+cleanup:
+    if (is_jack_activated && ((err = jack_deactivate(jack.client)) != 0)) {
+        fprintf(stderr, __FILE__ ": jack_deactivate() failed: 0x%x\n", err);
+        success = false;
+    }
+
+    free(jack.buf);
+
+    for (int i = 0; i < MAX_CHANNELS; ++i) {
+        if ((jack.port[i] != NULL) &&
+            ((err = jack_port_unregister(jack.client, jack.port[i])) != 0)) {
+            fprintf(stderr, __FILE__ ": jack_port_unregister('%s') failed: 
0x%x\n",
+                    jack_port_name(jack.port[i]), err);
+            success = false;
+        }
+    }
+
+    if ((jack.client != NULL) && ((err = jack_client_close(jack.client)) != 
0)) {
+        fprintf(stderr, __FILE__ ": jack_client_close() failed: 0x%x\n", err);
+        success = false;
+    }
+
+    signal_threadparams(audio);
+    signal_terminate(audio);
+
+    if (!success)
+        exit(EXIT_FAILURE);
+
+    return NULL;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/input/jack.h new/cava-0.10.1/input/jack.h
--- old/cava-0.10.0/input/jack.h        1970-01-01 01:00:00.000000000 +0100
+++ new/cava-0.10.1/input/jack.h        2024-02-02 18:47:27.000000000 +0100
@@ -0,0 +1,5 @@
+// header file for jack, part of cava.
+
+#pragma once
+
+void *input_jack(void *data);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/input/oss.c new/cava-0.10.1/input/oss.c
--- old/cava-0.10.0/input/oss.c 2024-01-09 19:26:04.000000000 +0100
+++ new/cava-0.10.1/input/oss.c 2024-02-02 18:47:27.000000000 +0100
@@ -31,14 +31,23 @@
     }
 
     // Determine the sle format for the requested bitlength.
-    if (audio->format <= 8)
+    switch (audio->format) {
+    case 8:
         fmt = AFMT_S8;
-    else if (audio->format <= 16)
+        break;
+    case 16:
         fmt = AFMT_S16_LE;
-    else if (audio->format <= 24)
+        break;
+    case 24:
         fmt = AFMT_S24_LE;
-    else
+        break;
+    case 32:
         fmt = AFMT_S32_LE;
+        break;
+    default:
+        fprintf(stderr, __FILE__ ": Invalid format: %d\n", audio->format);
+        return false;
+    }
 
     // If the requested format is not available then test for the other sle 
formats.
     if (!(fmts & fmt)) {
@@ -104,25 +113,12 @@
     return true;
 }
 
-static void signal_threadparams(struct audio_data *audio) {
-    pthread_mutex_lock(&audio->lock);
-    audio->threadparams = 0;
-    pthread_mutex_unlock(&audio->lock);
-}
-
-static void signal_terminate(struct audio_data *audio) {
-    pthread_mutex_lock(&audio->lock);
-    audio->terminate = 1;
-    pthread_mutex_unlock(&audio->lock);
-}
-
 void *input_oss(void *data) {
     static const int flags = O_RDONLY;
 
-    struct audio_data *audio = (struct audio_data *)data;
+    struct audio_data *audio = data;
     int bytes;
     size_t buf_size;
-    ssize_t rd;
 
     int fd = -1;
     void *buf = NULL;
@@ -136,7 +132,7 @@
     }
 
     // For OSS it's adviced to determine format, channels and rate in this 
order.
-    if (!(set_format(fd, audio) && set_channels(fd, audio) && set_rate(fd, 
audio)))
+    if (!set_format(fd, audio) || !set_channels(fd, audio) || !set_rate(fd, 
audio))
         goto cleanup;
 
     // Parameters finalized. Signal main thread.
@@ -156,7 +152,9 @@
     }
 
     while (audio->terminate != 1) {
-        if ((rd = read(fd, buf, buf_size)) == -1) {
+        ssize_t rd;
+
+        if ((rd = read(fd, buf, buf_size)) < 0) {
             fprintf(stderr, __FILE__ ": read() failed: %s\n", strerror(errno));
             goto cleanup;
         } else if (rd == 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/input/pulse.h 
new/cava-0.10.1/input/pulse.h
--- old/cava-0.10.0/input/pulse.h       2024-01-09 19:26:04.000000000 +0100
+++ new/cava-0.10.1/input/pulse.h       2024-02-02 18:47:27.000000000 +0100
@@ -3,4 +3,4 @@
 #pragma once
 
 void *input_pulse(void *data);
-void getPulseDefaultSink();
+void getPulseDefaultSink(void *data);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cava-0.10.0/input/sndio.c 
new/cava-0.10.1/input/sndio.c
--- old/cava-0.10.0/input/sndio.c       2024-01-09 19:26:04.000000000 +0100
+++ new/cava-0.10.1/input/sndio.c       2024-02-02 18:47:27.000000000 +0100
@@ -1,50 +1,117 @@
-#include "input/sndio.h"
-#include "input/common.h"
+#include <stdbool.h>
+#include <stddef.h>
 
 #include <sndio.h>
 
+#include "input/common.h"
+#include "input/sndio.h"
+
 void *input_sndio(void *data) {
-    struct audio_data *audio = (struct audio_data *)data;
+    static const unsigned int mode = SIO_REC;
+
+    struct audio_data *audio = data;
     struct sio_par par;
-    struct sio_hdl *hdl;
-    unsigned char buf[audio->input_buffer_size * audio->format / 8];
+    int bytes;
+    size_t buf_size;
+
+    struct sio_hdl *hdl = NULL;
+    void *buf = NULL;
+
+    bool is_sio_started = false;
+    bool success = false;
 
+    if ((hdl = sio_open(audio->source, mode, 0)) == NULL) {
+        fprintf(stderr, __FILE__ ": Could not open sndio source '%s'.\n", 
audio->source);
+        goto cleanup;
+    }
+
+    // The recommended approach to negotiate device parameters is to try to 
set them with preferred
+    // values and check what sndio returns for actual supported values. If 
CAVA doesn't support the
+    // final values for rate and channels then it will complain later. We test 
the resulting format
+    // explicitly here.
     sio_initpar(&par);
-    par.sig = 1;
     par.bits = audio->format;
+    par.sig = 1;
     par.le = 1;
-    par.rate = audio->rate;
-    ;
     par.rchan = audio->channels;
-    par.appbufsz = sizeof(buf) / par.rchan;
+    par.rate = audio->rate;
+    par.appbufsz = audio->input_buffer_size * SIO_BPS(audio->format) / 
audio->channels;
 
-    if ((hdl = sio_open(audio->source, SIO_REC, 0)) == NULL) {
-        fprintf(stderr, __FILE__ ": Could not open sndio source: %s\n", 
audio->source);
-        exit(EXIT_FAILURE);
+    if (sio_setpar(hdl, &par) == 0) {
+        fprintf(stderr, __FILE__ ": sio_setpar() failed.\n");
+        goto cleanup;
     }
 
-    if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par) || par.sig != 1 || 
par.le != 1 ||
-        par.rate != 44100 || par.rchan != audio->channels) {
-        fprintf(stderr, __FILE__ ": Could not set required audio 
parameters\n");
-        exit(EXIT_FAILURE);
+    if (sio_getpar(hdl, &par) == 0) {
+        fprintf(stderr, __FILE__ ": sio_getpar() failed.\n");
+        goto cleanup;
     }
 
-    if (!sio_start(hdl)) {
-        fprintf(stderr, __FILE__ ": sio_start() failed\n");
-        exit(EXIT_FAILURE);
+    switch (par.bits) {
+    case 8:
+    case 16:
+    case 24:
+    case 32:
+        audio->format = par.bits;
+        break;
+    default:
+        fprintf(stderr, __FILE__ ": No support for 8, 16, 24 or 32 bits in 
sndio source '%s'.\n",
+                audio->source);
+        goto cleanup;
+    }
+
+    audio->channels = par.rchan;
+    audio->rate = par.rate;
+
+    // Parameters finalized. Signal main thread.
+    signal_threadparams(audio);
+
+    // Get the correct number of bytes per sample. Sndio uses 32 bits for 
24bit, thankfully SIO_BPS
+    // handles this.
+    bytes = SIO_BPS(audio->format);
+    buf_size = audio->input_buffer_size * bytes;
+
+    if ((buf = malloc(buf_size)) == NULL) {
+        fprintf(stderr, __FILE__ ": malloc() failed: %s\n", strerror(errno));
+        goto cleanup;
+    }
+
+    if (sio_start(hdl) == 0) {
+        fprintf(stderr, __FILE__ ": sio_start() failed.\n");
+        goto cleanup;
     }
 
+    is_sio_started = true;
+
     while (audio->terminate != 1) {
-        if (sio_read(hdl, buf, sizeof(buf)) == 0) {
-            fprintf(stderr, __FILE__ ": sio_read() failed: %s\n", 
strerror(errno));
-            exit(EXIT_FAILURE);
+        size_t rd;
+
+        if ((rd = sio_read(hdl, buf, buf_size)) == 0) {
+            fprintf(stderr, __FILE__ ": sio_read() failed.\n");
+            goto cleanup;
         }
 
-        write_to_cava_input_buffers(audio->input_buffer_size, buf, audio);
+        write_to_cava_input_buffers(rd / bytes, buf, audio);
+    }
+
+    success = true;
+
+cleanup:
+    if (is_sio_started && (sio_stop(hdl) == 0)) {
+        fprintf(stderr, __FILE__ ": sio_stop() failed.\n");
+        success = false;
     }
 
-    sio_stop(hdl);
-    sio_close(hdl);
+    free(buf);
+
+    if (hdl != NULL)
+        sio_close(hdl);
+
+    signal_threadparams(audio);
+    signal_terminate(audio);
+
+    if (!success)
+        exit(EXIT_FAILURE);
 
-    return 0;
+    return NULL;
 }

Reply via email to