diff --git a/build.sh b/build.sh index b9b3ac45..d65bd23f 100755 --- a/build.sh +++ b/build.sh @@ -30,6 +30,7 @@ function main local build_ipc_msg="ON" local enable_alsa="ON" + local enable_pulseaudio="ON" local enable_i3="ON" local enable_network="ON" local enable_mpd="ON" @@ -41,6 +42,8 @@ function main [[ "${p^^}" != "Y" ]] && enable_i3="OFF" read -r -p "$(msg "Include support for \"internal/volume\" (requires alsalib) ---------- [Y/n]: ")" -n 1 p && echo [[ "${p^^}" != "Y" ]] && enable_alsa="OFF" + read -r -p "$(msg "Include support for \"internal/volume\" (requires libpulse) --------- [Y/n]: ")" -n 1 p && echo + [[ "${p^^}" != "Y" ]] && enable_pulseaudio="OFF" read -r -p "$(msg "Include support for \"internal/network\" (requires wireless_tools) -- [Y/n]: ")" -n 1 p && echo [[ "${p^^}" != "Y" ]] && enable_network="OFF" read -r -p "$(msg "Include support for \"internal/mpd\" (requires libmpdclient) -------- [Y/n]: ")" -n 1 p && echo @@ -50,6 +53,11 @@ function main read -r -p "$(msg "Build \"polybar-msg\" used to send ipc messages --------------------- [Y/n]: ")" -n 1 p && echo [[ "${p^^}" != "Y" ]] && build_ipc_msg="OFF" + # pulseaudio overrides alsa + if [[ "${enable_alsa}" == "ON" ]] && [[ "${enable_pulseaudio}" == "ON" ]]; then + enable_alsa="OFF" + fi + local cxx="c++" local cc="cc" @@ -68,6 +76,7 @@ function main -DCMAKE_C_COMPILER="${cc}" \ -DCMAKE_CXX_COMPILER="${cxx}" \ -DENABLE_ALSA:BOOL="${enable_alsa}" \ + -DENABLE_PULSEAUDIO:BOOL="${enable_pulseaudio}"\ -DENABLE_I3:BOOL="${enable_i3}" \ -DENABLE_MPD:BOOL="${enable_mpd}" \ -DENABLE_NETWORK:BOOL="${enable_network}" \ diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index e265ca5a..b14d452c 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -16,7 +16,7 @@ queryfont(FONT_SIJI ${FONT_SIJI} FIELDS family pixelsize) # Strip disabled modules {{{ -if(NOT ENABLE_ALSA) +if(NOT (ENABLE_ALSA OR ENABLE_PULSEAUDIO)) string(REPLACE " volume" "" MODULES_RIGHT ${MODULES_RIGHT}) endif() if(NOT ENABLE_I3) diff --git a/include/modules/meta/factory.hpp b/include/modules/meta/factory.hpp index 9c6ca9d8..8e510c58 100644 --- a/include/modules/meta/factory.hpp +++ b/include/modules/meta/factory.hpp @@ -31,7 +31,7 @@ #if ENABLE_NETWORK #include "modules/network.hpp" #endif -#if ENABLE_ALSA +#if ENABLE_ALSA || ENABLE_PULSEAUDIO #include "modules/volume.hpp" #endif #if ENABLE_CURL @@ -40,7 +40,7 @@ #if ENABLE_XKEYBOARD #include "modules/xkeyboard.hpp" #endif -#if not(ENABLE_I3 && ENABLE_MPD && ENABLE_NETWORK && ENABLE_ALSA && ENABLE_CURL && ENABLE_XKEYBOARD) +#if not(ENABLE_I3 && ENABLE_MPD && ENABLE_NETWORK && (ENABLE_ALSA || ENABLE_PULSEAUDIO) && ENABLE_CURL && ENABLE_XKEYBOARD) #include "modules/unsupported.hpp" #endif diff --git a/include/modules/unsupported.hpp b/include/modules/unsupported.hpp index c391a1c2..f9c2746e 100644 --- a/include/modules/unsupported.hpp +++ b/include/modules/unsupported.hpp @@ -1,5 +1,5 @@ #pragma once -#if ENABLE_I3 && ENABLE_MPD && ENABLE_NETWORK && ENABLE_ALSA && ENABLE_CURL && ENABLE_XKEYBOARD +#if ENABLE_I3 && ENABLE_MPD && ENABLE_NETWORK && (ENABLE_ALSA || ENABLE_PULSEAUDIO) && ENABLE_CURL && ENABLE_XKEYBOARD #error "Support has been enabled for all optional modules" #endif @@ -40,7 +40,7 @@ namespace modules { #if not ENABLE_NETWORK DEFINE_UNSUPPORTED_MODULE(network_module, "internal/network"); #endif -#if not ENABLE_ALSA +#if not (ENABLE_ALSA || ENABLE_PULSEAUDIO) DEFINE_UNSUPPORTED_MODULE(volume_module, "internal/volume"); #endif #if not ENABLE_CURL diff --git a/include/modules/volume.hpp b/include/modules/volume.hpp index 92949e43..008e6772 100644 --- a/include/modules/volume.hpp +++ b/include/modules/volume.hpp @@ -1,26 +1,31 @@ #pragma once #include "settings.hpp" -#include "adapters/pulseaudio.hpp" #include "modules/meta/event_module.hpp" #include "modules/meta/input_handler.hpp" POLYBAR_NS // fwd +#if ENABLE_ALSA namespace alsa { class mixer; class control; } -//class pulseaudio; +#elif ENABLE_PULSEAUDIO +class pulseaudio; +#endif namespace modules { enum class mixer { NONE = 0, MASTER, SPEAKER, HEADPHONE }; enum class control { NONE = 0, HEADPHONE }; +#if ENABLE_ALSA using mixer_t = shared_ptr; using control_t = shared_ptr; +#elif ENABLE_PULSEAUDIO using pulseaudio_t = shared_ptr; +#endif class volume_module : public event_module, public input_handler { public: @@ -57,12 +62,15 @@ namespace modules { label_t m_label_volume; label_t m_label_muted; +#if ENABLE_PULSEAUDIO + pulseaudio_t m_pulseaudio; +#elif ENABLE_ALSA map m_mixer; map m_ctrl; - pulseaudio_t m_pulseaudio; - //int m_headphoneid{0}; - //bool m_mapped{false}; + int m_headphoneid{0}; + bool m_mapped{false}; +#endif atomic m_muted{false}; atomic m_headphones{false}; atomic m_volume{0}; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 251c2866..36c892cf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,7 +8,6 @@ file(GLOB_RECURSE files RELATIVE ${CMAKE_CURRENT_LIST_DIR} *.c[p]*) list(REMOVE_ITEM files ipc.cpp) if(NOT ENABLE_ALSA) - list(REMOVE_ITEM files modules/volume.cpp) list(REMOVE_ITEM files adapters/alsa/control.cpp) list(REMOVE_ITEM files adapters/alsa/mixer.cpp) endif() @@ -31,6 +30,9 @@ endif() if(NOT ENABLE_PULSEAUDIO) list(REMOVE_ITEM files adapters/pulseaudio.cpp) endif() +if(NOT (ENABLE_ALSA OR ENABLE_PULSEAUDIO)) + list(REMOVE_ITEM files modules/volume.cpp) +endif() if(NOT WITH_XRANDR) list(REMOVE_ITEM files x11/extensions/randr.cpp) endif() diff --git a/src/adapters/pulseaudio.cpp b/src/adapters/pulseaudio.cpp index 8af56cf8..6f96307e 100644 --- a/src/adapters/pulseaudio.cpp +++ b/src/adapters/pulseaudio.cpp @@ -1,7 +1,6 @@ #include "adapters/pulseaudio.hpp" // TODO possibly move all the callback functions to lambda functions -// also maybe use pa_operation_unref(op) // create base volume backend class (mixer/control, pulseaudio inherits from base class) // use index instead of name internally? POLYBAR_NS @@ -56,6 +55,7 @@ pulseaudio::pulseaudio(string&& sink_name) : spec_s_name(sink_name) { pa_operation* op = pa_context_get_sink_info_by_name(m_context, sink_name.c_str(), sink_info_callback, this); while (pa_operation_get_state(op) != PA_OPERATION_DONE) pa_threaded_mainloop_wait(m_mainloop); + pa_operation_unref(op); if (exists) s_name = sink_name; else { @@ -65,15 +65,20 @@ pulseaudio::pulseaudio(string&& sink_name) : spec_s_name(sink_name) { } while (pa_operation_get_state(op) != PA_OPERATION_DONE) pa_threaded_mainloop_wait(m_mainloop); + pa_operation_unref(op); s_name = def_s_name; // get the sink index op = pa_context_get_sink_info_by_name(m_context, s_name.c_str(), sink_info_callback, this); + while (pa_operation_get_state(op) != PA_OPERATION_DONE) + pa_threaded_mainloop_wait(m_mainloop); + pa_operation_unref(op); } op = pa_context_subscribe(m_context, static_cast(PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SERVER), simple_callback, this); while (pa_operation_get_state(op) != PA_OPERATION_DONE) pa_threaded_mainloop_wait(m_mainloop); + pa_operation_unref(op); pa_context_set_subscribe_callback(m_context, subscribe_callback, this); pa_threaded_mainloop_unlock(m_mainloop); @@ -84,7 +89,6 @@ pulseaudio::pulseaudio(string&& sink_name) : spec_s_name(sink_name) { * Deconstruct pulseaudio */ pulseaudio::~pulseaudio() { - pa_threaded_mainloop_unlock(m_mainloop); pa_threaded_mainloop_stop(m_mainloop); pa_context_disconnect(m_context); pa_context_unref(m_context); @@ -123,6 +127,7 @@ int pulseaudio::process_events() { o = pa_context_get_sink_info_by_name(m_context, spec_s_name.c_str(), sink_info_callback, this); while (pa_operation_get_state(o) != PA_OPERATION_DONE) pa_threaded_mainloop_wait(m_mainloop); + pa_operation_unref(o); if (exists) s_name = spec_s_name; break; @@ -131,15 +136,18 @@ int pulseaudio::process_events() { o = pa_context_get_sink_info_by_name(m_context, s_name.c_str(), get_sink_volume_callback, this); while (pa_operation_get_state(o) != PA_OPERATION_DONE) pa_threaded_mainloop_wait(m_mainloop); + pa_operation_unref(o); break; // get default sink case evtype::REMOVE: o = pa_context_get_server_info(m_context, get_default_sink_callback, this); while (pa_operation_get_state(o) != PA_OPERATION_DONE) pa_threaded_mainloop_wait(m_mainloop); + pa_operation_unref(o); o = pa_context_get_sink_info_by_name(m_context, s_name.c_str(), sink_info_callback, this); while (pa_operation_get_state(o) != PA_OPERATION_DONE) pa_threaded_mainloop_wait(m_mainloop); + pa_operation_unref(o); break; } m_events.pop(); @@ -154,9 +162,9 @@ int pulseaudio::process_events() { int pulseaudio::get_volume() { pa_threaded_mainloop_lock(m_mainloop); pa_operation *op = pa_context_get_sink_info_by_name(m_context, s_name.c_str(), get_sink_volume_callback, this); - while (pa_operation_get_state(op) != PA_OPERATION_DONE) { + while (pa_operation_get_state(op) != PA_OPERATION_DONE) pa_threaded_mainloop_wait(m_mainloop); - } + pa_operation_unref(op); pa_threaded_mainloop_unlock(m_mainloop); // alternatively, user pa_cvolume_avg_mask() to average selected channels //return math_util::percentage(pa_cvolume_avg(&cv), PA_VOLUME_MUTED, PA_VOLUME_NORM); @@ -172,11 +180,13 @@ void pulseaudio::set_volume(float percentage) { pa_operation *op = pa_context_get_sink_info_by_name(m_context, s_name.c_str(), get_sink_volume_callback, this); while (pa_operation_get_state(op) != PA_OPERATION_DONE) pa_threaded_mainloop_wait(m_mainloop); + pa_operation_unref(op); pa_volume_t vol = math_util::percentage_to_value(percentage, PA_VOLUME_MUTED, PA_VOLUME_NORM); pa_cvolume_scale(&cv, vol); op = pa_context_set_sink_volume_by_name(m_context, s_name.c_str(), &cv, simple_callback, this); while (pa_operation_get_state(op) != PA_OPERATION_DONE) pa_threaded_mainloop_wait(m_mainloop); + pa_operation_unref(op); pa_threaded_mainloop_unlock(m_mainloop); } @@ -188,6 +198,7 @@ void pulseaudio::set_mute(bool mode) { pa_operation *op = pa_context_set_sink_mute_by_name(m_context, s_name.c_str(), mode, simple_callback, this); while (pa_operation_get_state(op) != PA_OPERATION_DONE) pa_threaded_mainloop_wait(m_mainloop); + pa_operation_unref(op); pa_threaded_mainloop_unlock(m_mainloop); } @@ -206,6 +217,7 @@ bool pulseaudio::is_muted() { pa_operation *op = pa_context_get_sink_info_by_name(m_context, s_name.c_str(), check_mute_callback, this); while (pa_operation_get_state(op) != PA_OPERATION_DONE) pa_threaded_mainloop_wait(m_mainloop); + pa_operation_unref(op); pa_threaded_mainloop_unlock(m_mainloop); return muted; } diff --git a/src/modules/volume.cpp b/src/modules/volume.cpp index 37206ea4..7a81b226 100644 --- a/src/modules/volume.cpp +++ b/src/modules/volume.cpp @@ -1,8 +1,11 @@ #include "modules/volume.hpp" +#if ENABLE_ALSA #include "adapters/alsa/control.hpp" #include "adapters/alsa/generic.hpp" #include "adapters/alsa/mixer.hpp" +#elif ENABLE_PULSEAUDIO #include "adapters/pulseaudio.hpp" +#endif #include "drawtypes/label.hpp" #include "drawtypes/progressbar.hpp" #include "drawtypes/ramp.hpp" @@ -14,14 +17,16 @@ POLYBAR_NS +#if ENABLE_ALSA using namespace alsa; +#endif namespace modules { template class module; volume_module::volume_module(const bar_settings& bar, string name_) : event_module(bar, move(name_)) { // Load configuration values - /* +#if ENABLE_ALSA m_mapped = m_conf.get(name(), "mapped", m_mapped); auto master_mixer_name = m_conf.get(name(), "master-mixer", "Master"s); @@ -68,10 +73,10 @@ namespace modules { } catch (const control_error& err) { throw module_error(err.what()); } - */ +#elif ENABLE_PULSEAUDIO auto sink_name = m_conf.get(name(), "sink", ""s); - //m_pulseaudio = new pulseaudio_t::element_type{move(sink_name)}; m_pulseaudio = factory_util::unique(move(sink_name)); +#endif // Add formats and elements m_formatter->add(FORMAT_VOLUME, TAG_LABEL_VOLUME, {TAG_RAMP_VOLUME, TAG_LABEL_VOLUME, TAG_BAR_VOLUME}); @@ -93,18 +98,18 @@ namespace modules { } void volume_module::teardown() { - /* +#if ENABLE_ALSA m_mixer.clear(); m_ctrl.clear(); - */ - //m_pulseaudio.clear(); - m_pulseaudio.reset(); snd_config_update_free_global(); +#elif ENABLE_PULSEAUDIO + m_pulseaudio.reset(); +#endif } bool volume_module::has_event() { // Poll for mixer and control events - /* +#if ENABLE_ALSA try { if (m_mixer[mixer::MASTER] && m_mixer[mixer::MASTER]->wait(25)) { return true; @@ -121,19 +126,20 @@ namespace modules { } catch (const alsa_exception& e) { m_log.err("%s: %s", name(), e.what()); } - */ +#elif ENABLE_PULSEAUDIO try { if (m_pulseaudio->wait(25)) return true; } catch (const pulseaudio_error& e) { m_log.err("%s: %s", name(), e.what()); } +#endif return false; } bool volume_module::update() { // Consume pending events - /* +#if ENABLE_ALSA if (m_mixer[mixer::MASTER]) { m_mixer[mixer::MASTER]->process_events(); } @@ -146,15 +152,16 @@ namespace modules { if (m_ctrl[control::HEADPHONE]) { m_ctrl[control::HEADPHONE]->process_events(); } - */ +#elif ENABLE_PULSEAUDIO m_pulseaudio->process_events(); +#endif // Get volume, mute and headphone state m_volume = 100; m_muted = false; m_headphones = false; - /* +#if ENABLE_ALSA try { if (m_mixer[mixer::MASTER]) { m_volume = m_volume * (m_mapped ? m_mixer[mixer::MASTER]->get_normalized_volume() / 100.0f @@ -185,7 +192,7 @@ namespace modules { } catch (const alsa_exception& err) { m_log.err("%s: Failed to query speaker mixer (%s)", name(), err.what()); } - */ +#elif ENABLE_PULSEAUDIO try { if (m_pulseaudio) { m_volume = m_volume * m_pulseaudio->get_volume() / 100.0f; @@ -194,6 +201,7 @@ namespace modules { } catch (const pulseaudio_error& err) { m_log.err("%s: Failed to query pulseaudio sink (%s)", name(), err.what()); } +#endif // Replace label tokens if (m_label_volume) { @@ -252,12 +260,14 @@ namespace modules { return false; } else if (cmd.compare(0, 3, EVENT_PREFIX) != 0) { return false; - //} else if (!m_mixer[mixer::MASTER]) { - // return false; +#if ENABLE_ALSA + } else if (!m_mixer[mixer::MASTER]) { + return false; +#endif } try { - /* +#if ENABLE_ALSA vector mixers; bool headphones{m_headphones}; @@ -297,7 +307,7 @@ namespace modules { mixer->process_events(); } } - */ +#elif ENABLE_PULSEAUDIO if (m_pulseaudio && !m_pulseaudio->get_name().empty()) { if (cmd.compare(0, strlen(EVENT_TOGGLE_MUTE), EVENT_TOGGLE_MUTE) == 0) { printf("toggling mute\n"); @@ -314,6 +324,7 @@ namespace modules { m_pulseaudio->process_events(); } } +#endif } catch (const exception& err) { m_log.err("%s: Failed to handle command (%s)", name(), err.what()); }