diff options
Diffstat (limited to 'indra/media_plugins')
-rw-r--r-- | indra/media_plugins/webkit/CMakeLists.txt | 11 | ||||
-rw-r--r-- | indra/media_plugins/webkit/linux_volume_catcher.cpp | 202 |
2 files changed, 170 insertions, 43 deletions
diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt index a9e202da99..a43680bb16 100644 --- a/indra/media_plugins/webkit/CMakeLists.txt +++ b/indra/media_plugins/webkit/CMakeLists.txt @@ -34,11 +34,6 @@ set(media_plugin_webkit_SOURCE_FILES media_plugin_webkit.cpp ) -add_library(media_plugin_webkit - SHARED - ${media_plugin_webkit_SOURCE_FILES} -) - set(media_plugin_webkit_LINK_LIBRARIES ${LLPLUGIN_LIBRARIES} ${MEDIA_PLUGIN_BASE_LIBRARIES} @@ -48,6 +43,7 @@ set(media_plugin_webkit_LINK_LIBRARIES ) if (LINUX) + list(APPEND media_plugin_webkit_SOURCE_FILES linux_volume_catcher.cpp) list(APPEND media_plugin_webkit_LINK_LIBRARIES ${UI_LIBRARIES} # for glib/GTK pulse @@ -55,6 +51,11 @@ if (LINUX) ) endif (LINUX) +add_library(media_plugin_webkit + SHARED + ${media_plugin_webkit_SOURCE_FILES} +) + target_link_libraries(media_plugin_webkit ${media_plugin_webkit_LINK_LIBRARIES}) add_dependencies(media_plugin_webkit diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp index 43731fe8d0..6eb5a9a30c 100644 --- a/indra/media_plugins/webkit/linux_volume_catcher.cpp +++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp @@ -44,31 +44,6 @@ //////////////////////////////////////////////////// -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); @@ -86,20 +61,21 @@ public: void setVol(F32 volume); void pump(void); -private: + // for internal use - can't be private because used from our C callbacks + void init(); void cleanup(); - void connected_okay(); - void update_index_volume(F32 volume); void update_all_volumes(F32 volume); + void update_index_volume(U32 index, F32 volume); + void connected_okay(); + std::set<U32> mSinkInputIndices; + std::map<U32,U32> mSinkInputNumChannels; F32 mDesiredVolume; pa_glib_mainloop *mMainloop; pa_context *mPAContext; - bool connected; - std::set<U32> mSinkInputIndices; - std::map<U32,U32> mSinkInputNumChannels; + bool mConnected; }; LinuxVolumeCatcherImpl::LinuxVolumeCatcherImpl() @@ -116,7 +92,7 @@ LinuxVolumeCatcherImpl::~LinuxVolumeCatcherImpl() cleanup(); } -LinuxVolumeCatcherImpl::init() +void 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 @@ -146,8 +122,8 @@ LinuxVolumeCatcherImpl::init() // 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? + pa_context_set_state_callback(mPAContext, callback_context_state, this); + pa_context_flags_t cflags = (pa_context_flags)0; // maybe add PA_CONTEXT_NOAUTOSPAWN? if (pa_context_connect(mPAContext, NULL, cflags, NULL) >= 0) { // Okay! We haven't definitely connected, but we @@ -161,12 +137,14 @@ LinuxVolumeCatcherImpl::init() } } -LinuxVolumeCatcherImpl::cleanup() +void LinuxVolumeCatcherImpl::cleanup() { // there's some cleanup we could do, but do nothing... for now. + + mConnected = false; } -LinuxVolumeCatcherImpl::setVol(F32 volume) +void LinuxVolumeCatcherImpl::setVol(F32 volume) { mDesiredVolume = volume; @@ -178,20 +156,168 @@ LinuxVolumeCatcherImpl::setVol(F32 volume) pump(); } -LinuxVolumeCatcherImpl::pump() +void 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 LinuxVolumeCatcherImpl::connected_okay() { + pa_operation *op; + + // fetch global list of existing sinkinputs + if (op = pa_context_get_sink_input_info_list(mPAContext, + callback_discovered_sinkinput, + this)) + { + pa_operation_unref(op); + } + + // subscribe to future global sinkinput changes + pa_context_set_subscribe_callback(mPAContext, + callback_subscription_alert, + this); + if (op = pa_context_subscribe(mPAContext, (pa_subscription_mask_t) + (PA_SUBSCRIPTION_MASK_SINK_INPUT), + NULL, NULL)) + { + pa_operation_unref(op); + } +} + +void LinuxVolumeCatcherImpl::update_all_volumes(F32 volume) +{ + for (std::set<U32>::iterator it = mSinkInputIndices.begin(); + it != mSinkInputIndices.end(); ++it) + { + update_index_volume(*it, volume); + } +} + +void LinuxVolumeCatcherImpl::update_index_volume(U32 index, F32 volume) +{ + static pa_cvolume cvol; + pa_cvolume_set(&cvol, mSinkInputNumChannels[index], + pa_sw_volume_from_linear(volume)); + + pa_context *c = mPAContext; + uint32_t idx = index; + const pa_cvolume *volume = &cvol; + pa_context_success_cb_t cb = NULL; // okay as null + void *userdata = NULL; // okay as null + + if (op = pa_context_set_sink_input_volume(c, idx, volume, cb, userdata)) + { + pa_operation_unref(op); + } +} + + +void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *sii, int eol, void *userdata) +{ + LinuxVolumeCatcherImpl *impl = dynamic_cast<LinuxVolumeCatcherImpl*>(userdata); + llassert(impl); + + if (0 == eol) + { + pa_proplist *proplist = sii->proplist; + pid_t sinkpid = atoll(pa_proplist_gets(proplist, PA_PROP_APPLICATION_PROCESS_ID)); + fprintf(stderr, "Found sinkinput #%d, name=%s, pid=%d\t", sii->index, sii->name, int(sinkpid)); + + if (sinkpid == getpid()) // 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! + fprintf(stderr, "\nJACKPOT!\n"); + 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) { + LinuxVolumeCatcherImpl *impl = dynamic_cast<LinuxVolumeCatcherImpl*>(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 + { + // ask for more info about this new sinkinput + pa_operation *op; + if (op = pa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, impl)) + { + pa_operation_unref(o); + } + } + break; + + default:; + } } void callback_context_state(pa_context *context, void *userdata) { + LinuxVolumeCatcherImpl *impl = dynamic_cast<LinuxVolumeCatcherImpl*>(userdata); + llassert(impl); + + switch (pa_context_get_state(c)) + { + case PA_CONTEXT_READY: + impl->mConnected = true; + impl->connected_okay(c); + break; + case PA_CONTEXT_TERMINATED: + impl->mConnected = false; + break; + case PA_CONTEXT_FAILED: + impl->mConnected = false; + break; + default:; + } +} + +///////////////////////////////////////////////////// + +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(); } |