summaryrefslogtreecommitdiff
path: root/backends
diff options
context:
space:
mode:
authorMichal Ratajsky <[email protected]>2014-06-13 17:36:14 +0200
committerMichal Ratajsky <[email protected]>2014-06-13 17:36:14 +0200
commita2290d5e13ccee88fd9ae66a3895eb4da646f81f (patch)
tree4948171de11f476e5a0b7d7d44bdbad8b422d812 /backends
parent7cf09a2b40a507caf2bea0c54af00da84a8f88af (diff)
downloadlibmatemixer-a2290d5e13ccee88fd9ae66a3895eb4da646f81f.tar.bz2
libmatemixer-a2290d5e13ccee88fd9ae66a3895eb4da646f81f.tar.xz
Weekly update
Diffstat (limited to 'backends')
-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
29 files changed, 4184 insertions, 1358 deletions
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 */