From 477b45be1be256b7496e1d45b41754c6e40ef58a Mon Sep 17 00:00:00 2001 From: Maki Date: Fri, 19 Apr 2024 02:32:29 -0400 Subject: Add toggle for PipeWire volume catcher, and refactoring --- .../cef/linux/volume_catcher_pulseaudio.cpp | 322 +++++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100755 indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp (limited to 'indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp') diff --git a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp new file mode 100755 index 0000000000..20a6458ea3 --- /dev/null +++ b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp @@ -0,0 +1,322 @@ +/** + * @file volume_catcher_pulseaudio.cpp + * @brief A Linux-specific, PulseAudio-specific hack to detect and volume-adjust new audio sources + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * @endcond + */ + +/* + The high-level design is as follows: + 1) Connect to the PulseAudio daemon + 2) Watch for the creation of new audio players connecting to the daemon (this includes ALSA clients running on the PulseAudio emulation layer, such as Flash plugins) + 3) Examine any new audio player's PID to see if it belongs to our own process + 4) If so, tell PA to adjust the volume of that audio player ('sink input' in PA parlance) + 5) Keep a list of all living audio players that we care about, adjust the volumes of all of them when we get a new setVolume() call + */ + +#include "linden_common.h" + +#include "volume_catcher_linux.h" + +extern "C" { +#include +#include + +#include + +#include +} + +SymbolGrabber paSymbolGrabber; +#undef LL_SYMBOL_GRABBER +#define LL_SYMBOL_GRABBER paSymbolGrabber + +#include "volume_catcher_pulseaudio_syms.inc" +#include "volume_catcher_pulseaudio_glib_syms.inc" + +//////////////////////////////////////////////////// + +// PulseAudio requires a chain of callbacks with C linkage +extern "C" { + void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *i, int eol, void *userdata); + void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata); + void callback_context_state(pa_context *context, void *userdata); +} + +VolumeCatcherPulseAudio::VolumeCatcherPulseAudio() + : mDesiredVolume(0.0f), + mMainloop(nullptr), + mPAContext(nullptr), + mConnected(false), + mGotSyms(false) +{ + init(); +} + +VolumeCatcherPulseAudio::~VolumeCatcherPulseAudio() +{ + cleanup(); +} + +bool VolumeCatcherPulseAudio::loadsyms(std::string pulse_dso_name) +{ + return paSymbolGrabber.grabSymbols({ pulse_dso_name }); +} + +void VolumeCatcherPulseAudio::init() +{ + // try to be as defensive as possible because PA's interface is a + // bit fragile and (for our purposes) we'd rather simply not function + // than crash + + // we cheat and rely upon libpulse-mainloop-glib.so.0 to pull-in + // libpulse.so.0 - this isn't a great assumption, and the two DSOs should + // probably be loaded separately. Our Linux DSO framework needs refactoring, + // we do this sort of thing a lot with practically identical logic... + mGotSyms = loadsyms("libpulse-mainloop-glib.so.0"); + if (!mGotSyms) mGotSyms = loadsyms("libpulse.so.0"); + + if (!mGotSyms) + return; + + mMainloop = llpa_glib_mainloop_new(g_main_context_default()); + + if (mMainloop) + { + pa_mainloop_api *api = llpa_glib_mainloop_get_api(mMainloop); + + if (api) + { + pa_proplist *proplist = llpa_proplist_new(); + + if (proplist) + { + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "multimedia-player"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.secondlife.viewer.mediaplugvoladjust"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "SL Plugin Volume Adjuster"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, "1"); + + // plain old pa_context_new() is broken! + mPAContext = llpa_context_new_with_proplist(api, nullptr, proplist); + + llpa_proplist_free(proplist); + } + } + } + + // Now we've set up a PA context and mainloop, try connecting the + // PA context to a PA daemon. + if (mPAContext) + { + llpa_context_set_state_callback(mPAContext, callback_context_state, this); + pa_context_flags_t cflags = (pa_context_flags)0; // maybe add PA_CONTEXT_NOAUTOSPAWN? + if (llpa_context_connect(mPAContext, nullptr, cflags, nullptr) >= 0) + { + // Okay! We haven't definitely connected, but we + // haven't definitely failed yet. + } + else + { + // Failed to connect to PA manager... we'll leave + // things like that. Perhaps we should try again later. + } + } +} + +void VolumeCatcherPulseAudio::cleanup() +{ + mConnected = false; + + if (mGotSyms && mPAContext) + { + llpa_context_disconnect(mPAContext); + llpa_context_unref(mPAContext); + } + + mPAContext = nullptr; + + if (mGotSyms && mMainloop) + llpa_glib_mainloop_free(mMainloop); + + mMainloop = nullptr; +} + +void VolumeCatcherPulseAudio::setVolume(F32 volume) +{ + mDesiredVolume = volume; + + if (!mGotSyms) + return; + + if (mConnected && mPAContext) + { + update_all_volumes(mDesiredVolume); + } + + pump(); +} + +void VolumeCatcherPulseAudio::setPan(F32 pan) +{ +} + +void VolumeCatcherPulseAudio::pump() +{ + gboolean may_block = FALSE; + g_main_context_iteration(g_main_context_default(), may_block); +} + +void VolumeCatcherPulseAudio::connected_okay() +{ + pa_operation *op; + + // fetch global list of existing sinkinputs + if ((op = llpa_context_get_sink_input_info_list(mPAContext, + callback_discovered_sinkinput, + this))) + { + llpa_operation_unref(op); + } + + // subscribe to future global sinkinput changes + llpa_context_set_subscribe_callback(mPAContext, + callback_subscription_alert, + this); + if ((op = llpa_context_subscribe(mPAContext, (pa_subscription_mask_t) + (PA_SUBSCRIPTION_MASK_SINK_INPUT), + nullptr, nullptr))) + { + llpa_operation_unref(op); + } +} + +void VolumeCatcherPulseAudio::update_all_volumes(F32 volume) +{ + for (std::set::iterator it = mSinkInputIndices.begin(); + it != mSinkInputIndices.end(); ++it) + { + update_index_volume(*it, volume); + } +} + +void VolumeCatcherPulseAudio::update_index_volume(U32 index, F32 volume) +{ + static pa_cvolume cvol; + llpa_cvolume_set(&cvol, mSinkInputNumChannels[index], + llpa_sw_volume_from_linear(volume)); + + pa_context *c = mPAContext; + uint32_t idx = index; + const pa_cvolume *cvolumep = &cvol; + pa_context_success_cb_t cb = nullptr; // okay as null + void *userdata = nullptr; // okay as null + + pa_operation *op; + if ((op = llpa_context_set_sink_input_volume(c, idx, cvolumep, cb, userdata))) + llpa_operation_unref(op); +} + +void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *sii, int eol, void *userdata) +{ + VolumeCatcherPulseAudio *impl = dynamic_cast((VolumeCatcherPulseAudio*)userdata); + llassert(impl); + + if (0 == eol) + { + pa_proplist *proplist = sii->proplist; + pid_t sinkpid = atoll(llpa_proplist_gets(proplist, PA_PROP_APPLICATION_PROCESS_ID)); + + if (isPluginPid( sinkpid )) // does the discovered sinkinput belong to this process? + { + bool is_new = (impl->mSinkInputIndices.find(sii->index) == impl->mSinkInputIndices.end()); + + impl->mSinkInputIndices.insert(sii->index); + impl->mSinkInputNumChannels[sii->index] = sii->channel_map.channels; + + if (is_new) + { + // new! + impl->update_index_volume(sii->index, impl->mDesiredVolume); + } + else + { + // seen it already, do nothing. + } + } + } +} + +void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata) +{ + VolumeCatcherPulseAudio *impl = dynamic_cast((VolumeCatcherPulseAudio*)userdata); + llassert(impl); + + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) + { + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) + { + // forget this sinkinput, if we were caring about it + impl->mSinkInputIndices.erase(index); + impl->mSinkInputNumChannels.erase(index); + } + else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) + { + // ask for more info about this new sinkinput + pa_operation *op; + if ((op = llpa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl))) + { + llpa_operation_unref(op); + } + } + else + { + // property change on this sinkinput - we don't care. + } + break; + + default:; + } +} + +void callback_context_state(pa_context *context, void *userdata) +{ + VolumeCatcherPulseAudio *impl = dynamic_cast((VolumeCatcherPulseAudio*)userdata); + llassert(impl); + + switch (llpa_context_get_state(context)) + { + case PA_CONTEXT_READY: + impl->mConnected = true; + impl->connected_okay(); + break; + case PA_CONTEXT_TERMINATED: + impl->mConnected = false; + break; + case PA_CONTEXT_FAILED: + impl->mConnected = false; + break; + default:; + } +} -- cgit v1.3 From d09ec5e87bfd892306ccdba56944583bd9213aaf Mon Sep 17 00:00:00 2001 From: Maki Date: Sat, 20 Apr 2024 18:34:09 -0400 Subject: Rework macro magic for symbol grabber --- indra/media_plugins/base/media_plugin_base.h | 6 +- .../cef/linux/volume_catcher_pipewire.cpp | 2 - .../cef/linux/volume_catcher_pipewire_syms.inc | 42 +++---- .../cef/linux/volume_catcher_pulseaudio.cpp | 6 +- .../linux/volume_catcher_pulseaudio_glib_syms.inc | 10 +- .../cef/linux/volume_catcher_pulseaudio_syms.inc | 48 ++++---- .../gstreamer10/llmediaimplgstreamer_syms_raw.inc | 122 +++++++++++---------- .../gstreamer10/media_plugin_gstreamer10.cpp | 8 +- 8 files changed, 128 insertions(+), 116 deletions(-) (limited to 'indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp') diff --git a/indra/media_plugins/base/media_plugin_base.h b/indra/media_plugins/base/media_plugin_base.h index 571dd3bd1b..10c3b67235 100644 --- a/indra/media_plugins/base/media_plugin_base.h +++ b/indra/media_plugins/base/media_plugin_base.h @@ -60,11 +60,9 @@ extern SymbolGrabber gSymbolGrabber; // extern SymbolGrabber gSymbolGrabber; -#define LL_SYMBOL_GRABBER gSymbolGrabber - -#define LL_GRAB_SYM(REQUIRED, SYMBOL_NAME, RETURN, ...) \ +#define LL_GRAB_SYM(SYMBOL_GRABBER, REQUIRED, SYMBOL_NAME, RETURN, ...) \ RETURN (*ll##SYMBOL_NAME)(__VA_ARGS__) = nullptr; \ - size_t gRegistered##SYMBOL_NAME = LL_SYMBOL_GRABBER.registerSymbol( \ + size_t gRegistered##SYMBOL_NAME = SYMBOL_GRABBER.registerSymbol( \ { REQUIRED, #SYMBOL_NAME , (apr_dso_handle_sym_t*)&ll##SYMBOL_NAME} \ ); diff --git a/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp b/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp index 213efbfcfb..ca1808d63c 100755 --- a/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp +++ b/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp @@ -45,8 +45,6 @@ extern "C" { } SymbolGrabber pwSymbolGrabber; -#undef LL_SYMBOL_GRABBER -#define LL_SYMBOL_GRABBER pwSymbolGrabber #include "volume_catcher_pipewire_syms.inc" diff --git a/indra/media_plugins/cef/linux/volume_catcher_pipewire_syms.inc b/indra/media_plugins/cef/linux/volume_catcher_pipewire_syms.inc index 14e4a42f1d..dbc0f5f169 100644 --- a/indra/media_plugins/cef/linux/volume_catcher_pipewire_syms.inc +++ b/indra/media_plugins/cef/linux/volume_catcher_pipewire_syms.inc @@ -1,22 +1,26 @@ +#define G pwSymbolGrabber + // required symbols to grab -LL_GRAB_SYM(true, pw_init, void, int *argc, char **argv[]); -// LL_GRAB_SYM(true, pw_main_loop_new, struct pw_main_loop *, const struct spa_dict *props); -// LL_GRAB_SYM(true, pw_main_loop_get_loop, struct pw_loop *, struct pw_main_loop *loop); -// LL_GRAB_SYM(true, pw_main_loop_destroy, void, struct pw_main_loop *loop); -// LL_GRAB_SYM(true, pw_main_loop_run, void, struct pw_main_loop *loop); -LL_GRAB_SYM(true, pw_context_new, struct pw_context *, struct pw_loop *main_loop, struct pw_properties *props, size_t user_data_size); -LL_GRAB_SYM(true, pw_context_destroy, void, struct pw_context *context); -LL_GRAB_SYM(true, pw_context_connect, struct pw_core *, struct pw_context *context, struct pw_properties *properties, size_t user_data_size); -LL_GRAB_SYM(true, pw_thread_loop_new, struct pw_thread_loop *, const char *name, const struct spa_dict *props); -LL_GRAB_SYM(true, pw_thread_loop_destroy, void, struct pw_thread_loop *loop); -LL_GRAB_SYM(true, pw_thread_loop_get_loop, struct pw_loop *, struct pw_thread_loop *loop); -LL_GRAB_SYM(true, pw_thread_loop_start, int, struct pw_thread_loop *loop); -LL_GRAB_SYM(true, pw_thread_loop_stop, void, struct pw_thread_loop *loop); -LL_GRAB_SYM(true, pw_thread_loop_lock, void, struct pw_thread_loop *loop); -LL_GRAB_SYM(true, pw_thread_loop_unlock, void, struct pw_thread_loop *loop); -LL_GRAB_SYM(true, pw_proxy_add_listener, void, struct pw_proxy *proxy, struct spa_hook *listener, const struct pw_proxy_events *events, void *data); -LL_GRAB_SYM(true, pw_proxy_destroy, void, struct pw_proxy *proxy); -LL_GRAB_SYM(true, pw_proxy_get_user_data, void *, struct pw_proxy *proxy); -LL_GRAB_SYM(true, pw_core_disconnect, int, struct pw_core *core); +LL_GRAB_SYM(G, true, pw_init, void, int *argc, char **argv[]); +// LL_GRAB_SYM(G, true, pw_main_loop_new, struct pw_main_loop *, const struct spa_dict *props); +// LL_GRAB_SYM(G, true, pw_main_loop_get_loop, struct pw_loop *, struct pw_main_loop *loop); +// LL_GRAB_SYM(G, true, pw_main_loop_destroy, void, struct pw_main_loop *loop); +// LL_GRAB_SYM(G, true, pw_main_loop_run, void, struct pw_main_loop *loop); +LL_GRAB_SYM(G, true, pw_context_new, struct pw_context *, struct pw_loop *main_loop, struct pw_properties *props, size_t user_data_size); +LL_GRAB_SYM(G, true, pw_context_destroy, void, struct pw_context *context); +LL_GRAB_SYM(G, true, pw_context_connect, struct pw_core *, struct pw_context *context, struct pw_properties *properties, size_t user_data_size); +LL_GRAB_SYM(G, true, pw_thread_loop_new, struct pw_thread_loop *, const char *name, const struct spa_dict *props); +LL_GRAB_SYM(G, true, pw_thread_loop_destroy, void, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_get_loop, struct pw_loop *, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_start, int, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_stop, void, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_lock, void, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_thread_loop_unlock, void, struct pw_thread_loop *loop); +LL_GRAB_SYM(G, true, pw_proxy_add_listener, void, struct pw_proxy *proxy, struct spa_hook *listener, const struct pw_proxy_events *events, void *data); +LL_GRAB_SYM(G, true, pw_proxy_destroy, void, struct pw_proxy *proxy); +LL_GRAB_SYM(G, true, pw_proxy_get_user_data, void *, struct pw_proxy *proxy); +LL_GRAB_SYM(G, true, pw_core_disconnect, int, struct pw_core *core); // optional symbols to grab + +#undef G diff --git a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp index 20a6458ea3..f7f64ef76c 100755 --- a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp +++ b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp @@ -49,8 +49,6 @@ extern "C" { } SymbolGrabber paSymbolGrabber; -#undef LL_SYMBOL_GRABBER -#define LL_SYMBOL_GRABBER paSymbolGrabber #include "volume_catcher_pulseaudio_syms.inc" #include "volume_catcher_pulseaudio_glib_syms.inc" @@ -95,7 +93,9 @@ void VolumeCatcherPulseAudio::init() // probably be loaded separately. Our Linux DSO framework needs refactoring, // we do this sort of thing a lot with practically identical logic... mGotSyms = loadsyms("libpulse-mainloop-glib.so.0"); - if (!mGotSyms) mGotSyms = loadsyms("libpulse.so.0"); + + if (!mGotSyms) + mGotSyms = loadsyms("libpulse.so.0"); if (!mGotSyms) return; diff --git a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_glib_syms.inc b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_glib_syms.inc index 5fba60c188..e9b7196e51 100755 --- a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_glib_syms.inc +++ b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_glib_syms.inc @@ -1,6 +1,10 @@ +#define G paSymbolGrabber + // required symbols to grab -LL_GRAB_SYM(true, pa_glib_mainloop_free, void, pa_glib_mainloop* g) -LL_GRAB_SYM(true, pa_glib_mainloop_get_api, pa_mainloop_api*, pa_glib_mainloop* g) -LL_GRAB_SYM(true, pa_glib_mainloop_new, pa_glib_mainloop *, GMainContext *c) +LL_GRAB_SYM(G, true, pa_glib_mainloop_free, void, pa_glib_mainloop* g) +LL_GRAB_SYM(G, true, pa_glib_mainloop_get_api, pa_mainloop_api*, pa_glib_mainloop* g) +LL_GRAB_SYM(G, true, pa_glib_mainloop_new, pa_glib_mainloop *, GMainContext *c) // optional symbols to grab + +#undef G diff --git a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_syms.inc b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_syms.inc index fe4ad084b6..4859a34405 100755 --- a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_syms.inc +++ b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio_syms.inc @@ -1,25 +1,29 @@ +#define G paSymbolGrabber + // required symbols to grab -LL_GRAB_SYM(true, pa_context_connect, int, pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api) -LL_GRAB_SYM(true, pa_context_disconnect, void, pa_context *c) -LL_GRAB_SYM(true, pa_context_get_sink_input_info, pa_operation*, pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata) -LL_GRAB_SYM(true, pa_context_get_sink_input_info_list, pa_operation*, pa_context *c, pa_sink_input_info_cb_t cb, void *userdata) -LL_GRAB_SYM(true, pa_context_get_state, pa_context_state_t, pa_context *c) -LL_GRAB_SYM(true, pa_context_new_with_proplist, pa_context*, pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist) -LL_GRAB_SYM(true, pa_context_set_sink_input_volume, pa_operation*, pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) -LL_GRAB_SYM(true, pa_context_set_state_callback, void, pa_context *c, pa_context_notify_cb_t cb, void *userdata) -LL_GRAB_SYM(true, pa_context_set_subscribe_callback, void, pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) -LL_GRAB_SYM(true, pa_context_subscribe, pa_operation*, pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata) -LL_GRAB_SYM(true, pa_context_unref, void, pa_context *c) -LL_GRAB_SYM(true, pa_cvolume_set, pa_cvolume*, pa_cvolume *a, unsigned channels, pa_volume_t v) -LL_GRAB_SYM(true, pa_operation_unref, void, pa_operation *o) -LL_GRAB_SYM(true, pa_proplist_free, void, pa_proplist* p) -LL_GRAB_SYM(true, pa_proplist_gets, const char*, pa_proplist *p, const char *key) -LL_GRAB_SYM(true, pa_proplist_new, pa_proplist*, void) -LL_GRAB_SYM(true, pa_proplist_sets, int, pa_proplist *p, const char *key, const char *value) -LL_GRAB_SYM(true, pa_sw_volume_from_linear, pa_volume_t, double v) -// LL_GRAB_SYM(true, pa_mainloop_free, void, pa_mainloop *m) -// LL_GRAB_SYM(true, pa_mainloop_get_api, pa_mainloop_api *, pa_mainloop *m) -// LL_GRAB_SYM(true, pa_mainloop_iterate, int, pa_mainloop *m, int block, int *retval) -// LL_GRAB_SYM(true, pa_mainloop_new, pa_mainloop *, void) +LL_GRAB_SYM(G, true, pa_context_connect, int, pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api) +LL_GRAB_SYM(G, true, pa_context_disconnect, void, pa_context *c) +LL_GRAB_SYM(G, true, pa_context_get_sink_input_info, pa_operation*, pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_get_sink_input_info_list, pa_operation*, pa_context *c, pa_sink_input_info_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_get_state, pa_context_state_t, pa_context *c) +LL_GRAB_SYM(G, true, pa_context_new_with_proplist, pa_context*, pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist) +LL_GRAB_SYM(G, true, pa_context_set_sink_input_volume, pa_operation*, pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_set_state_callback, void, pa_context *c, pa_context_notify_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_set_subscribe_callback, void, pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_subscribe, pa_operation*, pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata) +LL_GRAB_SYM(G, true, pa_context_unref, void, pa_context *c) +LL_GRAB_SYM(G, true, pa_cvolume_set, pa_cvolume*, pa_cvolume *a, unsigned channels, pa_volume_t v) +LL_GRAB_SYM(G, true, pa_operation_unref, void, pa_operation *o) +LL_GRAB_SYM(G, true, pa_proplist_free, void, pa_proplist* p) +LL_GRAB_SYM(G, true, pa_proplist_gets, const char*, pa_proplist *p, const char *key) +LL_GRAB_SYM(G, true, pa_proplist_new, pa_proplist*, void) +LL_GRAB_SYM(G, true, pa_proplist_sets, int, pa_proplist *p, const char *key, const char *value) +LL_GRAB_SYM(G, true, pa_sw_volume_from_linear, pa_volume_t, double v) +// LL_GRAB_SYM(G, true, pa_mainloop_free, void, pa_mainloop *m) +// LL_GRAB_SYM(G, true, pa_mainloop_get_api, pa_mainloop_api *, pa_mainloop *m) +// LL_GRAB_SYM(G, true, pa_mainloop_iterate, int, pa_mainloop *m, int block, int *retval) +// LL_GRAB_SYM(G, true, pa_mainloop_new, pa_mainloop *, void) // optional symbols to grab + +#undef G diff --git a/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc index e5abf22203..6f5bb04bdf 100644 --- a/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc +++ b/indra/media_plugins/gstreamer10/llmediaimplgstreamer_syms_raw.inc @@ -1,67 +1,71 @@ -LL_GRAB_SYM(true, gst_buffer_new, GstBuffer*, void) -LL_GRAB_SYM(true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*) -LL_GRAB_SYM(true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err) -LL_GRAB_SYM(true, gst_message_get_type, GType, void) -LL_GRAB_SYM(true, gst_message_type_get_name, const gchar*, GstMessageType type) -LL_GRAB_SYM(true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug) -LL_GRAB_SYM(true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug) -LL_GRAB_SYM(true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending) -LL_GRAB_SYM(true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state) -LL_GRAB_SYM(true, gst_object_unref, void, gpointer object) -LL_GRAB_SYM(true, gst_object_get_type, GType, void) -LL_GRAB_SYM(true, gst_pipeline_get_type, GType, void) -LL_GRAB_SYM(true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline) -LL_GRAB_SYM(true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data) -LL_GRAB_SYM(true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name) -LL_GRAB_SYM(true, gst_element_get_type, GType, void) -LL_GRAB_SYM(true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template) -LL_GRAB_SYM(true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp) -LL_GRAB_SYM(true, gst_caps_from_string, GstCaps *, const gchar *string) -LL_GRAB_SYM(true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index) -LL_GRAB_SYM(true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type) -LL_GRAB_SYM(true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value) -LL_GRAB_SYM(true, gst_structure_get_value, const GValue *, const GstStructure *structure, const gchar *fieldname) -LL_GRAB_SYM(true, gst_value_get_fraction_numerator, gint, const GValue *value) -LL_GRAB_SYM(true, gst_value_get_fraction_denominator, gint, const GValue *value) -LL_GRAB_SYM(true, gst_structure_get_name, const gchar *, const GstStructure *structure) -LL_GRAB_SYM(true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64) +#define G gstSymbolGrabber -LL_GRAB_SYM(false, gst_registry_fork_set_enabled, void, gboolean enabled) -LL_GRAB_SYM(false, gst_segtrap_set_enabled, void, gboolean enabled) -LL_GRAB_SYM(false, gst_message_parse_buffering, void, GstMessage *message, gint *percent) -LL_GRAB_SYM(false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug) -LL_GRAB_SYM(false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur) -LL_GRAB_SYM(false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano) +LL_GRAB_SYM(G, true, gst_buffer_new, GstBuffer*, void) +LL_GRAB_SYM(G, true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*) +LL_GRAB_SYM(G, true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err) +LL_GRAB_SYM(G, true, gst_message_get_type, GType, void) +LL_GRAB_SYM(G, true, gst_message_type_get_name, const gchar*, GstMessageType type) +LL_GRAB_SYM(G, true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GRAB_SYM(G, true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GRAB_SYM(G, true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending) +LL_GRAB_SYM(G, true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state) +LL_GRAB_SYM(G, true, gst_object_unref, void, gpointer object) +LL_GRAB_SYM(G, true, gst_object_get_type, GType, void) +LL_GRAB_SYM(G, true, gst_pipeline_get_type, GType, void) +LL_GRAB_SYM(G, true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline) +LL_GRAB_SYM(G, true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data) +LL_GRAB_SYM(G, true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name) +LL_GRAB_SYM(G, true, gst_element_get_type, GType, void) +LL_GRAB_SYM(G, true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template) +LL_GRAB_SYM(G, true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp) +LL_GRAB_SYM(G, true, gst_caps_from_string, GstCaps *, const gchar *string) +LL_GRAB_SYM(G, true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index) +LL_GRAB_SYM(G, true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type) +LL_GRAB_SYM(G, true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value) +LL_GRAB_SYM(G, true, gst_structure_get_value, const GValue *, const GstStructure *structure, const gchar *fieldname) +LL_GRAB_SYM(G, true, gst_value_get_fraction_numerator, gint, const GValue *value) +LL_GRAB_SYM(G, true, gst_value_get_fraction_denominator, gint, const GValue *value) +LL_GRAB_SYM(G, true, gst_structure_get_name, const gchar *, const GstStructure *structure) +LL_GRAB_SYM(G, true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64) -LL_GRAB_SYM( true, gst_message_parse_tag, void, GstMessage *, GstTagList **) -LL_GRAB_SYM( true, gst_tag_list_foreach, void, const GstTagList *, GstTagForeachFunc, gpointer) -LL_GRAB_SYM( true, gst_tag_list_get_tag_size, guint, const GstTagList *, const gchar *) -LL_GRAB_SYM( true, gst_tag_list_get_value_index, const GValue *, const GstTagList *, const gchar *, guint) +LL_GRAB_SYM(G, false, gst_registry_fork_set_enabled, void, gboolean enabled) +LL_GRAB_SYM(G, false, gst_segtrap_set_enabled, void, gboolean enabled) +LL_GRAB_SYM(G, false, gst_message_parse_buffering, void, GstMessage *message, gint *percent) +LL_GRAB_SYM(G, false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug) +LL_GRAB_SYM(G, false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur) +LL_GRAB_SYM(G, false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano) -LL_GRAB_SYM( true, gst_caps_new_simple, GstCaps*, const char *, const char*, ... ) +LL_GRAB_SYM(G, true, gst_message_parse_tag, void, GstMessage *, GstTagList **) +LL_GRAB_SYM(G, true, gst_tag_list_foreach, void, const GstTagList *, GstTagForeachFunc, gpointer) +LL_GRAB_SYM(G, true, gst_tag_list_get_tag_size, guint, const GstTagList *, const gchar *) +LL_GRAB_SYM(G, true, gst_tag_list_get_value_index, const GValue *, const GstTagList *, const gchar *, guint) -LL_GRAB_SYM( true, gst_sample_get_caps, GstCaps*, GstSample* ) -LL_GRAB_SYM( true, gst_sample_get_buffer, GstBuffer*, GstSample* ) -LL_GRAB_SYM( true, gst_buffer_map, gboolean, GstBuffer*, GstMapInfo*, GstMapFlags ) -LL_GRAB_SYM( true, gst_buffer_unmap, void, GstBuffer*, GstMapInfo* ) +LL_GRAB_SYM(G, true, gst_caps_new_simple, GstCaps*, const char *, const char*, ... ) -LL_GRAB_SYM( true, gst_app_sink_set_caps, void, GstAppSink*, GstCaps const* ) -LL_GRAB_SYM( true, gst_app_sink_pull_sample, GstSample*, GstAppSink* ) +LL_GRAB_SYM(G, true, gst_sample_get_caps, GstCaps*, GstSample* ) +LL_GRAB_SYM(G, true, gst_sample_get_buffer, GstBuffer*, GstSample* ) +LL_GRAB_SYM(G, true, gst_buffer_map, gboolean, GstBuffer*, GstMapInfo*, GstMapFlags ) +LL_GRAB_SYM(G, true, gst_buffer_unmap, void, GstBuffer*, GstMapInfo* ) -LL_GRAB_SYM( true, g_free, void, gpointer ) -LL_GRAB_SYM( true, g_error_free, void, GError* ) +LL_GRAB_SYM(G, true, gst_app_sink_set_caps, void, GstAppSink*, GstCaps const* ) +LL_GRAB_SYM(G, true, gst_app_sink_pull_sample, GstSample*, GstAppSink* ) -LL_GRAB_SYM( true, g_main_context_pending, gboolean, GMainContext* ) -LL_GRAB_SYM( true, g_main_loop_get_context, GMainContext*, GMainLoop* ) -LL_GRAB_SYM( true, g_main_context_iteration, gboolean, GMainContext*, gboolean ) -LL_GRAB_SYM( true, g_main_loop_new, GMainLoop*, GMainContext*, gboolean ) -LL_GRAB_SYM( true, g_main_loop_quit, void, GMainLoop* ) -LL_GRAB_SYM( true, gst_mini_object_unref, void, GstMiniObject* ) -LL_GRAB_SYM( true, g_object_set, void, gpointer, gchar const*, ... ) -LL_GRAB_SYM( true, g_source_remove, gboolean, guint ) -LL_GRAB_SYM( true, g_value_get_string, gchar const*, GValue const* ) +LL_GRAB_SYM(G, true, g_free, void, gpointer ) +LL_GRAB_SYM(G, true, g_error_free, void, GError* ) -LL_GRAB_SYM( true, gst_debug_set_active, void, gboolean ) -LL_GRAB_SYM( true, gst_debug_add_log_function, void, GstLogFunction, gpointer, GDestroyNotify ) -LL_GRAB_SYM( true, gst_debug_set_default_threshold, void, GstDebugLevel ) -LL_GRAB_SYM( true, gst_debug_message_get , gchar const*, GstDebugMessage * ) \ No newline at end of file +LL_GRAB_SYM(G, true, g_main_context_pending, gboolean, GMainContext* ) +LL_GRAB_SYM(G, true, g_main_loop_get_context, GMainContext*, GMainLoop* ) +LL_GRAB_SYM(G, true, g_main_context_iteration, gboolean, GMainContext*, gboolean ) +LL_GRAB_SYM(G, true, g_main_loop_new, GMainLoop*, GMainContext*, gboolean ) +LL_GRAB_SYM(G, true, g_main_loop_quit, void, GMainLoop* ) +LL_GRAB_SYM(G, true, gst_mini_object_unref, void, GstMiniObject* ) +LL_GRAB_SYM(G, true, g_object_set, void, gpointer, gchar const*, ... ) +LL_GRAB_SYM(G, true, g_source_remove, gboolean, guint ) +LL_GRAB_SYM(G, true, g_value_get_string, gchar const*, GValue const* ) + +LL_GRAB_SYM(G, true, gst_debug_set_active, void, gboolean ) +LL_GRAB_SYM(G, true, gst_debug_add_log_function, void, GstLogFunction, gpointer, GDestroyNotify ) +LL_GRAB_SYM(G, true, gst_debug_set_default_threshold, void, GstDebugLevel ) +LL_GRAB_SYM(G, true, gst_debug_message_get , gchar const*, GstDebugMessage * ) + +#undef G diff --git a/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp b/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp index dbc544d96b..3f636915ea 100644 --- a/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp +++ b/indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp @@ -41,9 +41,9 @@ extern "C" { #include #include - } -SymbolGrabber gSymbolGrabber; + +SymbolGrabber gstSymbolGrabber; #include "llmediaimplgstreamer_syms_raw.inc" @@ -650,7 +650,7 @@ bool MediaPluginGStreamer10::startup() vctDSONames.push_back( "libgstapp-1.0.so.0" ); vctDSONames.push_back( "libglib-2.0.so.0" ); vctDSONames.push_back( "libgobject-2.0.so" ); - if( !gSymbolGrabber.grabSymbols( vctDSONames ) ) + if( !gstSymbolGrabber.grabSymbols( vctDSONames ) ) return false; if (llgst_segtrap_set_enabled) @@ -712,7 +712,7 @@ bool MediaPluginGStreamer10::closedown() if (!mDoneInit) return false; // error - gSymbolGrabber.ungrabSymbols(); + gstSymbolGrabber.ungrabSymbols(); mDoneInit = false; return true; -- cgit v1.3 From 3dc5fa00753bb889280771a2cd17029aa1e42f24 Mon Sep 17 00:00:00 2001 From: Nicky Date: Mon, 22 Apr 2024 09:32:54 +0200 Subject: Tabs to spaces --- .../cef/linux/volume_catcher_linux.cpp | 40 +-- .../cef/linux/volume_catcher_pipewire.cpp | 206 +++++------ .../cef/linux/volume_catcher_pulseaudio.cpp | 394 ++++++++++----------- 3 files changed, 320 insertions(+), 320 deletions(-) (limited to 'indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp') diff --git a/indra/media_plugins/cef/linux/volume_catcher_linux.cpp b/indra/media_plugins/cef/linux/volume_catcher_linux.cpp index 439c0a6768..b4d20935e7 100644 --- a/indra/media_plugins/cef/linux/volume_catcher_linux.cpp +++ b/indra/media_plugins/cef/linux/volume_catcher_linux.cpp @@ -36,45 +36,45 @@ VolumeCatcher::VolumeCatcher() void VolumeCatcher::onEnablePipeWireVolumeCatcher(bool enable) { - if (pimpl != nullptr) - return; + if (pimpl != nullptr) + return; - if (enable) + if (enable) { - LL_DEBUGS() << "volume catcher using pipewire" << LL_ENDL; - pimpl = new VolumeCatcherPipeWire(); - } + LL_DEBUGS() << "volume catcher using pipewire" << LL_ENDL; + pimpl = new VolumeCatcherPipeWire(); + } else { - LL_DEBUGS() << "volume catcher using pulseaudio" << LL_ENDL; - pimpl = new VolumeCatcherPulseAudio(); - } + LL_DEBUGS() << "volume catcher using pulseaudio" << LL_ENDL; + pimpl = new VolumeCatcherPulseAudio(); + } } VolumeCatcher::~VolumeCatcher() { - if (pimpl != nullptr) + if (pimpl != nullptr) { - delete pimpl; - pimpl = nullptr; - } + delete pimpl; + pimpl = nullptr; + } } void VolumeCatcher::setVolume(F32 volume) { - if (pimpl != nullptr) { - pimpl->setVolume(volume); - } + if (pimpl != nullptr) { + pimpl->setVolume(volume); + } } void VolumeCatcher::setPan(F32 pan) { - if (pimpl != nullptr) - pimpl->setPan(pan); + if (pimpl != nullptr) + pimpl->setPan(pan); } void VolumeCatcher::pump() { - if (pimpl != nullptr) - pimpl->pump(); + if (pimpl != nullptr) + pimpl->pump(); } diff --git a/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp b/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp index 8617468f17..0fb9d26476 100755 --- a/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp +++ b/indra/media_plugins/cef/linux/volume_catcher_pipewire.cpp @@ -52,77 +52,77 @@ SymbolGrabber pwSymbolGrabber; VolumeCatcherPipeWire::VolumeCatcherPipeWire() { - init(); + init(); } VolumeCatcherPipeWire::~VolumeCatcherPipeWire() { - cleanup(); + cleanup(); } static void registryEventGlobal( - void *data, uint32_t id, uint32_t permissions, const char *type, - uint32_t version, const struct spa_dict *props) + void *data, uint32_t id, uint32_t permissions, const char *type, + uint32_t version, const struct spa_dict *props) { - static_cast(data)->handleRegistryEventGlobal( - id, permissions, type, version, props - ); + static_cast(data)->handleRegistryEventGlobal( + id, permissions, type, version, props + ); } static const struct pw_registry_events REGISTRY_EVENTS = { - .version = PW_VERSION_REGISTRY_EVENTS, + .version = PW_VERSION_REGISTRY_EVENTS, .global = registryEventGlobal, }; bool VolumeCatcherPipeWire::loadsyms(std::string pw_dso_name) { - return pwSymbolGrabber.grabSymbols({ pw_dso_name }); + return pwSymbolGrabber.grabSymbols({ pw_dso_name }); } void VolumeCatcherPipeWire::init() { LL_DEBUGS() << "init" << LL_ENDL; - mGotSyms = loadsyms("libpipewire-0.3.so.0"); - - if (!mGotSyms) - return; + mGotSyms = loadsyms("libpipewire-0.3.so.0"); + + if (!mGotSyms) + return; LL_DEBUGS() << "successfully got symbols" << LL_ENDL; - llpw_init(nullptr, nullptr); + llpw_init(nullptr, nullptr); - mThreadLoop = llpw_thread_loop_new("SL Plugin Volume Adjuster", nullptr); + mThreadLoop = llpw_thread_loop_new("SL Plugin Volume Adjuster", nullptr); - if (!mThreadLoop) - return; + if (!mThreadLoop) + return; - // i dont think we need to lock this early - // std::lock_guard pwLock(*this); + // i dont think we need to lock this early + // std::lock_guard pwLock(*this); - mContext = llpw_context_new( - llpw_thread_loop_get_loop(mThreadLoop), nullptr, 0 - ); + mContext = llpw_context_new( + llpw_thread_loop_get_loop(mThreadLoop), nullptr, 0 + ); - if (!mContext) - return; + if (!mContext) + return; - mCore = llpw_context_connect(mContext, nullptr, 0); + mCore = llpw_context_connect(mContext, nullptr, 0); - if (!mCore) - return; + if (!mCore) + return; - mRegistry = pw_core_get_registry(mCore, PW_VERSION_REGISTRY, 0); + mRegistry = pw_core_get_registry(mCore, PW_VERSION_REGISTRY, 0); LL_DEBUGS() << "pw_core_get_registry: " << (mRegistry?"success":"nullptr") << LL_ENDL; - spa_zero(mRegistryListener); + spa_zero(mRegistryListener); - pw_registry_add_listener( - mRegistry, &mRegistryListener, ®ISTRY_EVENTS, this - ); + pw_registry_add_listener( + mRegistry, &mRegistryListener, ®ISTRY_EVENTS, this + ); - llpw_thread_loop_start(mThreadLoop); + llpw_thread_loop_start(mThreadLoop); LL_DEBUGS() << "thread loop started" << LL_ENDL; } @@ -150,52 +150,52 @@ void VolumeCatcherPipeWire::cleanup() llpw_context_destroy(mContext); } - if (!mThreadLoop) - return; + if (!mThreadLoop) + return; - llpw_thread_loop_stop(mThreadLoop); - llpw_thread_loop_destroy(mThreadLoop); + llpw_thread_loop_stop(mThreadLoop); + llpw_thread_loop_destroy(mThreadLoop); LL_DEBUGS() << "cleanup done" << LL_ENDL; } void VolumeCatcherPipeWire::lock() { - if (!mThreadLoop) - return; + if (!mThreadLoop) + return; - llpw_thread_loop_lock(mThreadLoop); + llpw_thread_loop_lock(mThreadLoop); } void VolumeCatcherPipeWire::unlock() { - if (!mThreadLoop) - return; + if (!mThreadLoop) + return; - llpw_thread_loop_unlock(mThreadLoop); + llpw_thread_loop_unlock(mThreadLoop); } void VolumeCatcherPipeWire::ChildNode::updateVolume() { - if (!mActive) - return; + if (!mActive) + return; - F32 volume = std::clamp(mImpl->mVolume, 0.0f, 1.0f); + F32 volume = std::clamp(mImpl->mVolume, 0.0f, 1.0f); - const uint32_t channels = 1; - float volumes[channels]; - volumes[0] = volume; + const uint32_t channels = 1; + float volumes[channels]; + volumes[0] = volume; - uint8_t buffer[512]; + uint8_t buffer[512]; - spa_pod_builder builder; - spa_pod_builder_init(&builder, buffer, sizeof(buffer)); + spa_pod_builder builder; + spa_pod_builder_init(&builder, buffer, sizeof(buffer)); - spa_pod_frame frame; - spa_pod_builder_push_object(&builder, &frame, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props); - spa_pod_builder_prop(&builder, SPA_PROP_channelVolumes, 0); - spa_pod_builder_array(&builder, sizeof(float), SPA_TYPE_Float, channels, volumes); - spa_pod* pod = static_cast(spa_pod_builder_pop(&builder, &frame)); + spa_pod_frame frame; + spa_pod_builder_push_object(&builder, &frame, SPA_TYPE_OBJECT_Props, SPA_PARAM_Props); + spa_pod_builder_prop(&builder, SPA_PROP_channelVolumes, 0); + spa_pod_builder_array(&builder, sizeof(float), SPA_TYPE_Float, channels, volumes); + spa_pod* pod = static_cast(spa_pod_builder_pop(&builder, &frame)); { std::lock_guard pwLock(*mImpl); @@ -205,18 +205,18 @@ void VolumeCatcherPipeWire::ChildNode::updateVolume() void VolumeCatcherPipeWire::ChildNode::destroy() { - if (!mActive) - return; + if (!mActive) + return; - mActive = false; + mActive = false; { std::unique_lock childNodesLock(mImpl->mChildNodesMutex); mImpl->mChildNodes.erase(this); } - spa_hook_remove(&mNodeListener); - spa_hook_remove(&mProxyListener); + spa_hook_remove(&mNodeListener); + spa_hook_remove(&mProxyListener); { std::lock_guard pwLock(*mImpl); @@ -226,23 +226,23 @@ void VolumeCatcherPipeWire::ChildNode::destroy() static void nodeEventInfo(void* data, const struct pw_node_info* info) { - const char* processId = spa_dict_lookup(info->props, PW_KEY_APP_PROCESS_ID); + const char* processId = spa_dict_lookup(info->props, PW_KEY_APP_PROCESS_ID); + + if (processId == nullptr) + return; - if (processId == nullptr) - return; - - pid_t pid = atoll(processId); + pid_t pid = atoll(processId); - if (!isPluginPid(pid)) - return; + if (!isPluginPid(pid)) + return; const char* appName = spa_dict_lookup(info->props, PW_KEY_APP_NAME); LL_DEBUGS() << "got app: " << appName << LL_ENDL; - - auto* const childNode = static_cast(data); + + auto* const childNode = static_cast(data); LL_DEBUGS() << "init volume: " << childNode->mImpl->mVolume << LL_ENDL; - childNode->updateVolume(); + childNode->updateVolume(); { std::lock_guard childNodesLock(childNode->mImpl->mChildNodesMutex); @@ -251,59 +251,59 @@ static void nodeEventInfo(void* data, const struct pw_node_info* info) } static const struct pw_node_events NODE_EVENTS = { - .version = PW_VERSION_CLIENT_EVENTS, - .info = nodeEventInfo, + .version = PW_VERSION_CLIENT_EVENTS, + .info = nodeEventInfo, }; static void proxyEventDestroy(void* data) { - auto* const childNode = static_cast(data); - childNode->destroy(); + auto* const childNode = static_cast(data); + childNode->destroy(); } static void proxyEventRemoved(void* data) { - auto* const childNode = static_cast(data); - childNode->destroy(); + auto* const childNode = static_cast(data); + childNode->destroy(); } static const struct pw_proxy_events PROXY_EVENTS = { - .version = PW_VERSION_PROXY_EVENTS, + .version = PW_VERSION_PROXY_EVENTS, .destroy = proxyEventDestroy, - .removed = proxyEventRemoved, + .removed = proxyEventRemoved, }; void VolumeCatcherPipeWire::handleRegistryEventGlobal( - uint32_t id, uint32_t permissions, const char *type, uint32_t version, - const struct spa_dict *props) + uint32_t id, uint32_t permissions, const char *type, uint32_t version, + const struct spa_dict *props) { - if (props == nullptr || type == nullptr || strcmp(type, PW_TYPE_INTERFACE_Node) != 0) - return; - - const char* mediaClass = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS); - - if (mediaClass == nullptr || strcmp(mediaClass, "Stream/Output/Audio") != 0) - return; - - pw_proxy* proxy = static_cast( - pw_registry_bind(mRegistry, id, type, PW_VERSION_CLIENT, sizeof(ChildNode)) - ); - - auto* const childNode = static_cast(llpw_proxy_get_user_data(proxy)); - - childNode->mActive = true; - childNode->mProxy = proxy; - childNode->mImpl = this; - - pw_node_add_listener(proxy, &childNode->mNodeListener, &NODE_EVENTS, childNode); - llpw_proxy_add_listener(proxy, &childNode->mProxyListener, &PROXY_EVENTS, childNode); + if (props == nullptr || type == nullptr || strcmp(type, PW_TYPE_INTERFACE_Node) != 0) + return; + + const char* mediaClass = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS); + + if (mediaClass == nullptr || strcmp(mediaClass, "Stream/Output/Audio") != 0) + return; + + pw_proxy* proxy = static_cast( + pw_registry_bind(mRegistry, id, type, PW_VERSION_CLIENT, sizeof(ChildNode)) + ); + + auto* const childNode = static_cast(llpw_proxy_get_user_data(proxy)); + + childNode->mActive = true; + childNode->mProxy = proxy; + childNode->mImpl = this; + + pw_node_add_listener(proxy, &childNode->mNodeListener, &NODE_EVENTS, childNode); + llpw_proxy_add_listener(proxy, &childNode->mProxyListener, &PROXY_EVENTS, childNode); } void VolumeCatcherPipeWire::setVolume(F32 volume) { LL_DEBUGS() << "setting volume to: " << volume << LL_ENDL; - mVolume = volume; + mVolume = volume; { std::unique_lock childNodeslock(mChildNodesMutex); diff --git a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp index f7f64ef76c..9417c49d38 100755 --- a/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp +++ b/indra/media_plugins/cef/linux/volume_catcher_pulseaudio.cpp @@ -57,124 +57,124 @@ SymbolGrabber paSymbolGrabber; // PulseAudio requires a chain of callbacks with C linkage extern "C" { - void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *i, int eol, void *userdata); - void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata); - void callback_context_state(pa_context *context, void *userdata); + void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *i, int eol, void *userdata); + void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata); + void callback_context_state(pa_context *context, void *userdata); } VolumeCatcherPulseAudio::VolumeCatcherPulseAudio() - : mDesiredVolume(0.0f), - mMainloop(nullptr), - mPAContext(nullptr), - mConnected(false), - mGotSyms(false) + : mDesiredVolume(0.0f), + mMainloop(nullptr), + mPAContext(nullptr), + mConnected(false), + mGotSyms(false) { - init(); + init(); } VolumeCatcherPulseAudio::~VolumeCatcherPulseAudio() { - cleanup(); + cleanup(); } bool VolumeCatcherPulseAudio::loadsyms(std::string pulse_dso_name) { - return paSymbolGrabber.grabSymbols({ pulse_dso_name }); + return paSymbolGrabber.grabSymbols({ pulse_dso_name }); } void VolumeCatcherPulseAudio::init() { - // try to be as defensive as possible because PA's interface is a - // bit fragile and (for our purposes) we'd rather simply not function - // than crash - - // we cheat and rely upon libpulse-mainloop-glib.so.0 to pull-in - // libpulse.so.0 - this isn't a great assumption, and the two DSOs should - // probably be loaded separately. Our Linux DSO framework needs refactoring, - // we do this sort of thing a lot with practically identical logic... - mGotSyms = loadsyms("libpulse-mainloop-glib.so.0"); - - if (!mGotSyms) - mGotSyms = loadsyms("libpulse.so.0"); - - if (!mGotSyms) - return; - - mMainloop = llpa_glib_mainloop_new(g_main_context_default()); - - if (mMainloop) - { - pa_mainloop_api *api = llpa_glib_mainloop_get_api(mMainloop); - - if (api) - { - pa_proplist *proplist = llpa_proplist_new(); - - if (proplist) - { - llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "multimedia-player"); - llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.secondlife.viewer.mediaplugvoladjust"); - llpa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "SL Plugin Volume Adjuster"); - llpa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, "1"); - - // plain old pa_context_new() is broken! - mPAContext = llpa_context_new_with_proplist(api, nullptr, proplist); - - llpa_proplist_free(proplist); - } - } - } - - // Now we've set up a PA context and mainloop, try connecting the - // PA context to a PA daemon. - if (mPAContext) - { - llpa_context_set_state_callback(mPAContext, callback_context_state, this); - pa_context_flags_t cflags = (pa_context_flags)0; // maybe add PA_CONTEXT_NOAUTOSPAWN? - if (llpa_context_connect(mPAContext, nullptr, cflags, nullptr) >= 0) - { - // Okay! We haven't definitely connected, but we - // haven't definitely failed yet. - } - else - { - // Failed to connect to PA manager... we'll leave - // things like that. Perhaps we should try again later. - } - } + // try to be as defensive as possible because PA's interface is a + // bit fragile and (for our purposes) we'd rather simply not function + // than crash + + // we cheat and rely upon libpulse-mainloop-glib.so.0 to pull-in + // libpulse.so.0 - this isn't a great assumption, and the two DSOs should + // probably be loaded separately. Our Linux DSO framework needs refactoring, + // we do this sort of thing a lot with practically identical logic... + mGotSyms = loadsyms("libpulse-mainloop-glib.so.0"); + + if (!mGotSyms) + mGotSyms = loadsyms("libpulse.so.0"); + + if (!mGotSyms) + return; + + mMainloop = llpa_glib_mainloop_new(g_main_context_default()); + + if (mMainloop) + { + pa_mainloop_api *api = llpa_glib_mainloop_get_api(mMainloop); + + if (api) + { + pa_proplist *proplist = llpa_proplist_new(); + + if (proplist) + { + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "multimedia-player"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.secondlife.viewer.mediaplugvoladjust"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "SL Plugin Volume Adjuster"); + llpa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, "1"); + + // plain old pa_context_new() is broken! + mPAContext = llpa_context_new_with_proplist(api, nullptr, proplist); + + llpa_proplist_free(proplist); + } + } + } + + // Now we've set up a PA context and mainloop, try connecting the + // PA context to a PA daemon. + if (mPAContext) + { + llpa_context_set_state_callback(mPAContext, callback_context_state, this); + pa_context_flags_t cflags = (pa_context_flags)0; // maybe add PA_CONTEXT_NOAUTOSPAWN? + if (llpa_context_connect(mPAContext, nullptr, cflags, nullptr) >= 0) + { + // Okay! We haven't definitely connected, but we + // haven't definitely failed yet. + } + else + { + // Failed to connect to PA manager... we'll leave + // things like that. Perhaps we should try again later. + } + } } void VolumeCatcherPulseAudio::cleanup() { - mConnected = false; + mConnected = false; - if (mGotSyms && mPAContext) - { - llpa_context_disconnect(mPAContext); - llpa_context_unref(mPAContext); - } + if (mGotSyms && mPAContext) + { + llpa_context_disconnect(mPAContext); + llpa_context_unref(mPAContext); + } - mPAContext = nullptr; + mPAContext = nullptr; - if (mGotSyms && mMainloop) - llpa_glib_mainloop_free(mMainloop); + if (mGotSyms && mMainloop) + llpa_glib_mainloop_free(mMainloop); - mMainloop = nullptr; + mMainloop = nullptr; } void VolumeCatcherPulseAudio::setVolume(F32 volume) { - mDesiredVolume = volume; - - if (!mGotSyms) - return; + mDesiredVolume = volume; - if (mConnected && mPAContext) - { - update_all_volumes(mDesiredVolume); - } + if (!mGotSyms) + return; - pump(); + if (mConnected && mPAContext) + { + update_all_volumes(mDesiredVolume); + } + + pump(); } void VolumeCatcherPulseAudio::setPan(F32 pan) @@ -183,140 +183,140 @@ void VolumeCatcherPulseAudio::setPan(F32 pan) void VolumeCatcherPulseAudio::pump() { - gboolean may_block = FALSE; - g_main_context_iteration(g_main_context_default(), may_block); + gboolean may_block = FALSE; + g_main_context_iteration(g_main_context_default(), may_block); } void VolumeCatcherPulseAudio::connected_okay() { - pa_operation *op; - - // fetch global list of existing sinkinputs - if ((op = llpa_context_get_sink_input_info_list(mPAContext, - callback_discovered_sinkinput, - this))) - { - llpa_operation_unref(op); - } - - // subscribe to future global sinkinput changes - llpa_context_set_subscribe_callback(mPAContext, - callback_subscription_alert, - this); - if ((op = llpa_context_subscribe(mPAContext, (pa_subscription_mask_t) - (PA_SUBSCRIPTION_MASK_SINK_INPUT), + pa_operation *op; + + // fetch global list of existing sinkinputs + if ((op = llpa_context_get_sink_input_info_list(mPAContext, + callback_discovered_sinkinput, + this))) + { + llpa_operation_unref(op); + } + + // subscribe to future global sinkinput changes + llpa_context_set_subscribe_callback(mPAContext, + callback_subscription_alert, + this); + if ((op = llpa_context_subscribe(mPAContext, (pa_subscription_mask_t) + (PA_SUBSCRIPTION_MASK_SINK_INPUT), nullptr, nullptr))) - { - llpa_operation_unref(op); - } + { + llpa_operation_unref(op); + } } void VolumeCatcherPulseAudio::update_all_volumes(F32 volume) { - for (std::set::iterator it = mSinkInputIndices.begin(); - it != mSinkInputIndices.end(); ++it) - { - update_index_volume(*it, volume); - } + for (std::set::iterator it = mSinkInputIndices.begin(); + it != mSinkInputIndices.end(); ++it) + { + update_index_volume(*it, volume); + } } void VolumeCatcherPulseAudio::update_index_volume(U32 index, F32 volume) { - static pa_cvolume cvol; - llpa_cvolume_set(&cvol, mSinkInputNumChannels[index], - llpa_sw_volume_from_linear(volume)); - - pa_context *c = mPAContext; - uint32_t idx = index; - const pa_cvolume *cvolumep = &cvol; - pa_context_success_cb_t cb = nullptr; // okay as null - void *userdata = nullptr; // okay as null - - pa_operation *op; - if ((op = llpa_context_set_sink_input_volume(c, idx, cvolumep, cb, userdata))) - llpa_operation_unref(op); + static pa_cvolume cvol; + llpa_cvolume_set(&cvol, mSinkInputNumChannels[index], + llpa_sw_volume_from_linear(volume)); + + pa_context *c = mPAContext; + uint32_t idx = index; + const pa_cvolume *cvolumep = &cvol; + pa_context_success_cb_t cb = nullptr; // okay as null + void *userdata = nullptr; // okay as null + + pa_operation *op; + if ((op = llpa_context_set_sink_input_volume(c, idx, cvolumep, cb, userdata))) + llpa_operation_unref(op); } void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *sii, int eol, void *userdata) { - VolumeCatcherPulseAudio *impl = dynamic_cast((VolumeCatcherPulseAudio*)userdata); - llassert(impl); - - if (0 == eol) - { - pa_proplist *proplist = sii->proplist; - pid_t sinkpid = atoll(llpa_proplist_gets(proplist, PA_PROP_APPLICATION_PROCESS_ID)); - - if (isPluginPid( sinkpid )) // does the discovered sinkinput belong to this process? - { - bool is_new = (impl->mSinkInputIndices.find(sii->index) == impl->mSinkInputIndices.end()); - - impl->mSinkInputIndices.insert(sii->index); - impl->mSinkInputNumChannels[sii->index] = sii->channel_map.channels; - - if (is_new) - { - // new! - impl->update_index_volume(sii->index, impl->mDesiredVolume); - } - else - { - // seen it already, do nothing. - } - } - } + VolumeCatcherPulseAudio *impl = dynamic_cast((VolumeCatcherPulseAudio*)userdata); + llassert(impl); + + if (0 == eol) + { + pa_proplist *proplist = sii->proplist; + pid_t sinkpid = atoll(llpa_proplist_gets(proplist, PA_PROP_APPLICATION_PROCESS_ID)); + + if (isPluginPid( sinkpid )) // does the discovered sinkinput belong to this process? + { + bool is_new = (impl->mSinkInputIndices.find(sii->index) == impl->mSinkInputIndices.end()); + + impl->mSinkInputIndices.insert(sii->index); + impl->mSinkInputNumChannels[sii->index] = sii->channel_map.channels; + + if (is_new) + { + // new! + impl->update_index_volume(sii->index, impl->mDesiredVolume); + } + else + { + // seen it already, do nothing. + } + } + } } void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata) { - VolumeCatcherPulseAudio *impl = dynamic_cast((VolumeCatcherPulseAudio*)userdata); - llassert(impl); + VolumeCatcherPulseAudio *impl = dynamic_cast((VolumeCatcherPulseAudio*)userdata); + llassert(impl); - switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) - { + switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) + { case PA_SUBSCRIPTION_EVENT_SINK_INPUT: - if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) - { - // forget this sinkinput, if we were caring about it - impl->mSinkInputIndices.erase(index); - impl->mSinkInputNumChannels.erase(index); - } - else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) - { - // ask for more info about this new sinkinput - pa_operation *op; - if ((op = llpa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl))) - { - llpa_operation_unref(op); - } - } - else - { - // property change on this sinkinput - we don't care. - } - break; - - default:; - } + if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) + { + // forget this sinkinput, if we were caring about it + impl->mSinkInputIndices.erase(index); + impl->mSinkInputNumChannels.erase(index); + } + else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) + { + // ask for more info about this new sinkinput + pa_operation *op; + if ((op = llpa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl))) + { + llpa_operation_unref(op); + } + } + else + { + // property change on this sinkinput - we don't care. + } + break; + + default:; + } } void callback_context_state(pa_context *context, void *userdata) { - VolumeCatcherPulseAudio *impl = dynamic_cast((VolumeCatcherPulseAudio*)userdata); - llassert(impl); - - switch (llpa_context_get_state(context)) - { - case PA_CONTEXT_READY: - impl->mConnected = true; - impl->connected_okay(); - break; - case PA_CONTEXT_TERMINATED: - impl->mConnected = false; - break; - case PA_CONTEXT_FAILED: - impl->mConnected = false; - break; - default:; - } + VolumeCatcherPulseAudio *impl = dynamic_cast((VolumeCatcherPulseAudio*)userdata); + llassert(impl); + + switch (llpa_context_get_state(context)) + { + case PA_CONTEXT_READY: + impl->mConnected = true; + impl->connected_okay(); + break; + case PA_CONTEXT_TERMINATED: + impl->mConnected = false; + break; + case PA_CONTEXT_FAILED: + impl->mConnected = false; + break; + default:; + } } -- cgit v1.3