mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-21 22:40:30 +00:00
131 lines
4.2 KiB
C++
131 lines
4.2 KiB
C++
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#include "config_unix.h"
|
|
#endif
|
|
|
|
#include "debug.h"
|
|
#include "utils/color_out.h"
|
|
|
|
#include "pipewire_common.hpp"
|
|
|
|
static void on_core_done(void *data, uint32_t /*id*/, int seq)
|
|
{
|
|
auto s = static_cast<pipewire_state_common *>(data);
|
|
|
|
s->pw_last_seq = seq;
|
|
pw_thread_loop_signal(s->pipewire_loop.get(), false);
|
|
}
|
|
|
|
static void on_core_error(void * /*data*/, uint32_t id, int seq, int res, const char *message)
|
|
{
|
|
log_msg(LOG_LEVEL_ERROR, "Pipewire error: id:%d seq:%x res:%d msg: %s\n", id, seq, res, message);
|
|
}
|
|
|
|
static const struct pw_core_events core_events = {
|
|
PW_VERSION_CORE_EVENTS,
|
|
.info = nullptr,
|
|
.done = on_core_done,
|
|
.ping = nullptr,
|
|
.error = on_core_error,
|
|
.remove_id = nullptr,
|
|
.bound_id = nullptr,
|
|
.add_mem = nullptr,
|
|
.remove_mem = nullptr,
|
|
#if PW_MAJOR > 0 || PW_MINOR > 3 || (PW_MINOR == 3 && PW_MICRO > 67)
|
|
.bound_props = nullptr,
|
|
#endif
|
|
};
|
|
|
|
bool initialize_pw_common(pipewire_state_common& s, int fd){
|
|
s.init_guard.init();
|
|
s.pipewire_loop.reset(pw_thread_loop_new("Playback", nullptr));
|
|
s.pipewire_context.reset(pw_context_new(pw_thread_loop_get_loop(s.pipewire_loop.get()), nullptr, 0)); //TODO check return
|
|
|
|
if(fd != -1)
|
|
s.pipewire_core.reset(pw_context_connect_fd(s.pipewire_context.get(), fd, nullptr, 0));
|
|
else
|
|
s.pipewire_core.reset(pw_context_connect(s.pipewire_context.get(), nullptr, 0));
|
|
|
|
pw_core_add_listener(s.pipewire_core.get(), &s.core_listener.get(), &core_events, &s);
|
|
|
|
pw_thread_loop_start(s.pipewire_loop.get());
|
|
|
|
return true;
|
|
}
|
|
|
|
static void on_registry_event_global(void *data, uint32_t /*id*/,
|
|
uint32_t /*permissions*/, const char *type, uint32_t /*version*/,
|
|
const struct spa_dict *props)
|
|
{
|
|
auto result = static_cast<std::vector<Pipewire_device> *>(data);
|
|
std::string_view type_sv(type);
|
|
if(type_sv != "PipeWire:Interface:Node")
|
|
return;
|
|
|
|
Pipewire_device dev;
|
|
for(unsigned i = 0; i < props->n_items; i++){
|
|
std::string_view key(props->items[i].key);
|
|
std::string_view val(props->items[i].value);
|
|
|
|
if(key == "node.description")
|
|
dev.description = val;
|
|
else if(key == "node.nick")
|
|
dev.nick = val;
|
|
else if(key == "media.class")
|
|
dev.media_class = val;
|
|
else if(key == "node.name")
|
|
dev.name = val;
|
|
else if(key == "object.serial")
|
|
dev.serial = val;
|
|
}
|
|
|
|
result->push_back(std::move(dev));
|
|
}
|
|
|
|
std::vector<Pipewire_device> get_pw_device_list(){
|
|
pipewire_state_common s;
|
|
initialize_pw_common(s);
|
|
|
|
std::vector<Pipewire_device> result;
|
|
|
|
pipewire_thread_loop_lock_guard lock(s.pipewire_loop.get());
|
|
|
|
pw_registry_uniq registry(pw_core_get_registry(s.pipewire_core.get(), PW_VERSION_REGISTRY, 0));
|
|
|
|
const static pw_registry_events registry_events = {
|
|
PW_VERSION_REGISTRY_EVENTS,
|
|
.global = on_registry_event_global,
|
|
.global_remove = nullptr
|
|
};
|
|
|
|
spa_hook_uniq registry_listener;
|
|
pw_registry_add_listener(registry.get(), ®istry_listener.get(), ®istry_events, &result);
|
|
|
|
s.pw_pending_seq = pw_core_sync(s.pipewire_core.get(), PW_ID_CORE, s.pw_pending_seq);
|
|
int wait_seq = s.pw_pending_seq;
|
|
|
|
do{
|
|
pw_thread_loop_wait(s.pipewire_loop.get());
|
|
} while(s.pw_last_seq < wait_seq);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
pipewire_state_common::~pipewire_state_common(){
|
|
if(pipewire_loop)
|
|
pw_thread_loop_stop(pipewire_loop.get());
|
|
}
|
|
|
|
void print_devices(std::string_view media_class){
|
|
auto devices = get_pw_device_list();
|
|
|
|
for(const auto& dev : devices){
|
|
if(dev.media_class == media_class){
|
|
color_printf("\t%s: %s (%s)\n", dev.serial.c_str(), dev.description.c_str(), dev.name.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
|