Обработчик сигнала не вызывается
Я создал для своего класса device_manager сигнал added
enum {
SIGNAL_ADDED,
LAST_SIGNAL
};
static guint device_manager_signals[LAST_SIGNAL] = { 0 };
static void
device_manager_class_init(DeviceManagerClass * class){
device_manager_signals[SIGNAL_ADDED] =
g_signal_new(
"added",
G_TYPE_FROM_CLASS(class),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL,
g_cclosure_user_marshal_VOID__STRING_STRING_BOOLEAN,
G_TYPE_NONE,
3,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_BOOLEAN
);
}
Маршалер g_cclosure_user_marshal_VOID__STRING_STRING_BOOLEAN сгенерировал при помощи glib-genmarshal. У меня есть vapi обвязка:
[CCode (cheader_filename = "device_manager.h")]
public class DeviceManager : GLib.Object {
public signal void added (string name, string nick, bool is_default);
[CCode (cname = "device_manager_new")]
public DeviceManager();
[CCode (cname = "device_manager_run")]
public void run();
}
в vala коде я создаю объект и привязываю обработчик
var deviceManager = new DeviceManager();
deviceManager.added.connect(on_added);
сам обработчик выглядит так
private void on_added(string name, string nick, bool is_default){
print("added!\n");
}
но когда я посылаю сигнал, обработчик не срабатывает.
static void
on_addet(
WpObjectManager * self,
gpointer object,
gpointer user_data
){
DeviceManager *manager = user_data;
g_autoptr (WpPlugin) def_nodes_api = NULL;
def_nodes_api = wp_plugin_find (manager->core, "default-nodes-api");
guint32 default_node_id = -1;
guint32 id = wp_proxy_get_bound_id (WP_PROXY (object));
gboolean is_default = FALSE;
const gchar *class = wp_pipewire_object_get_property (WP_PIPEWIRE_OBJECT (object), "media.class");
const gchar *name = wp_pipewire_object_get_property (WP_PIPEWIRE_OBJECT (object), "node.name");
const gchar *nick = wp_pipewire_object_get_property (WP_PIPEWIRE_OBJECT (object), "node.description");
if(g_strcmp0 (class, "Audio/Sink") == 0){
g_signal_emit_by_name (def_nodes_api, "get-default-node", "Audio/Sink", &default_node_id);
is_default = (default_node_id == id);
g_signal_emit_by_name(manager, "added", name, nick, is_default);
}
}
сигнал точно посылается, код точно доходит до этой строки. Но обработчик в vala ни как не реагирует. Не происходит ошибки сегментации, или какой-либо другой ошибки, просто ноль реакции. Я немного в отчаянии, не могу понять где искать ошибку, я пробовал исключить маршалер, послать сигнал без параметров, но он так же не реагирует. Может я написал неправильную обвязку? Вот полный код device_manager.c на всякий случай
#include <wp/wp.h>
#include <glib.h>
#include <stdio.h>
#include <pipewire/pipewire.h>
#include <pipewire/keys.h>
#include "device_manager.h"
#include "node_marshal.h"
struct _DeviceManager {
GMainContext *context;
GObject parent_instance;
GMainLoop *loop;
WpCore *core;
WpObjectManager *object_manager;
guint pending_plugins;
WpSettings * settings;
};
struct _DeviceManagerClass
{
GObjectClass parent_class;
void (*run) (DeviceManager*);
};
G_DEFINE_TYPE (DeviceManager, device_manager, G_TYPE_OBJECT);
static void device_manager_clear(DeviceManager * self){
g_clear_object (&self->object_manager);
g_clear_object (&self->core);
g_clear_pointer (&self->loop, g_main_loop_unref);
}
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (DeviceManager, device_manager_clear);
enum {
SIGNAL_ADDED,
LAST_SIGNAL
};
static guint device_manager_signals[LAST_SIGNAL] = { 0 };
static void
device_manager_class_init(DeviceManagerClass * class){
device_manager_signals[SIGNAL_ADDED] =
g_signal_new(
"added",
G_TYPE_FROM_CLASS(class),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL,
g_cclosure_user_marshal_VOID__STRING_STRING_BOOLEAN,
G_TYPE_NONE,
3,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_BOOLEAN
);
}
static void
device_manager_init(DeviceManager * self){
/**/
}
DeviceManager *
device_manager_new(){
return g_object_new(TYPE_DEVICE_MANAGER, NULL);
}
WpObjectManager *
create_object_manager(){
WpObjectManager * manager = wp_object_manager_new();
wp_object_manager_add_interest(
manager,
WP_TYPE_METADATA,
NULL
);
wp_object_manager_request_object_features (
manager,
WP_TYPE_METADATA,
WP_OBJECT_FEATURES_ALL
);
wp_object_manager_add_interest(
manager,
WP_TYPE_NODE,
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "#s", "Audio/Sink*",
NULL
);
wp_object_manager_add_interest(
manager,
WP_TYPE_NODE,
WP_CONSTRAINT_TYPE_PW_PROPERTY, PW_KEY_MEDIA_CLASS, "#s", "Audio/Source*",
NULL
);
return manager;
}
static void on_settings_activated (WpSettings *s, GAsyncResult *res, DeviceManager *deviceManager)
{
GError *error = NULL;
if (!wp_object_activate_finish (WP_OBJECT (s), res, &error)) {
//error code
g_main_loop_quit (deviceManager->loop);
return;
}
wp_core_register_object (deviceManager->core, g_object_ref (s));
}
static void on_plugin_loaded (WpCore * core, GAsyncResult * res, DeviceManager *deviceManager)
{
GError *error = NULL;
if (!wp_core_load_component_finish (core, res, &error)) {
fprintf (stderr, "%s\n", error->message);
g_main_loop_quit (deviceManager->loop);
return;
}
if (--deviceManager->pending_plugins == 0) {
g_autoptr (WpPlugin) mixer_api = wp_plugin_find (core, "mixer-api");
g_object_set (mixer_api, "scale", 1 /* cubic */, NULL);
wp_core_install_object_manager (deviceManager->core, deviceManager->object_manager);
}
}
void load_plugins(DeviceManager * deviceManager){
deviceManager->pending_plugins++;
wp_core_load_component (
deviceManager->core,
"libwireplumber-module-default-nodes-api",
"module",
NULL,
NULL,
NULL,
(GAsyncReadyCallback) on_plugin_loaded,
deviceManager
);
deviceManager->pending_plugins++;
wp_core_load_component (
deviceManager->core,
"libwireplumber-module-mixer-api",
"module",
NULL,
NULL,
NULL,
(GAsyncReadyCallback) on_plugin_loaded,
deviceManager
);
}
static void
on_addet(
WpObjectManager * self,
gpointer object,
gpointer user_data
){
DeviceManager *manager = user_data;
g_autoptr (WpPlugin) def_nodes_api = NULL;
def_nodes_api = wp_plugin_find (manager->core, "default-nodes-api");
guint32 default_node_id = -1;
guint32 id = wp_proxy_get_bound_id (WP_PROXY (object));
gboolean is_default = FALSE;
const gchar *class = wp_pipewire_object_get_property (WP_PIPEWIRE_OBJECT (object), "media.class");
const gchar *name = wp_pipewire_object_get_property (WP_PIPEWIRE_OBJECT (object), "node.name");
const gchar *nick = wp_pipewire_object_get_property (WP_PIPEWIRE_OBJECT (object), "node.description");
if(g_strcmp0 (class, "Audio/Sink") == 0){
g_signal_emit_by_name (def_nodes_api, "get-default-node", "Audio/Sink", &default_node_id);
is_default = (default_node_id == id);
g_signal_emit_by_name(manager, "added", name, nick, is_default);
}
}
static void on_removed(WpObjectManager * self, WpObject * object, gpointer user_data){
/**/
}
static void
device_manager_connect_signals(DeviceManager *self) {
g_signal_connect_swapped (
self->core,
"disconnected",
(GCallback) g_main_loop_quit,
self->loop
);
g_signal_connect(self->object_manager, "object-added", (GCallback)on_addet, self);
g_signal_connect(self->object_manager, "object-removed", (GCallback)on_removed, self);
}
void
device_manager_run(DeviceManager * self){
wp_init(WP_INIT_ALL);
self->context = g_main_context_default();
self->loop = g_main_loop_new(self->context, FALSE);
self->core = wp_core_new(self->context, NULL, NULL);
self->object_manager = create_object_manager();
self->settings = wp_settings_new (self->core, NULL);
wp_object_activate (
WP_OBJECT (self->settings),
WP_OBJECT_FEATURES_ALL,
NULL,
(GAsyncReadyCallback)on_settings_activated,
self
);
load_plugins(self);
/* connect */
if (!wp_core_connect (self->core)) {
fprintf (stderr, "Could not connect to PipeWire\n");
}
device_manager_connect_signals(self);
}
device_manager.h
#ifndef _DEVICE_MANAGER_H_
#define _DEVICE_MANAGER_H_
#include <glib-object.h>
G_BEGIN_DECLS
#define TYPE_DEVICE_MANAGER device_manager_get_type()
G_DECLARE_FINAL_TYPE (DeviceManager, device_manager, DEVICE, MANAGER, GObject)
DeviceManager*
device_manager_new();
void
device_manager_run(DeviceManager* self);
G_END_DECLS
#endif /* _DEVICE_MANAGER_H_ */
Ответы (1 шт):
Причина крылась тут:
struct _DeviceManager {
GMainContext *context;
GObject parent_instance; /* <- Ошибка */
GMainLoop *loop;
WpCore *core;
WpObjectManager *object_manager;
guint pending_plugins;
WpSettings * settings;
};
parent_instance должен быть всегда указан на первом месте в структуре.
Рабочий вариант:
struct _DeviceManager {
GObject parent_instance;
GMainContext *context;
GMainLoop *loop;
WpCore *core;
WpObjectManager *object_manager;
guint pending_plugins;
WpSettings * settings;
};
Из-за того, что я определил структуру неправильно, объект не возвращал свой тип, поэтому сигнал не срабатывал.
Вы можете проверить это при помощи G_OBJECT_TYPE_NAME(ваш объект), если возвращает NULL, значит возможно ошибка в структуре.