Break Linux? Fix volume catcher? Only time will tell
This commit is contained in:
@@ -155,55 +155,40 @@ extern "C" {
|
||||
}
|
||||
|
||||
|
||||
class VolumeCatcherImpl
|
||||
class VolumeCatcherImpl : public LLSingleton<VolumeCatcherImpl>
|
||||
{
|
||||
public:
|
||||
friend LLSingleton<VolumeCatcherImpl>;
|
||||
VolumeCatcherImpl();
|
||||
// This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance.
|
||||
~VolumeCatcherImpl();
|
||||
|
||||
public:
|
||||
|
||||
void setVolume(F32 volume);
|
||||
void pump(void);
|
||||
void setPan(F32 pan) {};
|
||||
|
||||
// for internal use - can't be private because used from our C callbacks
|
||||
|
||||
bool loadsyms(std::string pulse_dso_name);
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
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;
|
||||
F32 mVolume;
|
||||
pa_glib_mainloop *mMainloop;
|
||||
pa_context *mPAContext;
|
||||
bool mConnected;
|
||||
bool mGotSyms;
|
||||
F32 mPan;
|
||||
};
|
||||
|
||||
VolumeCatcherImpl::VolumeCatcherImpl()
|
||||
: mDesiredVolume(0.0f),
|
||||
mMainloop(NULL),
|
||||
mPAContext(NULL),
|
||||
: mVolume(0.0f),
|
||||
mMainloop(nullptr),
|
||||
mPAContext(nullptr),
|
||||
mConnected(false),
|
||||
mGotSyms(false)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
VolumeCatcherImpl::~VolumeCatcherImpl()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
bool VolumeCatcherImpl::loadsyms(std::string pulse_dso_name)
|
||||
{
|
||||
return grab_pa_syms(pulse_dso_name);
|
||||
}
|
||||
|
||||
void VolumeCatcherImpl::init()
|
||||
mGotSyms(false),
|
||||
mPan(0.f) // default pan is centered
|
||||
{
|
||||
// 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
|
||||
@@ -213,7 +198,7 @@ void VolumeCatcherImpl::init()
|
||||
// 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");
|
||||
mGotSyms = grab_pa_syms("libpulse-mainloop-glib.so.0");
|
||||
if (!mGotSyms) return;
|
||||
|
||||
// better make double-sure glib itself is initialized properly.
|
||||
@@ -245,7 +230,7 @@ void VolumeCatcherImpl::init()
|
||||
// PA context to a PA daemon.
|
||||
if (mPAContext)
|
||||
{
|
||||
llpa_context_set_state_callback(mPAContext, callback_context_state, this);
|
||||
llpa_context_set_state_callback(mPAContext, callback_context_state, nullptr);
|
||||
pa_context_flags_t cflags = (pa_context_flags)0; // maybe add PA_CONTEXT_NOAUTOSPAWN?
|
||||
if (llpa_context_connect(mPAContext, NULL, cflags, NULL) >= 0)
|
||||
{
|
||||
@@ -260,7 +245,7 @@ void VolumeCatcherImpl::init()
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeCatcherImpl::cleanup()
|
||||
VolumeCatcherImpl::~VolumeCatcherImpl()
|
||||
{
|
||||
mConnected = false;
|
||||
|
||||
@@ -269,33 +254,30 @@ void VolumeCatcherImpl::cleanup()
|
||||
llpa_context_disconnect(mPAContext);
|
||||
llpa_context_unref(mPAContext);
|
||||
}
|
||||
mPAContext = NULL;
|
||||
mPAContext = nullptr;
|
||||
|
||||
if (mGotSyms && mMainloop)
|
||||
{
|
||||
llpa_glib_mainloop_free(mMainloop);
|
||||
}
|
||||
mMainloop = NULL;
|
||||
mMainloop = nullptr;
|
||||
}
|
||||
|
||||
void VolumeCatcherImpl::setVolume(F32 volume)
|
||||
{
|
||||
mDesiredVolume = volume;
|
||||
mVolume = volume;
|
||||
|
||||
if (!mGotSyms) return;
|
||||
|
||||
if (mConnected && mPAContext)
|
||||
{
|
||||
update_all_volumes(mDesiredVolume);
|
||||
for (auto& input : mSinkInputIndices)
|
||||
{
|
||||
update_index_volume(input, mVolume);
|
||||
}
|
||||
}
|
||||
|
||||
pump();
|
||||
}
|
||||
|
||||
void VolumeCatcherImpl::pump()
|
||||
{
|
||||
gboolean may_block = FALSE;
|
||||
g_main_context_iteration(g_main_context_default(), may_block);
|
||||
g_main_context_iteration(g_main_context_default(), /*may_block = */false);
|
||||
}
|
||||
|
||||
void VolumeCatcherImpl::connected_okay()
|
||||
@@ -305,7 +287,7 @@ void VolumeCatcherImpl::connected_okay()
|
||||
// fetch global list of existing sinkinputs
|
||||
if ((op = llpa_context_get_sink_input_info_list(mPAContext,
|
||||
callback_discovered_sinkinput,
|
||||
this)))
|
||||
nullptr)))
|
||||
{
|
||||
llpa_operation_unref(op);
|
||||
}
|
||||
@@ -313,7 +295,7 @@ void VolumeCatcherImpl::connected_okay()
|
||||
// subscribe to future global sinkinput changes
|
||||
llpa_context_set_subscribe_callback(mPAContext,
|
||||
callback_subscription_alert,
|
||||
this);
|
||||
nullptr);
|
||||
if ((op = llpa_context_subscribe(mPAContext, (pa_subscription_mask_t)
|
||||
(PA_SUBSCRIPTION_MASK_SINK_INPUT),
|
||||
NULL, NULL)))
|
||||
@@ -322,15 +304,6 @@ void VolumeCatcherImpl::connected_okay()
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeCatcherImpl::update_all_volumes(F32 volume)
|
||||
{
|
||||
for (std::set<U32>::iterator it = mSinkInputIndices.begin();
|
||||
it != mSinkInputIndices.end(); ++it)
|
||||
{
|
||||
update_index_volume(*it, volume);
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeCatcherImpl::update_index_volume(U32 index, F32 volume)
|
||||
{
|
||||
static pa_cvolume cvol;
|
||||
@@ -340,10 +313,10 @@ void VolumeCatcherImpl::update_index_volume(U32 index, F32 volume)
|
||||
pa_context *c = mPAContext;
|
||||
uint32_t idx = index;
|
||||
const pa_cvolume *cvolumep = &cvol;
|
||||
pa_context_success_cb_t cb = NULL; // okay as null
|
||||
void *userdata = NULL; // okay as null
|
||||
pa_context_success_cb_t cb = nullptr; // okay as null
|
||||
void* userdata = nullptr; // okay as null
|
||||
|
||||
pa_operation *op;
|
||||
pa_operation* op;
|
||||
if ((op = llpa_context_set_sink_input_volume(c, idx, cvolumep, cb, userdata)))
|
||||
{
|
||||
llpa_operation_unref(op);
|
||||
@@ -353,9 +326,6 @@ void VolumeCatcherImpl::update_index_volume(U32 index, F32 volume)
|
||||
|
||||
void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info *sii, int eol, void *userdata)
|
||||
{
|
||||
VolumeCatcherImpl *impl = dynamic_cast<VolumeCatcherImpl*>((VolumeCatcherImpl*)userdata);
|
||||
llassert(impl);
|
||||
|
||||
if (0 == eol)
|
||||
{
|
||||
pa_proplist *proplist = sii->proplist;
|
||||
@@ -363,6 +333,7 @@ void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info
|
||||
|
||||
if (sinkpid == getpid()) // does the discovered sinkinput belong to this process?
|
||||
{
|
||||
auto impl = VolumeCatcherImpl::getInstance();
|
||||
bool is_new = (impl->mSinkInputIndices.find(sii->index) ==
|
||||
impl->mSinkInputIndices.end());
|
||||
|
||||
@@ -371,12 +342,7 @@ void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info
|
||||
|
||||
if (is_new)
|
||||
{
|
||||
// new!
|
||||
impl->update_index_volume(sii->index, impl->mDesiredVolume);
|
||||
}
|
||||
else
|
||||
{
|
||||
// seen it already, do nothing.
|
||||
impl->update_index_volume(sii->index, impl->mVolume);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -384,8 +350,7 @@ void callback_discovered_sinkinput(pa_context *context, const pa_sink_input_info
|
||||
|
||||
void callback_subscription_alert(pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata)
|
||||
{
|
||||
VolumeCatcherImpl *impl = dynamic_cast<VolumeCatcherImpl*>((VolumeCatcherImpl*)userdata);
|
||||
llassert(impl);
|
||||
VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance();
|
||||
|
||||
switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
|
||||
case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
|
||||
@@ -401,15 +366,11 @@ void callback_subscription_alert(pa_context *context, pa_subscription_event_type
|
||||
{
|
||||
// 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)))
|
||||
if ((op = llpa_context_get_sink_input_info(impl->mPAContext, index, callback_discovered_sinkinput, nullptr)))
|
||||
{
|
||||
llpa_operation_unref(op);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// property change on this sinkinput - we don't care.
|
||||
}
|
||||
break;
|
||||
|
||||
default:;
|
||||
@@ -418,8 +379,7 @@ void callback_subscription_alert(pa_context *context, pa_subscription_event_type
|
||||
|
||||
void callback_context_state(pa_context *context, void *userdata)
|
||||
{
|
||||
VolumeCatcherImpl *impl = dynamic_cast<VolumeCatcherImpl*>((VolumeCatcherImpl*)userdata);
|
||||
llassert(impl);
|
||||
VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance();
|
||||
|
||||
switch (llpa_context_get_state(context))
|
||||
{
|
||||
@@ -441,28 +401,25 @@ void callback_context_state(pa_context *context, void *userdata)
|
||||
|
||||
VolumeCatcher::VolumeCatcher()
|
||||
{
|
||||
pimpl = new VolumeCatcherImpl();
|
||||
pimpl = VolumeCatcherImpl::getInstance();
|
||||
}
|
||||
|
||||
VolumeCatcher::~VolumeCatcher()
|
||||
{
|
||||
delete pimpl;
|
||||
pimpl = NULL;
|
||||
// Let the instance persist until exit.
|
||||
}
|
||||
|
||||
void VolumeCatcher::setVolume(F32 volume)
|
||||
{
|
||||
llassert(pimpl);
|
||||
pimpl->setVolume(volume);
|
||||
}
|
||||
|
||||
void VolumeCatcher::setPan(F32 pan)
|
||||
{
|
||||
// TODO: implement this (if possible)
|
||||
pimpl->setPan(pan);
|
||||
}
|
||||
|
||||
void VolumeCatcher::pump()
|
||||
{
|
||||
llassert(pimpl);
|
||||
pimpl->pump();
|
||||
g_main_context_iteration(g_main_context_default(), /*may_block = */false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user