summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rwxr-xr-xautogen.sh3
-rw-r--r--backends/null/Makefile.am5
-rw-r--r--backends/null/null-backend.c (renamed from backends/null/null.c)40
-rw-r--r--backends/null/null-backend.h (renamed from backends/null/null.h)48
-rw-r--r--backends/pulse/Makefile.am12
-rw-r--r--backends/pulse/pulse-backend.c812
-rw-r--r--backends/pulse/pulse-backend.h60
-rw-r--r--backends/pulse/pulse-client-stream.c146
-rw-r--r--backends/pulse/pulse-client-stream.h69
-rw-r--r--backends/pulse/pulse-connection.c1265
-rw-r--r--backends/pulse/pulse-connection.h162
-rw-r--r--backends/pulse/pulse-device.c221
-rw-r--r--backends/pulse/pulse-device.h79
-rw-r--r--backends/pulse/pulse-enum-types.c45
-rw-r--r--backends/pulse/pulse-enum-types.h36
-rw-r--r--backends/pulse/pulse-enums.h29
-rw-r--r--backends/pulse/pulse-helpers.c75
-rw-r--r--backends/pulse/pulse-helpers.h35
-rw-r--r--backends/pulse/pulse-sink-input.c170
-rw-r--r--backends/pulse/pulse-sink-input.h71
-rw-r--r--backends/pulse/pulse-sink.c175
-rw-r--r--backends/pulse/pulse-sink.h62
-rw-r--r--backends/pulse/pulse-source-output.c143
-rw-r--r--backends/pulse/pulse-source-output.h71
-rw-r--r--backends/pulse/pulse-source.c213
-rw-r--r--backends/pulse/pulse-source.h71
-rw-r--r--backends/pulse/pulse-stream.c885
-rw-r--r--backends/pulse/pulse-stream.h109
-rw-r--r--backends/pulse/pulse.c370
-rw-r--r--backends/pulse/pulse.h63
-rw-r--r--configure.ac33
-rw-r--r--data/libmatemixer.pc.in4
-rw-r--r--docs/Makefile.am1
-rw-r--r--docs/reference/Makefile.am109
-rw-r--r--docs/reference/libmatemixer-docs.xml32
-rw-r--r--docs/reference/libmatemixer-overrides.txt0
-rw-r--r--docs/reference/libmatemixer-sections.txt187
-rw-r--r--docs/reference/libmatemixer.types6
-rw-r--r--docs/reference/version.xml.in1
-rw-r--r--examples/Makefile.am15
-rw-r--r--examples/monitor.c270
-rw-r--r--gtk-doc.make289
-rw-r--r--libmatemixer/Makefile.am8
-rw-r--r--libmatemixer/matemixer-backend-module.c22
-rw-r--r--libmatemixer/matemixer-backend-module.h6
-rw-r--r--libmatemixer/matemixer-backend.c163
-rw-r--r--libmatemixer/matemixer-backend.h70
-rw-r--r--libmatemixer/matemixer-client-stream.c83
-rw-r--r--libmatemixer/matemixer-client-stream.h59
-rw-r--r--libmatemixer/matemixer-control.c1043
-rw-r--r--libmatemixer/matemixer-control.h67
-rw-r--r--libmatemixer/matemixer-device.c7
-rw-r--r--libmatemixer/matemixer-device.h8
-rw-r--r--libmatemixer/matemixer-enum-types.c30
-rw-r--r--libmatemixer/matemixer-enum-types.h13
-rw-r--r--libmatemixer/matemixer-enums.h61
-rw-r--r--libmatemixer/matemixer-port.c102
-rw-r--r--libmatemixer/matemixer-port.h32
-rw-r--r--libmatemixer/matemixer-profile.c65
-rw-r--r--libmatemixer/matemixer-profile.h16
-rw-r--r--libmatemixer/matemixer-stream.c131
-rw-r--r--libmatemixer/matemixer-stream.h69
-rw-r--r--libmatemixer/matemixer-version.h.in64
-rw-r--r--libmatemixer/matemixer.c27
-rw-r--r--libmatemixer/matemixer.h4
-rw-r--r--m4/gtk-doc.m488
-rw-r--r--omf.make65
-rw-r--r--xmldocs.make101
69 files changed, 7231 insertions, 1668 deletions
diff --git a/Makefile.am b/Makefile.am
index 0eb7591..a1659ac 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,7 +4,8 @@ SUBDIRS = \
libmatemixer \
backends \
data \
- docs
+ docs \
+ examples
EXTRA_DIST = autogen.sh
diff --git a/autogen.sh b/autogen.sh
index cfa4c75..62cf8eb 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -18,6 +18,7 @@ which mate-autogen || {
}
REQUIRED_AUTOMAKE_VERSION=1.9
-# USE_COMMON_DOC_BUILD=yes
+REQUIRED_GTK_DOC_VERSION=1.9
+USE_COMMON_DOC_BUILD=yes
. mate-autogen
diff --git a/backends/null/Makefile.am b/backends/null/Makefile.am
index f28bc06..8ce28d1 100644
--- a/backends/null/Makefile.am
+++ b/backends/null/Makefile.am
@@ -9,13 +9,14 @@ AM_CPPFLAGS = \
libmatemixer_null_la_CFLAGS = $(GLIB_CFLAGS)
libmatemixer_null_la_SOURCES = \
- null.c \
- null.h
+ null-backend.c \
+ null-backend.h
libmatemixer_null_la_LIBADD = $(GLIB_LIBS)
libmatemixer_null_la_LDFLAGS = \
-avoid-version \
+ -no-undefined \
-export-dynamic \
-module
diff --git a/backends/null/null.c b/backends/null/null-backend.c
index 1e8085d..f8c22c8 100644
--- a/backends/null/null.c
+++ b/backends/null/null-backend.c
@@ -21,31 +21,35 @@
#include <libmatemixer/matemixer-backend.h>
#include <libmatemixer/matemixer-backend-module.h>
-#include "null.h"
+#include "null-backend.h"
#define BACKEND_NAME "Null"
-#define BACKEND_PRIORITY 999
+#define BACKEND_PRIORITY 0
static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface);
-static void mate_mixer_null_class_init (MateMixerNullClass *klass);
-static void mate_mixer_null_class_finalize (MateMixerNullClass *klass);
-static void mate_mixer_null_init (MateMixerNull *null);
-G_DEFINE_DYNAMIC_TYPE_EXTENDED (MateMixerNull, mate_mixer_null,
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (NullBackend, null_backend,
G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE_DYNAMIC (MATE_MIXER_TYPE_BACKEND,
mate_mixer_backend_interface_init))
+static void null_backend_class_init (NullBackendClass *klass);
+static void null_backend_class_finalize (NullBackendClass *klass);
+static void null_backend_init (NullBackend *null);
+
+static gboolean backend_open (MateMixerBackend *backend);
+static MateMixerState backend_get_state (MateMixerBackend *backend);
+
static MateMixerBackendInfo info;
void
backend_module_init (GTypeModule *module)
{
- mate_mixer_null_register_type (module);
+ null_backend_register_type (module);
info.name = BACKEND_NAME;
info.priority = BACKEND_PRIORITY;
- info.g_type = MATE_MIXER_TYPE_NULL;
+ info.g_type = NULL_TYPE_BACKEND;
info.backend_type = MATE_MIXER_BACKEND_NULL;
}
@@ -58,27 +62,35 @@ backend_module_get_info (void)
static void
mate_mixer_backend_interface_init (MateMixerBackendInterface *iface)
{
- iface->open = mate_mixer_null_open;
+ iface->open = backend_open;
+ iface->get_state = backend_get_state;
}
static void
-mate_mixer_null_class_init (MateMixerNullClass *klass)
+null_backend_class_init (NullBackendClass *klass)
{
+ // XXX is it needed to have this function? shouldn't it call parent method if empty?
}
/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE_EXTENDED() */
static void
-mate_mixer_null_class_finalize (MateMixerNullClass *klass)
+null_backend_class_finalize (NullBackendClass *klass)
{
}
static void
-mate_mixer_null_init (MateMixerNull *null)
+null_backend_init (NullBackend *null)
{
}
-gboolean
-mate_mixer_null_open (MateMixerBackend *backend)
+static gboolean
+backend_open (MateMixerBackend *backend)
{
return TRUE;
}
+
+static MateMixerState
+backend_get_state (MateMixerBackend *backend)
+{
+ return MATE_MIXER_STATE_READY;
+}
diff --git a/backends/null/null.h b/backends/null/null-backend.h
index c9dd501..2d718e3 100644
--- a/backends/null/null.h
+++ b/backends/null/null-backend.h
@@ -15,46 +15,46 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef MATEMIXER_NULL_H
-#define MATEMIXER_NULL_H
+#ifndef MATEMIXER_NULL_BACKEND_H
+#define MATEMIXER_NULL_BACKEND_H
#include <glib.h>
#include <glib-object.h>
#include <libmatemixer/matemixer-backend.h>
-#define MATE_MIXER_TYPE_NULL \
- (mate_mixer_null_get_type ())
-#define MATE_MIXER_NULL(o) \
- (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_NULL, MateMixerNull))
-#define MATE_MIXER_IS_NULL(o) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_NULL))
-#define MATE_MIXER_NULL_CLASS(k) \
- (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_NULL, MateMixerNullClass))
-#define MATE_MIXER_IS_NULL_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_NULL))
-#define MATE_MIXER_NULL_GET_CLASS(o) \
- (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_NULL, MateMixerNullClass))
-
-typedef struct _MateMixerNull MateMixerNull;
-typedef struct _MateMixerNullClass MateMixerNullClass;
-
-struct _MateMixerNull
+#define NULL_TYPE_BACKEND \
+ (null_backend_get_type ())
+#define NULL_BACKEND(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), NULL_TYPE_BACKEND, NullBackend))
+#define NULL_IS_BACKEND(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), NULL_TYPE_BACKEND))
+#define NULL_BACKEND_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), NULL_TYPE_BACKEND, NullBackendClass))
+#define NULL_IS_BACKEND_CLASS(k) \
+ (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), NULL_TYPE_BACKEND))
+#define NULL_BACKEND_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), NULL_TYPE_BACKEND, NullBackendClass))
+
+typedef struct _NullBackend NullBackend;
+typedef struct _NullBackendClass NullBackendClass;
+
+struct _NullBackend
{
+ /*< private >*/
GObject parent;
};
-struct _MateMixerNullClass
+struct _NullBackendClass
{
+ /*< private >*/
GObjectClass parent;
};
-GType mate_mixer_null_get_type (void) G_GNUC_CONST;
+GType null_backend_get_type (void) G_GNUC_CONST;
/* Support function for dynamic loading of the backend module */
-void backend_module_init (GTypeModule *module);
+void backend_module_init (GTypeModule *module);
const MateMixerBackendInfo *backend_module_get_info (void);
-gboolean mate_mixer_null_open (MateMixerBackend *backend);
-
#endif /* MATEMIXER_NULL_H */
diff --git a/backends/pulse/Makefile.am b/backends/pulse/Makefile.am
index 2cc7b5e..fe0d459 100644
--- a/backends/pulse/Makefile.am
+++ b/backends/pulse/Makefile.am
@@ -11,12 +11,19 @@ libmatemixer_pulse_la_CFLAGS = \
$(PULSEAUDIO_CFLAGS)
libmatemixer_pulse_la_SOURCES = \
- pulse.c \
- pulse.h \
+ pulse-backend.c \
+ pulse-backend.h \
+ pulse-client-stream.c \
+ pulse-client-stream.h \
pulse-connection.c \
pulse-connection.h \
pulse-device.c \
pulse-device.h \
+ pulse-enums.h \
+ pulse-enum-types.c \
+ pulse-enum-types.h \
+ pulse-helpers.c \
+ pulse-helpers.h \
pulse-stream.c \
pulse-stream.h \
pulse-sink.c \
@@ -34,6 +41,7 @@ libmatemixer_pulse_la_LIBADD = \
libmatemixer_pulse_la_LDFLAGS = \
-avoid-version \
+ -no-undefined \
-export-dynamic \
-module
diff --git a/backends/pulse/pulse-backend.c b/backends/pulse/pulse-backend.c
new file mode 100644
index 0000000..79a69a0
--- /dev/null
+++ b/backends/pulse/pulse-backend.c
@@ -0,0 +1,812 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-backend.h>
+#include <libmatemixer/matemixer-backend-module.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-backend.h"
+#include "pulse-connection.h"
+#include "pulse-device.h"
+#include "pulse-enums.h"
+#include "pulse-stream.h"
+#include "pulse-sink.h"
+#include "pulse-sink-input.h"
+#include "pulse-source.h"
+#include "pulse-source-output.h"
+
+#define BACKEND_NAME "PulseAudio"
+#define BACKEND_PRIORITY 10
+
+struct _PulseBackendPrivate
+{
+ gchar *app_name;
+ gchar *app_id;
+ gchar *app_version;
+ gchar *app_icon;
+ gchar *server_address;
+ gchar *default_sink;
+ gchar *default_source;
+ GHashTable *devices;
+ GHashTable *cards;
+ GHashTable *sinks;
+ GHashTable *sink_inputs;
+ GHashTable *sources;
+ GHashTable *source_outputs;
+ MateMixerState state;
+ PulseConnection *connection;
+};
+
+enum {
+ PROP_0,
+ PROP_STATE,
+ N_PROPERTIES
+};
+
+static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (PulseBackend, pulse_backend,
+ G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE_DYNAMIC (MATE_MIXER_TYPE_BACKEND,
+ mate_mixer_backend_interface_init))
+
+static gboolean backend_open (MateMixerBackend *backend);
+static void backend_close (MateMixerBackend *backend);
+
+static MateMixerState backend_get_state (MateMixerBackend *backend);
+
+static void backend_set_data (MateMixerBackend *backend,
+ const MateMixerBackendData *data);
+
+static GList * backend_list_devices (MateMixerBackend *backend);
+static GList * backend_list_streams (MateMixerBackend *backend);
+
+static MateMixerStream *backend_get_default_input_stream (MateMixerBackend *backend);
+static gboolean backend_set_default_input_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
+
+static MateMixerStream *backend_get_default_output_stream (MateMixerBackend *backend);
+static gboolean backend_set_default_output_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
+
+static void backend_connection_state_cb (PulseConnection *connection,
+ GParamSpec *pspec,
+ PulseBackend *pulse);
+
+static void backend_server_info_cb (PulseConnection *connection,
+ const pa_server_info *info,
+ PulseBackend *pulse);
+
+static void backend_card_info_cb (PulseConnection *connection,
+ const pa_card_info *info,
+ PulseBackend *pulse);
+static void backend_card_removed_cb (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse);
+static void backend_sink_info_cb (PulseConnection *connection,
+ const pa_sink_info *info,
+ PulseBackend *pulse);
+static void backend_sink_removed_cb (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse);
+static void backend_sink_input_info_cb (PulseConnection *connection,
+ const pa_sink_input_info *info,
+ PulseBackend *pulse);
+static void backend_sink_input_removed_cb (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse);
+static void backend_source_info_cb (PulseConnection *connection,
+ const pa_source_info *info,
+ PulseBackend *pulse);
+static void backend_source_removed_cb (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse);
+static void backend_source_output_info_cb (PulseConnection *connection,
+ const pa_source_output_info *info,
+ PulseBackend *pulse);
+static void backend_source_output_removed_cb (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse);
+
+static gint backend_compare_devices (gconstpointer a,
+ gconstpointer b);
+static gint backend_compare_streams (gconstpointer a,
+ gconstpointer b);
+
+static MateMixerBackendInfo info;
+
+void
+backend_module_init (GTypeModule *module)
+{
+ pulse_backend_register_type (module);
+
+ info.name = BACKEND_NAME;
+ info.priority = BACKEND_PRIORITY;
+ info.g_type = PULSE_TYPE_BACKEND;
+ info.backend_type = MATE_MIXER_BACKEND_PULSE;
+}
+
+const MateMixerBackendInfo *
+backend_module_get_info (void)
+{
+ return &info;
+}
+
+static void
+mate_mixer_backend_interface_init (MateMixerBackendInterface *iface)
+{
+ iface->open = backend_open;
+ iface->close = backend_close;
+ iface->get_state = backend_get_state;
+ iface->set_data = backend_set_data;
+ iface->list_devices = backend_list_devices;
+ iface->list_streams = backend_list_streams;
+ iface->get_default_input_stream = backend_get_default_input_stream;
+ iface->set_default_input_stream = backend_set_default_input_stream;
+ iface->get_default_output_stream = backend_get_default_output_stream;
+ iface->set_default_output_stream = backend_set_default_output_stream;
+}
+
+static void
+pulse_backend_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PulseBackend *pulse;
+
+ pulse = PULSE_BACKEND (object);
+
+ switch (param_id) {
+ case PROP_STATE:
+ g_value_set_enum (value, pulse->priv->state);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_backend_init (PulseBackend *pulse)
+{
+ pulse->priv = G_TYPE_INSTANCE_GET_PRIVATE (pulse,
+ PULSE_TYPE_BACKEND,
+ PulseBackendPrivate);
+ pulse->priv->devices =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+ pulse->priv->cards =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+ pulse->priv->sinks =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+ pulse->priv->sink_inputs =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+ pulse->priv->sources =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+ pulse->priv->source_outputs =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+}
+
+static void
+pulse_backend_dispose (GObject *object)
+{
+ PulseBackend *pulse;
+
+ pulse = PULSE_BACKEND (object);
+
+ if (pulse->priv->devices) {
+ g_hash_table_destroy (pulse->priv->devices);
+ pulse->priv->devices = NULL;
+ }
+
+ if (pulse->priv->cards) {
+ g_hash_table_destroy (pulse->priv->cards);
+ pulse->priv->cards = NULL;
+ }
+
+ if (pulse->priv->sinks) {
+ g_hash_table_destroy (pulse->priv->sinks);
+ pulse->priv->devices = NULL;
+ }
+
+ if (pulse->priv->sink_inputs) {
+ g_hash_table_destroy (pulse->priv->sink_inputs);
+ pulse->priv->devices = NULL;
+ }
+
+ if (pulse->priv->sources) {
+ g_hash_table_destroy (pulse->priv->sources);
+ pulse->priv->devices = NULL;
+ }
+
+ if (pulse->priv->source_outputs) {
+ g_hash_table_destroy (pulse->priv->source_outputs);
+ pulse->priv->source_outputs = NULL;
+ }
+
+ g_clear_object (&pulse->priv->connection);
+
+ G_OBJECT_CLASS (pulse_backend_parent_class)->dispose (object);
+}
+
+static void
+pulse_backend_finalize (GObject *object)
+{
+ PulseBackend *pulse;
+
+ pulse = PULSE_BACKEND (object);
+
+ g_free (pulse->priv->app_name);
+ g_free (pulse->priv->app_id);
+ g_free (pulse->priv->app_version);
+ g_free (pulse->priv->app_icon);
+ g_free (pulse->priv->server_address);
+
+ G_OBJECT_CLASS (pulse_backend_parent_class)->finalize (object);
+}
+
+static void
+pulse_backend_class_init (PulseBackendClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_backend_dispose;
+ object_class->finalize = pulse_backend_finalize;
+ object_class->get_property = pulse_backend_get_property;
+
+ g_object_class_override_property (object_class, PROP_STATE, "state");
+
+ g_type_class_add_private (klass, sizeof (PulseBackendPrivate));
+}
+
+/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE_EXTENDED() */
+static void
+pulse_backend_class_finalize (PulseBackendClass *klass)
+{
+}
+
+static gboolean
+backend_open (MateMixerBackend *backend)
+{
+ PulseBackend *pulse;
+ PulseConnection *connection;
+
+ g_return_val_if_fail (PULSE_IS_BACKEND (backend), FALSE);
+
+ pulse = PULSE_BACKEND (backend);
+
+ if (G_UNLIKELY (pulse->priv->connection != NULL))
+ return TRUE;
+
+ connection = pulse_connection_new (pulse->priv->app_name,
+ pulse->priv->app_id,
+ pulse->priv->app_version,
+ pulse->priv->app_icon,
+ pulse->priv->server_address);
+ if (G_UNLIKELY (connection == NULL)) {
+ pulse->priv->state = MATE_MIXER_STATE_FAILED;
+ return FALSE;
+ }
+
+ g_signal_connect (connection,
+ "notify::state",
+ G_CALLBACK (backend_connection_state_cb),
+ pulse);
+ g_signal_connect (connection,
+ "server-info",
+ G_CALLBACK (backend_server_info_cb),
+ pulse);
+ g_signal_connect (connection,
+ "card-info",
+ G_CALLBACK (backend_card_info_cb),
+ pulse);
+ g_signal_connect (connection,
+ "card-removed",
+ G_CALLBACK (backend_card_removed_cb),
+ pulse);
+ g_signal_connect (connection,
+ "sink-info",
+ G_CALLBACK (backend_sink_info_cb),
+ pulse);
+ g_signal_connect (connection,
+ "sink-removed",
+ G_CALLBACK (backend_sink_removed_cb),
+ pulse);
+ g_signal_connect (connection,
+ "sink-input-info",
+ G_CALLBACK (backend_sink_input_info_cb),
+ pulse);
+ g_signal_connect (connection,
+ "sink-input-removed",
+ G_CALLBACK (backend_sink_input_removed_cb),
+ pulse);
+ g_signal_connect (connection,
+ "source-info",
+ G_CALLBACK (backend_source_info_cb),
+ pulse);
+ g_signal_connect (connection,
+ "source-removed",
+ G_CALLBACK (backend_source_removed_cb),
+ pulse);
+ g_signal_connect (connection,
+ "source-output-info",
+ G_CALLBACK (backend_source_output_info_cb),
+ pulse);
+ g_signal_connect (connection,
+ "source-output-removed",
+ G_CALLBACK (backend_source_output_removed_cb),
+ pulse);
+
+ if (!pulse_connection_connect (connection)) {
+ pulse->priv->state = MATE_MIXER_STATE_FAILED;
+ g_object_unref (connection);
+ return FALSE;
+ }
+ pulse->priv->connection = connection;
+ pulse->priv->state = MATE_MIXER_STATE_CONNECTING;
+ return TRUE;
+}
+
+static void
+backend_close (MateMixerBackend *backend)
+{
+ g_return_if_fail (PULSE_IS_BACKEND (backend));
+
+ g_clear_object (&PULSE_BACKEND (backend)->priv->connection);
+}
+
+static MateMixerState
+backend_get_state (MateMixerBackend *backend)
+{
+ g_return_val_if_fail (PULSE_IS_BACKEND (backend), MATE_MIXER_STATE_UNKNOWN);
+
+ return PULSE_BACKEND (backend)->priv->state;
+}
+
+static void
+backend_set_data (MateMixerBackend *backend, const MateMixerBackendData *data)
+{
+ PulseBackend *pulse;
+
+ if (data == NULL)
+ return;
+
+ g_return_if_fail (PULSE_IS_BACKEND (backend));
+
+ pulse = PULSE_BACKEND (backend);
+
+ g_free (data->app_name);
+ g_free (data->app_id);
+ g_free (data->app_version);
+ g_free (data->app_icon);
+ g_free (data->server_address);
+
+ pulse->priv->app_name = g_strdup (data->app_name);
+ pulse->priv->app_id = g_strdup (data->app_id);
+ pulse->priv->app_version = g_strdup (data->app_version);
+ pulse->priv->app_icon = g_strdup (data->app_icon);
+ pulse->priv->server_address = g_strdup (data->server_address);
+}
+
+static GList *
+backend_list_devices (MateMixerBackend *backend)
+{
+ GList *list;
+
+ g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
+
+ list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->devices);
+
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ return g_list_sort (list, backend_compare_devices);
+}
+
+static GList *
+backend_list_streams (MateMixerBackend *backend)
+{
+ GList *list;
+ PulseBackend *pulse;
+
+ g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
+
+ pulse = PULSE_BACKEND (backend);
+
+ list = g_list_concat (g_hash_table_get_values (pulse->priv->sinks),
+ g_hash_table_get_values (pulse->priv->sink_inputs));
+ list = g_list_concat (list,
+ g_hash_table_get_values (pulse->priv->sources));
+ list = g_list_concat (list,
+ g_hash_table_get_values (pulse->priv->source_outputs));
+
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ return g_list_sort (list, backend_compare_streams);
+}
+
+static MateMixerStream *
+backend_get_default_input_stream (MateMixerBackend *backend)
+{
+ return NULL;
+}
+
+static gboolean
+backend_set_default_input_stream (MateMixerBackend *backend, MateMixerStream *stream)
+{
+ PulseBackend *pulse;
+
+ g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
+
+ pulse = PULSE_BACKEND (backend);
+
+ return pulse_connection_set_default_source (pulse->priv->connection,
+ mate_mixer_stream_get_name (stream));
+}
+
+static MateMixerStream *
+backend_get_default_output_stream (MateMixerBackend *backend)
+{
+ return NULL;
+}
+
+static gboolean
+backend_set_default_output_stream (MateMixerBackend *backend, MateMixerStream *stream)
+{
+ PulseBackend *pulse;
+
+ g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
+
+ pulse = PULSE_BACKEND (backend);
+
+ return pulse_connection_set_default_sink (pulse->priv->connection,
+ mate_mixer_stream_get_name (stream));
+}
+
+static void
+backend_connection_state_cb (PulseConnection *connection,
+ GParamSpec *pspec,
+ PulseBackend *pulse)
+{
+ PulseConnectionState state = pulse_connection_get_state (connection);
+
+ switch (state) {
+ case PULSE_CONNECTION_DISCONNECTED:
+ break;
+ case PULSE_CONNECTION_CONNECTING:
+ break;
+ case PULSE_CONNECTION_AUTHORIZING:
+ break;
+ case PULSE_CONNECTION_LOADING:
+ break;
+ case PULSE_CONNECTION_CONNECTED:
+ pulse->priv->state = MATE_MIXER_STATE_READY;
+
+ g_object_notify (G_OBJECT (pulse), "state");
+ break;
+ }
+}
+
+static void
+backend_server_info_cb (PulseConnection *connection,
+ const pa_server_info *info,
+ PulseBackend *pulse)
+{
+ // XXX add property
+
+ if (g_strcmp0 (pulse->priv->default_sink, info->default_sink_name)) {
+ g_free (pulse->priv->default_sink);
+
+ pulse->priv->default_sink = g_strdup (info->default_sink_name);
+ // g_object_notify (G_OBJECT (pulse), "default-output");
+ }
+
+ if (g_strcmp0 (pulse->priv->default_source, info->default_source_name)) {
+ g_free (pulse->priv->default_source);
+
+ pulse->priv->default_source = g_strdup (info->default_source_name);
+ // g_object_notify (G_OBJECT (pulse), "default-input");
+ }
+}
+
+static void
+backend_card_info_cb (PulseConnection *connection,
+ const pa_card_info *info,
+ PulseBackend *pulse)
+{
+ gpointer p;
+
+ p = g_hash_table_lookup (pulse->priv->devices, GINT_TO_POINTER (info->index));
+ if (!p) {
+ PulseDevice *device;
+
+ device = pulse_device_new (connection, info);
+ g_hash_table_insert (pulse->priv->devices,
+ GINT_TO_POINTER (pulse_device_get_index (device)),
+ device);
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "device-added",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
+ } else {
+ pulse_device_update (PULSE_DEVICE (p), info);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "device-changed",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (p)));
+ }
+}
+
+static void
+backend_card_removed_cb (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse)
+{
+ gpointer p;
+ gchar *name;
+
+ p = g_hash_table_lookup (pulse->priv->devices, GINT_TO_POINTER (index));
+ if (G_UNLIKELY (p == NULL))
+ return;
+
+ name = g_strdup (mate_mixer_device_get_name (MATE_MIXER_DEVICE (p)));
+
+ g_hash_table_remove (pulse->priv->devices, GINT_TO_POINTER (index));
+ if (G_LIKELY (name != NULL))
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "device-removed",
+ name);
+ g_free (name);
+}
+
+static void
+backend_sink_info_cb (PulseConnection *connection,
+ const pa_sink_info *info,
+ PulseBackend *pulse)
+{
+ gpointer p;
+
+ p = g_hash_table_lookup (pulse->priv->sinks, GINT_TO_POINTER (info->index));
+ if (!p) {
+ PulseStream *stream;
+
+ stream = pulse_sink_new (connection, info);
+ g_hash_table_insert (pulse->priv->sinks,
+ GINT_TO_POINTER (pulse_stream_get_index (stream)),
+ stream);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ } else {
+ pulse_sink_update (p, info);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-changed",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (p)));
+ }
+}
+
+static void
+backend_sink_removed_cb (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse)
+{
+ gpointer p;
+ gchar *name;
+
+ p = g_hash_table_lookup (pulse->priv->sinks, GINT_TO_POINTER (index));
+ if (G_UNLIKELY (p == NULL))
+ return;
+
+ name = g_strdup (mate_mixer_stream_get_name (MATE_MIXER_STREAM (p)));
+
+ g_hash_table_remove (pulse->priv->sinks, GINT_TO_POINTER (index));
+ if (G_LIKELY (name != NULL))
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-removed",
+ name);
+ g_free (name);
+}
+
+static void
+backend_sink_input_info_cb (PulseConnection *connection,
+ const pa_sink_input_info *info,
+ PulseBackend *pulse)
+{
+ gpointer p;
+
+ p = g_hash_table_lookup (pulse->priv->sink_inputs, GINT_TO_POINTER (info->index));
+ if (!p) {
+ PulseStream *stream;
+
+ stream = pulse_sink_input_new (connection, info);
+ g_hash_table_insert (pulse->priv->sink_inputs,
+ GINT_TO_POINTER (pulse_stream_get_index (stream)),
+ stream);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ } else {
+ pulse_sink_input_update (p, info);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-changed",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (p)));
+ }
+}
+
+static void
+backend_sink_input_removed_cb (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse)
+{
+ gpointer p;
+ gchar *name;
+
+ p = g_hash_table_lookup (pulse->priv->sink_inputs, GINT_TO_POINTER (index));
+ if (G_UNLIKELY (p == NULL))
+ return;
+
+ name = g_strdup (mate_mixer_stream_get_name (MATE_MIXER_STREAM (p)));
+
+ g_hash_table_remove (pulse->priv->sink_inputs, GINT_TO_POINTER (index));
+ if (G_LIKELY (name != NULL))
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-removed",
+ name);
+ g_free (name);
+}
+
+static void
+backend_source_info_cb (PulseConnection *connection,
+ const pa_source_info *info,
+ PulseBackend *pulse)
+{
+ gpointer p;
+
+ p = g_hash_table_lookup (pulse->priv->sources, GINT_TO_POINTER (info->index));
+ if (!p) {
+ PulseStream *stream;
+
+ stream = pulse_source_new (connection, info);
+ g_hash_table_insert (pulse->priv->sources,
+ GINT_TO_POINTER (pulse_stream_get_index (stream)),
+ stream);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ } else {
+ pulse_source_update (p, info);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-changed",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (p)));
+ }
+}
+
+static void
+backend_source_removed_cb (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse)
+{
+ gpointer p;
+ gchar *name;
+
+ p = g_hash_table_lookup (pulse->priv->sources, GINT_TO_POINTER (index));
+ if (G_UNLIKELY (p == NULL))
+ return;
+
+ name = g_strdup (mate_mixer_stream_get_name (MATE_MIXER_STREAM (p)));
+
+ g_hash_table_remove (pulse->priv->sources, GINT_TO_POINTER (index));
+ if (G_LIKELY (name != NULL))
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-removed",
+ name);
+ g_free (name);
+}
+
+static void
+backend_source_output_info_cb (PulseConnection *connection,
+ const pa_source_output_info *info,
+ PulseBackend *pulse)
+{
+ gpointer p;
+
+ p = g_hash_table_lookup (pulse->priv->source_outputs, GINT_TO_POINTER (info->index));
+ if (!p) {
+ PulseStream *stream;
+
+ stream = pulse_source_output_new (connection, info);
+ g_hash_table_insert (pulse->priv->source_outputs,
+ GINT_TO_POINTER (pulse_stream_get_index (stream)),
+ stream);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ } else {
+ pulse_source_output_update (p, info);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-changed",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (p)));
+ }
+}
+
+static void
+backend_source_output_removed_cb (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse)
+{
+ gpointer p;
+ gchar *name;
+
+ p = g_hash_table_lookup (pulse->priv->source_outputs, GINT_TO_POINTER (index));
+ if (G_UNLIKELY (p == NULL))
+ return;
+
+ name = g_strdup (mate_mixer_stream_get_name (MATE_MIXER_STREAM (p)));
+
+ g_hash_table_remove (pulse->priv->source_outputs, GINT_TO_POINTER (index));
+ if (G_LIKELY (name != NULL))
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-removed",
+ name);
+ g_free (name);
+}
+
+static gint
+backend_compare_devices (gconstpointer a, gconstpointer b)
+{
+ return strcmp (mate_mixer_device_get_name (MATE_MIXER_DEVICE (a)),
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (b)));
+}
+
+static gint
+backend_compare_streams (gconstpointer a, gconstpointer b)
+{
+ return strcmp (mate_mixer_stream_get_name (MATE_MIXER_STREAM (a)),
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (b)));
+}
diff --git a/backends/pulse/pulse-backend.h b/backends/pulse/pulse-backend.h
new file mode 100644
index 0000000..64be9b7
--- /dev/null
+++ b/backends/pulse/pulse-backend.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_BACKEND_H
+#define PULSE_BACKEND_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#define PULSE_TYPE_BACKEND \
+ (pulse_backend_get_type ())
+#define PULSE_BACKEND(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_BACKEND, PulseBackend))
+#define PULSE_IS_BACKEND(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_BACKEND))
+#define PULSE_BACKEND_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_BACKEND, PulseBackendClass))
+#define PULSE_IS_BACKEND_CLASS(k) \
+ (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_BACKEND))
+#define PULSE_BACKEND_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_BACKEND, PulseBackendClass))
+
+typedef struct _PulseBackend PulseBackend;
+typedef struct _PulseBackendClass PulseBackendClass;
+typedef struct _PulseBackendPrivate PulseBackendPrivate;
+
+struct _PulseBackend
+{
+ /*< private >*/
+ GObject parent;
+ PulseBackendPrivate *priv;
+};
+
+struct _PulseBackendClass
+{
+ /*< private >*/
+ GObjectClass parent;
+};
+
+GType pulse_backend_get_type (void) G_GNUC_CONST;
+
+/* Support function for dynamic loading of the backend module */
+void backend_module_init (GTypeModule *module);
+const MateMixerBackendInfo *backend_module_get_info (void);
+
+#endif /* PULSE_BACKEND_H */
diff --git a/backends/pulse/pulse-client-stream.c b/backends/pulse/pulse-client-stream.c
new file mode 100644
index 0000000..ebeec99
--- /dev/null
+++ b/backends/pulse/pulse-client-stream.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <string.h>
+
+#include <libmatemixer/matemixer-client-stream.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-client-stream.h"
+#include "pulse-stream.h"
+
+struct _PulseClientStreamPrivate
+{
+ MateMixerStream *parent;
+};
+
+enum
+{
+ PROP_0,
+ PROP_PARENT,
+ N_PROPERTIES
+};
+
+static void mate_mixer_client_stream_interface_init (MateMixerClientStreamInterface *iface);
+static void pulse_client_stream_class_init (PulseClientStreamClass *klass);
+static void pulse_client_stream_init (PulseClientStream *client);
+static void pulse_client_stream_dispose (GObject *object);
+
+/* Interface implementation */
+static MateMixerStream *stream_client_get_parent (MateMixerClientStream *client);
+static gboolean stream_client_set_parent (MateMixerClientStream *client,
+ MateMixerStream *parent);
+static gboolean stream_client_remove (MateMixerClientStream *client);
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (PulseClientStream, pulse_client_stream, PULSE_TYPE_STREAM,
+ G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_CLIENT_STREAM,
+ mate_mixer_client_stream_interface_init))
+
+static void
+mate_mixer_client_stream_interface_init (MateMixerClientStreamInterface *iface)
+{
+ iface->get_parent = stream_client_get_parent;
+ iface->set_parent = stream_client_set_parent;
+ iface->remove = stream_client_remove;
+}
+
+static void
+pulse_client_stream_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PulseClientStream *client;
+
+ client = PULSE_CLIENT_STREAM (object);
+
+ switch (param_id) {
+ case PROP_PARENT:
+ g_value_set_object (value, client->priv->parent);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_client_stream_class_init (PulseClientStreamClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_client_stream_dispose;
+ object_class->get_property = pulse_client_stream_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_PARENT,
+ g_param_spec_object ("parent",
+ "Parent",
+ "Parent stream of the client stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_type_class_add_private (object_class, sizeof (PulseClientStreamPrivate));
+}
+
+static void
+pulse_client_stream_init (PulseClientStream *client)
+{
+ client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client,
+ PULSE_TYPE_CLIENT_STREAM,
+ PulseClientStreamPrivate);
+}
+
+static void
+pulse_client_stream_dispose (GObject *object)
+{
+ PulseClientStream *client;
+
+ client = PULSE_CLIENT_STREAM (object);
+
+ g_clear_object (&client->priv->parent);
+
+ G_OBJECT_CLASS (pulse_client_stream_parent_class)->dispose (object);
+}
+
+static MateMixerStream *
+stream_client_get_parent (MateMixerClientStream *client)
+{
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
+
+ return PULSE_CLIENT_STREAM (client)->priv->parent;
+}
+
+static gboolean
+stream_client_set_parent (MateMixerClientStream *client, MateMixerStream *parent)
+{
+ // TODO
+ return TRUE;
+}
+
+static gboolean
+stream_client_remove (MateMixerClientStream *client)
+{
+ // TODO
+ return TRUE;
+}
diff --git a/backends/pulse/pulse-client-stream.h b/backends/pulse/pulse-client-stream.h
new file mode 100644
index 0000000..cf801ce
--- /dev/null
+++ b/backends/pulse/pulse-client-stream.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_CLIENT_STREAM_H
+#define PULSE_CLIENT_STREAM_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-client-stream.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-stream.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_CLIENT_STREAM \
+ (pulse_client_stream_get_type ())
+#define PULSE_CLIENT_STREAM(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_CLIENT_STREAM, PulseClientStream))
+#define PULSE_IS_CLIENT_STREAM(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_CLIENT_STREAM))
+#define PULSE_CLIENT_STREAM_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_CLIENT_STREAM, PulseClientStreamClass))
+#define PULSE_IS_CLIENT_STREAM_CLASS(k) \
+ (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_CLIENT_STREAM))
+#define PULSE_CLIENT_STREAM_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_CLIENT_STREAM, PulseClientStreamClass))
+
+typedef struct _PulseClientStream PulseClientStream;
+typedef struct _PulseClientStreamClass PulseClientStreamClass;
+typedef struct _PulseClientStreamPrivate PulseClientStreamPrivate;
+
+struct _PulseClientStream
+{
+ PulseStream parent;
+
+ PulseClientStreamPrivate *priv;
+};
+
+struct _PulseClientStreamClass
+{
+ PulseStreamClass parent;
+
+ gboolean (*set_parent) (MateMixerClientStream *client,
+ MateMixerStream *stream);
+ gboolean (*remove) (MateMixerClientStream *client);
+};
+
+GType pulse_client_stream_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* PULSE_CLIENT_STREAM_H */
diff --git a/backends/pulse/pulse-connection.c b/backends/pulse/pulse-connection.c
index 6c70490..ec172ca 100644
--- a/backends/pulse/pulse-connection.c
+++ b/backends/pulse/pulse-connection.c
@@ -21,105 +21,106 @@
#include <unistd.h>
#include <pulse/pulseaudio.h>
+#include <pulse/glib-mainloop.h>
#include "pulse-connection.h"
+#include "pulse-enums.h"
+#include "pulse-enum-types.h"
-struct _MateMixerPulseConnectionPrivate
+struct _PulseConnectionPrivate
{
- gchar *server;
- gboolean reconnect;
- gboolean connected;
- pa_context *context;
- pa_threaded_mainloop *mainloop;
+ gchar *server;
+ guint outstanding;
+ gboolean reconnect;
+ gboolean connected_once;
+ pa_context *context;
+ pa_glib_mainloop *mainloop;
+ PulseConnectionState state;
};
enum {
PROP_0,
PROP_SERVER,
PROP_RECONNECT,
- PROP_CONNECTED,
+ PROP_STATE,
N_PROPERTIES
};
enum {
- LIST_ITEM_CARD,
- LIST_ITEM_SINK,
- LIST_ITEM_SOURCE,
- LIST_ITEM_SINK_INPUT,
- LIST_ITEM_SOURCE_OUTPUT,
- CARD_ADDED,
+ SERVER_INFO,
+ CARD_INFO,
CARD_REMOVED,
- CARD_CHANGED,
- SINK_ADDED,
+ SINK_INFO,
SINK_REMOVED,
- SINK_CHANGED,
- SOURCE_ADDED,
+ SOURCE_INFO,
SOURCE_REMOVED,
- SOURCE_CHANGED,
+ SINK_INPUT_INFO,
+ SINK_INPUT_REMOVED,
+ SOURCE_OUTPUT_INFO,
+ SOURCE_OUTPUT_REMOVED,
N_SIGNALS
};
+static gchar *connection_get_app_name (void);
+static gboolean connection_load_lists (PulseConnection *connection);
+
+static void connection_state_cb (pa_context *c,
+ void *userdata);
+static void connection_subscribe_cb (pa_context *c,
+ pa_subscription_event_type_t t,
+ uint32_t idx,
+ void *userdata);
+static void connection_server_info_cb (pa_context *c,
+ const pa_server_info *info,
+ void *userdata);
+static void connection_card_info_cb (pa_context *c,
+ const pa_card_info *info,
+ int eol,
+ void *userdata);
+static void connection_sink_info_cb (pa_context *c,
+ const pa_sink_info *info,
+ int eol,
+ void *userdata);
+static void connection_source_info_cb (pa_context *c,
+ const pa_source_info *info,
+ int eol,
+ void *userdata);
+static void connection_sink_input_info_cb (pa_context *c,
+ const pa_sink_input_info *info,
+ int eol,
+ void *userdata);
+static void connection_source_output_info_cb (pa_context *c,
+ const pa_source_output_info *info,
+ int eol,
+ void *userdata);
+
+static void connection_list_loaded (PulseConnection *connection);
+static gboolean connection_process_operation (PulseConnection *connection,
+ pa_operation *op);
+
+G_DEFINE_TYPE (PulseConnection, pulse_connection, G_TYPE_OBJECT);
+
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
static guint signals[N_SIGNALS] = { 0, };
-G_DEFINE_TYPE (MateMixerPulseConnection, mate_mixer_pulse_connection, G_TYPE_OBJECT);
-
-static gchar *pulse_connection_get_name (void);
-
-static gboolean pulse_connection_process_operation (MateMixerPulseConnection *connection,
- pa_operation *o);
-
-static void pulse_connection_state_cb (pa_context *c, void *userdata);
-
-static void pulse_connection_subscribe_cb (pa_context *c,
- pa_subscription_event_type_t t,
- uint32_t idx,
- void *userdata);
-
-static void pulse_connection_card_info_cb (pa_context *c,
- const pa_card_info *info,
- int eol,
- void *userdata);
-
-static void pulse_connection_sink_info_cb (pa_context *c,
- const pa_sink_info *info,
- int eol,
- void *userdata);
-
-static void pulse_connection_source_info_cb (pa_context *c,
- const pa_source_info *info,
- int eol,
- void *userdata);
-
-static void pulse_connection_sink_input_info_cb (pa_context *c,
- const pa_sink_input_info *info,
- int eol,
- void *userdata);
-
-static void pulse_connection_source_output_info_cb (pa_context *c,
- const pa_source_output_info *info,
- int eol,
- void *userdata);
-
static void
-mate_mixer_pulse_connection_init (MateMixerPulseConnection *connection)
+pulse_connection_init (PulseConnection *connection)
{
- connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (
- connection,
- MATE_MIXER_TYPE_PULSE_CONNECTION,
- MateMixerPulseConnectionPrivate);
+ connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection,
+ PULSE_TYPE_CONNECTION,
+ PulseConnectionPrivate);
}
static void
-mate_mixer_pulse_connection_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec)
+pulse_connection_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- MateMixerPulseConnection *connection;
+ PulseConnection *connection;
- connection = MATE_MIXER_PULSE_CONNECTION (object);
+ connection = PULSE_CONNECTION (object);
switch (param_id) {
case PROP_SERVER:
@@ -128,8 +129,8 @@ mate_mixer_pulse_connection_get_property (GObject *object,
case PROP_RECONNECT:
g_value_set_boolean (value, connection->priv->reconnect);
break;
- case PROP_CONNECTED:
- g_value_set_boolean (value, connection->priv->connected);
+ case PROP_STATE:
+ g_value_set_enum (value, connection->priv->state);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -138,18 +139,20 @@ mate_mixer_pulse_connection_get_property (GObject *object,
}
static void
-mate_mixer_pulse_connection_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec)
+pulse_connection_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- MateMixerPulseConnection *connection;
+ PulseConnection *connection;
- connection = MATE_MIXER_PULSE_CONNECTION (object);
+ connection = PULSE_CONNECTION (object);
switch (param_id) {
case PROP_SERVER:
- connection->priv->server = g_strdup (g_value_get_string (value));
+ g_free (connection->priv->server);
+
+ connection->priv->server = g_value_dup_string (value);
break;
case PROP_RECONNECT:
connection->priv->reconnect = g_value_get_boolean (value);
@@ -161,171 +164,249 @@ mate_mixer_pulse_connection_set_property (GObject *object,
}
static void
-mate_mixer_pulse_connection_finalize (GObject *object)
+pulse_connection_finalize (GObject *object)
{
- MateMixerPulseConnection *connection;
+ PulseConnection *connection;
- connection = MATE_MIXER_PULSE_CONNECTION (object);
+ connection = PULSE_CONNECTION (object);
g_free (connection->priv->server);
- G_OBJECT_CLASS (mate_mixer_pulse_connection_parent_class)->finalize (object);
+ G_OBJECT_CLASS (pulse_connection_parent_class)->finalize (object);
}
static void
-mate_mixer_pulse_connection_class_init (MateMixerPulseConnectionClass *klass)
+pulse_connection_class_init (PulseConnectionClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = mate_mixer_pulse_connection_finalize;
- object_class->get_property = mate_mixer_pulse_connection_get_property;
- object_class->set_property = mate_mixer_pulse_connection_set_property;
-
- properties[PROP_SERVER] = g_param_spec_string (
- "server",
- "Server",
- "PulseAudio server to connect to",
- NULL,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
- properties[PROP_RECONNECT] = g_param_spec_boolean (
- "reconnect",
- "Reconnect",
- "Try to reconnect when connection to PulseAudio server is lost",
- TRUE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
- properties[PROP_CONNECTED] = g_param_spec_boolean (
- "connected",
- "Connected",
- "Connected to a PulseAudio server or not",
- FALSE,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
- signals[LIST_ITEM_CARD] = g_signal_new (
- "list-item-card",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerPulseConnectionClass, list_item_card),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[LIST_ITEM_SINK] = g_signal_new (
- "list-item-sink",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerPulseConnectionClass, list_item_sink),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[LIST_ITEM_SINK_INPUT] = g_signal_new (
- "list-item-sink-input",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerPulseConnectionClass, list_item_sink_input),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[LIST_ITEM_SOURCE] = g_signal_new (
- "list-item-source",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerPulseConnectionClass, list_item_source),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[LIST_ITEM_SOURCE_OUTPUT] = g_signal_new (
- "list-item-source-output",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerPulseConnectionClass, list_item_source_output),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
+ object_class->finalize = pulse_connection_finalize;
+ object_class->get_property = pulse_connection_get_property;
+ object_class->set_property = pulse_connection_set_property;
+
+ properties[PROP_SERVER] = g_param_spec_string ("server",
+ "Server",
+ "PulseAudio server to connect to",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_RECONNECT] = g_param_spec_boolean ("reconnect",
+ "Reconnect",
+ "Try to reconnect when connection is lost",
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_STATE] = g_param_spec_enum ("state",
+ "State",
+ "Connection state",
+ PULSE_TYPE_CONNECTION_STATE,
+ PULSE_CONNECTION_DISCONNECTED,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ signals[SERVER_INFO] = g_signal_new ("server-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, server_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[CARD_INFO] = g_signal_new ("card-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, card_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[CARD_REMOVED] = g_signal_new ("card-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, card_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ signals[SINK_INFO] = g_signal_new ("sink-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, sink_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[SINK_REMOVED] = g_signal_new ("sink-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, sink_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ signals[SINK_INPUT_INFO] = g_signal_new ("sink-input-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, sink_input_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[SINK_INPUT_REMOVED] = g_signal_new ("sink-input-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, sink_input_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ signals[SOURCE_INFO] = g_signal_new ("source-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, source_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[SOURCE_REMOVED] = g_signal_new ("source-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, source_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ signals[SOURCE_OUTPUT_INFO] = g_signal_new ("source-output-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, source_output_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[SOURCE_OUTPUT_REMOVED] = g_signal_new ("source-output-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, source_output_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
- g_type_class_add_private (object_class, sizeof (MateMixerPulseConnectionPrivate));
+ g_type_class_add_private (object_class, sizeof (PulseConnectionPrivate));
}
-// XXX: pass more info about application, provide API
-
-MateMixerPulseConnection *
-mate_mixer_pulse_connection_new (const gchar *server, const gchar *app_name)
+PulseConnection *
+pulse_connection_new (const gchar *app_name,
+ const gchar *app_id,
+ const gchar *app_version,
+ const gchar *app_icon,
+ const gchar *server_address)
{
- pa_threaded_mainloop *mainloop;
- pa_context *context;
- MateMixerPulseConnection *connection;
+ pa_glib_mainloop *mainloop;
+ pa_context *context;
+ pa_proplist *proplist;
+ PulseConnection *connection;
- mainloop = pa_threaded_mainloop_new ();
+ mainloop = pa_glib_mainloop_new (g_main_context_get_thread_default ());
if (G_UNLIKELY (mainloop == NULL)) {
g_warning ("Failed to create PulseAudio main loop");
return NULL;
}
+ proplist = pa_proplist_new ();
+ if (app_name)
+ pa_proplist_sets (proplist, PA_PROP_APPLICATION_NAME, app_name);
+ if (app_id)
+ pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, app_id);
+ if (app_icon)
+ pa_proplist_sets (proplist, PA_PROP_APPLICATION_ICON_NAME, app_icon);
+ if (app_version)
+ pa_proplist_sets (proplist, PA_PROP_APPLICATION_VERSION, app_version);
+
if (app_name != NULL) {
- context = pa_context_new (
- pa_threaded_mainloop_get_api (mainloop),
- app_name);
+ context = pa_context_new_with_proplist (pa_glib_mainloop_get_api (mainloop),
+ app_name,
+ proplist);
} else {
- gchar *name = pulse_connection_get_name ();
+ gchar *name = connection_get_app_name ();
- context = pa_context_new (
- pa_threaded_mainloop_get_api (mainloop),
- name);
+ context = pa_context_new_with_proplist (pa_glib_mainloop_get_api (mainloop),
+ name,
+ proplist);
g_free (name);
}
+ pa_proplist_free (proplist);
if (G_UNLIKELY (context == NULL)) {
g_warning ("Failed to create PulseAudio context");
-
- pa_threaded_mainloop_free (mainloop);
+ pa_glib_mainloop_free (mainloop);
return NULL;
}
- connection = g_object_new (MATE_MIXER_TYPE_PULSE_CONNECTION,
- "server", server,
- "reconnect", TRUE,
- NULL);
+ connection = g_object_new (PULSE_TYPE_CONNECTION,
+ "server", server_address,
+ "reconnect", TRUE,
+ NULL);
connection->priv->mainloop = mainloop;
- connection->priv->context = context;
-
+ connection->priv->context = context;
return connection;
}
gboolean
-mate_mixer_pulse_connection_connect (MateMixerPulseConnection *connection)
+pulse_connection_connect (PulseConnection *connection)
{
int ret;
- pa_operation *o;
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- if (connection->priv->connected)
+ if (connection->priv->state != PULSE_CONNECTION_DISCONNECTED)
return TRUE;
+ /* Set function to monitor status changes */
+ pa_context_set_state_callback (connection->priv->context,
+ connection_state_cb,
+ connection);
+
/* Initiate a connection, this call does not guarantee the connection
* to be established and usable */
ret = pa_context_connect (connection->priv->context, NULL, PA_CONTEXT_NOFLAGS, NULL);
@@ -333,272 +414,323 @@ mate_mixer_pulse_connection_connect (MateMixerPulseConnection *connection)
g_warning ("Failed to connect to PulseAudio server: %s", pa_strerror (ret));
return FALSE;
}
+ return TRUE;
+}
- pa_threaded_mainloop_lock (connection->priv->mainloop);
-
- /* Set callback for connection status changes; the callback is not really
- * used when connecting the first time, it is only needed to signal
- * a status change */
- pa_context_set_state_callback (connection->priv->context,
- pulse_connection_state_cb,
- connection);
+void
+pulse_connection_disconnect (PulseConnection *connection)
+{
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- ret = pa_threaded_mainloop_start (connection->priv->mainloop);
- if (ret < 0) {
- g_warning ("Failed to start PulseAudio main loop: %s", pa_strerror (ret));
+ if (connection->priv->state == PULSE_CONNECTION_DISCONNECTED)
+ return;
- pa_context_disconnect (connection->priv->context);
- pa_threaded_mainloop_unlock (connection->priv->mainloop);
- return FALSE;
- }
+ pa_context_disconnect (connection->priv->context);
- while (TRUE) {
- /* Wait for a connection state which tells us whether the connection
- * has been established or has failed */
- pa_context_state_t state =
- pa_context_get_state (connection->priv->context);
+ connection->priv->state = PULSE_CONNECTION_DISCONNECTED;
- if (state == PA_CONTEXT_READY)
- break;
+ g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
+}
- if (state == PA_CONTEXT_FAILED ||
- state == PA_CONTEXT_TERMINATED) {
- g_warning ("Failed to connect to PulseAudio server: %s",
- pa_strerror (pa_context_errno (connection->priv->context)));
+PulseConnectionState
+pulse_connection_get_state (PulseConnection *connection)
+{
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- pa_context_disconnect (connection->priv->context);
- pa_threaded_mainloop_unlock (connection->priv->mainloop);
- return FALSE;
- }
- pa_threaded_mainloop_wait (connection->priv->mainloop);
- }
+ return connection->priv->state;
+}
- pa_context_set_subscribe_callback (connection->priv->context,
- pulse_connection_subscribe_cb,
- connection);
-
- // XXX don't want notifications before the initial lists are downloaded
-
- o = pa_context_subscribe (connection->priv->context,
- PA_SUBSCRIPTION_MASK_CARD |
- PA_SUBSCRIPTION_MASK_SINK |
- PA_SUBSCRIPTION_MASK_SOURCE |
- PA_SUBSCRIPTION_MASK_SINK_INPUT |
- PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT,
- NULL, NULL);
- if (o == NULL)
- g_warning ("Failed to subscribe to PulseAudio notifications: %s",
- pa_strerror (pa_context_errno (connection->priv->context)));
- else
- pa_operation_unref (o);
+gboolean
+pulse_connection_set_default_sink (PulseConnection *connection,
+ const gchar *name)
+{
+ pa_operation *op;
- pa_threaded_mainloop_unlock (connection->priv->mainloop);
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- connection->priv->connected = TRUE;
+ op = pa_context_set_default_sink (connection->priv->context,
+ name,
+ NULL, NULL);
- g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_CONNECTED]);
- return TRUE;
+ return connection_process_operation (connection, op);
}
-void
-mate_mixer_pulse_connection_disconnect (MateMixerPulseConnection *connection)
+gboolean
+pulse_connection_set_default_source (PulseConnection *connection,
+ const gchar *name)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_CONNECTION (connection), FALSE);
+ pa_operation *op;
- if (!connection->priv->connected)
- return;
-
- pa_context_disconnect (connection->priv->context);
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- connection->priv->connected = FALSE;
+ op = pa_context_set_default_source (connection->priv->context,
+ name,
+ NULL, NULL);
- g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_CONNECTED]);
+ return connection_process_operation (connection, op);
}
gboolean
-mate_mixer_pulse_connection_get_server_info (MateMixerPulseConnection *connection)
+pulse_connection_set_card_profile (PulseConnection *connection,
+ const gchar *card,
+ const gchar *profile)
{
- // TODO
- return TRUE;
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ op = pa_context_set_card_profile_by_name (connection->priv->context,
+ card,
+ profile,
+ NULL, NULL);
+
+ return connection_process_operation (connection, op);
}
gboolean
-mate_mixer_pulse_connection_get_card_list (MateMixerPulseConnection *connection)
+pulse_connection_set_sink_mute (PulseConnection *connection,
+ guint32 index,
+ gboolean mute)
{
- pa_operation *o;
- gboolean ret;
-
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_CONNECTION (connection), FALSE);
+ pa_operation *op;
- pa_threaded_mainloop_lock (connection->priv->mainloop);
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- o = pa_context_get_card_info_list (
- connection->priv->context,
- pulse_connection_card_info_cb,
- connection);
+ op = pa_context_set_sink_mute_by_index (connection->priv->context,
+ index,
+ (int) mute,
+ NULL, NULL);
- ret = pulse_connection_process_operation (connection, o);
-
- pa_threaded_mainloop_unlock (connection->priv->mainloop);
- return ret;
+ return connection_process_operation (connection, op);
}
gboolean
-mate_mixer_pulse_connection_get_sink_list (MateMixerPulseConnection *connection)
+pulse_connection_set_sink_volume (PulseConnection *connection,
+ guint32 index,
+ const pa_cvolume *volume)
{
- pa_operation *o;
- gboolean ret;
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_CONNECTION (connection), FALSE);
+ op = pa_context_set_sink_volume_by_index (connection->priv->context,
+ index,
+ volume,
+ NULL, NULL);
- pa_threaded_mainloop_lock (connection->priv->mainloop);
+ return connection_process_operation (connection, op);
+}
- o = pa_context_get_sink_info_list (
- connection->priv->context,
- pulse_connection_sink_info_cb,
- connection);
+gboolean
+pulse_connection_set_sink_port (PulseConnection *connection,
+ guint32 index,
+ const gchar *port)
+{
+ pa_operation *op;
- ret = pulse_connection_process_operation (connection, o);
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- pa_threaded_mainloop_unlock (connection->priv->mainloop);
- return ret;
+ op = pa_context_set_sink_port_by_index (connection->priv->context,
+ index,
+ port,
+ NULL, NULL);
+
+ return connection_process_operation (connection, op);
}
gboolean
-mate_mixer_pulse_connection_get_sink_input_list (MateMixerPulseConnection *connection)
+pulse_connection_set_sink_input_mute (PulseConnection *connection,
+ guint32 index,
+ gboolean mute)
{
- pa_operation *o;
- gboolean ret;
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_CONNECTION (connection), FALSE);
+ op = pa_context_set_sink_input_mute (connection->priv->context,
+ index,
+ (int) mute,
+ NULL, NULL);
+
+ return connection_process_operation (connection, op);
+}
- pa_threaded_mainloop_lock (connection->priv->mainloop);
+gboolean
+pulse_connection_set_sink_input_volume (PulseConnection *connection,
+ guint32 index,
+ const pa_cvolume *volume)
+{
+ pa_operation *op;
- o = pa_context_get_sink_input_info_list (
- connection->priv->context,
- pulse_connection_sink_input_info_cb,
- connection);
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- ret = pulse_connection_process_operation (connection, o);
+ op = pa_context_set_sink_input_volume (connection->priv->context,
+ index,
+ volume,
+ NULL, NULL);
- pa_threaded_mainloop_unlock (connection->priv->mainloop);
- return ret;
+ return connection_process_operation (connection, op);
}
gboolean
-mate_mixer_pulse_connection_get_source_list (MateMixerPulseConnection *connection)
+pulse_connection_set_source_mute (PulseConnection *connection,
+ guint32 index,
+ gboolean mute)
{
- pa_operation *o;
- gboolean ret;
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_CONNECTION (connection), FALSE);
+ op = pa_context_set_source_mute_by_index (connection->priv->context,
+ index,
+ (int) mute,
+ NULL, NULL);
+
+ return connection_process_operation (connection, op);
+}
- pa_threaded_mainloop_lock (connection->priv->mainloop);
+gboolean
+pulse_connection_set_source_volume (PulseConnection *connection,
+ guint32 index,
+ const pa_cvolume *volume)
+{
+ pa_operation *op;
- o = pa_context_get_source_info_list (
- connection->priv->context,
- pulse_connection_source_info_cb,
- connection);
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- ret = pulse_connection_process_operation (connection, o);
+ op = pa_context_set_source_volume_by_index (connection->priv->context,
+ index,
+ volume,
+ NULL, NULL);
- pa_threaded_mainloop_unlock (connection->priv->mainloop);
- return ret;
+ return connection_process_operation (connection, op);
}
gboolean
-mate_mixer_pulse_connection_get_source_output_list (MateMixerPulseConnection *connection)
+pulse_connection_set_source_port (PulseConnection *connection,
+ guint32 index,
+ const gchar *port)
{
- pa_operation *o;
- gboolean ret;
+ pa_operation *op;
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- pa_threaded_mainloop_lock (connection->priv->mainloop);
+ op = pa_context_set_source_port_by_index (connection->priv->context,
+ index,
+ port,
+ NULL, NULL);
- o = pa_context_get_source_output_info_list (
- connection->priv->context,
- pulse_connection_source_output_info_cb,
- connection);
+ return connection_process_operation (connection, op);
+}
- ret = pulse_connection_process_operation (connection, o);
+gboolean
+pulse_connection_set_source_output_mute (PulseConnection *connection,
+ guint32 index,
+ gboolean mute)
+{
+#if PA_CHECK_VERSION(1, 0, 0)
+ pa_operation *op;
- pa_threaded_mainloop_unlock (connection->priv->mainloop);
- return ret;
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ op = pa_context_set_source_output_mute (connection->priv->context,
+ index,
+ (int) mute,
+ NULL, NULL);
+
+ return connection_process_operation (connection, op);
+#else
+ return FALSE;
+#endif
}
gboolean
-mate_mixer_pulse_connection_set_card_profile (MateMixerPulseConnection *connection,
- const gchar *card,
- const gchar *profile)
+pulse_connection_set_source_output_volume (PulseConnection *connection,
+ guint32 index,
+ const pa_cvolume *volume)
{
- pa_operation *o;
- gboolean ret;
+#if PA_CHECK_VERSION(1, 0, 0)
+ pa_operation *op;
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- pa_threaded_mainloop_lock (connection->priv->mainloop);
+ op = pa_context_set_source_output_volume (connection->priv->context,
+ index,
+ volume,
+ NULL, NULL);
- o = pa_context_set_card_profile_by_name (
- connection->priv->context,
- card,
- profile,
- NULL, NULL);
+ return connection_process_operation (connection, op);
+#else
+ return FALSE;
+#endif
+}
- // XXX maybe shouldn't wait for the completion
+gboolean
+pulse_connection_move_sink_input (PulseConnection *connection,
+ guint32 index,
+ guint32 sink_index)
+{
+ pa_operation *op;
- ret = pulse_connection_process_operation (connection, o);
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- pa_threaded_mainloop_unlock (connection->priv->mainloop);
- return ret;
+ op = pa_context_move_sink_input_by_index (connection->priv->context,
+ index,
+ sink_index,
+ NULL, NULL);
+
+ return connection_process_operation (connection, op);
}
gboolean
-mate_mixer_pulse_connection_set_sink_mute (MateMixerPulseConnection *connection,
- guint32 index,
- gboolean mute)
+pulse_connection_move_source_output (PulseConnection *connection,
+ guint32 index,
+ guint32 source_index)
{
- pa_operation *o;
- gboolean ret;
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_CONNECTION (connection), FALSE);
+ op = pa_context_move_source_output_by_index (connection->priv->context,
+ index,
+ source_index,
+ NULL, NULL);
- pa_threaded_mainloop_lock (connection->priv->mainloop);
+ return connection_process_operation (connection, op);
+}
- o = pa_context_set_sink_mute_by_index (
- connection->priv->context,
- index,
- (int) mute,
- NULL, NULL);
+gboolean
+pulse_connection_kill_sink_input (PulseConnection *connection,
+ guint32 index)
+{
+ pa_operation *op;
- // XXX maybe shouldn't wait for the completion
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- ret = pulse_connection_process_operation (connection, o);
+ op = pa_context_kill_sink_input (connection->priv->context,
+ index,
+ NULL, NULL);
- pa_threaded_mainloop_unlock (connection->priv->mainloop);
- return ret;
+ return connection_process_operation (connection, op);
}
-static gboolean
-pulse_connection_process_operation (MateMixerPulseConnection *connection,
- pa_operation *o)
+gboolean
+pulse_connection_kill_source_output (PulseConnection *connection,
+ guint32 index)
{
- if (o == NULL) {
- g_warning ("Failed to process PulseAudio operation: %s",
- pa_strerror (pa_context_errno (connection->priv->context)));
+ pa_operation *op;
- return FALSE;
- }
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
- while (pa_operation_get_state (o) == PA_OPERATION_RUNNING)
- pa_threaded_mainloop_wait (connection->priv->mainloop);
+ op = pa_context_kill_source_output (connection->priv->context,
+ index,
+ NULL, NULL);
- pa_operation_unref (o);
- return TRUE;
+ return connection_process_operation (connection, op);
}
static gchar *
-pulse_connection_get_name (void)
+connection_get_app_name (void)
{
const char *name_app;
char name_buf[256];
@@ -614,151 +746,368 @@ pulse_connection_get_name (void)
return g_strdup_printf ("libmatemixer-%lu", (gulong) getpid ());
}
+static gboolean
+connection_load_lists (PulseConnection *connection)
+{
+ GList *ops = NULL;
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ if (G_UNLIKELY (connection->priv->outstanding)) {
+ /* This can only mean a bug */
+ g_warn_if_reached ();
+ return FALSE;
+ }
+
+ op = pa_context_get_server_info (connection->priv->context,
+ connection_server_info_cb,
+ connection);
+ if (G_UNLIKELY (op == NULL))
+ goto error;
+
+ ops = g_list_prepend (ops, op);
+
+ op = pa_context_get_card_info_list (connection->priv->context,
+ connection_card_info_cb,
+ connection);
+ if (G_UNLIKELY (op == NULL))
+ goto error;
+
+ ops = g_list_prepend (ops, op);
+
+ op = pa_context_get_sink_info_list (connection->priv->context,
+ connection_sink_info_cb,
+ connection);
+ if (G_UNLIKELY (op == NULL))
+ goto error;
+
+ ops = g_list_prepend (ops, op);
+
+ op = pa_context_get_sink_input_info_list (connection->priv->context,
+ connection_sink_input_info_cb,
+ connection);
+ if (G_UNLIKELY (op == NULL))
+ goto error;
+
+ ops = g_list_prepend (ops, op);
+
+ op = pa_context_get_source_info_list (connection->priv->context,
+ connection_source_info_cb,
+ connection);
+ if (G_UNLIKELY (op == NULL))
+ goto error;
+
+ ops = g_list_prepend (ops, op);
+
+ op = pa_context_get_source_output_info_list (connection->priv->context,
+ connection_source_output_info_cb,
+ connection);
+ if (G_UNLIKELY (op == NULL))
+ goto error;
+
+ ops = g_list_prepend (ops, op);
+
+ g_list_foreach (ops, (GFunc) pa_operation_unref, NULL);
+ g_list_free (ops);
+
+ connection->priv->outstanding = 5;
+ return TRUE;
+
+error:
+ g_list_foreach (ops, (GFunc) pa_operation_cancel, NULL);
+ g_list_foreach (ops, (GFunc) pa_operation_unref, NULL);
+ g_list_free (ops);
+ return FALSE;
+}
+
static void
-pulse_connection_state_cb (pa_context *c, void *userdata)
+connection_state_cb (pa_context *c, void *userdata)
{
- MateMixerPulseConnection *connection;
- pa_context_state_t state;
+ PulseConnection *connection;
+ pa_context_state_t state;
- connection = MATE_MIXER_PULSE_CONNECTION (userdata);
+ connection = PULSE_CONNECTION (userdata);
state = pa_context_get_state (c);
- switch (state) {
- case PA_CONTEXT_READY:
- /* The connection is established, the context is ready to
- * execute operations. */
- if (!connection->priv->connected) {
- connection->priv->connected = TRUE;
-
- g_object_notify_by_pspec (
- G_OBJECT (connection),
- properties[PROP_CONNECTED]);
+
+ if (state == PA_CONTEXT_READY) {
+ pa_operation *op;
+
+ // XXX check state
+
+ op = pa_context_subscribe (connection->priv->context,
+ PA_SUBSCRIPTION_MASK_CARD |
+ PA_SUBSCRIPTION_MASK_SINK |
+ PA_SUBSCRIPTION_MASK_SOURCE |
+ PA_SUBSCRIPTION_MASK_SINK_INPUT |
+ PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT,
+ NULL, NULL);
+ if (op) {
+ connection->priv->state = PULSE_CONNECTION_LOADING;
+ connection->priv->connected_once = TRUE;
+
+ pa_context_set_subscribe_callback (connection->priv->context,
+ connection_subscribe_cb,
+ connection);
+ pa_operation_unref (op);
+
+ connection_load_lists (connection);
+
+ g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
+ } else {
+ /* If we could not subscribe to notifications, we consider it the
+ * same as a connection failture */
+ g_warning ("Failed to subscribe to PulseAudio notifications: %s",
+ pa_strerror (pa_context_errno (connection->priv->context)));
+
+ state = PA_CONTEXT_FAILED;
}
- break;
+ }
- case PA_CONTEXT_TERMINATED:
- /* The connection was terminated cleanly. */
- if (connection->priv->connected) {
- connection->priv->connected = FALSE;
+ if (state == PA_CONTEXT_TERMINATED || state == PA_CONTEXT_FAILED) {
+ /* We also handle the case of clean connection termination as it is a state
+ * change which should not normally happen, because the signal subscription
+ * is cancelled before disconnecting */
+ pulse_connection_disconnect (connection);
- g_object_notify_by_pspec (
- G_OBJECT (connection),
- properties[PROP_CONNECTED]);
+ if (connection->priv->connected_once && connection->priv->reconnect)
+ pulse_connection_connect (connection);
+ }
+}
- pa_context_disconnect (connection->priv->context);
+static void
+connection_subscribe_cb (pa_context *c,
+ pa_subscription_event_type_t t,
+ uint32_t idx,
+ void *userdata)
+{
+ PulseConnection *connection;
+ pa_operation *op;
+
+ connection = PULSE_CONNECTION (userdata);
+
+ switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
+ case PA_SUBSCRIPTION_EVENT_CARD:
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ g_signal_emit (G_OBJECT (connection),
+ signals[CARD_REMOVED],
+ 0,
+ idx);
+ } else {
+ op = pa_context_get_card_info_by_index (connection->priv->context,
+ idx,
+ connection_card_info_cb,
+ connection);
+ connection_process_operation (connection, op);
}
break;
- case PA_CONTEXT_FAILED:
+ case PA_SUBSCRIPTION_EVENT_SINK:
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ g_signal_emit (G_OBJECT (connection),
+ signals[SINK_REMOVED],
+ 0,
+ idx);
+ } else {
+ op = pa_context_get_sink_info_by_index (connection->priv->context,
+ idx,
+ connection_sink_info_cb,
+ connection);
+ connection_process_operation (connection, op);
+ }
break;
- default:
+ case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ g_signal_emit (G_OBJECT (connection),
+ signals[SINK_INPUT_REMOVED],
+ 0,
+ idx);
+ } else {
+ op = pa_context_get_sink_input_info (connection->priv->context,
+ idx,
+ connection_sink_input_info_cb,
+ connection);
+ connection_process_operation (connection, op);
+ }
+ break;
+
+ case PA_SUBSCRIPTION_EVENT_SOURCE:
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ g_signal_emit (G_OBJECT (connection),
+ signals[SOURCE_REMOVED],
+ 0,
+ idx);
+ } else {
+ op = pa_context_get_source_info_by_index (connection->priv->context,
+ idx,
+ connection_source_info_cb,
+ connection);
+ connection_process_operation (connection, op);
+ }
break;
- }
- pa_threaded_mainloop_signal (connection->priv->mainloop, 0);
+ case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ g_signal_emit (G_OBJECT (connection),
+ signals[SOURCE_OUTPUT_REMOVED],
+ 0,
+ idx);
+ } else {
+ op = pa_context_get_source_output_info (connection->priv->context,
+ idx,
+ connection_source_output_info_cb,
+ connection);
+ connection_process_operation (connection, op);
+ }
+ break;
+ }
}
static void
-pulse_connection_subscribe_cb (pa_context *c,
- pa_subscription_event_type_t t,
- uint32_t idx,
- void *userdata)
+connection_server_info_cb (pa_context *c,
+ const pa_server_info *info,
+ void *userdata)
{
- // TODO
+ g_signal_emit (G_OBJECT (userdata),
+ signals[SERVER_INFO],
+ 0,
+ info);
}
static void
-pulse_connection_card_info_cb (pa_context *c,
- const pa_card_info *info,
- int eol,
- void *userdata)
+connection_card_info_cb (pa_context *c,
+ const pa_card_info *info,
+ int eol,
+ void *userdata)
{
- MateMixerPulseConnection *connection;
+ PulseConnection *connection;
- connection = MATE_MIXER_PULSE_CONNECTION (userdata);
+ connection = PULSE_CONNECTION (userdata);
- if (!eol)
- g_signal_emit (G_OBJECT (connection),
- signals[LIST_ITEM_CARD],
- 0,
- info);
+ if (eol) {
+ if (connection->priv->state == PULSE_CONNECTION_LOADING)
+ connection_list_loaded (connection);
+ return;
+ }
- pa_threaded_mainloop_signal (connection->priv->mainloop, 0);
+ g_signal_emit (G_OBJECT (connection),
+ signals[CARD_INFO],
+ 0,
+ info);
}
static void
-pulse_connection_sink_info_cb (pa_context *c,
- const pa_sink_info *info,
- int eol,
- void *userdata)
+connection_sink_info_cb (pa_context *c,
+ const pa_sink_info *info,
+ int eol,
+ void *userdata)
{
- MateMixerPulseConnection *connection;
+ PulseConnection *connection;
- connection = MATE_MIXER_PULSE_CONNECTION (userdata);
+ connection = PULSE_CONNECTION (userdata);
- if (!eol)
+ if (eol)
+ connection_list_loaded (connection);
+ else
g_signal_emit (G_OBJECT (connection),
- signals[LIST_ITEM_SINK],
- 0,
- info);
+ signals[SINK_INFO],
+ 0,
+ info);
+}
+
+static void
+connection_sink_input_info_cb (pa_context *c,
+ const pa_sink_input_info *info,
+ int eol,
+ void *userdata)
+{
+ PulseConnection *connection;
+
+ connection = PULSE_CONNECTION (userdata);
- pa_threaded_mainloop_signal (connection->priv->mainloop, 0);
+ if (eol) {
+ if (connection->priv->state == PULSE_CONNECTION_LOADING)
+ connection_list_loaded (connection);
+ return;
+ }
+
+ g_signal_emit (G_OBJECT (connection),
+ signals[SINK_INPUT_INFO],
+ 0,
+ info);
}
static void
-pulse_connection_sink_input_info_cb (pa_context *c,
- const pa_sink_input_info *info,
- int eol,
- void *userdata)
+connection_source_info_cb (pa_context *c,
+ const pa_source_info *info,
+ int eol,
+ void *userdata)
{
- MateMixerPulseConnection *connection;
+ PulseConnection *connection;
- connection = MATE_MIXER_PULSE_CONNECTION (userdata);
+ connection = PULSE_CONNECTION (userdata);
- if (!eol)
- g_signal_emit (G_OBJECT (connection),
- signals[LIST_ITEM_SINK_INPUT],
- 0,
- info);
+ if (eol) {
+ if (connection->priv->state == PULSE_CONNECTION_LOADING)
+ connection_list_loaded (connection);
+ return;
+ }
- pa_threaded_mainloop_signal (connection->priv->mainloop, 0);
+ g_signal_emit (G_OBJECT (connection),
+ signals[SOURCE_INFO],
+ 0,
+ info);
}
static void
-pulse_connection_source_info_cb (pa_context *c,
- const pa_source_info *info,
- int eol,
- void *userdata)
+connection_source_output_info_cb (pa_context *c,
+ const pa_source_output_info *info,
+ int eol,
+ void *userdata)
{
- MateMixerPulseConnection *connection;
+ PulseConnection *connection;
- connection = MATE_MIXER_PULSE_CONNECTION (userdata);
+ connection = PULSE_CONNECTION (userdata);
- if (!eol)
- g_signal_emit (G_OBJECT (connection),
- signals[LIST_ITEM_SOURCE],
- 0,
- info);
+ if (eol) {
+ if (connection->priv->state == PULSE_CONNECTION_LOADING)
+ connection_list_loaded (connection);
+ return;
+ }
- pa_threaded_mainloop_signal (connection->priv->mainloop, 0);
+ g_signal_emit (G_OBJECT (connection),
+ signals[SOURCE_OUTPUT_INFO],
+ 0,
+ info);
}
static void
-pulse_connection_source_output_info_cb (pa_context *c,
- const pa_source_output_info *info,
- int eol,
- void *userdata)
+connection_list_loaded (PulseConnection *connection)
{
- MateMixerPulseConnection *connection;
+ connection->priv->outstanding--;
- connection = MATE_MIXER_PULSE_CONNECTION (userdata);
+ if (G_UNLIKELY (connection->priv->outstanding < 0)) {
+ g_warn_if_reached ();
+ connection->priv->outstanding = 0;
+ }
+ if (connection->priv->outstanding == 0) {
+ connection->priv->state = PULSE_CONNECTION_CONNECTED;
- if (!eol)
- g_signal_emit (G_OBJECT (connection),
- signals[LIST_ITEM_SOURCE_OUTPUT],
- 0,
- info);
+ g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
+ }
+}
- pa_threaded_mainloop_signal (connection->priv->mainloop, 0);
+static gboolean
+connection_process_operation (PulseConnection *connection, pa_operation *op)
+{
+ if (G_UNLIKELY (op == NULL)) {
+ g_warning ("PulseAudio operation failed: %s",
+ pa_strerror (pa_context_errno (connection->priv->context)));
+ return FALSE;
+ }
+
+ pa_operation_unref (op);
+ return TRUE;
}
diff --git a/backends/pulse/pulse-connection.h b/backends/pulse/pulse-connection.h
index 85fd0b7..922b65a 100644
--- a/backends/pulse/pulse-connection.h
+++ b/backends/pulse/pulse-connection.h
@@ -15,88 +15,144 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef MATEMIXER_PULSE_CONNECTION_H
-#define MATEMIXER_PULSE_CONNECTION_H
+#ifndef PULSE_CONNECTION_H
+#define PULSE_CONNECTION_H
#include <glib.h>
#include <glib-object.h>
#include <pulse/pulseaudio.h>
+#include "pulse-enums.h"
+
G_BEGIN_DECLS
-#define MATE_MIXER_TYPE_PULSE_CONNECTION \
- (mate_mixer_pulse_connection_get_type ())
-#define MATE_MIXER_PULSE_CONNECTION(o) \
- (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_PULSE_CONNECTION, MateMixerPulseConnection))
-#define MATE_MIXER_IS_PULSE_CONNECTION(o) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_PULSE_CONNECTION))
-#define MATE_MIXER_PULSE_CONNECTION_CLASS(k) \
- (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_PULSE_CONNECTION, MateMixerPulseConnectionClass))
-#define MATE_MIXER_IS_PULSE_CONNECTION_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_PULSE_CONNECTION))
-#define MATE_MIXER_PULSE_CONNECTION_GET_CLASS(o) \
- (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_PULSE_CONNECTION, MateMixerPulseConnectionClass))
-
-typedef struct _MateMixerPulseConnection MateMixerPulseConnection;
-typedef struct _MateMixerPulseConnectionClass MateMixerPulseConnectionClass;
-typedef struct _MateMixerPulseConnectionPrivate MateMixerPulseConnectionPrivate;
-
-struct _MateMixerPulseConnection
+#define PULSE_TYPE_CONNECTION \
+ (pulse_connection_get_type ())
+#define PULSE_CONNECTION(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_CONNECTION, PulseConnection))
+#define PULSE_IS_CONNECTION(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_CONNECTION))
+#define PULSE_CONNECTION_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_CONNECTION, PulseConnectionClass))
+#define PULSE_IS_CONNECTION_CLASS(k) \
+ (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_CONNECTION))
+#define PULSE_CONNECTION_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_CONNECTION, PulseConnectionClass))
+
+typedef struct _PulseConnection PulseConnection;
+typedef struct _PulseConnectionClass PulseConnectionClass;
+typedef struct _PulseConnectionPrivate PulseConnectionPrivate;
+
+struct _PulseConnection
{
GObject parent;
- MateMixerPulseConnectionPrivate *priv;
+ PulseConnectionPrivate *priv;
};
-struct _MateMixerPulseConnectionClass
+struct _PulseConnectionClass
{
GObjectClass parent;
- void (*disconnected) (MateMixerPulseConnection *connection);
- void (*reconnected) (MateMixerPulseConnection *connection);
-
- void (*list_item_card) (MateMixerPulseConnection *connection,
- const pa_card_info *info);
- void (*list_item_sink) (MateMixerPulseConnection *connection,
- const pa_sink_info *info);
- void (*list_item_sink_input) (MateMixerPulseConnection *connection,
- const pa_sink_input_info *info);
- void (*list_item_source) (MateMixerPulseConnection *connection,
- const pa_source_info *info);
- void (*list_item_source_output) (MateMixerPulseConnection *connection,
- const pa_source_output_info *info);
+ void (*server_info) (PulseConnection *connection,
+ const pa_server_info *info);
+ void (*card_info) (PulseConnection *connection,
+ const pa_card_info *info);
+ void (*card_removed) (PulseConnection *connection,
+ guint32 index);
+ void (*sink_info) (PulseConnection *connection,
+ const pa_sink_info *info);
+ void (*sink_removed) (PulseConnection *connection,
+ guint32 index);
+ void (*sink_input_info) (PulseConnection *connection,
+ const pa_sink_input_info *info);
+ void (*sink_input_removed) (PulseConnection *connection,
+ guint32 index);
+ void (*source_info) (PulseConnection *connection,
+ const pa_source_info *info);
+ void (*source_removed) (PulseConnection *connection,
+ guint32 index);
+ void (*source_output_info) (PulseConnection *connection,
+ const pa_source_output_info *info);
+ void (*source_output_removed) (PulseConnection *connection,
+ guint32 index);
};
-GType mate_mixer_pulse_connection_get_type (void) G_GNUC_CONST;
+GType pulse_connection_get_type (void) G_GNUC_CONST;
+
+PulseConnection *pulse_connection_new (const gchar *app_name,
+ const gchar *app_id,
+ const gchar *app_version,
+ const gchar *app_icon,
+ const gchar *server_address);
+
+gboolean pulse_connection_connect (PulseConnection *connection);
+void pulse_connection_disconnect (PulseConnection *connection);
+
+PulseConnectionState pulse_connection_get_state (PulseConnection *connection);
+
+gboolean pulse_connection_set_default_sink (PulseConnection *connection,
+ const gchar *name);
+
+gboolean pulse_connection_set_default_source (PulseConnection *connection,
+ const gchar *name);
+
+gboolean pulse_connection_set_card_profile (PulseConnection *connection,
+ const gchar *device,
+ const gchar *profile);
-MateMixerPulseConnection *mate_mixer_pulse_connection_new (const gchar *server,
- const gchar *app_name);
+gboolean pulse_connection_set_sink_mute (PulseConnection *connection,
+ guint32 index,
+ gboolean mute);
+gboolean pulse_connection_set_sink_volume (PulseConnection *connection,
+ guint32 index,
+ const pa_cvolume *volume);
+gboolean pulse_connection_set_sink_port (PulseConnection *connection,
+ guint32 index,
+ const gchar *port);
-gboolean mate_mixer_pulse_connection_connect (MateMixerPulseConnection *connection);
+gboolean pulse_connection_set_sink_input_mute (PulseConnection *connection,
+ guint32 index,
+ gboolean mute);
-void mate_mixer_pulse_connection_disconnect (MateMixerPulseConnection *connection);
+gboolean pulse_connection_set_sink_input_volume (PulseConnection *connection,
+ guint32 index,
+ const pa_cvolume *volume);
-gboolean mate_mixer_pulse_connection_get_server_info (MateMixerPulseConnection *connection);
-gboolean mate_mixer_pulse_connection_get_card_list (MateMixerPulseConnection *connection);
+gboolean pulse_connection_set_source_mute (PulseConnection *connection,
+ guint32 index,
+ gboolean mute);
+gboolean pulse_connection_set_source_volume (PulseConnection *connection,
+ guint32 index,
+ const pa_cvolume *volume);
+gboolean pulse_connection_set_source_port (PulseConnection *connection,
+ guint32 index,
+ const gchar *port);
-gboolean mate_mixer_pulse_connection_get_sink_list (MateMixerPulseConnection *connection);
+gboolean pulse_connection_set_source_output_mute (PulseConnection *connection,
+ guint32 index,
+ gboolean mute);
-gboolean mate_mixer_pulse_connection_get_sink_input_list (MateMixerPulseConnection *connection);
+gboolean pulse_connection_set_source_output_volume (PulseConnection *connection,
+ guint32 index,
+ const pa_cvolume *volume);
-gboolean mate_mixer_pulse_connection_get_source_list (MateMixerPulseConnection *connection);
+gboolean pulse_connection_move_sink_input (PulseConnection *connection,
+ guint32 index,
+ guint32 sink_index);
-gboolean mate_mixer_pulse_connection_get_source_output_list (MateMixerPulseConnection *connection);
+gboolean pulse_connection_move_source_output (PulseConnection *connection,
+ guint32 index,
+ guint32 source_index);
-gboolean mate_mixer_pulse_connection_set_card_profile (MateMixerPulseConnection *connection,
- const gchar *device,
- const gchar *profile);
+gboolean pulse_connection_kill_sink_input (PulseConnection *connection,
+ guint32 index);
-gboolean mate_mixer_pulse_connection_set_sink_mute (MateMixerPulseConnection *connection,
- guint32 index,
- gboolean mute);
+gboolean pulse_connection_kill_source_output (PulseConnection *connection,
+ guint32 index);
G_END_DECLS
-#endif /* MATEMIXER_PULSE_CONNECTION_H */
+#endif /* PULSE_CONNECTION_H */
diff --git a/backends/pulse/pulse-device.c b/backends/pulse/pulse-device.c
index a411d7f..ad17f21 100644
--- a/backends/pulse/pulse-device.c
+++ b/backends/pulse/pulse-device.c
@@ -27,16 +27,16 @@
#include "pulse-connection.h"
#include "pulse-device.h"
-struct _MateMixerPulseDevicePrivate
+struct _PulseDevicePrivate
{
- guint32 index;
- gchar *name;
- gchar *description;
- GList *profiles;
- GList *ports;
- gchar *icon;
- MateMixerProfile *profile;
- MateMixerPulseConnection *connection;
+ guint32 index;
+ gchar *name;
+ gchar *description;
+ GList *profiles;
+ GList *ports;
+ gchar *icon;
+ PulseConnection *connection;
+ MateMixerProfile *profile;
};
enum
@@ -51,40 +51,53 @@ enum
static void mate_mixer_device_interface_init (MateMixerDeviceInterface *iface);
-G_DEFINE_TYPE_WITH_CODE (MateMixerPulseDevice, mate_mixer_pulse_device, G_TYPE_OBJECT,
+static const gchar * device_get_name (MateMixerDevice *device);
+static const gchar * device_get_description (MateMixerDevice *device);
+static const gchar * device_get_icon (MateMixerDevice *device);
+
+static const GList * device_list_streams (MateMixerDevice *device);
+
+static const GList * device_list_ports (MateMixerDevice *device);
+static const GList * device_list_profiles (MateMixerDevice *device);
+static MateMixerProfile *device_get_active_profile (MateMixerDevice *device);
+
+static gboolean device_set_active_profile (MateMixerDevice *device,
+ const gchar *name);
+
+G_DEFINE_TYPE_WITH_CODE (PulseDevice, pulse_device, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_DEVICE,
mate_mixer_device_interface_init))
static void
mate_mixer_device_interface_init (MateMixerDeviceInterface *iface)
{
- iface->get_name = mate_mixer_pulse_device_get_name;
- iface->get_description = mate_mixer_pulse_device_get_description;
- iface->get_icon = mate_mixer_pulse_device_get_icon;
- iface->list_streams = mate_mixer_pulse_device_list_streams;
- iface->list_ports = mate_mixer_pulse_device_list_ports;
- iface->list_profiles = mate_mixer_pulse_device_list_profiles;
- iface->get_active_profile = mate_mixer_pulse_device_get_active_profile;
- iface->set_active_profile = mate_mixer_pulse_device_set_active_profile;
+ iface->get_name = device_get_name;
+ iface->get_description = device_get_description;
+ iface->get_icon = device_get_icon;
+ iface->list_streams = device_list_streams;
+ iface->list_ports = device_list_ports;
+ iface->list_profiles = device_list_profiles;
+ iface->get_active_profile = device_get_active_profile;
+ iface->set_active_profile = device_set_active_profile;
}
static void
-mate_mixer_pulse_device_init (MateMixerPulseDevice *device)
+pulse_device_init (PulseDevice *device)
{
device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
- MATE_MIXER_TYPE_PULSE_DEVICE,
- MateMixerPulseDevicePrivate);
+ PULSE_TYPE_DEVICE,
+ PulseDevicePrivate);
}
static void
-mate_mixer_pulse_device_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec)
+pulse_device_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- MateMixerPulseDevice *device;
+ PulseDevice *device;
- device = MATE_MIXER_PULSE_DEVICE (object);
+ device = PULSE_DEVICE (object);
switch (param_id) {
case PROP_NAME:
@@ -106,14 +119,14 @@ mate_mixer_pulse_device_get_property (GObject *object,
}
static void
-mate_mixer_pulse_device_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec)
+pulse_device_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- MateMixerPulseDevice *device;
+ PulseDevice *device;
- device = MATE_MIXER_PULSE_DEVICE (object);
+ device = PULSE_DEVICE (object);
switch (param_id) {
case PROP_NAME:
@@ -132,11 +145,11 @@ mate_mixer_pulse_device_set_property (GObject *object,
}
static void
-mate_mixer_pulse_device_dispose (GObject *object)
+pulse_device_dispose (GObject *object)
{
- MateMixerPulseDevice *device;
+ PulseDevice *device;
- device = MATE_MIXER_PULSE_DEVICE (object);
+ device = PULSE_DEVICE (object);
if (device->priv->profiles != NULL) {
g_list_free_full (device->priv->profiles, g_object_unref);
@@ -151,50 +164,50 @@ mate_mixer_pulse_device_dispose (GObject *object)
g_clear_object (&device->priv->profile);
g_clear_object (&device->priv->connection);
- G_OBJECT_CLASS (mate_mixer_pulse_device_parent_class)->dispose (object);
+ G_OBJECT_CLASS (pulse_device_parent_class)->dispose (object);
}
static void
-mate_mixer_pulse_device_finalize (GObject *object)
+pulse_device_finalize (GObject *object)
{
- MateMixerPulseDevice *device;
+ PulseDevice *device;
- device = MATE_MIXER_PULSE_DEVICE (object);
+ device = PULSE_DEVICE (object);
g_free (device->priv->name);
g_free (device->priv->description);
g_free (device->priv->icon);
- G_OBJECT_CLASS (mate_mixer_pulse_device_parent_class)->finalize (object);
+ G_OBJECT_CLASS (pulse_device_parent_class)->finalize (object);
}
static void
-mate_mixer_pulse_device_class_init (MateMixerPulseDeviceClass *klass)
+pulse_device_class_init (PulseDeviceClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = mate_mixer_pulse_device_dispose;
- object_class->finalize = mate_mixer_pulse_device_finalize;
- object_class->get_property = mate_mixer_pulse_device_get_property;
- object_class->set_property = mate_mixer_pulse_device_set_property;
+ object_class->dispose = pulse_device_dispose;
+ object_class->finalize = pulse_device_finalize;
+ object_class->get_property = pulse_device_get_property;
+ object_class->set_property = pulse_device_set_property;
g_object_class_override_property (object_class, PROP_NAME, "name");
g_object_class_override_property (object_class, PROP_DESCRIPTION, "description");
g_object_class_override_property (object_class, PROP_ICON, "icon");
g_object_class_override_property (object_class, PROP_ACTIVE_PROFILE, "active-profile");
- g_type_class_add_private (object_class, sizeof (MateMixerPulseDevicePrivate));
+ g_type_class_add_private (object_class, sizeof (PulseDevicePrivate));
}
-MateMixerPulseDevice *
-mate_mixer_pulse_device_new (MateMixerPulseConnection *connection, const pa_card_info *info)
+PulseDevice *
+pulse_device_new (PulseConnection *connection, const pa_card_info *info)
{
- MateMixerPulseDevice *device;
- MateMixerProfile *active_profile = NULL;
- GList *profiles = NULL;
- GList *ports = NULL;
- guint32 i;
+ PulseDevice *device;
+ MateMixerProfile *active_profile = NULL;
+ GList *profiles = NULL;
+ GList *ports = NULL;
+ guint32 i;
g_return_val_if_fail (info != NULL, NULL);
@@ -264,7 +277,7 @@ mate_mixer_pulse_device_new (MateMixerPulseConnection *connection, const pa_card
if (ports)
ports = g_list_reverse (ports);
- device = g_object_new (MATE_MIXER_TYPE_PULSE_DEVICE,
+ device = g_object_new (PULSE_TYPE_DEVICE,
"name", info->name,
"description", pa_proplist_gets (info->proplist, "device.description"),
"icon", pa_proplist_gets (info->proplist, "device.icon_name"),
@@ -285,113 +298,97 @@ mate_mixer_pulse_device_new (MateMixerPulseConnection *connection, const pa_card
}
gboolean
-mate_mixer_pulse_device_update (MateMixerPulseDevice *device, const pa_card_info *info)
+pulse_device_update (PulseDevice *device, const pa_card_info *info)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), FALSE);
+ g_return_val_if_fail (PULSE_IS_DEVICE (device), FALSE);
g_return_val_if_fail (info != NULL, FALSE);
// TODO: update status, active_profile, maybe others?
return TRUE;
}
-MateMixerPulseConnection *
-mate_mixer_pulse_device_get_connection (MateMixerPulseDevice *device)
+PulseConnection *
+pulse_device_get_connection (PulseDevice *device)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), NULL);
+ g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
return device->priv->connection;
}
guint32
-mate_mixer_pulse_device_get_index (MateMixerPulseDevice *device)
+pulse_device_get_index (PulseDevice *device)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), 0);
+ g_return_val_if_fail (PULSE_IS_DEVICE (device), 0);
return device->priv->index;
}
-const gchar *
-mate_mixer_pulse_device_get_name (MateMixerDevice *device)
+static const gchar *
+device_get_name (MateMixerDevice *device)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), NULL);
+ g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
- return MATE_MIXER_PULSE_DEVICE (device)->priv->name;
+ return PULSE_DEVICE (device)->priv->name;
}
-const gchar *
-mate_mixer_pulse_device_get_description (MateMixerDevice *device)
+static const gchar *
+device_get_description (MateMixerDevice *device)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), NULL);
+ g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
- return MATE_MIXER_PULSE_DEVICE (device)->priv->description;
+ return PULSE_DEVICE (device)->priv->description;
}
-const gchar *
-mate_mixer_pulse_device_get_icon (MateMixerDevice *device)
+static const gchar *
+device_get_icon (MateMixerDevice *device)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), NULL);
+ g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
- return MATE_MIXER_PULSE_DEVICE (device)->priv->icon;
+ return PULSE_DEVICE (device)->priv->icon;
}
-const GList *
-mate_mixer_pulse_device_list_streams (MateMixerDevice *device)
+static const GList *
+device_list_streams (MateMixerDevice *device)
{
// TODO
return NULL;
}
-const GList *
-mate_mixer_pulse_device_list_ports (MateMixerDevice *device)
+static const GList *
+device_list_ports (MateMixerDevice *device)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), NULL);
+ g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
- return (const GList *) MATE_MIXER_PULSE_DEVICE (device)->priv->ports;
+ return (const GList *) PULSE_DEVICE (device)->priv->ports;
}
-const GList *
-mate_mixer_pulse_device_list_profiles (MateMixerDevice *device)
+static const GList *
+device_list_profiles (MateMixerDevice *device)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), NULL);
+ g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
- return (const GList *) MATE_MIXER_PULSE_DEVICE (device)->priv->profiles;
+ return (const GList *) PULSE_DEVICE (device)->priv->profiles;
}
-MateMixerProfile *
-mate_mixer_pulse_device_get_active_profile (MateMixerDevice *device)
+static MateMixerProfile *
+device_get_active_profile (MateMixerDevice *device)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), NULL);
+ g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
- return MATE_MIXER_PULSE_DEVICE (device)->priv->profile;
+ return PULSE_DEVICE (device)->priv->profile;
}
-gboolean
-mate_mixer_pulse_device_set_active_profile (MateMixerDevice *device, const gchar *name)
+static gboolean
+device_set_active_profile (MateMixerDevice *device, const gchar *name)
{
- gboolean ret;
- MateMixerPulseDevicePrivate *priv;
+ PulseDevicePrivate *priv;
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_DEVICE (device), FALSE);
+ g_return_val_if_fail (PULSE_IS_DEVICE (device), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
- priv = MATE_MIXER_PULSE_DEVICE (device)->priv;
- ret = mate_mixer_pulse_connection_set_card_profile (priv->connection,
- priv->name,
- name);
+ priv = PULSE_DEVICE (device)->priv;
- // XXX decide to either confirm the change during the connection call or
- // wait for a notification from Pulse
-/*
- if (ret) {
- if (priv->profile)
- g_object_unref (priv->profile);
-
- priv->profile = g_object_ref (profile);
-
- g_object_notify_by_pspec (
- G_OBJECT (device),
- properties[PROP_ACTIVE_PROFILE]);
- }
-*/
- return ret;
+ return pulse_connection_set_card_profile (priv->connection,
+ priv->name,
+ name);
}
diff --git a/backends/pulse/pulse-device.h b/backends/pulse/pulse-device.h
index 896b02b..b862879 100644
--- a/backends/pulse/pulse-device.h
+++ b/backends/pulse/pulse-device.h
@@ -15,77 +15,58 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef MATEMIXER_PULSE_DEVICE_H
-#define MATEMIXER_PULSE_DEVICE_H
+#ifndef PULSE_DEVICE_H
+#define PULSE_DEVICE_H
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-device.h>
-#include <libmatemixer/matemixer-profile.h>
-
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
G_BEGIN_DECLS
-#define MATE_MIXER_TYPE_PULSE_DEVICE \
- (mate_mixer_pulse_device_get_type ())
-#define MATE_MIXER_PULSE_DEVICE(o) \
- (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_PULSE_DEVICE, MateMixerPulseDevice))
-#define MATE_MIXER_IS_PULSE_DEVICE(o) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_PULSE_DEVICE))
-#define MATE_MIXER_PULSE_DEVICE_CLASS(k) \
- (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_PULSE_DEVICE, MateMixerPulseDeviceClass))
-#define MATE_MIXER_IS_PULSE_DEVICE_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_PULSE_DEVICE))
-#define MATE_MIXER_PULSE_DEVICE_GET_CLASS(o) \
- (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_PULSE_DEVICE, MateMixerPulseDeviceClass))
-
-typedef struct _MateMixerPulseDevice MateMixerPulseDevice;
-typedef struct _MateMixerPulseDeviceClass MateMixerPulseDeviceClass;
-typedef struct _MateMixerPulseDevicePrivate MateMixerPulseDevicePrivate;
-
-struct _MateMixerPulseDevice
+#define PULSE_TYPE_DEVICE \
+ (pulse_device_get_type ())
+#define PULSE_DEVICE(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_DEVICE, PulseDevice))
+#define PULSE_IS_DEVICE(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_DEVICE))
+#define PULSE_DEVICE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_DEVICE, PulseDeviceClass))
+#define PULSE_IS_DEVICE_CLASS(k) \
+ (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_DEVICE))
+#define PULSE_DEVICE_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_IS_DEVICE, PulseDeviceClass))
+
+typedef struct _PulseDevice PulseDevice;
+typedef struct _PulseDeviceClass PulseDeviceClass;
+typedef struct _PulseDevicePrivate PulseDevicePrivate;
+
+struct _PulseDevice
{
GObject parent;
- MateMixerPulseDevicePrivate *priv;
+ PulseDevicePrivate *priv;
};
-struct _MateMixerPulseDeviceClass
+struct _PulseDeviceClass
{
GObjectClass parent;
};
-GType mate_mixer_pulse_device_get_type (void) G_GNUC_CONST;
-
-MateMixerPulseDevice *mate_mixer_pulse_device_new (MateMixerPulseConnection *connection,
- const pa_card_info *info);
-
-gboolean mate_mixer_pulse_device_update (MateMixerPulseDevice *device,
- const pa_card_info *info);
-
-MateMixerPulseConnection *mate_mixer_pulse_device_get_connection (MateMixerPulseDevice *device);
-
-guint32 mate_mixer_pulse_device_get_index (MateMixerPulseDevice *device);
-
-/* Interface implementation */
-const gchar *mate_mixer_pulse_device_get_name (MateMixerDevice *device);
-const gchar *mate_mixer_pulse_device_get_description (MateMixerDevice *device);
-const gchar *mate_mixer_pulse_device_get_icon (MateMixerDevice *device);
-
-const GList *mate_mixer_pulse_device_list_streams (MateMixerDevice *device);
+GType pulse_device_get_type (void) G_GNUC_CONST;
-const GList *mate_mixer_pulse_device_list_ports (MateMixerDevice *device);
-const GList *mate_mixer_pulse_device_list_profiles (MateMixerDevice *device);
+PulseDevice *pulse_device_new (PulseConnection *connection,
+ const pa_card_info *info);
-MateMixerProfile *mate_mixer_pulse_device_get_active_profile (MateMixerDevice *device);
+gboolean pulse_device_update (PulseDevice *device,
+ const pa_card_info *info);
-gboolean mate_mixer_pulse_device_set_active_profile (MateMixerDevice *device,
- const gchar *name);
+guint32 pulse_device_get_index (PulseDevice *device);
+PulseConnection *pulse_device_get_connection (PulseDevice *device);
G_END_DECLS
-#endif /* MATEMIXER_PULSE_DEVICE_H */
+#endif /* PULSE_DEVICE_H */
diff --git a/backends/pulse/pulse-enum-types.c b/backends/pulse/pulse-enum-types.c
new file mode 100644
index 0000000..e31b9f7
--- /dev/null
+++ b/backends/pulse/pulse-enum-types.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pulse-enum-types.h"
+#include "pulse-enums.h"
+
+/*
+ * GTypes are not generated by glib-mkenums, see:
+ * https://bugzilla.gnome.org/show_bug.cgi?id=621942
+ */
+
+GType
+pulse_connection_state_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ { PULSE_CONNECTION_DISCONNECTED, "PULSE_CONNECTION_DISCONNECTED", "disconnected" },
+ { PULSE_CONNECTION_CONNECTING, "PULSE_CONNECTION_CONNECTING", "connecting" },
+ { PULSE_CONNECTION_AUTHORIZING, "PULSE_CONNECTION_AUTHORIZING", "authorizing" },
+ { PULSE_CONNECTION_LOADING, "PULSE_CONNECTION_LOADING", "loading" },
+ { PULSE_CONNECTION_CONNECTED, "PULSE_CONNECTION_CONNECTED", "connected" },
+ { 0, NULL, NULL }
+ };
+ etype = g_enum_register_static (
+ g_intern_static_string ("PulseConnectionState"),
+ values);
+ }
+ return etype;
+}
diff --git a/backends/pulse/pulse-enum-types.h b/backends/pulse/pulse-enum-types.h
new file mode 100644
index 0000000..71b52f4
--- /dev/null
+++ b/backends/pulse/pulse-enum-types.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_ENUM_TYPES_H
+#define PULSE_ENUM_TYPES_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*
+ * GTypes are not generated by glib-mkenums, see:
+ * https://bugzilla.gnome.org/show_bug.cgi?id=621942
+ */
+
+#define PULSE_TYPE_CONNECTION_STATE (pulse_connection_state_get_type ())
+GType pulse_connection_state_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* PULSE_ENUM_TYPES_H */
diff --git a/backends/pulse/pulse-enums.h b/backends/pulse/pulse-enums.h
new file mode 100644
index 0000000..947c35c
--- /dev/null
+++ b/backends/pulse/pulse-enums.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_ENUMS_H
+#define PULSE_ENUMS_H
+
+typedef enum {
+ PULSE_CONNECTION_DISCONNECTED = 0,
+ PULSE_CONNECTION_CONNECTING,
+ PULSE_CONNECTION_AUTHORIZING,
+ PULSE_CONNECTION_LOADING,
+ PULSE_CONNECTION_CONNECTED
+} PulseConnectionState;
+
+#endif /* PULSE_ENUMS_H */
diff --git a/backends/pulse/pulse-helpers.c b/backends/pulse/pulse-helpers.c
new file mode 100644
index 0000000..ca39d8f
--- /dev/null
+++ b/backends/pulse/pulse-helpers.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+
+#include <libmatemixer/matemixer-enums.h>
+#include <pulse/pulseaudio.h>
+
+#include "pulse-helpers.h"
+
+typedef struct {
+ MateMixerChannelPosition mm_position;
+ pa_channel_position_t pa_position;
+} PositionMap;
+
+static PositionMap const position_map[] = {
+ { MATE_MIXER_CHANNEL_UNKNOWN_POSITION, PA_CHANNEL_POSITION_INVALID },
+ { MATE_MIXER_CHANNEL_MONO, PA_CHANNEL_POSITION_MONO },
+ { MATE_MIXER_CHANNEL_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_LEFT },
+ { MATE_MIXER_CHANNEL_FRONT_RIGHT, PA_CHANNEL_POSITION_FRONT_RIGHT },
+ { MATE_MIXER_CHANNEL_FRONT_CENTER, PA_CHANNEL_POSITION_FRONT_CENTER },
+ { MATE_MIXER_CHANNEL_LFE, PA_CHANNEL_POSITION_LFE },
+ { MATE_MIXER_CHANNEL_BACK_LEFT, PA_CHANNEL_POSITION_REAR_LEFT },
+ { MATE_MIXER_CHANNEL_BACK_RIGHT, PA_CHANNEL_POSITION_REAR_RIGHT },
+ { MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER, PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER },
+ { MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER, PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER },
+ { MATE_MIXER_CHANNEL_BACK_CENTER, PA_CHANNEL_POSITION_REAR_CENTER },
+ { MATE_MIXER_CHANNEL_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_LEFT },
+ { MATE_MIXER_CHANNEL_SIDE_RIGHT, PA_CHANNEL_POSITION_SIDE_RIGHT },
+ { MATE_MIXER_CHANNEL_TOP_FRONT_LEFT, PA_CHANNEL_POSITION_TOP_FRONT_LEFT },
+ { MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT, PA_CHANNEL_POSITION_TOP_FRONT_RIGHT },
+ { MATE_MIXER_CHANNEL_TOP_FRONT_CENTER, PA_CHANNEL_POSITION_TOP_FRONT_CENTER },
+ { MATE_MIXER_CHANNEL_TOP_CENTER, PA_CHANNEL_POSITION_TOP_CENTER },
+ { MATE_MIXER_CHANNEL_TOP_BACK_LEFT, PA_CHANNEL_POSITION_TOP_REAR_LEFT },
+ { MATE_MIXER_CHANNEL_TOP_BACK_RIGHT, PA_CHANNEL_POSITION_TOP_REAR_RIGHT },
+ { MATE_MIXER_CHANNEL_TOP_BACK_CENTER, PA_CHANNEL_POSITION_TOP_REAR_CENTER },
+};
+
+MateMixerChannelPosition
+pulse_convert_position_from_pulse (pa_channel_position_t position)
+{
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (position_map); i++) {
+ if (position == position_map[i].pa_position)
+ return position_map[i].mm_position;
+ }
+ return MATE_MIXER_CHANNEL_UNKNOWN_POSITION;
+}
+
+pa_channel_position_t
+pulse_convert_position_to_pulse (MateMixerChannelPosition position)
+{
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (position_map); i++) {
+ if (position == position_map[i].mm_position)
+ return position_map[i].pa_position;
+ }
+ return PA_CHANNEL_POSITION_INVALID;
+}
diff --git a/backends/pulse/pulse-helpers.h b/backends/pulse/pulse-helpers.h
new file mode 100644
index 0000000..36cc0c1
--- /dev/null
+++ b/backends/pulse/pulse-helpers.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_HELPERS_H
+#define PULSE_HELPERS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-enums.h>
+
+#include <pulse/pulseaudio.h>
+
+ G_BEGIN_DECLS
+
+MateMixerChannelPosition pulse_convert_position_from_pulse (pa_channel_position_t position);
+pa_channel_position_t pulse_convert_position_to_pulse (MateMixerChannelPosition position);
+
+G_END_DECLS
+
+#endif /* PULSE_HELPERS_H */
diff --git a/backends/pulse/pulse-sink-input.c b/backends/pulse/pulse-sink-input.c
index e69de29..8540193 100644
--- a/backends/pulse/pulse-sink-input.c
+++ b/backends/pulse/pulse-sink-input.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-client-stream.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-connection.h"
+#include "pulse-client-stream.h"
+#include "pulse-sink-input.h"
+#include "pulse-stream.h"
+
+struct _PulseSinkInputPrivate
+{
+ guint32 index_monitor;
+};
+
+static gboolean sink_input_set_mute (MateMixerStream *stream,
+ gboolean mute);
+static gboolean sink_input_set_volume (MateMixerStream *stream,
+ pa_cvolume *volume);
+static gboolean sink_input_set_parent (MateMixerClientStream *stream,
+ MateMixerStream *parent);
+
+static gboolean sink_input_remove (MateMixerClientStream *stream);
+
+G_DEFINE_TYPE (PulseSinkInput, pulse_sink_input, PULSE_TYPE_CLIENT_STREAM);
+
+static void
+pulse_sink_input_init (PulseSinkInput *input)
+{
+ input->priv = G_TYPE_INSTANCE_GET_PRIVATE (input,
+ PULSE_TYPE_SINK_INPUT,
+ PulseSinkInputPrivate);
+}
+
+static void
+pulse_sink_input_class_init (PulseSinkInputClass *klass)
+{
+ PulseStreamClass *stream_class;
+ PulseClientStreamClass *client_class;
+
+ stream_class = PULSE_STREAM_CLASS (klass);
+
+ stream_class->set_mute = sink_input_set_mute;
+ stream_class->set_volume = sink_input_set_volume;
+
+ client_class = PULSE_CLIENT_STREAM_CLASS (klass);
+
+ client_class->set_parent = sink_input_set_parent;
+ client_class->remove = sink_input_remove;
+
+ g_type_class_add_private (klass, sizeof (PulseSinkInputPrivate));
+}
+
+PulseStream *
+pulse_sink_input_new (PulseConnection *connection, const pa_sink_input_info *info)
+{
+ PulseSinkInput *input;
+
+ /* Consider the sink input index as unchanging parameter */
+ input = g_object_new (PULSE_TYPE_SINK_INPUT,
+ "connection", connection,
+ "index", info->index,
+ NULL);
+
+ /* Other data may change at any time, so let's make a use of our update function */
+ pulse_sink_input_update (PULSE_STREAM (input), info);
+
+ return PULSE_STREAM (input);
+}
+
+gboolean
+pulse_sink_input_update (PulseStream *stream, const pa_sink_input_info *info)
+{
+ MateMixerStreamFlags flags = MATE_MIXER_STREAM_OUTPUT |
+ MATE_MIXER_STREAM_CLIENT |
+ MATE_MIXER_STREAM_HAS_MUTE;
+
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), FALSE);
+
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (stream));
+
+ pulse_stream_update_name (stream, info->name);
+ // pulse_stream_update_description (stream, info->description);
+ pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
+ pulse_stream_update_channel_map (stream, &info->channel_map);
+
+ /* Build the flag list */
+ if (info->has_volume) {
+ flags |= MATE_MIXER_STREAM_HAS_VOLUME;
+ pulse_stream_update_volume (stream, &info->volume);
+ }
+ if (info->volume_writable)
+ flags |= MATE_MIXER_STREAM_CAN_SET_VOLUME;
+
+ if (info->client != PA_INVALID_INDEX)
+ flags |= MATE_MIXER_STREAM_APPLICATION;
+
+ if (pa_channel_map_can_balance (&info->channel_map))
+ flags |= MATE_MIXER_STREAM_CAN_BALANCE;
+ if (pa_channel_map_can_fade (&info->channel_map))
+ flags |= MATE_MIXER_STREAM_CAN_FADE;
+
+ pulse_stream_update_flags (stream, flags);
+
+ g_object_thaw_notify (G_OBJECT (stream));
+ return TRUE;
+}
+
+static gboolean
+sink_input_set_mute (MateMixerStream *stream, gboolean mute)
+{
+ PulseStream *ps;
+
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), FALSE);
+
+ ps = PULSE_STREAM (stream);
+
+ return pulse_connection_set_sink_input_mute (pulse_stream_get_connection (ps),
+ pulse_stream_get_index (ps),
+ mute);
+}
+
+static gboolean
+sink_input_set_volume (MateMixerStream *stream, pa_cvolume *volume)
+{
+ PulseStream *ps;
+
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), FALSE);
+ g_return_val_if_fail (volume != NULL, FALSE);
+
+ ps = PULSE_STREAM (stream);
+
+ return pulse_connection_set_sink_input_volume (pulse_stream_get_connection (ps),
+ pulse_stream_get_index (ps),
+ volume);
+}
+
+static gboolean
+sink_input_set_parent (MateMixerClientStream *stream, MateMixerStream *parent)
+{
+ // TODO
+ return TRUE;
+}
+
+static gboolean
+sink_input_remove (MateMixerClientStream *stream)
+{
+ // TODO
+ return TRUE;
+}
diff --git a/backends/pulse/pulse-sink-input.h b/backends/pulse/pulse-sink-input.h
index e69de29..110ca9c 100644
--- a/backends/pulse/pulse-sink-input.h
+++ b/backends/pulse/pulse-sink-input.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_SINK_INPUT_H
+#define PULSE_SINK_INPUT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-stream.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-client-stream.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_SINK_INPUT \
+ (pulse_sink_input_get_type ())
+#define PULSE_SINK_INPUT(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SINK_INPUT, PulseSinkInput))
+#define PULSE_IS_SINK_INPUT(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SINK_INPUT))
+#define PULSE_SINK_INPUT_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SINK_INPUT, PulseSinkInputClass))
+#define PULSE_IS_SINK_INPUT_CLASS(k) \
+ (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SINK_INPUT))
+#define PULSE_SINK_INPUT_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SINK_INPUT, PulseSinkInputClass))
+
+typedef struct _PulseSinkInput PulseSinkInput;
+typedef struct _PulseSinkInputClass PulseSinkInputClass;
+typedef struct _PulseSinkInputPrivate PulseSinkInputPrivate;
+
+struct _PulseSinkInput
+{
+ PulseClientStream parent;
+
+ PulseSinkInputPrivate *priv;
+};
+
+struct _PulseSinkInputClass
+{
+ PulseClientStreamClass parent;
+};
+
+GType pulse_sink_input_get_type (void) G_GNUC_CONST;
+
+PulseStream *pulse_sink_input_new (PulseConnection *connection,
+ const pa_sink_input_info *info);
+
+gboolean pulse_sink_input_update (PulseStream *stream,
+ const pa_sink_input_info *info);
+
+G_END_DECLS
+
+#endif /* PULSE_SINK_INPUT_H */
diff --git a/backends/pulse/pulse-sink.c b/backends/pulse/pulse-sink.c
index 64eb4c1..53ed64f 100644
--- a/backends/pulse/pulse-sink.c
+++ b/backends/pulse/pulse-sink.c
@@ -27,41 +27,55 @@
#include "pulse-stream.h"
#include "pulse-sink.h"
-struct _MateMixerPulseSinkPrivate
+struct _PulseSinkPrivate
{
guint32 index_monitor;
};
-G_DEFINE_TYPE (MateMixerPulseSink, mate_mixer_pulse_sink, MATE_MIXER_TYPE_PULSE_STREAM);
+enum {
+ PROP_0,
+ N_PROPERTIES
+};
+
+static gboolean sink_set_mute (MateMixerStream *stream,
+ gboolean mute);
+static gboolean sink_set_volume (MateMixerStream *stream,
+ pa_cvolume *volume);
+static gboolean sink_set_active_port (MateMixerStream *stream,
+ const gchar *port_name);
+
+G_DEFINE_TYPE (PulseSink, pulse_sink, PULSE_TYPE_STREAM);
static void
-mate_mixer_pulse_sink_init (MateMixerPulseSink *sink)
+pulse_sink_init (PulseSink *sink)
{
sink->priv = G_TYPE_INSTANCE_GET_PRIVATE (sink,
- MATE_MIXER_TYPE_PULSE_SINK,
- MateMixerPulseSinkPrivate);
+ PULSE_TYPE_SINK,
+ PulseSinkPrivate);
}
static void
-mate_mixer_pulse_sink_class_init (MateMixerPulseSinkClass *klass)
+pulse_sink_class_init (PulseSinkClass *klass)
{
- MateMixerPulseStreamClass *stream_class;
+ PulseStreamClass *stream_class;
- stream_class = MATE_MIXER_PULSE_STREAM_CLASS (klass);
+ stream_class = PULSE_STREAM_CLASS (klass);
- stream_class->set_volume = mate_mixer_pulse_sink_set_volume;
- stream_class->set_mute = mate_mixer_pulse_sink_set_mute;
+ stream_class->set_mute = sink_set_mute;
+ stream_class->set_volume = sink_set_volume;
+ stream_class->set_active_port = sink_set_active_port;
- g_type_class_add_private (G_OBJECT (klass), sizeof (MateMixerPulseSinkPrivate));
+ g_type_class_add_private (klass, sizeof (PulseSinkPrivate));
}
-MateMixerPulseStream *
-mate_mixer_pulse_sink_new (MateMixerPulseConnection *connection, const pa_sink_info *info)
+PulseStream *
+pulse_sink_new (PulseConnection *connection, const pa_sink_info *info)
{
- MateMixerPulseStream *stream;
- GList *ports = NULL;
- int i;
+ PulseSink *sink;
+ GList *ports = NULL;
+ int i;
+ /* Convert the list of sink ports to a GList of MateMixerPorts */
for (i = 0; i < info->n_ports; i++) {
MateMixerPort *port;
MateMixerPortStatus status = MATE_MIXER_PORT_UNKNOWN_STATUS;
@@ -88,43 +102,122 @@ mate_mixer_pulse_sink_new (MateMixerPulseConnection *connection, const pa_sink_i
ports = g_list_prepend (ports, port);
}
- if (ports)
- ports = g_list_reverse (ports);
+ /* Consider the sink index as unchanging parameter */
+ sink = g_object_new (PULSE_TYPE_SINK,
+ "connection", connection,
+ "index", info->index,
+ NULL);
- stream = g_object_new (MATE_MIXER_TYPE_PULSE_STREAM,
- "connection", connection,
- "index", info->index,
- "name", info->name,
- "description", info->description,
- "channels", info->channel_map.channels,
- "mute", info->mute ? TRUE : FALSE,
- NULL);
+ /* According to the PulseAudio code, the list of sink port never changes with
+ * updates.
+ * This may be not future-proof, but checking and validating the list of ports on
+ * each update would be an expensive operation, so let's set the list only during
+ * the construction */
+ pulse_stream_update_ports (PULSE_STREAM (sink), g_list_reverse (ports));
- return stream;
+ /* Other data may change at any time, so let's make a use of our update function */
+ pulse_sink_update (PULSE_STREAM (sink), info);
+
+ return PULSE_STREAM (sink);
}
gboolean
-mate_mixer_pulse_sink_set_volume (MateMixerStream *stream, guint32 volume)
+pulse_sink_update (PulseStream *stream, const pa_sink_info *info)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_STREAM (stream), FALSE);
+ PulseSink *sink;
+ MateMixerStreamFlags flags = MATE_MIXER_STREAM_OUTPUT |
+ MATE_MIXER_STREAM_HAS_MUTE |
+ MATE_MIXER_STREAM_HAS_VOLUME |
+ MATE_MIXER_STREAM_CAN_SET_VOLUME;
+
+ g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
+
+ sink = PULSE_SINK (stream);
+
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (stream));
+
+ pulse_stream_update_name (stream, info->name);
+ pulse_stream_update_description (stream, info->description);
+ pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
+ pulse_stream_update_channel_map (stream, &info->channel_map);
+ pulse_stream_update_volume_extended (stream,
+ &info->volume,
+ info->base_volume,
+ info->n_volume_steps);
+ if (info->active_port)
+ pulse_stream_update_active_port (stream, info->active_port->name);
+
+ switch (info->state) {
+ case PA_SINK_RUNNING:
+ pulse_stream_update_status (stream, MATE_MIXER_STREAM_RUNNING);
+ break;
+ case PA_SINK_IDLE:
+ pulse_stream_update_status (stream, MATE_MIXER_STREAM_IDLE);
+ break;
+ case PA_SINK_SUSPENDED:
+ pulse_stream_update_status (stream, MATE_MIXER_STREAM_SUSPENDED);
+ break;
+ default:
+ pulse_stream_update_status (stream, MATE_MIXER_STREAM_UNKNOWN_STATUS);
+ break;
+ }
-/*
- return mate_mixer_pulse_connection_set_sink_volume (mate_mixer_pulse_stream_get_connection (MATE_MIXER_PULSE_STREAM (stream)),
- volume);
-*/
+ /* Build the flag list */
+ if (info->flags & PA_SINK_DECIBEL_VOLUME)
+ flags |= MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME;
+ if (info->flags & PA_SINK_FLAT_VOLUME)
+ flags |= MATE_MIXER_STREAM_HAS_FLAT_VOLUME;
+
+ if (info->monitor_source_name)
+ flags |= MATE_MIXER_STREAM_OUTPUT_MONITOR;
+
+ if (pa_channel_map_can_balance (&info->channel_map))
+ flags |= MATE_MIXER_STREAM_CAN_BALANCE;
+ if (pa_channel_map_can_fade (&info->channel_map))
+ flags |= MATE_MIXER_STREAM_CAN_FADE;
+
+ pulse_stream_update_flags (stream, flags);
+
+ if (sink->priv->index_monitor != info->monitor_source) {
+ sink->priv->index_monitor = info->monitor_source;
+
+ // TODO: provide a property
+ // g_object_notify (G_OBJECT (stream), "monitor");
+ }
+
+ g_object_thaw_notify (G_OBJECT (stream));
return TRUE;
}
-gboolean
-mate_mixer_pulse_sink_set_mute (MateMixerStream *stream, gboolean mute)
+static gboolean
+sink_set_mute (MateMixerStream *stream, gboolean mute)
+{
+ g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
+
+ return pulse_connection_set_sink_mute (pulse_stream_get_connection (PULSE_STREAM (stream)),
+ pulse_stream_get_index (PULSE_STREAM (stream)),
+ mute);
+}
+
+static gboolean
+sink_set_volume (MateMixerStream *stream, pa_cvolume *volume)
{
- MateMixerPulseStream *pulse_stream;
+ g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
+ g_return_val_if_fail (volume != NULL, FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_STREAM (stream), FALSE);
+ return pulse_connection_set_sink_volume (pulse_stream_get_connection (PULSE_STREAM (stream)),
+ pulse_stream_get_index (PULSE_STREAM (stream)),
+ volume);
+}
- pulse_stream = MATE_MIXER_PULSE_STREAM (stream);
+static gboolean
+sink_set_active_port (MateMixerStream *stream, const gchar *port_name)
+{
+ g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
+ g_return_val_if_fail (port_name != NULL, FALSE);
- return mate_mixer_pulse_connection_set_sink_mute (mate_mixer_pulse_stream_get_connection (pulse_stream),
- mate_mixer_pulse_stream_get_index (pulse_stream),
- mute);
+ return pulse_connection_set_sink_port (pulse_stream_get_connection (PULSE_STREAM (stream)),
+ pulse_stream_get_index (PULSE_STREAM (stream)),
+ port_name);
}
diff --git a/backends/pulse/pulse-sink.h b/backends/pulse/pulse-sink.h
index ef2608f..22ca41f 100644
--- a/backends/pulse/pulse-sink.h
+++ b/backends/pulse/pulse-sink.h
@@ -15,8 +15,8 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef MATEMIXER_PULSE_SINK_H
-#define MATEMIXER_PULSE_SINK_H
+#ifndef PULSE_SINK_H
+#define PULSE_SINK_H
#include <glib.h>
#include <glib-object.h>
@@ -25,45 +25,47 @@
#include <pulse/pulseaudio.h>
+#include "pulse-stream.h"
+
G_BEGIN_DECLS
-#define MATE_MIXER_TYPE_PULSE_SINK \
- (mate_mixer_pulse_sink_get_type ())
-#define MATE_MIXER_PULSE_SINK(o) \
- (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_PULSE_SINK, MateMixerPulseSink))
-#define MATE_MIXER_IS_PULSE_SINK(o) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_PULSE_SINK))
-#define MATE_MIXER_PULSE_SINK_CLASS(k) \
- (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_PULSE_SINK, MateMixerPulseSinkClass))
-#define MATE_MIXER_IS_PULSE_SINK_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_PULSE_SINK))
-#define MATE_MIXER_PULSE_SINK_GET_CLASS(o) \
- (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_PULSE_SINK, MateMixerPulseSinkClass))
-
-typedef struct _MateMixerPulseSink MateMixerPulseSink;
-typedef struct _MateMixerPulseSinkClass MateMixerPulseSinkClass;
-typedef struct _MateMixerPulseSinkPrivate MateMixerPulseSinkPrivate;
-
-struct _MateMixerPulseSink
+#define PULSE_TYPE_SINK \
+ (pulse_sink_get_type ())
+#define PULSE_SINK(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SINK, PulseSink))
+#define PULSE_IS_SINK(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SINK))
+#define PULSE_SINK_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SINK, PulseSinkClass))
+#define PULSE_IS_SINK_CLASS(k) \
+ (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SINK))
+#define PULSE_SINK_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SINK, PulseSinkClass))
+
+typedef struct _PulseSink PulseSink;
+typedef struct _PulseSinkClass PulseSinkClass;
+typedef struct _PulseSinkPrivate PulseSinkPrivate;
+
+struct _PulseSink
{
- GObject parent;
+ PulseStream parent;
- MateMixerPulseSinkPrivate *priv;
+ PulseSinkPrivate *priv;
};
-struct _MateMixerPulseSinkClass
+struct _PulseSinkClass
{
- GObjectClass parent;
+ PulseStreamClass parent;
};
-GType mate_mixer_pulse_sink_get_type (void) G_GNUC_CONST;
+GType pulse_sink_get_type (void) G_GNUC_CONST;
-MateMixerPulseStream *mate_mixer_pulse_sink_new (MateMixerPulseConnection *connection,
- const pa_sink_info *info);
+PulseStream *pulse_sink_new (PulseConnection *connection,
+ const pa_sink_info *info);
-gboolean mate_mixer_pulse_sink_set_volume (MateMixerStream *stream, guint32 volume);
-gboolean mate_mixer_pulse_sink_set_mute (MateMixerStream *stream, gboolean mute);
+gboolean pulse_sink_update (PulseStream *stream,
+ const pa_sink_info *info);
G_END_DECLS
-#endif /* MATEMIXER_PULSE_SINK_H */
+#endif /* PULSE_SINK_H */
diff --git a/backends/pulse/pulse-source-output.c b/backends/pulse/pulse-source-output.c
index e69de29..94a4963 100644
--- a/backends/pulse/pulse-source-output.c
+++ b/backends/pulse/pulse-source-output.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-stream.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-connection.h"
+#include "pulse-stream.h"
+#include "pulse-source-output.h"
+
+struct _PulseSourceOutputPrivate
+{
+ guint32 index_monitor;
+};
+
+static gboolean source_output_set_mute (MateMixerStream *stream, gboolean mute);
+static gboolean source_output_set_volume (MateMixerStream *stream, pa_cvolume *volume);
+
+G_DEFINE_TYPE (PulseSourceOutput, pulse_source_output, PULSE_TYPE_STREAM);
+
+static void
+pulse_source_output_init (PulseSourceOutput *output)
+{
+ output->priv = G_TYPE_INSTANCE_GET_PRIVATE (output,
+ PULSE_TYPE_SOURCE_OUTPUT,
+ PulseSourceOutputPrivate);
+}
+
+static void
+pulse_source_output_class_init (PulseSourceOutputClass *klass)
+{
+ PulseStreamClass *stream_class;
+
+ stream_class = PULSE_STREAM_CLASS (klass);
+
+ stream_class->set_mute = source_output_set_mute;
+ stream_class->set_volume = source_output_set_volume;
+
+ g_type_class_add_private (klass, sizeof (PulseSourceOutputPrivate));
+}
+
+PulseStream *
+pulse_source_output_new (PulseConnection *connection, const pa_source_output_info *info)
+{
+ PulseSourceOutput *output;
+
+ /* Consider the sink input index as unchanging parameter */
+ output = g_object_new (PULSE_TYPE_SOURCE_OUTPUT,
+ "connection", connection,
+ "index", info->index,
+ NULL);
+
+ /* Other data may change at any time, so let's make a use of our update function */
+ pulse_source_output_update (PULSE_STREAM (output), info);
+
+ return PULSE_STREAM (output);
+}
+
+gboolean
+pulse_source_output_update (PulseStream *stream, const pa_source_output_info *info)
+{
+ MateMixerStreamFlags flags = MATE_MIXER_STREAM_INPUT |
+ MATE_MIXER_STREAM_CLIENT |
+ MATE_MIXER_STREAM_HAS_MUTE;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), FALSE);
+
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (stream));
+
+ pulse_stream_update_name (stream, info->name);
+ // pulse_stream_update_description (stream, info->description);
+ pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
+ pulse_stream_update_channel_map (stream, &info->channel_map);
+
+ /* Build the flag list */
+ if (info->has_volume) {
+ flags |= MATE_MIXER_STREAM_HAS_VOLUME;
+ pulse_stream_update_volume (stream, &info->volume);
+ }
+ if (info->volume_writable)
+ flags |= MATE_MIXER_STREAM_CAN_SET_VOLUME;
+
+ if (info->client != PA_INVALID_INDEX)
+ flags |= MATE_MIXER_STREAM_APPLICATION;
+
+ if (pa_channel_map_can_balance (&info->channel_map))
+ flags |= MATE_MIXER_STREAM_CAN_BALANCE;
+ if (pa_channel_map_can_fade (&info->channel_map))
+ flags |= MATE_MIXER_STREAM_CAN_FADE;
+
+ pulse_stream_update_flags (stream, flags);
+
+ g_object_thaw_notify (G_OBJECT (stream));
+ return TRUE;
+}
+
+static gboolean
+source_output_set_mute (MateMixerStream *stream, gboolean mute)
+{
+ PulseStream *ps;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), FALSE);
+
+ ps = PULSE_STREAM (stream);
+
+ return pulse_connection_set_source_output_mute (pulse_stream_get_connection (ps),
+ pulse_stream_get_index (ps),
+ mute);
+}
+
+static gboolean
+source_output_set_volume (MateMixerStream *stream, pa_cvolume *volume)
+{
+ PulseStream *ps;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), FALSE);
+ g_return_val_if_fail (volume != NULL, FALSE);
+
+ ps = PULSE_STREAM (stream);
+
+ return pulse_connection_set_source_output_volume (pulse_stream_get_connection (ps),
+ pulse_stream_get_index (ps),
+ volume);
+}
diff --git a/backends/pulse/pulse-source-output.h b/backends/pulse/pulse-source-output.h
index e69de29..554819f 100644
--- a/backends/pulse/pulse-source-output.h
+++ b/backends/pulse/pulse-source-output.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_SOURCE_OUTPUT_H
+#define PULSE_SOURCE_OUTPUT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-stream.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-stream.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_SOURCE_OUTPUT \
+ (pulse_source_output_get_type ())
+#define PULSE_SOURCE_OUTPUT(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SOURCE_OUTPUT, PulseSourceOutput))
+#define PULSE_IS_SOURCE_OUTPUT(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SOURCE_OUTPUT))
+#define PULSE_SOURCE_OUTPUT_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SOURCE_OUTPUT, PulseSourceOutputClass))
+#define PULSE_IS_SOURCE_OUTPUT_CLASS(k) \
+ (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SOURCE_OUTPUT))
+#define PULSE_SOURCE_OUTPUT_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SOURCE_OUTPUT, PulseSourceOutputClass))
+
+typedef struct _PulseSourceOutput PulseSourceOutput;
+typedef struct _PulseSourceOutputClass PulseSourceOutputClass;
+typedef struct _PulseSourceOutputPrivate PulseSourceOutputPrivate;
+
+struct _PulseSourceOutput
+{
+ PulseStream parent;
+
+ PulseSourceOutputPrivate *priv;
+};
+
+struct _PulseSourceOutputClass
+{
+ PulseStreamClass parent;
+};
+
+GType pulse_source_output_get_type (void) G_GNUC_CONST;
+
+PulseStream *pulse_source_output_new (PulseConnection *connection,
+ const pa_source_output_info *info);
+
+gboolean pulse_source_output_update (PulseStream *stream,
+ const pa_source_output_info *info);
+
+G_END_DECLS
+
+#endif /* PULSE_SOURCE_OUTPUT_H */
diff --git a/backends/pulse/pulse-source.c b/backends/pulse/pulse-source.c
index e69de29..2aea6b6 100644
--- a/backends/pulse/pulse-source.c
+++ b/backends/pulse/pulse-source.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer-port.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-connection.h"
+#include "pulse-stream.h"
+#include "pulse-source.h"
+
+struct _PulseSourcePrivate
+{
+ guint32 index_monitored_sink;
+};
+
+static gboolean source_set_mute (MateMixerStream *stream,
+ gboolean mute);
+static gboolean source_set_volume (MateMixerStream *stream,
+ pa_cvolume *volume);
+static gboolean source_set_active_port (MateMixerStream *stream,
+ const gchar *port_name);
+
+G_DEFINE_TYPE (PulseSource, pulse_source, PULSE_TYPE_STREAM);
+
+static void
+pulse_source_init (PulseSource *source)
+{
+ source->priv = G_TYPE_INSTANCE_GET_PRIVATE (source,
+ PULSE_TYPE_SOURCE,
+ PulseSourcePrivate);
+}
+
+static void
+pulse_source_class_init (PulseSourceClass *klass)
+{
+ PulseStreamClass *stream_class;
+
+ stream_class = PULSE_STREAM_CLASS (klass);
+
+ stream_class->set_mute = source_set_mute;
+ stream_class->set_volume = source_set_volume;
+ stream_class->set_active_port = source_set_active_port;
+
+ g_type_class_add_private (klass, sizeof (PulseSourcePrivate));
+}
+
+PulseStream *
+pulse_source_new (PulseConnection *connection, const pa_source_info *info)
+{
+ PulseSource *source;
+ GList *ports = NULL;
+ int i;
+
+ for (i = 0; i < info->n_ports; i++) {
+ MateMixerPort *port;
+ MateMixerPortStatus status = MATE_MIXER_PORT_UNKNOWN_STATUS;
+ pa_source_port_info *p_info = info->ports[i];
+
+#if PA_CHECK_VERSION(2, 0, 0)
+ switch (p_info->available) {
+ case PA_PORT_AVAILABLE_YES:
+ status = MATE_MIXER_PORT_AVAILABLE;
+ break;
+ case PA_PORT_AVAILABLE_NO:
+ status = MATE_MIXER_PORT_UNAVAILABLE;
+ break;
+ default:
+ break;
+ }
+#endif
+ port = mate_mixer_port_new (p_info->name,
+ p_info->description,
+ NULL,
+ p_info->priority,
+ status);
+
+ ports = g_list_prepend (ports, port);
+ }
+
+ source = g_object_new (PULSE_TYPE_SOURCE,
+ "connection", connection,
+ "index", info->index,
+ NULL);
+
+ /* According to the PulseAudio code, the list of sink port never changes with
+ * updates.
+ * This may be not future-proof, but checking and validating the list of ports on
+ * each update would be an expensive operation, so let's set the list only during
+ * the construction */
+ pulse_stream_update_ports (PULSE_STREAM (source), g_list_reverse (ports));
+
+ /* Other data may change at any time, so let's make a use of our update function */
+ pulse_source_update (PULSE_STREAM (source), info);
+
+ return PULSE_STREAM (source);
+}
+
+gboolean
+pulse_source_update (PulseStream *stream, const pa_source_info *info)
+{
+ PulseSource *source;
+ MateMixerStreamFlags flags = MATE_MIXER_STREAM_INPUT |
+ MATE_MIXER_STREAM_HAS_MUTE |
+ MATE_MIXER_STREAM_HAS_VOLUME |
+ MATE_MIXER_STREAM_CAN_SET_VOLUME;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE (stream), FALSE);
+
+ source = PULSE_SOURCE (stream);
+
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (stream));
+
+ pulse_stream_update_name (stream, info->name);
+ pulse_stream_update_description (stream, info->description);
+ pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
+ pulse_stream_update_channel_map (stream, &info->channel_map);
+ pulse_stream_update_volume_extended (stream,
+ &info->volume,
+ info->base_volume,
+ info->n_volume_steps);
+ if (info->active_port)
+ pulse_stream_update_active_port (stream, info->active_port->name);
+
+ switch (info->state) {
+ case PA_SOURCE_RUNNING:
+ pulse_stream_update_status (stream, MATE_MIXER_STREAM_RUNNING);
+ break;
+ case PA_SOURCE_IDLE:
+ pulse_stream_update_status (stream, MATE_MIXER_STREAM_IDLE);
+ break;
+ case PA_SOURCE_SUSPENDED:
+ pulse_stream_update_status (stream, MATE_MIXER_STREAM_SUSPENDED);
+ break;
+ default:
+ pulse_stream_update_status (stream, MATE_MIXER_STREAM_UNKNOWN_STATUS);
+ break;
+ }
+
+ /* Build the flag list */
+ if (info->flags & PA_SINK_DECIBEL_VOLUME)
+ flags |= MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME;
+ if (info->flags & PA_SINK_FLAT_VOLUME)
+ flags |= MATE_MIXER_STREAM_HAS_FLAT_VOLUME;
+
+ if (pa_channel_map_can_balance (&info->channel_map))
+ flags |= MATE_MIXER_STREAM_CAN_BALANCE;
+ if (pa_channel_map_can_fade (&info->channel_map))
+ flags |= MATE_MIXER_STREAM_CAN_FADE;
+
+ pulse_stream_update_flags (stream, flags);
+
+ if (source->priv->index_monitored_sink != info->monitor_of_sink) {
+ source->priv->index_monitored_sink = info->monitor_of_sink;
+
+ // TODO: provide a property
+ // g_object_notify (G_OBJECT (stream), "monitor");
+ }
+
+ g_object_thaw_notify (G_OBJECT (stream));
+ return TRUE;
+}
+
+static gboolean
+source_set_mute (MateMixerStream *stream, gboolean mute)
+{
+ g_return_val_if_fail (PULSE_IS_SOURCE (stream), FALSE);
+
+ return pulse_connection_set_source_mute (pulse_stream_get_connection (PULSE_STREAM (stream)),
+ pulse_stream_get_index (PULSE_STREAM (stream)),
+ mute);
+}
+
+static gboolean
+source_set_volume (MateMixerStream *stream, pa_cvolume *volume)
+{
+ g_return_val_if_fail (PULSE_IS_SOURCE (stream), FALSE);
+ g_return_val_if_fail (volume != NULL, FALSE);
+
+ return pulse_connection_set_source_volume (pulse_stream_get_connection (PULSE_STREAM (stream)),
+ pulse_stream_get_index (PULSE_STREAM (stream)),
+ volume);
+}
+
+static gboolean
+source_set_active_port (MateMixerStream *stream, const gchar *port_name)
+{
+ g_return_val_if_fail (PULSE_IS_SOURCE (stream), FALSE);
+ g_return_val_if_fail (port_name != NULL, FALSE);
+
+ return pulse_connection_set_source_port (pulse_stream_get_connection (PULSE_STREAM (stream)),
+ pulse_stream_get_index (PULSE_STREAM (stream)),
+ port_name);
+}
diff --git a/backends/pulse/pulse-source.h b/backends/pulse/pulse-source.h
index e69de29..a8fd13c 100644
--- a/backends/pulse/pulse-source.h
+++ b/backends/pulse/pulse-source.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_SOURCE_H
+#define PULSE_SOURCE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-stream.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-stream.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_SOURCE \
+ (pulse_source_get_type ())
+#define PULSE_SOURCE(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SOURCE, PulseSource))
+#define PULSE_IS_SOURCE(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SOURCE))
+#define PULSE_SOURCE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SOURCE, PulseSourceClass))
+#define PULSE_IS_SOURCE_CLASS(k) \
+ (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SOURCE))
+#define PULSE_SOURCE_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SOURCE, PulseSourceClass))
+
+typedef struct _PulseSource PulseSource;
+typedef struct _PulseSourceClass PulseSourceClass;
+typedef struct _PulseSourcePrivate PulseSourcePrivate;
+
+struct _PulseSource
+{
+ PulseStream parent;
+
+ PulseSourcePrivate *priv;
+};
+
+struct _PulseSourceClass
+{
+ PulseStreamClass parent;
+};
+
+GType pulse_source_get_type (void) G_GNUC_CONST;
+
+PulseStream *pulse_source_new (PulseConnection *connection,
+ const pa_source_info *info);
+
+gboolean pulse_source_update (PulseStream *stream,
+ const pa_source_info *info);
+
+G_END_DECLS
+
+#endif /* PULSE_SOURCE_H */
diff --git a/backends/pulse/pulse-stream.c b/backends/pulse/pulse-stream.c
index a9e01d1..529f2c9 100644
--- a/backends/pulse/pulse-stream.c
+++ b/backends/pulse/pulse-stream.c
@@ -17,69 +17,178 @@
#include <glib.h>
#include <glib-object.h>
+#include <string.h>
+#include <libmatemixer/matemixer-device.h>
+#include <libmatemixer/matemixer-enums.h>
#include <libmatemixer/matemixer-stream.h>
#include <libmatemixer/matemixer-port.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
+#include "pulse-helpers.h"
#include "pulse-stream.h"
-struct _MateMixerPulseStreamPrivate
-{
- guint32 index;
- gchar *name;
- gchar *description;
- gchar *icon;
- guint channels;
- gboolean mute;
- GList *ports;
- MateMixerPort *port;
- MateMixerPulseConnection *connection;
+struct _PulseStreamPrivate
+{
+ guint32 index;
+ guint32 index_device;
+ gchar *name;
+ gchar *description;
+ gchar *icon;
+ MateMixerDevice *device;
+ MateMixerStreamFlags flags;
+ MateMixerStreamStatus status;
+ gboolean mute;
+ pa_cvolume volume;
+ pa_volume_t volume_base;
+ guint32 volume_steps;
+ pa_channel_map channel_map;
+ gdouble balance;
+ gdouble fade;
+ GList *ports;
+ MateMixerPort *port;
+ PulseConnection *connection;
};
enum
{
PROP_0,
- PROP_INDEX,
PROP_NAME,
PROP_DESCRIPTION,
PROP_ICON,
- PROP_CHANNELS,
- PROP_VOLUME,
+ PROP_DEVICE,
+ PROP_FLAGS,
+ PROP_STATUS,
PROP_MUTE,
+ PROP_NUM_CHANNELS,
+ PROP_VOLUME,
+ PROP_VOLUME_DB,
+ PROP_BALANCE,
+ PROP_FADE,
+ PROP_ACTIVE_PORT,
+ PROP_INDEX,
+ PROP_CONNECTION,
N_PROPERTIES
};
-static void mate_mixer_stream_interface_init (MateMixerStreamInterface *iface);
-static void mate_mixer_pulse_stream_class_init (MateMixerPulseStreamClass *klass);
-static void mate_mixer_pulse_stream_init (MateMixerPulseStream *stream);
-static void mate_mixer_pulse_stream_dispose (GObject *object);
-static void mate_mixer_pulse_stream_finalize (GObject *object);
-
-G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MateMixerPulseStream, mate_mixer_pulse_stream, G_TYPE_OBJECT,
+static void mate_mixer_stream_interface_init (MateMixerStreamInterface *iface);
+static void pulse_stream_class_init (PulseStreamClass *klass);
+static void pulse_stream_init (PulseStream *stream);
+static void pulse_stream_dispose (GObject *object);
+static void pulse_stream_finalize (GObject *object);
+
+/* Interface implementation */
+static const gchar * stream_get_name (MateMixerStream *stream);
+static const gchar * stream_get_description (MateMixerStream *stream);
+static const gchar * stream_get_icon (MateMixerStream *stream);
+static MateMixerDevice * stream_get_device (MateMixerStream *stream);
+static MateMixerStreamFlags stream_get_flags (MateMixerStream *stream);
+static MateMixerStreamStatus stream_get_status (MateMixerStream *stream);
+static gboolean stream_get_mute (MateMixerStream *stream);
+static gboolean stream_set_mute (MateMixerStream *stream,
+ gboolean mute);
+static guint stream_get_num_channels (MateMixerStream *stream);
+static gint64 stream_get_volume (MateMixerStream *stream);
+static gboolean stream_set_volume (MateMixerStream *stream,
+ gint64 volume);
+static gdouble stream_get_volume_db (MateMixerStream *stream);
+static gboolean stream_set_volume_db (MateMixerStream *stream,
+ gdouble volume_db);
+static MateMixerChannelPosition stream_get_channel_position (MateMixerStream *stream,
+ guint channel);
+static gint64 stream_get_channel_volume (MateMixerStream *stream,
+ guint channel);
+static gboolean stream_set_channel_volume (MateMixerStream *stream,
+ guint channel,
+ gint64 volume);
+static gdouble stream_get_channel_volume_db (MateMixerStream *stream,
+ guint channel);
+static gboolean stream_set_channel_volume_db (MateMixerStream *stream,
+ guint channel,
+ gdouble volume_db);
+static gboolean stream_has_position (MateMixerStream *stream,
+ MateMixerChannelPosition position);
+static gint64 stream_get_position_volume (MateMixerStream *stream,
+ MateMixerChannelPosition position);
+static gboolean stream_set_position_volume (MateMixerStream *stream,
+ MateMixerChannelPosition position,
+ gint64 volume);
+static gdouble stream_get_position_volume_db (MateMixerStream *stream,
+ MateMixerChannelPosition position);
+static gboolean stream_set_position_volume_db (MateMixerStream *stream,
+ MateMixerChannelPosition position,
+ gdouble volume_db);
+static gdouble stream_get_balance (MateMixerStream *stream);
+static gboolean stream_set_balance (MateMixerStream *stream,
+ gdouble balance);
+static gdouble stream_get_fade (MateMixerStream *stream);
+static gboolean stream_set_fade (MateMixerStream *stream,
+ gdouble fade);
+static gboolean stream_suspend (MateMixerStream *stream);
+static gboolean stream_resume (MateMixerStream *stream);
+static const GList * stream_list_ports (MateMixerStream *stream);
+static MateMixerPort * stream_get_active_port (MateMixerStream *stream);
+static gboolean stream_set_active_port (MateMixerStream *stream,
+ const gchar *port);
+static gint64 stream_get_min_volume (MateMixerStream *stream);
+static gint64 stream_get_max_volume (MateMixerStream *stream);
+static gint64 stream_get_normal_volume (MateMixerStream *stream);
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (PulseStream, pulse_stream, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_STREAM,
mate_mixer_stream_interface_init))
static void
mate_mixer_stream_interface_init (MateMixerStreamInterface *iface)
{
- iface->get_name = mate_mixer_pulse_stream_get_name;
- iface->get_description = mate_mixer_pulse_stream_get_description;
- iface->get_icon = mate_mixer_pulse_stream_get_icon;
- iface->list_ports = mate_mixer_pulse_stream_list_ports;
+ iface->get_name = stream_get_name;
+ iface->get_description = stream_get_description;
+ iface->get_icon = stream_get_icon;
+ iface->get_device = stream_get_device;
+ iface->get_flags = stream_get_flags;
+ iface->get_status = stream_get_status;
+ iface->get_mute = stream_get_mute;
+ iface->set_mute = stream_set_mute;
+ iface->get_num_channels = stream_get_num_channels;
+ iface->get_volume = stream_get_volume;
+ iface->set_volume = stream_set_volume;
+ iface->get_volume_db = stream_get_volume_db;
+ iface->set_volume_db = stream_set_volume_db;
+ iface->get_channel_position = stream_get_channel_position;
+ iface->get_channel_volume = stream_get_channel_volume;
+ iface->set_channel_volume = stream_set_channel_volume;
+ iface->get_channel_volume_db = stream_get_channel_volume_db;
+ iface->set_channel_volume_db = stream_set_channel_volume_db;
+ iface->has_position = stream_has_position;
+ iface->get_position_volume = stream_get_position_volume;
+ iface->set_position_volume = stream_set_position_volume;
+ iface->get_position_volume_db = stream_get_position_volume_db;
+ iface->set_position_volume_db = stream_set_position_volume_db;
+ iface->get_balance = stream_get_balance;
+ iface->set_balance = stream_set_balance;
+ iface->get_fade = stream_get_fade;
+ iface->set_fade = stream_set_fade;
+ iface->suspend = stream_suspend;
+ iface->resume = stream_resume;
+ iface->list_ports = stream_list_ports;
+ iface->get_active_port = stream_get_active_port;
+ iface->set_active_port = stream_set_active_port;
+ iface->get_min_volume = stream_get_min_volume;
+ iface->get_max_volume = stream_get_max_volume;
+ iface->get_normal_volume = stream_get_normal_volume;
}
static void
-mate_mixer_pulse_stream_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec)
+pulse_stream_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- MateMixerPulseStream *stream;
+ PulseStream *stream;
- stream = MATE_MIXER_PULSE_STREAM (object);
+ stream = PULSE_STREAM (object);
switch (param_id) {
case PROP_NAME:
@@ -91,6 +200,42 @@ mate_mixer_pulse_stream_get_property (GObject *object,
case PROP_ICON:
g_value_set_string (value, stream->priv->icon);
break;
+ case PROP_DEVICE:
+ g_value_set_object (value, stream->priv->device);
+ break;
+ case PROP_FLAGS:
+ g_value_set_flags (value, stream->priv->flags);
+ break;
+ case PROP_STATUS:
+ g_value_set_enum (value, stream->priv->status);
+ break;
+ case PROP_MUTE:
+ g_value_set_boolean (value, stream->priv->mute);
+ break;
+ case PROP_NUM_CHANNELS:
+ g_value_set_uint (value, stream_get_num_channels (MATE_MIXER_STREAM (stream)));
+ break;
+ case PROP_VOLUME:
+ g_value_set_int64 (value, stream_get_volume (MATE_MIXER_STREAM (stream)));
+ break;
+ case PROP_VOLUME_DB:
+ g_value_set_double (value, stream_get_volume_db (MATE_MIXER_STREAM (stream)));
+ break;
+ case PROP_BALANCE:
+ g_value_set_double (value, stream->priv->balance);
+ break;
+ case PROP_FADE:
+ g_value_set_double (value, stream->priv->fade);
+ break;
+ case PROP_ACTIVE_PORT:
+ g_value_set_object (value, stream->priv->port);
+ break;
+ case PROP_INDEX:
+ g_value_set_uint (value, stream->priv->index);
+ break;
+ case PROP_CONNECTION:
+ g_value_set_object (value, stream->priv->connection);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -98,18 +243,18 @@ mate_mixer_pulse_stream_get_property (GObject *object,
}
static void
-mate_mixer_pulse_stream_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec)
+pulse_stream_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- MateMixerPulseStream *stream;
+ PulseStream *stream;
- stream = MATE_MIXER_PULSE_STREAM (object);
+ stream = PULSE_STREAM (object);
switch (param_id) {
case PROP_NAME:
- stream->priv->name = g_strdup (g_value_get_string (value));
+ stream->priv->name = g_strdup (g_value_dup_string (value));
break;
case PROP_DESCRIPTION:
stream->priv->description = g_strdup (g_value_get_string (value));
@@ -117,6 +262,28 @@ mate_mixer_pulse_stream_set_property (GObject *object,
case PROP_ICON:
stream->priv->icon = g_strdup (g_value_get_string (value));
break;
+ case PROP_DEVICE:
+ // XXX may be NULL and the device may become known after the stream,
+ // figure this out..
+ // stream->priv->device = g_object_ref (g_value_get_object (value));
+ break;
+ case PROP_FLAGS:
+ stream->priv->flags = g_value_get_flags (value);
+ break;
+ case PROP_STATUS:
+ stream->priv->status = g_value_get_enum (value);
+ break;
+ case PROP_MUTE:
+ stream->priv->mute = g_value_get_boolean (value);
+ break;
+ case PROP_INDEX:
+ stream->priv->index = g_value_get_uint (value);
+ break;
+ case PROP_CONNECTION:
+ stream->priv->connection = g_value_dup_object (value);
+ break;
+ case PROP_ACTIVE_PORT:
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -124,136 +291,670 @@ mate_mixer_pulse_stream_set_property (GObject *object,
}
static void
-mate_mixer_pulse_stream_class_init (MateMixerPulseStreamClass *klass)
+pulse_stream_class_init (PulseStreamClass *klass)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = mate_mixer_pulse_stream_dispose;
- object_class->finalize = mate_mixer_pulse_stream_finalize;
- object_class->get_property = mate_mixer_pulse_stream_get_property;
- object_class->set_property = mate_mixer_pulse_stream_set_property;
+ object_class->dispose = pulse_stream_dispose;
+ object_class->finalize = pulse_stream_finalize;
+ object_class->get_property = pulse_stream_get_property;
+ object_class->set_property = pulse_stream_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_INDEX,
+ g_param_spec_uint ("index",
+ "Index",
+ "Stream index",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class,
+ PROP_CONNECTION,
+ g_param_spec_object ("connection",
+ "Connection",
+ "PulseAudio connection",
+ PULSE_TYPE_CONNECTION,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
g_object_class_override_property (object_class, PROP_NAME, "name");
g_object_class_override_property (object_class, PROP_DESCRIPTION, "description");
g_object_class_override_property (object_class, PROP_ICON, "icon");
-
- g_type_class_add_private (object_class, sizeof (MateMixerPulseStreamPrivate));
+ g_object_class_override_property (object_class, PROP_DEVICE, "device");
+ g_object_class_override_property (object_class, PROP_FLAGS, "flags");
+ g_object_class_override_property (object_class, PROP_STATUS, "status");
+ g_object_class_override_property (object_class, PROP_MUTE, "mute");
+ g_object_class_override_property (object_class, PROP_NUM_CHANNELS, "num-channels");
+ g_object_class_override_property (object_class, PROP_VOLUME, "volume");
+ g_object_class_override_property (object_class, PROP_VOLUME_DB, "volume-db");
+ g_object_class_override_property (object_class, PROP_BALANCE, "balance");
+ g_object_class_override_property (object_class, PROP_FADE, "fade");
+ g_object_class_override_property (object_class, PROP_ACTIVE_PORT, "active-port");
+
+ g_type_class_add_private (object_class, sizeof (PulseStreamPrivate));
}
static void
-mate_mixer_pulse_stream_init (MateMixerPulseStream *stream)
+pulse_stream_init (PulseStream *stream)
{
- stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (
- stream,
- MATE_MIXER_TYPE_PULSE_STREAM,
- MateMixerPulseStreamPrivate);
+ stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
+ PULSE_TYPE_STREAM,
+ PulseStreamPrivate);
}
static void
-mate_mixer_pulse_stream_dispose (GObject *object)
+pulse_stream_dispose (GObject *object)
{
- MateMixerPulseStream *stream;
+ PulseStream *stream;
- stream = MATE_MIXER_PULSE_STREAM (object);
+ stream = PULSE_STREAM (object);
if (stream->priv->ports) {
g_list_free_full (stream->priv->ports, g_object_unref);
stream->priv->ports = NULL;
}
+
+ g_clear_object (&stream->priv->port);
+ g_clear_object (&stream->priv->device);
g_clear_object (&stream->priv->connection);
- G_OBJECT_CLASS (mate_mixer_pulse_stream_parent_class)->dispose (object);
+ G_OBJECT_CLASS (pulse_stream_parent_class)->dispose (object);
}
static void
-mate_mixer_pulse_stream_finalize (GObject *object)
+pulse_stream_finalize (GObject *object)
{
- MateMixerPulseStream *stream;
+ PulseStream *stream;
- stream = MATE_MIXER_PULSE_STREAM (object);
+ stream = PULSE_STREAM (object);
g_free (stream->priv->name);
g_free (stream->priv->description);
g_free (stream->priv->icon);
- G_OBJECT_CLASS (mate_mixer_pulse_stream_parent_class)->finalize (object);
+ G_OBJECT_CLASS (pulse_stream_parent_class)->finalize (object);
+}
+
+guint32
+pulse_stream_get_index (PulseStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return stream->priv->index;
}
-MateMixerPulseConnection *
-mate_mixer_pulse_stream_get_connection (MateMixerPulseStream *stream)
+PulseConnection *
+pulse_stream_get_connection (PulseStream *stream)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_STREAM (stream), NULL);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
return stream->priv->connection;
}
-guint32
-mate_mixer_pulse_stream_get_index (MateMixerPulseStream *stream)
+gboolean
+pulse_stream_update_name (PulseStream *stream, const gchar *name)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- return stream->priv->index;
+ /* Allow the name to be NULL */
+ if (g_strcmp0 (name, stream->priv->name)) {
+ g_free (stream->priv->name);
+ stream->priv->name = g_strdup (name);
+
+ g_object_notify (G_OBJECT (stream), "name");
+ }
+ return TRUE;
+}
+
+gboolean
+pulse_stream_update_description (PulseStream *stream, const gchar *description)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ /* Allow the description to be NULL */
+ if (g_strcmp0 (description, stream->priv->description)) {
+ g_free (stream->priv->description);
+ stream->priv->description = g_strdup (description);
+
+ g_object_notify (G_OBJECT (stream), "description");
+ }
+ return TRUE;
}
-const gchar *
-mate_mixer_pulse_stream_get_name (MateMixerStream *stream)
+gboolean
+pulse_stream_update_flags (PulseStream *stream, MateMixerStreamFlags flags)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- return MATE_MIXER_PULSE_STREAM (stream)->priv->name;
+ if (stream->priv->flags != flags) {
+ stream->priv->flags = flags;
+ g_object_notify (G_OBJECT (stream), "flags");
+ }
+ return TRUE;
}
-const gchar *
-mate_mixer_pulse_stream_get_description (MateMixerStream *stream)
+gboolean
+pulse_stream_update_status (PulseStream *stream, MateMixerStreamStatus status)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- return MATE_MIXER_PULSE_STREAM (stream)->priv->description;
+ if (stream->priv->status != status) {
+ stream->priv->status = status;
+ g_object_notify (G_OBJECT (stream), "status");
+ }
+ return TRUE;
}
-const gchar *
-mate_mixer_pulse_stream_get_icon (MateMixerStream *stream)
+gboolean
+pulse_stream_update_mute (PulseStream *stream, gboolean mute)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- return MATE_MIXER_PULSE_STREAM (stream)->priv->icon;
+ if (stream->priv->mute != mute) {
+ stream->priv->mute = mute;
+ g_object_notify (G_OBJECT (stream), "mute");
+ }
+ return TRUE;
}
-MateMixerPort *
-mate_mixer_pulse_stream_get_active_port (MateMixerStream *stream)
+gboolean
+pulse_stream_update_volume (PulseStream *stream, const pa_cvolume *volume)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- return MATE_MIXER_PULSE_STREAM (stream)->priv->port;
+ if (!pa_cvolume_equal (&stream->priv->volume, volume)) {
+ stream->priv->volume = *volume;
+
+ g_object_notify (G_OBJECT (stream), "volume");
+
+ // XXX probably should notify about volume-db too but the flags may
+ // be known later
+ }
+ return TRUE;
}
-const GList *
-mate_mixer_pulse_stream_list_ports (MateMixerStream *stream)
+gboolean
+pulse_stream_update_volume_extended (PulseStream *stream,
+ const pa_cvolume *volume,
+ pa_volume_t volume_base,
+ guint32 volume_steps)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ // XXX use volume_base and volume_steps
+
+ if (!pa_cvolume_equal (&stream->priv->volume, volume)) {
+ stream->priv->volume = *volume;
+
+ g_object_notify (G_OBJECT (stream), "volume");
- return MATE_MIXER_PULSE_STREAM (stream)->priv->ports;
+ // XXX probably should notify about volume-db too but the flags may
+ // be known later
+ }
+
+ stream->priv->volume_base = volume_base;
+ stream->priv->volume_steps = volume_steps;
+ return TRUE;
}
gboolean
-mate_mixer_pulse_stream_set_volume (MateMixerStream *stream, guint32 volume)
+pulse_stream_update_channel_map (PulseStream *stream, const pa_channel_map *map)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- return MATE_MIXER_PULSE_STREAM_GET_CLASS (stream)->set_volume (stream, volume);
+ if (!pa_channel_map_equal (&stream->priv->channel_map, map))
+ stream->priv->channel_map = *map;
+
+ return TRUE;
}
gboolean
-mate_mixer_pulse_stream_set_mute (MateMixerStream *stream, gboolean mute)
+pulse_stream_update_ports (PulseStream *stream, GList *ports)
{
- g_return_val_if_fail (MATE_MIXER_IS_PULSE_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- return MATE_MIXER_PULSE_STREAM_GET_CLASS (stream)->set_mute (stream, mute);
+ /* Right now we do not change the list of ports during update */
+ g_warn_if_fail (stream->priv->ports == NULL);
+
+ stream->priv->ports = ports;
+ return TRUE;
}
gboolean
-mate_mixer_pulse_stream_set_active_port (MateMixerStream *stream, MateMixerPort *port)
+pulse_stream_update_active_port (PulseStream *stream, const gchar *port_name)
{
+ GList *list;
+ MateMixerPort *port = NULL;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ list = stream->priv->ports;
+ while (list) {
+ port = MATE_MIXER_PORT (list->data);
+
+ if (!g_strcmp0 (mate_mixer_port_get_name (port), port_name))
+ break;
+
+ port = NULL;
+ list = list->next;
+ }
+
+ if (stream->priv->port != port) {
+ if (stream->priv->port)
+ g_clear_object (&stream->priv->port);
+ if (port)
+ stream->priv->port = g_object_ref (port);
+
+ g_object_notify (G_OBJECT (stream), "active-port");
+ }
return TRUE;
}
+
+static const gchar *
+stream_get_name (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return PULSE_STREAM (stream)->priv->name;
+}
+
+static const gchar *
+stream_get_description (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return PULSE_STREAM (stream)->priv->description;
+}
+
+static const gchar *
+stream_get_icon (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return PULSE_STREAM (stream)->priv->icon;
+}
+
+static MateMixerDevice *
+stream_get_device (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return PULSE_STREAM (stream)->priv->device;
+}
+
+static MateMixerStreamFlags
+stream_get_flags (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return PULSE_STREAM (stream)->priv->flags;
+}
+
+static MateMixerStreamStatus
+stream_get_status (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return PULSE_STREAM (stream)->priv->status;
+}
+
+static gboolean
+stream_get_mute (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return PULSE_STREAM (stream)->priv->mute;
+}
+
+static gboolean
+stream_set_mute (MateMixerStream *stream, gboolean mute)
+{
+ PulseStream *ps;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ ps = PULSE_STREAM (stream);
+
+ if (ps->priv->mute == mute)
+ return TRUE;
+
+ return PULSE_STREAM_GET_CLASS (stream)->set_mute (stream, mute);
+}
+
+static guint
+stream_get_num_channels (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return PULSE_STREAM (stream)->priv->volume.channels;
+}
+
+static gint64
+stream_get_volume (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return (gint64) pa_cvolume_max (&PULSE_STREAM (stream)->priv->volume);
+}
+
+static gboolean
+stream_set_volume (MateMixerStream *stream, gint64 volume)
+{
+ pa_cvolume cvolume;
+ PulseStream *ps;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ ps = PULSE_STREAM (stream);
+ cvolume = ps->priv->volume;
+
+ if (pa_cvolume_scale (&cvolume, (pa_volume_t) volume) == NULL) {
+ g_warning ("Invalid PulseAudio volume value %" G_GINT64_FORMAT, volume);
+ return FALSE;
+ }
+
+ /* This is the only function which passes a volume request to the real class, so
+ * all the pa_cvolume validations are only done here */
+
+
+
+ return PULSE_STREAM_GET_CLASS (stream)->set_volume (stream, &cvolume);
+}
+
+static gdouble
+stream_get_volume_db (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0);
+
+ if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
+ return FALSE;
+
+ return pa_sw_volume_to_dB (stream_get_volume (stream));
+}
+
+static gboolean
+stream_set_volume_db (MateMixerStream *stream, gdouble volume_db)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
+ return FALSE;
+
+ return stream_set_volume (stream, pa_sw_volume_from_dB (volume_db));
+}
+
+static MateMixerChannelPosition
+stream_get_channel_position (MateMixerStream *stream, guint channel)
+{
+ PulseStream *ps;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ ps = PULSE_STREAM (stream);
+
+ if (channel >= ps->priv->channel_map.channels) {
+ g_warning ("Invalid channel %u of stream %s", channel, ps->priv->name);
+ return MATE_MIXER_CHANNEL_UNKNOWN_POSITION;
+ }
+ return pulse_convert_position_to_pulse (ps->priv->channel_map.map[channel]);
+}
+
+static gint64
+stream_get_channel_volume (MateMixerStream *stream, guint channel)
+{
+ PulseStream *ps;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ ps = PULSE_STREAM (stream);
+
+ if (channel >= ps->priv->volume.channels) {
+ g_warning ("Invalid channel %u of stream %s", channel, ps->priv->name);
+ return stream_get_min_volume (stream);
+ }
+ return (gint64) ps->priv->volume.values[channel];
+}
+
+static gboolean
+stream_set_channel_volume (MateMixerStream *stream, guint channel, gint64 volume)
+{
+ pa_cvolume cvolume;
+ PulseStream *pstream;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ pstream = PULSE_STREAM (stream);
+ cvolume = pstream->priv->volume;
+
+ if (channel >= pstream->priv->volume.channels) {
+ g_warning ("Invalid channel %u of stream %s", channel, pstream->priv->name);
+ return FALSE;
+ }
+
+ cvolume.values[channel] = (pa_volume_t) volume;
+
+ if (!pa_cvolume_valid (&cvolume)) {
+ g_warning ("Invalid PulseAudio volume value %" G_GINT64_FORMAT, volume);
+ return FALSE;
+ }
+ return PULSE_STREAM_GET_CLASS (stream)->set_volume (stream, &cvolume);
+}
+
+static gdouble
+stream_get_channel_volume_db (MateMixerStream *stream, guint channel)
+{
+ PulseStream *pstream;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0);
+
+ pstream = PULSE_STREAM (stream);
+
+ if (channel >= pstream->priv->volume.channels) {
+ g_warning ("Invalid channel %u of stream %s", channel, pstream->priv->name);
+ return 0.0;
+ }
+ return pa_sw_volume_to_dB (pstream->priv->volume.values[channel]);
+}
+
+static gboolean
+stream_set_channel_volume_db (MateMixerStream *stream,
+ guint channel,
+ gdouble volume_db)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return stream_set_channel_volume (stream,
+ channel,
+ pa_sw_volume_from_dB (volume_db));
+}
+
+static gboolean
+stream_has_position (MateMixerStream *stream, MateMixerChannelPosition position)
+{
+ PulseStreamPrivate *priv;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ priv = PULSE_STREAM (stream)->priv;
+
+ return pa_channel_map_has_position (&priv->channel_map,
+ pulse_convert_position_to_pulse (position));
+}
+
+static gint64
+stream_get_position_volume (MateMixerStream *stream,
+ MateMixerChannelPosition position)
+{
+ PulseStreamPrivate *priv;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
+
+ priv = PULSE_STREAM (stream)->priv;
+
+ return pa_cvolume_get_position (&priv->volume,
+ &priv->channel_map,
+ pulse_convert_position_to_pulse (position));
+}
+
+static gboolean
+stream_set_position_volume (MateMixerStream *stream,
+ MateMixerChannelPosition position,
+ gint64 volume)
+{
+ PulseStreamPrivate *priv;
+ pa_cvolume cvolume;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ priv = PULSE_STREAM (stream)->priv;
+ cvolume = priv->volume;
+
+ if (!pa_cvolume_set_position (&cvolume,
+ &priv->channel_map,
+ pulse_convert_position_to_pulse (position),
+ (pa_volume_t) volume)) {
+ return FALSE;
+ }
+ return PULSE_STREAM_GET_CLASS (stream)->set_volume (stream, &cvolume);
+}
+
+static gdouble
+stream_get_position_volume_db (MateMixerStream *stream,
+ MateMixerChannelPosition position)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0);
+
+ return pa_sw_volume_to_dB (stream_get_position_volume (stream, position));
+}
+
+static gboolean
+stream_set_position_volume_db (MateMixerStream *stream,
+ MateMixerChannelPosition position,
+ gdouble volume_db)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return stream_set_position_volume (stream, position, pa_sw_volume_from_dB (volume_db));
+}
+
+static gdouble
+stream_get_balance (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0);
+
+ return PULSE_STREAM (stream)->priv->balance;
+}
+
+static gboolean
+stream_set_balance (MateMixerStream *stream, gdouble balance)
+{
+ PulseStream *pstream;
+ pa_cvolume cvolume;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ pstream = PULSE_STREAM (stream);
+ cvolume = pstream->priv->volume;
+
+ if (balance == pstream->priv->balance)
+ return TRUE;
+
+ if (pa_cvolume_set_balance (&cvolume,
+ &pstream->priv->channel_map,
+ (float) balance) == NULL) {
+ return FALSE;
+ }
+ return PULSE_STREAM_GET_CLASS (stream)->set_volume (stream, &cvolume);
+}
+
+static gdouble
+stream_get_fade (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return PULSE_STREAM (stream)->priv->fade;
+}
+
+static gboolean
+stream_set_fade (MateMixerStream *stream, gdouble fade)
+{
+ pa_cvolume cvolume;
+ PulseStream *pstream;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ pstream = PULSE_STREAM (stream);
+ cvolume = pstream->priv->volume;
+
+ if (fade == pstream->priv->fade)
+ return TRUE;
+
+ if (pa_cvolume_set_fade (&cvolume,
+ &pstream->priv->channel_map,
+ (float) fade) == NULL) {
+ return FALSE;
+ }
+ return PULSE_STREAM_GET_CLASS (stream)->set_volume (stream, &cvolume);
+}
+
+static gboolean
+stream_suspend (MateMixerStream *stream)
+{
+ // TODO
+ return TRUE;
+}
+
+static gboolean
+stream_resume (MateMixerStream *stream)
+{
+ // TODO
+ return TRUE;
+}
+
+static const GList *
+stream_list_ports (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return (const GList *) PULSE_STREAM (stream)->priv->ports;
+}
+
+static MateMixerPort *
+stream_get_active_port (MateMixerStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ return PULSE_STREAM (stream)->priv->port;
+}
+
+static gboolean
+stream_set_active_port (MateMixerStream *stream, const gchar *port_name)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (port_name != NULL, FALSE);
+
+ return PULSE_STREAM_GET_CLASS (stream)->set_active_port (stream, port_name);
+}
+
+static gint64
+stream_get_min_volume (MateMixerStream *stream)
+{
+ return (gint64) PA_VOLUME_MUTED;
+}
+
+static gint64
+stream_get_max_volume (MateMixerStream *stream)
+{
+ return (gint64) PA_VOLUME_UI_MAX;
+}
+
+static gint64
+stream_get_normal_volume (MateMixerStream *stream)
+{
+ return (gint64) PA_VOLUME_NORM;
+}
diff --git a/backends/pulse/pulse-stream.h b/backends/pulse/pulse-stream.h
index 3d3ee78..49eac42 100644
--- a/backends/pulse/pulse-stream.h
+++ b/backends/pulse/pulse-stream.h
@@ -15,14 +15,13 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef MATEMIXER_PULSE_STREAM_H
-#define MATEMIXER_PULSE_STREAM_H
+#ifndef PULSE_STREAM_H
+#define PULSE_STREAM_H
#include <glib.h>
#include <glib-object.h>
#include <libmatemixer/matemixer-stream.h>
-#include <libmatemixer/matemixer-port.h>
#include <pulse/pulseaudio.h>
@@ -30,57 +29,71 @@
G_BEGIN_DECLS
-#define MATE_MIXER_TYPE_PULSE_STREAM \
- (mate_mixer_pulse_stream_get_type ())
-#define MATE_MIXER_PULSE_STREAM(o) \
- (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_PULSE_STREAM, MateMixerPulseStream))
-#define MATE_MIXER_IS_PULSE_STREAM(o) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_PULSE_STREAM))
-#define MATE_MIXER_PULSE_STREAM_CLASS(k) \
- (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_PULSE_STREAM, MateMixerPulseStreamClass))
-#define MATE_MIXER_IS_PULSE_STREAM_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_PULSE_STREAM))
-#define MATE_MIXER_PULSE_STREAM_GET_CLASS(o) \
- (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_PULSE_STREAM, MateMixerPulseStreamClass))
-
-typedef struct _MateMixerPulseStream MateMixerPulseStream;
-typedef struct _MateMixerPulseStreamClass MateMixerPulseStreamClass;
-typedef struct _MateMixerPulseStreamPrivate MateMixerPulseStreamPrivate;
-
-struct _MateMixerPulseStream
+#define PULSE_TYPE_STREAM \
+ (pulse_stream_get_type ())
+#define PULSE_STREAM(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_STREAM, PulseStream))
+#define PULSE_IS_STREAM(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_STREAM))
+#define PULSE_STREAM_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_STREAM, PulseStreamClass))
+#define PULSE_IS_STREAM_CLASS(k) \
+ (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_STREAM))
+#define PULSE_STREAM_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_STREAM, PulseStreamClass))
+
+typedef struct _PulseStream PulseStream;
+typedef struct _PulseStreamClass PulseStreamClass;
+typedef struct _PulseStreamPrivate PulseStreamPrivate;
+
+struct _PulseStream
{
- GObject parent;
-
- MateMixerPulseStreamPrivate *priv;
+ /*< private >*/
+ GObject parent;
+ PulseStreamPrivate *priv;
};
-struct _MateMixerPulseStreamClass
+struct _PulseStreamClass
{
- GObjectClass parent;
-
- gboolean (*set_volume) (MateMixerStream *stream, guint32 volume);
- gboolean (*set_mute) (MateMixerStream *stream, gboolean mute);
+ /*< private >*/
+ GObjectClass parent;
+
+ gboolean (*set_mute) (MateMixerStream *stream,
+ gboolean mute);
+ gboolean (*set_volume) (MateMixerStream *stream,
+ pa_cvolume *volume);
+ gboolean (*set_active_port) (MateMixerStream *stream,
+ const gchar *port_name);
};
-GType mate_mixer_pulse_stream_get_type (void) G_GNUC_CONST;
-
-MateMixerPulseConnection * mate_mixer_pulse_stream_get_connection (MateMixerPulseStream *stream);
-guint32 mate_mixer_pulse_stream_get_index (MateMixerPulseStream *stream);
-
-/* Interface implementation */
-const gchar * mate_mixer_pulse_stream_get_name (MateMixerStream *stream);
-const gchar * mate_mixer_pulse_stream_get_description (MateMixerStream *stream);
-const gchar * mate_mixer_pulse_stream_get_icon (MateMixerStream *stream);
-
-MateMixerPort * mate_mixer_pulse_stream_get_active_port (MateMixerStream *stream);
-gboolean mate_mixer_pulse_stream_set_active_port (MateMixerStream *stream,
- MateMixerPort *port);
-const GList * mate_mixer_pulse_stream_list_ports (MateMixerStream *stream);
-gboolean mate_mixer_pulse_stream_set_mute (MateMixerStream *stream,
- gboolean mute);
-gboolean mate_mixer_pulse_stream_set_volume (MateMixerStream *stream,
- guint32 volume);
+GType pulse_stream_get_type (void) G_GNUC_CONST;
+
+guint32 pulse_stream_get_index (PulseStream *stream);
+PulseConnection *pulse_stream_get_connection (PulseStream *stream);
+
+gboolean pulse_stream_update_name (PulseStream *stream,
+ const gchar *name);
+gboolean pulse_stream_update_description (PulseStream *stream,
+ const gchar *description);
+gboolean pulse_stream_update_flags (PulseStream *stream,
+ MateMixerStreamFlags flags);
+gboolean pulse_stream_update_status (PulseStream *stream,
+ MateMixerStreamStatus status);
+gboolean pulse_stream_update_mute (PulseStream *stream,
+ gboolean mute);
+gboolean pulse_stream_update_volume (PulseStream *stream,
+ const pa_cvolume *volume);
+gboolean pulse_stream_update_volume_extended (PulseStream *stream,
+ const pa_cvolume *volume,
+ pa_volume_t volume_base,
+ guint32 volume_steps);
+gboolean pulse_stream_update_channel_map (PulseStream *stream,
+ const pa_channel_map *map);
+gboolean pulse_stream_update_ports (PulseStream *stream,
+ GList *ports);
+gboolean pulse_stream_update_active_port (PulseStream *stream,
+ const gchar *port_name);
G_END_DECLS
-#endif /* MATEMIXER_PULSE_STREAM_H */
+#endif /* PULSE_STREAM_H */
diff --git a/backends/pulse/pulse.c b/backends/pulse/pulse.c
deleted file mode 100644
index 59c5935..0000000
--- a/backends/pulse/pulse.c
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (C) 2014 Michal Ratajsky <[email protected]>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the licence, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <libmatemixer/matemixer-backend.h>
-#include <libmatemixer/matemixer-backend-module.h>
-
-#include <pulse/pulseaudio.h>
-#include <pulse/thread-mainloop.h>
-
-#include "pulse.h"
-#include "pulse-connection.h"
-#include "pulse-device.h"
-#include "pulse-stream.h"
-#include "pulse-sink.h"
-
-#define BACKEND_NAME "PulseAudio"
-#define BACKEND_PRIORITY 0
-
-struct _MateMixerPulsePrivate
-{
- GHashTable *devices;
- gboolean lists_loaded;
- GHashTable *cards;
- GHashTable *sinks;
- GHashTable *sink_inputs;
- GHashTable *sources;
- GHashTable *source_outputs;
- MateMixerPulseConnection *connection;
-};
-
-/* Support function for dynamic loading of the backend module */
-void backend_module_init (GTypeModule *module);
-
-const MateMixerBackendInfo *backend_module_get_info (void);
-
-static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface);
-
-static void pulse_card_cb (MateMixerPulseConnection *connection,
- const pa_card_info *info,
- MateMixerPulse *pulse);
-
-static void pulse_sink_cb (MateMixerPulseConnection *connection,
- const pa_sink_info *info,
- MateMixerPulse *pulse);
-
-static void pulse_sink_input_cb (MateMixerPulseConnection *connection,
- const pa_sink_input_info *info,
- MateMixerPulse *pulse);
-
-static void pulse_source_cb (MateMixerPulseConnection *connection,
- const pa_source_info *info,
- MateMixerPulse *pulse);
-
-static void pulse_source_output_cb (MateMixerPulseConnection *connection,
- const pa_source_output_info *info,
- MateMixerPulse *pulse);
-
-G_DEFINE_DYNAMIC_TYPE_EXTENDED (MateMixerPulse, mate_mixer_pulse,
- G_TYPE_OBJECT, 0,
- G_IMPLEMENT_INTERFACE_DYNAMIC (MATE_MIXER_TYPE_BACKEND,
- mate_mixer_backend_interface_init))
-
-static MateMixerBackendInfo info;
-
-void
-backend_module_init (GTypeModule *module)
-{
- mate_mixer_pulse_register_type (module);
-
- info.name = BACKEND_NAME;
- info.priority = BACKEND_PRIORITY;
- info.g_type = MATE_MIXER_TYPE_PULSE;
- info.backend_type = MATE_MIXER_BACKEND_PULSE;
-}
-
-const MateMixerBackendInfo *
-backend_module_get_info (void)
-{
- return &info;
-}
-
-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;
-}
-
-static void
-mate_mixer_pulse_init (MateMixerPulse *pulse)
-{
- pulse->priv = G_TYPE_INSTANCE_GET_PRIVATE (
- pulse,
- MATE_MIXER_TYPE_PULSE,
- MateMixerPulsePrivate);
-
- pulse->priv->devices = g_hash_table_new_full (
- g_direct_hash,
- g_direct_equal,
- NULL,
- g_object_unref);
-
- pulse->priv->cards = g_hash_table_new_full (
- g_direct_hash,
- g_direct_equal,
- NULL,
- g_object_unref);
- pulse->priv->sinks = g_hash_table_new_full (
- g_direct_hash,
- g_direct_equal,
- NULL,
- g_object_unref);
- pulse->priv->sink_inputs = g_hash_table_new_full (
- g_direct_hash,
- g_direct_equal,
- NULL,
- g_object_unref);
- pulse->priv->sources = g_hash_table_new_full (
- g_direct_hash,
- g_direct_equal,
- NULL,
- g_object_unref);
- pulse->priv->source_outputs = g_hash_table_new_full (
- g_direct_hash,
- g_direct_equal,
- NULL,
- g_object_unref);
-}
-
-static void
-mate_mixer_pulse_dispose (GObject *object)
-{
- MateMixerPulse *pulse;
-
- pulse = MATE_MIXER_PULSE (object);
-
- if (pulse->priv->devices) {
- g_hash_table_destroy (pulse->priv->devices);
- pulse->priv->devices = NULL;
- }
-
- if (pulse->priv->cards) {
- g_hash_table_destroy (pulse->priv->cards);
- pulse->priv->cards = NULL;
- }
- if (pulse->priv->sinks) {
- g_hash_table_destroy (pulse->priv->sinks);
- pulse->priv->devices = NULL;
- }
- if (pulse->priv->sink_inputs) {
- g_hash_table_destroy (pulse->priv->sink_inputs);
- pulse->priv->devices = NULL;
- }
- if (pulse->priv->sources) {
- g_hash_table_destroy (pulse->priv->sources);
- pulse->priv->devices = NULL;
- }
- if (pulse->priv->source_outputs) {
- g_hash_table_destroy (pulse->priv->source_outputs);
- pulse->priv->source_outputs = NULL;
- }
-
- g_clear_object (&pulse->priv->connection);
-
- G_OBJECT_CLASS (mate_mixer_pulse_parent_class)->dispose (object);
-}
-
-static void
-mate_mixer_pulse_class_init (MateMixerPulseClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = mate_mixer_pulse_dispose;
-
- g_type_class_add_private (object_class, sizeof (MateMixerPulsePrivate));
-}
-
-/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE_EXTENDED() */
-static void
-mate_mixer_pulse_class_finalize (MateMixerPulseClass *klass)
-{
-}
-
-gboolean
-mate_mixer_pulse_open (MateMixerBackend *backend)
-{
- MateMixerPulse *pulse;
- MateMixerPulseConnection *connection;
-
- g_return_val_if_fail (MATE_MIXER_IS_PULSE (backend), FALSE);
-
- pulse = MATE_MIXER_PULSE (backend);
-
- g_return_val_if_fail (pulse->priv->connection == NULL, FALSE);
-
- connection = mate_mixer_pulse_connection_new (NULL, NULL);
- if (G_UNLIKELY (connection == NULL)) {
- g_object_unref (connection);
- return FALSE;
- }
-
- if (!mate_mixer_pulse_connection_connect (connection)) {
- g_object_unref (connection);
- return FALSE;
- }
-
- g_signal_connect (connection,
- "list-item-card",
- G_CALLBACK (pulse_card_cb),
- pulse);
- g_signal_connect (connection,
- "list-item-sink",
- G_CALLBACK (pulse_sink_cb),
- pulse);
- g_signal_connect (connection,
- "list-item-sink-input",
- G_CALLBACK (pulse_sink_input_cb),
- pulse);
- g_signal_connect (connection,
- "list-item-source",
- G_CALLBACK (pulse_source_cb),
- pulse);
- g_signal_connect (connection,
- "list-item-source-output",
- G_CALLBACK (pulse_source_output_cb),
- pulse);
-
- pulse->priv->connection = connection;
- return TRUE;
-}
-
-void
-mate_mixer_pulse_close (MateMixerBackend *backend)
-{
- MateMixerPulse *pulse;
-
- g_return_if_fail (MATE_MIXER_IS_PULSE (backend));
-
- pulse = MATE_MIXER_PULSE (backend);
-
- g_clear_object (&pulse->priv->connection);
-}
-
-static gboolean
-pulse_load_lists (MateMixerPulse *pulse)
-{
- /* The Pulse server is queried for initial lists, each of the functions
- * waits until the list is available and then continues with the next.
- *
- * One possible improvement would be to load the lists asynchronously right
- * after we connect to Pulse and when the application calls one of the
- * list_* () functions, check if the initial list is already available and
- * eventually wait until it's available. However, this would be
- * tricky with the way the Pulse API is currently used and might not
- * be beneficial at all.
- */
-
- // XXX figure out how to handle server reconnects, ideally everything
- // we know should be ditched and read again asynchronously and
- // the user should only be notified about actual differences
- // from the state before we were disconnected
-
- // mate_mixer_pulse_connection_get_server_info (pulse->priv->connection);
- mate_mixer_pulse_connection_get_card_list (pulse->priv->connection);
- mate_mixer_pulse_connection_get_sink_list (pulse->priv->connection);
- mate_mixer_pulse_connection_get_sink_input_list (pulse->priv->connection);
- mate_mixer_pulse_connection_get_source_list (pulse->priv->connection);
- mate_mixer_pulse_connection_get_source_output_list (pulse->priv->connection);
-
- return TRUE;
-}
-
-GList *
-mate_mixer_pulse_list_devices (MateMixerBackend *backend)
-{
- MateMixerPulse *pulse;
- GList *list;
-
- g_return_val_if_fail (MATE_MIXER_IS_PULSE (backend), NULL);
-
- pulse = MATE_MIXER_PULSE (backend);
-
- if (!pulse->priv->lists_loaded)
- pulse_load_lists (pulse);
-
- list = g_hash_table_get_values (pulse->priv->devices);
-
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
- return list;
-}
-
-GList *
-mate_mixer_pulse_list_streams (MateMixerBackend *backend)
-{
- // TODO
- return NULL;
-}
-
-static void
-pulse_card_cb (MateMixerPulseConnection *connection,
- const pa_card_info *info,
- MateMixerPulse *pulse)
-{
- MateMixerPulseDevice *device;
-
- device = mate_mixer_pulse_device_new (connection, info);
- if (G_LIKELY (device))
- g_hash_table_insert (
- pulse->priv->devices,
- GINT_TO_POINTER (mate_mixer_pulse_device_get_index (device)),
- device);
-}
-
-static void
-pulse_sink_cb (MateMixerPulseConnection *connection,
- const pa_sink_info *info,
- MateMixerPulse *pulse)
-{
- MateMixerPulseStream *stream;
-
- stream = mate_mixer_pulse_sink_new (connection, info);
- if (G_LIKELY (stream))
- g_hash_table_insert (
- pulse->priv->sinks,
- GINT_TO_POINTER (mate_mixer_pulse_stream_get_index (stream)),
- stream);
-}
-
-static void
-pulse_sink_input_cb (MateMixerPulseConnection *connection,
- const pa_sink_input_info *info,
- MateMixerPulse *pulse)
-{
-
-}
-
-static void
-pulse_source_cb (MateMixerPulseConnection *connection,
- const pa_source_info *info,
- MateMixerPulse *pulse)
-{
-
-}
-
-static void
-pulse_source_output_cb (MateMixerPulseConnection *connection,
- const pa_source_output_info *info,
- MateMixerPulse *pulse)
-{
-
-}
diff --git a/backends/pulse/pulse.h b/backends/pulse/pulse.h
deleted file mode 100644
index d94a543..0000000
--- a/backends/pulse/pulse.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2014 Michal Ratajsky <[email protected]>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the licence, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MATEMIXER_PULSE_H
-#define MATEMIXER_PULSE_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <libmatemixer/matemixer-backend.h>
-
-#define MATE_MIXER_TYPE_PULSE \
- (mate_mixer_pulse_get_type ())
-#define MATE_MIXER_PULSE(o) \
- (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_PULSE, MateMixerPulse))
-#define MATE_MIXER_IS_PULSE(o) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_PULSE))
-#define MATE_MIXER_PULSE_CLASS(k) \
- (G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_PULSE, MateMixerPulseClass))
-#define MATE_MIXER_IS_PULSE_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_PULSE))
-#define MATE_MIXER_PULSE_GET_CLASS(o) \
- (G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_PULSE, MateMixerPulseClass))
-
-typedef struct _MateMixerPulse MateMixerPulse;
-typedef struct _MateMixerPulseClass MateMixerPulseClass;
-typedef struct _MateMixerPulsePrivate MateMixerPulsePrivate;
-
-struct _MateMixerPulse
-{
- GObject parent;
-
- MateMixerPulsePrivate *priv;
-};
-
-struct _MateMixerPulseClass
-{
- GObjectClass parent;
-};
-
-GType mate_mixer_pulse_get_type (void) G_GNUC_CONST;
-
-/* Interface implementation */
-gboolean mate_mixer_pulse_open (MateMixerBackend *backend);
-void mate_mixer_pulse_close (MateMixerBackend *backend);
-GList *mate_mixer_pulse_list_devices (MateMixerBackend *backend);
-GList *mate_mixer_pulse_list_streams (MateMixerBackend *backend);
-
-#endif /* MATEMIXER_PULSE_H */
diff --git a/configure.ac b/configure.ac
index e004f47..4925691 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,27 @@
+dnl Process this file with autoconf to produce a configure script.
+
AC_PREREQ([2.60])
+m4_define(libmatemixer_major_version, 1)
+m4_define(libmatemixer_minor_version, 9)
+m4_define(libmatemixer_micro_version, 0)
+m4_define(libmatemixer_interface_age, 0)
+m4_define(libmatemixer_version,
+ [libmatemixer_major_version.libmatemixer_minor_version.libmatemixer_micro_version])
+
AC_INIT([libmatemixer],
- [1.9.0],
+ [libmatemixer_version],
[http://www.mate-desktop.org])
+AC_DEFINE(LIBMATEMIXER_MAJOR_VERSION, libmatemixer_major_version, [Libmatemixer major version])
+AC_DEFINE(LIBMATEMIXER_MINOR_VERSION, libmatemixer_minor_version, [Libmatemixer minor version])
+AC_DEFINE(LIBMATEMIXER_MICRO_VERSION, libmatemixer_micro_version, [Libmatemixer micro version])
+
+AC_SUBST(LIBMATEMIXER_MAJOR_VERSION, libmatemixer_major_version)
+AC_SUBST(LIBMATEMIXER_MINOR_VERSION, libmatemixer_minor_version)
+AC_SUBST(LIBMATEMIXER_MICRO_VERSION, libmatemixer_micro_version)
+AC_SUBST(LIBMATEMIXER_VERSION, libmatemixer_version)
+
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([build-aux])
@@ -23,7 +41,7 @@ AC_PROG_INSTALL
# Checks for header files.
AC_HEADER_STDC
-AC_CHECK_HEADERS([sys/types.h unistd.h])
+AC_CHECK_HEADERS([string.h sys/types.h unistd.h])
# =======================================================================
# Libtool
@@ -53,10 +71,12 @@ PKG_CHECK_MODULES(GLIB, [
AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
AC_PATH_PROG(GLIB_MKENUMS, glib-mkenums)
+GTK_DOC_CHECK([1.10], [--flavour no-tmpl])
+
# =======================================================================
# Check for backend module support
# =======================================================================
-PA_REQUIRED_VERSION=0.9.16
+PA_REQUIRED_VERSION=0.9.23
AC_ARG_ENABLE([pulseaudio],
AS_HELP_STRING([--enable-pulseaudio],
@@ -65,7 +85,8 @@ AC_ARG_ENABLE([pulseaudio],
if test "x$enable_pulseaudio" != "xno"; then
PKG_CHECK_MODULES(PULSEAUDIO,
- libpulse >= $PA_REQUIRED_VERSION,
+ libpulse >= $PA_REQUIRED_VERSION
+ libpulse-mainloop-glib >= $PA_REQUIRED_VERSION,
have_pulseaudio=yes,
have_pulseaudio=no)
@@ -133,12 +154,16 @@ AC_SUBST(CFLAGS)
AC_CONFIG_FILES([
Makefile
libmatemixer/Makefile
+libmatemixer/matemixer-version.h
backends/Makefile
backends/null/Makefile
backends/pulse/Makefile
data/Makefile
data/libmatemixer.pc
docs/Makefile
+docs/reference/Makefile
+docs/reference/version.xml
+examples/Makefile
])
AC_OUTPUT
diff --git a/data/libmatemixer.pc.in b/data/libmatemixer.pc.in
index d56bfdb..9a89f48 100644
--- a/data/libmatemixer.pc.in
+++ b/data/libmatemixer.pc.in
@@ -6,6 +6,6 @@ includedir=@includedir@
Name: libmatemixer
Description:
Version: @VERSION@
-Requires: glib-2.0 gobject-2.0
+Requires: glib-2.0 gobject-2.0 gmodule-2.0
Libs: -L${libdir} -lmatemixer
-Cflags: -I${includedir}/libmatemixer
+Cflags: -I${includedir}
diff --git a/docs/Makefile.am b/docs/Makefile.am
index 9b582ee..034926c 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -1,2 +1,3 @@
+SUBDIRS = reference
-include $(top_srcdir)/git.mk
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
new file mode 100644
index 0000000..d7fe572
--- /dev/null
+++ b/docs/reference/Makefile.am
@@ -0,0 +1,109 @@
+## Process this file with automake to produce Makefile.in
+
+# We require automake 1.6 at least.
+AUTOMAKE_OPTIONS = 1.6
+
+# The name of the module, e.g. 'glib'.
+DOC_MODULE=libmatemixer
+
+# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
+#DOC_MODULE_VERSION=2
+
+# The top-level XML file (SGML in the past). You can change this if you want to.
+DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
+
+# Directories containing the source code.
+# gtk-doc will search all .c and .h files beneath these paths
+# for inline comments documenting functions and macros.
+# e.g. DOC_SOURCE_DIR=$(top_srcdir)/gtk $(top_srcdir)/gdk
+DOC_SOURCE_DIR=$(top_srcdir)/libmatemixer
+
+# Extra options to pass to gtkdoc-scangobj. Not normally needed.
+SCANGOBJ_OPTIONS=
+
+# Extra options to supply to gtkdoc-scan.
+# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
+SCAN_OPTIONS=--rebuild-sections --rebuild-types
+
+# Extra options to supply to gtkdoc-mkdb.
+# e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
+MKDB_OPTIONS=--xml-mode --output-format=xml
+
+# Extra options to supply to gtkdoc-mktmpl
+# e.g. MKTMPL_OPTIONS=--only-section-tmpl
+MKTMPL_OPTIONS=
+
+# Extra options to supply to gtkdoc-mkhtml
+MKHTML_OPTIONS=
+
+# Extra options to supply to gtkdoc-fixref. Not normally needed.
+# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
+FIXXREF_OPTIONS=
+
+# Used for dependencies. The docs will be rebuilt if any of these change.
+# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
+# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
+HFILE_GLOB=$(top_srcdir)/libmatemixer/*.h
+CFILE_GLOB=$(top_srcdir)/libmatemixer/*.c
+
+# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
+# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
+EXTRA_HFILES=
+
+# Header files or dirs to ignore when scanning. Use base file/dir names
+# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
+IGNORE_HFILES= \
+ matemixer-backend.h \
+ matemixer-backend-module.h \
+ matemixer-enum-types.h \
+ matemixer-private.h
+
+# Images to copy into HTML directory.
+# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
+HTML_IMAGES=
+
+# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
+# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
+content_files=version.xml
+
+# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
+# These files must be listed here *and* in content_files
+# e.g. expand_content_files=running.sgml
+expand_content_files=
+
+# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
+# Only needed if you are using gtkdoc-scangobj to dynamically query widget
+# signals and properties.
+# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
+# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
+GTKDOC_CFLAGS= \
+ -I$(top_srcdir) \
+ -I$(top_builddir) \
+ $(GLIB_CFLAGS)
+
+GTKDOC_LIBS= \
+ $(top_builddir)/libmatemixer/libmatemixer.la \
+ $(GLIB_LIBS)
+
+# This includes the standard gtk-doc make rules, copied by gtkdocize.
+include $(top_srcdir)/gtk-doc.make
+
+# Other files to distribute
+# e.g. EXTRA_DIST += version.xml.in
+EXTRA_DIST += version.xml.in
+
+# Files not to distribute
+# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
+# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
+#DISTCLEANFILES +=
+
+# Comment this out if you want 'make check' to test you doc status
+# and run some sanity checks
+if ENABLE_GTK_DOC
+TESTS_ENVIRONMENT = \
+ DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
+ SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
+#TESTS = $(GTKDOC_CHECK)
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/docs/reference/libmatemixer-docs.xml b/docs/reference/libmatemixer-docs.xml
new file mode 100644
index 0000000..9a073a4
--- /dev/null
+++ b/docs/reference/libmatemixer-docs.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+ "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
+[
+ <!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
+ <!ENTITY version SYSTEM "version.xml">
+]>
+<book id="index">
+ <bookinfo>
+ <title>libmatemixer Reference Manual</title>
+ <releaseinfo>
+ for libmatemixer &version;.
+ </releaseinfo>
+ </bookinfo>
+
+ <chapter>
+ <title>API Reference</title>
+ <xi:include href="xml/matemixer.xml"/>
+ <xi:include href="xml/matemixer-enums.xml"/>
+ <xi:include href="xml/matemixer-version.xml"/>
+ <xi:include href="xml/matemixer-client-stream.xml"/>
+ <xi:include href="xml/matemixer-control.xml"/>
+ <xi:include href="xml/matemixer-device.xml"/>
+ <xi:include href="xml/matemixer-port.xml"/>
+ <xi:include href="xml/matemixer-profile.xml"/>
+ <xi:include href="xml/matemixer-stream.xml"/>
+ </chapter>
+ <index id="api-index-full">
+ <title>API Index</title>
+ <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
+ </index>
+</book>
diff --git a/docs/reference/libmatemixer-overrides.txt b/docs/reference/libmatemixer-overrides.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/docs/reference/libmatemixer-overrides.txt
diff --git a/docs/reference/libmatemixer-sections.txt b/docs/reference/libmatemixer-sections.txt
new file mode 100644
index 0000000..e109f09
--- /dev/null
+++ b/docs/reference/libmatemixer-sections.txt
@@ -0,0 +1,187 @@
+<SECTION>
+<FILE>matemixer</FILE>
+mate_mixer_init
+mate_mixer_deinit
+</SECTION>
+
+<SECTION>
+<FILE>matemixer-client-stream</FILE>
+<TITLE>MateMixerClientStream</TITLE>
+MateMixerClientStreamInterface
+mate_mixer_client_stream_get_parent
+mate_mixer_client_stream_set_parent
+mate_mixer_client_stream_remove
+MateMixerClientStream
+<SUBSECTION Standard>
+MATE_MIXER_CLIENT_STREAM
+MATE_MIXER_CLIENT_STREAM_GET_INTERFACE
+MATE_MIXER_IS_CLIENT_STREAM
+MATE_MIXER_TYPE_CLIENT_STREAM
+mate_mixer_client_stream_get_type
+</SECTION>
+
+<SECTION>
+<FILE>matemixer-control</FILE>
+<TITLE>MateMixerControl</TITLE>
+MateMixerControl
+MateMixerControlClass
+mate_mixer_control_new
+mate_mixer_control_set_backend_type
+mate_mixer_control_set_app_name
+mate_mixer_control_set_app_id
+mate_mixer_control_set_app_version
+mate_mixer_control_set_app_icon
+mate_mixer_control_set_server_address
+mate_mixer_control_open
+mate_mixer_control_get_state
+mate_mixer_control_get_device
+mate_mixer_control_get_stream
+mate_mixer_control_list_devices
+mate_mixer_control_list_streams
+mate_mixer_control_get_default_input_stream
+mate_mixer_control_set_default_input_stream
+mate_mixer_control_get_default_output_stream
+mate_mixer_control_set_default_output_stream
+mate_mixer_control_get_backend_name
+mate_mixer_control_get_backend_type
+MateMixerControlPrivate
+<SUBSECTION Standard>
+MATE_MIXER_CONTROL
+MATE_MIXER_CONTROL_CLASS
+MATE_MIXER_CONTROL_GET_CLASS
+MATE_MIXER_IS_CONTROL
+MATE_MIXER_IS_CONTROL_CLASS
+MATE_MIXER_TYPE_CONTROL
+mate_mixer_control_get_type
+</SECTION>
+
+<SECTION>
+<FILE>matemixer-device</FILE>
+<TITLE>MateMixerDevice</TITLE>
+MateMixerDeviceInterface
+mate_mixer_device_get_name
+mate_mixer_device_get_description
+mate_mixer_device_get_icon
+mate_mixer_device_list_streams
+mate_mixer_device_list_ports
+mate_mixer_device_list_profiles
+mate_mixer_device_get_active_profile
+mate_mixer_device_set_active_profile
+MateMixerDevice
+<SUBSECTION Standard>
+MATE_MIXER_DEVICE
+MATE_MIXER_DEVICE_GET_INTERFACE
+MATE_MIXER_IS_DEVICE
+MATE_MIXER_TYPE_DEVICE
+mate_mixer_device_get_type
+</SECTION>
+
+<SECTION>
+<FILE>matemixer-enums</FILE>
+MateMixerState
+MateMixerBackendType
+MateMixerPortStatus
+MateMixerStreamFlags
+MateMixerStreamStatus
+MateMixerChannelPosition
+</SECTION>
+
+<SECTION>
+<FILE>matemixer-port</FILE>
+<TITLE>MateMixerPort</TITLE>
+MateMixerPort
+MateMixerPortClass
+mate_mixer_port_new
+mate_mixer_port_get_name
+mate_mixer_port_get_description
+mate_mixer_port_get_icon
+mate_mixer_port_get_priority
+mate_mixer_port_get_status
+MateMixerPortPrivate
+<SUBSECTION Standard>
+MATE_MIXER_IS_PORT
+MATE_MIXER_IS_PORT_CLASS
+MATE_MIXER_PORT
+MATE_MIXER_PORT_CLASS
+MATE_MIXER_PORT_GET_CLASS
+MATE_MIXER_TYPE_PORT
+mate_mixer_port_get_type
+</SECTION>
+
+<SECTION>
+<FILE>matemixer-profile</FILE>
+<TITLE>MateMixerProfile</TITLE>
+MateMixerProfile
+MateMixerProfileClass
+mate_mixer_profile_new
+mate_mixer_profile_get_name
+mate_mixer_profile_get_description
+mate_mixer_profile_get_priority
+MateMixerProfilePrivate
+<SUBSECTION Standard>
+MATE_MIXER_IS_PROFILE
+MATE_MIXER_IS_PROFILE_CLASS
+MATE_MIXER_PROFILE
+MATE_MIXER_PROFILE_CLASS
+MATE_MIXER_PROFILE_GET_CLASS
+MATE_MIXER_TYPE_PROFILE
+mate_mixer_profile_get_type
+</SECTION>
+
+<SECTION>
+<FILE>matemixer-stream</FILE>
+<TITLE>MateMixerStream</TITLE>
+MateMixerStreamInterface
+mate_mixer_stream_get_name
+mate_mixer_stream_get_description
+mate_mixer_stream_get_icon
+mate_mixer_stream_get_device
+mate_mixer_stream_get_flags
+mate_mixer_stream_get_status
+mate_mixer_stream_get_mute
+mate_mixer_stream_set_mute
+mate_mixer_stream_get_num_channels
+mate_mixer_stream_get_volume
+mate_mixer_stream_set_volume
+mate_mixer_stream_get_volume_db
+mate_mixer_stream_set_volume_db
+mate_mixer_stream_get_channel_position
+mate_mixer_stream_get_channel_volume
+mate_mixer_stream_set_channel_volume
+mate_mixer_stream_get_channel_volume_db
+mate_mixer_stream_set_channel_volume_db
+mate_mixer_stream_has_position
+mate_mixer_stream_get_position_volume
+mate_mixer_stream_set_position_volume
+mate_mixer_stream_get_position_volume_db
+mate_mixer_stream_set_position_volume_db
+mate_mixer_stream_get_balance
+mate_mixer_stream_set_balance
+mate_mixer_stream_get_fade
+mate_mixer_stream_set_fade
+mate_mixer_stream_suspend
+mate_mixer_stream_resume
+mate_mixer_stream_list_ports
+mate_mixer_stream_get_active_port
+mate_mixer_stream_set_active_port
+mate_mixer_stream_get_min_volume
+mate_mixer_stream_get_max_volume
+mate_mixer_stream_get_normal_volume
+MateMixerStream
+<SUBSECTION Standard>
+MATE_MIXER_IS_STREAM
+MATE_MIXER_STREAM
+MATE_MIXER_STREAM_GET_INTERFACE
+MATE_MIXER_TYPE_STREAM
+mate_mixer_stream_get_type
+</SECTION>
+
+<SECTION>
+<FILE>matemixer-version</FILE>
+LIBMATEMIXER_MAJOR_VERSION
+LIBMATEMIXER_MINOR_VERSION
+LIBMATEMIXER_MICRO_VERSION
+LIBMATEMIXER_VERSION
+LIBMATEMIXER_CHECK_VERSION
+</SECTION>
+
diff --git a/docs/reference/libmatemixer.types b/docs/reference/libmatemixer.types
new file mode 100644
index 0000000..be96363
--- /dev/null
+++ b/docs/reference/libmatemixer.types
@@ -0,0 +1,6 @@
+mate_mixer_client_stream_get_type
+mate_mixer_control_get_type
+mate_mixer_device_get_type
+mate_mixer_port_get_type
+mate_mixer_profile_get_type
+mate_mixer_stream_get_type
diff --git a/docs/reference/version.xml.in b/docs/reference/version.xml.in
new file mode 100644
index 0000000..6f8d6bf
--- /dev/null
+++ b/docs/reference/version.xml.in
@@ -0,0 +1 @@
+@LIBMATEMIXER_VERSION@
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..820a0f3
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,15 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ $(GLIB_CFLAGS)
+
+noinst_PROGRAMS = matemixer-monitor
+
+matemixer_monitor_SOURCES = monitor.c
+
+matemixer_monitor_LDADD = \
+ $(GLIB_LIBS) \
+ $(top_builddir)/libmatemixer/libmatemixer.la
+
+EXTRA_DIST = monitor.c
+
+-include $(top_srcdir)/git.mk
diff --git a/examples/monitor.c b/examples/monitor.c
new file mode 100644
index 0000000..3759073
--- /dev/null
+++ b/examples/monitor.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib-unix.h>
+#include <locale.h>
+
+#include <libmatemixer/matemixer.h>
+
+static MateMixerControl *control;
+
+static gchar *
+create_volume_bar (MateMixerStream *stream, double *percent)
+{
+ GString *string;
+ gint64 volume;
+ gint64 volume_min;
+ gint64 volume_max;
+ double p;
+ int i;
+ int length = 30;
+ int stars;
+
+ volume = mate_mixer_stream_get_volume (stream);
+ volume_min = mate_mixer_stream_get_min_volume (stream);
+ volume_max = mate_mixer_stream_get_normal_volume (stream);
+
+ string = g_string_new ("[");
+
+ p = (double) (volume - volume_min) / (volume_max - volume_min) * 100;
+ if (percent != NULL)
+ *percent = p;
+
+ stars = (int) ((p / 100) * length);
+
+ for (i = 0; i < length; i++)
+ g_string_append_c (string, (i < stars) ? '*' : '.');
+
+ return g_string_free (g_string_append_c (string, ']'), FALSE);
+}
+
+static void
+print_devices (void)
+{
+ const GList *devices;
+ const GList *ports;
+ const GList *profiles;
+ MateMixerProfile *active_profile;
+
+ devices = mate_mixer_control_list_devices (control);
+
+ while (devices) {
+ MateMixerDevice *device = MATE_MIXER_DEVICE (devices->data);
+
+ g_print ("Device %s\n"
+ " |-| Description : %s\n"
+ " |-| Icon Name : %s\n\n",
+ mate_mixer_device_get_name (device),
+ mate_mixer_device_get_description (device),
+ mate_mixer_device_get_icon (device));
+
+ ports = mate_mixer_device_list_ports (device);
+ while (ports) {
+ MateMixerPort *port = MATE_MIXER_PORT (ports->data);
+
+ g_print (" |-| Port %s\n"
+ " |-| Description : %s\n"
+ " |-| Icon Name : %s\n"
+ " |-| Priority : %lu\n"
+ " |-| Status : \n\n",
+ mate_mixer_port_get_name (port),
+ mate_mixer_port_get_description (port),
+ mate_mixer_port_get_icon (port),
+ mate_mixer_port_get_priority (port));
+
+ ports = ports->next;
+ }
+
+ profiles = mate_mixer_device_list_profiles (device);
+
+ active_profile = mate_mixer_device_get_active_profile (device);
+ while (profiles) {
+ MateMixerProfile *profile = MATE_MIXER_PROFILE (profiles->data);
+
+ g_print (" |%c| Profile %s\n"
+ " |-| Description : %s\n"
+ " |-| Priority : %lu\n\n",
+ (profile == active_profile)
+ ? 'A'
+ : '-',
+ mate_mixer_profile_get_name (profile),
+ mate_mixer_profile_get_description (profile),
+ mate_mixer_profile_get_priority (profile));
+
+ profiles = profiles->next;
+ }
+ g_print ("\n");
+
+ devices = devices->next;
+ }
+}
+
+static void
+print_streams (void)
+{
+ const GList *streams;
+ const GList *ports;
+ const GList *profiles;
+ MateMixerProfile *active_profile;
+
+ streams = mate_mixer_control_list_streams (control);
+
+ while (streams) {
+ MateMixerStream *stream = MATE_MIXER_STREAM (streams->data);
+ gchar *volume_bar;
+ gdouble volume;
+
+ volume_bar = create_volume_bar (stream, &volume);
+
+ g_print ("Stream %s\n"
+ " |-| Description : %s\n"
+ " |-| Icon Name : %s\n"
+ " |-| Volume : %s %.1f %%\n"
+ " |-| Muted : %s\n"
+ " |-| Channels : %d\n"
+ " |-| Balance : %.1f\n"
+ " |-| Fade : %.1f\n\n",
+ mate_mixer_stream_get_name (stream),
+ mate_mixer_stream_get_description (stream),
+ mate_mixer_stream_get_icon (stream),
+ volume_bar,
+ volume,
+ mate_mixer_stream_get_mute (stream) ? "Yes" : "No",
+ mate_mixer_stream_get_num_channels (stream),
+ mate_mixer_stream_get_balance (stream),
+ mate_mixer_stream_get_fade (stream));
+
+ g_free (volume_bar);
+
+ ports = mate_mixer_stream_list_ports (stream);
+ while (ports) {
+ MateMixerPort *port = MATE_MIXER_PORT (ports->data);
+
+ g_print (" |-| Port %s\n"
+ " |-| Description : %s\n"
+ " |-| Icon Name : %s\n"
+ " |-| Priority : %lu\n"
+ " |-| Status : \n\n",
+ mate_mixer_port_get_name (port),
+ mate_mixer_port_get_description (port),
+ mate_mixer_port_get_icon (port),
+ mate_mixer_port_get_priority (port));
+
+ ports = ports->next;
+ }
+
+ streams = streams->next;
+ }
+}
+
+static void
+connected (void)
+{
+ g_print ("Connected using the %s backend.\n\n",
+ mate_mixer_control_get_backend_name (control));
+
+ print_devices ();
+ print_streams ();
+
+ g_print ("Waiting for events. Hit CTRL+C to quit.\n");
+}
+
+static void
+state_cb (void)
+{
+ MateMixerState state;
+
+ state = mate_mixer_control_get_state (control);
+
+ switch (state) {
+ case MATE_MIXER_STATE_READY:
+ connected ();
+ break;
+ case MATE_MIXER_STATE_FAILED:
+ g_printerr ("aaa");
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static gboolean
+signal_cb (gpointer mainloop)
+{
+ g_idle_add ((GSourceFunc) g_main_loop_quit, mainloop);
+ return FALSE;
+}
+
+int main ()
+{
+ MateMixerState state;
+ GMainLoop *mainloop;
+
+ setlocale (LC_ALL, "");
+
+ /* The library */
+
+ if (!mate_mixer_init ())
+ return 1;
+
+ control = mate_mixer_control_new ();
+
+ mate_mixer_control_set_app_name (control, "MateMixer Monitor");
+ mate_mixer_control_set_app_icon (control, "multimedia-volume-control");
+
+ if (!mate_mixer_control_open (control)) {
+ g_object_unref (control);
+ mate_mixer_deinit ();
+ return 1;
+ }
+
+ state = mate_mixer_control_get_state (control);
+
+ switch (state) {
+ case MATE_MIXER_STATE_READY:
+ connected ();
+ break;
+ case MATE_MIXER_STATE_CONNECTING:
+ g_print ("Waiting for connection...\n");
+
+ /* This state means that the result will be determined asynchronously, so
+ * let's wait until the state transitions to a different value */
+ g_signal_connect (control, "notify::state", G_CALLBACK (state_cb), NULL);
+ break;
+ default:
+ /* If mate_mixer_control_open() returns TRUE, these two are the only
+ * possible states.
+ * In case mate_mixer_control_open() returned FALSE, the current state
+ * would be MATE_MIXER_STATE_FAILED */
+ g_assert_not_reached ();
+ break;
+ }
+
+ mainloop = g_main_loop_new (NULL, FALSE);
+
+ g_unix_signal_add (SIGTERM, signal_cb, mainloop);
+ g_unix_signal_add (SIGINT, signal_cb, mainloop);
+
+ g_main_loop_run (mainloop);
+
+ g_object_unref (control);
+ mate_mixer_deinit ();
+ return 0;
+}
diff --git a/gtk-doc.make b/gtk-doc.make
new file mode 100644
index 0000000..e791656
--- /dev/null
+++ b/gtk-doc.make
@@ -0,0 +1,289 @@
+# -*- mode: makefile -*-
+
+####################################
+# Everything below here is generic #
+####################################
+
+if GTK_DOC_USE_LIBTOOL
+GTKDOC_CC = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(INCLUDES) $(GTKDOC_DEPS_CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+GTKDOC_LD = $(LIBTOOL) --tag=CC --mode=link $(CC) $(GTKDOC_DEPS_LIBS) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
+GTKDOC_RUN = $(LIBTOOL) --mode=execute
+else
+GTKDOC_CC = $(CC) $(INCLUDES) $(GTKDOC_DEPS_CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+GTKDOC_LD = $(CC) $(GTKDOC_DEPS_LIBS) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
+GTKDOC_RUN =
+endif
+
+# We set GPATH here; this gives us semantics for GNU make
+# which are more like other make's VPATH, when it comes to
+# whether a source that is a target of one rule is then
+# searched for in VPATH/GPATH.
+#
+GPATH = $(srcdir)
+
+TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)
+
+SETUP_FILES = \
+ $(content_files) \
+ $(DOC_MAIN_SGML_FILE) \
+ $(DOC_MODULE)-sections.txt \
+ $(DOC_MODULE)-overrides.txt
+
+EXTRA_DIST = \
+ $(HTML_IMAGES) \
+ $(SETUP_FILES)
+
+DOC_STAMPS=setup-build.stamp scan-build.stamp sgml-build.stamp \
+ html-build.stamp pdf-build.stamp \
+ sgml.stamp html.stamp pdf.stamp
+
+SCANOBJ_FILES = \
+ $(DOC_MODULE).args \
+ $(DOC_MODULE).hierarchy \
+ $(DOC_MODULE).interfaces \
+ $(DOC_MODULE).prerequisites \
+ $(DOC_MODULE).signals
+
+REPORT_FILES = \
+ $(DOC_MODULE)-undocumented.txt \
+ $(DOC_MODULE)-undeclared.txt \
+ $(DOC_MODULE)-unused.txt
+
+gtkdoc-check.test: Makefile
+ $(AM_V_GEN)echo "#!/bin/sh -e" > $@; \
+ echo "$(GTKDOC_CHECK_PATH) || exit 1" >> $@; \
+ chmod +x $@
+
+CLEANFILES = $(SCANOBJ_FILES) $(REPORT_FILES) $(DOC_STAMPS) gtkdoc-check.test
+
+if GTK_DOC_BUILD_HTML
+HTML_BUILD_STAMP=html-build.stamp
+else
+HTML_BUILD_STAMP=
+endif
+if GTK_DOC_BUILD_PDF
+PDF_BUILD_STAMP=pdf-build.stamp
+else
+PDF_BUILD_STAMP=
+endif
+
+all-gtk-doc: $(HTML_BUILD_STAMP) $(PDF_BUILD_STAMP)
+.PHONY: all-gtk-doc
+
+if ENABLE_GTK_DOC
+all-local: all-gtk-doc
+endif
+
+docs: $(HTML_BUILD_STAMP) $(PDF_BUILD_STAMP)
+
+$(REPORT_FILES): sgml-build.stamp
+
+#### setup ####
+
+GTK_DOC_V_SETUP=$(GTK_DOC_V_SETUP_$(V))
+GTK_DOC_V_SETUP_=$(GTK_DOC_V_SETUP_$(AM_DEFAULT_VERBOSITY))
+GTK_DOC_V_SETUP_0=@echo " DOC Preparing build";
+
+setup-build.stamp:
+ -$(GTK_DOC_V_SETUP)if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \
+ files=`echo $(SETUP_FILES) $(expand_content_files) $(DOC_MODULE).types`; \
+ if test "x$$files" != "x" ; then \
+ for file in $$files ; do \
+ destdir=`dirname $(abs_builddir)/$$file`; \
+ test -d "$$destdir" || mkdir -p "$$destdir"; \
+ test -f $(abs_srcdir)/$$file && \
+ cp -pf $(abs_srcdir)/$$file $(abs_builddir)/$$file || true; \
+ done; \
+ fi; \
+ fi
+ $(AM_V_at)touch setup-build.stamp
+
+
+#### scan ####
+
+GTK_DOC_V_SCAN=$(GTK_DOC_V_SCAN_$(V))
+GTK_DOC_V_SCAN_=$(GTK_DOC_V_SCAN_$(AM_DEFAULT_VERBOSITY))
+GTK_DOC_V_SCAN_0=@echo " DOC Scanning header files";
+
+GTK_DOC_V_INTROSPECT=$(GTK_DOC_V_INTROSPECT_$(V))
+GTK_DOC_V_INTROSPECT_=$(GTK_DOC_V_INTROSPECT_$(AM_DEFAULT_VERBOSITY))
+GTK_DOC_V_INTROSPECT_0=@echo " DOC Introspecting gobjects";
+
+scan-build.stamp: setup-build.stamp $(HFILE_GLOB) $(CFILE_GLOB)
+ $(GTK_DOC_V_SCAN)_source_dir='' ; \
+ for i in $(DOC_SOURCE_DIR) ; do \
+ _source_dir="$${_source_dir} --source-dir=$$i" ; \
+ done ; \
+ gtkdoc-scan --module=$(DOC_MODULE) --ignore-headers="$(IGNORE_HFILES)" $${_source_dir} $(SCAN_OPTIONS) $(EXTRA_HFILES)
+ $(GTK_DOC_V_INTROSPECT)if grep -l '^..*$$' $(DOC_MODULE).types > /dev/null 2>&1 ; then \
+ scanobj_options=""; \
+ gtkdoc-scangobj 2>&1 --help | grep >/dev/null "\-\-verbose"; \
+ if test "$(?)" = "0"; then \
+ if test "x$(V)" = "x1"; then \
+ scanobj_options="--verbose"; \
+ fi; \
+ fi; \
+ CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" RUN="$(GTKDOC_RUN)" CFLAGS="$(GTKDOC_CFLAGS) $(CFLAGS)" LDFLAGS="$(GTKDOC_LIBS) $(LDFLAGS)" \
+ gtkdoc-scangobj $(SCANGOBJ_OPTIONS) $$scanobj_options --module=$(DOC_MODULE); \
+ else \
+ for i in $(SCANOBJ_FILES) ; do \
+ test -f $$i || touch $$i ; \
+ done \
+ fi
+ $(AM_V_at)touch scan-build.stamp
+
+$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp
+ @true
+
+#### xml ####
+
+GTK_DOC_V_XML=$(GTK_DOC_V_XML_$(V))
+GTK_DOC_V_XML_=$(GTK_DOC_V_XML_$(AM_DEFAULT_VERBOSITY))
+GTK_DOC_V_XML_0=@echo " DOC Building XML";
+
+sgml-build.stamp: setup-build.stamp $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt $(expand_content_files)
+ $(GTK_DOC_V_XML)_source_dir='' ; \
+ for i in $(DOC_SOURCE_DIR) ; do \
+ _source_dir="$${_source_dir} --source-dir=$$i" ; \
+ done ; \
+ gtkdoc-mkdb --module=$(DOC_MODULE) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $${_source_dir} $(MKDB_OPTIONS)
+ $(AM_V_at)touch sgml-build.stamp
+
+sgml.stamp: sgml-build.stamp
+ @true
+
+#### html ####
+
+GTK_DOC_V_HTML=$(GTK_DOC_V_HTML_$(V))
+GTK_DOC_V_HTML_=$(GTK_DOC_V_HTML_$(AM_DEFAULT_VERBOSITY))
+GTK_DOC_V_HTML_0=@echo " DOC Building HTML";
+
+GTK_DOC_V_XREF=$(GTK_DOC_V_XREF_$(V))
+GTK_DOC_V_XREF_=$(GTK_DOC_V_XREF_$(AM_DEFAULT_VERBOSITY))
+GTK_DOC_V_XREF_0=@echo " DOC Fixing cross-references";
+
+html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files)
+ $(GTK_DOC_V_HTML)rm -rf html && mkdir html && \
+ mkhtml_options=""; \
+ gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-verbose"; \
+ if test "$(?)" = "0"; then \
+ if test "x$(V)" = "x1"; then \
+ mkhtml_options="$$mkhtml_options --verbose"; \
+ fi; \
+ fi; \
+ gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-path"; \
+ if test "$(?)" = "0"; then \
+ mkhtml_options="$$mkhtml_options --path=\"$(abs_srcdir)\""; \
+ fi; \
+ cd html && gtkdoc-mkhtml $$mkhtml_options $(MKHTML_OPTIONS) $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE)
+ -@test "x$(HTML_IMAGES)" = "x" || \
+ for file in $(HTML_IMAGES) ; do \
+ if test -f $(abs_srcdir)/$$file ; then \
+ cp $(abs_srcdir)/$$file $(abs_builddir)/html; \
+ fi; \
+ if test -f $(abs_builddir)/$$file ; then \
+ cp $(abs_builddir)/$$file $(abs_builddir)/html; \
+ fi; \
+ done;
+ $(GTK_DOC_V_XREF)gtkdoc-fixxref --module=$(DOC_MODULE) --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS)
+ $(AM_V_at)touch html-build.stamp
+
+#### pdf ####
+
+GTK_DOC_V_PDF=$(GTK_DOC_V_PDF_$(V))
+GTK_DOC_V_PDF_=$(GTK_DOC_V_PDF_$(AM_DEFAULT_VERBOSITY))
+GTK_DOC_V_PDF_0=@echo " DOC Building PDF";
+
+pdf-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files)
+ $(GTK_DOC_V_PDF)rm -f $(DOC_MODULE).pdf && \
+ mkpdf_options=""; \
+ gtkdoc-mkpdf 2>&1 --help | grep >/dev/null "\-\-verbose"; \
+ if test "$(?)" = "0"; then \
+ if test "x$(V)" = "x1"; then \
+ mkpdf_options="$$mkpdf_options --verbose"; \
+ fi; \
+ fi; \
+ if test "x$(HTML_IMAGES)" != "x"; then \
+ for img in $(HTML_IMAGES); do \
+ part=`dirname $$img`; \
+ echo $$mkpdf_options | grep >/dev/null "\-\-imgdir=$$part "; \
+ if test $$? != 0; then \
+ mkpdf_options="$$mkpdf_options --imgdir=$$part"; \
+ fi; \
+ done; \
+ fi; \
+ gtkdoc-mkpdf --path="$(abs_srcdir)" $$mkpdf_options $(DOC_MODULE) $(DOC_MAIN_SGML_FILE) $(MKPDF_OPTIONS)
+ $(AM_V_at)touch pdf-build.stamp
+
+##############
+
+clean-local:
+ @rm -f *~ *.bak
+ @rm -rf .libs
+ @if echo $(SCAN_OPTIONS) | grep -q "\-\-rebuild-types" ; then \
+ rm -f $(DOC_MODULE).types; \
+ fi
+
+distclean-local:
+ @rm -rf xml html $(REPORT_FILES) $(DOC_MODULE).pdf \
+ $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt
+ @if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \
+ rm -f $(SETUP_FILES) $(expand_content_files) $(DOC_MODULE).types; \
+ fi
+
+maintainer-clean-local:
+ @rm -rf xml html
+
+install-data-local:
+ @installfiles=`echo $(builddir)/html/*`; \
+ if test "$$installfiles" = '$(builddir)/html/*'; \
+ then echo 1>&2 'Nothing to install' ; \
+ else \
+ if test -n "$(DOC_MODULE_VERSION)"; then \
+ installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \
+ else \
+ installdir="$(DESTDIR)$(TARGET_DIR)"; \
+ fi; \
+ $(mkinstalldirs) $${installdir} ; \
+ for i in $$installfiles; do \
+ echo ' $(INSTALL_DATA) '$$i ; \
+ $(INSTALL_DATA) $$i $${installdir}; \
+ done; \
+ if test -n "$(DOC_MODULE_VERSION)"; then \
+ mv -f $${installdir}/$(DOC_MODULE).devhelp2 \
+ $${installdir}/$(DOC_MODULE)-$(DOC_MODULE_VERSION).devhelp2; \
+ fi; \
+ $(GTKDOC_REBASE) --relative --dest-dir=$(DESTDIR) --html-dir=$${installdir}; \
+ fi
+
+uninstall-local:
+ @if test -n "$(DOC_MODULE_VERSION)"; then \
+ installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \
+ else \
+ installdir="$(DESTDIR)$(TARGET_DIR)"; \
+ fi; \
+ rm -rf $${installdir}
+
+#
+# Require gtk-doc when making dist
+#
+if HAVE_GTK_DOC
+dist-check-gtkdoc: docs
+else
+dist-check-gtkdoc:
+ @echo "*** gtk-doc is needed to run 'make dist'. ***"
+ @echo "*** gtk-doc was not found when 'configure' ran. ***"
+ @echo "*** please install gtk-doc and rerun 'configure'. ***"
+ @false
+endif
+
+dist-hook: dist-check-gtkdoc all-gtk-doc dist-hook-local
+ @mkdir $(distdir)/html
+ @cp ./html/* $(distdir)/html
+ @-cp ./$(DOC_MODULE).pdf $(distdir)/
+ @-cp ./$(DOC_MODULE).types $(distdir)/
+ @-cp ./$(DOC_MODULE)-sections.txt $(distdir)/
+ @cd $(distdir) && rm -f $(DISTCLEANFILES)
+ @$(GTKDOC_REBASE) --online --relative --html-dir=$(distdir)/html
+
+.PHONY : dist-hook-local docs
diff --git a/libmatemixer/Makefile.am b/libmatemixer/Makefile.am
index 0280b27..a45b29c 100644
--- a/libmatemixer/Makefile.am
+++ b/libmatemixer/Makefile.am
@@ -10,12 +10,14 @@ libmatemixer_includedir = $(includedir)/libmatemixer
libmatemixer_include_HEADERS = \
matemixer.h \
+ matemixer-client-stream.h \
matemixer-control.h \
matemixer-device.h \
matemixer-enums.h \
matemixer-port.h \
matemixer-profile.h \
- matemixer-stream.h
+ matemixer-stream.h \
+ matemixer-version.h
libmatemixer_la_CFLAGS = $(GLIB_CFLAGS)
@@ -26,6 +28,7 @@ libmatemixer_la_SOURCES = \
matemixer-backend.h \
matemixer-backend-module.c \
matemixer-backend-module.h \
+ matemixer-client-stream.c \
matemixer-control.c \
matemixer-device.c \
matemixer-enum-types.c \
@@ -38,6 +41,9 @@ libmatemixer_la_LIBADD = $(GLIB_LIBS)
libmatemixer_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -no-undefined \
-export-dynamic
+EXTRA_DIST = matemixer-version.h.in
+
-include $(top_srcdir)/git.mk
diff --git a/libmatemixer/matemixer-backend-module.c b/libmatemixer/matemixer-backend-module.c
index 5ad2836..b04ad6f 100644
--- a/libmatemixer/matemixer-backend-module.c
+++ b/libmatemixer/matemixer-backend-module.c
@@ -22,8 +22,6 @@
#include "matemixer-backend.h"
#include "matemixer-backend-module.h"
-G_DEFINE_TYPE (MateMixerBackendModule, mate_mixer_backend_module, G_TYPE_TYPE_MODULE);
-
struct _MateMixerBackendModulePrivate
{
GModule *gmodule;
@@ -44,6 +42,8 @@ static void mate_mixer_backend_module_finalize (GObject
static gboolean mate_mixer_backend_module_load (GTypeModule *gmodule);
static void mate_mixer_backend_module_unload (GTypeModule *gmodule);
+G_DEFINE_TYPE (MateMixerBackendModule, mate_mixer_backend_module, G_TYPE_TYPE_MODULE);
+
static void
mate_mixer_backend_module_class_init (MateMixerBackendModuleClass *klass)
{
@@ -58,7 +58,7 @@ mate_mixer_backend_module_class_init (MateMixerBackendModuleClass *klass)
module_class->load = mate_mixer_backend_module_load;
module_class->unload = mate_mixer_backend_module_unload;
- g_type_class_add_private (object_class, sizeof (MateMixerBackendModulePrivate));
+ g_type_class_add_private (klass, sizeof (MateMixerBackendModulePrivate));
}
static void
@@ -88,11 +88,7 @@ mate_mixer_backend_module_dispose (GObject *object)
static void
mate_mixer_backend_module_finalize (GObject *object)
{
- MateMixerBackendModule *module;
-
- module = MATE_MIXER_BACKEND_MODULE (object);
-
- g_free (module->priv->path);
+ g_free (MATE_MIXER_BACKEND_MODULE (object)->priv->path);
G_OBJECT_CLASS (mate_mixer_backend_module_parent_class)->finalize (object);
}
@@ -139,8 +135,8 @@ mate_mixer_backend_module_load (GTypeModule *type_module)
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 */
+ /* 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);
@@ -158,7 +154,7 @@ mate_mixer_backend_module_load (GTypeModule *type_module)
g_debug ("Loaded backend module %s", module->priv->path);
} else {
- /* This function was called before so initialize only */
+ /* This function was called before, so initialize only */
module->priv->init (type_module);
}
return TRUE;
@@ -171,8 +167,8 @@ mate_mixer_backend_module_unload (GTypeModule *type_module)
module = MATE_MIXER_BACKEND_MODULE (type_module);
- /* Only deinitialize the backend module, do not modify the loaded
- * flag as the module remains loaded */
+ /* Only deinitialize the backend module, do not modify the loaded flag
+ * as the module remains loaded */
if (module->priv->deinit)
module->priv->deinit ();
}
diff --git a/libmatemixer/matemixer-backend-module.h b/libmatemixer/matemixer-backend-module.h
index b629bfc..61a426d 100644
--- a/libmatemixer/matemixer-backend-module.h
+++ b/libmatemixer/matemixer-backend-module.h
@@ -61,11 +61,11 @@ struct _MateMixerBackendModuleClass
GTypeModuleClass parent;
};
-GType mate_mixer_backend_module_get_type (void) G_GNUC_CONST;
+GType mate_mixer_backend_module_get_type (void) G_GNUC_CONST;
-MateMixerBackendModule *mate_mixer_backend_module_new (const gchar *path);
+MateMixerBackendModule * mate_mixer_backend_module_new (const gchar *path);
const MateMixerBackendInfo *mate_mixer_backend_module_get_info (MateMixerBackendModule *module);
-const gchar *mate_mixer_backend_module_get_path (MateMixerBackendModule *module);
+const gchar * mate_mixer_backend_module_get_path (MateMixerBackendModule *module);
G_END_DECLS
diff --git a/libmatemixer/matemixer-backend.c b/libmatemixer/matemixer-backend.c
index 890c34b..474edd4 100644
--- a/libmatemixer/matemixer-backend.c
+++ b/libmatemixer/matemixer-backend.c
@@ -19,15 +19,121 @@
#include <glib-object.h>
#include "matemixer-backend.h"
+#include "matemixer-enums.h"
+#include "matemixer-enum-types.h"
#include "matemixer-stream.h"
+enum {
+ DEVICE_ADDED,
+ DEVICE_CHANGED,
+ DEVICE_REMOVED,
+ STREAM_ADDED,
+ STREAM_CHANGED,
+ STREAM_REMOVED,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0, };
+
G_DEFINE_INTERFACE (MateMixerBackend, mate_mixer_backend, G_TYPE_OBJECT)
static void
mate_mixer_backend_default_init (MateMixerBackendInterface *iface)
{
+ g_object_interface_install_property (iface,
+ g_param_spec_enum ("state",
+ "State",
+ "Backend connection state",
+ MATE_MIXER_TYPE_STATE,
+ MATE_MIXER_STATE_IDLE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ signals[DEVICE_ADDED] = g_signal_new ("device-added",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerBackendInterface, device_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[DEVICE_CHANGED] = g_signal_new ("device-changed",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerBackendInterface, device_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[DEVICE_REMOVED] = g_signal_new ("device-removed",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerBackendInterface, device_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[STREAM_ADDED] = g_signal_new ("stream-added",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerBackendInterface, stream_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[STREAM_CHANGED] = g_signal_new ("stream-changed",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerBackendInterface, stream_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[STREAM_REMOVED] = g_signal_new ("stream-removed",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerBackendInterface, stream_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+}
+
+void
+mate_mixer_backend_set_data (MateMixerBackend *backend, const MateMixerBackendData *data)
+{
+ MateMixerBackendInterface *iface;
+
+ g_return_if_fail (MATE_MIXER_IS_BACKEND (backend));
+
+ iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+
+ if (iface->set_data)
+ iface->set_data (backend, data);
}
+/*
+ * Required behaviour:
+ * if the function returns TRUE, the state must be either MATE_MIXER_STATE_READY or
+ * MATE_MIXER_STATE_CONNECTING.
+ */
gboolean
mate_mixer_backend_open (MateMixerBackend *backend)
{
@@ -37,10 +143,11 @@ mate_mixer_backend_open (MateMixerBackend *backend)
iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
- if (iface->open)
- return iface->open (backend);
-
- return FALSE;
+ if (!iface->open) {
+ g_critical ("Backend module does not implement the open() method");
+ return FALSE;
+ }
+ return iface->open (backend);
}
void
@@ -56,6 +163,22 @@ mate_mixer_backend_close (MateMixerBackend *backend)
iface->close (backend);
}
+MateMixerState
+mate_mixer_backend_get_state (MateMixerBackend *backend)
+{
+ MateMixerBackendInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), MATE_MIXER_STATE_UNKNOWN);
+
+ iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+
+ if (!iface->get_state) {
+ g_critical ("Backend module does not implement the get_state() method");
+ return MATE_MIXER_STATE_UNKNOWN;
+ }
+ return iface->get_state (backend);
+}
+
GList *
mate_mixer_backend_list_devices (MateMixerBackend *backend)
{
@@ -101,6 +224,22 @@ mate_mixer_backend_get_default_input_stream (MateMixerBackend *backend)
return NULL;
}
+gboolean
+mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
+ MateMixerStream *stream)
+{
+ MateMixerBackendInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), FALSE);
+
+ iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+
+ if (iface->set_default_input_stream)
+ return iface->set_default_input_stream (backend, stream);
+
+ return FALSE;
+}
+
MateMixerStream *
mate_mixer_backend_get_default_output_stream (MateMixerBackend *backend)
{
@@ -115,3 +254,19 @@ mate_mixer_backend_get_default_output_stream (MateMixerBackend *backend)
return NULL;
}
+
+gboolean
+mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,
+ MateMixerStream *stream)
+{
+ MateMixerBackendInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), FALSE);
+
+ iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+
+ if (iface->set_default_output_stream)
+ return iface->set_default_output_stream (backend, stream);
+
+ return FALSE;
+}
diff --git a/libmatemixer/matemixer-backend.h b/libmatemixer/matemixer-backend.h
index 897641f..1a5418f 100644
--- a/libmatemixer/matemixer-backend.h
+++ b/libmatemixer/matemixer-backend.h
@@ -25,6 +25,15 @@
G_BEGIN_DECLS
+typedef struct
+{
+ gchar *app_name;
+ gchar *app_id;
+ gchar *app_version;
+ gchar *app_icon;
+ gchar *server_address;
+} MateMixerBackendData;
+
#define MATE_MIXER_TYPE_BACKEND \
(mate_mixer_backend_get_type ())
#define MATE_MIXER_BACKEND(o) \
@@ -42,23 +51,58 @@ struct _MateMixerBackendInterface
GTypeInterface parent;
/* Required */
- gboolean (*open) (MateMixerBackend *backend);
+ gboolean (*open) (MateMixerBackend *backend);
+ MateMixerState (*get_state) (MateMixerBackend *backend);
+
+ /* Optional */
+ void (*set_data) (MateMixerBackend *backend,
+ const MateMixerBackendData *data);
- void (*close) (MateMixerBackend *backend);
- GList *(*list_devices) (MateMixerBackend *backend);
- GList *(*list_streams) (MateMixerBackend *backend);
- MateMixerStream *(*get_default_input_stream) (MateMixerBackend *backend);
- MateMixerStream *(*get_default_output_stream) (MateMixerBackend *backend);
+ void (*close) (MateMixerBackend *backend);
+ GList *(*list_devices) (MateMixerBackend *backend);
+ GList *(*list_streams) (MateMixerBackend *backend);
+ MateMixerStream *(*get_default_input_stream) (MateMixerBackend *backend);
+ gboolean (*set_default_input_stream) (MateMixerBackend *backend,
+ MateMixerStream *stream);
+ MateMixerStream *(*get_default_output_stream) (MateMixerBackend *backend);
+ gboolean (*set_default_output_stream) (MateMixerBackend *backend,
+ MateMixerStream *stream);
+
+ /* Signals */
+ void (*device_added) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*device_changed) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*device_removed) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*stream_added) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*stream_changed) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*stream_removed) (MateMixerBackend *backend,
+ const gchar *name);
};
-GType mate_mixer_backend_get_type (void) G_GNUC_CONST;
+GType mate_mixer_backend_get_type (void) G_GNUC_CONST;
+
+void mate_mixer_backend_set_data (MateMixerBackend *backend,
+ const MateMixerBackendData *data);
+
+gboolean mate_mixer_backend_open (MateMixerBackend *backend);
+void mate_mixer_backend_close (MateMixerBackend *backend);
+
+MateMixerState mate_mixer_backend_get_state (MateMixerBackend *backend);
+
+GList * mate_mixer_backend_list_devices (MateMixerBackend *backend);
+GList * mate_mixer_backend_list_streams (MateMixerBackend *backend);
+
+MateMixerStream *mate_mixer_backend_get_default_input_stream (MateMixerBackend *backend);
+gboolean mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
-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_streams (MateMixerBackend *backend);
-MateMixerStream *mate_mixer_backend_get_default_input_stream (MateMixerBackend *backend);
-MateMixerStream *mate_mixer_backend_get_default_output_stream (MateMixerBackend *backend);
+MateMixerStream *mate_mixer_backend_get_default_output_stream (MateMixerBackend *backend);
+gboolean mate_mixer_backend_set_default_output_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
G_END_DECLS
diff --git a/libmatemixer/matemixer-client-stream.c b/libmatemixer/matemixer-client-stream.c
new file mode 100644
index 0000000..80f48a9
--- /dev/null
+++ b/libmatemixer/matemixer-client-stream.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "matemixer-client-stream.h"
+#include "matemixer-stream.h"
+
+G_DEFINE_INTERFACE (MateMixerClientStream, mate_mixer_client_stream, G_TYPE_OBJECT)
+
+static void
+mate_mixer_client_stream_default_init (MateMixerClientStreamInterface *iface)
+{
+ g_object_interface_install_property (iface,
+ g_param_spec_object ("parent",
+ "Parent",
+ "Parent stream of the client stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+}
+
+MateMixerStream *
+mate_mixer_client_stream_get_parent (MateMixerClientStream *client)
+{
+ MateMixerClientStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
+
+ iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
+
+ if (iface->get_parent)
+ return iface->get_parent (client);
+
+ return NULL;
+}
+
+gboolean
+mate_mixer_client_stream_set_parent (MateMixerClientStream *client, MateMixerStream *parent)
+{
+ MateMixerClientStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (parent), FALSE);
+
+ iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
+
+ if (iface->set_parent)
+ return iface->set_parent (client, parent);
+
+ return FALSE;
+}
+
+gboolean
+mate_mixer_client_stream_remove (MateMixerClientStream *client)
+{
+ MateMixerClientStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), FALSE);
+
+ iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
+
+ if (iface->remove)
+ return iface->remove (client);
+
+ return FALSE;
+}
diff --git a/libmatemixer/matemixer-client-stream.h b/libmatemixer/matemixer-client-stream.h
new file mode 100644
index 0000000..2c690c5
--- /dev/null
+++ b/libmatemixer/matemixer-client-stream.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_CLIENT_STREAM_H
+#define MATEMIXER_CLIENT_STREAM_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-stream.h>
+
+G_BEGIN_DECLS
+
+#define MATE_MIXER_TYPE_CLIENT_STREAM \
+ (mate_mixer_client_stream_get_type ())
+#define MATE_MIXER_CLIENT_STREAM(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), MATE_MIXER_TYPE_CLIENT_STREAM, MateMixerClientStream))
+#define MATE_MIXER_IS_CLIENT_STREAM(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), MATE_MIXER_TYPE_CLIENT_STREAM))
+#define MATE_MIXER_CLIENT_STREAM_GET_INTERFACE(o) \
+ (G_TYPE_INSTANCE_GET_INTERFACE ((o), MATE_MIXER_TYPE_CLIENT_STREAM, MateMixerClientStreamInterface))
+
+typedef struct _MateMixerClientStream MateMixerClientStream; /* dummy object */
+typedef struct _MateMixerClientStreamInterface MateMixerClientStreamInterface;
+
+struct _MateMixerClientStreamInterface
+{
+ /*< private >*/
+ GTypeInterface parent;
+
+ MateMixerStream *(*get_parent) (MateMixerClientStream *client);
+ gboolean (*set_parent) (MateMixerClientStream *client,
+ MateMixerStream *stream);
+ gboolean (*remove) (MateMixerClientStream *client);
+};
+
+GType mate_mixer_client_stream_get_type (void) G_GNUC_CONST;
+MateMixerStream *mate_mixer_client_stream_get_parent (MateMixerClientStream *client);
+gboolean mate_mixer_client_stream_set_parent (MateMixerClientStream *client,
+ MateMixerStream *parent);
+gboolean mate_mixer_client_stream_remove (MateMixerClientStream *client);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_CLIENT_STREAM_H */
diff --git a/libmatemixer/matemixer-control.c b/libmatemixer/matemixer-control.c
index c122a7e..3e3045e 100644
--- a/libmatemixer/matemixer-control.c
+++ b/libmatemixer/matemixer-control.c
@@ -15,6 +15,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#include <string.h>
#include <glib.h>
#include <glib-object.h>
@@ -22,6 +23,7 @@
#include "matemixer-backend-module.h"
#include "matemixer-control.h"
#include "matemixer-enums.h"
+#include "matemixer-enum-types.h"
#include "matemixer-private.h"
#include "matemixer-stream.h"
@@ -29,17 +31,146 @@ struct _MateMixerControlPrivate
{
GList *devices;
GList *streams;
+ MateMixerState state;
MateMixerBackend *backend;
+ MateMixerBackendData backend_data;
+ MateMixerBackendType backend_type;
MateMixerBackendModule *module;
};
+enum {
+ PROP_0,
+ PROP_APP_NAME,
+ PROP_APP_ID,
+ PROP_APP_VERSION,
+ PROP_APP_ICON,
+ PROP_SERVER_ADDRESS,
+ PROP_STATE,
+ PROP_DEFAULT_INPUT,
+ PROP_DEFAULT_OUTPUT,
+ N_PROPERTIES
+};
+
+enum {
+ DEVICE_ADDED,
+ DEVICE_CHANGED,
+ DEVICE_REMOVED,
+ STREAM_ADDED,
+ STREAM_CHANGED,
+ STREAM_REMOVED,
+ N_SIGNALS
+};
+
+static void mate_mixer_control_class_init (MateMixerControlClass *klass);
+static void mate_mixer_control_init (MateMixerControl *control);
+static void mate_mixer_control_dispose (GObject *object);
+static void mate_mixer_control_finalize (GObject *object);
+
+static gboolean control_try_next_backend (MateMixerControl *control);
+static void control_change_state (MateMixerControl *control,
+ MateMixerState state);
+static void control_state_changed_cb (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerControl *control);
+
+static void control_device_added_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+static void control_device_changed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+static void control_device_removed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+
+static void control_stream_added_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+static void control_stream_changed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+static void control_stream_removed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+
G_DEFINE_TYPE (MateMixerControl, mate_mixer_control, G_TYPE_OBJECT);
-static void mate_mixer_control_class_init (MateMixerControlClass *klass);
-static void mate_mixer_control_init (MateMixerControl *control);
-static void mate_mixer_control_dispose (GObject *object);
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+static guint signals[N_SIGNALS] = { 0, };
+
+static void
+mate_mixer_control_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerControl *control;
+
+ control = MATE_MIXER_CONTROL (object);
+
+ switch (param_id) {
+ case PROP_APP_NAME:
+ g_value_set_string (value, control->priv->backend_data.app_name);
+ break;
+ case PROP_APP_ID:
+ g_value_set_string (value, control->priv->backend_data.app_id);
+ break;
+ case PROP_APP_VERSION:
+ g_value_set_string (value, control->priv->backend_data.app_version);
+ break;
+ case PROP_APP_ICON:
+ g_value_set_string (value, control->priv->backend_data.app_icon);
+ break;
+ case PROP_SERVER_ADDRESS:
+ g_value_set_string (value, control->priv->backend_data.server_address);
+ break;
+ case PROP_STATE:
+ g_value_set_enum (value, control->priv->state);
+ break;
+ case PROP_DEFAULT_INPUT:
+ g_value_set_object (value, mate_mixer_control_get_default_input_stream (control));
+ break;
+ case PROP_DEFAULT_OUTPUT:
+ g_value_set_object (value, mate_mixer_control_get_default_output_stream (control));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+mate_mixer_control_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerControl *control;
+
+ control = MATE_MIXER_CONTROL (object);
-static MateMixerBackend *mixer_control_init_module (MateMixerBackendModule *module);
+ switch (param_id) {
+ case PROP_APP_NAME:
+ mate_mixer_control_set_app_name (control, g_value_get_string (value));
+ break;
+ case PROP_APP_ID:
+ mate_mixer_control_set_app_id (control, g_value_get_string (value));
+ break;
+ case PROP_APP_VERSION:
+ mate_mixer_control_set_app_version (control, g_value_get_string (value));
+ break;
+ case PROP_APP_ICON:
+ mate_mixer_control_set_app_icon (control, g_value_get_string (value));
+ break;
+ case PROP_SERVER_ADDRESS:
+ mate_mixer_control_set_server_address (control, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
static void
mate_mixer_control_class_init (MateMixerControlClass *klass)
@@ -47,7 +178,160 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = mate_mixer_control_dispose;
+ object_class->dispose = mate_mixer_control_dispose;
+ object_class->finalize = mate_mixer_control_finalize;
+ object_class->get_property = mate_mixer_control_get_property;
+ object_class->set_property = mate_mixer_control_set_property;
+
+ /**
+ * MateMixerControl:app-name:
+ *
+ * Localized human readable name of the application.
+ */
+ properties[PROP_APP_NAME] = g_param_spec_string ("app-name",
+ "App name",
+ "Application name",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+ /**
+ * MateMixerControl:app-id:
+ *
+ * Identifier of the application (e.g. org.example.app).
+ */
+ properties[PROP_APP_ID] = g_param_spec_string ("app-id",
+ "App ID",
+ "Application identifier",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+ /**
+ * MateMixerControl:app-version:
+ *
+ * Version of the application.
+ */
+ properties[PROP_APP_VERSION] = g_param_spec_string ("app-version",
+ "App version",
+ "Application version",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+ /**
+ * MateMixerControl:app-icon:
+ *
+ * An XDG icon name for the application.
+ */
+ properties[PROP_APP_ICON] = g_param_spec_string ("app-icon",
+ "App icon",
+ "Application icon",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ /**
+ * MateMixerControl:server-address:
+ *
+ * Address of the sound server to connect to.
+ *
+ * This feature is only supported in the PulseAudio backend. There is
+ * no need to specify an address in order to connect to the local daemon.
+ */
+ properties[PROP_SERVER_ADDRESS] = g_param_spec_string ("server-address",
+ "Server address",
+ "Sound server address",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_STATE] = g_param_spec_enum ("state",
+ "State",
+ "Current backend connection state",
+ MATE_MIXER_TYPE_STATE,
+ MATE_MIXER_STATE_IDLE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DEFAULT_INPUT] = g_param_spec_object ("default-input",
+ "Default input",
+ "Default input stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DEFAULT_OUTPUT] = g_param_spec_object ("default-output",
+ "Default output",
+ "Default output stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ signals[DEVICE_ADDED] = g_signal_new ("device-added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerControlClass, device_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[DEVICE_CHANGED] = g_signal_new ("device-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerControlClass, device_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[DEVICE_REMOVED] = g_signal_new ("device-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerControlClass, device_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[STREAM_ADDED] = g_signal_new ("stream-added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerControlClass, stream_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[STREAM_CHANGED] = g_signal_new ("stream-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerControlClass, stream_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[STREAM_REMOVED] = g_signal_new ("stream-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerControlClass, stream_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
g_type_class_add_private (object_class, sizeof (MateMixerControlPrivate));
}
@@ -86,86 +370,443 @@ mate_mixer_control_dispose (GObject *object)
G_OBJECT_CLASS (mate_mixer_control_parent_class)->dispose (object);
}
-MateMixerControl *
-mate_mixer_control_new (void)
+static void
+mate_mixer_control_finalize (GObject *object)
{
- const GList *modules;
- MateMixerControl *control;
- MateMixerBackend *backend = NULL;
- MateMixerBackendModule *module = NULL;
+ MateMixerControl *control;
+
+ control = MATE_MIXER_CONTROL (object);
+
+ g_free (control->priv->backend_data.app_name);
+ g_free (control->priv->backend_data.app_id);
+ g_free (control->priv->backend_data.app_version);
+ g_free (control->priv->backend_data.app_icon);
+ g_free (control->priv->backend_data.server_address);
+ G_OBJECT_CLASS (mate_mixer_control_parent_class)->finalize (object);
+}
+
+/**
+ * mate_mixer_control_new:
+ *
+ * Creates a new #MateMixerControl instance.
+ *
+ * Returns: a new #MateMixerControl instance or %NULL if the library has not
+ * been initialized using mate_mixer_init().
+ */
+MateMixerControl *mate_mixer_control_new (void)
+{
if (!mate_mixer_is_initialized ()) {
g_critical ("The library has not been initialized");
return NULL;
}
+ return g_object_new (MATE_MIXER_TYPE_CONTROL, NULL);
+}
+
+/**
+ * mate_mixer_control_set_backend_type:
+ * @control: a #MateMixerControl
+ * @backend_type: the sound system backend to use
+ *
+ * Makes the #MateMixerControl use the given #MateMixerBackendType.
+ *
+ * By default the backend type is determined automatically. This function can
+ * be used before mate_mixer_control_open() to alter this behavior and make the
+ * @control use the given backend.
+ *
+ * This function will fail if support for the backend is not installed in
+ * the system.
+ *
+ * Returns: %TRUE on success or %FALSE on failure.
+ */
+gboolean
+mate_mixer_control_set_backend_type (MateMixerControl *control,
+ MateMixerBackendType backend_type)
+{
+ MateMixerBackendModule *module;
+ const GList *modules;
+ const MateMixerBackendInfo *info;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
modules = mate_mixer_get_modules ();
while (modules) {
- module = MATE_MIXER_BACKEND_MODULE (modules->data);
- backend = mixer_control_init_module (module);
- if (backend != NULL)
- break;
+ module = MATE_MIXER_BACKEND_MODULE (modules->data);
+ info = mate_mixer_backend_module_get_info (module);
+ if (info->backend_type == backend_type) {
+ control->priv->backend_type = backend_type;
+ return TRUE;
+ }
modules = modules->next;
}
+ return FALSE;
+}
- /* 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 */
- if (backend == NULL)
- return NULL;
+/**
+ * mate_mixer_control_set_app_name:
+ * @control: a #MateMixerControl
+ * @app_name: the name of your application, or %NULL to unset
+ *
+ * Sets the name of the application. This feature is only supported in the
+ * PulseAudio backend.
+ *
+ * This function will fail if the current state is either
+ * %MATE_MIXER_STATE_CONNECTING or %MATE_MIXER_STATE_READY, therefore you should
+ * use it before opening a connection to the sound system.
+ *
+ * Returns: %TRUE on success or %FALSE on failure.
+ */
+gboolean
+mate_mixer_control_set_app_name (MateMixerControl *control, const gchar *app_name)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
- control = g_object_new (MATE_MIXER_TYPE_CONTROL, NULL);
+ if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ control->priv->state == MATE_MIXER_STATE_READY)
+ return FALSE;
- control->priv->module = g_object_ref (module);
- control->priv->backend = backend;
+ g_free (control->priv->backend_data.app_name);
+
+ control->priv->backend_data.app_name = g_strdup (app_name);
- return control;
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_NAME]);
+ return TRUE;
}
-MateMixerControl *
-mate_mixer_control_new_backend (MateMixerBackendType backend_type)
+/**
+ * mate_mixer_control_set_app_id:
+ * @control: a #MateMixerControl
+ * @app_id: the identifier of your application, or %NULL to unset
+ *
+ * Sets the identifier of the application (e.g. org.example.app). This feature
+ * is only supported in the PulseAudio backend.
+ *
+ * This function will fail if the current state is either
+ * %MATE_MIXER_STATE_CONNECTING or %MATE_MIXER_STATE_READY, therefore you should
+ * use it before opening a connection to the sound system.
+ *
+ * Returns: %TRUE on success or %FALSE on failure.
+ */
+gboolean
+mate_mixer_control_set_app_id (MateMixerControl *control, const gchar *app_id)
{
- const GList *modules;
- MateMixerControl *control;
- MateMixerBackend *backend = NULL;
- MateMixerBackendModule *module = NULL;
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
- if (!mate_mixer_is_initialized ()) {
- g_critical ("The library has not been initialized");
- return NULL;
- }
+ if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ control->priv->state == MATE_MIXER_STATE_READY)
+ return FALSE;
+
+ g_free (control->priv->backend_data.app_id);
+
+ control->priv->backend_data.app_id = g_strdup (app_id);
+
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_ID]);
+ return TRUE;
+}
+
+/**
+ * mate_mixer_control_set_app_version:
+ * @control: a #MateMixerControl
+ * @app_version: the version of your application, or %NULL to unset
+ *
+ * Sets the version of the application. This feature is only supported in the
+ * PulseAudio backend.
+ *
+ * This function will fail if the current state is either
+ * %MATE_MIXER_STATE_CONNECTING or %MATE_MIXER_STATE_READY, therefore you should
+ * use it before opening a connection to the sound system.
+ *
+ * Returns: %TRUE on success or %FALSE on failure.
+ */
+gboolean
+mate_mixer_control_set_app_version (MateMixerControl *control, const gchar *app_version)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+
+ if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ control->priv->state == MATE_MIXER_STATE_READY)
+ return FALSE;
+
+ g_free (control->priv->backend_data.app_version);
+
+ control->priv->backend_data.app_version = g_strdup (app_version);
+
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_VERSION]);
+ return TRUE;
+}
+
+/**
+ * mate_mixer_control_set_app_icon:
+ * @control: a #MateMixerControl
+ * @app_icon: the XDG icon name of your application, or %NULL to unset
+ *
+ * Sets the XDG icon name of the application. This feature is only supported in
+ * the PulseAudio backend.
+ *
+ * This function will fail if the current state is either
+ * %MATE_MIXER_STATE_CONNECTING or %MATE_MIXER_STATE_READY, therefore you should
+ * use it before opening a connection to the sound system.
+ *
+ * Returns: %TRUE on success or %FALSE on failure.
+ */
+gboolean
+mate_mixer_control_set_app_icon (MateMixerControl *control, const gchar *app_icon)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+
+ if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ control->priv->state == MATE_MIXER_STATE_READY)
+ return FALSE;
+
+ g_free (control->priv->backend_data.app_icon);
+
+ control->priv->backend_data.app_icon = g_strdup (app_icon);
+
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_ICON]);
+ return TRUE;
+}
+
+/**
+ * mate_mixer_control_set_server_address:
+ * @control: a #MateMixerControl
+ * @address: the address of the sound server to connect to or %NULL
+ *
+ * Sets the address of the sound server. This feature is only supported in the
+ * PulseAudio backend. If the address is not set, the default PulseAudio sound
+ * server will be used, which is normally the local daemon.
+ *
+ * This function will fail if the current state is either
+ * %MATE_MIXER_STATE_CONNECTING or %MATE_MIXER_STATE_READY, therefore you should
+ * use it before opening a connection to the sound system.
+ *
+ * Returns: %TRUE on success or %FALSE on failure.
+ */
+gboolean
+mate_mixer_control_set_server_address (MateMixerControl *control, const gchar *address)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+
+ if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ control->priv->state == MATE_MIXER_STATE_READY)
+ return FALSE;
+
+ g_free (control->priv->backend_data.server_address);
+
+ control->priv->backend_data.server_address = g_strdup (address);
+
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_SERVER_ADDRESS]);
+ return TRUE;
+}
+
+/**
+ * mate_mixer_control_open:
+ * @control: a #MateMixerControl
+ *
+ * Opens connection to a sound system. Unless the backend type was given
+ * beforehand, the library will find a working sound system automatically.
+ * If the automatic discovery fails to find a working sound system, it will
+ * use the "Null" backend, which provides no functionality.
+ *
+ * This function can complete the operation either synchronously or
+ * asynchronously.
+ *
+ * In case this function returns %TRUE, you should check the current state of
+ * the connection using mate_mixer_control_get_state(). If the current state
+ * is %MATE_MIXER_STATE_READY, the connection has been established successfully.
+ * Otherwise the state will be set to %MATE_MIXER_STATE_CONNECTING and the
+ * result of the operation will be determined asynchronously. You should wait
+ * for the state transition by connecting to the notification signal of the
+ * #MateMixerControl:state property.
+ *
+ * In case this function returns %FALSE, it is not possible to use the selected
+ * backend and the state will be set to %MATE_MIXER_STATE_FAILED.
+ *
+ * Returns: %TRUE on success or if the result will be determined asynchronously,
+ * or %FALSE on failure.
+ */
+gboolean
+mate_mixer_control_open (MateMixerControl *control)
+{
+ MateMixerBackendModule *module = NULL;
+ MateMixerState state;
+ const GList *modules;
+ const MateMixerBackendInfo *info = NULL;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+ g_return_val_if_fail (control->priv->state != MATE_MIXER_STATE_CONNECTING &&
+ control->priv->state != MATE_MIXER_STATE_READY, FALSE);
+ /* We are going to choose the first backend to try. It will be either the one
+ * specified by the user or the one with the highest priority */
modules = mate_mixer_get_modules ();
- while (modules) {
- const MateMixerBackendInfo *info;
- module = MATE_MIXER_BACKEND_MODULE (modules->data);
- info = mate_mixer_backend_module_get_info (module);
+ if (control->priv->backend_type != MATE_MIXER_BACKEND_UNKNOWN) {
+ while (modules) {
+ const MateMixerBackendInfo *info;
- if (info->backend_type == backend_type) {
- backend = mixer_control_init_module (module);
- break;
+ module = MATE_MIXER_BACKEND_MODULE (modules->data);
+ info = mate_mixer_backend_module_get_info (module);
+
+ if (info->backend_type == control->priv->backend_type)
+ break;
+
+ module = NULL;
+ modules = modules->next;
}
- modules = modules->next;
+ } else {
+ /* The highest priority module is on the top of the list */
+ module = MATE_MIXER_BACKEND_MODULE (modules->data);
}
- /* The initialization might fail or the selected module might be absent */
- if (backend == NULL)
- return NULL;
+ if (module == NULL) {
+ /* Most likely the selected backend is not installed */
+ control_change_state (control, MATE_MIXER_STATE_FAILED);
+ return FALSE;
+ }
- control = g_object_new (MATE_MIXER_TYPE_CONTROL, NULL);
+ if (info == NULL)
+ info = mate_mixer_backend_module_get_info (module);
control->priv->module = g_object_ref (module);
- control->priv->backend = backend;
+ control->priv->backend = g_object_newv (info->g_type, 0, NULL);
+
+ mate_mixer_backend_set_data (control->priv->backend, &control->priv->backend_data);
+
+ /* This transitional state is always present, it will change to MATE_MIXER_STATE_READY
+ * or MATE_MIXER_STATE_FAILED either instantly or asynchronously */
+ control_change_state (control, MATE_MIXER_STATE_CONNECTING);
+
+ /* The backend initialization might fail in case it is known right now that
+ * it is unusable */
+ if (!mate_mixer_backend_open (control->priv->backend)) {
+ if (control->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) {
+ /* User didn't request a specific backend, so try another one */
+ return control_try_next_backend (control);
+ }
+
+ /* User requested a specific backend and it failed */
+ g_clear_object (&control->priv->module);
+ g_clear_object (&control->priv->backend);
+
+ control_change_state (control, MATE_MIXER_STATE_FAILED);
+ return FALSE;
+ }
- return control;
+ state = mate_mixer_backend_get_state (control->priv->backend);
+
+ if (G_UNLIKELY (state != MATE_MIXER_STATE_READY &&
+ state != MATE_MIXER_STATE_CONNECTING)) {
+ /* The backend should not be in this state */
+ g_warn_if_reached ();
+
+ g_clear_object (&control->priv->module);
+ g_clear_object (&control->priv->backend);
+ control_change_state (control, MATE_MIXER_STATE_FAILED);
+ return FALSE;
+ }
+
+ g_signal_connect (control->priv->backend,
+ "notify::state",
+ G_CALLBACK (control_state_changed_cb),
+ control);
+
+ control_change_state (control, state);
+ return TRUE;
+}
+
+/**
+ * mate_mixer_control_get_state:
+ * @control: a #MateMixerControl
+ *
+ * Gets the current backend connection state of the #MateMixerControl.
+ *
+ * Returns: The current connection state.
+ */
+MateMixerState
+mate_mixer_control_get_state (MateMixerControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), MATE_MIXER_STATE_UNKNOWN);
+
+ return control->priv->state;
}
+/**
+ * mate_mixer_control_get_device:
+ * @control: a #MateMixerControl
+ * @name: a device name
+ *
+ * Gets the devices with the given name.
+ *
+ * Returns: a #MateMixerDevice or %NULL if there is no such device.
+ */
+MateMixerDevice *
+mate_mixer_control_get_device (MateMixerControl *control, const gchar *name)
+{
+ GList *list;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ list = control->priv->devices;
+ while (list) {
+ MateMixerDevice *device = MATE_MIXER_DEVICE (list->data);
+
+ if (!strcmp (name, mate_mixer_device_get_name (device)))
+ return device;
+
+ list = list->next;
+ }
+ return NULL;
+}
+
+/**
+ * mate_mixer_control_get_stream:
+ * @control: a #MateMixerControl
+ * @name: a stream name
+ *
+ * Gets the stream with the given name.
+ *
+ * Returns: a #MateMixerStream or %NULL if there is no such stream.
+ */
+MateMixerStream *
+mate_mixer_control_get_stream (MateMixerControl *control, const gchar *name)
+{
+ GList *list;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ list = control->priv->streams;
+ while (list) {
+ MateMixerStream *stream = MATE_MIXER_STREAM (list->data);
+
+ if (!strcmp (name, mate_mixer_stream_get_name (stream)))
+ return stream;
+
+ list = list->next;
+ }
+ return NULL;
+}
+
+/**
+ * mate_mixer_control_list_devices:
+ * @control: a #MateMixerControl
+ *
+ * Gets a list of devices. Each list item is a #MateMixerDevice representing a
+ * hardware or software sound device in the system.
+ *
+ * The returned #GList is owned by the #MateMixerControl and may be invalidated
+ * at any time.
+ *
+ * Returns: a #GList of all devices in the system or %NULL if there are none or
+ * you are not connected to a sound system.
+ */
const GList *
mate_mixer_control_list_devices (MateMixerControl *control)
{
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
/* This list is cached here and invalidated when the backend notifies us
* about a change */
@@ -176,10 +817,24 @@ mate_mixer_control_list_devices (MateMixerControl *control)
return (const GList *) control->priv->devices;
}
+/**
+ * mate_mixer_control_list_streams:
+ * @control: a #MateMixerControl
+ *
+ * Gets a list of streams. Each list item is a #MateMixerStream representing an
+ * input or output of a sound device.
+ *
+ * The returned #GList is owned by the #MateMixerControl and may be invalidated
+ * at any time.
+ *
+ * Returns: a #GList of all streams in the system or %NULL if there are none or
+ * you are not connected to a sound system.
+ */
const GList *
mate_mixer_control_list_streams (MateMixerControl *control)
{
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
/* This list is cached here and invalidated when the backend notifies us
* about a change */
@@ -190,58 +845,330 @@ mate_mixer_control_list_streams (MateMixerControl *control)
return (const GList *) control->priv->streams;
}
+/**
+ * mate_mixer_control_get_default_input_stream:
+ * @control: a #MateMixerControl
+ *
+ * Gets the default input stream. The returned stream is where sound input is
+ * directed to by default.
+ *
+ * Returns: a #MateMixerStream or %NULL if there are no input streams in
+ * the system.
+ */
MateMixerStream *
mate_mixer_control_get_default_input_stream (MateMixerControl *control)
{
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
return mate_mixer_backend_get_default_input_stream (control->priv->backend);
}
+/**
+ * mate_mixer_control_set_default_input_stream:
+ * @control: a #MateMixerControl
+ * @stream: a #MateMixerStream to set as the default input stream
+ *
+ * Changes the default input stream in the system.
+ *
+ * Returns: %TRUE on success or %FALSE on failure.
+ */
+gboolean
+mate_mixer_control_set_default_input_stream (MateMixerControl *control,
+ MateMixerStream *stream)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
+
+ return mate_mixer_backend_set_default_input_stream (control->priv->backend, stream);
+}
+
+/**
+ * mate_mixer_control_get_default_output_stream:
+ * @control: a #MateMixerControl
+ *
+ * Gets the default output stream. The returned stream is where sound output is
+ * directed to by default.
+ *
+ * Returns: a #MateMixerStream or %NULL if there are no output streams in
+ * the system.
+ */
MateMixerStream *
mate_mixer_control_get_default_output_stream (MateMixerControl *control)
{
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
return mate_mixer_backend_get_default_output_stream (control->priv->backend);
}
+/**
+ * mate_mixer_control_set_default_output_stream:
+ * @control: a #MateMixerControl
+ * @stream: a #MateMixerStream to set as the default output stream
+ *
+ * Changes the default output stream in the system.
+ *
+ * Returns: %TRUE on success or %FALSE on failure.
+ */
+gboolean
+mate_mixer_control_set_default_output_stream (MateMixerControl *control,
+ MateMixerStream *stream)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
+
+ return mate_mixer_backend_set_default_input_stream (control->priv->backend, stream);
+}
+
+/**
+ * mate_mixer_control_get_backend_name:
+ * @control: a #MateMixerControl
+ *
+ * Gets the name of the currently used backend. The @control must be in the
+ * %MATE_MIXER_STATE_READY state.
+ *
+ * Returns: the name or %NULL on error.
+ */
const gchar *
mate_mixer_control_get_backend_name (MateMixerControl *control)
{
const MateMixerBackendInfo *info;
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
info = mate_mixer_backend_module_get_info (control->priv->module);
return info->name;
}
+/**
+ * mate_mixer_control_get_backend_type:
+ * @control: a #MateMixerControl
+ *
+ * Gets the type of the currently used backend. The @control must be in the
+ * %MATE_MIXER_STATE_READY state.
+ *
+ * Returns: the backend type or %MATE_MIXER_BACKEND_UNKNOWN on error.
+ */
MateMixerBackendType
mate_mixer_control_get_backend_type (MateMixerControl *control)
{
const MateMixerBackendInfo *info;
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+ g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, FALSE);
info = mate_mixer_backend_module_get_info (control->priv->module);
return info->backend_type;
}
-static MateMixerBackend *
-mixer_control_init_module (MateMixerBackendModule *module)
+static gboolean
+control_try_next_backend (MateMixerControl *control)
{
- MateMixerBackend *backend;
- const MateMixerBackendInfo *info;
+ const GList *modules;
+ MateMixerBackendModule *module = NULL;
+
+ modules = mate_mixer_get_modules ();
+ while (modules) {
+ if (control->priv->module == modules->data) {
+ /* Found the last tested backend, try to use the next one with a lower
+ * priority unless we have reached the end of the list */
+ if (modules->next)
+ module = MATE_MIXER_BACKEND_MODULE (modules->next->data);
+ break;
+ }
+ modules = modules->next;
+ }
+ g_clear_object (&control->priv->module);
+ g_clear_object (&control->priv->backend);
- info = mate_mixer_backend_module_get_info (module);
- backend = g_object_newv (info->g_type, 0, NULL);
+ if (module == NULL) {
+ /* This shouldn't happen under normal circumstances as the lowest
+ * priority module is the "Null" module which never fails to initialize,
+ * but in a broken installation this module could be missing */
+ control_change_state (control, MATE_MIXER_STATE_FAILED);
+ return FALSE;
+ }
- if (!mate_mixer_backend_open (backend)) {
- g_object_unref (backend);
- return NULL;
+ control->priv->module = g_object_ref (module);
+ control->priv->backend =
+ g_object_newv (mate_mixer_backend_module_get_info (module)->g_type,
+ 0,
+ NULL);
+
+ if (!mate_mixer_backend_open (control->priv->backend))
+ return control_try_next_backend (control);
+
+ g_signal_connect (control->priv->backend,
+ "notify::state",
+ G_CALLBACK (control_state_changed_cb),
+ control);
+ return TRUE;
+}
+
+static void
+control_change_state (MateMixerControl *control, MateMixerState state)
+{
+ if (control->priv->state == state)
+ return;
+
+ control->priv->state = state;
+
+ if (state == MATE_MIXER_STATE_READY) {
+ /* It is safe to connect to the backend signals after reaching the READY
+ * state, because the app is not allowed to query any data before that state */
+ g_signal_connect (control->priv->backend,
+ "device-added",
+ G_CALLBACK (control_device_added_cb),
+ control);
+ g_signal_connect (control->priv->backend,
+ "device-changed",
+ G_CALLBACK (control_device_changed_cb),
+ control);
+ g_signal_connect (control->priv->backend,
+ "device-removed",
+ G_CALLBACK (control_device_removed_cb),
+ control);
+ g_signal_connect (control->priv->backend,
+ "stream-added",
+ G_CALLBACK (control_stream_added_cb),
+ control);
+ g_signal_connect (control->priv->backend,
+ "stream-changed",
+ G_CALLBACK (control_stream_changed_cb),
+ control);
+ g_signal_connect (control->priv->backend,
+ "stream-removed",
+ G_CALLBACK (control_stream_removed_cb),
+ control);
+ }
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_STATE]);
+}
+
+static void
+control_state_changed_cb (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerControl *control)
+{
+ MateMixerState state = mate_mixer_backend_get_state (backend);
+
+ switch (state) {
+ case MATE_MIXER_STATE_READY:
+ control_change_state (control, state);
+ break;
+
+ case MATE_MIXER_STATE_FAILED:
+ control_try_next_backend (control);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+control_device_added_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
+{
+ if (control->priv->devices) {
+ g_list_free_full (control->priv->devices, g_object_unref);
+ control->priv->devices = NULL;
+ }
+
+ g_debug ("Device added: %s", name);
+
+ g_signal_emit (G_OBJECT (control),
+ signals[DEVICE_ADDED],
+ 0,
+ name);
+}
+
+static void
+control_device_changed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
+{
+ /* Do not invalidate the list of devices here as the list has not changed,
+ * only some properties of a device */
+
+ g_debug ("Device changed: %s", name);
+
+ g_signal_emit (G_OBJECT (control),
+ signals[DEVICE_CHANGED],
+ 0,
+ name);
+}
+
+static void
+control_device_removed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
+{
+ if (control->priv->devices) {
+ g_list_free_full (control->priv->devices, g_object_unref);
+ control->priv->devices = NULL;
}
- return backend;
+
+ g_debug ("Device removed: %s", name);
+
+ g_signal_emit (G_OBJECT (control),
+ signals[DEVICE_REMOVED],
+ 0,
+ name);
+}
+
+static void
+control_stream_added_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
+{
+ if (control->priv->streams) {
+ g_list_free_full (control->priv->streams, g_object_unref);
+ control->priv->streams = NULL;
+ }
+
+ g_debug ("Stream added: %s", name);
+
+ g_signal_emit (G_OBJECT (control),
+ signals[STREAM_ADDED],
+ 0,
+ name);
+}
+
+static void
+control_stream_changed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
+{
+ /* Do not invalidate the list of streams here as the list has not changed,
+ * only some properties of a stream */
+
+ g_debug ("Stream changed: %s", name);
+
+ g_signal_emit (G_OBJECT (control),
+ signals[STREAM_CHANGED],
+ 0,
+ name);
+}
+
+static void
+control_stream_removed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
+{
+ if (control->priv->streams) {
+ g_list_free_full (control->priv->streams, g_object_unref);
+ control->priv->streams = NULL;
+ }
+
+ g_debug ("Stream removed: %s", name);
+
+ g_signal_emit (G_OBJECT (control),
+ signals[STREAM_REMOVED],
+ 0,
+ name);
}
diff --git a/libmatemixer/matemixer-control.h b/libmatemixer/matemixer-control.h
index 3482fbb..ad48768 100644
--- a/libmatemixer/matemixer-control.h
+++ b/libmatemixer/matemixer-control.h
@@ -43,26 +43,79 @@ typedef struct _MateMixerControl MateMixerControl;
typedef struct _MateMixerControlClass MateMixerControlClass;
typedef struct _MateMixerControlPrivate MateMixerControlPrivate;
+/**
+ * MateMixerControl:
+ *
+ * The #MateMixerControl structure contains only private data and should only
+ * be accessed using the provided API.
+ */
struct _MateMixerControl
{
- GObject parent;
-
- MateMixerControlPrivate *priv;
+ /*< private >*/
+ GObject parent;
+ MateMixerControlPrivate *priv;
};
+/**
+ * MateMixerControlClass:
+ *
+ * The class structure of #MateMixerControl.
+ */
struct _MateMixerControlClass
{
- GObjectClass parent;
-};
+ /*< private >*/
+ GObjectClass parent;
-GType mate_mixer_control_get_type (void) G_GNUC_CONST;
+ /* Signals */
+ void (*device_added) (MateMixerControl *control,
+ const gchar *name);
+ void (*device_changed) (MateMixerControl *control,
+ const gchar *name);
+ void (*device_removed) (MateMixerControl *control,
+ const gchar *name);
+ void (*stream_added) (MateMixerControl *control,
+ const gchar *name);
+ void (*stream_changed) (MateMixerControl *control,
+ const gchar *name);
+ void (*stream_removed) (MateMixerControl *control,
+ const gchar *name);
+};
+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);
+
+gboolean mate_mixer_control_set_backend_type (MateMixerControl *control,
+ MateMixerBackendType backend_type);
+gboolean mate_mixer_control_set_app_name (MateMixerControl *control,
+ const gchar *app_name);
+gboolean mate_mixer_control_set_app_id (MateMixerControl *control,
+ const gchar *app_id);
+gboolean mate_mixer_control_set_app_version (MateMixerControl *control,
+ const gchar *app_version);
+gboolean mate_mixer_control_set_app_icon (MateMixerControl *control,
+ const gchar *app_icon);
+gboolean mate_mixer_control_set_server_address (MateMixerControl *control,
+ const gchar *address);
+gboolean mate_mixer_control_open (MateMixerControl *control);
+
+MateMixerState mate_mixer_control_get_state (MateMixerControl *control);
+
+MateMixerDevice * mate_mixer_control_get_device (MateMixerControl *control,
+ const gchar *name);
+MateMixerStream * mate_mixer_control_get_stream (MateMixerControl *control,
+ const gchar *name);
+
const GList * mate_mixer_control_list_devices (MateMixerControl *control);
const GList * mate_mixer_control_list_streams (MateMixerControl *control);
+
MateMixerStream * mate_mixer_control_get_default_input_stream (MateMixerControl *control);
+gboolean mate_mixer_control_set_default_input_stream (MateMixerControl *control,
+ MateMixerStream *stream);
+
MateMixerStream * mate_mixer_control_get_default_output_stream (MateMixerControl *control);
+gboolean mate_mixer_control_set_default_output_stream (MateMixerControl *control,
+ MateMixerStream *stream);
+
const gchar * mate_mixer_control_get_backend_name (MateMixerControl *control);
MateMixerBackendType mate_mixer_control_get_backend_type (MateMixerControl *control);
diff --git a/libmatemixer/matemixer-device.c b/libmatemixer/matemixer-device.c
index cd5a47c..a022877 100644
--- a/libmatemixer/matemixer-device.c
+++ b/libmatemixer/matemixer-device.c
@@ -19,7 +19,6 @@
#include <glib-object.h>
#include "matemixer-device.h"
-#include "matemixer-enum-types.h"
#include "matemixer-profile.h"
G_DEFINE_INTERFACE (MateMixerDevice, mate_mixer_device, G_TYPE_OBJECT)
@@ -169,17 +168,17 @@ mate_mixer_device_get_active_profile (MateMixerDevice *device)
}
gboolean
-mate_mixer_device_set_active_profile (MateMixerDevice *device, const gchar *profile_name)
+mate_mixer_device_set_active_profile (MateMixerDevice *device, const gchar *profile)
{
MateMixerDeviceInterface *iface;
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (profile_name != NULL, FALSE);
+ g_return_val_if_fail (profile != NULL, FALSE);
iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
if (iface->set_active_profile)
- return iface->set_active_profile (device, profile_name);
+ return iface->set_active_profile (device, profile);
return FALSE;
}
diff --git a/libmatemixer/matemixer-device.h b/libmatemixer/matemixer-device.h
index 3b25313..d814847 100644
--- a/libmatemixer/matemixer-device.h
+++ b/libmatemixer/matemixer-device.h
@@ -39,6 +39,7 @@ typedef struct _MateMixerDeviceInterface MateMixerDeviceInterface;
struct _MateMixerDeviceInterface
{
+ /*< private >*/
GTypeInterface parent;
const gchar *(*get_name) (MateMixerDevice *device);
@@ -49,11 +50,10 @@ struct _MateMixerDeviceInterface
const GList *(*list_profiles) (MateMixerDevice *device);
MateMixerProfile *(*get_active_profile) (MateMixerDevice *device);
gboolean (*set_active_profile) (MateMixerDevice *device,
- const gchar *profile_name);
+ const gchar *profile);
};
-GType mate_mixer_device_get_type (void) G_GNUC_CONST;
-
+GType mate_mixer_device_get_type (void) G_GNUC_CONST;
const gchar * mate_mixer_device_get_name (MateMixerDevice *device);
const gchar * mate_mixer_device_get_description (MateMixerDevice *device);
const gchar * mate_mixer_device_get_icon (MateMixerDevice *device);
@@ -62,7 +62,7 @@ const GList * mate_mixer_device_list_ports (MateMixerDevice *device)
const GList * mate_mixer_device_list_profiles (MateMixerDevice *device);
MateMixerProfile *mate_mixer_device_get_active_profile (MateMixerDevice *device);
gboolean mate_mixer_device_set_active_profile (MateMixerDevice *device,
- const gchar *profile_name);
+ const gchar *profile);
G_END_DECLS
diff --git a/libmatemixer/matemixer-enum-types.c b/libmatemixer/matemixer-enum-types.c
index 0d1c57d..43249a3 100644
--- a/libmatemixer/matemixer-enum-types.c
+++ b/libmatemixer/matemixer-enum-types.c
@@ -24,6 +24,27 @@
*/
GType
+mate_mixer_state_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ { MATE_MIXER_STATE_IDLE, "MATE_MIXER_STATE_IDLE", "idle" },
+ { MATE_MIXER_STATE_CONNECTING, "MATE_MIXER_STATE_CONNECTING", "connecting" },
+ { MATE_MIXER_STATE_READY, "MATE_MIXER_STATE_READY", "ready" },
+ { MATE_MIXER_STATE_FAILED, "MATE_MIXER_STATE_FAILED", "failed" },
+ { MATE_MIXER_STATE_UNKNOWN, "MATE_MIXER_STATE_UNKNOWN", "unknown" },
+ { 0, NULL, NULL }
+ };
+ etype = g_enum_register_static (
+ g_intern_static_string ("MateMixerState"),
+ values);
+ }
+ return etype;
+}
+
+GType
mate_mixer_backend_type_get_type (void)
{
static GType etype = 0;
@@ -68,14 +89,19 @@ mate_mixer_stream_flags_get_type (void)
if (etype == 0) {
static const GFlagsValue values[] = {
+ { MATE_MIXER_STREAM_NO_FLAGS, "MATE_MIXER_STREAM_NO_FLAGS", "no-flags" },
{ MATE_MIXER_STREAM_INPUT, "MATE_MIXER_STREAM_INPUT", "input" },
{ MATE_MIXER_STREAM_OUTPUT, "MATE_MIXER_STREAM_OUTPUT", "output" },
{ MATE_MIXER_STREAM_CLIENT, "MATE_MIXER_STREAM_CLIENT", "client" },
- { MATE_MIXER_STREAM_VIRTUAL, "MATE_MIXER_STREAM_VIRTUAL", "virtual" },
+ { MATE_MIXER_STREAM_APPLICATION, "MATE_MIXER_STREAM_APPLICATION", "application" },
{ MATE_MIXER_STREAM_OUTPUT_MONITOR, "MATE_MIXER_STREAM_OUTPUT_MONITOR", "output-monitor" },
+ { MATE_MIXER_STREAM_HAS_MUTE, "MATE_MIXER_STREAM_HAS_MUTE", "has-mute" },
+ { MATE_MIXER_STREAM_HAS_VOLUME, "MATE_MIXER_STREAM_HAS_VOLUME", "has-volume" },
+ { MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME, "MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME", "has-decibel-volume" },
+ { MATE_MIXER_STREAM_HAS_FLAT_VOLUME, "MATE_MIXER_STREAM_HAS_FLAT_VOLUME", "has-flat-volume" },
{ MATE_MIXER_STREAM_CAN_BALANCE, "MATE_MIXER_STREAM_CAN_BALANCE", "can-balance" },
{ MATE_MIXER_STREAM_CAN_FADE, "MATE_MIXER_STREAM_CAN_FADE", "can-fade" },
- { MATE_MIXER_STREAM_FLAT_VOLUME, "MATE_MIXER_STREAM_FLAT_VOLUME", "flat-volume" },
+ { MATE_MIXER_STREAM_CAN_SET_VOLUME, "MATE_MIXER_STREAM_CAN_SET_VOLUME", "can-set-volume" },
{ 0, NULL, NULL }
};
etype = g_flags_register_static (
diff --git a/libmatemixer/matemixer-enum-types.h b/libmatemixer/matemixer-enum-types.h
index ccb87a6..0275c27 100644
--- a/libmatemixer/matemixer-enum-types.h
+++ b/libmatemixer/matemixer-enum-types.h
@@ -28,19 +28,22 @@ G_BEGIN_DECLS
* https://bugzilla.gnome.org/show_bug.cgi?id=621942
*/
-#define MATE_MIXER_TYPE_BACKEND_TYPE (mate_mixer_backend_type_get_type ())
+#define MATE_MIXER_TYPE_STATE (mate_mixer_state_get_type ())
+GType mate_mixer_state_get_type (void) G_GNUC_CONST;
+
+#define MATE_MIXER_TYPE_BACKEND_TYPE (mate_mixer_backend_type_get_type ())
GType mate_mixer_backend_type_get_type (void) G_GNUC_CONST;
-#define MATE_MIXER_TYPE_PORT_STATUS (mate_mixer_port_status_get_type ())
+#define MATE_MIXER_TYPE_PORT_STATUS (mate_mixer_port_status_get_type ())
GType mate_mixer_port_status_get_type (void) G_GNUC_CONST;
-#define MATE_MIXER_TYPE_STREAM_FLAGS (mate_mixer_stream_flags_get_type ())
+#define MATE_MIXER_TYPE_STREAM_FLAGS (mate_mixer_stream_flags_get_type ())
GType mate_mixer_stream_flags_get_type (void) G_GNUC_CONST;
-#define MATE_MIXER_TYPE_STREAM_STATUS (mate_mixer_stream_status_get_type ())
+#define MATE_MIXER_TYPE_STREAM_STATUS (mate_mixer_stream_status_get_type ())
GType mate_mixer_stream_status_get_type (void) G_GNUC_CONST;
-#define MATE_MIXER_TYPE_CHANNEL_POSITION (mate_mixer_channel_position_get_type ())
+#define MATE_MIXER_TYPE_CHANNEL_POSITION (mate_mixer_channel_position_get_type ())
GType mate_mixer_channel_position_get_type (void) G_GNUC_CONST;
G_END_DECLS
diff --git a/libmatemixer/matemixer-enums.h b/libmatemixer/matemixer-enums.h
index cccb70d..5fc348d 100644
--- a/libmatemixer/matemixer-enums.h
+++ b/libmatemixer/matemixer-enums.h
@@ -24,7 +24,15 @@
*/
typedef enum {
- MATE_MIXER_BACKEND_UNKNOWN,
+ MATE_MIXER_STATE_IDLE = 0,
+ MATE_MIXER_STATE_CONNECTING,
+ MATE_MIXER_STATE_READY,
+ MATE_MIXER_STATE_FAILED,
+ MATE_MIXER_STATE_UNKNOWN
+} MateMixerState;
+
+typedef enum {
+ MATE_MIXER_BACKEND_UNKNOWN = 0,
MATE_MIXER_BACKEND_PULSE,
MATE_MIXER_BACKEND_NULL
} MateMixerBackendType;
@@ -36,29 +44,34 @@ typedef enum {
} MateMixerPortStatus;
typedef enum { /*< flags >*/
- MATE_MIXER_STREAM_INPUT = 1 << 0,
- MATE_MIXER_STREAM_OUTPUT = 1 << 1,
- MATE_MIXER_STREAM_CLIENT = 1 << 2,
- MATE_MIXER_STREAM_VIRTUAL = 1 << 3,
- MATE_MIXER_STREAM_OUTPUT_MONITOR = 1 << 4,
- MATE_MIXER_STREAM_CAN_BALANCE = 1 << 5,
- MATE_MIXER_STREAM_CAN_FADE = 1 << 6,
- MATE_MIXER_STREAM_FLAT_VOLUME = 1 << 7
+ MATE_MIXER_STREAM_NO_FLAGS = 0,
+ MATE_MIXER_STREAM_INPUT = 1 << 0,
+ MATE_MIXER_STREAM_OUTPUT = 1 << 1,
+ MATE_MIXER_STREAM_CLIENT = 1 << 2,
+ MATE_MIXER_STREAM_APPLICATION = 1 << 3,
+ MATE_MIXER_STREAM_OUTPUT_MONITOR = 1 << 4,
+ MATE_MIXER_STREAM_HAS_MUTE = 1 << 5,
+ MATE_MIXER_STREAM_HAS_VOLUME = 1 << 6,
+ MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME = 1 << 7,
+ MATE_MIXER_STREAM_HAS_FLAT_VOLUME = 1 << 8,
+ MATE_MIXER_STREAM_CAN_BALANCE = 1 << 9,
+ MATE_MIXER_STREAM_CAN_FADE = 1 << 10,
+ MATE_MIXER_STREAM_CAN_SET_VOLUME = 1 << 11
} MateMixerStreamFlags;
typedef enum {
- MATE_MIXER_STREAM_UNKNOWN_STATUS,
- MATE_MIXER_STREAM_RUNNING,
- MATE_MIXER_STREAM_IDLE,
- MATE_MIXER_STREAM_SUSPENDED
+ MATE_MIXER_STREAM_UNKNOWN_STATUS,
+ MATE_MIXER_STREAM_RUNNING,
+ MATE_MIXER_STREAM_IDLE,
+ MATE_MIXER_STREAM_SUSPENDED
} MateMixerStreamStatus;
typedef enum {
- MATE_MIXER_CHANNEL_UNKNOWN_POSITION,
- MATE_MIXER_CHANNEL_MONO,
- MATE_MIXER_CHANNEL_FRONT_LEFT,
- MATE_MIXER_CHANNEL_FRONT_RIGHT,
- MATE_MIXER_CHANNEL_FRONT_CENTER,
+ MATE_MIXER_CHANNEL_UNKNOWN_POSITION,
+ MATE_MIXER_CHANNEL_MONO,
+ MATE_MIXER_CHANNEL_FRONT_LEFT,
+ MATE_MIXER_CHANNEL_FRONT_RIGHT,
+ MATE_MIXER_CHANNEL_FRONT_CENTER,
MATE_MIXER_CHANNEL_LFE,
MATE_MIXER_CHANNEL_BACK_LEFT,
MATE_MIXER_CHANNEL_BACK_RIGHT,
@@ -67,13 +80,13 @@ typedef enum {
MATE_MIXER_CHANNEL_BACK_CENTER,
MATE_MIXER_CHANNEL_SIDE_LEFT,
MATE_MIXER_CHANNEL_SIDE_RIGHT,
- MATE_MIXER_CHANNEL_TOP_FRONT_LEFT,
- MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT,
- MATE_MIXER_CHANNEL_TOP_FRONT_CENTER,
+ MATE_MIXER_CHANNEL_TOP_FRONT_LEFT,
+ MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT,
+ MATE_MIXER_CHANNEL_TOP_FRONT_CENTER,
MATE_MIXER_CHANNEL_TOP_CENTER,
- MATE_MIXER_CHANNEL_TOP_BACK_LEFT,
- MATE_MIXER_CHANNEL_TOP_BACK_RIGHT,
- MATE_MIXER_CHANNEL_TOP_BACK_CENTER
+ MATE_MIXER_CHANNEL_TOP_BACK_LEFT,
+ MATE_MIXER_CHANNEL_TOP_BACK_RIGHT,
+ MATE_MIXER_CHANNEL_TOP_BACK_CENTER
} MateMixerChannelPosition;
#endif /* MATEMIXER_ENUMS_H */
diff --git a/libmatemixer/matemixer-port.c b/libmatemixer/matemixer-port.c
index c4b2de3..7ac21f7 100644
--- a/libmatemixer/matemixer-port.c
+++ b/libmatemixer/matemixer-port.c
@@ -27,12 +27,11 @@ struct _MateMixerPortPrivate
gchar *name;
gchar *description;
gchar *icon;
- guint32 priority;
+ gulong priority;
MateMixerPortStatus status;
};
-enum
-{
+enum {
PROP_0,
PROP_NAME,
PROP_DESCRIPTION,
@@ -71,7 +70,7 @@ mate_mixer_port_get_property (GObject *object,
g_value_set_string (value, port->priv->icon);
break;
case PROP_PRIORITY:
- g_value_set_uint (value, port->priv->priority);
+ g_value_set_ulong (value, port->priv->priority);
break;
case PROP_STATUS:
g_value_set_enum (value, port->priv->status);
@@ -103,7 +102,7 @@ mate_mixer_port_set_property (GObject *object,
port->priv->icon = g_strdup (g_value_get_string (value));
break;
case PROP_PRIORITY:
- port->priv->priority = g_value_get_uint (value);
+ port->priv->priority = g_value_get_ulong (value);
break;
case PROP_STATUS:
port->priv->status = g_value_get_enum (value);
@@ -124,53 +123,48 @@ mate_mixer_port_class_init (MateMixerPortClass *klass)
object_class->get_property = mate_mixer_port_get_property;
object_class->set_property = mate_mixer_port_set_property;
- properties[PROP_NAME] =
- g_param_spec_string ("name",
- "Name",
- "Name of the port",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_DESCRIPTION] =
- g_param_spec_string ("description",
- "Description",
- "Description of the port",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_ICON] =
- g_param_spec_string ("icon",
- "Icon",
- "Name of the port icon",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_PRIORITY] =
- g_param_spec_uint ("priority",
- "Priority",
- "Priority of the port",
- 0,
- G_MAXUINT32,
- 0,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_STATUS] =
- g_param_spec_enum ("status",
- "Status",
- "Status for the port",
- MATE_MIXER_TYPE_PORT_STATUS,
- MATE_MIXER_PORT_UNKNOWN_STATUS,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
+ properties[PROP_NAME] = g_param_spec_string ("name",
+ "Name",
+ "Name of the port",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DESCRIPTION] = g_param_spec_string ("description",
+ "Description",
+ "Description of the port",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ICON] = g_param_spec_string ("icon",
+ "Icon",
+ "Name of the port icon",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_PRIORITY] = g_param_spec_ulong ("priority",
+ "Priority",
+ "Priority of the port",
+ 0,
+ G_MAXULONG,
+ 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_STATUS] = g_param_spec_enum ("status",
+ "Status",
+ "Status for the port",
+ MATE_MIXER_TYPE_PORT_STATUS,
+ MATE_MIXER_PORT_UNKNOWN_STATUS,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
@@ -203,7 +197,7 @@ MateMixerPort *
mate_mixer_port_new (const gchar *name,
const gchar *description,
const gchar *icon,
- guint32 priority,
+ gulong priority,
MateMixerPortStatus status)
{
return g_object_new (MATE_MIXER_TYPE_PORT,
@@ -239,7 +233,7 @@ mate_mixer_port_get_icon (MateMixerPort *port)
return port->priv->icon;
}
-guint32
+gulong
mate_mixer_port_get_priority (MateMixerPort *port)
{
g_return_val_if_fail (MATE_MIXER_IS_PORT (port), 0);
diff --git a/libmatemixer/matemixer-port.h b/libmatemixer/matemixer-port.h
index 581f4ec..e0a9f79 100644
--- a/libmatemixer/matemixer-port.h
+++ b/libmatemixer/matemixer-port.h
@@ -44,29 +44,29 @@ typedef struct _MateMixerPortPrivate MateMixerPortPrivate;
struct _MateMixerPort
{
- GObject parent;
-
- MateMixerPortPrivate *priv;
+ /*< private >*/
+ GObject parent;
+ MateMixerPortPrivate *priv;
};
struct _MateMixerPortClass
{
- GObjectClass parent;
+ /*< private >*/
+ GObjectClass parent;
};
-GType mate_mixer_port_get_type (void) G_GNUC_CONST;
-
-MateMixerPort * mate_mixer_port_new (const gchar *name,
- const gchar *description,
- const gchar *icon,
- guint32 priority,
- MateMixerPortStatus status);
+GType mate_mixer_port_get_type (void) G_GNUC_CONST;
+MateMixerPort * mate_mixer_port_new (const gchar *name,
+ const gchar *description,
+ const gchar *icon,
+ gulong priority,
+ MateMixerPortStatus status);
-const gchar * mate_mixer_port_get_name (MateMixerPort *port);
-const gchar * mate_mixer_port_get_description (MateMixerPort *port);
-const gchar * mate_mixer_port_get_icon (MateMixerPort *port);
-guint32 mate_mixer_port_get_priority (MateMixerPort *port);
-MateMixerPortStatus mate_mixer_port_get_status (MateMixerPort *port);
+const gchar * mate_mixer_port_get_name (MateMixerPort *port);
+const gchar * mate_mixer_port_get_description (MateMixerPort *port);
+const gchar * mate_mixer_port_get_icon (MateMixerPort *port);
+gulong mate_mixer_port_get_priority (MateMixerPort *port);
+MateMixerPortStatus mate_mixer_port_get_status (MateMixerPort *port);
G_END_DECLS
diff --git a/libmatemixer/matemixer-profile.c b/libmatemixer/matemixer-profile.c
index c32489f..38f17c7 100644
--- a/libmatemixer/matemixer-profile.c
+++ b/libmatemixer/matemixer-profile.c
@@ -24,7 +24,7 @@ struct _MateMixerProfilePrivate
{
gchar *name;
gchar *description;
- guint32 priority;
+ gulong priority;
};
enum
@@ -62,7 +62,7 @@ mate_mixer_profile_get_property (GObject *object,
g_value_set_string (value, profile->priv->description);
break;
case PROP_PRIORITY:
- g_value_set_uint (value, profile->priv->priority);
+ g_value_set_ulong (value, profile->priv->priority);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -88,7 +88,7 @@ mate_mixer_profile_set_property (GObject *object,
profile->priv->description = g_strdup (g_value_get_string (value));
break;
case PROP_PRIORITY:
- profile->priv->priority = g_value_get_uint (value);
+ profile->priv->priority = g_value_get_ulong (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -106,34 +106,31 @@ mate_mixer_profile_class_init (MateMixerProfileClass *klass)
object_class->get_property = mate_mixer_profile_get_property;
object_class->set_property = mate_mixer_profile_set_property;
- properties[PROP_NAME] =
- g_param_spec_string ("name",
- "Name",
- "Name of the profile",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_DESCRIPTION] =
- g_param_spec_string ("description",
- "Description",
- "Description of the profile",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_PRIORITY] =
- g_param_spec_uint ("priority",
- "Priority",
- "Priority of the profile",
- 0,
- G_MAXUINT32,
- 0,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
+ properties[PROP_NAME] = g_param_spec_string ("name",
+ "Name",
+ "Name of the profile",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DESCRIPTION] = g_param_spec_string ("description",
+ "Description",
+ "Description of the profile",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_PRIORITY] = g_param_spec_ulong ("priority",
+ "Priority",
+ "Priority of the profile",
+ 0,
+ G_MAXULONG,
+ 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
@@ -162,7 +159,7 @@ mate_mixer_profile_finalize (GObject *object)
}
MateMixerProfile *
-mate_mixer_profile_new (const gchar *name, const gchar *description, guint32 priority)
+mate_mixer_profile_new (const gchar *name, const gchar *description, gulong priority)
{
return g_object_new (MATE_MIXER_TYPE_PROFILE,
"name", name,
@@ -187,10 +184,10 @@ mate_mixer_profile_get_description (MateMixerProfile *profile)
return profile->priv->description;
}
-guint32
+gulong
mate_mixer_profile_get_priority (MateMixerProfile *profile)
{
- g_return_val_if_fail (MATE_MIXER_IS_PROFILE (profile), G_MAXUINT32);
+ g_return_val_if_fail (MATE_MIXER_IS_PROFILE (profile), 0);
return profile->priv->priority;
}
diff --git a/libmatemixer/matemixer-profile.h b/libmatemixer/matemixer-profile.h
index 7be140b..4ce0d1a 100644
--- a/libmatemixer/matemixer-profile.h
+++ b/libmatemixer/matemixer-profile.h
@@ -42,25 +42,25 @@ typedef struct _MateMixerProfilePrivate MateMixerProfilePrivate;
struct _MateMixerProfile
{
- GObject parent;
-
- MateMixerProfilePrivate *priv;
+ /*< private >*/
+ GObject parent;
+ MateMixerProfilePrivate *priv;
};
struct _MateMixerProfileClass
{
- GObjectClass parent;
+ /*< private >*/
+ GObjectClass parent;
};
-GType mate_mixer_profile_get_type (void) G_GNUC_CONST;
-
+GType mate_mixer_profile_get_type (void) G_GNUC_CONST;
MateMixerProfile *mate_mixer_profile_new (const gchar *name,
const gchar *description,
- guint32 priority);
+ gulong priority);
const gchar * mate_mixer_profile_get_name (MateMixerProfile *profile);
const gchar * mate_mixer_profile_get_description (MateMixerProfile *profile);
-guint32 mate_mixer_profile_get_priority (MateMixerProfile *profile);
+gulong mate_mixer_profile_get_priority (MateMixerProfile *profile);
G_END_DECLS
diff --git a/libmatemixer/matemixer-stream.c b/libmatemixer/matemixer-stream.c
index 8fd309d..e2c9820 100644
--- a/libmatemixer/matemixer-stream.c
+++ b/libmatemixer/matemixer-stream.c
@@ -66,6 +66,16 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
+ g_param_spec_flags ("flags",
+ "Flags",
+ "Capability flags of the stream",
+ MATE_MIXER_TYPE_STREAM_FLAGS,
+ MATE_MIXER_STREAM_NO_FLAGS,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
g_param_spec_enum ("status",
"Status",
"Status of the stream",
@@ -80,13 +90,14 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
"Mute",
"Mute state of the stream",
FALSE,
- G_PARAM_READABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
- g_param_spec_uint ("volume",
- "Volume",
- "Volume of the stream",
+ g_param_spec_uint ("num-channels",
+ "Number of channels",
+ "Number of volume channels in the stream",
0,
G_MAXUINT,
0,
@@ -94,6 +105,16 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
+ g_param_spec_int64 ("volume",
+ "Volume",
+ "Volume of the stream",
+ G_MININT64,
+ G_MAXINT64,
+ 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
g_param_spec_double ("volume-db",
"Volume dB",
"Volume of the stream in decibels",
@@ -128,7 +149,8 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
"Active port",
"The currently active port of the stream",
MATE_MIXER_TYPE_PORT,
- G_PARAM_READABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
}
@@ -237,7 +259,7 @@ mate_mixer_stream_set_mute (MateMixerStream *stream, gboolean mute)
return FALSE;
}
-guint32
+gint64
mate_mixer_stream_get_volume (MateMixerStream *stream)
{
MateMixerStreamInterface *iface;
@@ -253,7 +275,7 @@ mate_mixer_stream_get_volume (MateMixerStream *stream)
}
gboolean
-mate_mixer_stream_set_volume (MateMixerStream *stream, guint32 volume)
+mate_mixer_stream_set_volume (MateMixerStream *stream, gint64 volume)
{
MateMixerStreamInterface *iface;
@@ -297,7 +319,7 @@ mate_mixer_stream_set_volume_db (MateMixerStream *stream, gdouble volume_db)
return FALSE;
}
-guint8
+guint
mate_mixer_stream_get_num_channels (MateMixerStream *stream)
{
MateMixerStreamInterface *iface;
@@ -313,7 +335,7 @@ mate_mixer_stream_get_num_channels (MateMixerStream *stream)
}
MateMixerChannelPosition
-mate_mixer_stream_get_channel_position (MateMixerStream *stream, guint8 channel)
+mate_mixer_stream_get_channel_position (MateMixerStream *stream, guint channel)
{
MateMixerStreamInterface *iface;
@@ -327,8 +349,8 @@ mate_mixer_stream_get_channel_position (MateMixerStream *stream, guint8 channel)
return MATE_MIXER_CHANNEL_UNKNOWN_POSITION;
}
-guint32
-mate_mixer_stream_get_channel_volume (MateMixerStream *stream, guint8 channel)
+gint64
+mate_mixer_stream_get_channel_volume (MateMixerStream *stream, guint channel)
{
MateMixerStreamInterface *iface;
@@ -344,8 +366,8 @@ mate_mixer_stream_get_channel_volume (MateMixerStream *stream, guint8 channel)
gboolean
mate_mixer_stream_set_channel_volume (MateMixerStream *stream,
- guint8 channel,
- guint32 volume)
+ guint channel,
+ gint64 volume)
{
MateMixerStreamInterface *iface;
@@ -360,7 +382,7 @@ mate_mixer_stream_set_channel_volume (MateMixerStream *stream,
}
gdouble
-mate_mixer_stream_get_channel_volume_db (MateMixerStream *stream, guint8 channel)
+mate_mixer_stream_get_channel_volume_db (MateMixerStream *stream, guint channel)
{
MateMixerStreamInterface *iface;
@@ -376,7 +398,7 @@ mate_mixer_stream_get_channel_volume_db (MateMixerStream *stream, guint8 channel
gboolean
mate_mixer_stream_set_channel_volume_db (MateMixerStream *stream,
- guint8 channel,
+ guint channel,
gdouble volume_db)
{
MateMixerStreamInterface *iface;
@@ -407,7 +429,7 @@ mate_mixer_stream_has_position (MateMixerStream *stream,
return FALSE;
}
-guint32
+gint64
mate_mixer_stream_get_position_volume (MateMixerStream *stream,
MateMixerChannelPosition position)
{
@@ -426,7 +448,7 @@ mate_mixer_stream_get_position_volume (MateMixerStream *stream,
gboolean
mate_mixer_stream_set_position_volume (MateMixerStream *stream,
MateMixerChannelPosition position,
- guint32 volume)
+ gint64 volume)
{
MateMixerStreamInterface *iface;
@@ -533,6 +555,36 @@ mate_mixer_stream_set_fade (MateMixerStream *stream, gdouble fade)
return FALSE;
}
+gboolean
+mate_mixer_stream_suspend (MateMixerStream *stream)
+{
+ MateMixerStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
+
+ iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+
+ if (iface->suspend)
+ return iface->suspend (stream);
+
+ return FALSE;
+}
+
+gboolean
+mate_mixer_stream_resume (MateMixerStream *stream)
+{
+ MateMixerStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
+
+ iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+
+ if (iface->resume)
+ return iface->resume (stream);
+
+ return FALSE;
+}
+
const GList *
mate_mixer_stream_list_ports (MateMixerStream *stream)
{
@@ -578,3 +630,48 @@ mate_mixer_stream_set_active_port (MateMixerStream *stream, const gchar *port_na
return FALSE;
}
+
+gint64
+mate_mixer_stream_get_min_volume (MateMixerStream *stream)
+{
+ MateMixerStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0);
+
+ iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+
+ if (iface->get_min_volume)
+ return iface->get_min_volume (stream);
+
+ return 0;
+}
+
+gint64
+mate_mixer_stream_get_max_volume (MateMixerStream *stream)
+{
+ MateMixerStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0);
+
+ iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+
+ if (iface->get_max_volume)
+ return iface->get_max_volume (stream);
+
+ return 0;
+}
+
+gint64
+mate_mixer_stream_get_normal_volume (MateMixerStream *stream)
+{
+ MateMixerStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0);
+
+ iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+
+ if (iface->get_normal_volume)
+ return iface->get_normal_volume (stream);
+
+ return 0;
+}
diff --git a/libmatemixer/matemixer-stream.h b/libmatemixer/matemixer-stream.h
index a6e8dde..d773398 100644
--- a/libmatemixer/matemixer-stream.h
+++ b/libmatemixer/matemixer-stream.h
@@ -41,42 +41,44 @@ typedef struct _MateMixerStreamInterface MateMixerStreamInterface;
struct _MateMixerStreamInterface
{
+ /*< private >*/
GTypeInterface parent;
const gchar * (*get_name) (MateMixerStream *stream);
const gchar * (*get_description) (MateMixerStream *stream);
const gchar * (*get_icon) (MateMixerStream *stream);
MateMixerDevice * (*get_device) (MateMixerStream *stream);
+ MateMixerStreamFlags (*get_flags) (MateMixerStream *stream);
MateMixerStreamStatus (*get_status) (MateMixerStream *stream);
gboolean (*get_mute) (MateMixerStream *stream);
gboolean (*set_mute) (MateMixerStream *stream,
gboolean mute);
- guint32 (*get_volume) (MateMixerStream *stream);
+ guint (*get_num_channels) (MateMixerStream *stream);
+ gint64 (*get_volume) (MateMixerStream *stream);
gboolean (*set_volume) (MateMixerStream *stream,
- guint32 volume);
+ gint64 volume);
gdouble (*get_volume_db) (MateMixerStream *stream);
gboolean (*set_volume_db) (MateMixerStream *stream,
gdouble volume_db);
- guint8 (*get_num_channels) (MateMixerStream *stream);
MateMixerChannelPosition (*get_channel_position) (MateMixerStream *stream,
- guint8 channel);
- guint32 (*get_channel_volume) (MateMixerStream *stream,
- guint8 channel);
+ guint channel);
+ gint64 (*get_channel_volume) (MateMixerStream *stream,
+ guint channel);
gboolean (*set_channel_volume) (MateMixerStream *stream,
- guint8 channel,
- guint32 volume);
+ guint channel,
+ gint64 volume);
gdouble (*get_channel_volume_db) (MateMixerStream *stream,
- guint8 channel);
+ guint channel);
gboolean (*set_channel_volume_db) (MateMixerStream *stream,
- guint8 channel,
+ guint channel,
gdouble volume_db);
gboolean (*has_position) (MateMixerStream *stream,
MateMixerChannelPosition position);
- guint32 (*get_position_volume) (MateMixerStream *stream,
+ gint64 (*get_position_volume) (MateMixerStream *stream,
MateMixerChannelPosition position);
gboolean (*set_position_volume) (MateMixerStream *stream,
MateMixerChannelPosition position,
- guint32 volume);
+ gint64 volume);
gdouble (*get_position_volume_db) (MateMixerStream *stream,
MateMixerChannelPosition position);
gboolean (*set_position_volume_db) (MateMixerStream *stream,
@@ -88,57 +90,63 @@ struct _MateMixerStreamInterface
gdouble (*get_fade) (MateMixerStream *stream);
gboolean (*set_fade) (MateMixerStream *stream,
gdouble fade);
+ gboolean (*suspend) (MateMixerStream *stream);
+ gboolean (*resume) (MateMixerStream *stream);
+ const GList * (*list_ports) (MateMixerStream *stream);
MateMixerPort * (*get_active_port) (MateMixerStream *stream);
gboolean (*set_active_port) (MateMixerStream *stream,
const gchar *port_name);
- const GList * (*list_ports) (MateMixerStream *stream);
+ gint64 (*get_min_volume) (MateMixerStream *stream);
+ gint64 (*get_max_volume) (MateMixerStream *stream);
+ gint64 (*get_normal_volume) (MateMixerStream *stream);
};
-GType mate_mixer_stream_get_type (void) G_GNUC_CONST;
+GType mate_mixer_stream_get_type (void) G_GNUC_CONST;
const gchar * mate_mixer_stream_get_name (MateMixerStream *stream);
const gchar * mate_mixer_stream_get_description (MateMixerStream *stream);
const gchar * mate_mixer_stream_get_icon (MateMixerStream *stream);
MateMixerDevice * mate_mixer_stream_get_device (MateMixerStream *stream);
+MateMixerStreamFlags mate_mixer_stream_get_flags (MateMixerStream *stream);
MateMixerStreamStatus mate_mixer_stream_get_status (MateMixerStream *stream);
gboolean mate_mixer_stream_get_mute (MateMixerStream *stream);
gboolean mate_mixer_stream_set_mute (MateMixerStream *stream,
gboolean mute);
-guint32 mate_mixer_stream_get_volume (MateMixerStream *stream);
+guint mate_mixer_stream_get_num_channels (MateMixerStream *stream);
+
+gint64 mate_mixer_stream_get_volume (MateMixerStream *stream);
gboolean mate_mixer_stream_set_volume (MateMixerStream *stream,
- guint32 volume);
+ gint64 volume);
gdouble mate_mixer_stream_get_volume_db (MateMixerStream *stream);
gboolean mate_mixer_stream_set_volume_db (MateMixerStream *stream,
gdouble volume_db);
-guint8 mate_mixer_stream_get_num_channels (MateMixerStream *stream);
-
MateMixerChannelPosition mate_mixer_stream_get_channel_position (MateMixerStream *stream,
- guint8 channel);
+ guint channel);
-guint32 mate_mixer_stream_get_channel_volume (MateMixerStream *stream,
- guint8 channel);
+gint64 mate_mixer_stream_get_channel_volume (MateMixerStream *stream,
+ guint channel);
gboolean mate_mixer_stream_set_channel_volume (MateMixerStream *stream,
- guint8 channel,
- guint32 volume);
+ guint channel,
+ gint64 volume);
gdouble mate_mixer_stream_get_channel_volume_db (MateMixerStream *stream,
- guint8 channel);
+ guint channel);
gboolean mate_mixer_stream_set_channel_volume_db (MateMixerStream *stream,
- guint8 channel,
+ guint channel,
gdouble volume_db);
gboolean mate_mixer_stream_has_position (MateMixerStream *stream,
MateMixerChannelPosition position);
-guint32 mate_mixer_stream_get_position_volume (MateMixerStream *stream,
+gint64 mate_mixer_stream_get_position_volume (MateMixerStream *stream,
MateMixerChannelPosition position);
gboolean mate_mixer_stream_set_position_volume (MateMixerStream *stream,
MateMixerChannelPosition position,
- guint32 volume);
+ gint64 volume);
gdouble mate_mixer_stream_get_position_volume_db (MateMixerStream *stream,
MateMixerChannelPosition position);
@@ -154,12 +162,19 @@ gdouble mate_mixer_stream_get_fade (MateMixerStre
gboolean mate_mixer_stream_set_fade (MateMixerStream *stream,
gdouble fade);
+gboolean mate_mixer_stream_suspend (MateMixerStream *stream);
+gboolean mate_mixer_stream_resume (MateMixerStream *stream);
+
const GList * mate_mixer_stream_list_ports (MateMixerStream *stream);
MateMixerPort * mate_mixer_stream_get_active_port (MateMixerStream *stream);
gboolean mate_mixer_stream_set_active_port (MateMixerStream *stream,
const gchar *port);
+gint64 mate_mixer_stream_get_min_volume (MateMixerStream *stream);
+gint64 mate_mixer_stream_get_max_volume (MateMixerStream *stream);
+gint64 mate_mixer_stream_get_normal_volume (MateMixerStream *stream);
+
G_END_DECLS
#endif /* MATEMIXER_STREAM_H */
diff --git a/libmatemixer/matemixer-version.h.in b/libmatemixer/matemixer-version.h.in
new file mode 100644
index 0000000..17ea7b4
--- /dev/null
+++ b/libmatemixer/matemixer-version.h.in
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_VERSION_H
+#define MATEMIXER_VERSION_H
+
+/**
+ * LIBMATEMIXER_MAJOR_VERSION:
+ *
+ * Libmatemixer major version component (e.g. 1 if %LIBMATEMIXER_VERSION is 1.2.3).
+ */
+#define LIBMATEMIXER_MAJOR_VERSION (@LIBMATEMIXER_MAJOR_VERSION@)
+
+/**
+ * LIBMATEMIXER_MINOR_VERSION:
+ *
+ * Libmatemixer minor version component (e.g. 2 if %LIBMATEMIXER_VERSION is 1.2.3).
+ */
+#define LIBMATEMIXER_MINOR_VERSION (@LIBMATEMIXER_MINOR_VERSION@)
+
+/**
+ * LIBMATEMIXER_MICRO_VERSION:
+ *
+ * Libmatemixer micro version component (e.g. 3 if %LIBMATEMIXER_VERSION is 1.2.3).
+ */
+#define LIBMATEMIXER_MICRO_VERSION (@LIBMATEMIXER_MICRO_VERSION@)
+
+/**
+ * LIBMATEMIXER_VERSION:
+ *
+ * Libmatemixer version.
+ */
+#define LIBMATEMIXER_VERSION (@LIBMATEMIXER_VERSION@)
+
+/**
+ * LIBMATEMIXER_CHECK_VERSION:
+ * @major: major version number
+ * @minor: minor version number
+ * @micro: micro version number
+ *
+ * Compile-time version checking. Evaluates to %TRUE if the version of the
+ * library is greater than the required one.
+ */
+#define LIBMATEMIXER_CHECK_VERSION(major, minor, micro) \
+ (LIBMATEMIXER_MAJOR_VERSION > (major) || \
+ (LIBMATEMIXER_MAJOR_VERSION == (major) && LIBMATEMIXER_MINOR_VERSION > (minor)) || \
+ (LIBMATEMIXER_MAJOR_VERSION == (major) && LIBMATEMIXER_MINOR_VERSION == (minor) && \
+ LIBMATEMIXER_MICRO_VERSION >= (micro)))
+
+#endif /* LIBMATEMIXER_VERSION_H */
diff --git a/libmatemixer/matemixer.c b/libmatemixer/matemixer.c
index 3c8f643..1e5d4e0 100644
--- a/libmatemixer/matemixer.c
+++ b/libmatemixer/matemixer.c
@@ -25,12 +25,21 @@
#include "matemixer-private.h"
#include "matemixer-backend-module.h"
-static void mixer_load_modules (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;
+/**
+ * mate_mixer_init:
+ *
+ * Initializes the library. You must call this function before using any other
+ * function from the library.
+ *
+ * Returns: %TRUE on success, or %FALSE if the library installation is broken and
+ * does not provide support for any sound systems.
+ */
gboolean
mate_mixer_init (void)
{
@@ -66,6 +75,12 @@ mate_mixer_init (void)
return mixer_initialized;
}
+/**
+ * mate_mixer_deinit:
+ *
+ * Deinitializes the library. You should call this function when you do not need
+ * to use the library any longer or before exitting the application.
+ */
void
mate_mixer_deinit (void)
{
@@ -135,14 +150,14 @@ mixer_load_modules (void)
g_error_free (error);
}
} else {
- g_critical ("Unable to load backend modules: GModule not supported");
+ g_critical ("Unable to load backend modules: GModule is not supported in your system");
}
loaded = TRUE;
}
-/* GCompareFunc function to sort backend modules by the priority, lower
- * number means higher priority */
+/* GCompareFunc function to sort backend modules by the priority, higher number means
+ * higher priority */
static gint
mixer_compare_modules (gconstpointer a, gconstpointer b)
{
@@ -151,5 +166,5 @@ mixer_compare_modules (gconstpointer a, gconstpointer b)
info1 = mate_mixer_backend_module_get_info (MATE_MIXER_BACKEND_MODULE (a));
info2 = mate_mixer_backend_module_get_info (MATE_MIXER_BACKEND_MODULE (b));
- return info1->priority - info2->priority;
+ return info2->priority - info1->priority;
}
diff --git a/libmatemixer/matemixer.h b/libmatemixer/matemixer.h
index b43de79..99df233 100644
--- a/libmatemixer/matemixer.h
+++ b/libmatemixer/matemixer.h
@@ -26,8 +26,8 @@
G_BEGIN_DECLS
-gboolean mate_mixer_init (void);
-void mate_mixer_deinit (void);
+gboolean mate_mixer_init (void);
+void mate_mixer_deinit (void);
G_END_DECLS
diff --git a/m4/gtk-doc.m4 b/m4/gtk-doc.m4
new file mode 100644
index 0000000..3675543
--- /dev/null
+++ b/m4/gtk-doc.m4
@@ -0,0 +1,88 @@
+dnl -*- mode: autoconf -*-
+
+# serial 2
+
+dnl Usage:
+dnl GTK_DOC_CHECK([minimum-gtk-doc-version])
+AC_DEFUN([GTK_DOC_CHECK],
+[
+ AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+ AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first
+ AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first
+
+ ifelse([$1],[],[gtk_doc_requires="gtk-doc"],[gtk_doc_requires="gtk-doc >= $1"])
+ AC_MSG_CHECKING([for gtk-doc])
+ PKG_CHECK_EXISTS([$gtk_doc_requires],[have_gtk_doc=yes],[have_gtk_doc=no])
+ AC_MSG_RESULT($have_gtk_doc)
+
+ if test "$have_gtk_doc" = "no"; then
+ AC_MSG_WARN([
+ You will not be able to create source packages with 'make dist'
+ because $gtk_doc_requires is not found.])
+ fi
+
+ dnl check for tools we added during development
+ dnl Use AC_CHECK_PROG to avoid the check target using an absolute path that
+ dnl may not be writable by the user. Currently, automake requires that the
+ dnl test name must end in '.test'.
+ dnl https://bugzilla.gnome.org/show_bug.cgi?id=701638
+ AC_CHECK_PROG([GTKDOC_CHECK],[gtkdoc-check],[gtkdoc-check.test])
+ AC_PATH_PROG([GTKDOC_CHECK_PATH],[gtkdoc-check])
+ AC_PATH_PROGS([GTKDOC_REBASE],[gtkdoc-rebase],[true])
+ AC_PATH_PROG([GTKDOC_MKPDF],[gtkdoc-mkpdf])
+
+ dnl for overriding the documentation installation directory
+ AC_ARG_WITH([html-dir],
+ AS_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),,
+ [with_html_dir='${datadir}/gtk-doc/html'])
+ HTML_DIR="$with_html_dir"
+ AC_SUBST([HTML_DIR])
+
+ dnl enable/disable documentation building
+ AC_ARG_ENABLE([gtk-doc],
+ AS_HELP_STRING([--enable-gtk-doc],
+ [use gtk-doc to build documentation [[default=no]]]),,
+ [enable_gtk_doc=no])
+
+ AC_MSG_CHECKING([whether to build gtk-doc documentation])
+ AC_MSG_RESULT($enable_gtk_doc)
+
+ if test "x$enable_gtk_doc" = "xyes" && test "$have_gtk_doc" = "no"; then
+ AC_MSG_ERROR([
+ You must have $gtk_doc_requires installed to build documentation for
+ $PACKAGE_NAME. Please install gtk-doc or disable building the
+ documentation by adding '--disable-gtk-doc' to '[$]0'.])
+ fi
+
+ dnl don't check for glib if we build glib
+ if test "x$PACKAGE_NAME" != "xglib"; then
+ dnl don't fail if someone does not have glib
+ PKG_CHECK_MODULES(GTKDOC_DEPS, glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0,,[:])
+ fi
+
+ dnl enable/disable output formats
+ AC_ARG_ENABLE([gtk-doc-html],
+ AS_HELP_STRING([--enable-gtk-doc-html],
+ [build documentation in html format [[default=yes]]]),,
+ [enable_gtk_doc_html=yes])
+ AC_ARG_ENABLE([gtk-doc-pdf],
+ AS_HELP_STRING([--enable-gtk-doc-pdf],
+ [build documentation in pdf format [[default=no]]]),,
+ [enable_gtk_doc_pdf=no])
+
+ if test -z "$GTKDOC_MKPDF"; then
+ enable_gtk_doc_pdf=no
+ fi
+
+ if test -z "$AM_DEFAULT_VERBOSITY"; then
+ AM_DEFAULT_VERBOSITY=1
+ fi
+ AC_SUBST([AM_DEFAULT_VERBOSITY])
+
+ AM_CONDITIONAL([HAVE_GTK_DOC], [test x$have_gtk_doc = xyes])
+ AM_CONDITIONAL([ENABLE_GTK_DOC], [test x$enable_gtk_doc = xyes])
+ AM_CONDITIONAL([GTK_DOC_BUILD_HTML], [test x$enable_gtk_doc_html = xyes])
+ AM_CONDITIONAL([GTK_DOC_BUILD_PDF], [test x$enable_gtk_doc_pdf = xyes])
+ AM_CONDITIONAL([GTK_DOC_USE_LIBTOOL], [test -n "$LIBTOOL"])
+ AM_CONDITIONAL([GTK_DOC_USE_REBASE], [test -n "$GTKDOC_REBASE"])
+])
diff --git a/omf.make b/omf.make
new file mode 100644
index 0000000..35dec24
--- /dev/null
+++ b/omf.make
@@ -0,0 +1,65 @@
+#
+# No modifications of this Makefile should be necessary.
+#
+# This file contains the build instructions for installing OMF files. It is
+# generally called from the makefiles for particular formats of documentation.
+#
+# Note that you must configure your package with --localstatedir=/var
+# so that the scrollkeeper-update command below will update the database
+# in the standard scrollkeeper directory.
+#
+# If it is impossible to configure with --localstatedir=/var, then
+# modify the definition of scrollkeeper_localstate_dir so that
+# it points to the correct location. Note that you must still use
+# $(localstatedir) in this or when people build RPMs it will update
+# the real database on their system instead of the one under RPM_BUILD_ROOT.
+#
+# Note: This make file is not incorporated into xmldocs.make because, in
+# general, there will be other documents install besides XML documents
+# and the makefiles for these formats should also include this file.
+#
+# About this file:
+# This file was derived from scrollkeeper_example2, a package
+# illustrating how to install documentation and OMF files for use with
+# ScrollKeeper 0.3.x and 0.4.x. For more information, see:
+# http://scrollkeeper.sourceforge.net/
+# Version: 0.1.3 (last updated: March 20, 2002)
+#
+
+omf_dest_dir=$(datadir)/omf/@PACKAGE@
+scrollkeeper_localstate_dir = $(localstatedir)/scrollkeeper
+
+# At some point, it may be wise to change to something like this:
+# scrollkeeper_localstate_dir = @SCROLLKEEPER_STATEDIR@
+
+omf: omf_timestamp
+
+omf_timestamp: $(omffile)
+ -for file in $(omffile); do \
+ absfile=$(srcdir)/$$file; \
+ test -r $$file && absfile=$$file; \
+ scrollkeeper-preinstall $(docdir)/$(docname).xml $$absfile $$file.out; \
+ done; \
+ touch omf_timestamp
+
+install-data-hook-omf:
+ $(mkinstalldirs) $(DESTDIR)$(omf_dest_dir)
+ for file in $(omffile); do \
+ absfile=$(srcdir)/$$file.out; \
+ test -r $$file.out && absfile=$$file.out; \
+ $(INSTALL_DATA) $$absfile $(DESTDIR)$(omf_dest_dir)/$$file; \
+ done
+ -scrollkeeper-update -p $(DESTDIR)$(scrollkeeper_localstate_dir) -o $(DESTDIR)$(omf_dest_dir)
+
+uninstall-local-omf:
+ -for file in $(omffile); do \
+ basefile=`basename $$file`; \
+ rm -f $(DESTDIR)$(omf_dest_dir)/$$basefile; \
+ done
+ -rmdir $(DESTDIR)$(omf_dest_dir)
+ -scrollkeeper-update -p $(DESTDIR)$(scrollkeeper_localstate_dir)
+
+clean-local-omf:
+ -for file in $(omffile); do \
+ rm -f $$file.out; \
+ done
diff --git a/xmldocs.make b/xmldocs.make
new file mode 100644
index 0000000..0bc375c
--- /dev/null
+++ b/xmldocs.make
@@ -0,0 +1,101 @@
+#
+# No modifications of this Makefile should be necessary.
+#
+# To use this template:
+# 1) Define: figdir, docname, lang, omffile, and entities in
+# your Makefile.am file for each document directory,
+# although figdir, omffile, and entities may be empty
+# 2) Make sure the Makefile in (1) also includes
+# "include $(top_srcdir)/xmldocs.make" and
+# "dist-hook: app-dist-hook".
+# 3) Optionally define 'entities' to hold xml entities which
+# you would also like installed
+# 4) Figures must go under $(figdir)/ and be in PNG format
+# 5) You should only have one document per directory
+# 6) Note that the figure directory, $(figdir)/, should not have its
+# own Makefile since this Makefile installs those figures.
+#
+# example Makefile.am:
+# figdir = figures
+# docname = scrollkeeper-manual
+# lang = C
+# omffile=scrollkeeper-manual-C.omf
+# entities = fdl.xml
+# include $(top_srcdir)/xmldocs.make
+# dist-hook: app-dist-hook
+#
+# About this file:
+# This file was taken from scrollkeeper_example2, a package illustrating
+# how to install documentation and OMF files for use with ScrollKeeper
+# 0.3.x and 0.4.x. For more information, see:
+# http://scrollkeeper.sourceforge.net/
+# Version: 0.1.2 (last updated: March 20, 2002)
+#
+
+
+# ********** Begin of section some packagers may need to modify **********
+# This variable (docdir) specifies where the documents should be installed.
+# This default value should work for most packages.
+docdir = $(datadir)/mate/help/$(docname)/$(lang)
+
+# ********** You should not have to edit below this line **********
+xml_files = $(entities) $(docname).xml
+
+EXTRA_DIST = $(xml_files) $(omffile)
+CLEANFILES = omf_timestamp
+
+include $(top_srcdir)/omf.make
+
+all: omf
+
+$(docname).xml: $(entities)
+ -ourdir=`pwd`; \
+ cd $(srcdir); \
+ cp $(entities) $$ourdir
+
+app-dist-hook:
+ if test "$(figdir)"; then \
+ $(mkinstalldirs) $(distdir)/$(figdir); \
+ for file in $(srcdir)/$(figdir)/*.png; do \
+ basefile=`echo $$file | sed -e 's,^.*/,,'`; \
+ $(INSTALL_DATA) $$file $(distdir)/$(figdir)/$$basefile; \
+ done \
+ fi
+
+install-data-local: omf
+ $(mkinstalldirs) $(DESTDIR)$(docdir)
+ for file in $(xml_files); do \
+ cp $(srcdir)/$$file $(DESTDIR)$(docdir); \
+ done
+ if test "$(figdir)"; then \
+ $(mkinstalldirs) $(DESTDIR)$(docdir)/$(figdir); \
+ for file in $(srcdir)/$(figdir)/*.png; do \
+ basefile=`echo $$file | sed -e 's,^.*/,,'`; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(docdir)/$(figdir)/$$basefile; \
+ done \
+ fi
+
+install-data-hook: install-data-hook-omf
+
+uninstall-local: uninstall-local-doc uninstall-local-omf
+
+uninstall-local-doc:
+ -if test "$(figdir)"; then \
+ for file in $(srcdir)/$(figdir)/*.png; do \
+ basefile=`echo $$file | sed -e 's,^.*/,,'`; \
+ rm -f $(DESTDIR)$(docdir)/$(figdir)/$$basefile; \
+ done; \
+ rmdir $(DESTDIR)$(docdir)/$(figdir); \
+ fi
+ -for file in $(xml_files); do \
+ rm -f $(DESTDIR)$(docdir)/$$file; \
+ done
+ -rmdir $(DESTDIR)$(docdir)
+
+clean-local: clean-local-doc clean-local-omf
+
+# for non-srcdir builds, remove the copied entities.
+clean-local-doc:
+ if test $(srcdir) != .; then \
+ rm -f $(entities); \
+ fi