mirror of
				https://github.com/rad4day/Waybar.git
				synced 2025-10-31 07:52:42 +01:00 
			
		
		
		
	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.cpp
This commit is contained in:
		| @@ -62,6 +62,9 @@ | ||||
| #    include "modules/bluetooth.hpp" | ||||
| #  endif | ||||
| #endif | ||||
| #ifdef HAVE_LIBJACK | ||||
| #include "modules/jack.hpp" | ||||
| #endif | ||||
|  | ||||
| namespace waybar { | ||||
|  | ||||
|   | ||||
							
								
								
									
										29
									
								
								include/modules/jack.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								include/modules/jack.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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]); | ||||
|   | ||||
							
								
								
									
										127
									
								
								src/modules/jack.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								src/modules/jack.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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(); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Kenny Phelps-McKeown
					Kenny Phelps-McKeown