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
12caae8fd2
commit
d5c400c0cc
|
@ -62,6 +62,9 @@
|
|||
# include "modules/bluetooth.hpp"
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_LIBJACK
|
||||
#include "modules/jack.hpp"
|
||||
#endif
|
||||
|
||||
namespace waybar {
|
||||
|
||||
|
|
|
@ -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
|
|
@ -97,6 +97,8 @@ libudev = dependency('libudev', required: get_option('libudev'))
|
|||
libevdev = dependency('libevdev', required: get_option('libevdev'))
|
||||
libmpdclient = dependency('libmpdclient', required: get_option('mpd'))
|
||||
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'))
|
||||
if libsndio.found()
|
||||
|
@ -207,6 +209,11 @@ if libpulse.found()
|
|||
src_files += 'src/modules/pulseaudio.cpp'
|
||||
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()
|
||||
add_project_arguments('-DHAVE_DBUSMENU', language: 'cpp')
|
||||
src_files += files(
|
||||
|
@ -288,6 +295,8 @@ executable(
|
|||
libnl,
|
||||
libnlgen,
|
||||
libpulse,
|
||||
libjack,
|
||||
libprocps,
|
||||
libudev,
|
||||
libepoll,
|
||||
libmpdclient,
|
||||
|
|
|
@ -13,3 +13,5 @@ option('sndio', type: 'feature', value: 'auto', description: 'Enable support for
|
|||
option('logind', type: 'feature', value: 'auto', description: 'Enable support for logind')
|
||||
option('tests', type: 'feature', value: 'auto', description: 'Enable tests')
|
||||
option('experimental', type : 'boolean', value : false, description: 'Enable experimental features')
|
||||
option('jack', type: 'feature', value: 'auto', description: 'Enable support for JACK DSP load monitoring')
|
||||
|
||||
|
|
|
@ -85,6 +85,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
|
|||
return new waybar::modules::Pulseaudio(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_LIBJACK
|
||||
if (ref == "jack") {
|
||||
return new waybar::modules::JACK(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_LIBMPDCLIENT
|
||||
if (ref == "mpd") {
|
||||
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