diff options
| -rw-r--r-- | indra/media_plugins/webkit/linux_volume_catcher.cpp | 141 | 
1 files changed, 140 insertions, 1 deletions
| diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 8d8600c344..43731fe8d0 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -40,19 +40,158 @@  #include <pulse/subscribe.h>  #include <pulse/glib-mainloop.h> // There's no special reason why we want the *glib* PA mainloop, but the generic polling implementation seems broken. +#include "linux_volume_catcher.h" + +//////////////////////////////////////////////////// + +LinuxVolumeCatcher::LinuxVolumeCatcher() +{ +	pimpl = new LinuxVolumeCatcherImpl(); +} + +LinuxVolumeCatcher::LinuxVolumeCatcher~() +{ +	delete pimpl; +	pimpl = NULL; +} + +void LinuxVolumeCatcher::setVol(F32 volume) +{ +	llassert(pimpl); +	pimpl->setVol(volume); +} + +void LinuxVolumeCatcher::pump() +{ +	llassert(pimpl); +	pimpl->pump(); +} + +///////////////////////////////////////////////////// + +// 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); +} + +  class LinuxVolumeCatcherImpl  {  public: +	LinuxVolumeCatcherImpl(); +	~LinuxVolumeCatcherImpl(); +  	void setVol(F32 volume);  	void pump(void);  private: +	void init(); +	void cleanup(); + +	void connected_okay(); +	void update_index_volume(F32 volume); +	void update_all_volumes(F32 volume); +  	F32 mDesiredVolume;  	pa_glib_mainloop *mMainloop; -	pa_context *mLastContext; +	pa_context *mPAContext;  	bool connected;  	std::set<U32> mSinkInputIndices;  	std::map<U32,U32> mSinkInputNumChannels; +}; + +LinuxVolumeCatcherImpl::LinuxVolumeCatcherImpl() +	: mDesiredVolume(0.0f), +	  mMainloop(NULL), +	  mPAContext(NULL), +	  mConnected(false) +{ +	init();  } +LinuxVolumeCatcherImpl::~LinuxVolumeCatcherImpl() +{ +	cleanup(); +} + +LinuxVolumeCatcherImpl::init() +{ +	// try to be as robust as possible because PA's interface is a +	// bit fragile and (for our purposes) we'd rather simply not function +	// than crash +	mMainloop = pa_glib_mainloop_new(g_main_context_default()); +	if (mMainloop) +	{ +		pa_mainloop_api *api = pa_glib_mainloop_get_api(mMainloop); +		if (api) +		{ +			pa_proplist *proplist = pa_proplist_new(); +			if (proplist) +			{ +				pa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "multimedia-player"); +				pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "com.secondlife.viewer.mediaplugvoladjust"); +				pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "SL Plugin Volume Adjuster"); +				pa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, "1"); + +				// plain old pa_context_new() is broken! +				mPAContext = pa_context_new_with_proplist(api, NULL, proplist); +				pa_proplist_free(proplist); +			} +		} +	} + +	// Now we've set up a PA context and mainloop, try connecting the +	// PA context to a PA daemon. +	if (mPAContext) +	{ +		pa_context_set_state_callback(mPAContext, callback_context_state, NULL); +		pa_context_flags_t cflags = 0; // maybe add PA_CONTEXT_NOAUTOSPAWN? +		if (pa_context_connect(mPAContext, NULL, cflags, NULL) >= 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. +		} +	} +} + +LinuxVolumeCatcherImpl::cleanup() +{ +	// there's some cleanup we could do, but do nothing... for now. +} + +LinuxVolumeCatcherImpl::setVol(F32 volume) +{ +	mDesiredVolume = volume; +	 +	if (mConnected && mPAContext) +	{ +		update_all_volumes(mDesiredVolume); +	} + +	pump(); +} + +LinuxVolumeCatcherImpl::pump() +{ +	g_main_context_iteration(g_main_context_default()); +} + +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) +{ +} | 
