diff options
| -rw-r--r-- | backends/null/null.c | 13 | ||||
| -rw-r--r-- | backends/null/null.h | 2 | ||||
| -rw-r--r-- | backends/pulse/pulse-device.c | 53 | ||||
| -rw-r--r-- | backends/pulse/pulse-device.h | 18 | ||||
| -rw-r--r-- | backends/pulse/pulse.c | 12 | ||||
| -rw-r--r-- | libmatemixer/matemixer-backend-module.c | 121 | ||||
| -rw-r--r-- | libmatemixer/matemixer-backend.c | 34 | ||||
| -rw-r--r-- | libmatemixer/matemixer-backend.h | 18 | ||||
| -rw-r--r-- | libmatemixer/matemixer-control.c | 114 | ||||
| -rw-r--r-- | libmatemixer/matemixer-control.h | 11 | ||||
| -rw-r--r-- | libmatemixer/matemixer-device-port.c | 66 | ||||
| -rw-r--r-- | libmatemixer/matemixer-device-port.h | 14 | ||||
| -rw-r--r-- | libmatemixer/matemixer-device-profile.c | 30 | ||||
| -rw-r--r-- | libmatemixer/matemixer-device-profile.h | 4 | ||||
| -rw-r--r-- | libmatemixer/matemixer-device.c | 66 | ||||
| -rw-r--r-- | libmatemixer/matemixer-device.h | 16 | ||||
| -rw-r--r-- | libmatemixer/matemixer-enums.h | 1 | ||||
| -rw-r--r-- | 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) @@ -48,6 +49,22 @@ mate_mixer_backend_module_init (MateMixerBackendModule *module)  }  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)  {      MateMixerBackendModule *module; @@ -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 <glib.h>  #include <glib-object.h> +#include <libmatemixer/matemixer-device-port.h> +#include <libmatemixer/matemixer-device-profile.h> +  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  | 
