Initial commit for Waybar JACK monitoring module
-DSP load -xruns -connected/disconnected state -only tested with Pipewire so far but should work with JACK2 as well On branch dsp Changes to be committed: modified: include/factory.hpp new file: include/modules/jack.hpp modified: meson.build modified: meson_options.txt modified: src/factory.cpp new file: src/modules/jack.cpppull/1653/head
parent
d906080f26
commit
8fc8bb40bf
|
@ -67,6 +67,10 @@
|
||||||
#include "modules/custom.hpp"
|
#include "modules/custom.hpp"
|
||||||
#include "modules/temperature.hpp"
|
#include "modules/temperature.hpp"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBJACK
|
||||||
|
#include "modules/jack.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
|
||||||
class Factory {
|
class Factory {
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <jack/jack.h>
|
||||||
|
#include <proc/readproc.h>
|
||||||
|
#include "ALabel.hpp"
|
||||||
|
#include "util/sleeper_thread.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules {
|
||||||
|
|
||||||
|
class JACK : public ALabel {
|
||||||
|
public:
|
||||||
|
JACK(const std::string&, const Json::Value&);
|
||||||
|
~JACK() = default;
|
||||||
|
auto update() -> void;
|
||||||
|
jack_nframes_t bufsize_;
|
||||||
|
jack_client_t* client_;
|
||||||
|
unsigned int xruns_;
|
||||||
|
std::string state_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string JACKState();
|
||||||
|
|
||||||
|
jack_nframes_t samplerate_;
|
||||||
|
util::SleeperThread thread_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules
|
|
@ -98,6 +98,8 @@ libudev = dependency('libudev', required: get_option('libudev'))
|
||||||
libevdev = dependency('libevdev', required: get_option('libevdev'))
|
libevdev = dependency('libevdev', required: get_option('libevdev'))
|
||||||
libmpdclient = dependency('libmpdclient', required: get_option('mpd'))
|
libmpdclient = dependency('libmpdclient', required: get_option('mpd'))
|
||||||
xkbregistry = dependency('xkbregistry')
|
xkbregistry = dependency('xkbregistry')
|
||||||
|
libjack = dependency('jack', required: get_option('jack'))
|
||||||
|
libprocps = dependency('libprocps', required: get_option('jack'))
|
||||||
|
|
||||||
libsndio = compiler.find_library('sndio', required: get_option('sndio'))
|
libsndio = compiler.find_library('sndio', required: get_option('sndio'))
|
||||||
if libsndio.found()
|
if libsndio.found()
|
||||||
|
@ -222,6 +224,11 @@ if libpulse.found()
|
||||||
src_files += 'src/modules/pulseaudio.cpp'
|
src_files += 'src/modules/pulseaudio.cpp'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if libjack.found() and libprocps.found()
|
||||||
|
add_project_arguments('-DHAVE_LIBJACK', language: 'cpp')
|
||||||
|
src_files += 'src/modules/jack.cpp'
|
||||||
|
endif
|
||||||
|
|
||||||
if dbusmenu_gtk.found()
|
if dbusmenu_gtk.found()
|
||||||
add_project_arguments('-DHAVE_DBUSMENU', language: 'cpp')
|
add_project_arguments('-DHAVE_DBUSMENU', language: 'cpp')
|
||||||
src_files += files(
|
src_files += files(
|
||||||
|
@ -302,6 +309,8 @@ executable(
|
||||||
libnlgen,
|
libnlgen,
|
||||||
upower_glib,
|
upower_glib,
|
||||||
libpulse,
|
libpulse,
|
||||||
|
libjack,
|
||||||
|
libprocps,
|
||||||
libudev,
|
libudev,
|
||||||
libepoll,
|
libepoll,
|
||||||
libmpdclient,
|
libmpdclient,
|
||||||
|
|
|
@ -14,3 +14,5 @@ option('sndio', type: 'feature', value: 'auto', description: 'Enable support for
|
||||||
option('logind', type: 'feature', value: 'auto', description: 'Enable support for logind')
|
option('logind', type: 'feature', value: 'auto', description: 'Enable support for logind')
|
||||||
option('tests', type: 'feature', value: 'auto', description: 'Enable tests')
|
option('tests', type: 'feature', value: 'auto', description: 'Enable tests')
|
||||||
option('experimental', type : 'boolean', value : false, description: 'Enable experimental features')
|
option('experimental', type : 'boolean', value : false, description: 'Enable experimental features')
|
||||||
|
option('jack', type: 'feature', value: 'auto', description: 'Enable support for JACK DSP load monitoring')
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
|
||||||
return new waybar::modules::Pulseaudio(id, config_[name]);
|
return new waybar::modules::Pulseaudio(id, config_[name]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_LIBJACK
|
||||||
|
if (ref == "jack") {
|
||||||
|
return new waybar::modules::JACK(id, config_[name]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef HAVE_LIBMPDCLIENT
|
#ifdef HAVE_LIBMPDCLIENT
|
||||||
if (ref == "mpd") {
|
if (ref == "mpd") {
|
||||||
return new waybar::modules::MPD(id, config_[name]);
|
return new waybar::modules::MPD(id, config_[name]);
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
#include "modules/jack.hpp"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
int bufSizeCallback(unsigned int size, void *obj) {
|
||||||
|
waybar::modules::JACK* x = (waybar::modules::JACK*)obj;
|
||||||
|
x->bufsize_ = size;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xrunCallback(void *obj) {
|
||||||
|
waybar::modules::JACK* x = (waybar::modules::JACK*)obj;
|
||||||
|
x->xruns_ += 1;
|
||||||
|
x->state_ = "xrun";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shutdownCallback(void *obj) {
|
||||||
|
waybar::modules::JACK* x = (waybar::modules::JACK*)obj;
|
||||||
|
x->client_ = NULL;
|
||||||
|
x->state_ = "disconnected";
|
||||||
|
x->xruns_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
waybar::modules::JACK::JACK(const std::string& id, const Json::Value& config)
|
||||||
|
: ALabel(config, "jack", id, "{load}%", 1) {
|
||||||
|
xruns_ = 0;
|
||||||
|
state_ = "disconnected";
|
||||||
|
client_ = NULL;
|
||||||
|
|
||||||
|
state_ = JACKState();
|
||||||
|
thread_ = [this] {
|
||||||
|
dp.emit();
|
||||||
|
thread_.sleep_for(interval_);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string waybar::modules::JACK::JACKState() {
|
||||||
|
if(state_.compare("xrun") == 0)
|
||||||
|
return "xrun";
|
||||||
|
if(state_.compare("connected") == 0)
|
||||||
|
return "connected";
|
||||||
|
|
||||||
|
std::string procname;
|
||||||
|
bool foundJACK = false;
|
||||||
|
proc_t** proctab = readproctab(PROC_FILLSTAT);
|
||||||
|
for(int i=0; proctab[i]; i++) {
|
||||||
|
procname = proctab[i]->cmd;
|
||||||
|
if(!procname.compare("jackd") || !procname.compare("pipewire"))
|
||||||
|
foundJACK = true;
|
||||||
|
freeproc(proctab[i]);
|
||||||
|
}
|
||||||
|
free(proctab);
|
||||||
|
if(!foundJACK)
|
||||||
|
return "disconnected";
|
||||||
|
|
||||||
|
client_ = jack_client_open("waybar", JackNoStartServer, NULL);
|
||||||
|
|
||||||
|
if (client_) {
|
||||||
|
bufsize_ = jack_get_buffer_size(client_);
|
||||||
|
samplerate_ = jack_get_sample_rate(client_);
|
||||||
|
jack_set_buffer_size_callback(client_, bufSizeCallback, this);
|
||||||
|
jack_set_xrun_callback(client_, xrunCallback, this);
|
||||||
|
jack_on_shutdown(client_, shutdownCallback, this);
|
||||||
|
|
||||||
|
if (!jack_activate(client_))
|
||||||
|
return "connected";
|
||||||
|
}
|
||||||
|
return "disconnected";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto waybar::modules::JACK::update() -> void {
|
||||||
|
std::string format;
|
||||||
|
float latency = 1000 * (float)bufsize_ / (float)samplerate_;
|
||||||
|
auto state = JACKState();
|
||||||
|
float load;
|
||||||
|
|
||||||
|
if(label_.get_style_context()->has_class("xrun")) {
|
||||||
|
label_.get_style_context()->remove_class("xrun");
|
||||||
|
state = "connected";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(state.compare("disconnected") != 0)
|
||||||
|
load = jack_cpu_load(client_);
|
||||||
|
else {
|
||||||
|
load = 0;
|
||||||
|
bufsize_ = 0;
|
||||||
|
samplerate_ = 0;
|
||||||
|
latency = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(label_.get_style_context()->has_class(state_))
|
||||||
|
label_.get_style_context()->remove_class(state_);
|
||||||
|
|
||||||
|
if (config_["format-" + state].isString()) {
|
||||||
|
format = config_["format-" + state].asString();
|
||||||
|
} else if (config_["format"].isString()) {
|
||||||
|
format = config_["format"].asString();
|
||||||
|
} else format = "DSP {load}%";
|
||||||
|
|
||||||
|
if(!label_.get_style_context()->has_class(state))
|
||||||
|
label_.get_style_context()->add_class(state);
|
||||||
|
state_ = state;
|
||||||
|
|
||||||
|
label_.set_markup(fmt::format(format, fmt::arg("load", std::round(load)),
|
||||||
|
fmt::arg("bufsize", bufsize_),
|
||||||
|
fmt::arg("samplerate", samplerate_),
|
||||||
|
fmt::arg("latency", fmt::format("{:.2f}", latency)),
|
||||||
|
fmt::arg("xruns", xruns_)));
|
||||||
|
|
||||||
|
if (tooltipEnabled()) {
|
||||||
|
std::string tooltip_format = "{bufsize}/{samplerate} {latency}ms";
|
||||||
|
if (config_["tooltip-format"].isString())
|
||||||
|
tooltip_format = config_["tooltip-format"].asString();
|
||||||
|
label_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("load", std::round(load)),
|
||||||
|
fmt::arg("bufsize", bufsize_),
|
||||||
|
fmt::arg("samplerate", samplerate_),
|
||||||
|
fmt::arg("latency", fmt::format("{:.2f}", latency)),
|
||||||
|
fmt::arg("xruns", xruns_)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call parent update
|
||||||
|
ALabel::update();
|
||||||
|
}
|
Loading…
Reference in New Issue