Skip to content

Commit

Permalink
PulseAudio: Implement node addition/removal callback(s)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidebeatrici committed Oct 23, 2024
1 parent 506fa11 commit 8fd1818
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 58 deletions.
123 changes: 66 additions & 57 deletions src/backends/PulseAudio/PulseAudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ static ErrorCode engineFree(BE_Engine *engine) {
return CROSSAUDIO_EC_OK;
}

static ErrorCode engineStart(BE_Engine *engine, const EngineFeedback *) {
return toImpl(engine)->start();
static ErrorCode engineStart(BE_Engine *engine, const EngineFeedback *feedback) {
return toImpl(engine)->start(feedback ? *feedback : EngineFeedback());
}

static ErrorCode engineStop(BE_Engine *engine) {
Expand Down Expand Up @@ -190,7 +190,7 @@ void Engine::unlock() {
}
}

ErrorCode Engine::start() {
ErrorCode Engine::start(const EngineFeedback &feedback) {
switch (lib().context_get_state(m_context)) {
case PA_CONTEXT_UNCONNECTED:
case PA_CONTEXT_FAILED:
Expand All @@ -200,6 +200,8 @@ ErrorCode Engine::start() {
return CROSSAUDIO_EC_INIT;
}

m_feedback = feedback;

lib().context_set_state_callback(m_context, contextState, this);
lib().context_set_subscribe_callback(m_context, contextEvent, this);

Expand Down Expand Up @@ -288,6 +290,57 @@ void Engine::fixNameIfMonitor(std::string &name) {
}
}

void Engine::addNode(const uint32_t index, const char *name, const char *description, Direction direction,
const char *monitorName) {
{
std::unique_lock lock(m_nodesLock);

if (monitorName) {
direction = CROSSAUDIO_DIR_BOTH;
m_nodeMonitors.emplace(name, monitorName);
}

m_nodes.emplace(index, Node(name, description, direction));
}

if (m_feedback.nodeAdded) {
::Node *nodeNotif = nodeNew();

nodeNotif->id = strdup(name);
nodeNotif->name = strdup(description);
nodeNotif->direction = direction;

m_feedback.nodeAdded(m_feedback.userData, nodeNotif);
}
}

void Engine::removeNode(const uint32_t index) {
m_nodesLock.lock();

const auto iter = m_nodes.extract(index);
if (iter.empty()) {
m_nodesLock.unlock();
return;
}

const Node &node = iter.mapped();
if (node.direction == CROSSAUDIO_DIR_BOTH) {
m_nodeMonitors.erase(node.name);
}

m_nodesLock.unlock();

if (m_feedback.nodeRemoved) {
::Node *nodeNotif = nodeNew();

nodeNotif->id = strdup(node.name.data());
nodeNotif->name = strdup(node.description.data());
nodeNotif->direction = node.direction;

m_feedback.nodeRemoved(m_feedback.userData, nodeNotif);
}
}

void Engine::serverInfo(pa_context *, const pa_server_info *info, void *userData) {
auto &engine = *static_cast< Engine * >(userData);

Expand All @@ -304,16 +357,7 @@ void Engine::sinkInfo(pa_context *, const pa_sink_info *info, const int eol, voi

auto &engine = *static_cast< Engine * >(userData);

const std::unique_lock lock(engine.m_nodesLock);

auto direction = CROSSAUDIO_DIR_OUT;

if (info->monitor_source != PA_INVALID_INDEX) {
direction = CROSSAUDIO_DIR_BOTH;
engine.m_nodeMonitors.emplace(info->name, info->monitor_source_name);
}

engine.m_nodes.emplace(info->index, Node(info->name, info->description, direction));
engine.addNode(info->index, info->name, info->description, CROSSAUDIO_DIR_OUT, info->monitor_source_name);
}

void Engine::sourceInfo(pa_context *, const pa_source_info *info, const int eol, void *userData) {
Expand All @@ -323,64 +367,29 @@ void Engine::sourceInfo(pa_context *, const pa_source_info *info, const int eol,

auto &engine = *static_cast< Engine * >(userData);

const std::unique_lock lock(engine.m_nodesLock);

engine.m_nodes.emplace(info->index, Node(info->name, info->description, CROSSAUDIO_DIR_IN));
engine.addNode(info->index, info->name, info->description, CROSSAUDIO_DIR_IN, nullptr);
}

void Engine::contextEvent(pa_context *context, pa_subscription_event_type_t type, unsigned int index, void *userData) {
auto &engine = *static_cast< Engine * >(userData);

bool source;
switch (type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
case PA_SUBSCRIPTION_EVENT_SINK:
source = false;
break;
case PA_SUBSCRIPTION_EVENT_SOURCE:
source = true;
break;
default:
return;
}

bool add;
switch (type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
case PA_SUBSCRIPTION_EVENT_NEW:
add = true;
break;
case PA_SUBSCRIPTION_EVENT_REMOVE:
add = false;
break;
engine.removeNode(index);
[[fallthrough]];
default:
return;
}

if (add) {
if (source) {
lib().operation_unref(lib().context_get_source_info_by_index(context, index, sourceInfo, userData));
} else {
switch (type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
case PA_SUBSCRIPTION_EVENT_SINK:
lib().operation_unref(lib().context_get_sink_info_by_index(context, index, sinkInfo, userData));
}
} else {
std::unique_lock lock(engine.m_nodesLock);

auto &nodes = engine.m_nodes;

const auto iter = nodes.find(index);
if (iter == nodes.cend()) {
return;
}

if (source) {
nodes.erase(iter);
} else {
auto &monitors = engine.m_nodeMonitors;

const auto node = nodes.extract(iter);
if (const auto monitorIter = monitors.find(node.mapped().name); monitorIter != monitors.cend()) {
engine.m_nodeMonitors.erase(monitorIter);
}
}
break;
case PA_SUBSCRIPTION_EVENT_SOURCE:
lib().operation_unref(lib().context_get_source_info_by_index(context, index, sourceInfo, userData));
break;
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/backends/PulseAudio/PulseAudio.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Backend.h"

#include "crossaudio/Direction.h"
#include "crossaudio/Engine.h"
#include "crossaudio/ErrorCode.h"
#include "crossaudio/Flux.h"
#include "crossaudio/Node.h"
Expand Down Expand Up @@ -63,7 +64,7 @@ class Engine {

Nodes *engineNodesGet();

ErrorCode start();
ErrorCode start(const EngineFeedback &feedback);
ErrorCode stop();

std::string defaultInName();
Expand All @@ -76,6 +77,10 @@ class Engine {
Engine(const Engine &) = delete;
Engine &operator=(const Engine &) = delete;

void addNode(uint32_t index, const char *name, const char *description, Direction direction,
const char *monitorName);
void removeNode(uint32_t index);

static void serverInfo(pa_context *context, const pa_server_info *info, void *userData);
static void sinkInfo(pa_context *context, const pa_sink_info *info, int eol, void *userData);
static void sourceInfo(pa_context *context, const pa_source_info *info, int eol, void *userData);
Expand All @@ -84,6 +89,8 @@ class Engine {
void *userData);
static void contextState(pa_context *context, void *userData);

EngineFeedback m_feedback;

std::atomic_flag m_connectComplete;
pa_threaded_mainloop *m_threadLoop;
std::string m_name;
Expand Down

0 comments on commit 8fd1818

Please sign in to comment.