diff options
3 files changed, 320 insertions, 320 deletions
| 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<VolumeCatcherPipeWire*>(data)->handleRegistryEventGlobal( -		id, permissions, type, version, props -	); +    static_cast<VolumeCatcherPipeWire*>(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*>(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*>(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<VolumeCatcherPipeWire::ChildNode*>(data); + +    auto* const childNode = static_cast<VolumeCatcherPipeWire::ChildNode*>(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<VolumeCatcherPipeWire::ChildNode*>(data); -	childNode->destroy(); +    auto* const childNode = static_cast<VolumeCatcherPipeWire::ChildNode*>(data); +    childNode->destroy();  }  static void proxyEventRemoved(void* data)  { -	auto* const childNode = static_cast<VolumeCatcherPipeWire::ChildNode*>(data); -	childNode->destroy(); +    auto* const childNode = static_cast<VolumeCatcherPipeWire::ChildNode*>(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_proxy*>( -		pw_registry_bind(mRegistry, id, type, PW_VERSION_CLIENT, sizeof(ChildNode)) -	); - -	auto* const childNode = static_cast<ChildNode*>(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_proxy*>( +        pw_registry_bind(mRegistry, id, type, PW_VERSION_CLIENT, sizeof(ChildNode)) +    ); + +    auto* const childNode = static_cast<ChildNode*>(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<U32>::iterator it = mSinkInputIndices.begin(); -	     it != mSinkInputIndices.end(); ++it) -	{ -		update_index_volume(*it, volume); -	} +    for (std::set<U32>::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*>((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*>((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*>((VolumeCatcherPulseAudio*)userdata); -	llassert(impl); +    VolumeCatcherPulseAudio *impl = dynamic_cast<VolumeCatcherPulseAudio*>((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*>((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*>((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:; +    }  } | 
