From 4db8dc0cbb3959d6278a9e7650d5103a475ab897 Mon Sep 17 00:00:00 2001 From: Michal Ratajsky Date: Sat, 24 May 2014 21:01:21 +0200 Subject: General additions and improvements --- backends/null/null.c | 13 ++-- backends/null/null.h | 2 + backends/pulse/pulse-device.c | 53 ++++++++----- backends/pulse/pulse-device.h | 18 +++-- backends/pulse/pulse.c | 12 +-- libmatemixer/matemixer-backend-module.c | 121 +++++++++++++++++++--------- libmatemixer/matemixer-backend.c | 34 ++++++-- libmatemixer/matemixer-backend.h | 18 +++-- libmatemixer/matemixer-control.c | 114 +++++++++++++++------------ libmatemixer/matemixer-control.h | 11 ++- libmatemixer/matemixer-device-port.c | 66 ++++++++++++++-- libmatemixer/matemixer-device-port.h | 14 ++++ libmatemixer/matemixer-device-profile.c | 30 ++++++- libmatemixer/matemixer-device-profile.h | 4 + libmatemixer/matemixer-device.c | 66 +++++++++++++++- libmatemixer/matemixer-device.h | 16 ++++ libmatemixer/matemixer-enums.h | 1 + libmatemixer/matemixer.c | 134 ++++++++++++++++---------------- 18 files changed, 503 insertions(+), 224 deletions(-) diff --git a/backends/null/null.c b/backends/null/null.c index c049dcb..b96c9b0 100644 --- a/backends/null/null.c +++ b/backends/null/null.c @@ -28,7 +28,6 @@ /* Support function for dynamic loading of the backend module */ void backend_module_init (GTypeModule *module); -void backend_module_free (void); const MateMixerBackendModuleInfo *backend_module_get_info (void); @@ -52,11 +51,6 @@ backend_module_init (GTypeModule *module) info.backend_type = MATE_MIXER_BACKEND_TYPE_NULL; } -void -backend_module_free (void) -{ -} - const MateMixerBackendModuleInfo * backend_module_get_info (void) { @@ -66,6 +60,7 @@ backend_module_get_info (void) static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface) { + iface->open = mate_mixer_null_open; } static void @@ -93,3 +88,9 @@ static void mate_mixer_null_class_finalize (MateMixerNullClass *klass) { } + +gboolean +mate_mixer_null_open (MateMixerBackend *backend) +{ + return TRUE; +} diff --git a/backends/null/null.h b/backends/null/null.h index ef5b779..d73794e 100644 --- a/backends/null/null.h +++ b/backends/null/null.h @@ -51,4 +51,6 @@ struct _MateMixerNullClass GType mate_mixer_null_get_type (void) G_GNUC_CONST; +gboolean mate_mixer_null_open (MateMixerBackend *backend); + #endif /* MATEMIXER_NULL_H */ diff --git a/backends/pulse/pulse-device.c b/backends/pulse/pulse-device.c index 75c5a32..4421e97 100644 --- a/backends/pulse/pulse-device.c +++ b/backends/pulse/pulse-device.c @@ -57,7 +57,11 @@ G_DEFINE_TYPE_WITH_CODE (MateMixerPulseDevice, mate_mixer_pulse_device, G_TYPE_O static void mate_mixer_device_interface_init (MateMixerDeviceInterface *iface) { - + iface->list_tracks = mate_mixer_pulse_device_list_tracks; + iface->get_ports = mate_mixer_pulse_device_get_ports; + iface->get_profiles = mate_mixer_pulse_device_get_profiles; + iface->get_active_profile = mate_mixer_pulse_device_get_active_profile; + iface->set_active_profile = mate_mixer_pulse_device_set_active_profile; } static void @@ -119,7 +123,9 @@ mate_mixer_pulse_device_set_property (GObject *object, device->priv->icon = g_strdup (g_value_get_string (value)); break; case PROP_ACTIVE_PROFILE: - // TODO + mate_mixer_pulse_device_set_active_profile ( + MATE_MIXER_DEVICE (device), + g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -261,33 +267,50 @@ mate_mixer_pulse_device_new (const pa_card_info *info) return device; } +gboolean +mate_mixer_pulse_device_update (MateMixerPulseDevice *device, const pa_card_info *info) +{ + g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), FALSE); + g_return_val_if_fail (info != NULL, FALSE); + + // TODO: update status, active_profile, maybe others? + return TRUE; +} + +const GList * +mate_mixer_pulse_device_list_tracks (MateMixerDevice *device) +{ + // TODO + return NULL; +} + const GList * -mate_mixer_pulse_device_get_ports (MateMixerPulseDevice *device) +mate_mixer_pulse_device_get_ports (MateMixerDevice *device) { g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), NULL); - return device->priv->ports; + return MATE_MIXER_PULSE_DEVICE (device)->priv->ports; } const GList * -mate_mixer_pulse_device_get_profiles (MateMixerPulseDevice *device) +mate_mixer_pulse_device_get_profiles (MateMixerDevice *device) { g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), NULL); - return device->priv->profiles; + return MATE_MIXER_PULSE_DEVICE (device)->priv->profiles; } MateMixerDeviceProfile * -mate_mixer_pulse_device_get_active_profile (MateMixerPulseDevice *device) +mate_mixer_pulse_device_get_active_profile (MateMixerDevice *device) { g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), NULL); - return device->priv->active_profile; + return MATE_MIXER_PULSE_DEVICE (device)->priv->active_profile; } gboolean -mate_mixer_pulse_device_set_active_profile (MateMixerPulseDevice *device, - MateMixerDeviceProfile *profile) +mate_mixer_pulse_device_set_active_profile (MateMixerDevice *device, + MateMixerDeviceProfile *profile) { g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), FALSE); g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE); @@ -296,13 +319,3 @@ mate_mixer_pulse_device_set_active_profile (MateMixerPulseDevice *device, // pa_context_set_card_profile_by_index () return TRUE; } - -gboolean -mate_mixer_pulse_device_update (MateMixerPulseDevice *device, const pa_card_info *info) -{ - g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), FALSE); - g_return_val_if_fail (info != NULL, FALSE); - - // TODO: update status, active_profile, maybe others? - return TRUE; -} diff --git a/backends/pulse/pulse-device.h b/backends/pulse/pulse-device.h index f8b5a07..ab997fe 100644 --- a/backends/pulse/pulse-device.h +++ b/backends/pulse/pulse-device.h @@ -60,18 +60,20 @@ struct _MateMixerPulseDeviceClass GType mate_mixer_pulse_device_get_type (void) G_GNUC_CONST; MateMixerPulseDevice *mate_mixer_pulse_device_new (const pa_card_info *info); -GList *mate_mixer_pulse_device_list_tracks (MateMixerPulseDevice *device); -const GList *mate_mixer_pulse_device_get_ports (MateMixerPulseDevice *device); -const GList *mate_mixer_pulse_device_get_profiles (MateMixerPulseDevice *device); +gboolean mate_mixer_pulse_device_update (MateMixerPulseDevice *device, + const pa_card_info *info); -MateMixerDeviceProfile *mate_mixer_pulse_device_get_active_profile (MateMixerPulseDevice *device); +/* Interface implementation */ +const GList *mate_mixer_pulse_device_list_tracks (MateMixerDevice *device); -gboolean mate_mixer_pulse_device_set_active_profile (MateMixerPulseDevice *device, - MateMixerDeviceProfile *profile); +const GList *mate_mixer_pulse_device_get_ports (MateMixerDevice *device); +const GList *mate_mixer_pulse_device_get_profiles (MateMixerDevice *device); -gboolean mate_mixer_pulse_device_update (MateMixerPulseDevice *device, - const pa_card_info *info); +MateMixerDeviceProfile *mate_mixer_pulse_device_get_active_profile (MateMixerDevice *device); + +gboolean mate_mixer_pulse_device_set_active_profile (MateMixerDevice *device, + MateMixerDeviceProfile *profile); G_END_DECLS diff --git a/backends/pulse/pulse.c b/backends/pulse/pulse.c index e969dcf..d306577 100644 --- a/backends/pulse/pulse.c +++ b/backends/pulse/pulse.c @@ -41,7 +41,6 @@ struct _MateMixerPulsePrivate /* Support function for dynamic loading of the backend module */ void backend_module_init (GTypeModule *module); -void backend_module_free (void); const MateMixerBackendModuleInfo *backend_module_get_info (void); @@ -81,11 +80,6 @@ backend_module_init (GTypeModule *module) info.backend_type = MATE_MIXER_BACKEND_TYPE_PULSE; } -void -backend_module_free (void) -{ -} - const MateMixerBackendModuleInfo * backend_module_get_info (void) { @@ -95,9 +89,9 @@ backend_module_get_info (void) static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface) { - iface->open = mate_mixer_pulse_open; - iface->close = mate_mixer_pulse_close; - iface->list_devices = mate_mixer_pulse_list_devices; + iface->open = mate_mixer_pulse_open; + iface->close = mate_mixer_pulse_close; + iface->list_devices = mate_mixer_pulse_list_devices; } static void diff --git a/libmatemixer/matemixer-backend-module.c b/libmatemixer/matemixer-backend-module.c index 0acd786..7846359 100644 --- a/libmatemixer/matemixer-backend-module.c +++ b/libmatemixer/matemixer-backend-module.c @@ -28,15 +28,16 @@ struct _MateMixerBackendModulePrivate { GModule *gmodule; gchar *path; + gboolean loaded; - void (*init) (GTypeModule *type_module); - void (*free) (void); + void (*init) (GTypeModule *type_module); + void (*deinit) (void); const MateMixerBackendModuleInfo *(*get_info) (void); }; -static gboolean mate_mixer_backend_module_load (GTypeModule *gmodule); -static void mate_mixer_backend_module_unload (GTypeModule *gmodule); +static gboolean mate_mixer_backend_module_load (GTypeModule *gmodule); +static void mate_mixer_backend_module_unload (GTypeModule *gmodule); static void mate_mixer_backend_module_init (MateMixerBackendModule *module) @@ -47,6 +48,22 @@ mate_mixer_backend_module_init (MateMixerBackendModule *module) MateMixerBackendModulePrivate); } +static void +mate_mixer_backend_module_dispose (GObject *object) +{ + MateMixerBackendModule *module; + + module = MATE_MIXER_BACKEND_MODULE (object); + + if (module->priv->loaded) { + /* Keep the module alive and avoid calling the parent dispose, which + * would do the same thing and also produce a warning */ + g_object_ref (object); + return; + } + G_OBJECT_CLASS (mate_mixer_backend_module_parent_class)->dispose (object); +} + static void mate_mixer_backend_module_finalize (GObject *object) { @@ -66,6 +83,7 @@ mate_mixer_backend_module_class_init (MateMixerBackendModuleClass *klass) GTypeModuleClass *gtype_class; object_class = G_OBJECT_CLASS (klass); + object_class->dispose = mate_mixer_backend_module_dispose; object_class->finalize = mate_mixer_backend_module_finalize; gtype_class = G_TYPE_MODULE_CLASS (klass); @@ -82,39 +100,64 @@ mate_mixer_backend_module_load (GTypeModule *type_module) module = MATE_MIXER_BACKEND_MODULE (type_module); - module->priv->gmodule = g_module_open ( - module->priv->path, - G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); - - if (module->priv->gmodule == NULL) { - g_warning ("Failed to load backend module %s: %s", - module->priv->path, - g_module_error ()); - - return FALSE; + if (!module->priv->loaded) { + module->priv->gmodule = g_module_open ( + module->priv->path, + G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); + + if (module->priv->gmodule == NULL) { + g_warning ("Failed to load backend module %s: %s", + module->priv->path, + g_module_error ()); + + return FALSE; + } + + /* Validate library symbols that each backend module must provide */ + if (!g_module_symbol (module->priv->gmodule, + "backend_module_init", + (gpointer *) &module->priv->init) || + !g_module_symbol (module->priv->gmodule, + "backend_module_get_info", + (gpointer *) &module->priv->get_info)) { + g_warning ("Failed to load backend module %s: %s", + module->priv->path, + g_module_error ()); + + g_module_close (module->priv->gmodule); + return FALSE; + } + + /* Optional backend functions */ + g_module_symbol (module->priv->gmodule, + "backend_module_deinit", + (gpointer *) &module->priv->deinit); + + module->priv->init (type_module); + module->priv->loaded = TRUE; + + /* Make sure get_info () returns something so we can avoid checking + * it in other parts of the library */ + if (G_UNLIKELY (module->priv->get_info () == NULL)) { + g_warning ("Backend module %s does not provide module information", + module->priv->path); + + /* Close the module but keep the loaded flag to avoid unreffing + * this instance as the GType has most likely been registered */ + g_module_close (module->priv->gmodule); + return FALSE; + } + + /* It is not possible to unref this instance, so let's avoid unloading + * the module and just let the backend module (de)initialize when + * (un)load are called repeatedly */ + g_module_make_resident (module->priv->gmodule); + + g_debug ("Loaded backend module %s", module->priv->path); + } else { + /* This function was called before so initialize only */ + module->priv->init (type_module); } - - /* Validate library symbols that each backend module must provide */ - if (!g_module_symbol (module->priv->gmodule, - "backend_module_init", - (gpointer *) &module->priv->init) || - !g_module_symbol (module->priv->gmodule, - "backend_module_free", - (gpointer *) &module->priv->free) || - !g_module_symbol (module->priv->gmodule, - "backend_module_get_info", - (gpointer *) &module->priv->get_info)) { - g_warning ("Failed to load backend module %s: %s", - module->priv->path, - g_module_error ()); - - g_module_close (module->priv->gmodule); - return FALSE; - } - - g_debug ("Loaded backend module %s", module->priv->path); - - module->priv->init (type_module); return TRUE; } @@ -124,9 +167,11 @@ mate_mixer_backend_module_unload (GTypeModule *type_module) MateMixerBackendModule *module; module = MATE_MIXER_BACKEND_MODULE (type_module); - module->priv->free (); - g_module_close (module->priv->gmodule); + /* Only deinitialize the backend module, do not modify the loaded + * flag as the module remains loaded */ + if (module->priv->deinit) + module->priv->deinit (); } MateMixerBackendModule * diff --git a/libmatemixer/matemixer-backend.c b/libmatemixer/matemixer-backend.c index 9533e0f..18e622f 100644 --- a/libmatemixer/matemixer-backend.c +++ b/libmatemixer/matemixer-backend.c @@ -30,31 +30,53 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface) gboolean mate_mixer_backend_open (MateMixerBackend *backend) { + MateMixerBackendInterface *iface; + g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL); - return MATE_MIXER_BACKEND_GET_INTERFACE (backend)->open (backend); + iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend); + if (iface->open) + return iface->open (backend); + + return FALSE; } void mate_mixer_backend_close (MateMixerBackend *backend) { + MateMixerBackendInterface *iface; + g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL); - MATE_MIXER_BACKEND_GET_INTERFACE (backend)->close (backend); + iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend); + if (iface->close) + iface->close (backend); } -const GList * +GList * mate_mixer_backend_list_devices (MateMixerBackend *backend) { + MateMixerBackendInterface *iface; + g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL); - return MATE_MIXER_BACKEND_GET_INTERFACE (backend)->list_devices (backend); + iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend); + if (iface->list_devices) + return iface->list_devices (backend); + + return NULL; } -const GList * +GList * mate_mixer_backend_list_tracks (MateMixerBackend *backend) { + MateMixerBackendInterface *iface; + g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL); - return MATE_MIXER_BACKEND_GET_INTERFACE (backend)->list_tracks (backend); + iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend); + if (iface->list_tracks) + return iface->list_tracks (backend); + + return NULL; } diff --git a/libmatemixer/matemixer-backend.h b/libmatemixer/matemixer-backend.h index 6b0c318..e5a8585 100644 --- a/libmatemixer/matemixer-backend.h +++ b/libmatemixer/matemixer-backend.h @@ -41,18 +41,20 @@ struct _MateMixerBackendInterface { GTypeInterface parent; - gboolean (*open) (MateMixerBackend *backend); - void (*close) (MateMixerBackend *backend); - const GList *(*list_devices) (MateMixerBackend *backend); - const GList *(*list_tracks) (MateMixerBackend *backend); + /* Required */ + gboolean (*open) (MateMixerBackend *backend); + + void (*close) (MateMixerBackend *backend); + GList *(*list_devices) (MateMixerBackend *backend); + GList *(*list_tracks) (MateMixerBackend *backend); }; GType mate_mixer_backend_get_type (void) G_GNUC_CONST; -gboolean mate_mixer_backend_open (MateMixerBackend *backend); -void mate_mixer_backend_close (MateMixerBackend *backend); -const GList *mate_mixer_backend_list_devices (MateMixerBackend *backend); -const GList *mate_mixer_backend_list_tracks (MateMixerBackend *backend); +gboolean mate_mixer_backend_open (MateMixerBackend *backend); +void mate_mixer_backend_close (MateMixerBackend *backend); +GList *mate_mixer_backend_list_devices (MateMixerBackend *backend); +GList *mate_mixer_backend_list_tracks (MateMixerBackend *backend); G_END_DECLS diff --git a/libmatemixer/matemixer-control.c b/libmatemixer/matemixer-control.c index c3489e6..cf59ad5 100644 --- a/libmatemixer/matemixer-control.c +++ b/libmatemixer/matemixer-control.c @@ -27,15 +27,14 @@ struct _MateMixerControlPrivate { - MateMixerBackend *backend; - GHashTable *devices; - GHashTable *tracks; + GList *devices; + GList *tracks; + MateMixerBackend *backend; + MateMixerBackendModule *module; }; G_DEFINE_TYPE (MateMixerControl, mate_mixer_control, G_TYPE_OBJECT); -G_LOCK_DEFINE_STATIC (mixer_control_get_modules_lock); - static MateMixerBackend *mixer_control_init_module (MateMixerBackendModule *module); static void @@ -45,18 +44,6 @@ mate_mixer_control_init (MateMixerControl *control) control, MATE_MIXER_TYPE_CONTROL, MateMixerControlPrivate); - - control->priv->devices = g_hash_table_new_full ( - g_direct_hash, - g_direct_equal, - NULL, - g_object_unref); - - control->priv->tracks = g_hash_table_new_full ( - g_direct_hash, - g_direct_equal, - NULL, - g_object_unref); } static void @@ -66,9 +53,15 @@ mate_mixer_control_finalize (GObject *object) control = MATE_MIXER_CONTROL (object); + mate_mixer_backend_close (control->priv->backend); + g_object_unref (control->priv->backend); - g_hash_table_destroy (control->priv->devices); - g_hash_table_destroy (control->priv->tracks); + g_object_unref (control->priv->module); + + if (control->priv->devices) + g_list_free_full (control->priv->devices, g_object_unref); + if (control->priv->tracks) + g_list_free_full (control->priv->tracks, g_object_unref); G_OBJECT_CLASS (mate_mixer_control_parent_class)->finalize (object); } @@ -87,21 +80,18 @@ mate_mixer_control_class_init (MateMixerControlClass *klass) MateMixerControl * mate_mixer_control_new (void) { - GList *modules; - MateMixerControl *control; - MateMixerBackend *backend = NULL; + GList *modules; + MateMixerControl *control; + MateMixerBackend *backend = NULL; + MateMixerBackendModule *module = NULL; if (!mate_mixer_is_initialized ()) { g_critical ("The library has not been initialized"); return NULL; } - G_LOCK (mixer_control_get_modules_lock); - modules = mate_mixer_get_modules (); while (modules) { - MateMixerBackendModule *module; - module = MATE_MIXER_BACKEND_MODULE (modules->data); backend = mixer_control_init_module (module); if (backend != NULL) @@ -110,8 +100,6 @@ mate_mixer_control_new (void) modules = modules->next; } - G_UNLOCK (mixer_control_get_modules_lock); - /* The last module in the priority list is the "null" module which * should always be initialized correctly, but in case "null" is absent * all the other modules might fail their initializations */ @@ -119,6 +107,8 @@ mate_mixer_control_new (void) return NULL; control = g_object_new (MATE_MIXER_TYPE_CONTROL, NULL); + + control->priv->module = g_object_ref (module); control->priv->backend = backend; return control; @@ -127,22 +117,19 @@ mate_mixer_control_new (void) MateMixerControl * mate_mixer_control_new_backend (MateMixerBackendType backend_type) { - GList *modules; - MateMixerControl *control; - MateMixerBackend *backend = NULL; + GList *modules; + MateMixerControl *control; + MateMixerBackend *backend = NULL; + MateMixerBackendModule *module = NULL; if (!mate_mixer_is_initialized ()) { g_critical ("The library has not been initialized"); return NULL; } - G_LOCK (mixer_control_get_modules_lock); - modules = mate_mixer_get_modules (); - while (modules) { - MateMixerBackendModule *module; - const MateMixerBackendModuleInfo *info; + const MateMixerBackendModuleInfo *info; module = MATE_MIXER_BACKEND_MODULE (modules->data); info = mate_mixer_backend_module_get_info (module); @@ -154,13 +141,13 @@ mate_mixer_control_new_backend (MateMixerBackendType backend_type) modules = modules->next; } - G_UNLOCK (mixer_control_get_modules_lock); - /* The initialization might fail or the selected module might be absent */ if (backend == NULL) return NULL; control = g_object_new (MATE_MIXER_TYPE_CONTROL, NULL); + + control->priv->module = g_object_ref (module); control->priv->backend = backend; return control; @@ -171,12 +158,15 @@ mate_mixer_control_list_devices (MateMixerControl *control) { g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL); - // XXX - // this is the midpoint between MateMixerDevice implementation and - // the application, probably the list could be cached here but the - // implementation uses a hash table, figure out how to do this properly + /* This list is cached here and invalidated when the backend + * notifies us about a change */ + if (control->priv->devices == NULL) + control->priv->devices = mate_mixer_backend_list_devices ( + MATE_MIXER_BACKEND (control->priv->backend)); - return mate_mixer_backend_list_devices (MATE_MIXER_BACKEND (control->priv->backend)); + // TODO: notification signals from backend + + return (const GList *) control->priv->devices; } const GList * @@ -184,7 +174,37 @@ mate_mixer_control_list_tracks (MateMixerControl *control) { g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL); - return mate_mixer_backend_list_tracks (MATE_MIXER_BACKEND (control->priv->backend)); + /* This list is cached here and invalidated when the backend + * notifies us about a change */ + if (control->priv->tracks == NULL) + control->priv->tracks = mate_mixer_backend_list_tracks ( + MATE_MIXER_BACKEND (control->priv->backend)); + + return (const GList *) control->priv->tracks; +} + +const gchar * +mate_mixer_control_get_backend_name (MateMixerControl *control) +{ + const MateMixerBackendModuleInfo *info; + + g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL); + + info = mate_mixer_backend_module_get_info (control->priv->module); + + return info->name; +} + +MateMixerBackendType +mate_mixer_control_get_backend_type (MateMixerControl *control) +{ + const MateMixerBackendModuleInfo *info; + + g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE); + + info = mate_mixer_backend_module_get_info (control->priv->module); + + return info->backend_type; } static MateMixerBackend * @@ -194,12 +214,6 @@ mixer_control_init_module (MateMixerBackendModule *module) const MateMixerBackendModuleInfo *info; info = mate_mixer_backend_module_get_info (module); - if (G_UNLIKELY (info == NULL)) { - g_warning ("Backend module %s does not provide module information", - mate_mixer_backend_module_get_path (module)); - return NULL; - } - backend = g_object_newv (info->g_type, 0, NULL); if (!mate_mixer_backend_open (backend)) { diff --git a/libmatemixer/matemixer-control.h b/libmatemixer/matemixer-control.h index 010cbfa..739eabd 100644 --- a/libmatemixer/matemixer-control.h +++ b/libmatemixer/matemixer-control.h @@ -56,10 +56,13 @@ struct _MateMixerControlClass GType mate_mixer_control_get_type (void) G_GNUC_CONST; -MateMixerControl *mate_mixer_control_new (void); -MateMixerControl *mate_mixer_control_new_backend (MateMixerBackendType backend_type); -const GList *mate_mixer_control_list_devices (MateMixerControl *control); -const GList *mate_mixer_control_list_tracks (MateMixerControl *control); +MateMixerControl *mate_mixer_control_new (void); +MateMixerControl *mate_mixer_control_new_backend (MateMixerBackendType backend_type); +const GList *mate_mixer_control_list_devices (MateMixerControl *control); +const GList *mate_mixer_control_list_tracks (MateMixerControl *control); + +const gchar *mate_mixer_control_get_backend_name (MateMixerControl *control); +MateMixerBackendType mate_mixer_control_get_backend_type (MateMixerControl *control); G_END_DECLS diff --git a/libmatemixer/matemixer-device-port.c b/libmatemixer/matemixer-device-port.c index 9443879..04771fa 100644 --- a/libmatemixer/matemixer-device-port.c +++ b/libmatemixer/matemixer-device-port.c @@ -155,28 +155,28 @@ mate_mixer_device_port_class_init (MateMixerDevicePortClass *klass) object_class->get_property = mate_mixer_device_port_get_property; object_class->set_property = mate_mixer_device_port_set_property; - properties[PROP_IDENTIFIER] = g_param_spec_string( + properties[PROP_IDENTIFIER] = g_param_spec_string ( "identifier", "Identifier", "Identifier of the device port", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); - properties[PROP_NAME] = g_param_spec_string( + properties[PROP_NAME] = g_param_spec_string ( "name", "Name", "Name of the device port", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); - properties[PROP_ICON] = g_param_spec_string( + properties[PROP_ICON] = g_param_spec_string ( "icon", "Icon", "Icon name for the device port", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); - properties[PROP_PRIORITY] = g_param_spec_uint( + properties[PROP_PRIORITY] = g_param_spec_uint ( "priority", "Priority", "Priority of the device port", @@ -185,7 +185,7 @@ mate_mixer_device_port_class_init (MateMixerDevicePortClass *klass) 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); - properties[PROP_LATENCY_OFFSET] = g_param_spec_int64( + properties[PROP_LATENCY_OFFSET] = g_param_spec_int64 ( "latency-offset", "Latency offset", "Latency offset of the device port", @@ -218,3 +218,59 @@ mate_mixer_device_port_new (const gchar *identifier, "latency-offset", latency_offset, NULL); } + +const gchar * +mate_mixer_device_port_get_identifier (MateMixerDevicePort *port) +{ + g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PORT (port), NULL); + + return port->priv->identifier; +} + +const gchar * +mate_mixer_device_port_get_name (MateMixerDevicePort *port) +{ + g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PORT (port), NULL); + + return port->priv->name; +} + +const gchar * +mate_mixer_device_port_get_icon (MateMixerDevicePort *port) +{ + g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PORT (port), NULL); + + return port->priv->icon; +} + +guint32 +mate_mixer_device_port_get_priority (MateMixerDevicePort *port) +{ + g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PORT (port), 0); + + return port->priv->priority; +} + +MateMixerDevicePortDirection +mate_mixer_device_port_get_direction (MateMixerDevicePort *port) +{ + g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PORT (port), 0); + + return port->priv->direction; +} + +MateMixerDevicePortStatus +mate_mixer_device_port_get_status (MateMixerDevicePort *port) +{ + g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PORT (port), 0); + + return port->priv->status; +} + +gint64 +mate_mixer_device_port_get_latency_offset (MateMixerDevicePort *port) +{ + g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PORT (port), 0); + + return port->priv->latency_offset; +} diff --git a/libmatemixer/matemixer-device-port.h b/libmatemixer/matemixer-device-port.h index d411c89..d9dfbfa 100644 --- a/libmatemixer/matemixer-device-port.h +++ b/libmatemixer/matemixer-device-port.h @@ -64,6 +64,20 @@ MateMixerDevicePort *mate_mixer_device_port_new (const gchar *i MateMixerDevicePortStatus status, gint64 latency_offset); +const gchar *mate_mixer_device_port_get_identifier (MateMixerDevicePort *port); + +const gchar *mate_mixer_device_port_get_name (MateMixerDevicePort *port); + +const gchar *mate_mixer_device_port_get_icon (MateMixerDevicePort *port); + +guint32 mate_mixer_device_port_get_priority (MateMixerDevicePort *port); + +MateMixerDevicePortDirection mate_mixer_device_port_get_direction (MateMixerDevicePort *port); + +MateMixerDevicePortStatus mate_mixer_device_port_get_status (MateMixerDevicePort *port); + +gint64 mate_mixer_device_port_get_latency_offset (MateMixerDevicePort *port); + G_END_DECLS #endif /* MATEMIXER_PORT_H */ diff --git a/libmatemixer/matemixer-device-profile.c b/libmatemixer/matemixer-device-profile.c index bfcbe6a..975f5ff 100644 --- a/libmatemixer/matemixer-device-profile.c +++ b/libmatemixer/matemixer-device-profile.c @@ -124,21 +124,21 @@ mate_mixer_device_profile_class_init (MateMixerDeviceProfileClass *klass) object_class->get_property = mate_mixer_device_profile_get_property; object_class->set_property = mate_mixer_device_profile_set_property; - properties[PROP_IDENTIFIER] = g_param_spec_string( + properties[PROP_IDENTIFIER] = g_param_spec_string ( "identifier", "Identifier", "Identifier of the device profile", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); - properties[PROP_NAME] = g_param_spec_string( + properties[PROP_NAME] = g_param_spec_string ( "name", "Name", "Name of the device profile", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); - properties[PROP_PRIORITY] = g_param_spec_uint( + properties[PROP_PRIORITY] = g_param_spec_uint ( "priority", "Priority", "Priority of the device profile", @@ -163,3 +163,27 @@ mate_mixer_device_profile_new (const gchar *identifier, "priority", priority, NULL); } + +const gchar * +mate_mixer_device_profile_get_identifier (MateMixerDeviceProfile *profile) +{ + g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), NULL); + + return profile->priv->identifier; +} + +const gchar * +mate_mixer_device_profile_get_name (MateMixerDeviceProfile *profile) +{ + g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), NULL); + + return profile->priv->name; +} + +guint32 +mate_mixer_device_profile_get_priority (MateMixerDeviceProfile *profile) +{ + g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), NULL); + + return profile->priv->priority; +} diff --git a/libmatemixer/matemixer-device-profile.h b/libmatemixer/matemixer-device-profile.h index fa750b8..1ac9020 100644 --- a/libmatemixer/matemixer-device-profile.h +++ b/libmatemixer/matemixer-device-profile.h @@ -58,6 +58,10 @@ MateMixerDeviceProfile *mate_mixer_device_profile_new (const gchar *identifier, const gchar *name, guint32 priority); +const gchar *mate_mixer_device_profile_get_identifier (MateMixerDeviceProfile *profile); +const gchar *mate_mixer_device_profile_get_name (MateMixerDeviceProfile *profile); +guint32 mate_mixer_device_profile_get_priority (MateMixerDeviceProfile *profile); + G_END_DECLS #endif /* MATEMIXER_PROFILE_H */ diff --git a/libmatemixer/matemixer-device.c b/libmatemixer/matemixer-device.c index 0c36b0b..8e6a465 100644 --- a/libmatemixer/matemixer-device.c +++ b/libmatemixer/matemixer-device.c @@ -62,7 +62,71 @@ mate_mixer_device_default_init (MateMixerDeviceInterface *iface) const GList * mate_mixer_device_list_tracks (MateMixerDevice *device) { + MateMixerDeviceInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); + + iface = MATE_MIXER_DEVICE_GET_INTERFACE (device); + if (iface->list_tracks) + return iface->list_tracks (device); + + return NULL; +} + +const GList * +mate_mixer_device_get_ports (MateMixerDevice *device) +{ + MateMixerDeviceInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); + + iface = MATE_MIXER_DEVICE_GET_INTERFACE (device); + if (iface->get_ports) + return iface->get_ports (device); + + return NULL; +} + +const GList * +mate_mixer_device_get_profiles (MateMixerDevice *device) +{ + MateMixerDeviceInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); + + iface = MATE_MIXER_DEVICE_GET_INTERFACE (device); + if (iface->get_profiles) + return iface->get_profiles (device); + + return NULL; +} + +MateMixerDeviceProfile * +mate_mixer_device_get_active_profile (MateMixerDevice *device) +{ + MateMixerDeviceInterface *iface; + g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); - return MATE_MIXER_DEVICE_GET_INTERFACE (device)->list_tracks (device); + iface = MATE_MIXER_DEVICE_GET_INTERFACE (device); + if (iface->get_active_profile) + return iface->get_active_profile (device); + + return NULL; +} + +gboolean +mate_mixer_device_set_active_profile (MateMixerDevice *device, + MateMixerDeviceProfile *profile) +{ + MateMixerDeviceInterface *iface; + + g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL); + g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), NULL); + + iface = MATE_MIXER_DEVICE_GET_INTERFACE (device); + if (iface->set_active_profile) + return iface->set_active_profile (device, profile); + + return FALSE; } diff --git a/libmatemixer/matemixer-device.h b/libmatemixer/matemixer-device.h index af5a1ce..b601f7d 100644 --- a/libmatemixer/matemixer-device.h +++ b/libmatemixer/matemixer-device.h @@ -21,6 +21,9 @@ #include #include +#include +#include + G_BEGIN_DECLS #define MATE_MIXER_TYPE_DEVICE \ @@ -40,12 +43,25 @@ struct _MateMixerDeviceInterface GTypeInterface parent; const GList *(*list_tracks) (MateMixerDevice *device); + const GList *(*get_ports) (MateMixerDevice *device); + const GList *(*get_profiles) (MateMixerDevice *device); + MateMixerDeviceProfile *(*get_active_profile) (MateMixerDevice *device); + gboolean (*set_active_profile) (MateMixerDevice *device, MateMixerDeviceProfile *profile); }; GType mate_mixer_device_get_type (void) G_GNUC_CONST; const GList *mate_mixer_device_list_tracks (MateMixerDevice *device); +const GList *mate_mixer_device_get_ports (MateMixerDevice *device); + +const GList *mate_mixer_device_get_profiles (MateMixerDevice *device); + +MateMixerDeviceProfile *mate_mixer_device_get_active_profile (MateMixerDevice *device); + +gboolean mate_mixer_device_set_active_profile (MateMixerDevice *device, + MateMixerDeviceProfile *profile); + G_END_DECLS #endif /* MATEMIXER_DEVICE_H */ diff --git a/libmatemixer/matemixer-enums.h b/libmatemixer/matemixer-enums.h index 445af7d..50190ce 100644 --- a/libmatemixer/matemixer-enums.h +++ b/libmatemixer/matemixer-enums.h @@ -19,6 +19,7 @@ #define MATEMIXER_ENUMS_H typedef enum { + MATE_MIXER_BACKEND_TYPE_UNKNOWN, MATE_MIXER_BACKEND_TYPE_PULSE, MATE_MIXER_BACKEND_TYPE_NULL } MateMixerBackendType; diff --git a/libmatemixer/matemixer.c b/libmatemixer/matemixer.c index 6c25cc5..cc4b5f1 100644 --- a/libmatemixer/matemixer.c +++ b/libmatemixer/matemixer.c @@ -25,8 +25,8 @@ #include "matemixer-private.h" #include "matemixer-backend-module.h" -static gboolean mixer_load_backends (void); -static gint mixer_compare_modules (gconstpointer a, gconstpointer b); +static void mixer_load_modules (void); +static gint mixer_compare_modules (gconstpointer a, gconstpointer b); static GList *mixer_modules = NULL; static gboolean mixer_initialized = FALSE; @@ -34,8 +34,37 @@ static gboolean mixer_initialized = FALSE; gboolean mate_mixer_init (void) { - if (!mixer_initialized) - mixer_initialized = mixer_load_backends (); + if (!mixer_initialized) { + mixer_load_modules (); + + if (mixer_modules) { + GList *list; + + list = mixer_modules; + while (list) { + GTypeModule *module = G_TYPE_MODULE (list->data); + GList *next = list->next; + + /* Attempt to load the module and remove it from the list + * if it isn't usable */ + if (!g_type_module_use (module)) { + g_object_unref (module); + mixer_modules = g_list_delete_link (mixer_modules, list); + } + list = next; + } + + if (mixer_modules) { + /* Sort the usable modules by the priority */ + mixer_modules = g_list_sort ( + mixer_modules, + mixer_compare_modules); + + mixer_initialized = TRUE; + } else + g_critical ("No usable backend modules have been found"); + } + } return mixer_initialized; } @@ -50,24 +79,13 @@ mate_mixer_deinit (void) list = mixer_modules; while (list) { - MateMixerBackendModule *module; - - module = MATE_MIXER_BACKEND_MODULE (list->data); - - g_type_module_unuse (G_TYPE_MODULE (module)); - - // XXX it is not possible to unref the module, figure out how - // to handle repeated initialization - // g_object_unref (module); - + g_type_module_unuse (G_TYPE_MODULE (list->data)); list = list->next; } - g_list_free (mixer_modules); - mixer_initialized = FALSE; } -/* Internal function: return a *shared* list of loaded backend modules */ +/* Internal function: return a shared list of loaded backend modules */ GList * mate_mixer_get_modules (void) { @@ -78,70 +96,54 @@ mate_mixer_get_modules (void) gboolean mate_mixer_is_initialized (void) { - gboolean initialized; - - G_LOCK_DEFINE_STATIC (mixer_initialized_lock); - - G_LOCK (mixer_initialized_lock); - initialized = mixer_initialized; - G_UNLOCK (mixer_initialized_lock); - - return initialized; + return mixer_initialized; } -static gboolean -mixer_load_backends (void) +static void +mixer_load_modules (void) { - GDir *dir; - GError *error = NULL; + static gboolean loaded = FALSE; - if (!g_module_supported ()) { - g_critical ("Unable to load backend modules: GModule not supported"); - return FALSE; - } + if (loaded) + return; - /* Read the directory which contains module libraries and load them */ - dir = g_dir_open (LIBMATEMIXER_BACKEND_DIR, 0, &error); - if (dir != NULL) { - const gchar *name; + if (g_module_supported ()) { + GDir *dir; + GError *error = NULL; - while ((name = g_dir_read_name (dir)) != NULL) { - gchar *file; - MateMixerBackendModule *module; + /* Read the directory which contains module libraries and create a list + * of those that are likely to be usable backend modules */ + dir = g_dir_open (LIBMATEMIXER_BACKEND_DIR, 0, &error); + if (dir != NULL) { + const gchar *name; - if (!g_str_has_suffix (name, "." G_MODULE_SUFFIX)) - continue; + while ((name = g_dir_read_name (dir)) != NULL) { + gchar *file; - file = g_build_filename (LIBMATEMIXER_BACKEND_DIR, name, NULL); - module = mate_mixer_backend_module_new (file); + if (!g_str_has_suffix (name, "." G_MODULE_SUFFIX)) + continue; - /* Load the backend module and make sure it includes all the - * required symbols */ - if (g_type_module_use (G_TYPE_MODULE (module))) - mixer_modules = g_list_prepend (mixer_modules, module); - else - g_object_unref (module); + file = g_build_filename (LIBMATEMIXER_BACKEND_DIR, name, NULL); + mixer_modules = g_list_prepend ( + mixer_modules, + mate_mixer_backend_module_new (file)); - g_free (file); - } + g_free (file); + } - if (mixer_modules == NULL) - g_critical ("No usable backend modules have been found"); + if (mixer_modules == NULL) + g_critical ("No backend modules have been found"); - g_dir_close (dir); + g_dir_close (dir); + } else { + g_critical ("%s", error->message); + g_error_free (error); + } } else { - g_critical ("%s", error->message); - g_error_free (error); - } - - if (mixer_modules) { - mixer_modules = g_list_sort (mixer_modules, mixer_compare_modules); - return TRUE; + g_critical ("Unable to load backend modules: GModule not supported"); } - /* As we include a "null" backend module to provide no functionality, - * we fail the initialization in case no module could be loaded */ - return FALSE; + loaded = TRUE; } /* GCompareFunc function to sort backend modules by the priority, lower -- cgit v1.2.1