summaryrefslogtreecommitdiff
path: root/backends/pulse
diff options
context:
space:
mode:
Diffstat (limited to 'backends/pulse')
-rw-r--r--backends/pulse/Makefile.am24
-rw-r--r--backends/pulse/pulse-backend.c1078
-rw-r--r--backends/pulse/pulse-backend.h9
-rw-r--r--backends/pulse/pulse-client-stream.c433
-rw-r--r--backends/pulse/pulse-client-stream.h94
-rw-r--r--backends/pulse/pulse-connection.c39
-rw-r--r--backends/pulse/pulse-connection.h5
-rw-r--r--backends/pulse/pulse-device-profile.c88
-rw-r--r--backends/pulse/pulse-device-profile.h69
-rw-r--r--backends/pulse/pulse-device-switch.c261
-rw-r--r--backends/pulse/pulse-device-switch.h77
-rw-r--r--backends/pulse/pulse-device.c575
-rw-r--r--backends/pulse/pulse-device.h33
-rw-r--r--backends/pulse/pulse-ext-stream.c374
-rw-r--r--backends/pulse/pulse-ext-stream.h30
-rw-r--r--backends/pulse/pulse-helpers.c27
-rw-r--r--backends/pulse/pulse-helpers.h9
-rw-r--r--backends/pulse/pulse-monitor.c52
-rw-r--r--backends/pulse/pulse-monitor.h10
-rw-r--r--backends/pulse/pulse-port-switch.c241
-rw-r--r--backends/pulse/pulse-port-switch.h77
-rw-r--r--backends/pulse/pulse-port.c89
-rw-r--r--backends/pulse/pulse-port.h70
-rw-r--r--backends/pulse/pulse-sink-control.c161
-rw-r--r--backends/pulse/pulse-sink-control.h67
-rw-r--r--backends/pulse/pulse-sink-input.c321
-rw-r--r--backends/pulse/pulse-sink-input.h22
-rw-r--r--backends/pulse/pulse-sink-switch.c76
-rw-r--r--backends/pulse/pulse-sink-switch.h62
-rw-r--r--backends/pulse/pulse-sink.c382
-rw-r--r--backends/pulse/pulse-sink.h24
-rw-r--r--backends/pulse/pulse-source-control.c154
-rw-r--r--backends/pulse/pulse-source-control.h67
-rw-r--r--backends/pulse/pulse-source-output.c306
-rw-r--r--backends/pulse/pulse-source-output.h37
-rw-r--r--backends/pulse/pulse-source-switch.c76
-rw-r--r--backends/pulse/pulse-source-switch.h62
-rw-r--r--backends/pulse/pulse-source.c339
-rw-r--r--backends/pulse/pulse-source.h27
-rw-r--r--backends/pulse/pulse-stream-control.c744
-rw-r--r--backends/pulse/pulse-stream-control.h94
-rw-r--r--backends/pulse/pulse-stream.c1225
-rw-r--r--backends/pulse/pulse-stream.h64
-rw-r--r--backends/pulse/pulse-types.h45
44 files changed, 4260 insertions, 3859 deletions
diff --git a/backends/pulse/Makefile.am b/backends/pulse/Makefile.am
index 0e5a4d6..4c851bf 100644
--- a/backends/pulse/Makefile.am
+++ b/backends/pulse/Makefile.am
@@ -3,6 +3,7 @@ backenddir = $(libdir)/libmatemixer
backend_LTLIBRARIES = libmatemixer-pulse.la
AM_CPPFLAGS = \
+ -Wno-unknown-pragmas \
-I$(top_srcdir) \
-DG_LOG_DOMAIN=\"libmatemixer-pulse\"
@@ -13,12 +14,14 @@ libmatemixer_pulse_la_CFLAGS = \
libmatemixer_pulse_la_SOURCES = \
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-device-profile.c \
+ pulse-device-profile.h \
+ pulse-device-switch.c \
+ pulse-device-switch.h \
pulse-enums.h \
pulse-enum-types.c \
pulse-enum-types.h \
@@ -28,16 +31,31 @@ libmatemixer_pulse_la_SOURCES = \
pulse-helpers.h \
pulse-monitor.c \
pulse-monitor.h \
+ pulse-port.c \
+ pulse-port.h \
+ pulse-port-switch.c \
+ pulse-port-switch.h \
pulse-stream.c \
pulse-stream.h \
+ pulse-stream-control.c \
+ pulse-stream-control.h \
pulse-sink.c \
pulse-sink.h \
+ pulse-sink-control.c \
+ pulse-sink-control.h \
pulse-sink-input.c \
pulse-sink-input.h \
+ pulse-sink-switch.c \
+ pulse-sink-switch.h \
pulse-source.c \
pulse-source.h \
+ pulse-source-control.c \
+ pulse-source-control.h \
pulse-source-output.c \
- pulse-source-output.h
+ pulse-source-output.h \
+ pulse-source-switch.c \
+ pulse-source-switch.h \
+ pulse-types.h
libmatemixer_pulse_la_LIBADD = \
$(GLIB_LIBS) \
diff --git a/backends/pulse/pulse-backend.c b/backends/pulse/pulse-backend.c
index 0494545..e1b7ed5 100644
--- a/backends/pulse/pulse-backend.c
+++ b/backends/pulse/pulse-backend.c
@@ -19,9 +19,8 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-backend.h>
-#include <libmatemixer/matemixer-backend-module.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include <pulse/ext-stream-restore.h>
@@ -38,72 +37,110 @@
#include "pulse-source-output.h"
#define BACKEND_NAME "PulseAudio"
-#define BACKEND_PRIORITY 10
+#define BACKEND_PRIORITY 100
struct _PulseBackendPrivate
{
- gchar *app_name;
- gchar *app_id;
- gchar *app_version;
- gchar *app_icon;
- gchar *server_address;
- gboolean connected_once;
- GSource *connect_source;
- MateMixerStream *default_sink;
- MateMixerStream *default_source;
- GHashTable *devices;
- GHashTable *streams;
- GHashTable *ext_streams;
- MateMixerState state;
- PulseConnection *connection;
-};
-
-enum {
- PROP_0,
- PROP_STATE,
- PROP_DEFAULT_INPUT,
- PROP_DEFAULT_OUTPUT,
- N_PROPERTIES
+ guint connect_tag;
+ gboolean connected_once;
+ GHashTable *devices;
+ GHashTable *sinks;
+ GHashTable *sources;
+ GHashTable *sink_inputs;
+ GHashTable *source_outputs;
+ GHashTable *ext_streams;
+ GList *devices_list;
+ GList *streams_list;
+ GList *ext_streams_list;
+ MateMixerAppInfo *app_info;
+ gchar *server_address;
+ PulseConnection *connection;
};
-static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface);
+#define PULSE_CHANGE_STATE(p, s) \
+ (_mate_mixer_backend_set_state (MATE_MIXER_BACKEND (p), (s)))
+#define PULSE_GET_DEFAULT_SINK(p) \
+ (mate_mixer_backend_get_default_output_stream (MATE_MIXER_BACKEND (p)))
+#define PULSE_GET_DEFAULT_SOURCE(p) \
+ (mate_mixer_backend_get_default_input_stream (MATE_MIXER_BACKEND (p)))
+#define PULSE_SET_DEFAULT_SINK(p, s) \
+ (_mate_mixer_backend_set_default_output_stream (MATE_MIXER_BACKEND (p), MATE_MIXER_STREAM (s)))
+#define PULSE_SET_DEFAULT_SOURCE(p, s) \
+ (_mate_mixer_backend_set_default_input_stream (MATE_MIXER_BACKEND (p), MATE_MIXER_STREAM (s)))
+
+#define PULSE_GET_PENDING_SINK(p) \
+ (g_object_get_data (G_OBJECT (p), \
+ "__matemixer_pulse_pending_sink")) \
+
+#define PULSE_SET_PENDING_SINK(p,name) \
+ (g_object_set_data_full (G_OBJECT (p), \
+ "__matemixer_pulse_pending_sink", \
+ g_strdup (name), \
+ g_free))
+
+#define PULSE_SET_PENDING_SINK_NULL(p) \
+ (g_object_set_data (G_OBJECT (p), \
+ "__matemixer_pulse_pending_sink", \
+ NULL))
+
+#define PULSE_GET_PENDING_SOURCE(p) \
+ (g_object_get_data (G_OBJECT (p), \
+ "__matemixer_pulse_pending_source")) \
+
+#define PULSE_SET_PENDING_SOURCE(p,name) \
+ (g_object_set_data_full (G_OBJECT (p), \
+ "__matemixer_pulse_pending_source", \
+ g_strdup (name), \
+ g_free))
+
+#define PULSE_SET_PENDING_SOURCE_NULL(p) \
+ (g_object_set_data (G_OBJECT (p), \
+ "__matemixer_pulse_pending_source", \
+ NULL))
+
+#define PULSE_GET_HANGING(o) \
+ ((gboolean) g_object_get_data (G_OBJECT (o), \
+ "__matemixer_pulse_hanging"))
+
+#define PULSE_SET_HANGING(o) \
+ (g_object_set_data (G_OBJECT (o), \
+ "__matemixer_pulse_hanging", \
+ GUINT_TO_POINTER (1)))
+
+#define PULSE_UNSET_HANGING(o) \
+ (g_object_steal_data (G_OBJECT (o), \
+ "__matemixer_pulse_hanging"))
static void pulse_backend_class_init (PulseBackendClass *klass);
static void pulse_backend_class_finalize (PulseBackendClass *klass);
-static void pulse_backend_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec);
-
static void pulse_backend_init (PulseBackend *pulse);
static void pulse_backend_dispose (GObject *object);
static void pulse_backend_finalize (GObject *object);
-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))
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+G_DEFINE_DYNAMIC_TYPE (PulseBackend, pulse_backend, MATE_MIXER_TYPE_BACKEND)
+#pragma clang diagnostic pop
-static gboolean pulse_backend_open (MateMixerBackend *backend);
-static void pulse_backend_close (MateMixerBackend *backend);
+static gboolean pulse_backend_open (MateMixerBackend *backend);
+static void pulse_backend_close (MateMixerBackend *backend);
-static MateMixerState pulse_backend_get_state (MateMixerBackend *backend);
+static void pulse_backend_set_app_info (MateMixerBackend *backend,
+ MateMixerAppInfo *info);
-static void pulse_backend_set_data (MateMixerBackend *backend,
- const MateMixerBackendData *data);
+static void pulse_backend_set_server_address (MateMixerBackend *backend,
+ const gchar *address);
-static GList * pulse_backend_list_devices (MateMixerBackend *backend);
-static GList * pulse_backend_list_streams (MateMixerBackend *backend);
-static GList * pulse_backend_list_cached_streams (MateMixerBackend *backend);
+static const GList * pulse_backend_list_devices (MateMixerBackend *backend);
+static const GList * pulse_backend_list_streams (MateMixerBackend *backend);
+static const GList * pulse_backend_list_stored_controls (MateMixerBackend *backend);
-static MateMixerStream *pulse_backend_get_default_input_stream (MateMixerBackend *backend);
-static gboolean pulse_backend_set_default_input_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
+static gboolean pulse_backend_set_default_input_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
-static MateMixerStream *pulse_backend_get_default_output_stream (MateMixerBackend *backend);
-static gboolean pulse_backend_set_default_output_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
+static gboolean pulse_backend_set_default_output_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
static void on_connection_state_notify (PulseConnection *connection,
GParamSpec *pspec,
@@ -152,32 +189,16 @@ static void on_connection_ext_stream_info (PulseConnection
PulseBackend *pulse);
static gboolean connect_source_reconnect (PulseBackend *pulse);
-static void connect_source_remove (PulseBackend *pulse);
static void check_pending_sink (PulseBackend *pulse,
PulseStream *stream);
static void check_pending_source (PulseBackend *pulse,
PulseStream *stream);
-static void mark_hanging (PulseBackend *pulse);
-static void mark_hanging_hash (GHashTable *hash);
-
-static void unmark_hanging (PulseBackend *pulse,
- GObject *object);
-
-static void remove_hanging (PulseBackend *pulse);
-static void remove_device (PulseBackend *pulse,
- PulseDevice *device);
-static void remove_stream (PulseBackend *pulse,
- PulseStream *stream);
-
-static void change_state (PulseBackend *backend,
- MateMixerState state);
+static void free_list_devices (PulseBackend *pulse);
+static void free_list_streams (PulseBackend *pulse);
+static void free_list_ext_streams (PulseBackend *pulse);
-static gint compare_devices (gconstpointer a,
- gconstpointer b);
-static gint compare_streams (gconstpointer a,
- gconstpointer b);
static gboolean compare_stream_names (gpointer key,
gpointer value,
gpointer user_data);
@@ -195,78 +216,42 @@ backend_module_init (GTypeModule *module)
info.backend_type = MATE_MIXER_BACKEND_PULSEAUDIO;
}
-const MateMixerBackendInfo *
-backend_module_get_info (void)
+const MateMixerBackendInfo *backend_module_get_info (void)
{
return &info;
}
static void
-mate_mixer_backend_interface_init (MateMixerBackendInterface *iface)
-{
- iface->open = pulse_backend_open;
- iface->close = pulse_backend_close;
- iface->get_state = pulse_backend_get_state;
- iface->set_data = pulse_backend_set_data;
- iface->list_devices = pulse_backend_list_devices;
- iface->list_streams = pulse_backend_list_streams;
- iface->list_cached_streams = pulse_backend_list_cached_streams;
- iface->get_default_input_stream = pulse_backend_get_default_input_stream;
- iface->set_default_input_stream = pulse_backend_set_default_input_stream;
- iface->get_default_output_stream = pulse_backend_get_default_output_stream;
- iface->set_default_output_stream = pulse_backend_set_default_output_stream;
-}
-
-static void
pulse_backend_class_init (PulseBackendClass *klass)
{
- GObjectClass *object_class;
+ GObjectClass *object_class;
+ MateMixerBackendClass *backend_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_object_class_override_property (object_class, PROP_DEFAULT_INPUT, "default-input");
- g_object_class_override_property (object_class, PROP_DEFAULT_OUTPUT, "default-output");
+ object_class->dispose = pulse_backend_dispose;
+ object_class->finalize = pulse_backend_finalize;
+
+ backend_class = MATE_MIXER_BACKEND_CLASS (klass);
+ backend_class->set_app_info = pulse_backend_set_app_info;
+ backend_class->set_server_address = pulse_backend_set_server_address;
+ backend_class->open = pulse_backend_open;
+ backend_class->close = pulse_backend_close;
+ backend_class->list_devices = pulse_backend_list_devices;
+ backend_class->list_streams = pulse_backend_list_streams;
+ backend_class->list_stored_controls = pulse_backend_list_stored_controls;
+ backend_class->set_default_input_stream = pulse_backend_set_default_input_stream;
+ backend_class->set_default_output_stream = pulse_backend_set_default_output_stream;
g_type_class_add_private (object_class, sizeof (PulseBackendPrivate));
}
-/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE_EXTENDED() */
+/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE() */
static void
pulse_backend_class_finalize (PulseBackendClass *klass)
{
}
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;
- case PROP_DEFAULT_INPUT:
- g_value_set_object (value, pulse->priv->default_source);
- break;
- case PROP_DEFAULT_OUTPUT:
- g_value_set_object (value, pulse->priv->default_sink);
- 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,
@@ -279,22 +264,46 @@ pulse_backend_init (PulseBackend *pulse)
g_direct_equal,
NULL,
g_object_unref);
- pulse->priv->streams =
- g_hash_table_new_full (g_int64_hash,
- g_int64_equal,
- g_free,
+ pulse->priv->sinks =
+ 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->ext_streams =
g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
g_object_unref);
+
+ pulse->priv->sink_inputs =
+ 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)
{
- pulse_backend_close (MATE_MIXER_BACKEND (object));
+ MateMixerBackend *backend;
+ MateMixerState state;
+
+ backend = MATE_MIXER_BACKEND (object);
+
+ state = mate_mixer_backend_get_state (backend);
+ if (state != MATE_MIXER_STATE_IDLE)
+ pulse_backend_close (backend);
G_OBJECT_CLASS (pulse_backend_parent_class)->dispose (object);
}
@@ -306,19 +315,24 @@ pulse_backend_finalize (GObject *object)
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);
+ if (pulse->priv->app_info != NULL)
+ _mate_mixer_app_info_free (pulse->priv->app_info);
- g_hash_table_destroy (pulse->priv->devices);
- g_hash_table_destroy (pulse->priv->streams);
- g_hash_table_destroy (pulse->priv->ext_streams);
+ g_hash_table_unref (pulse->priv->devices);
+ g_hash_table_unref (pulse->priv->sinks);
+ g_hash_table_unref (pulse->priv->sources);
+ g_hash_table_unref (pulse->priv->ext_streams);
+ g_hash_table_unref (pulse->priv->sink_inputs);
+ g_hash_table_unref (pulse->priv->source_outputs);
G_OBJECT_CLASS (pulse_backend_parent_class)->finalize (object);
}
+#define PULSE_APP_NAME(p) (mate_mixer_app_info_get_name (p->priv->app_info))
+#define PULSE_APP_ID(p) (mate_mixer_app_info_get_id (p->priv->app_info))
+#define PULSE_APP_VERSION(p) (mate_mixer_app_info_get_version (p->priv->app_info))
+#define PULSE_APP_ICON(p) (mate_mixer_app_info_get_icon (p->priv->app_info))
+
static gboolean
pulse_backend_open (MateMixerBackend *backend)
{
@@ -329,22 +343,22 @@ pulse_backend_open (MateMixerBackend *backend)
pulse = PULSE_BACKEND (backend);
- if (G_UNLIKELY (pulse->priv->connection != NULL)) {
+ if G_UNLIKELY (pulse->priv->connection != NULL) {
g_warn_if_reached ();
return TRUE;
}
- connection = pulse_connection_new (pulse->priv->app_name,
- pulse->priv->app_id,
- pulse->priv->app_version,
- pulse->priv->app_icon,
+ connection = pulse_connection_new (PULSE_APP_NAME (pulse),
+ PULSE_APP_ID (pulse),
+ PULSE_APP_VERSION (pulse),
+ PULSE_APP_ICON (pulse),
pulse->priv->server_address);
/* No connection attempt is made during the construction of the connection,
* but it sets up the PulseAudio structures, which might fail in an
* unlikely case */
- if (G_UNLIKELY (connection == NULL)) {
- change_state (pulse, MATE_MIXER_STATE_FAILED);
+ if G_UNLIKELY (connection == NULL) {
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_FAILED);
return FALSE;
}
@@ -409,16 +423,21 @@ pulse_backend_open (MateMixerBackend *backend)
G_CALLBACK (on_connection_ext_stream_info),
pulse);
- change_state (pulse, MATE_MIXER_STATE_CONNECTING);
+ PULSE_CHANGE_STATE (backend, MATE_MIXER_STATE_CONNECTING);
/* Connect to the PulseAudio server, this might fail either instantly or
* asynchronously, for example when remote connection timeouts */
if (pulse_connection_connect (connection, FALSE) == FALSE) {
g_object_unref (connection);
- change_state (pulse, MATE_MIXER_STATE_FAILED);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_FAILED);
return FALSE;
}
+ _mate_mixer_backend_set_flags (backend,
+ MATE_MIXER_BACKEND_HAS_APPLICATION_CONTROLS |
+ MATE_MIXER_BACKEND_CAN_SET_DEFAULT_INPUT_STREAM |
+ MATE_MIXER_BACKEND_CAN_SET_DEFAULT_OUTPUT_STREAM);
+
pulse->priv->connection = connection;
return TRUE;
}
@@ -432,7 +451,10 @@ pulse_backend_close (MateMixerBackend *backend)
pulse = PULSE_BACKEND (backend);
- connect_source_remove (pulse);
+ if (pulse->priv->connect_tag != 0) {
+ g_source_remove (pulse->priv->connect_tag);
+ pulse->priv->connect_tag = 0;
+ }
if (pulse->priv->connection != NULL) {
g_signal_handlers_disconnect_by_data (G_OBJECT (pulse->priv->connection),
@@ -441,109 +463,100 @@ pulse_backend_close (MateMixerBackend *backend)
g_clear_object (&pulse->priv->connection);
}
- g_clear_object (&pulse->priv->default_sink);
- g_clear_object (&pulse->priv->default_source);
-
g_hash_table_remove_all (pulse->priv->devices);
- g_hash_table_remove_all (pulse->priv->streams);
+ g_hash_table_remove_all (pulse->priv->sinks);
+ g_hash_table_remove_all (pulse->priv->sources);
g_hash_table_remove_all (pulse->priv->ext_streams);
pulse->priv->connected_once = FALSE;
- change_state (pulse, MATE_MIXER_STATE_IDLE);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_IDLE);
}
-static MateMixerState
-pulse_backend_get_state (MateMixerBackend *backend)
+static void
+pulse_backend_set_app_info (MateMixerBackend *backend, MateMixerAppInfo *info)
{
- g_return_val_if_fail (PULSE_IS_BACKEND (backend), MATE_MIXER_STATE_UNKNOWN);
+ PulseBackend *pulse;
+
+ g_return_if_fail (PULSE_IS_BACKEND (backend));
+ g_return_if_fail (info != NULL);
+
+ pulse = PULSE_BACKEND (backend);
- return PULSE_BACKEND (backend)->priv->state;
+ if (pulse->priv->app_info != NULL)
+ _mate_mixer_app_info_free (pulse->priv->app_info);
+
+ pulse->priv->app_info = _mate_mixer_app_info_copy (info);
}
static void
-pulse_backend_set_data (MateMixerBackend *backend, const MateMixerBackendData *data)
+pulse_backend_set_server_address (MateMixerBackend *backend, const gchar *address)
{
- PulseBackend *pulse;
-
g_return_if_fail (PULSE_IS_BACKEND (backend));
- g_return_if_fail (data != NULL);
- pulse = PULSE_BACKEND (backend);
+ g_free (PULSE_BACKEND (backend)->priv->server_address);
- 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);
-
- 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);
+ PULSE_BACKEND (backend)->priv->server_address = g_strdup (address);
}
-static GList *
+static const GList *
pulse_backend_list_devices (MateMixerBackend *backend)
{
- GList *list;
+ PulseBackend *pulse;
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
- /* Convert the hash table to a sorted linked list, this list is expected
- * to be cached in the main library */
- list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->devices);
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
+ pulse = PULSE_BACKEND (backend);
- return g_list_sort (list, compare_devices);
+ if (pulse->priv->devices_list == NULL) {
+ pulse->priv->devices_list = g_hash_table_get_values (pulse->priv->devices);
+ if (pulse->priv->devices_list != NULL)
+ g_list_foreach (pulse->priv->devices_list, (GFunc) g_object_ref, NULL);
}
- return NULL;
+ return pulse->priv->devices_list;
}
-static GList *
+static const GList *
pulse_backend_list_streams (MateMixerBackend *backend)
{
- GList *list;
+ PulseBackend *pulse;
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
- /* Convert the hash table to a sorted linked list, this list is expected
- * to be cached in the main library */
- list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->streams);
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- return g_list_sort (list, compare_streams);
- }
- return NULL;
-}
+ pulse = PULSE_BACKEND (backend);
-static GList *
-pulse_backend_list_cached_streams (MateMixerBackend *backend)
-{
- GList *list;
+ if (pulse->priv->streams_list == NULL) {
+ GList *sinks;
+ GList *sources;
- g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
+ sinks = g_hash_table_get_values (pulse->priv->sinks);
+ if (sinks != NULL)
+ g_list_foreach (sinks, (GFunc) g_object_ref, NULL);
- /* Convert the hash table to a sorted linked list, this list is expected
- * to be cached in the main library */
- list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->ext_streams);
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
+ sources = g_hash_table_get_values (pulse->priv->sources);
+ if (sources != NULL)
+ g_list_foreach (sources, (GFunc) g_object_ref, NULL);
- return g_list_sort (list, compare_streams);
+ pulse->priv->streams_list = g_list_concat (sinks, sources);
}
- return NULL;
+ return pulse->priv->streams_list;
}
-static MateMixerStream *
-pulse_backend_get_default_input_stream (MateMixerBackend *backend)
+static const GList *
+pulse_backend_list_stored_controls (MateMixerBackend *backend)
{
+ PulseBackend *pulse;
+
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
- return PULSE_BACKEND (backend)->priv->default_source;
+ pulse = PULSE_BACKEND (backend);
+
+ if (pulse->priv->ext_streams_list == NULL) {
+ pulse->priv->ext_streams_list = g_hash_table_get_values (pulse->priv->ext_streams);
+ if (pulse->priv->ext_streams_list != NULL)
+ g_list_foreach (pulse->priv->ext_streams_list, (GFunc) g_object_ref, NULL);
+ }
+ return pulse->priv->ext_streams_list;
}
static gboolean
@@ -562,29 +575,13 @@ pulse_backend_set_default_input_stream (MateMixerBackend *backend,
if (pulse_connection_set_default_source (pulse->priv->connection, name) == FALSE)
return FALSE;
- if (pulse->priv->default_source != NULL)
- g_object_unref (pulse->priv->default_source);
-
- pulse->priv->default_source = g_object_ref (stream);
-
/* We might be in the process of setting a default source for which the details
* are not yet known, make sure the change does not happen */
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-source",
- NULL);
-
- g_object_notify (G_OBJECT (pulse), "default-input");
+ PULSE_SET_PENDING_SOURCE_NULL (pulse);
+ PULSE_SET_DEFAULT_SOURCE (pulse, stream);
return TRUE;
}
-static MateMixerStream *
-pulse_backend_get_default_output_stream (MateMixerBackend *backend)
-{
- g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
-
- return PULSE_BACKEND (backend)->priv->default_sink;
-}
-
static gboolean
pulse_backend_set_default_output_stream (MateMixerBackend *backend,
MateMixerStream *stream)
@@ -601,18 +598,10 @@ pulse_backend_set_default_output_stream (MateMixerBackend *backend,
if (pulse_connection_set_default_sink (pulse->priv->connection, name) == FALSE)
return FALSE;
- if (pulse->priv->default_sink != NULL)
- g_object_unref (pulse->priv->default_sink);
-
- pulse->priv->default_sink = g_object_ref (stream);
-
/* We might be in the process of setting a default sink for which the details
* are not yet known, make sure the change does not happen */
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-sink",
- NULL);
-
- g_object_notify (G_OBJECT (pulse), "default-output");
+ PULSE_SET_PENDING_SINK_NULL (pulse);
+ PULSE_SET_DEFAULT_SINK (pulse, stream);
return TRUE;
}
@@ -633,41 +622,41 @@ on_connection_state_notify (PulseConnection *connection,
* Stream callbacks will unmark available streams and remaining
* unavailable streams will be removed when the CONNECTED state
* is reached. */
- mark_hanging (pulse);
- change_state (pulse, MATE_MIXER_STATE_CONNECTING);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_CONNECTING);
- if (pulse->priv->connect_source == NULL &&
- pulse_connection_connect (connection, TRUE) == FALSE) {
- pulse->priv->connect_source = g_timeout_source_new (200);
+ if G_UNLIKELY (pulse->priv->connect_tag != 0)
+ break;
- g_source_set_callback (pulse->priv->connect_source,
+ if (pulse_connection_connect (connection, TRUE) == FALSE) {
+ GSource *source;
+
+ source = g_timeout_source_new (200);
+ g_source_set_callback (source,
(GSourceFunc) connect_source_reconnect,
pulse,
- (GDestroyNotify) connect_source_remove);
+ NULL);
+ pulse->priv->connect_tag =
+ g_source_attach (source, g_main_context_get_thread_default ());
- g_source_attach (pulse->priv->connect_source,
- g_main_context_get_thread_default ());
+ g_source_unref (source);
}
break;
}
/* First connection attempt has failed */
- change_state (pulse, MATE_MIXER_STATE_FAILED);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_FAILED);
break;
case PULSE_CONNECTION_CONNECTING:
case PULSE_CONNECTION_AUTHORIZING:
case PULSE_CONNECTION_LOADING:
- change_state (pulse, MATE_MIXER_STATE_CONNECTING);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_CONNECTING);
break;
case PULSE_CONNECTION_CONNECTED:
- if (pulse->priv->connected_once == TRUE)
- remove_hanging (pulse);
- else
- pulse->priv->connected_once = TRUE;
+ pulse->priv->connected_once = TRUE;
- change_state (pulse, MATE_MIXER_STATE_READY);
+ PULSE_CHANGE_STATE (pulse, MATE_MIXER_STATE_READY);
break;
}
}
@@ -677,18 +666,17 @@ on_connection_server_info (PulseConnection *connection,
const pa_server_info *info,
PulseBackend *pulse)
{
- const gchar *name_source = NULL;
- const gchar *name_sink = NULL;
+ MateMixerStream *stream;
+ const gchar *name_source = NULL;
+ const gchar *name_sink = NULL;
- if (pulse->priv->default_source != NULL)
- name_source = mate_mixer_stream_get_name (pulse->priv->default_source);
+ stream = PULSE_GET_DEFAULT_SOURCE (pulse);
+ if (stream != NULL)
+ name_source = mate_mixer_stream_get_name (stream);
if (g_strcmp0 (name_source, info->default_source_name) != 0) {
- if (pulse->priv->default_source != NULL)
- g_clear_object (&pulse->priv->default_source);
-
if (info->default_source_name != NULL) {
- MateMixerStream *stream = g_hash_table_find (pulse->priv->streams,
+ MateMixerStream *stream = g_hash_table_find (pulse->priv->sources,
compare_stream_names,
(gpointer) info->default_source_name);
@@ -698,20 +686,14 @@ on_connection_server_info (PulseConnection *connection,
* When this happens, remember the name of the stream and wait for the
* stream info callback. */
if (stream != NULL) {
- pulse->priv->default_source = g_object_ref (stream);
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-source",
- NULL);
-
- g_debug ("Default input stream changed to %s", info->default_source_name);
+ PULSE_SET_DEFAULT_SOURCE (pulse, stream);
+ PULSE_SET_PENDING_SOURCE_NULL (pulse);
} else {
g_debug ("Default input stream changed to unknown stream %s",
info->default_source_name);
- g_object_set_data_full (G_OBJECT (pulse),
- "backend-pending-source",
- g_strdup (info->default_source_name),
- g_free);
+ PULSE_SET_PENDING_SOURCE (pulse, info->default_source_name);
+ PULSE_SET_DEFAULT_SOURCE (pulse, NULL);
/* In most cases (for example changing profile) the stream info
* arrives by itself, but do not rely on it and request it explicitely.
@@ -721,20 +703,16 @@ on_connection_server_info (PulseConnection *connection,
info->default_source_name);
}
} else
- g_debug ("Default input stream unset");
-
- g_object_notify (G_OBJECT (pulse), "default-input");
+ PULSE_SET_DEFAULT_SOURCE (pulse, NULL);
}
- if (pulse->priv->default_sink != NULL)
- name_sink = mate_mixer_stream_get_name (pulse->priv->default_sink);
+ stream = PULSE_GET_DEFAULT_SINK (pulse);
+ if (stream != NULL)
+ name_sink = mate_mixer_stream_get_name (stream);
if (g_strcmp0 (name_sink, info->default_sink_name) != 0) {
- if (pulse->priv->default_sink != NULL)
- g_clear_object (&pulse->priv->default_sink);
-
if (info->default_sink_name != NULL) {
- MateMixerStream *stream = g_hash_table_find (pulse->priv->streams,
+ MateMixerStream *stream = g_hash_table_find (pulse->priv->sinks,
compare_stream_names,
(gpointer) info->default_sink_name);
@@ -744,21 +722,14 @@ on_connection_server_info (PulseConnection *connection,
* When this happens, remember the name of the stream and wait for the
* stream info callback. */
if (stream != NULL) {
- pulse->priv->default_sink = g_object_ref (stream);
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-sink",
- NULL);
-
- g_debug ("Default output stream changed to %s", info->default_sink_name);
-
+ PULSE_SET_DEFAULT_SINK (pulse, stream);
+ PULSE_SET_PENDING_SINK_NULL (pulse);
} else {
g_debug ("Default output stream changed to unknown stream %s",
info->default_sink_name);
- g_object_set_data_full (G_OBJECT (pulse),
- "backend-pending-sink",
- g_strdup (info->default_sink_name),
- g_free);
+ PULSE_SET_PENDING_SINK (pulse, info->default_sink_name);
+ PULSE_SET_DEFAULT_SINK (pulse, NULL);
/* In most cases (for example changing profile) the stream info
* arrives by itself, but do not rely on it and request it explicitely.
@@ -768,12 +739,10 @@ on_connection_server_info (PulseConnection *connection,
info->default_sink_name);
}
} else
- g_debug ("Default output stream unset");
-
- g_object_notify (G_OBJECT (pulse), "default-output");
+ PULSE_SET_DEFAULT_SINK (pulse, NULL);
}
- if (pulse->priv->state != MATE_MIXER_STATE_READY)
+ if (mate_mixer_backend_get_state (MATE_MIXER_BACKEND (pulse)) != MATE_MIXER_STATE_READY)
g_debug ("Sound server is %s version %s, running on %s",
info->server_name,
info->server_version,
@@ -790,21 +759,17 @@ on_connection_card_info (PulseConnection *connection,
device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (info->index));
if (device == NULL) {
device = pulse_device_new (connection, info);
- if (G_UNLIKELY (device == NULL))
- return;
- g_hash_table_insert (pulse->priv->devices, GUINT_TO_POINTER (info->index), device);
+ g_hash_table_insert (pulse->priv->devices,
+ GUINT_TO_POINTER (info->index),
+ device);
+ free_list_devices (pulse);
g_signal_emit_by_name (G_OBJECT (pulse),
"device-added",
mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
- } else {
+ } else
pulse_device_update (device, info);
-
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (device));
- }
}
static void
@@ -813,29 +778,22 @@ on_connection_card_removed (PulseConnection *connection,
PulseBackend *pulse)
{
PulseDevice *device;
+ gchar *name;
device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (index));
- if (G_UNLIKELY (device == NULL))
+ if G_UNLIKELY (device == NULL)
return;
- remove_device (pulse, device);
-}
+ name = g_strdup (mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
-/* PulseAudio uses 32-bit integers as indices for sinks, sink inputs, sources and
- * source inputs, these indices are not unique among the different kinds of streams,
- * but we want to keep all of them in a single hash table. Allow this by using 64-bit
- * hash table keys, use the lower 32 bits for the PulseAudio index and some of the
- * higher bits to indicate what kind of stream it is. */
-enum {
- HASH_BIT_SINK = (1ULL << 63),
- HASH_BIT_SINK_INPUT = (1ULL << 62),
- HASH_BIT_SOURCE = (1ULL << 61),
- HASH_BIT_SOURCE_OUTPUT = (1ULL << 60)
-};
-#define HASH_ID_SINK(idx) (((idx) & 0xffffffff) | HASH_BIT_SINK)
-#define HASH_ID_SINK_INPUT(idx) (((idx) & 0xffffffff) | HASH_BIT_SINK_INPUT)
-#define HASH_ID_SOURCE(idx) (((idx) & 0xffffffff) | HASH_BIT_SOURCE)
-#define HASH_ID_SOURCE_OUTPUT(idx) (((idx) & 0xffffffff) | HASH_BIT_SOURCE_OUTPUT)
+ g_hash_table_remove (pulse->priv->devices, GUINT_TO_POINTER (index));
+
+ free_list_devices (pulse);
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "device-removed",
+ name);
+ g_free (name);
+}
static void
on_connection_sink_info (PulseConnection *connection,
@@ -844,32 +802,36 @@ on_connection_sink_info (PulseConnection *connection,
{
PulseDevice *device = NULL;
PulseStream *stream;
- gint64 index = HASH_ID_SINK (info->index);
if (info->card != PA_INVALID_INDEX)
- device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (info->card));
+ device = g_hash_table_lookup (pulse->priv->devices,
+ GUINT_TO_POINTER (info->card));
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ stream = g_hash_table_lookup (pulse->priv->sinks, GUINT_TO_POINTER (info->index));
if (stream == NULL) {
- stream = pulse_sink_new (connection, info, device);
- if (G_UNLIKELY (stream == NULL))
- return;
+ stream = PULSE_STREAM (pulse_sink_new (connection, info, device));
- g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+ free_list_streams (pulse);
+ g_hash_table_insert (pulse->priv->sinks,
+ GUINT_TO_POINTER (info->index),
+ stream);
- g_signal_emit_by_name (G_OBJECT (pulse),
- "stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ if (device != NULL) {
+ pulse_device_add_stream (device, stream);
+ } else {
+ const gchar *name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
+ /* Only emit when not a part of the device, otherwise emitted by
+ * the main library */
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ name);
+ }
/* We might be waiting for this sink to set it as the default */
check_pending_sink (pulse, stream);
- } else {
- pulse_sink_update (stream, info, device);
-
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (stream));
- }
+ } else
+ pulse_sink_update (PULSE_SINK (stream), info);
}
static void
@@ -878,13 +840,38 @@ on_connection_sink_removed (PulseConnection *connection,
PulseBackend *pulse)
{
PulseStream *stream;
- gint64 index = HASH_ID_SINK (idx);
+ PulseDevice *device;
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (stream == NULL))
+ stream = g_hash_table_lookup (pulse->priv->sinks, GUINT_TO_POINTER (idx));
+ if G_UNLIKELY (stream == NULL)
return;
- remove_stream (pulse, stream);
+ g_object_ref (stream);
+
+ free_list_streams (pulse);
+ g_hash_table_remove (pulse->priv->sinks, GUINT_TO_POINTER (idx));
+
+ device = pulse_stream_get_device (stream);
+ if (device != NULL) {
+ pulse_device_remove_stream (device, stream);
+ } else {
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-removed",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ }
+
+ /* The removed stream might be one of the default streams, this happens
+ * especially when switching profiles, after which PulseAudio removes the
+ * old streams and creates new ones with different names */
+ if (MATE_MIXER_STREAM (stream) == PULSE_GET_DEFAULT_SINK (pulse)) {
+ PULSE_SET_DEFAULT_SINK (pulse, NULL);
+
+ /* PulseAudio usually sends a server info update by itself when default
+ * stream changes, but there is at least one case when it does not - setting
+ * a card profile to off, so to be sure request an update explicitely */
+ pulse_connection_load_server_info (pulse->priv->connection);
+ }
+ g_object_unref (stream);
}
static void
@@ -892,40 +879,20 @@ on_connection_sink_input_info (PulseConnection *connection,
const pa_sink_input_info *info,
PulseBackend *pulse)
{
- PulseStream *stream;
- PulseStream *parent = NULL;
- gint64 index;
+ PulseSink *sink;
- if (G_LIKELY (info->sink != PA_INVALID_INDEX)) {
- index = HASH_ID_SINK (info->sink);
-
- parent = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (parent == NULL))
- g_debug ("Unknown parent %d of PulseAudio sink input %s",
- info->sink,
- info->name);
- }
-
- index = HASH_ID_SINK_INPUT (info->index);
-
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (stream == NULL) {
- stream = pulse_sink_input_new (connection, info, parent);
- if (G_UNLIKELY (stream == NULL))
- return;
+ if G_UNLIKELY (info->sink == PA_INVALID_INDEX)
+ return;
- g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+ sink = g_hash_table_lookup (pulse->priv->sinks, GUINT_TO_POINTER (info->sink));
+ if G_UNLIKELY (sink == NULL)
+ return;
- g_signal_emit_by_name (G_OBJECT (pulse),
- "stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
- } else {
- pulse_sink_input_update (stream, info, parent);
+ pulse_sink_add_input (sink, info);
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (stream));
- }
+ g_hash_table_insert (pulse->priv->sink_inputs,
+ GUINT_TO_POINTER (info->index),
+ g_object_ref (sink));
}
static void
@@ -933,14 +900,13 @@ on_connection_sink_input_removed (PulseConnection *connection,
guint idx,
PulseBackend *pulse)
{
- PulseStream *stream;
- gint64 index = HASH_ID_SINK_INPUT (idx);
+ PulseSink *sink;
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (stream == NULL))
+ sink = g_hash_table_lookup (pulse->priv->sink_inputs, GUINT_TO_POINTER (idx));
+ if G_UNLIKELY (sink == NULL)
return;
- remove_stream (pulse, stream);
+ pulse_sink_remove_input (sink, idx);
}
static void
@@ -950,36 +916,40 @@ on_connection_source_info (PulseConnection *connection,
{
PulseDevice *device = NULL;
PulseStream *stream;
- gint64 index = HASH_ID_SOURCE (info->index);
/* Skip monitor streams */
if (info->monitor_of_sink != PA_INVALID_INDEX)
return;
if (info->card != PA_INVALID_INDEX)
- device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (info->card));
+ device = g_hash_table_lookup (pulse->priv->devices,
+ GUINT_TO_POINTER (info->card));
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ stream = g_hash_table_lookup (pulse->priv->sources, GUINT_TO_POINTER (info->index));
if (stream == NULL) {
- stream = pulse_source_new (connection, info, device);
- if (G_UNLIKELY (stream == NULL))
- return;
+ stream = PULSE_STREAM (pulse_source_new (connection, info, device));
- g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+ free_list_streams (pulse);
+ g_hash_table_insert (pulse->priv->sources,
+ GUINT_TO_POINTER (info->index),
+ stream);
- g_signal_emit_by_name (G_OBJECT (pulse),
- "stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ if (device != NULL) {
+ pulse_device_add_stream (device, stream);
+ } else {
+ const gchar *name =
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
+ /* Only emit when not a part of the device, otherwise emitted by
+ * the main library */
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ name);
+ }
/* We might be waiting for this source to set it as the default */
check_pending_source (pulse, stream);
- } else {
- pulse_source_update (stream, info, device);
-
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (stream));
- }
+ } else
+ pulse_source_update (PULSE_SOURCE (stream), info);
}
static void
@@ -987,14 +957,39 @@ on_connection_source_removed (PulseConnection *connection,
guint idx,
PulseBackend *pulse)
{
+ PulseDevice *device;
PulseStream *stream;
- gint64 index = HASH_ID_SOURCE (idx);
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (stream == NULL))
+ stream = g_hash_table_lookup (pulse->priv->sources, GUINT_TO_POINTER (idx));
+ if G_UNLIKELY (stream == NULL)
return;
- remove_stream (pulse, stream);
+ g_object_ref (stream);
+
+ free_list_streams (pulse);
+ g_hash_table_remove (pulse->priv->sources, GUINT_TO_POINTER (idx));
+
+ device = pulse_stream_get_device (stream);
+ if (device != NULL) {
+ pulse_device_remove_stream (device, stream);
+ } else {
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-removed",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ }
+
+ /* The removed stream might be one of the default streams, this happens
+ * especially when switching profiles, after which PulseAudio removes the
+ * old streams and creates new ones with different names */
+ if (MATE_MIXER_STREAM (stream) == PULSE_GET_DEFAULT_SOURCE (pulse)) {
+ PULSE_SET_DEFAULT_SOURCE (pulse, NULL);
+
+ /* PulseAudio usually sends a server info update by itself when default
+ * stream changes, but there is at least one case when it does not - setting
+ * a card profile to off, so to be sure request an update explicitely */
+ pulse_connection_load_server_info (pulse->priv->connection);
+ }
+ g_object_unref (stream);
}
static void
@@ -1002,39 +997,20 @@ on_connection_source_output_info (PulseConnection *connection,
const pa_source_output_info *info,
PulseBackend *pulse)
{
- PulseStream *stream;
- PulseStream *parent = NULL;
- gint64 index;
-
- if (G_LIKELY (info->source != PA_INVALID_INDEX)) {
- index = HASH_ID_SOURCE (info->source);
-
- /* Most likely a monitor source that we have skipped */
- parent = g_hash_table_lookup (pulse->priv->streams, &index);
- if (parent == NULL)
- return;
- }
+ PulseSource *source;
- index = HASH_ID_SOURCE_OUTPUT (info->index);
-
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (stream == NULL) {
- stream = pulse_source_output_new (connection, info, parent);
- if (G_UNLIKELY (stream == NULL))
- return;
+ if G_UNLIKELY (info->source == PA_INVALID_INDEX)
+ return;
- g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+ source = g_hash_table_lookup (pulse->priv->sources, GUINT_TO_POINTER (info->source));
+ if G_UNLIKELY (source == NULL)
+ return;
- g_signal_emit_by_name (G_OBJECT (pulse),
- "stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
- } else {
- pulse_source_output_update (stream, info, parent);
+ pulse_source_add_output (source, info);
- /* The object might be hanging if reconnecting is in progress, remove the
- * hanging flag to prevent it from being removed when connected */
- unmark_hanging (pulse, G_OBJECT (stream));
- }
+ g_hash_table_insert (pulse->priv->source_outputs,
+ GUINT_TO_POINTER (info->index),
+ g_object_ref (source));
}
static void
@@ -1042,14 +1018,13 @@ on_connection_source_output_removed (PulseConnection *connection,
guint idx,
PulseBackend *pulse)
{
- PulseStream *stream;
- gint64 index = HASH_ID_SOURCE_OUTPUT (idx);
+ PulseSource *source;
- stream = g_hash_table_lookup (pulse->priv->streams, &index);
- if (G_UNLIKELY (stream == NULL))
+ source = g_hash_table_lookup (pulse->priv->source_outputs, GUINT_TO_POINTER (idx));
+ if G_UNLIKELY (source == NULL)
return;
- remove_stream (pulse, stream);
+ pulse_source_remove_output (source, idx);
}
static void
@@ -1057,63 +1032,75 @@ on_connection_ext_stream_info (PulseConnection *connection,
const pa_ext_stream_restore_info *info,
PulseBackend *pulse)
{
- PulseStream *stream;
- PulseStream *parent = NULL;
+ PulseExtStream *ext;
+ PulseStream *parent = NULL;
- if (G_LIKELY (info->device != NULL))
- parent = g_hash_table_find (pulse->priv->streams, compare_stream_names,
+ if (info->device != NULL) {
+ parent = g_hash_table_find (pulse->priv->sinks, compare_stream_names,
(gpointer) info->device);
- stream = g_hash_table_lookup (pulse->priv->ext_streams, info->name);
- if (stream == NULL) {
- stream = pulse_ext_stream_new (connection, info, parent);
- if (G_UNLIKELY (stream == NULL))
- return;
+ if (parent == NULL)
+ parent = g_hash_table_find (pulse->priv->sources, compare_stream_names,
+ (gpointer) info->device);
+ }
+
+ ext = g_hash_table_lookup (pulse->priv->ext_streams, info->name);
+ if (ext == NULL) {
+ ext = pulse_ext_stream_new (connection, info, parent);
- g_hash_table_insert (pulse->priv->ext_streams, g_strdup (info->name), stream);
+ free_list_ext_streams (pulse);
+ g_hash_table_insert (pulse->priv->ext_streams,
+ g_strdup (info->name),
+ ext);
g_signal_emit_by_name (G_OBJECT (pulse),
- "cached-stream-added",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ "stored-control-added",
+ mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (ext)));
} else {
- pulse_ext_stream_update (stream, info, parent);
+ pulse_ext_stream_update (ext, info, parent);
/* The object might be hanging if ext-streams are being loaded, remove
* the hanging flag to prevent it from being removed */
- unmark_hanging (pulse, G_OBJECT (stream));
+ PULSE_UNSET_HANGING (ext);
}
}
static void
on_connection_ext_stream_loading (PulseConnection *connection, PulseBackend *pulse)
{
- mark_hanging_hash (pulse->priv->ext_streams);
+ GHashTableIter iter;
+ gpointer ext;
+
+ g_hash_table_iter_init (&iter, pulse->priv->ext_streams);
+
+ while (g_hash_table_iter_next (&iter, NULL, &ext) == TRUE)
+ PULSE_SET_HANGING (ext);
}
static void
on_connection_ext_stream_loaded (PulseConnection *connection, PulseBackend *pulse)
{
GHashTableIter iter;
- gpointer value;
+ gpointer name;
+ gpointer ext;
g_hash_table_iter_init (&iter, pulse->priv->ext_streams);
- while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE) {
- guint hanging =
- GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (value), "backend-hanging"));
+ while (g_hash_table_iter_next (&iter, &name, &ext) == TRUE) {
+ if (PULSE_GET_HANGING (ext) == FALSE)
+ continue;
- if (hanging == 1) {
- gchar *name = g_strdup ((const gchar *) value);
+ free_list_ext_streams (pulse);
+ g_hash_table_remove (pulse->priv->ext_streams, (gconstpointer) name);
- g_hash_table_remove (pulse->priv->ext_streams, (gconstpointer) name);
- g_signal_emit_by_name (G_OBJECT (pulse),
- "cached-stream-removed",
- name);
- g_free (name);
- }
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stored-control-removed",
+ name);
}
+ g_debug ("Ext-streams refreshed");
}
+// XXX rename
static gboolean
connect_source_reconnect (PulseBackend *pulse)
{
@@ -1121,16 +1108,10 @@ connect_source_reconnect (PulseBackend *pulse)
* and wait for the connection state notifications, otherwise this function
* will be called again */
if (pulse_connection_connect (pulse->priv->connection, TRUE) == TRUE) {
- connect_source_remove (pulse);
- return FALSE;
+ pulse->priv->connect_tag = 0;
+ return G_SOURCE_REMOVE;
}
- return TRUE;
-}
-
-static void
-connect_source_remove (PulseBackend *pulse)
-{
- g_clear_pointer (&pulse->priv->connect_source, g_source_unref);
+ return G_SOURCE_CONTINUE;
}
static void
@@ -1141,7 +1122,7 @@ check_pending_sink (PulseBackend *pulse, PulseStream *stream)
/* See if the currently added sream matches the default input stream
* we are waiting for */
- pending = g_object_get_data (G_OBJECT (pulse), "backend-pending-sink");
+ pending = PULSE_GET_PENDING_SINK (pulse);
if (pending == NULL)
return;
@@ -1149,14 +1130,10 @@ check_pending_sink (PulseBackend *pulse, PulseStream *stream)
if (g_strcmp0 (pending, name) != 0)
return;
- pulse->priv->default_sink = g_object_ref (stream);
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-sink",
- NULL);
+ g_debug ("Setting default output stream to pending stream %s", name);
- g_debug ("Default output stream changed to pending stream %s", name);
-
- g_object_notify (G_OBJECT (pulse), "default-output");
+ PULSE_SET_PENDING_SINK_NULL (pulse);
+ PULSE_SET_DEFAULT_SINK (pulse, stream);
}
static void
@@ -1167,7 +1144,7 @@ check_pending_source (PulseBackend *pulse, PulseStream *stream)
/* See if the currently added sream matches the default input stream
* we are waiting for */
- pending = g_object_get_data (G_OBJECT (pulse), "backend-pending-source");
+ pending = PULSE_GET_PENDING_SOURCE (pulse);
if (pending == NULL)
return;
@@ -1175,160 +1152,43 @@ check_pending_source (PulseBackend *pulse, PulseStream *stream)
if (g_strcmp0 (pending, name) != 0)
return;
- pulse->priv->default_source = g_object_ref (stream);
- g_object_set_data (G_OBJECT (pulse),
- "backend-pending-source",
- NULL);
-
- g_debug ("Default input stream changed to pending stream %s", name);
+ g_debug ("Setting default input stream to pending stream %s", name);
- g_object_notify (G_OBJECT (pulse), "default-input");
+ PULSE_SET_PENDING_SOURCE_NULL (pulse);
+ PULSE_SET_DEFAULT_SOURCE (pulse, stream);
}
static void
-mark_hanging (PulseBackend *pulse)
+free_list_devices (PulseBackend *pulse)
{
- /* Mark devices and streams as hanging, ext-streams are handled separately */
- mark_hanging_hash (pulse->priv->devices);
- mark_hanging_hash (pulse->priv->streams);
-}
-
-static void
-mark_hanging_hash (GHashTable *hash)
-{
- GHashTableIter iter;
- gpointer value;
-
- g_hash_table_iter_init (&iter, hash);
-
- while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE)
- g_object_set_data (G_OBJECT (value), "backend-hanging", GUINT_TO_POINTER (1));
-}
-
-static void
-unmark_hanging (PulseBackend *pulse, GObject *object)
-{
- if (pulse->priv->connected_once == FALSE)
- return;
- if (pulse->priv->state == MATE_MIXER_STATE_READY)
+ if (pulse->priv->devices_list == NULL)
return;
- g_object_steal_data (object, "backend-hanging");
-}
-
-static void
-remove_hanging (PulseBackend *pulse)
-{
- GHashTableIter iter;
- gpointer value;
-
- g_hash_table_iter_init (&iter, pulse->priv->devices);
-
- while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE) {
- guint hanging =
- GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (value), "backend-hanging"));
-
- if (hanging == 1)
- remove_device (pulse, PULSE_DEVICE (value));
- }
-
- g_hash_table_iter_init (&iter, pulse->priv->streams);
-
- while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE) {
- guint hanging =
- GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (value), "backend-hanging"));
+ g_list_free_full (pulse->priv->devices_list, g_object_unref);
- if (hanging == 1)
- remove_stream (pulse, PULSE_STREAM (value));
- }
-}
-
-static void
-remove_device (PulseBackend *pulse, PulseDevice *device)
-{
- gchar *name;
-
- name = g_strdup (mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
-
- g_hash_table_remove (pulse->priv->devices,
- GUINT_TO_POINTER (pulse_device_get_index (device)));
-
- g_signal_emit_by_name (G_OBJECT (pulse), "device-removed", name);
- g_free (name);
+ pulse->priv->devices_list = NULL;
}
static void
-remove_stream (PulseBackend *pulse, PulseStream *stream)
+free_list_streams (PulseBackend *pulse)
{
- gchar *name;
- guint32 idx;
- gint64 index;
- gboolean reload = FALSE;
-
- /* The removed stream might be one of the default streams, this happens
- * especially when switching profiles, after which PulseAudio removes the
- * old streams and creates new ones with different names */
- if (MATE_MIXER_STREAM (stream) == pulse->priv->default_sink) {
- g_clear_object (&pulse->priv->default_sink);
-
- g_object_notify (G_OBJECT (pulse), "default-output");
- reload = TRUE;
- }
- else if (MATE_MIXER_STREAM (stream) == pulse->priv->default_source) {
- g_clear_object (&pulse->priv->default_source);
-
- g_object_notify (G_OBJECT (pulse), "default-input");
- reload = TRUE;
- }
-
- idx = pulse_stream_get_index (stream);
-
- if (PULSE_IS_SINK (stream))
- index = HASH_ID_SINK (idx);
- else if (PULSE_IS_SINK_INPUT (stream))
- index = HASH_ID_SINK_INPUT (idx);
- else if (PULSE_IS_SOURCE (stream))
- index = HASH_ID_SOURCE (idx);
- else
- index = HASH_ID_SOURCE_OUTPUT (idx);
-
- name = g_strdup (mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
-
- g_hash_table_remove (pulse->priv->streams, &index);
+ if (pulse->priv->streams_list == NULL)
+ return;
- /* PulseAudio usually sends a server info update by itself when default
- * stream changes, but there is at least one case when it does not - setting
- * a card profile to off, so to be sure request an update explicitely */
- if (reload == TRUE)
- pulse_connection_load_server_info (pulse->priv->connection);
+ g_list_free_full (pulse->priv->streams_list, g_object_unref);
- g_signal_emit_by_name (G_OBJECT (pulse), "stream-removed", name);
- g_free (name);
+ pulse->priv->streams_list = NULL;
}
static void
-change_state (PulseBackend *backend, MateMixerState state)
+free_list_ext_streams (PulseBackend *pulse)
{
- if (backend->priv->state == state)
+ if (pulse->priv->ext_streams_list == NULL)
return;
- backend->priv->state = state;
-
- g_object_notify (G_OBJECT (backend), "state");
-}
+ g_list_free_full (pulse->priv->ext_streams_list, g_object_unref);
-static gint
-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
-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)));
+ pulse->priv->ext_streams_list = NULL;
}
static gboolean
@@ -1336,5 +1196,5 @@ compare_stream_names (gpointer key, gpointer value, gpointer user_data)
{
MateMixerStream *stream = MATE_MIXER_STREAM (value);
- return !strcmp (mate_mixer_stream_get_name (stream), (const gchar *) user_data);
+ return strcmp (mate_mixer_stream_get_name (stream), (const gchar *) user_data) == 0;
}
diff --git a/backends/pulse/pulse-backend.h b/backends/pulse/pulse-backend.h
index bd1face..2c4b8a8 100644
--- a/backends/pulse/pulse-backend.h
+++ b/backends/pulse/pulse-backend.h
@@ -20,8 +20,10 @@
#include <glib.h>
#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
-#include <libmatemixer/matemixer-backend-module.h>
+#include "pulse-types.h"
#define PULSE_TYPE_BACKEND \
(pulse_backend_get_type ())
@@ -36,13 +38,12 @@
#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
{
- GObject parent;
+ MateMixerBackend parent;
/*< private >*/
PulseBackendPrivate *priv;
@@ -50,7 +51,7 @@ struct _PulseBackend
struct _PulseBackendClass
{
- GObjectClass parent_class;
+ MateMixerBackendClass parent_class;
};
GType pulse_backend_get_type (void) G_GNUC_CONST;
diff --git a/backends/pulse/pulse-client-stream.c b/backends/pulse/pulse-client-stream.c
deleted file mode 100644
index b99c498..0000000
--- a/backends/pulse/pulse-client-stream.c
+++ /dev/null
@@ -1,433 +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 <string.h>
-#include <glib.h>
-#include <glib-object.h>
-
-#include <libmatemixer/matemixer-client-stream.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-stream.h>
-
-#include <pulse/pulseaudio.h>
-
-#include "pulse-client-stream.h"
-#include "pulse-sink.h"
-#include "pulse-source.h"
-#include "pulse-stream.h"
-
-struct _PulseClientStreamPrivate
-{
- gchar *app_name;
- gchar *app_id;
- gchar *app_version;
- gchar *app_icon;
- MateMixerStream *parent;
- MateMixerClientStreamFlags flags;
- MateMixerClientStreamRole role;
-};
-
-enum {
- PROP_0,
- PROP_CLIENT_FLAGS,
- PROP_ROLE,
- PROP_PARENT,
- PROP_APP_NAME,
- PROP_APP_ID,
- PROP_APP_VERSION,
- PROP_APP_ICON
-};
-
-enum {
- REMOVED,
- N_SIGNALS
-};
-
-static guint signals[N_SIGNALS] = { 0, };
-
-static void mate_mixer_client_stream_interface_init (MateMixerClientStreamInterface *iface);
-
-static void pulse_client_stream_class_init (PulseClientStreamClass *klass);
-
-static void pulse_client_stream_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec);
-
-static void pulse_client_stream_init (PulseClientStream *client);
-static void pulse_client_stream_dispose (GObject *object);
-static void pulse_client_stream_finalize (GObject *object);
-
-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 MateMixerClientStreamFlags pulse_client_stream_get_flags (MateMixerClientStream *client);
-static MateMixerClientStreamRole pulse_client_stream_get_role (MateMixerClientStream *client);
-
-static MateMixerStream * pulse_client_stream_get_parent (MateMixerClientStream *client);
-static gboolean pulse_client_stream_set_parent (MateMixerClientStream *client,
- MateMixerStream *parent);
-
-static gboolean pulse_client_stream_remove (MateMixerClientStream *client);
-
-static const gchar * pulse_client_stream_get_app_name (MateMixerClientStream *client);
-static const gchar * pulse_client_stream_get_app_id (MateMixerClientStream *client);
-static const gchar * pulse_client_stream_get_app_version (MateMixerClientStream *client);
-static const gchar * pulse_client_stream_get_app_icon (MateMixerClientStream *client);
-
-static void
-mate_mixer_client_stream_interface_init (MateMixerClientStreamInterface *iface)
-{
- iface->get_flags = pulse_client_stream_get_flags;
- iface->get_role = pulse_client_stream_get_role;
- iface->get_parent = pulse_client_stream_get_parent;
- iface->set_parent = pulse_client_stream_set_parent;
- iface->remove = pulse_client_stream_remove;
- iface->get_app_name = pulse_client_stream_get_app_name;
- iface->get_app_id = pulse_client_stream_get_app_id;
- iface->get_app_version = pulse_client_stream_get_app_version;
- iface->get_app_icon = pulse_client_stream_get_app_icon;
-}
-
-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->finalize = pulse_client_stream_finalize;
- object_class->get_property = pulse_client_stream_get_property;
-
- signals[REMOVED] =
- g_signal_new ("removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseClientStreamClass, removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0,
- G_TYPE_NONE);
-
- g_object_class_override_property (object_class, PROP_CLIENT_FLAGS, "client-flags");
- g_object_class_override_property (object_class, PROP_ROLE, "role");
- g_object_class_override_property (object_class, PROP_PARENT, "parent");
- g_object_class_override_property (object_class, PROP_APP_NAME, "app-name");
- g_object_class_override_property (object_class, PROP_APP_ID, "app-id");
- g_object_class_override_property (object_class, PROP_APP_VERSION, "app-version");
- g_object_class_override_property (object_class, PROP_APP_ICON, "app-icon");
-
- g_type_class_add_private (object_class, sizeof (PulseClientStreamPrivate));
-}
-
-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_CLIENT_FLAGS:
- g_value_set_flags (value, client->priv->flags);
- break;
- case PROP_ROLE:
- g_value_set_enum (value, client->priv->role);
- break;
- case PROP_PARENT:
- g_value_set_object (value, client->priv->parent);
- break;
- case PROP_APP_NAME:
- g_value_set_string (value, client->priv->app_name);
- break;
- case PROP_APP_ID:
- g_value_set_string (value, client->priv->app_id);
- break;
- case PROP_APP_VERSION:
- g_value_set_string (value, client->priv->app_version);
- break;
- case PROP_APP_ICON:
- g_value_set_string (value, client->priv->app_icon);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- break;
- }
-}
-
-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 void
-pulse_client_stream_finalize (GObject *object)
-{
- PulseClientStream *client;
-
- client = PULSE_CLIENT_STREAM (object);
-
- g_free (client->priv->app_name);
- g_free (client->priv->app_id);
- g_free (client->priv->app_version);
- g_free (client->priv->app_icon);
-
- G_OBJECT_CLASS (pulse_client_stream_parent_class)->finalize (object);
-}
-
-gboolean
-pulse_client_stream_update_flags (PulseClientStream *pclient,
- MateMixerClientStreamFlags flags)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (pclient->priv->flags != flags) {
- pclient->priv->flags = flags;
-
- g_object_notify (G_OBJECT (pclient), "client-flags");
- }
- return TRUE;
-}
-
-gboolean
-pulse_client_stream_update_parent (PulseClientStream *pclient, MateMixerStream *parent)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (pclient->priv->parent != parent) {
- g_clear_object (&pclient->priv->parent);
-
- if (G_LIKELY (parent != NULL))
- pclient->priv->parent = g_object_ref (parent);
-
- g_object_notify (G_OBJECT (pclient), "parent");
- }
- return TRUE;
-}
-
-gboolean
-pulse_client_stream_update_role (PulseClientStream *pclient,
- MateMixerClientStreamRole role)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (pclient->priv->role != role) {
- pclient->priv->role = role;
-
- g_object_notify (G_OBJECT (pclient), "role");
- }
- return TRUE;
-}
-
-gboolean
-pulse_client_stream_update_app_name (PulseClientStream *pclient, const gchar *app_name)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (g_strcmp0 (pclient->priv->app_name, app_name) != 0) {
- g_free (pclient->priv->app_name);
- pclient->priv->app_name = g_strdup (app_name);
-
- g_object_notify (G_OBJECT (pclient), "app-name");
- }
- return TRUE;
-}
-
-gboolean
-pulse_client_stream_update_app_id (PulseClientStream *pclient, const gchar *app_id)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (g_strcmp0 (pclient->priv->app_id, app_id) != 0) {
- g_free (pclient->priv->app_id);
- pclient->priv->app_id = g_strdup (app_id);
-
- g_object_notify (G_OBJECT (pclient), "app-id");
- }
- return TRUE;
-}
-
-gboolean
-pulse_client_stream_update_app_version (PulseClientStream *pclient, const gchar *app_version)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (g_strcmp0 (pclient->priv->app_version, app_version) != 0) {
- g_free (pclient->priv->app_version);
- pclient->priv->app_version = g_strdup (app_version);
-
- g_object_notify (G_OBJECT (pclient), "app-version");
- }
- return TRUE;
-}
-
-gboolean
-pulse_client_stream_update_app_icon (PulseClientStream *pclient, const gchar *app_icon)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
-
- if (g_strcmp0 (pclient->priv->app_icon, app_icon) != 0) {
- g_free (pclient->priv->app_icon);
- pclient->priv->app_icon = g_strdup (app_icon);
-
- g_object_notify (G_OBJECT (pclient), "app-icon");
- }
- return TRUE;
-}
-
-static MateMixerClientStreamFlags
-pulse_client_stream_get_flags (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_NO_FLAGS);
-
- return PULSE_CLIENT_STREAM (client)->priv->flags;
-}
-
-static MateMixerClientStreamRole
-pulse_client_stream_get_role (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_ROLE_NONE);
-
- return PULSE_CLIENT_STREAM (client)->priv->role;
-}
-
-static MateMixerStream *
-pulse_client_stream_get_parent (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
-
- return PULSE_CLIENT_STREAM (client)->priv->parent;
-}
-
-static gboolean
-pulse_client_stream_set_parent (MateMixerClientStream *client, MateMixerStream *parent)
-{
- MateMixerStreamFlags flags;
- PulseClientStream *pclient;
- PulseClientStreamClass *klass;
-
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
- g_return_val_if_fail (PULSE_IS_STREAM (parent), FALSE);
-
- pclient = PULSE_CLIENT_STREAM (client);
- klass = PULSE_CLIENT_STREAM_GET_CLASS (pclient);
-
- if (pclient->priv->parent == parent)
- return TRUE;
-
- flags = mate_mixer_stream_get_flags (MATE_MIXER_STREAM (pclient));
-
- /* Validate the parent stream */
- if (flags & MATE_MIXER_STREAM_INPUT && !PULSE_IS_SOURCE (parent)) {
- g_warning ("Could not change stream parent to %s: not a parent input stream",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (parent)));
- return FALSE;
- } else if (flags & MATE_MIXER_STREAM_OUTPUT && !PULSE_IS_SINK (parent)) {
- g_warning ("Could not change stream parent to %s: not a parent output stream",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (parent)));
- return FALSE;
- }
-
- /* Set the parent */
- if (klass->set_parent (pclient, PULSE_STREAM (parent)) == FALSE)
- return FALSE;
-
- if (pclient->priv->parent != NULL)
- g_object_unref (pclient->priv->parent);
-
- /* It is allowed for the parent to be NULL when the instance is created, but
- * changing the parent requires a valid parent stream */
- pclient->priv->parent = g_object_ref (parent);
-
- g_object_notify (G_OBJECT (client), "parent");
- return TRUE;
-}
-
-static gboolean
-pulse_client_stream_remove (MateMixerClientStream *client)
-{
- PulseClientStream *pclient;
- PulseClientStreamClass *klass;
-
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
-
- pclient = PULSE_CLIENT_STREAM (client);
- klass = PULSE_CLIENT_STREAM_GET_CLASS (pclient);
-
- if (klass->remove (pclient) == FALSE)
- return FALSE;
-
- // XXX handle this in the backend
- g_signal_emit (G_OBJECT (client),
- signals[REMOVED],
- 0);
-
- return TRUE;
-}
-
-static const gchar *
-pulse_client_stream_get_app_name (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
-
- return PULSE_CLIENT_STREAM (client)->priv->app_name;
-}
-
-static const gchar *
-pulse_client_stream_get_app_id (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
-
- return PULSE_CLIENT_STREAM (client)->priv->app_id;
-}
-
-static const gchar *
-pulse_client_stream_get_app_version (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
-
- return PULSE_CLIENT_STREAM (client)->priv->app_version;
-}
-
-static const gchar *
-pulse_client_stream_get_app_icon (MateMixerClientStream *client)
-{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
-
- return PULSE_CLIENT_STREAM (client)->priv->app_icon;
-}
diff --git a/backends/pulse/pulse-client-stream.h b/backends/pulse/pulse-client-stream.h
deleted file mode 100644
index fe24dc3..0000000
--- a/backends/pulse/pulse-client-stream.h
+++ /dev/null
@@ -1,94 +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 PULSE_CLIENT_STREAM_H
-#define PULSE_CLIENT_STREAM_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <libmatemixer/matemixer-client-stream.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-stream.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_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;
-
- /*< private >*/
- PulseClientStreamPrivate *priv;
-};
-
-struct _PulseClientStreamClass
-{
- PulseStreamClass parent_class;
-
- /*< private >*/
- /* Virtual table */
- gboolean (*set_parent) (PulseClientStream *pclient,
- PulseStream *pstream);
-
- gboolean (*remove) (PulseClientStream *pclient);
-
- /* Signals */
- void (*removed) (PulseClientStream *pclient);
-};
-
-GType pulse_client_stream_get_type (void) G_GNUC_CONST;
-
-gboolean pulse_client_stream_update_flags (PulseClientStream *pclient,
- MateMixerClientStreamFlags flags);
-
-gboolean pulse_client_stream_update_role (PulseClientStream *pclient,
- MateMixerClientStreamRole role);
-
-gboolean pulse_client_stream_update_parent (PulseClientStream *pclient,
- MateMixerStream *parent);
-
-gboolean pulse_client_stream_update_app_name (PulseClientStream *pclient,
- const gchar *app_name);
-gboolean pulse_client_stream_update_app_id (PulseClientStream *pclient,
- const gchar *app_id);
-gboolean pulse_client_stream_update_app_version (PulseClientStream *pclient,
- const gchar *app_version);
-gboolean pulse_client_stream_update_app_icon (PulseClientStream *pclient,
- const gchar *app_icon);
-
-G_END_DECLS
-
-#endif /* PULSE_CLIENT_STREAM_H */
diff --git a/backends/pulse/pulse-connection.c b/backends/pulse/pulse-connection.c
index cc39caf..7344d2e 100644
--- a/backends/pulse/pulse-connection.c
+++ b/backends/pulse/pulse-connection.c
@@ -31,14 +31,14 @@
struct _PulseConnectionPrivate
{
- gchar *server;
- guint outstanding;
- pa_context *context;
- pa_proplist *proplist;
- pa_glib_mainloop *mainloop;
- gboolean ext_streams_loading;
- gboolean ext_streams_dirty;
- PulseConnectionState state;
+ gchar *server;
+ guint outstanding;
+ pa_context *context;
+ pa_proplist *proplist;
+ pa_glib_mainloop *mainloop;
+ gboolean ext_streams_loading;
+ gboolean ext_streams_dirty;
+ PulseConnectionState state;
};
enum {
@@ -417,7 +417,7 @@ pulse_connection_new (const gchar *app_name,
PulseConnection *connection;
mainloop = pa_glib_mainloop_new (g_main_context_get_thread_default ());
- if (G_UNLIKELY (mainloop == NULL)) {
+ if G_UNLIKELY (mainloop == NULL) {
g_warning ("Failed to create PulseAudio main loop");
return NULL;
}
@@ -468,7 +468,7 @@ pulse_connection_connect (PulseConnection *connection, gboolean wait_for_daemon)
context = pa_context_new_with_proplist (mainloop,
NULL,
connection->priv->proplist);
- if (G_UNLIKELY (context == NULL)) {
+ if G_UNLIKELY (context == NULL) {
g_warning ("Failed to create PulseAudio context");
return FALSE;
}
@@ -774,7 +774,6 @@ pulse_connection_create_monitor (PulseConnection *connection,
return pulse_monitor_new (connection->priv->context,
connection->priv->proplist,
- NULL,
index_source,
index_sink_input);
}
@@ -1227,7 +1226,7 @@ load_lists (PulseConnection *connection)
GSList *ops = NULL;
pa_operation *op;
- if (G_UNLIKELY (connection->priv->outstanding > 0)) {
+ if G_UNLIKELY (connection->priv->outstanding > 0) {
g_warn_if_reached ();
return FALSE;
}
@@ -1235,7 +1234,7 @@ load_lists (PulseConnection *connection)
op = pa_context_get_card_info_list (connection->priv->context,
pulse_card_info_cb,
connection);
- if (G_UNLIKELY (op == NULL))
+ if G_UNLIKELY (op == NULL)
goto error;
ops = g_slist_prepend (ops, op);
@@ -1243,7 +1242,7 @@ load_lists (PulseConnection *connection)
op = pa_context_get_sink_info_list (connection->priv->context,
pulse_sink_info_cb,
connection);
- if (G_UNLIKELY (op == NULL))
+ if G_UNLIKELY (op == NULL)
goto error;
ops = g_slist_prepend (ops, op);
@@ -1251,7 +1250,7 @@ load_lists (PulseConnection *connection)
op = pa_context_get_sink_input_info_list (connection->priv->context,
pulse_sink_input_info_cb,
connection);
- if (G_UNLIKELY (op == NULL))
+ if G_UNLIKELY (op == NULL)
goto error;
ops = g_slist_prepend (ops, op);
@@ -1259,7 +1258,7 @@ load_lists (PulseConnection *connection)
op = pa_context_get_source_info_list (connection->priv->context,
pulse_source_info_cb,
connection);
- if (G_UNLIKELY (op == NULL))
+ if G_UNLIKELY (op == NULL)
goto error;
ops = g_slist_prepend (ops, op);
@@ -1267,7 +1266,7 @@ load_lists (PulseConnection *connection)
op = pa_context_get_source_output_info_list (connection->priv->context,
pulse_source_output_info_cb,
connection);
- if (G_UNLIKELY (op == NULL))
+ if G_UNLIKELY (op == NULL)
goto error;
ops = g_slist_prepend (ops, op);
@@ -1303,7 +1302,7 @@ load_list_finished (PulseConnection *connection)
* as the final step in the connection process */
connection->priv->outstanding--;
- if (G_UNLIKELY (connection->priv->outstanding < 0)) {
+ if G_UNLIKELY (connection->priv->outstanding < 0) {
g_warn_if_reached ();
connection->priv->outstanding = 0;
}
@@ -1311,7 +1310,7 @@ load_list_finished (PulseConnection *connection)
if (connection->priv->outstanding == 0) {
gboolean ret = pulse_connection_load_server_info (connection);
- if (G_UNLIKELY (ret == FALSE)) {
+ if G_UNLIKELY (ret == FALSE) {
pulse_connection_disconnect (connection);
return FALSE;
}
@@ -1640,7 +1639,7 @@ change_state (PulseConnection *connection, PulseConnectionState state)
static gboolean
process_pulse_operation (PulseConnection *connection, pa_operation *op)
{
- if (G_UNLIKELY (op == NULL)) {
+ if G_UNLIKELY (op == NULL) {
g_warning ("PulseAudio operation failed: %s",
pa_strerror (pa_context_errno (connection->priv->context)));
return FALSE;
diff --git a/backends/pulse/pulse-connection.h b/backends/pulse/pulse-connection.h
index b9119fd..7dc0bfb 100644
--- a/backends/pulse/pulse-connection.h
+++ b/backends/pulse/pulse-connection.h
@@ -25,7 +25,7 @@
#include <pulse/ext-stream-restore.h>
#include "pulse-enums.h"
-#include "pulse-monitor.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
@@ -42,7 +42,6 @@ G_BEGIN_DECLS
#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;
@@ -59,7 +58,6 @@ struct _PulseConnectionClass
GObjectClass parent_class;
/*< private >*/
- /* Signals */
void (*server_info) (PulseConnection *connection,
const pa_server_info *info);
@@ -201,7 +199,6 @@ gboolean pulse_connection_kill_source_output (PulseConnection
gboolean pulse_connection_write_ext_stream (PulseConnection *connection,
const pa_ext_stream_restore_info *info);
-
gboolean pulse_connection_delete_ext_stream (PulseConnection *connection,
const gchar *name);
diff --git a/backends/pulse/pulse-device-profile.c b/backends/pulse/pulse-device-profile.c
new file mode 100644
index 0000000..5487841
--- /dev/null
+++ b/backends/pulse/pulse-device-profile.c
@@ -0,0 +1,88 @@
+/*
+ * 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.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-connection.h"
+#include "pulse-device.h"
+#include "pulse-device-profile.h"
+
+struct _PulseDeviceProfilePrivate
+{
+ guint priority;
+};
+
+static void pulse_device_profile_class_init (PulseDeviceProfileClass *klass);
+static void pulse_device_profile_init (PulseDeviceProfile *profile);
+
+G_DEFINE_TYPE (PulseDeviceProfile, pulse_device_profile, MATE_MIXER_TYPE_SWITCH_OPTION)
+
+static void
+pulse_device_profile_class_init (PulseDeviceProfileClass *klass)
+{
+ g_type_class_add_private (klass, sizeof (PulseDeviceProfilePrivate));
+}
+
+static void
+pulse_device_profile_init (PulseDeviceProfile *profile)
+{
+ profile->priv = G_TYPE_INSTANCE_GET_PRIVATE (profile,
+ PULSE_TYPE_DEVICE_PROFILE,
+ PulseDeviceProfilePrivate);
+}
+
+PulseDeviceProfile *
+pulse_device_profile_new (const gchar *name,
+ const gchar *label,
+ guint priority)
+{
+ PulseDeviceProfile *profile;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (label != NULL, NULL);
+
+ profile = g_object_new (PULSE_TYPE_DEVICE_PROFILE,
+ "name", name,
+ "label", label,
+ NULL);
+
+ profile->priv->priority = priority;
+ return profile;
+}
+
+const gchar *
+pulse_device_profile_get_name (PulseDeviceProfile *profile)
+{
+ g_return_val_if_fail (PULSE_IS_DEVICE_PROFILE (profile), NULL);
+
+ return mate_mixer_switch_option_get_name (MATE_MIXER_SWITCH_OPTION (profile));
+}
+
+guint
+pulse_device_profile_get_priority (PulseDeviceProfile *profile)
+{
+ g_return_val_if_fail (PULSE_IS_DEVICE_PROFILE (profile), 0);
+
+ return profile->priv->priority;
+}
diff --git a/backends/pulse/pulse-device-profile.h b/backends/pulse/pulse-device-profile.h
new file mode 100644
index 0000000..0a9c3f4
--- /dev/null
+++ b/backends/pulse/pulse-device-profile.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_DEVICE_PROFILE_H
+#define PULSE_DEVICE_PROFILE_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_DEVICE_PROFILE \
+ (pulse_device_profile_get_type ())
+#define PULSE_DEVICE_PROFILE(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_DEVICE_PROFILE, PulseDeviceProfile))
+#define PULSE_IS_DEVICE_PROFILE(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_DEVICE_PROFILE))
+#define PULSE_DEVICE_PROFILE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_DEVICE_PROFILE, PulseDeviceProfileClass))
+#define PULSE_IS_DEVICE_PROFILE_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_DEVICE_PROFILE))
+#define PULSE_DEVICE_PROFILE_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_IS_DEVICE_PROFILE, PulseDeviceProfileClass))
+
+typedef struct _PulseDeviceProfileClass PulseDeviceProfileClass;
+typedef struct _PulseDeviceProfilePrivate PulseDeviceProfilePrivate;
+
+struct _PulseDeviceProfile
+{
+ MateMixerSwitchOption parent;
+
+ /*< private >*/
+ PulseDeviceProfilePrivate *priv;
+};
+
+struct _PulseDeviceProfileClass
+{
+ MateMixerSwitchOptionClass parent;
+};
+
+GType pulse_device_profile_get_type (void) G_GNUC_CONST;
+
+PulseDeviceProfile *pulse_device_profile_new (const gchar *name,
+ const gchar *label,
+ guint priority);
+
+const gchar * pulse_device_profile_get_name (PulseDeviceProfile *profile);
+guint pulse_device_profile_get_priority (PulseDeviceProfile *profile);
+
+G_END_DECLS
+
+#endif /* PULSE_DEVICE_PROFILE_H */
diff --git a/backends/pulse/pulse-device-switch.c b/backends/pulse/pulse-device-switch.c
new file mode 100644
index 0000000..7a43d0a
--- /dev/null
+++ b/backends/pulse/pulse-device-switch.c
@@ -0,0 +1,261 @@
+/*
+ * 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.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "pulse-connection.h"
+#include "pulse-device.h"
+#include "pulse-device-profile.h"
+#include "pulse-device-switch.h"
+
+struct _PulseDeviceSwitchPrivate
+{
+ GList *profiles;
+ PulseDevice *device;
+};
+
+enum {
+ PROP_0,
+ PROP_DEVICE,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+static void pulse_device_switch_class_init (PulseDeviceSwitchClass *klass);
+
+static void pulse_device_switch_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void pulse_device_switch_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void pulse_device_switch_init (PulseDeviceSwitch *swtch);
+static void pulse_device_switch_dispose (GObject *object);
+
+G_DEFINE_TYPE (PulseDeviceSwitch, pulse_device_switch, MATE_MIXER_TYPE_SWITCH)
+
+static gboolean pulse_device_switch_set_active_option (MateMixerSwitch *mms,
+ MateMixerSwitchOption *mmso);
+
+static const GList *pulse_device_switch_list_options (MateMixerSwitch *mms);
+
+static gint compare_profiles (gconstpointer a,
+ gconstpointer b);
+static gint compare_profile_name (gconstpointer a,
+ gconstpointer b);
+
+static void
+pulse_device_switch_class_init (PulseDeviceSwitchClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerSwitchClass *switch_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_device_switch_dispose;
+ object_class->get_property = pulse_device_switch_get_property;
+ object_class->set_property = pulse_device_switch_set_property;
+
+ switch_class = MATE_MIXER_SWITCH_CLASS (klass);
+ switch_class->set_active_option = pulse_device_switch_set_active_option;
+ switch_class->list_options = pulse_device_switch_list_options;
+
+ properties[PROP_DEVICE] =
+ g_param_spec_object ("device",
+ "Device",
+ "PulseAudio device",
+ PULSE_TYPE_DEVICE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (PulseDeviceSwitchPrivate));
+}
+
+static void
+pulse_device_switch_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PulseDeviceSwitch *swtch;
+
+ swtch = PULSE_DEVICE_SWITCH (object);
+
+ switch (param_id) {
+ case PROP_DEVICE:
+ g_value_set_object (value, swtch->priv->device);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_device_switch_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PulseDeviceSwitch *swtch;
+
+ swtch = PULSE_DEVICE_SWITCH (object);
+
+ switch (param_id) {
+ case PROP_DEVICE:
+ /* Construct-only object */
+ swtch->priv->device = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_device_switch_init (PulseDeviceSwitch *swtch)
+{
+ swtch->priv = G_TYPE_INSTANCE_GET_PRIVATE (swtch,
+ PULSE_TYPE_DEVICE_SWITCH,
+ PulseDeviceSwitchPrivate);
+}
+
+static void
+pulse_device_switch_dispose (GObject *object)
+{
+ PulseDeviceSwitch *swtch;
+
+ swtch = PULSE_DEVICE_SWITCH (object);
+
+ g_clear_object (&swtch->priv->device);
+
+ G_OBJECT_CLASS (pulse_device_switch_parent_class)->dispose (object);
+}
+
+PulseDeviceSwitch *
+pulse_device_switch_new (const gchar *name, const gchar *label, PulseDevice *device)
+{
+ return g_object_new (PULSE_TYPE_DEVICE_SWITCH,
+ "name", name,
+ "label", label,
+ "role", MATE_MIXER_SWITCH_ROLE_DEVICE_PROFILE,
+ "device", device,
+ NULL);
+}
+
+PulseDevice *
+pulse_device_switch_get_device (PulseDeviceSwitch *swtch)
+{
+ g_return_val_if_fail (PULSE_IS_DEVICE_SWITCH (swtch), NULL);
+
+ return swtch->priv->device;
+}
+
+void
+pulse_device_switch_add_profile (PulseDeviceSwitch *swtch, PulseDeviceProfile *profile)
+{
+ g_return_if_fail (PULSE_IS_DEVICE_SWITCH (swtch));
+ g_return_if_fail (PULSE_IS_DEVICE_PROFILE (profile));
+
+ swtch->priv->profiles = g_list_insert_sorted (swtch->priv->profiles,
+ profile,
+ compare_profiles);
+}
+
+void
+pulse_device_switch_set_active_profile (PulseDeviceSwitch *swtch,
+ PulseDeviceProfile *profile)
+{
+ g_return_if_fail (PULSE_IS_DEVICE_SWITCH (swtch));
+ g_return_if_fail (PULSE_IS_DEVICE_PROFILE (profile));
+
+ _mate_mixer_switch_set_active_option (MATE_MIXER_SWITCH (swtch),
+ MATE_MIXER_SWITCH_OPTION (profile));
+}
+
+void
+pulse_device_switch_set_active_profile_by_name (PulseDeviceSwitch *swtch, const gchar *name)
+{
+ GList *item;
+
+ g_return_if_fail (PULSE_IS_DEVICE_SWITCH (swtch));
+ g_return_if_fail (name != NULL);
+
+ item = g_list_find_custom (swtch->priv->profiles, name, compare_profile_name);
+ if G_UNLIKELY (item == NULL) {
+ g_debug ("Invalid device switch profile name %s", name);
+ return;
+ }
+ pulse_device_switch_set_active_profile (swtch, PULSE_DEVICE_PROFILE (item->data));
+}
+
+static gboolean
+pulse_device_switch_set_active_option (MateMixerSwitch *mms, MateMixerSwitchOption *mmso)
+{
+ PulseDevice *device;
+ const gchar *device_name;
+ const gchar *profile_name;
+
+ g_return_val_if_fail (PULSE_IS_DEVICE_SWITCH (mms), FALSE);
+ g_return_val_if_fail (PULSE_IS_DEVICE_PROFILE (mmso), FALSE);
+
+ device = pulse_device_switch_get_device (PULSE_DEVICE_SWITCH (mms));
+ if G_UNLIKELY (device == NULL)
+ return FALSE;
+
+ device_name = mate_mixer_device_get_name (MATE_MIXER_DEVICE (device));
+ profile_name = mate_mixer_switch_option_get_name (mmso);
+
+ return pulse_connection_set_card_profile (pulse_device_get_connection (device),
+ device_name,
+ profile_name);
+}
+
+static const GList *
+pulse_device_switch_list_options (MateMixerSwitch *swtch)
+{
+ g_return_val_if_fail (PULSE_IS_DEVICE_SWITCH (swtch), NULL);
+
+ return PULSE_DEVICE_SWITCH (swtch)->priv->profiles;
+}
+
+static gint
+compare_profiles (gconstpointer a, gconstpointer b)
+{
+ return pulse_device_profile_get_priority (PULSE_DEVICE_PROFILE (b)) -
+ pulse_device_profile_get_priority (PULSE_DEVICE_PROFILE (a));
+}
+
+static gint
+compare_profile_name (gconstpointer a, gconstpointer b)
+{
+ PulseDeviceProfile *profile = PULSE_DEVICE_PROFILE (a);
+ const gchar *name = (const gchar *) b;
+
+ return strcmp (pulse_device_profile_get_name (profile), name);
+}
diff --git a/backends/pulse/pulse-device-switch.h b/backends/pulse/pulse-device-switch.h
new file mode 100644
index 0000000..50f4a68
--- /dev/null
+++ b/backends/pulse/pulse-device-switch.h
@@ -0,0 +1,77 @@
+/*
+ * 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_DEVICE_SWITCH_H
+#define PULSE_DEVICE_SWITCH_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_DEVICE_SWITCH \
+ (pulse_device_switch_get_type ())
+#define PULSE_DEVICE_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_DEVICE_SWITCH, PulseDeviceSwitch))
+#define PULSE_IS_DEVICE_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_DEVICE_SWITCH))
+#define PULSE_DEVICE_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_DEVICE_SWITCH, PulseDeviceSwitchClass))
+#define PULSE_IS_DEVICE_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_DEVICE_SWITCH))
+#define PULSE_DEVICE_SWITCH_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_DEVICE_SWITCH, PulseDeviceSwitchClass))
+
+typedef struct _PulseDeviceSwitchClass PulseDeviceSwitchClass;
+typedef struct _PulseDeviceSwitchPrivate PulseDeviceSwitchPrivate;
+
+struct _PulseDeviceSwitch
+{
+ MateMixerSwitch parent;
+
+ /*< private >*/
+ PulseDeviceSwitchPrivate *priv;
+};
+
+struct _PulseDeviceSwitchClass
+{
+ MateMixerSwitchClass parent_class;
+};
+
+GType pulse_device_switch_get_type (void) G_GNUC_CONST;
+
+PulseDeviceSwitch *pulse_device_switch_new (const gchar *name,
+ const gchar *label,
+ PulseDevice *device);
+
+PulseDevice * pulse_device_switch_get_device (PulseDeviceSwitch *swtch);
+
+void pulse_device_switch_add_profile (PulseDeviceSwitch *swtch,
+ PulseDeviceProfile *profile);
+
+void pulse_device_switch_set_active_profile (PulseDeviceSwitch *swtch,
+ PulseDeviceProfile *profile);
+
+void pulse_device_switch_set_active_profile_by_name (PulseDeviceSwitch *swtch,
+ const gchar *name);
+
+G_END_DECLS
+
+#endif /* PULSE_DEVICE_SWITCH_H */
diff --git a/backends/pulse/pulse-device.c b/backends/pulse/pulse-device.c
index 96e06c8..5403712 100644
--- a/backends/pulse/pulse-device.c
+++ b/backends/pulse/pulse-device.c
@@ -17,45 +17,40 @@
#include <string.h>
#include <glib.h>
+#include <glib/gi18n.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-device.h>
-#include <libmatemixer/matemixer-device-profile.h>
-#include <libmatemixer/matemixer-device-profile-private.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-port.h>
-#include <libmatemixer/matemixer-port-private.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
#include "pulse-device.h"
+#include "pulse-device-profile.h"
+#include "pulse-device-switch.h"
+#include "pulse-port.h"
+#include "pulse-stream.h"
struct _PulseDevicePrivate
{
- guint32 index;
- gchar *name;
- gchar *description;
- gchar *icon;
- GHashTable *ports;
- GList *ports_list;
- GHashTable *profiles;
- GList *profiles_list;
- PulseConnection *connection;
- MateMixerDeviceProfile *profile;
+ guint32 index;
+ GHashTable *ports;
+ GHashTable *streams;
+ GList *streams_list;
+ GList *switches_list;
+ PulseConnection *connection;
+ PulseDeviceSwitch *pswitch;
};
enum {
PROP_0,
- PROP_NAME,
- PROP_DESCRIPTION,
- PROP_ICON,
- PROP_ACTIVE_PROFILE,
PROP_INDEX,
- PROP_CONNECTION
+ PROP_CONNECTION,
+ N_PROPERTIES
};
-static void mate_mixer_device_interface_init (MateMixerDeviceInterface *iface);
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
static void pulse_device_class_init (PulseDeviceClass *klass);
@@ -72,60 +67,25 @@ static void pulse_device_init (PulseDevice *device);
static void pulse_device_dispose (GObject *object);
static void pulse_device_finalize (GObject *object);
-G_DEFINE_TYPE_WITH_CODE (PulseDevice, pulse_device, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_DEVICE,
- mate_mixer_device_interface_init))
+G_DEFINE_TYPE (PulseDevice, pulse_device, MATE_MIXER_TYPE_DEVICE)
-#if PA_CHECK_VERSION (5, 0, 0)
-typedef pa_card_profile_info2 _pa_card_profile_info;
-#else
-typedef pa_card_profile_info _pa_card_profile_info;
-#endif
-
-static const gchar * pulse_device_get_name (MateMixerDevice *device);
-static const gchar * pulse_device_get_description (MateMixerDevice *device);
-static const gchar * pulse_device_get_icon (MateMixerDevice *device);
+static MateMixerStream *pulse_device_get_stream (MateMixerDevice *mmd,
+ const gchar *name);
-static MateMixerPort * pulse_device_get_port (MateMixerDevice *device,
- const gchar *name);
-static MateMixerDeviceProfile *pulse_device_get_profile (MateMixerDevice *device,
- const gchar *name);
+static const GList * pulse_device_list_streams (MateMixerDevice *mmd);
+static const GList * pulse_device_list_switches (MateMixerDevice *mmd);
-static const GList * pulse_device_list_ports (MateMixerDevice *device);
-static const GList * pulse_device_list_profiles (MateMixerDevice *device);
+static void pulse_device_load (PulseDevice *device,
+ const pa_card_info *info);
-static MateMixerDeviceProfile *pulse_device_get_active_profile (MateMixerDevice *device);
-static gboolean pulse_device_set_active_profile (MateMixerDevice *device,
- MateMixerDeviceProfile *profile);
-
-static void update_port (PulseDevice *device,
- pa_card_port_info *p_info);
-static void update_profile (PulseDevice *device,
- _pa_card_profile_info *p_info);
-
-static gint compare_ports (gconstpointer a,
- gconstpointer b);
-static gint compare_profiles (gconstpointer a,
- gconstpointer b);
-
-static void
-mate_mixer_device_interface_init (MateMixerDeviceInterface *iface)
-{
- iface->get_name = pulse_device_get_name;
- iface->get_description = pulse_device_get_description;
- iface->get_icon = pulse_device_get_icon;
- iface->get_port = pulse_device_get_port;
- iface->get_profile = pulse_device_get_profile;
- iface->list_ports = pulse_device_list_ports;
- iface->list_profiles = pulse_device_list_profiles;
- iface->get_active_profile = pulse_device_get_active_profile;
- iface->set_active_profile = pulse_device_set_active_profile;
-}
+static void free_list_streams (PulseDevice *device);
+static void free_list_switches (PulseDevice *device);
static void
pulse_device_class_init (PulseDeviceClass *klass)
{
- GObjectClass *object_class;
+ GObjectClass *object_class;
+ MateMixerDeviceClass *device_class;
object_class = G_OBJECT_CLASS (klass);
object_class->dispose = pulse_device_dispose;
@@ -133,31 +93,32 @@ pulse_device_class_init (PulseDeviceClass *klass)
object_class->get_property = pulse_device_get_property;
object_class->set_property = pulse_device_set_property;
- g_object_class_install_property (object_class,
- PROP_INDEX,
- g_param_spec_uint ("index",
- "Index",
- "Device 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_object_class_override_property (object_class, PROP_ACTIVE_PROFILE, "active-profile");
+ device_class = MATE_MIXER_DEVICE_CLASS (klass);
+ device_class->get_stream = pulse_device_get_stream;
+ device_class->list_streams = pulse_device_list_streams;
+ device_class->list_switches = pulse_device_list_switches;
+
+ properties[PROP_INDEX] =
+ g_param_spec_uint ("index",
+ "Index",
+ "Index of the device",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_CONNECTION] =
+ g_param_spec_object ("connection",
+ "Connection",
+ "PulseAudio connection",
+ PULSE_TYPE_CONNECTION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
g_type_class_add_private (object_class, sizeof (PulseDevicePrivate));
}
@@ -173,18 +134,6 @@ pulse_device_get_property (GObject *object,
device = PULSE_DEVICE (object);
switch (param_id) {
- case PROP_NAME:
- g_value_set_string (value, device->priv->name);
- break;
- case PROP_DESCRIPTION:
- g_value_set_string (value, device->priv->description);
- break;
- case PROP_ICON:
- g_value_set_string (value, device->priv->icon);
- break;
- case PROP_ACTIVE_PROFILE:
- g_value_set_object (value, device->priv->profile);
- break;
case PROP_INDEX:
g_value_set_uint (value, device->priv->index);
break;
@@ -212,7 +161,6 @@ pulse_device_set_property (GObject *object,
device->priv->index = g_value_get_uint (value);
break;
case PROP_CONNECTION:
- /* Construct-only object */
device->priv->connection = g_value_dup_object (value);
break;
default:
@@ -233,10 +181,10 @@ pulse_device_init (PulseDevice *device)
g_free,
g_object_unref);
- device->priv->profiles = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- g_object_unref);
+ device->priv->streams = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
}
static void
@@ -246,20 +194,14 @@ pulse_device_dispose (GObject *object)
device = PULSE_DEVICE (object);
- if (device->priv->ports_list != NULL) {
- g_list_free_full (device->priv->ports_list, g_object_unref);
- device->priv->ports_list = NULL;
- }
g_hash_table_remove_all (device->priv->ports);
+ g_hash_table_remove_all (device->priv->streams);
- if (device->priv->profiles_list != NULL) {
- g_list_free_full (device->priv->profiles_list, g_object_unref);
- device->priv->profiles_list = NULL;
- }
- g_hash_table_remove_all (device->priv->profiles);
-
- g_clear_object (&device->priv->profile);
g_clear_object (&device->priv->connection);
+ g_clear_object (&device->priv->pswitch);
+
+ free_list_streams (device);
+ free_list_switches (device);
G_OBJECT_CLASS (pulse_device_parent_class)->dispose (object);
}
@@ -271,12 +213,8 @@ pulse_device_finalize (GObject *object)
device = PULSE_DEVICE (object);
- g_free (device->priv->name);
- g_free (device->priv->description);
- g_free (device->priv->icon);
-
- g_hash_table_destroy (device->priv->ports);
- g_hash_table_destroy (device->priv->profiles);
+ g_hash_table_unref (device->priv->ports);
+ g_hash_table_unref (device->priv->streams);
G_OBJECT_CLASS (pulse_device_parent_class)->finalize (object);
}
@@ -285,123 +223,86 @@ PulseDevice *
pulse_device_new (PulseConnection *connection, const pa_card_info *info)
{
PulseDevice *device;
+ const gchar *label;
+ const gchar *icon;
g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (info != NULL, NULL);
+ label = pa_proplist_gets (info->proplist, PA_PROP_DEVICE_DESCRIPTION);
+ if G_UNLIKELY (label == NULL)
+ label = info->name;
+
+ icon = pa_proplist_gets (info->proplist, PA_PROP_DEVICE_ICON_NAME);
+ if G_UNLIKELY (icon == NULL)
+ icon = "audio-card";
+
/* Consider the device index as unchanging parameter */
device = g_object_new (PULSE_TYPE_DEVICE,
- "connection", connection,
"index", info->index,
+ "connection", connection,
+ "name", info->name,
+ "label", label,
+ "icon", icon,
NULL);
- /* Other data may change at any time, so let's make a use of our update function */
+ pulse_device_load (device, info);
pulse_device_update (device, info);
return device;
}
-gboolean
+void
pulse_device_update (PulseDevice *device, const pa_card_info *info)
{
- MateMixerDeviceProfile *profile = NULL;
- const gchar *prop;
- guint32 i;
-
- g_return_val_if_fail (PULSE_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
-
- /* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (device));
-
- /* Name */
- if (g_strcmp0 (device->priv->name, info->name) != 0) {
- g_free (device->priv->name);
- device->priv->name = g_strdup (info->name);
-
- g_object_notify (G_OBJECT (device), "name");
- }
-
- /* Description */
- prop = pa_proplist_gets (info->proplist, PA_PROP_DEVICE_DESCRIPTION);
-
- if (G_UNLIKELY (prop == NULL))
- prop = info->name;
-
- if (g_strcmp0 (device->priv->description, prop) != 0) {
- g_free (device->priv->description);
- device->priv->description = g_strdup (prop);
-
- g_object_notify (G_OBJECT (device), "description");
- }
-
- /* Icon */
- prop = pa_proplist_gets (info->proplist, PA_PROP_DEVICE_ICON_NAME);
-
- if (G_UNLIKELY (prop == NULL))
- prop = "audio-card";
-
- if (g_strcmp0 (device->priv->icon, prop) != 0) {
- g_free (device->priv->icon);
- device->priv->icon = g_strdup (prop);
-
- g_object_notify (G_OBJECT (device), "icon");
- }
-
-#if PA_CHECK_VERSION (2, 0, 0)
- /* List of ports */
- for (i = 0; i < info->n_ports; i++) {
- update_port (device, info->ports[i]);
- }
-#endif
+ g_return_if_fail (PULSE_IS_DEVICE (device));
+ g_return_if_fail (info != NULL);
- /* List of profiles */
- for (i = 0; i < info->n_profiles; i++) {
#if PA_CHECK_VERSION (5, 0, 0)
- pa_card_profile_info2 *p_info = info->profiles2[i];
-
- /* PulseAudio 5.0 includes a new pa_card_profile_info2 which only
- * differs in the new available flag, we use it not to include profiles
- * which are unavailable */
- if (p_info->available == 0)
- continue;
+ if G_LIKELY (info->active_profile2 != NULL)
+ pulse_device_switch_set_active_profile_by_name (device->priv->pswitch,
+ info->active_profile2->name);
#else
- /* The old profile list is an array of structs, not pointers */
- pa_card_profile_info *p_info = &info->profiles[i];
+ if G_LIKELY (info->active_profile != NULL)
+ pulse_device_switch_set_active_profile_by_name (device->priv->pswitch,
+ info->active_profile->name);
#endif
- update_profile (device, p_info);
- }
-
- /* Figure out whether the currently active profile has changed */
- profile = NULL;
+}
-#if PA_CHECK_VERSION (5, 0, 0)
- if (G_LIKELY (info->active_profile2 != NULL))
- profile = g_hash_table_lookup (device->priv->profiles, info->active_profile2->name);
-#else
- if (G_LIKELY (info->active_profile != NULL))
- profile = g_hash_table_lookup (device->priv->profiles, info->active_profile->name);
-#endif
+void
+pulse_device_add_stream (PulseDevice *device, PulseStream *stream)
+{
+ const gchar *name;
- if (profile != device->priv->profile) {
- g_clear_object (&device->priv->profile);
+ g_return_if_fail (PULSE_IS_DEVICE (device));
+ g_return_if_fail (PULSE_IS_STREAM (stream));
- if (G_LIKELY (profile != NULL))
- device->priv->profile = g_object_ref (profile);
+ name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
- g_object_notify (G_OBJECT (device), "active-profile");
- }
+ free_list_streams (device);
- g_object_thaw_notify (G_OBJECT (device));
- return TRUE;
+ g_hash_table_insert (device->priv->streams, g_strdup (name), stream);
+ g_signal_emit_by_name (G_OBJECT (device),
+ "stream-added",
+ name);
}
-PulseConnection *
-pulse_device_get_connection (PulseDevice *device)
+void
+pulse_device_remove_stream (PulseDevice *device, PulseStream *stream)
{
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
+ const gchar *name;
- return device->priv->connection;
+ g_return_if_fail (PULSE_IS_DEVICE (device));
+ g_return_if_fail (PULSE_IS_STREAM (stream));
+
+ name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
+
+ free_list_streams (device);
+
+ g_hash_table_remove (device->priv->streams, name);
+ g_signal_emit_by_name (G_OBJECT (device),
+ "stream-removed",
+ name);
}
guint32
@@ -412,222 +313,130 @@ pulse_device_get_index (PulseDevice *device)
return device->priv->index;
}
-static const gchar *
-pulse_device_get_name (MateMixerDevice *device)
-{
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
-
- return PULSE_DEVICE (device)->priv->name;
-}
-
-static const gchar *
-pulse_device_get_description (MateMixerDevice *device)
-{
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
-
- return PULSE_DEVICE (device)->priv->description;
-}
-
-static const gchar *
-pulse_device_get_icon (MateMixerDevice *device)
+PulseConnection *
+pulse_device_get_connection (PulseDevice *device)
{
g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
- return PULSE_DEVICE (device)->priv->icon;
+ return device->priv->connection;
}
-static MateMixerPort *
-pulse_device_get_port (MateMixerDevice *device, const gchar *name)
+PulsePort *
+pulse_device_get_port (PulseDevice *device, const gchar *name)
{
g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
- g_return_val_if_fail (name != NULL, NULL);
- return g_hash_table_lookup (PULSE_DEVICE (device)->priv->ports, name);
+ return g_hash_table_lookup (device->priv->ports, name);
}
-static MateMixerDeviceProfile *
-pulse_device_get_profile (MateMixerDevice *device, const gchar *name)
+static MateMixerStream *
+pulse_device_get_stream (MateMixerDevice *mmd, const gchar *name)
{
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (PULSE_IS_DEVICE (mmd), NULL);
g_return_val_if_fail (name != NULL, NULL);
- return g_hash_table_lookup (PULSE_DEVICE (device)->priv->profiles, name);
+ return g_hash_table_lookup (PULSE_DEVICE (mmd)->priv->streams, name);
}
static const GList *
-pulse_device_list_ports (MateMixerDevice *device)
+pulse_device_list_streams (MateMixerDevice *mmd)
{
- PulseDevice *pulse;
-
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
-
- pulse = PULSE_DEVICE (device);
+ PulseDevice *device;
- if (pulse->priv->ports_list == NULL) {
- GList *list = g_hash_table_get_values (pulse->priv->ports);
+ g_return_val_if_fail (PULSE_IS_DEVICE (mmd), NULL);
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
+ device = PULSE_DEVICE (mmd);
- pulse->priv->ports_list = g_list_sort (list, compare_ports);
- }
+ if (device->priv->streams_list == NULL) {
+ device->priv->streams_list = g_hash_table_get_values (device->priv->streams);
+ if (device->priv->streams_list != NULL)
+ g_list_foreach (device->priv->streams_list, (GFunc) g_object_ref, NULL);
}
-
- return (const GList *) pulse->priv->ports_list;
+ return device->priv->streams_list;
}
static const GList *
-pulse_device_list_profiles (MateMixerDevice *device)
+pulse_device_list_switches (MateMixerDevice *mmd)
{
- PulseDevice *pulse;
-
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
-
- pulse = PULSE_DEVICE (device);
-
- if (pulse->priv->profiles_list == NULL) {
- GList *list = g_hash_table_get_values (pulse->priv->profiles);
-
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- pulse->priv->profiles_list = g_list_sort (list, compare_profiles);
- }
- }
+ g_return_val_if_fail (PULSE_IS_DEVICE (mmd), NULL);
- return (const GList *) pulse->priv->profiles_list;
+ return PULSE_DEVICE (mmd)->priv->switches_list;
}
-static MateMixerDeviceProfile *
-pulse_device_get_active_profile (MateMixerDevice *device)
+static void
+pulse_device_load (PulseDevice *device, const pa_card_info *info)
{
- g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
+ guint i;
- return PULSE_DEVICE (device)->priv->profile;
-}
+#if PA_CHECK_VERSION (2, 0, 0)
+ for (i = 0; i < info->n_ports; i++) {
+ PulsePort *port;
+ const gchar *name;
+ const gchar *icon;
-static gboolean
-pulse_device_set_active_profile (MateMixerDevice *device, MateMixerDeviceProfile *profile)
-{
- PulseDevice *pulse;
- const gchar *name;
- gboolean ret;
+ name = info->ports[i]->name;
+ icon = pa_proplist_gets (info->ports[i]->proplist, "device.icon_name");
- g_return_val_if_fail (PULSE_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
+ port = pulse_port_new (name,
+ info->ports[i]->description,
+ icon,
+ info->ports[i]->priority);
- pulse = PULSE_DEVICE (device);
+ g_hash_table_insert (device->priv->ports, g_strdup (name), port);
+ }
+#endif
- name = mate_mixer_device_profile_get_name (profile);
+ /* Create the device profile switch */
+ if (info->n_profiles > 0) {
+ device->priv->pswitch = pulse_device_switch_new ("profile",
+ _("Profile"),
+ device);
- /* Make sure the profile belongs to the device */
- if (g_hash_table_lookup (pulse->priv->profiles, name) == NULL) {
- g_warning ("Profile %s does not belong to device %s", name, pulse->priv->name);
- return FALSE;
+ device->priv->switches_list = g_list_prepend (NULL, g_object_ref (device->priv->pswitch));
}
- ret = pulse_connection_set_card_profile (pulse->priv->connection,
- pulse->priv->name,
- name);
- if (ret == TRUE) {
- if (pulse->priv->profile != NULL)
- g_object_unref (pulse->priv->profile);
+ for (i = 0; i < info->n_profiles; i++) {
+ PulseDeviceProfile *profile;
+
+#if PA_CHECK_VERSION (5, 0, 0)
+ pa_card_profile_info2 *p_info = info->profiles2[i];
+
+ /* PulseAudio 5.0 includes a new pa_card_profile_info2 which only
+ * differs in the new available flag, we use it not to include profiles
+ * which are unavailable */
+ if (p_info->available == 0)
+ continue;
+#else
+ /* The old profile list is an array of structs, not pointers */
+ pa_card_profile_info *p_info = &info->profiles[i];
+#endif
- pulse->priv->profile = g_object_ref (profile);
+ profile = pulse_device_profile_new (p_info->name,
+ p_info->description,
+ p_info->priority);
- g_object_notify (G_OBJECT (device), "active-profile");
+ pulse_device_switch_add_profile (device->priv->pswitch, profile);
}
- return ret;
}
static void
-update_port (PulseDevice *device, pa_card_port_info *p_info)
+free_list_streams (PulseDevice *device)
{
- MateMixerPort *port;
- MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
- const gchar *icon;
-
- icon = pa_proplist_gets (p_info->proplist, "device.icon_name");
-
- if (p_info->available == PA_PORT_AVAILABLE_YES)
- flags |= MATE_MIXER_PORT_AVAILABLE;
-
- if (p_info->direction & PA_DIRECTION_INPUT)
- flags |= MATE_MIXER_PORT_INPUT;
- if (p_info->direction & PA_DIRECTION_OUTPUT)
- flags |= MATE_MIXER_PORT_OUTPUT;
-
- port = g_hash_table_lookup (device->priv->ports, p_info->name);
-
- if (port != NULL) {
- /* Update existing port */
- _mate_mixer_port_update_description (port, p_info->description);
- _mate_mixer_port_update_icon (port, icon);
- _mate_mixer_port_update_priority (port, p_info->priority);
- _mate_mixer_port_update_flags (port, flags);
- } else {
- /* Add previously unknown port to the hash table */
- port = _mate_mixer_port_new (p_info->name,
- p_info->description,
- icon,
- p_info->priority,
- flags);
-
- g_hash_table_insert (device->priv->ports, g_strdup (p_info->name), port);
- }
+ if (device->priv->streams_list == NULL)
+ return;
+
+ g_list_free_full (device->priv->streams_list, g_object_unref);
+
+ device->priv->streams_list = NULL;
}
static void
-update_profile (PulseDevice *device, _pa_card_profile_info *p_info)
+free_list_switches (PulseDevice *device)
{
- MateMixerDeviceProfile *profile;
-
- profile = g_hash_table_lookup (device->priv->profiles, p_info->name);
-
- if (profile != NULL) {
- /* Update existing profile */
- _mate_mixer_device_profile_update_description (profile, p_info->description);
- _mate_mixer_device_profile_update_priority (profile, p_info->priority);
- _mate_mixer_device_profile_update_num_input_streams (profile, p_info->n_sources);
- _mate_mixer_device_profile_update_num_output_streams (profile, p_info->n_sinks);
- } else {
- /* Add previously unknown profile to the hash table */
- profile = _mate_mixer_device_profile_new (p_info->name,
- p_info->description,
- p_info->priority,
- p_info->n_sources,
- p_info->n_sinks);
-
- g_hash_table_insert (device->priv->profiles, g_strdup (p_info->name), profile);
- }
-}
+ if (device->priv->switches_list == NULL)
+ return;
-static gint
-compare_ports (gconstpointer a, gconstpointer b)
-{
- MateMixerPort *p1 = MATE_MIXER_PORT (a);
- MateMixerPort *p2 = MATE_MIXER_PORT (b);
-
- gint ret = (gint) (mate_mixer_port_get_priority (p2) -
- mate_mixer_port_get_priority (p1));
- if (ret != 0)
- return ret;
- else
- return strcmp (mate_mixer_port_get_name (p1),
- mate_mixer_port_get_name (p2));
-}
+ g_list_free_full (device->priv->switches_list, g_object_unref);
-static gint
-compare_profiles (gconstpointer a, gconstpointer b)
-{
- MateMixerDeviceProfile *p1 = MATE_MIXER_DEVICE_PROFILE (a);
- MateMixerDeviceProfile *p2 = MATE_MIXER_DEVICE_PROFILE (b);
-
- gint ret = (gint) (mate_mixer_device_profile_get_priority (p2) -
- mate_mixer_device_profile_get_priority (p1));
- if (ret != 0)
- return ret;
- else
- return strcmp (mate_mixer_device_profile_get_name (p1),
- mate_mixer_device_profile_get_name (p2));
+ device->priv->switches_list = NULL;
}
diff --git a/backends/pulse/pulse-device.h b/backends/pulse/pulse-device.h
index 94c331f..863330f 100644
--- a/backends/pulse/pulse-device.h
+++ b/backends/pulse/pulse-device.h
@@ -20,33 +20,33 @@
#include <glib.h>
#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
#include <pulse/pulseaudio.h>
-#include "pulse-connection.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
-#define PULSE_TYPE_DEVICE \
+#define PULSE_TYPE_DEVICE \
(pulse_device_get_type ())
-#define PULSE_DEVICE(o) \
+#define PULSE_DEVICE(o) \
(G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_DEVICE, PulseDevice))
-#define PULSE_IS_DEVICE(o) \
+#define PULSE_IS_DEVICE(o) \
(G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_DEVICE))
-#define PULSE_DEVICE_CLASS(k) \
+#define PULSE_DEVICE_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_DEVICE, PulseDeviceClass))
-#define PULSE_IS_DEVICE_CLASS(k) \
+#define PULSE_IS_DEVICE_CLASS(k) \
(G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_DEVICE))
-#define PULSE_DEVICE_GET_CLASS(o) \
+#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;
+ MateMixerDevice parent;
/*< private >*/
PulseDevicePrivate *priv;
@@ -54,20 +54,29 @@ struct _PulseDevice
struct _PulseDeviceClass
{
- GObjectClass parent;
+ MateMixerDeviceClass parent;
};
GType pulse_device_get_type (void) G_GNUC_CONST;
-PulseDevice *pulse_device_new (PulseConnection *connection,
+PulseDevice * pulse_device_new (PulseConnection *connection,
const pa_card_info *info);
-gboolean pulse_device_update (PulseDevice *device,
+void pulse_device_update (PulseDevice *device,
const pa_card_info *info);
+void pulse_device_add_stream (PulseDevice *device,
+ PulseStream *stream);
+
+void pulse_device_remove_stream (PulseDevice *device,
+ PulseStream *stream);
+
guint32 pulse_device_get_index (PulseDevice *device);
PulseConnection *pulse_device_get_connection (PulseDevice *device);
+PulsePort * pulse_device_get_port (PulseDevice *device,
+ const gchar *name);
+
G_END_DECLS
#endif /* PULSE_DEVICE_H */
diff --git a/backends/pulse/pulse-ext-stream.c b/backends/pulse/pulse-ext-stream.c
index b00e967..3e7490a 100644
--- a/backends/pulse/pulse-ext-stream.c
+++ b/backends/pulse/pulse-ext-stream.c
@@ -19,252 +19,326 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-client-stream.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include <pulse/ext-stream-restore.h>
#include "pulse-connection.h"
-#include "pulse-client-stream.h"
#include "pulse-ext-stream.h"
#include "pulse-helpers.h"
#include "pulse-stream.h"
+#include "pulse-stream-control.h"
-static void pulse_ext_stream_class_init (PulseExtStreamClass *klass);
-static void pulse_ext_stream_init (PulseExtStream *ext);
+struct _PulseExtStreamPrivate
+{
+ MateMixerAppInfo *app_info;
+ MateMixerDirection direction;
+};
-G_DEFINE_TYPE (PulseExtStream, pulse_ext_stream, PULSE_TYPE_CLIENT_STREAM);
+enum {
+ PROP_0,
+ PROP_DIRECTION
+};
-static void pulse_ext_stream_reload (PulseStream *pstream);
+static void mate_mixer_stored_control_interface_init (MateMixerStoredControlInterface *iface);
-static gboolean pulse_ext_stream_set_mute (PulseStream *pstream,
- gboolean mute);
-static gboolean pulse_ext_stream_set_volume (PulseStream *pstream,
- pa_cvolume *cvolume);
-static gboolean pulse_ext_stream_set_parent (PulseClientStream *pclient,
- PulseStream *parent);
-static gboolean pulse_ext_stream_remove (PulseClientStream *pclient);
+static void pulse_ext_stream_class_init (PulseExtStreamClass *klass);
-static void
-pulse_ext_stream_class_init (PulseExtStreamClass *klass)
-{
- PulseStreamClass *stream_class;
- PulseClientStreamClass *client_class;
+static void pulse_ext_stream_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void pulse_ext_stream_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
- stream_class = PULSE_STREAM_CLASS (klass);
+static void pulse_ext_stream_init (PulseExtStream *ext);
- stream_class->reload = pulse_ext_stream_reload;
- stream_class->set_mute = pulse_ext_stream_set_mute;
- stream_class->set_volume = pulse_ext_stream_set_volume;
+G_DEFINE_TYPE_WITH_CODE (PulseExtStream, pulse_ext_stream, PULSE_TYPE_STREAM_CONTROL,
+ G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_STORED_CONTROL,
+ mate_mixer_stored_control_interface_init))
- client_class = PULSE_CLIENT_STREAM_CLASS (klass);
+static MateMixerDirection pulse_ext_stream_get_direction (MateMixerStoredControl *mmsc);
- client_class->set_parent = pulse_ext_stream_set_parent;
- client_class->remove = pulse_ext_stream_remove;
-}
+static MateMixerAppInfo * pulse_ext_stream_get_app_info (MateMixerStreamControl *mmsc);
+
+static gboolean pulse_ext_stream_set_stream (MateMixerStreamControl *mmsc,
+ MateMixerStream *mms);
+
+static gboolean pulse_ext_stream_set_mute (PulseStreamControl *control,
+ gboolean mute);
+static gboolean pulse_ext_stream_set_volume (PulseStreamControl *control,
+ pa_cvolume *cvolume);
+
+static void fill_ext_stream_restore_info (PulseStreamControl *control,
+ pa_ext_stream_restore_info *info);
static void
-pulse_ext_stream_init (PulseExtStream *ext)
+mate_mixer_stored_control_interface_init (MateMixerStoredControlInterface *iface)
{
+ iface->get_direction = pulse_ext_stream_get_direction;
}
-PulseStream *
-pulse_ext_stream_new (PulseConnection *connection,
- const pa_ext_stream_restore_info *info,
- PulseStream *parent)
+static void
+pulse_ext_stream_class_init (PulseExtStreamClass *klass)
{
- PulseStream *ext;
+ GObjectClass *object_class;
+ MateMixerStreamControlClass *control_class;
+ PulseStreamControlClass *pulse_class;
- g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
- g_return_val_if_fail (info != NULL, NULL);
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->get_property = pulse_ext_stream_get_property;
+ object_class->set_property = pulse_ext_stream_set_property;
- ext = g_object_new (PULSE_TYPE_EXT_STREAM,
- "connection", connection,
- NULL);
+ control_class = MATE_MIXER_STREAM_CONTROL_CLASS (klass);
+ control_class->get_app_info = pulse_ext_stream_get_app_info;
+ control_class->set_stream = pulse_ext_stream_set_stream;
- /* Consider the stream name as unchanging parameter */
- pulse_stream_update_name (ext, info->name);
+ pulse_class = PULSE_STREAM_CONTROL_CLASS (klass);
+ pulse_class->set_mute = pulse_ext_stream_set_mute;
+ pulse_class->set_volume = pulse_ext_stream_set_volume;
- /* Other data may change at any time, so let's make a use of our update function */
- pulse_ext_stream_update (ext, info, parent);
+ g_object_class_override_property (object_class, PROP_DIRECTION, "direction");
- return ext;
+ g_type_class_add_private (object_class, sizeof (PulseExtStreamPrivate));
}
-gboolean
-pulse_ext_stream_update (PulseStream *pstream,
- const pa_ext_stream_restore_info *info,
- PulseStream *parent)
+static void
+pulse_ext_stream_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- MateMixerClientStreamRole role = MATE_MIXER_CLIENT_STREAM_ROLE_NONE;
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_CLIENT |
- MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_HAS_MUTE |
- MATE_MIXER_STREAM_CAN_SET_VOLUME;
- MateMixerClientStreamFlags client_flags =
- MATE_MIXER_CLIENT_STREAM_CACHED;
+ PulseExtStream *ext;
- PulseClientStream *pclient;
- gchar *suffix;
+ ext = PULSE_EXT_STREAM (object);
- g_return_val_if_fail (PULSE_IS_EXT_STREAM (pstream), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
+ switch (param_id) {
+ case PROP_DIRECTION:
+ g_value_set_enum (value, ext->priv->direction);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
- pclient = PULSE_CLIENT_STREAM (pstream);
+static void
+pulse_ext_stream_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PulseExtStream *ext;
- suffix = strchr (info->name, ':');
- if (suffix != NULL)
- suffix++;
+ ext = PULSE_EXT_STREAM (object);
- /* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (pstream));
+ switch (param_id) {
+ case PROP_DIRECTION:
+ ext->priv->direction = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_ext_stream_init (PulseExtStream *ext)
+{
+ ext->priv = G_TYPE_INSTANCE_GET_PRIVATE (ext,
+ PULSE_TYPE_EXT_STREAM,
+ PulseExtStreamPrivate);
+}
+
+PulseExtStream *
+pulse_ext_stream_new (PulseConnection *connection,
+ const pa_ext_stream_restore_info *info,
+ PulseStream *parent)
+{
+ PulseExtStream *ext;
+ gchar *suffix;
+ MateMixerDirection direction;
+ MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_MUTE_READABLE |
+ MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE;
+ MateMixerStreamControlRole role = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN;
+ MateMixerAppInfo *app_info;
+
+ MateMixerStreamControlMediaRole media_role = MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
if (g_str_has_prefix (info->name, "sink-input"))
- flags |= MATE_MIXER_STREAM_OUTPUT;
+ direction = MATE_MIXER_DIRECTION_OUTPUT;
else if (g_str_has_prefix (info->name, "source-output"))
- flags |= MATE_MIXER_STREAM_INPUT;
+ direction = MATE_MIXER_DIRECTION_INPUT;
else
- g_debug ("Unknown ext-stream %s", info->name);
+ direction = MATE_MIXER_DIRECTION_UNKNOWN;
+
+ app_info = _mate_mixer_app_info_new ();
+
+ suffix = strchr (info->name, ':');
+ if (suffix != NULL)
+ suffix++;
if (strstr (info->name, "-by-media-role:")) {
if (G_LIKELY (suffix != NULL))
- role = pulse_convert_media_role_name (suffix);
+ media_role = pulse_convert_media_role_name (suffix);
}
else if (strstr (info->name, "-by-application-name:")) {
- client_flags |= MATE_MIXER_CLIENT_STREAM_APPLICATION;
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION;
if (G_LIKELY (suffix != NULL))
- pulse_client_stream_update_app_name (pclient, suffix);
+ _mate_mixer_app_info_set_name (app_info, suffix);
}
else if (strstr (info->name, "-by-application-id:")) {
- client_flags |= MATE_MIXER_CLIENT_STREAM_APPLICATION;
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION;
if (G_LIKELY (suffix != NULL))
- pulse_client_stream_update_app_id (pclient, suffix);
+ _mate_mixer_app_info_set_id (app_info, suffix);
}
- /* Flags needed before volume */
- pulse_stream_update_flags (pstream, flags);
+ ext = g_object_new (PULSE_TYPE_EXT_STREAM,
+ "flags", flags,
+ "role", role,
+ "media-role", media_role,
+ "name", info->name,
+ "connection", connection,
+ "direction", direction,
+ "stream", parent,
+ NULL);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
- pulse_stream_update_volume (pstream, &info->volume, 0);
+ if (role == MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION)
+ ext->priv->app_info = app_info;
+ else
+ _mate_mixer_app_info_free (app_info);
- pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
+ pulse_ext_stream_update (ext, info, parent);
+ return ext;
+}
- pulse_client_stream_update_flags (pclient, client_flags);
- pulse_client_stream_update_role (pclient, role);
+void
+pulse_ext_stream_update (PulseExtStream *ext,
+ const pa_ext_stream_restore_info *info,
+ PulseStream *parent)
+{
+ g_return_if_fail (PULSE_IS_EXT_STREAM (ext));
+ g_return_if_fail (info != NULL);
- if (parent != NULL)
- pulse_client_stream_update_parent (pclient, MATE_MIXER_STREAM (parent));
- else
- pulse_client_stream_update_parent (pclient, NULL);
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (ext));
+
+ _mate_mixer_stream_control_set_mute (MATE_MIXER_STREAM_CONTROL (ext),
+ info->mute ? TRUE : FALSE);
- g_object_thaw_notify (G_OBJECT (pstream));
- return TRUE;
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (ext),
+ &info->channel_map);
+
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (ext),
+ &info->volume,
+ 0);
+
+ _mate_mixer_stream_control_set_stream (MATE_MIXER_STREAM_CONTROL (ext),
+ MATE_MIXER_STREAM (parent));
+
+ g_object_thaw_notify (G_OBJECT (ext));
}
-static void
-pulse_ext_stream_reload (PulseStream *pstream)
+static MateMixerDirection
+pulse_ext_stream_get_direction (MateMixerStoredControl *mmsc)
{
- g_return_if_fail (PULSE_IS_EXT_STREAM (pstream));
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), MATE_MIXER_DIRECTION_UNKNOWN);
- pulse_connection_load_ext_stream_info (pulse_stream_get_connection (pstream));
+ return PULSE_EXT_STREAM (mmsc)->priv->direction;
}
-static gboolean
-pulse_ext_stream_set_mute (PulseStream *pstream, gboolean mute)
+static MateMixerAppInfo *
+pulse_ext_stream_get_app_info (MateMixerStreamControl *mmsc)
{
- MateMixerStream *parent;
- const pa_channel_map *map;
- const pa_cvolume *cvolume;
- pa_ext_stream_restore_info info;
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), NULL);
- g_return_val_if_fail (PULSE_IS_EXT_STREAM (pstream), FALSE);
+ return PULSE_EXT_STREAM (mmsc)->priv->app_info;
+}
- info.name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream));
- info.mute = mute;
+static gboolean
+pulse_ext_stream_set_stream (MateMixerStreamControl *mmsc, MateMixerStream *mms)
+{
+ pa_ext_stream_restore_info info;
- map = pulse_stream_get_channel_map (pstream);
- info.channel_map = *map;
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (mmsc), FALSE);
+ g_return_val_if_fail (mms == NULL || PULSE_IS_STREAM (mms), FALSE);
- cvolume = pulse_stream_get_cvolume (pstream);
- info.volume = *cvolume;
+ fill_ext_stream_restore_info (PULSE_STREAM_CONTROL (mms), &info);
- parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (pstream));
- if (parent != NULL)
- info.device = mate_mixer_stream_get_name (parent);
+ if (mms != NULL)
+ info.device = mate_mixer_stream_get_name (mms);
else
info.device = NULL;
- return pulse_connection_write_ext_stream (pulse_stream_get_connection (pstream), &info);
+ return pulse_connection_write_ext_stream (pulse_stream_control_get_connection (PULSE_STREAM_CONTROL (mmsc)),
+ &info);
}
static gboolean
-pulse_ext_stream_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
+pulse_ext_stream_set_mute (PulseStreamControl *control, gboolean mute)
{
- MateMixerStream *parent;
- const pa_channel_map *map;
pa_ext_stream_restore_info info;
- g_return_val_if_fail (PULSE_IS_EXT_STREAM (pstream), FALSE);
- g_return_val_if_fail (cvolume != NULL, FALSE);
-
- info.name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream));
- info.mute = mate_mixer_stream_get_mute (MATE_MIXER_STREAM (pstream));
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (control), FALSE);
- map = pulse_stream_get_channel_map (pstream);
- info.channel_map = *map;
-
- parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (pstream));
- if (parent != NULL)
- info.device = mate_mixer_stream_get_name (parent);
- else
- info.device = NULL;
+ fill_ext_stream_restore_info (control, &info);
- info.volume = *cvolume;
+ info.mute = mute;
- return pulse_connection_write_ext_stream (pulse_stream_get_connection (pstream), &info);
+ return pulse_connection_write_ext_stream (pulse_stream_control_get_connection (control),
+ &info);
}
static gboolean
-pulse_ext_stream_set_parent (PulseClientStream *pclient, PulseStream *parent)
+pulse_ext_stream_set_volume (PulseStreamControl *control, pa_cvolume *cvolume)
{
- PulseStream *pstream;
- const pa_channel_map *map;
- const pa_cvolume *cvolume;
pa_ext_stream_restore_info info;
- g_return_val_if_fail (PULSE_IS_EXT_STREAM (pclient), FALSE);
- g_return_val_if_fail (PULSE_IS_STREAM (parent), FALSE);
-
- pstream = PULSE_STREAM (pclient);
-
- info.name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream));
- info.mute = mate_mixer_stream_get_mute (MATE_MIXER_STREAM (pstream));
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (control), FALSE);
+ g_return_val_if_fail (cvolume != NULL, FALSE);
- map = pulse_stream_get_channel_map (pstream);
- info.channel_map = *map;
+ fill_ext_stream_restore_info (control, &info);
- cvolume = pulse_stream_get_cvolume (pstream);
info.volume = *cvolume;
- info.device = mate_mixer_stream_get_name (MATE_MIXER_STREAM (parent));
-
- return pulse_connection_write_ext_stream (pulse_stream_get_connection (pstream), &info);
+ return pulse_connection_write_ext_stream (pulse_stream_control_get_connection (control),
+ &info);
}
-static gboolean
-pulse_ext_stream_remove (PulseClientStream *pclient)
+static void
+fill_ext_stream_restore_info (PulseStreamControl *control,
+ pa_ext_stream_restore_info *info)
{
- PulseStream *pstream;
- const gchar *name;
+ MateMixerStream *stream;
+ MateMixerStreamControl *mmsc;
+ const pa_channel_map *map;
+ const pa_cvolume *cvolume;
+
+ mmsc = MATE_MIXER_STREAM_CONTROL (control);
- g_return_val_if_fail (PULSE_IS_EXT_STREAM (pclient), FALSE);
+ info->name = mate_mixer_stream_control_get_name (mmsc);
+ info->mute = mate_mixer_stream_control_get_mute (mmsc);
- pstream = PULSE_STREAM (pclient);
- name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream));
+ map = pulse_stream_control_get_channel_map (control);
+ info->channel_map = *map;
- return pulse_connection_delete_ext_stream (pulse_stream_get_connection (pstream), name);
+ cvolume = pulse_stream_control_get_cvolume (control);
+ info->volume = *cvolume;
+
+ stream = mate_mixer_stream_control_get_stream (mmsc);
+ if (stream != NULL)
+ info->device = mate_mixer_stream_get_name (stream);
+ else
+ info->device = NULL;
}
diff --git a/backends/pulse/pulse-ext-stream.h b/backends/pulse/pulse-ext-stream.h
index e8dabb6..b667dc7 100644
--- a/backends/pulse/pulse-ext-stream.h
+++ b/backends/pulse/pulse-ext-stream.h
@@ -24,9 +24,8 @@
#include <pulse/pulseaudio.h>
#include <pulse/ext-stream-restore.h>
-#include "pulse-client-stream.h"
-#include "pulse-connection.h"
-#include "pulse-stream.h"
+#include "pulse-stream-control.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
@@ -43,28 +42,31 @@ G_BEGIN_DECLS
#define PULSE_EXT_STREAM_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_EXT_STREAM, PulseExtStreamClass))
-typedef struct _PulseExtStream PulseExtStream;
-typedef struct _PulseExtStreamClass PulseExtStreamClass;
+typedef struct _PulseExtStreamClass PulseExtStreamClass;
+typedef struct _PulseExtStreamPrivate PulseExtStreamPrivate;
struct _PulseExtStream
{
- PulseClientStream parent;
+ PulseStreamControl parent;
+
+ /*< private >*/
+ PulseExtStreamPrivate *priv;
};
struct _PulseExtStreamClass
{
- PulseClientStreamClass parent_class;
+ PulseStreamControlClass parent_class;
};
-GType pulse_ext_stream_get_type (void) G_GNUC_CONST;
+GType pulse_ext_stream_get_type (void) G_GNUC_CONST;
-PulseStream *pulse_ext_stream_new (PulseConnection *connection,
- const pa_ext_stream_restore_info *info,
- PulseStream *parent);
+PulseExtStream *pulse_ext_stream_new (PulseConnection *connection,
+ const pa_ext_stream_restore_info *info,
+ PulseStream *parent);
-gboolean pulse_ext_stream_update (PulseStream *pstream,
- const pa_ext_stream_restore_info *info,
- PulseStream *parent);
+void pulse_ext_stream_update (PulseExtStream *ext,
+ const pa_ext_stream_restore_info *info,
+ PulseStream *parent);
G_END_DECLS
diff --git a/backends/pulse/pulse-helpers.c b/backends/pulse/pulse-helpers.c
index 577f2c6..73f8cdb 100644
--- a/backends/pulse/pulse-helpers.c
+++ b/backends/pulse/pulse-helpers.c
@@ -29,6 +29,7 @@ typedef struct {
pa_channel_position_t pa_position;
} PositionMap;
+// XXX optimize
static PositionMap const position_map[] = {
{ MATE_MIXER_CHANNEL_UNKNOWN, PA_CHANNEL_POSITION_INVALID },
{ MATE_MIXER_CHANNEL_MONO, PA_CHANNEL_POSITION_MONO },
@@ -76,42 +77,42 @@ pulse_convert_position_to_pulse (MateMixerChannelPosition position)
return PA_CHANNEL_POSITION_INVALID;
}
-MateMixerClientStreamRole
+MateMixerStreamControlMediaRole
pulse_convert_media_role_name (const gchar *name)
{
if (!strcmp (name, "video")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_VIDEO;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_VIDEO;
}
else if (!strcmp (name, "music")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_MUSIC;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_MUSIC;
}
else if (!strcmp (name, "game")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_GAME;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_GAME;
}
else if (!strcmp (name, "event")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_EVENT;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_EVENT;
}
else if (!strcmp (name, "phone")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_PHONE;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_PHONE;
}
else if (!strcmp (name, "animation")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_ANIMATION;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_ANIMATION;
}
else if (!strcmp (name, "production")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_PRODUCTION;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_PRODUCTION;
}
else if (!strcmp (name, "a11y")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_A11Y;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_A11Y;
}
else if (!strcmp (name, "test")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_TEST;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_TEST;
}
else if (!strcmp (name, "abstract")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_ABSTRACT;
}
else if (!strcmp (name, "filter")) {
- return MATE_MIXER_CLIENT_STREAM_ROLE_FILTER;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_FILTER;
}
- return MATE_MIXER_CLIENT_STREAM_ROLE_NONE;
+ return MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN;
}
diff --git a/backends/pulse/pulse-helpers.h b/backends/pulse/pulse-helpers.h
index 7ccd753..667fc3c 100644
--- a/backends/pulse/pulse-helpers.h
+++ b/backends/pulse/pulse-helpers.h
@@ -19,17 +19,16 @@
#define PULSE_HELPERS_H
#include <glib.h>
-
-#include <libmatemixer/matemixer-enums.h>
+#include <libmatemixer/matemixer.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);
+MateMixerChannelPosition pulse_convert_position_from_pulse (pa_channel_position_t position);
+pa_channel_position_t pulse_convert_position_to_pulse (MateMixerChannelPosition position);
-MateMixerClientStreamRole pulse_convert_media_role_name (const gchar *name);
+MateMixerStreamControlMediaRole pulse_convert_media_role_name (const gchar *name);
G_END_DECLS
diff --git a/backends/pulse/pulse-monitor.c b/backends/pulse/pulse-monitor.c
index 3d5b4a8..915b71b 100644
--- a/backends/pulse/pulse-monitor.c
+++ b/backends/pulse/pulse-monitor.c
@@ -16,6 +16,7 @@
*/
#include <glib.h>
+#include <glib/gi18n.h>
#include <glib-object.h>
#include <pulse/pulseaudio.h>
@@ -27,7 +28,6 @@ struct _PulseMonitorPrivate
pa_context *context;
pa_proplist *proplist;
pa_stream *stream;
- gchar *name;
guint32 index_source;
guint32 index_sink_input;
gboolean enabled;
@@ -36,7 +36,6 @@ struct _PulseMonitorPrivate
enum {
PROP_0,
PROP_ENABLED,
- PROP_NAME,
PROP_INDEX_SOURCE,
PROP_INDEX_SINK_INPUT,
N_PROPERTIES
@@ -91,15 +90,6 @@ pulse_monitor_class_init (PulseMonitorClass *klass)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
- properties[PROP_NAME] =
- g_param_spec_string ("name",
- "Name",
- "Name of the monitor",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT |
- G_PARAM_STATIC_STRINGS);
-
properties[PROP_INDEX_SOURCE] =
g_param_spec_uint ("index-source",
"Index of source",
@@ -153,9 +143,6 @@ pulse_monitor_get_property (GObject *object,
case PROP_ENABLED:
g_value_set_boolean (value, monitor->priv->enabled);
break;
- case PROP_NAME:
- g_value_set_string (value, monitor->priv->name);
- break;
case PROP_INDEX_SOURCE:
g_value_set_uint (value, monitor->priv->index_source);
break;
@@ -179,9 +166,6 @@ pulse_monitor_set_property (GObject *object,
monitor = PULSE_MONITOR (object);
switch (param_id) {
- case PROP_NAME:
- pulse_monitor_set_name (monitor, g_value_get_string (value));
- break;
case PROP_INDEX_SOURCE:
monitor->priv->index_source = g_value_get_uint (value);
break;
@@ -218,15 +202,12 @@ pulse_monitor_finalize (GObject *object)
pa_context_unref (monitor->priv->context);
pa_proplist_free (monitor->priv->proplist);
- g_free (monitor->priv->name);
-
G_OBJECT_CLASS (pulse_monitor_parent_class)->finalize (object);
}
PulseMonitor *
pulse_monitor_new (pa_context *context,
pa_proplist *proplist,
- const gchar *name,
guint32 index_source,
guint32 index_sink_input)
{
@@ -236,7 +217,6 @@ pulse_monitor_new (pa_context *context,
g_return_val_if_fail (proplist != NULL, NULL);
monitor = g_object_new (PULSE_TYPE_MONITOR,
- "name", name,
"index-source", index_source,
"index-sink-input", index_sink_input,
NULL);
@@ -280,34 +260,11 @@ pulse_monitor_set_enabled (PulseMonitor *monitor, gboolean enabled)
return TRUE;
}
-const gchar *
-pulse_monitor_get_name (PulseMonitor *monitor)
-{
- g_return_val_if_fail (PULSE_IS_MONITOR (monitor), NULL);
-
- return monitor->priv->name;
-}
-
-gboolean
-pulse_monitor_set_name (PulseMonitor *monitor, const gchar *name)
-{
- g_return_val_if_fail (PULSE_IS_MONITOR (monitor), FALSE);
-
- if (g_strcmp0 (name, monitor->priv->name) != 0) {
- g_free (monitor->priv->name);
- monitor->priv->name = g_strdup (name);
-
- g_object_notify_by_pspec (G_OBJECT (monitor), properties[PROP_NAME]);
- }
- return TRUE;
-}
-
static gboolean
stream_connect (PulseMonitor *monitor)
{
pa_sample_spec spec;
pa_buffer_attr attr;
- const gchar *name;
gchar *idx;
int ret;
@@ -320,14 +277,9 @@ stream_connect (PulseMonitor *monitor)
spec.format = PA_SAMPLE_FLOAT32;
spec.rate = 25;
- if (monitor->priv->name != NULL)
- name = monitor->priv->name;
- else
- name = "Peak detect";
-
monitor->priv->stream =
pa_stream_new_with_proplist (monitor->priv->context,
- name,
+ _("Peak detect"),
&spec,
NULL,
monitor->priv->proplist);
diff --git a/backends/pulse/pulse-monitor.h b/backends/pulse/pulse-monitor.h
index 41147f5..e371ec3 100644
--- a/backends/pulse/pulse-monitor.h
+++ b/backends/pulse/pulse-monitor.h
@@ -23,6 +23,8 @@
#include <pulse/pulseaudio.h>
+#include "pulse-types.h"
+
G_BEGIN_DECLS
#define PULSE_TYPE_MONITOR \
@@ -38,7 +40,6 @@ G_BEGIN_DECLS
#define PULSE_MONITOR_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_MONITOR, PulseMonitorClass))
-typedef struct _PulseMonitor PulseMonitor;
typedef struct _PulseMonitorClass PulseMonitorClass;
typedef struct _PulseMonitorPrivate PulseMonitorPrivate;
@@ -54,7 +55,7 @@ struct _PulseMonitorClass
{
GObjectClass parent_class;
- /* Signals */
+ /*< private >*/
void (*value) (PulseMonitor *monitor,
gdouble value);
};
@@ -63,7 +64,6 @@ GType pulse_monitor_get_type (void) G_GNUC_CONST;
PulseMonitor *pulse_monitor_new (pa_context *context,
pa_proplist *proplist,
- const gchar *name,
guint32 index_source,
guint32 index_sink_input);
@@ -71,10 +71,6 @@ gboolean pulse_monitor_get_enabled (PulseMonitor *monitor);
gboolean pulse_monitor_set_enabled (PulseMonitor *monitor,
gboolean enabled);
-const gchar * pulse_monitor_get_name (PulseMonitor *monitor);
-gboolean pulse_monitor_set_name (PulseMonitor *monitor,
- const gchar *name);
-
G_END_DECLS
#endif /* PULSE_MONITOR_H */
diff --git a/backends/pulse/pulse-port-switch.c b/backends/pulse/pulse-port-switch.c
new file mode 100644
index 0000000..08f1543
--- /dev/null
+++ b/backends/pulse/pulse-port-switch.c
@@ -0,0 +1,241 @@
+/*
+ * 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.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "pulse-connection.h"
+#include "pulse-port.h"
+#include "pulse-port-switch.h"
+#include "pulse-stream.h"
+
+struct _PulsePortSwitchPrivate
+{
+ GList *ports;
+ PulseStream *stream;
+};
+
+enum {
+ PROP_0,
+ PROP_STREAM,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+static void pulse_port_switch_class_init (PulsePortSwitchClass *klass);
+
+static void pulse_port_switch_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void pulse_port_switch_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void pulse_port_switch_init (PulsePortSwitch *swtch);
+static void pulse_port_switch_dispose (GObject *object);
+
+G_DEFINE_ABSTRACT_TYPE (PulsePortSwitch, pulse_port_switch, MATE_MIXER_TYPE_SWITCH)
+
+static gboolean pulse_port_switch_set_active_option (MateMixerSwitch *mms,
+ MateMixerSwitchOption *mmso);
+
+static const GList *pulse_port_switch_list_options (MateMixerSwitch *mms);
+
+static gint compare_ports (gconstpointer a,
+ gconstpointer b);
+static gint compare_port_name (gconstpointer a,
+ gconstpointer b);
+
+static void
+pulse_port_switch_class_init (PulsePortSwitchClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerSwitchClass *switch_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_port_switch_dispose;
+ object_class->get_property = pulse_port_switch_get_property;
+ object_class->set_property = pulse_port_switch_set_property;
+
+ switch_class = MATE_MIXER_SWITCH_CLASS (klass);
+ switch_class->set_active_option = pulse_port_switch_set_active_option;
+ switch_class->list_options = pulse_port_switch_list_options;
+
+ properties[PROP_STREAM] =
+ g_param_spec_object ("stream",
+ "Stream",
+ "PulseAudio stream",
+ PULSE_TYPE_STREAM,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof (PulsePortSwitchPrivate));
+}
+
+static void
+pulse_port_switch_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PulsePortSwitch *swtch;
+
+ swtch = PULSE_PORT_SWITCH (object);
+
+ switch (param_id) {
+ case PROP_STREAM:
+ g_value_set_object (value, swtch->priv->stream);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_port_switch_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PulsePortSwitch *swtch;
+
+ swtch = PULSE_PORT_SWITCH (object);
+
+ switch (param_id) {
+ case PROP_STREAM:
+ /* Construct-only object */
+ swtch->priv->stream = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_port_switch_init (PulsePortSwitch *swtch)
+{
+ swtch->priv = G_TYPE_INSTANCE_GET_PRIVATE (swtch,
+ PULSE_TYPE_PORT_SWITCH,
+ PulsePortSwitchPrivate);
+}
+
+static void
+pulse_port_switch_dispose (GObject *object)
+{
+ PulsePortSwitch *swtch;
+
+ swtch = PULSE_PORT_SWITCH (object);
+
+ g_clear_object (&swtch->priv->stream);
+
+ G_OBJECT_CLASS (pulse_port_switch_parent_class)->dispose (object);
+}
+
+PulseStream *
+pulse_port_switch_get_stream (PulsePortSwitch *swtch)
+{
+ g_return_val_if_fail (PULSE_IS_PORT_SWITCH (swtch), NULL);
+
+ return swtch->priv->stream;
+}
+
+void
+pulse_port_switch_add_port (PulsePortSwitch *swtch, PulsePort *port)
+{
+ g_return_if_fail (PULSE_IS_PORT_SWITCH (swtch));
+ g_return_if_fail (PULSE_IS_PORT (port));
+
+ swtch->priv->ports = g_list_insert_sorted (swtch->priv->ports,
+ port,
+ compare_ports);
+}
+
+void
+pulse_port_switch_set_active_port (PulsePortSwitch *swtch, PulsePort *port)
+{
+ g_return_if_fail (PULSE_IS_PORT_SWITCH (swtch));
+ g_return_if_fail (PULSE_IS_PORT (port));
+
+ _mate_mixer_switch_set_active_option (MATE_MIXER_SWITCH (swtch),
+ MATE_MIXER_SWITCH_OPTION (port));
+}
+
+void
+pulse_port_switch_set_active_port_by_name (PulsePortSwitch *swtch, const gchar *name)
+{
+ GList *item;
+
+ g_return_if_fail (PULSE_IS_PORT_SWITCH (swtch));
+ g_return_if_fail (name != NULL);
+
+ item = g_list_find_custom (swtch->priv->ports, name, compare_port_name);
+ if G_UNLIKELY (item == NULL) {
+ g_debug ("Invalid switch port name %s", name);
+ return;
+ }
+ pulse_port_switch_set_active_port (swtch, PULSE_PORT (item->data));
+}
+
+static gboolean
+pulse_port_switch_set_active_option (MateMixerSwitch *mms, MateMixerSwitchOption *mmso)
+{
+ PulsePortSwitchClass *klass;
+
+ g_return_val_if_fail (PULSE_IS_PORT_SWITCH (mms), FALSE);
+ g_return_val_if_fail (PULSE_IS_PORT (mmso), FALSE);
+
+ klass = PULSE_PORT_SWITCH_GET_CLASS (PULSE_PORT_SWITCH (mms));
+
+ return klass->set_active_port (PULSE_PORT_SWITCH (mms),
+ PULSE_PORT (mmso));
+}
+
+static const GList *
+pulse_port_switch_list_options (MateMixerSwitch *swtch)
+{
+ g_return_val_if_fail (PULSE_IS_PORT_SWITCH (swtch), NULL);
+
+ return PULSE_PORT_SWITCH (swtch)->priv->ports;
+}
+
+static gint
+compare_ports (gconstpointer a, gconstpointer b)
+{
+ return pulse_port_get_priority (PULSE_PORT (b)) -
+ pulse_port_get_priority (PULSE_PORT (a));
+}
+
+static gint
+compare_port_name (gconstpointer a, gconstpointer b)
+{
+ PulsePort *port = PULSE_PORT (a);
+ const gchar *name = (const gchar *) b;
+
+ return strcmp (pulse_port_get_name (port), name);
+}
diff --git a/backends/pulse/pulse-port-switch.h b/backends/pulse/pulse-port-switch.h
new file mode 100644
index 0000000..6ccef38
--- /dev/null
+++ b/backends/pulse/pulse-port-switch.h
@@ -0,0 +1,77 @@
+/*
+ * 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_PORT_SWITCH_H
+#define PULSE_PORT_SWITCH_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_PORT_SWITCH \
+ (pulse_port_switch_get_type ())
+#define PULSE_PORT_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_PORT_SWITCH, PulsePortSwitch))
+#define PULSE_IS_PORT_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_PORT_SWITCH))
+#define PULSE_PORT_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_PORT_SWITCH, PulsePortSwitchClass))
+#define PULSE_IS_PORT_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_PORT_SWITCH))
+#define PULSE_PORT_SWITCH_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_PORT_SWITCH, PulsePortSwitchClass))
+
+typedef struct _PulsePortSwitchClass PulsePortSwitchClass;
+typedef struct _PulsePortSwitchPrivate PulsePortSwitchPrivate;
+
+struct _PulsePortSwitch
+{
+ MateMixerSwitch parent;
+
+ /*< private >*/
+ PulsePortSwitchPrivate *priv;
+};
+
+struct _PulsePortSwitchClass
+{
+ MateMixerSwitchClass parent_class;
+
+ /*< private >*/
+ gboolean (*set_active_port) (PulsePortSwitch *swtch,
+ PulsePort *port);
+};
+
+GType pulse_port_switch_get_type (void) G_GNUC_CONST;
+
+PulseStream *pulse_port_switch_get_stream (PulsePortSwitch *swtch);
+
+void pulse_port_switch_add_port (PulsePortSwitch *swtch,
+ PulsePort *port);
+
+void pulse_port_switch_set_active_port (PulsePortSwitch *swtch,
+ PulsePort *port);
+
+void pulse_port_switch_set_active_port_by_name (PulsePortSwitch *swtch,
+ const gchar *name);
+
+G_END_DECLS
+
+#endif /* PULSE_PORT_SWITCH_H */
diff --git a/backends/pulse/pulse-port.c b/backends/pulse/pulse-port.c
new file mode 100644
index 0000000..f427448
--- /dev/null
+++ b/backends/pulse/pulse-port.c
@@ -0,0 +1,89 @@
+/*
+ * 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.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-connection.h"
+#include "pulse-port.h"
+
+struct _PulsePortPrivate
+{
+ guint priority;
+};
+
+static void pulse_port_class_init (PulsePortClass *klass);
+static void pulse_port_init (PulsePort *port);
+
+G_DEFINE_TYPE (PulsePort, pulse_port, MATE_MIXER_TYPE_SWITCH_OPTION)
+
+static void
+pulse_port_class_init (PulsePortClass *klass)
+{
+ g_type_class_add_private (klass, sizeof (PulsePortPrivate));
+}
+
+static void
+pulse_port_init (PulsePort *port)
+{
+ port->priv = G_TYPE_INSTANCE_GET_PRIVATE (port,
+ PULSE_TYPE_PORT,
+ PulsePortPrivate);
+}
+
+PulsePort *
+pulse_port_new (const gchar *name,
+ const gchar *label,
+ const gchar *icon,
+ guint priority)
+{
+ PulsePort *port;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (label != NULL, NULL);
+
+ port = g_object_new (PULSE_TYPE_PORT,
+ "name", name,
+ "label", label,
+ "icon", icon,
+ NULL);
+
+ port->priv->priority = priority;
+ return port;
+}
+
+const gchar *
+pulse_port_get_name (PulsePort *port)
+{
+ g_return_val_if_fail (PULSE_IS_PORT (port), NULL);
+
+ return mate_mixer_switch_option_get_name (MATE_MIXER_SWITCH_OPTION (port));
+}
+
+guint
+pulse_port_get_priority (PulsePort *port)
+{
+ g_return_val_if_fail (PULSE_IS_PORT (port), 0);
+
+ return port->priv->priority;
+}
diff --git a/backends/pulse/pulse-port.h b/backends/pulse/pulse-port.h
new file mode 100644
index 0000000..241fa2d
--- /dev/null
+++ b/backends/pulse/pulse-port.h
@@ -0,0 +1,70 @@
+/*
+ * 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_PORT_H
+#define PULSE_PORT_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_PORT \
+ (pulse_port_get_type ())
+#define PULSE_PORT(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_PORT, PulsePort))
+#define PULSE_IS_PORT(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_PORT))
+#define PULSE_PORT_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_PORT, PulsePortClass))
+#define PULSE_IS_PORT_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_PORT))
+#define PULSE_PORT_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_IS_PORT, PulsePortClass))
+
+typedef struct _PulsePortClass PulsePortClass;
+typedef struct _PulsePortPrivate PulsePortPrivate;
+
+struct _PulsePort
+{
+ MateMixerSwitchOption parent;
+
+ /*< private >*/
+ PulsePortPrivate *priv;
+};
+
+struct _PulsePortClass
+{
+ MateMixerSwitchOptionClass parent;
+};
+
+GType pulse_port_get_type (void) G_GNUC_CONST;
+
+PulsePort * pulse_port_new (const gchar *name,
+ const gchar *label,
+ const gchar *icon,
+ guint priority);
+
+const gchar *pulse_port_get_name (PulsePort *port);
+guint pulse_port_get_priority (PulsePort *port);
+
+G_END_DECLS
+
+#endif /* PULSE_PORT_H */
diff --git a/backends/pulse/pulse-sink-control.c b/backends/pulse/pulse-sink-control.c
new file mode 100644
index 0000000..500cef0
--- /dev/null
+++ b/backends/pulse/pulse-sink-control.c
@@ -0,0 +1,161 @@
+/*
+ * 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.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-connection.h"
+#include "pulse-monitor.h"
+#include "pulse-stream-control.h"
+#include "pulse-sink.h"
+#include "pulse-sink-control.h"
+
+static void pulse_sink_control_class_init (PulseSinkControlClass *klass);
+static void pulse_sink_control_init (PulseSinkControl *control);
+
+G_DEFINE_TYPE (PulseSinkControl, pulse_sink_control, PULSE_TYPE_STREAM_CONTROL);
+
+static gboolean pulse_sink_control_set_mute (PulseStreamControl *psc,
+ gboolean mute);
+static gboolean pulse_sink_control_set_volume (PulseStreamControl *psc,
+ pa_cvolume *cvolume);
+static PulseMonitor *pulse_sink_control_create_monitor (PulseStreamControl *psc);
+
+static void
+pulse_sink_control_class_init (PulseSinkControlClass *klass)
+{
+ PulseStreamControlClass *control_class;
+
+ control_class = PULSE_STREAM_CONTROL_CLASS (klass);
+ control_class->set_mute = pulse_sink_control_set_mute;
+ control_class->set_volume = pulse_sink_control_set_volume;
+ control_class->create_monitor = pulse_sink_control_create_monitor;
+}
+
+static void
+pulse_sink_control_init (PulseSinkControl *control)
+{
+}
+
+PulseSinkControl *
+pulse_sink_control_new (PulseSink *sink,
+ const pa_sink_info *info)
+{
+ PulseSinkControl *control;
+ MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_MUTE_READABLE |
+ MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE;
+ MateMixerStreamControlRole role;
+ guint32 index;
+
+ g_return_val_if_fail (PULSE_IS_SINK (sink), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (info->active_port != NULL)
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_PORT;
+ else
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_MASTER;
+
+ /* Build the flag list */
+ if (info->flags & PA_SINK_DECIBEL_VOLUME)
+ flags |= MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
+
+ index = pulse_sink_get_index_monitor (sink);
+ if (index != PA_INVALID_INDEX)
+ flags |= MATE_MIXER_STREAM_CONTROL_HAS_MONITOR;
+
+ control = g_object_new (PULSE_TYPE_SINK_CONTROL,
+ "name", info->name,
+ "label", info->description,
+ "flags", flags,
+ "role", role,
+ "stream", sink,
+ NULL);
+
+ pulse_sink_control_update (control, info);
+ return control;
+}
+
+void
+pulse_sink_control_update (PulseSinkControl *control, const pa_sink_info *info)
+{
+ g_return_if_fail (PULSE_IS_SINK_CONTROL (control));
+ g_return_if_fail (info != NULL);
+
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (control));
+
+ _mate_mixer_stream_control_set_mute (MATE_MIXER_STREAM_CONTROL (control),
+ info->mute ? TRUE : FALSE);
+
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (control),
+ &info->channel_map);
+
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (control),
+ &info->volume,
+ info->base_volume);
+
+ g_object_thaw_notify (G_OBJECT (control));
+}
+
+static gboolean
+pulse_sink_control_set_mute (PulseStreamControl *psc, gboolean mute)
+{
+ g_return_val_if_fail (PULSE_IS_SINK_CONTROL (psc), FALSE);
+
+ return pulse_connection_set_sink_mute (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ PULSE_STREAM_CONTROL_GET_STREAM_INDEX (psc),
+ mute);
+}
+
+static gboolean
+pulse_sink_control_set_volume (PulseStreamControl *psc, pa_cvolume *cvolume)
+{
+ g_return_val_if_fail (PULSE_IS_SINK_CONTROL (psc), FALSE);
+ g_return_val_if_fail (cvolume != NULL, FALSE);
+
+ return pulse_connection_set_sink_volume (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ PULSE_STREAM_CONTROL_GET_STREAM_INDEX (psc),
+ cvolume);
+}
+
+static PulseMonitor *
+pulse_sink_control_create_monitor (PulseStreamControl *psc)
+{
+ PulseSink *sink;
+ guint32 index;
+
+ g_return_val_if_fail (PULSE_IS_SINK_CONTROL (psc), NULL);
+
+ sink = PULSE_SINK (mate_mixer_stream_control_get_stream (MATE_MIXER_STREAM_CONTROL (psc)));
+
+ index = pulse_sink_get_index_monitor (sink);
+ if G_UNLIKELY (index == PA_INVALID_INDEX) {
+ g_debug ("Monitor of stream control %s is not available",
+ mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (psc)));
+ return NULL;
+ }
+
+ return pulse_connection_create_monitor (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ index,
+ PA_INVALID_INDEX);
+}
diff --git a/backends/pulse/pulse-sink-control.h b/backends/pulse/pulse-sink-control.h
new file mode 100644
index 0000000..e9570f4
--- /dev/null
+++ b/backends/pulse/pulse-sink-control.h
@@ -0,0 +1,67 @@
+/*
+ * 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_CONTROL_H
+#define PULSE_SINK_CONTROL_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-stream-control.h"
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_SINK_CONTROL \
+ (pulse_sink_control_get_type ())
+#define PULSE_SINK_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SINK_CONTROL, PulseSinkControl))
+#define PULSE_IS_SINK_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SINK_CONTROL))
+#define PULSE_SINK_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SINK_CONTROL, PulseSinkControlClass))
+#define PULSE_IS_SINK_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SINK_CONTROL))
+#define PULSE_SINK_CONTROL_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SINK_CONTROL, PulseSinkControlClass))
+
+typedef struct _PulseSinkControlClass PulseSinkControlClass;
+typedef struct _PulseSinkControlPrivate PulseSinkControlPrivate;
+
+struct _PulseSinkControl
+{
+ PulseStreamControl parent;
+};
+
+struct _PulseSinkControlClass
+{
+ PulseStreamControlClass parent_class;
+};
+
+GType pulse_sink_control_get_type (void) G_GNUC_CONST;
+
+PulseSinkControl *pulse_sink_control_new (PulseSink *sink,
+ const pa_sink_info *info);
+
+void pulse_sink_control_update (PulseSinkControl *control,
+ const pa_sink_info *info);
+
+G_END_DECLS
+
+#endif /* PULSE_SINK_CONTROL_H */
diff --git a/backends/pulse/pulse-sink-input.c b/backends/pulse/pulse-sink-input.c
index 1d5f9c2..eab85b8 100644
--- a/backends/pulse/pulse-sink-input.c
+++ b/backends/pulse/pulse-sink-input.c
@@ -15,57 +15,41 @@
* 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-client-stream.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
-#include "pulse-client-stream.h"
#include "pulse-helpers.h"
#include "pulse-monitor.h"
#include "pulse-sink.h"
#include "pulse-sink-input.h"
#include "pulse-stream.h"
+#include "pulse-stream-control.h"
static void pulse_sink_input_class_init (PulseSinkInputClass *klass);
static void pulse_sink_input_init (PulseSinkInput *input);
-G_DEFINE_TYPE (PulseSinkInput, pulse_sink_input, PULSE_TYPE_CLIENT_STREAM);
-
-static void pulse_sink_input_reload (PulseStream *pstream);
+G_DEFINE_TYPE (PulseSinkInput, pulse_sink_input, PULSE_TYPE_STREAM_CONTROL);
-static gboolean pulse_sink_input_set_mute (PulseStream *pstream,
- gboolean mute);
-static gboolean pulse_sink_input_set_volume (PulseStream *pstream,
- pa_cvolume *cvolume);
-static gboolean pulse_sink_input_set_parent (PulseClientStream *pclient,
- PulseStream *parent);
-static gboolean pulse_sink_input_remove (PulseClientStream *pclient);
-static PulseMonitor *pulse_sink_input_create_monitor (PulseStream *pstream);
+static gboolean pulse_sink_input_set_mute (PulseStreamControl *psc,
+ gboolean mute);
+static gboolean pulse_sink_input_set_volume (PulseStreamControl *psc,
+ pa_cvolume *cvolume);
+static PulseMonitor *pulse_sink_input_create_monitor (PulseStreamControl *psc);
static void
pulse_sink_input_class_init (PulseSinkInputClass *klass)
{
- PulseStreamClass *stream_class;
- PulseClientStreamClass *client_class;
-
- stream_class = PULSE_STREAM_CLASS (klass);
+ PulseStreamControlClass *control_class;
- stream_class->reload = pulse_sink_input_reload;
- stream_class->set_mute = pulse_sink_input_set_mute;
- stream_class->set_volume = pulse_sink_input_set_volume;
- stream_class->create_monitor = pulse_sink_input_create_monitor;
-
- client_class = PULSE_CLIENT_STREAM_CLASS (klass);
-
- client_class->set_parent = pulse_sink_input_set_parent;
- client_class->remove = pulse_sink_input_remove;
+ control_class = PULSE_STREAM_CONTROL_CLASS (klass);
+ control_class->set_mute = pulse_sink_input_set_mute;
+ control_class->set_volume = pulse_sink_input_set_volume;
+ control_class->create_monitor = pulse_sink_input_create_monitor;
}
static void
@@ -73,230 +57,171 @@ pulse_sink_input_init (PulseSinkInput *input)
{
}
-PulseStream *
-pulse_sink_input_new (PulseConnection *connection,
- const pa_sink_input_info *info,
- PulseStream *parent)
+PulseSinkInput *
+pulse_sink_input_new (PulseSink *sink, const pa_sink_input_info *info)
{
- PulseSinkInput *input;
+ PulseSinkInput *input;
+ gchar *name;
+ const gchar *prop;
+ const gchar *label = NULL;
+ MateMixerAppInfo *app_info = NULL;
- g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
- g_return_val_if_fail (info != NULL, NULL);
+ MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_MUTE_READABLE |
+ MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_MONITOR;
+ MateMixerStreamControlRole role = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN;
- /* Consider the sink input index as unchanging parameter */
- input = g_object_new (PULSE_TYPE_SINK_INPUT,
- "connection", connection,
- "index", info->index,
- NULL);
+ MateMixerStreamControlMediaRole media_role = MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN;
- /* 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, parent);
-
- return PULSE_STREAM (input);
-}
-
-gboolean
-pulse_sink_input_update (PulseStream *pstream,
- const pa_sink_input_info *info,
- PulseStream *parent)
-{
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_OUTPUT |
- MATE_MIXER_STREAM_CLIENT |
- MATE_MIXER_STREAM_HAS_MUTE |
- MATE_MIXER_STREAM_HAS_MONITOR;
- PulseClientStream *pclient;
- const gchar *prop;
- const gchar *description = NULL;
- gchar *name;
-
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (pstream), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
-
- pclient = PULSE_CLIENT_STREAM (pstream);
-
- /* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (pstream));
+ g_return_val_if_fail (PULSE_IS_SINK (sink), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
/* Many mixer applications query the Pulse client list and use the client
* name here, but we use the name only as an identifier, so let's avoid
* this unnecessary overhead and use a custom name.
* Also make sure to make the name unique by including the PulseAudio index. */
- name = g_strdup_printf ("pulse-stream-client-output-%lu", (gulong) info->index);
-
- pulse_stream_update_name (pstream, name);
- g_free (name);
-
- prop = pa_proplist_gets (info->proplist, PA_PROP_MEDIA_ROLE);
- if (prop != NULL) {
- MateMixerClientStreamRole role = pulse_convert_media_role_name (prop);
-
- if (role == MATE_MIXER_CLIENT_STREAM_ROLE_EVENT) {
- /* The event description seems to provide much better readable
- * description for event streams */
- prop = pa_proplist_gets (info->proplist, PA_PROP_EVENT_DESCRIPTION);
-
- if (G_LIKELY (prop != NULL))
- description = prop;
- }
- pulse_client_stream_update_role (pclient, role);
- } else
- pulse_client_stream_update_role (pclient, MATE_MIXER_CLIENT_STREAM_ROLE_NONE);
-
- if (description == NULL)
- description = info->name;
-
- pulse_stream_update_description (pstream, description);
- pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
-
- if (info->client != PA_INVALID_INDEX)
- pulse_client_stream_update_flags (pclient, MATE_MIXER_CLIENT_STREAM_APPLICATION);
- else
- pulse_client_stream_update_flags (pclient, MATE_MIXER_CLIENT_STREAM_NO_FLAGS);
-
- if (G_LIKELY (parent != NULL)) {
- if (pulse_sink_get_monitor_index (parent) != PA_INVALID_INDEX)
- flags |= MATE_MIXER_STREAM_HAS_MONITOR;
-
- pulse_client_stream_update_parent (pclient, MATE_MIXER_STREAM (parent));
- } else
- pulse_client_stream_update_parent (pclient, NULL);
+ name = g_strdup_printf ("pulse-output-control-%lu", (gulong) info->index);
#if PA_CHECK_VERSION(1, 0, 0)
if (info->has_volume) {
flags |=
- MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME;
+ MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
if (info->volume_writable)
- flags |= MATE_MIXER_STREAM_CAN_SET_VOLUME;
+ flags |= MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE;
}
-
- /* Flags needed before volume */
- pulse_stream_update_flags (pstream, flags);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
-
- if (info->has_volume)
- pulse_stream_update_volume (pstream, &info->volume, 0);
- else
- pulse_stream_update_volume (pstream, NULL, 0);
#else
/* Pre-1.0 PulseAudio does not include the has_volume and volume_writable
* fields, but does include the volume info, so let's give it a try */
flags |=
- MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME |
- MATE_MIXER_STREAM_CAN_SET_VOLUME;
+ MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
+#endif
- /* Flags needed before volume */
- pulse_stream_update_flags (pstream, flags);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
+ if (info->client != PA_INVALID_INDEX) {
+ app_info = _mate_mixer_app_info_new ();
- pulse_stream_update_volume (pstream, &info->volume, 0);
-#endif
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION;
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_NAME);
- if (prop != NULL)
- pulse_client_stream_update_app_name (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_NAME);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_name (app_info, prop);
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ID);
- if (prop != NULL)
- pulse_client_stream_update_app_id (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ID);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_id (app_info, prop);
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_VERSION);
- if (prop != NULL)
- pulse_client_stream_update_app_version (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_VERSION);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_version (app_info, prop);
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ICON_NAME);
- if (prop != NULL)
- pulse_client_stream_update_app_icon (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ICON_NAME);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_icon (app_info, prop);
+ }
- // XXX needs to fix monitor if parent changes
+ prop = pa_proplist_gets (info->proplist, PA_PROP_MEDIA_ROLE);
+ if (prop != NULL) {
+ media_role = pulse_convert_media_role_name (prop);
- g_object_thaw_notify (G_OBJECT (pstream));
- return TRUE;
-}
+ if (media_role == MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_EVENT) {
+ /* The event description seems to provide much better readable
+ * description for event streams */
+ prop = pa_proplist_gets (info->proplist, PA_PROP_EVENT_DESCRIPTION);
+ if (prop != NULL)
+ label = prop;
+ }
+ }
-static void
-pulse_sink_input_reload (PulseStream *pstream)
-{
- g_return_if_fail (PULSE_IS_SINK_INPUT (pstream));
+ if (label == NULL)
+ label = info->name;
- pulse_connection_load_sink_input_info (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream));
-}
+ input = g_object_new (PULSE_TYPE_SINK_INPUT,
+ "name", name,
+ "label", label,
+ "flags", flags,
+ "role", role,
+ "media-role", media_role,
+ "index", info->index,
+ "stream", sink,
+ NULL);
+ g_free (name);
-static gboolean
-pulse_sink_input_set_mute (PulseStream *pstream, gboolean mute)
-{
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (pstream), FALSE);
+ if (app_info != NULL)
+ pulse_stream_control_set_app_info (PULSE_STREAM_CONTROL (input), app_info);
- return pulse_connection_set_sink_input_mute (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- mute);
+ pulse_sink_input_update (input, info);
+ return input;
}
-static gboolean
-pulse_sink_input_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
+void
+pulse_sink_input_update (PulseSinkInput *input, const pa_sink_input_info *info)
{
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (pstream), FALSE);
- g_return_val_if_fail (cvolume != NULL, FALSE);
+ g_return_if_fail (PULSE_IS_SINK_INPUT (input));
+ g_return_if_fail (info != NULL);
- return pulse_connection_set_sink_input_volume (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- cvolume);
-}
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (input));
-static gboolean
-pulse_sink_input_set_parent (PulseClientStream *pclient, PulseStream *parent)
-{
- PulseStream *pstream;
+ _mate_mixer_stream_control_set_mute (MATE_MIXER_STREAM_CONTROL (input),
+ info->mute ? TRUE : FALSE);
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (pclient), FALSE);
+#if PA_CHECK_VERSION(1, 0, 0)
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (input), &info->channel_map);
- pstream = PULSE_STREAM (pclient);
+ if (info->has_volume)
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (input), &info->volume, 0);
+ else
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (input), NULL, 0);
+#else
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (input), &info->channel_map);
+ pulse_stream_control_set_volume (PULSE_STREAM_CONTROL (input), &info->volume, 0);
+#endif
- return pulse_connection_move_sink_input (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- pulse_stream_get_index (parent));
+ g_object_thaw_notify (G_OBJECT (input));
}
static gboolean
-pulse_sink_input_remove (PulseClientStream *pclient)
+pulse_sink_input_set_mute (PulseStreamControl *psc, gboolean mute)
{
- PulseStream *pstream;
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (psc), FALSE);
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (pclient), FALSE);
+ return pulse_connection_set_sink_input_mute (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ pulse_stream_control_get_index (psc),
+ mute);
+}
- pstream = PULSE_STREAM (pclient);
+static gboolean
+pulse_sink_input_set_volume (PulseStreamControl *psc, pa_cvolume *cvolume)
+{
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (psc), FALSE);
+ g_return_val_if_fail (cvolume != NULL, FALSE);
- return pulse_connection_kill_sink_input (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream));
+ return pulse_connection_set_sink_input_volume (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ pulse_stream_control_get_index (psc),
+ cvolume);
}
static PulseMonitor *
-pulse_sink_input_create_monitor (PulseStream *pstream)
+pulse_sink_input_create_monitor (PulseStreamControl *psc)
{
- MateMixerStream *parent;
- guint32 index;
-
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (pstream), NULL);
+ PulseSink *sink;
+ guint32 index;
- parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (pstream));
- if (G_UNLIKELY (parent == NULL)) {
- g_debug ("Not creating monitor for client stream %s as it is not available",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)));
- return NULL;
- }
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (psc), NULL);
- index = pulse_sink_get_monitor_index (PULSE_STREAM (parent));
+ sink = PULSE_SINK (mate_mixer_stream_control_get_stream (MATE_MIXER_STREAM_CONTROL (psc)));
- if (G_UNLIKELY (index == PA_INVALID_INDEX)) {
- g_debug ("Not creating monitor for client stream %s as it is not available",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)));
+ index = pulse_sink_get_index_monitor (sink);
+ if G_UNLIKELY (index == PA_INVALID_INDEX) {
+ g_debug ("Monitor of stream control %s is not available",
+ mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (psc)));
return NULL;
}
- return pulse_connection_create_monitor (pulse_stream_get_connection (pstream),
+ return pulse_connection_create_monitor (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
index,
- pulse_stream_get_index (pstream));
+ pulse_stream_control_get_index (psc));
}
diff --git a/backends/pulse/pulse-sink-input.h b/backends/pulse/pulse-sink-input.h
index 1e5004b..127eab6 100644
--- a/backends/pulse/pulse-sink-input.h
+++ b/backends/pulse/pulse-sink-input.h
@@ -23,9 +23,8 @@
#include <pulse/pulseaudio.h>
-#include "pulse-client-stream.h"
-#include "pulse-connection.h"
-#include "pulse-stream.h"
+#include "pulse-stream-control.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
@@ -42,28 +41,25 @@ G_BEGIN_DECLS
#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;
struct _PulseSinkInput
{
- PulseClientStream parent;
+ PulseStreamControl parent;
};
struct _PulseSinkInputClass
{
- PulseClientStreamClass parent_class;
+ PulseStreamControlClass parent_class;
};
-GType pulse_sink_input_get_type (void) G_GNUC_CONST;
+GType pulse_sink_input_get_type (void) G_GNUC_CONST;
-PulseStream *pulse_sink_input_new (PulseConnection *connection,
- const pa_sink_input_info *info,
- PulseStream *parent);
+PulseSinkInput *pulse_sink_input_new (PulseSink *sink,
+ const pa_sink_input_info *info);
-gboolean pulse_sink_input_update (PulseStream *pstream,
- const pa_sink_input_info *info,
- PulseStream *parent);
+void pulse_sink_input_update (PulseSinkInput *input,
+ const pa_sink_input_info *info);
G_END_DECLS
diff --git a/backends/pulse/pulse-sink-switch.c b/backends/pulse/pulse-sink-switch.c
new file mode 100644
index 0000000..0e08dac
--- /dev/null
+++ b/backends/pulse/pulse-sink-switch.c
@@ -0,0 +1,76 @@
+/*
+ * 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.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "pulse-connection.h"
+#include "pulse-port.h"
+#include "pulse-port-switch.h"
+#include "pulse-sink-switch.h"
+#include "pulse-stream.h"
+
+static void pulse_sink_switch_class_init (PulseSinkSwitchClass *klass);
+static void pulse_sink_switch_init (PulseSinkSwitch *swtch);
+
+G_DEFINE_TYPE (PulseSinkSwitch, pulse_sink_switch, PULSE_TYPE_PORT_SWITCH)
+
+static gboolean pulse_sink_switch_set_active_port (PulsePortSwitch *swtch,
+ PulsePort *port);
+
+static void
+pulse_sink_switch_class_init (PulseSinkSwitchClass *klass)
+{
+ PulsePortSwitchClass *switch_class;
+
+ switch_class = PULSE_PORT_SWITCH_CLASS (klass);
+ switch_class->set_active_port = pulse_sink_switch_set_active_port;
+}
+
+static void
+pulse_sink_switch_init (PulseSinkSwitch *swtch)
+{
+}
+
+PulsePortSwitch *
+pulse_sink_switch_new (const gchar *name, const gchar *label, PulseSink *sink)
+{
+ return g_object_new (PULSE_TYPE_SINK_SWITCH,
+ "name", name,
+ "label", label,
+ "role", MATE_MIXER_SWITCH_ROLE_PORT,
+ "stream", sink,
+ NULL);
+}
+
+static gboolean
+pulse_sink_switch_set_active_port (PulsePortSwitch *swtch, PulsePort *port)
+{
+ PulseStream *stream;
+
+ g_return_val_if_fail (PULSE_IS_SINK_SWITCH (swtch), FALSE);
+ g_return_val_if_fail (PULSE_IS_PORT (port), FALSE);
+
+ stream = pulse_port_switch_get_stream (swtch);
+
+ return pulse_connection_set_sink_port (pulse_stream_get_connection (stream),
+ pulse_stream_get_index (stream),
+ pulse_port_get_name (port));
+}
diff --git a/backends/pulse/pulse-sink-switch.h b/backends/pulse/pulse-sink-switch.h
new file mode 100644
index 0000000..71ed4c9
--- /dev/null
+++ b/backends/pulse/pulse-sink-switch.h
@@ -0,0 +1,62 @@
+/*
+ * 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_SWITCH_H
+#define PULSE_SINK_SWITCH_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_SINK_SWITCH \
+ (pulse_sink_switch_get_type ())
+#define PULSE_SINK_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SINK_SWITCH, PulseSinkSwitch))
+#define PULSE_IS_SINK_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SINK_SWITCH))
+#define PULSE_SINK_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SINK_SWITCH, PulseSinkSwitchClass))
+#define PULSE_IS_SINK_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SINK_SWITCH))
+#define PULSE_SINK_SWITCH_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SINK_SWITCH, PulseSinkSwitchClass))
+
+typedef struct _PulseSinkSwitchClass PulseSinkSwitchClass;
+typedef struct _PulseSinkSwitchPrivate PulseSinkSwitchPrivate;
+
+struct _PulseSinkSwitch
+{
+ PulsePortSwitch parent;
+};
+
+struct _PulseSinkSwitchClass
+{
+ PulsePortSwitchClass parent_class;
+};
+
+GType pulse_sink_switch_get_type (void) G_GNUC_CONST;
+
+PulsePortSwitch *pulse_sink_switch_new (const gchar *name,
+ const gchar *label,
+ PulseSink *sink);
+
+G_END_DECLS
+
+#endif /* PULSE_SINK_SWITCH_H */
diff --git a/backends/pulse/pulse-sink.c b/backends/pulse/pulse-sink.c
index 0f828b1..d2f0280 100644
--- a/backends/pulse/pulse-sink.c
+++ b/backends/pulse/pulse-sink.c
@@ -16,62 +16,57 @@
*/
#include <glib.h>
+#include <glib/gi18n.h>
#include <glib-object.h>
-
-#include <libmatemixer/matemixer-port.h>
-#include <libmatemixer/matemixer-port-private.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
#include "pulse-device.h"
#include "pulse-monitor.h"
+#include "pulse-port.h"
+#include "pulse-port-switch.h"
#include "pulse-stream.h"
#include "pulse-sink.h"
+#include "pulse-sink-control.h"
+#include "pulse-sink-input.h"
+#include "pulse-sink-switch.h"
struct _PulseSinkPrivate
{
- guint32 index_monitor;
+ guint32 monitor;
+ GHashTable *inputs;
+ PulsePortSwitch *pswitch;
+ GList *streams_list;
+ GList *switches_list;
+ PulseSinkControl *control;
};
static void pulse_sink_class_init (PulseSinkClass *klass);
static void pulse_sink_init (PulseSink *sink);
+static void pulse_sink_dispose (GObject *object);
+static void pulse_sink_finalize (GObject *object);
G_DEFINE_TYPE (PulseSink, pulse_sink, PULSE_TYPE_STREAM);
-static void pulse_sink_reload (PulseStream *pstream);
-
-static gboolean pulse_sink_set_mute (PulseStream *pstream,
- gboolean mute);
-static gboolean pulse_sink_set_volume (PulseStream *pstream,
- pa_cvolume *cvolume);
-static gboolean pulse_sink_set_active_port (PulseStream *pstream,
- MateMixerPort *port);
-
-static gboolean pulse_sink_suspend (PulseStream *pstream);
-static gboolean pulse_sink_resume (PulseStream *pstream);
-
-static PulseMonitor *pulse_sink_create_monitor (PulseStream *pstream);
-
-static void update_ports (PulseStream *pstream,
- pa_sink_port_info **ports,
- pa_sink_port_info *active);
+static const GList *pulse_sink_list_controls (MateMixerStream *mms);
+static const GList *pulse_sink_list_switches (MateMixerStream *mms);
static void
pulse_sink_class_init (PulseSinkClass *klass)
{
- PulseStreamClass *stream_class;
+ GObjectClass *object_class;
+ MateMixerStreamClass *stream_class;
- stream_class = PULSE_STREAM_CLASS (klass);
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_sink_dispose;
+ object_class->finalize = pulse_sink_finalize;
- stream_class->reload = pulse_sink_reload;
- stream_class->set_mute = pulse_sink_set_mute;
- stream_class->set_volume = pulse_sink_set_volume;
- stream_class->set_active_port = pulse_sink_set_active_port;
- stream_class->suspend = pulse_sink_suspend;
- stream_class->resume = pulse_sink_resume;
- stream_class->create_monitor = pulse_sink_create_monitor;
+ stream_class = MATE_MIXER_STREAM_CLASS (klass);
+ stream_class->list_controls = pulse_sink_list_controls;
+ stream_class->list_switches = pulse_sink_list_switches;
g_type_class_add_private (klass, sizeof (PulseSinkPrivate));
}
@@ -83,247 +78,190 @@ pulse_sink_init (PulseSink *sink)
PULSE_TYPE_SINK,
PulseSinkPrivate);
- sink->priv->index_monitor = PA_INVALID_INDEX;
+ sink->priv->inputs = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+
+ sink->priv->monitor = PA_INVALID_INDEX;
}
-PulseStream *
-pulse_sink_new (PulseConnection *connection,
- const pa_sink_info *info,
- PulseDevice *device)
+static void
+pulse_sink_dispose (GObject *object)
{
- PulseStream *stream;
+ PulseSink *sink;
- g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
- g_return_val_if_fail (info != NULL, NULL);
+ sink = PULSE_SINK (object);
- /* Consider the sink index as unchanging parameter */
- stream = g_object_new (PULSE_TYPE_SINK,
- "connection", connection,
- "index", info->index,
- NULL);
+ g_clear_object (&sink->priv->control);
+ g_clear_object (&sink->priv->pswitch);
- /* Other data may change at any time, so let's make a use of our update function */
- pulse_sink_update (stream, info, device);
+ g_hash_table_remove_all (sink->priv->inputs);
- return stream;
+ G_OBJECT_CLASS (pulse_sink_parent_class)->dispose (object);
}
-guint32
-pulse_sink_get_monitor_index (PulseStream *pstream)
+static void
+pulse_sink_finalize (GObject *object)
{
- g_return_val_if_fail (PULSE_IS_SINK (pstream), PA_INVALID_INDEX);
+ PulseSink *sink;
+
+ sink = PULSE_SINK (object);
- return PULSE_SINK (pstream)->priv->index_monitor;
+ g_hash_table_unref (sink->priv->inputs);
+
+ G_OBJECT_CLASS (pulse_sink_parent_class)->finalize (object);
}
-gboolean
-pulse_sink_update (PulseStream *pstream, const pa_sink_info *info, PulseDevice *device)
+PulseSink *
+pulse_sink_new (PulseConnection *connection,
+ const pa_sink_info *info,
+ PulseDevice *device)
{
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_OUTPUT |
- MATE_MIXER_STREAM_HAS_MUTE |
- MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_CAN_SET_VOLUME |
- MATE_MIXER_STREAM_CAN_SUSPEND;
PulseSink *sink;
- g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
-
- /* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (pstream));
-
- pulse_stream_update_name (pstream, info->name);
- pulse_stream_update_description (pstream, info->description);
- pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
-
- /* Stream state */
- switch (info->state) {
- case PA_SINK_RUNNING:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_RUNNING);
- break;
- case PA_SINK_IDLE:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_IDLE);
- break;
- case PA_SINK_SUSPENDED:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_SUSPENDED);
- break;
- default:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_UNKNOWN);
- 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;
-
- sink = PULSE_SINK (pstream);
-
- if (sink->priv->index_monitor == PA_INVALID_INDEX)
- sink->priv->index_monitor = info->monitor_source;
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
- if (sink->priv->index_monitor != PA_INVALID_INDEX)
- flags |= MATE_MIXER_STREAM_HAS_MONITOR;
+ sink = g_object_new (PULSE_TYPE_SINK,
+ "name", info->name,
+ "label", info->description,
+ "device", device,
+ "direction", MATE_MIXER_DIRECTION_OUTPUT,
+ "connection", connection,
+ "index", info->index,
+ NULL);
+
+ sink->priv->control = pulse_sink_control_new (sink, info);
+
+ if (info->n_ports > 0) {
+ pa_sink_port_info **ports = info->ports;
+
+ /* Create the port switch */
+ sink->priv->pswitch = pulse_sink_switch_new ("port", _("Port"), sink);
+
+ while (*ports != NULL) {
+ pa_sink_port_info *p = *ports++;
+ PulsePort *port;
+ const gchar *icon = NULL;
+
+ /* A port may include an icon but in PulseAudio sink and source ports
+ * the property is not included, for this reason ports are also read from
+ * devices where the icons may be present */
+ if (device != NULL) {
+ port = pulse_device_get_port (PULSE_DEVICE (device), p->name);
+ if (port != NULL)
+ icon = mate_mixer_switch_option_get_icon (MATE_MIXER_SWITCH_OPTION (port));
+ }
- /* Flags must be updated before volume */
- pulse_stream_update_flags (pstream, flags);
+ port = pulse_port_new (p->name,
+ p->description,
+ icon,
+ p->priority);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
- pulse_stream_update_volume (pstream, &info->volume, info->base_volume);
+ pulse_port_switch_add_port (sink->priv->pswitch, port);
- pulse_stream_update_device (pstream, MATE_MIXER_DEVICE (device));
+ if (p == info->active_port)
+ pulse_port_switch_set_active_port (sink->priv->pswitch, port);
+ }
- /* Ports must be updated after device */
- if (info->ports != NULL) {
- update_ports (pstream, info->ports, info->active_port);
+ g_debug ("Created port list for sink %s", info->name);
}
- g_object_thaw_notify (G_OBJECT (pstream));
- return TRUE;
-}
-
-static void
-pulse_sink_reload (PulseStream *pstream)
-{
- g_return_if_fail (PULSE_IS_SINK (pstream));
+ pulse_sink_update (sink, info);
- pulse_connection_load_sink_info (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream));
+ _mate_mixer_stream_set_default_control (MATE_MIXER_STREAM (sink),
+ MATE_MIXER_STREAM_CONTROL (sink->priv->control));
+ return sink;
}
-static gboolean
-pulse_sink_set_mute (PulseStream *pstream, gboolean mute)
+void
+pulse_sink_add_input (PulseSink *sink, const pa_sink_input_info *info)
{
- g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
-
- return pulse_connection_set_sink_mute (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- mute);
+ PulseSinkInput *input;
+
+ /* This function is used for both creating and refreshing sink inputs */
+ input = g_hash_table_lookup (sink->priv->inputs, GINT_TO_POINTER (info->index));
+ if (input == NULL) {
+ const gchar *name;
+
+ input = pulse_sink_input_new (sink, info);
+ g_hash_table_insert (sink->priv->inputs,
+ GINT_TO_POINTER (info->index),
+ input);
+
+ name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (input));
+ g_signal_emit_by_name (G_OBJECT (sink),
+ "control-added",
+ name);
+ } else
+ pulse_sink_input_update (input, info);
}
-static gboolean
-pulse_sink_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
+void
+pulse_sink_remove_input (PulseSink *sink, guint32 index)
{
- g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
- g_return_val_if_fail (cvolume != NULL, FALSE);
+ PulseSinkInput *input;
+ const gchar *name;
- return pulse_connection_set_sink_volume (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- cvolume);
-}
+ input = g_hash_table_lookup (sink->priv->inputs, GINT_TO_POINTER (index));
+ if G_UNLIKELY (input == NULL)
+ return;
-static gboolean
-pulse_sink_set_active_port (PulseStream *pstream, MateMixerPort *port)
-{
- g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
+ name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (input));
- return pulse_connection_set_sink_port (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- mate_mixer_port_get_name (port));
+ g_hash_table_remove (sink->priv->inputs, GINT_TO_POINTER (index));
+ g_signal_emit_by_name (G_OBJECT (sink),
+ "control-removed",
+ name);
}
-static gboolean
-pulse_sink_suspend (PulseStream *pstream)
+void
+pulse_sink_update (PulseSink *sink, const pa_sink_info *info)
{
- g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
+ g_return_if_fail (PULSE_IS_SINK (sink));
+ g_return_if_fail (info != NULL);
- return pulse_connection_suspend_sink (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- TRUE);
+ /* The switch doesn't allow being unset, PulseAudio should always include
+ * the active port name if the are any ports available */
+ if (info->active_port != NULL)
+ pulse_port_switch_set_active_port_by_name (sink->priv->pswitch,
+ info->active_port->name);
+
+ sink->priv->monitor = info->monitor_source;
}
-static gboolean
-pulse_sink_resume (PulseStream *pstream)
+guint32
+pulse_sink_get_index_monitor (PulseSink *sink)
{
- g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SINK (sink), 0);
- return pulse_connection_suspend_sink (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- FALSE);
+ return sink->priv->monitor;
}
-static PulseMonitor *
-pulse_sink_create_monitor (PulseStream *pstream)
+static const GList *
+pulse_sink_list_controls (MateMixerStream *mms)
{
- guint32 index;
+ GList *list;
- g_return_val_if_fail (PULSE_IS_SINK (pstream), NULL);
+ g_return_val_if_fail (PULSE_IS_SINK (mms), NULL);
- index = pulse_sink_get_monitor_index (pstream);
+ // XXX
+ list = g_hash_table_get_values (PULSE_SINK (mms)->priv->inputs);
+ if (list != NULL)
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
- if (G_UNLIKELY (index == PA_INVALID_INDEX)) {
- g_debug ("Not creating monitor for stream %s: not available",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)));
- return NULL;
- }
-
- return pulse_connection_create_monitor (pulse_stream_get_connection (pstream),
- index,
- PA_INVALID_INDEX);
+ return g_list_prepend (list, g_object_ref (PULSE_SINK (mms)->priv->control));
}
-static void
-update_ports (PulseStream *pstream,
- pa_sink_port_info **ports,
- pa_sink_port_info *active)
+static const GList *
+pulse_sink_list_switches (MateMixerStream *mms)
{
- MateMixerPort *port;
- MateMixerDevice *device;
- GHashTable *hash;
-
- hash = pulse_stream_get_ports (pstream);
-
- while (*ports != NULL) {
- MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
- pa_sink_port_info *info = *ports;
- const gchar *icon = NULL;
-
- device = mate_mixer_stream_get_device (MATE_MIXER_STREAM (pstream));
- if (device != NULL) {
- port = mate_mixer_device_get_port (device, info->name);
-
- if (port != NULL) {
- flags = mate_mixer_port_get_flags (port);
- icon = mate_mixer_port_get_icon (port);
- }
- }
-
-#if PA_CHECK_VERSION(2, 0, 0)
- if (info->available == PA_PORT_AVAILABLE_YES)
- flags |= MATE_MIXER_PORT_AVAILABLE;
- else
- flags &= ~MATE_MIXER_PORT_AVAILABLE;
-#endif
-
- port = g_hash_table_lookup (hash, info->name);
-
- if (port != NULL) {
- /* Update existing port */
- _mate_mixer_port_update_description (port, info->description);
- _mate_mixer_port_update_icon (port, icon);
- _mate_mixer_port_update_priority (port, info->priority);
- _mate_mixer_port_update_flags (port, flags);
- } else {
- /* Add previously unknown port to the hash table */
- port = _mate_mixer_port_new (info->name,
- info->description,
- icon,
- info->priority,
- flags);
-
- g_hash_table_insert (hash, g_strdup (info->name), port);
- }
-
- ports++;
- }
+ g_return_val_if_fail (PULSE_IS_SINK (mms), NULL);
- /* Active port */
- if (G_LIKELY (active != NULL))
- port = g_hash_table_lookup (hash, active->name);
- else
- port = NULL;
+ // XXX
+ if (PULSE_SINK (mms)->priv->pswitch != NULL)
+ return g_list_prepend (NULL, PULSE_SINK (mms)->priv->pswitch);
- pulse_stream_update_active_port (pstream, port);
+ return NULL;
}
diff --git a/backends/pulse/pulse-sink.h b/backends/pulse/pulse-sink.h
index c0631ca..5eaeaa0 100644
--- a/backends/pulse/pulse-sink.h
+++ b/backends/pulse/pulse-sink.h
@@ -23,9 +23,8 @@
#include <pulse/pulseaudio.h>
-#include "pulse-connection.h"
-#include "pulse-device.h"
#include "pulse-stream.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
@@ -42,7 +41,6 @@ G_BEGIN_DECLS
#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;
@@ -59,17 +57,21 @@ struct _PulseSinkClass
PulseStreamClass parent_class;
};
-GType pulse_sink_get_type (void) G_GNUC_CONST;
+GType pulse_sink_get_type (void) G_GNUC_CONST;
-PulseStream *pulse_sink_new (PulseConnection *connection,
- const pa_sink_info *info,
- PulseDevice *device);
+PulseSink *pulse_sink_new (PulseConnection *connection,
+ const pa_sink_info *info,
+ PulseDevice *device);
-guint32 pulse_sink_get_monitor_index (PulseStream *pstream);
+void pulse_sink_add_input (PulseSink *sink,
+ const pa_sink_input_info *info);
-gboolean pulse_sink_update (PulseStream *pstream,
- const pa_sink_info *info,
- PulseDevice *device);
+void pulse_sink_remove_input (PulseSink *sink, guint32 index);
+
+void pulse_sink_update (PulseSink *sink,
+ const pa_sink_info *info);
+
+guint32 pulse_sink_get_index_monitor (PulseSink *sink);
G_END_DECLS
diff --git a/backends/pulse/pulse-source-control.c b/backends/pulse/pulse-source-control.c
new file mode 100644
index 0000000..3ed1573
--- /dev/null
+++ b/backends/pulse/pulse-source-control.c
@@ -0,0 +1,154 @@
+/*
+ * 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.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-connection.h"
+#include "pulse-monitor.h"
+#include "pulse-stream-control.h"
+#include "pulse-source.h"
+#include "pulse-source-control.h"
+
+static void pulse_source_control_class_init (PulseSourceControlClass *klass);
+static void pulse_source_control_init (PulseSourceControl *control);
+
+G_DEFINE_TYPE (PulseSourceControl, pulse_source_control, PULSE_TYPE_STREAM_CONTROL);
+
+static gboolean pulse_source_control_set_mute (PulseStreamControl *psc,
+ gboolean mute);
+static gboolean pulse_source_control_set_volume (PulseStreamControl *psc,
+ pa_cvolume *cvolume);
+static PulseMonitor *pulse_source_control_create_monitor (PulseStreamControl *psc);
+
+static void
+pulse_source_control_class_init (PulseSourceControlClass *klass)
+{
+ PulseStreamControlClass *control_class;
+
+ control_class = PULSE_STREAM_CONTROL_CLASS (klass);
+ control_class->set_mute = pulse_source_control_set_mute;
+ control_class->set_volume = pulse_source_control_set_volume;
+ control_class->create_monitor = pulse_source_control_create_monitor;
+}
+
+static void
+pulse_source_control_init (PulseSourceControl *control)
+{
+}
+
+PulseSourceControl *
+pulse_source_control_new (PulseSource *source,
+ const pa_source_info *info)
+{
+ PulseSourceControl *control;
+ MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_MUTE_READABLE |
+ MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_MONITOR;
+ MateMixerStreamControlRole role;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE (source), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
+
+ if (info->active_port != NULL)
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_PORT;
+ else
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_MASTER;
+
+ /* Build the flag list */
+ if (info->flags & PA_SOURCE_DECIBEL_VOLUME)
+ flags |= MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
+
+ control = g_object_new (PULSE_TYPE_SOURCE_CONTROL,
+ "name", info->name,
+ "label", info->description,
+ "flags", flags,
+ "role", role,
+ "stream", source,
+ NULL);
+
+ pulse_source_control_update (control, info);
+ return control;
+}
+
+void
+pulse_source_control_update (PulseSourceControl *control, const pa_source_info *info)
+{
+ g_return_if_fail (PULSE_IS_SOURCE_CONTROL (control));
+ g_return_if_fail (info != NULL);
+
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (control));
+
+ _mate_mixer_stream_control_set_mute (MATE_MIXER_STREAM_CONTROL (control),
+ info->mute ? TRUE : FALSE);
+
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (control),
+ &info->channel_map);
+
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (control),
+ &info->volume,
+ info->base_volume);
+
+ g_object_thaw_notify (G_OBJECT (control));
+}
+
+static gboolean
+pulse_source_control_set_mute (PulseStreamControl *psc, gboolean mute)
+{
+ g_return_val_if_fail (PULSE_IS_SOURCE_CONTROL (psc), FALSE);
+
+ return pulse_connection_set_source_mute (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ PULSE_STREAM_CONTROL_GET_STREAM_INDEX (psc),
+ mute);
+}
+
+static gboolean
+pulse_source_control_set_volume (PulseStreamControl *psc, pa_cvolume *cvolume)
+{
+ g_return_val_if_fail (PULSE_IS_SOURCE_CONTROL (psc), FALSE);
+ g_return_val_if_fail (cvolume != NULL, FALSE);
+
+ return pulse_connection_set_source_volume (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ PULSE_STREAM_CONTROL_GET_STREAM_INDEX (psc),
+ cvolume);
+}
+
+static PulseMonitor *
+pulse_source_control_create_monitor (PulseStreamControl *psc)
+{
+ guint32 index;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE_CONTROL (psc), NULL);
+
+ index = PULSE_STREAM_CONTROL_GET_STREAM_INDEX (psc);
+ if G_UNLIKELY (index == PA_INVALID_INDEX) {
+ g_debug ("Monitor of stream control %s is not available",
+ mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (psc)));
+ return NULL;
+ }
+
+ return pulse_connection_create_monitor (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ index,
+ PA_INVALID_INDEX);
+}
diff --git a/backends/pulse/pulse-source-control.h b/backends/pulse/pulse-source-control.h
new file mode 100644
index 0000000..a8d659f
--- /dev/null
+++ b/backends/pulse/pulse-source-control.h
@@ -0,0 +1,67 @@
+/*
+ * 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_CONTROL_H
+#define PULSE_SOURCE_CONTROL_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-stream-control.h"
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_SOURCE_CONTROL \
+ (pulse_source_control_get_type ())
+#define PULSE_SOURCE_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SOURCE_CONTROL, PulseSourceControl))
+#define PULSE_IS_SOURCE_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SOURCE_CONTROL))
+#define PULSE_SOURCE_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SOURCE_CONTROL, PulseSourceControlClass))
+#define PULSE_IS_SOURCE_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SOURCE_CONTROL))
+#define PULSE_SOURCE_CONTROL_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SOURCE_CONTROL, PulseSourceControlClass))
+
+typedef struct _PulseSourceControlClass PulseSourceControlClass;
+typedef struct _PulseSourceControlPrivate PulseSourceControlPrivate;
+
+struct _PulseSourceControl
+{
+ PulseStreamControl parent;
+};
+
+struct _PulseSourceControlClass
+{
+ PulseStreamControlClass parent_class;
+};
+
+GType pulse_source_control_get_type (void) G_GNUC_CONST;
+
+PulseSourceControl *pulse_source_control_new (PulseSource *source,
+ const pa_source_info *info);
+
+void pulse_source_control_update (PulseSourceControl *control,
+ const pa_source_info *info);
+
+G_END_DECLS
+
+#endif /* PULSE_SOURCE_CONTROL_H */
diff --git a/backends/pulse/pulse-source-output.c b/backends/pulse/pulse-source-output.c
index 6cbd888..69fc3e4 100644
--- a/backends/pulse/pulse-source-output.c
+++ b/backends/pulse/pulse-source-output.c
@@ -17,56 +17,39 @@
#include <glib.h>
#include <glib-object.h>
-#include <string.h>
-
-#include <libmatemixer/matemixer-client-stream.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
-#include "pulse-client-stream.h"
#include "pulse-helpers.h"
#include "pulse-monitor.h"
-#include "pulse-stream.h"
#include "pulse-source.h"
#include "pulse-source-output.h"
+#include "pulse-stream.h"
+#include "pulse-stream-control.h"
static void pulse_source_output_class_init (PulseSourceOutputClass *klass);
static void pulse_source_output_init (PulseSourceOutput *output);
-G_DEFINE_TYPE (PulseSourceOutput, pulse_source_output, PULSE_TYPE_CLIENT_STREAM);
-
-static void pulse_source_output_reload (PulseStream *pstream);
-
-static gboolean pulse_source_output_set_mute (PulseStream *pstream,
- gboolean mute);
-static gboolean pulse_source_output_set_volume (PulseStream *pstream,
- pa_cvolume *cvolume);
+G_DEFINE_TYPE (PulseSourceOutput, pulse_source_output, PULSE_TYPE_STREAM_CONTROL);
-static gboolean pulse_source_output_set_parent (PulseClientStream *pclient,
- PulseStream *parent);
-static gboolean pulse_source_output_remove (PulseClientStream *pclient);
-
-static PulseMonitor *pulse_source_output_create_monitor (PulseStream *pstream);
+static gboolean pulse_source_output_set_mute (PulseStreamControl *psc,
+ gboolean mute);
+static gboolean pulse_source_output_set_volume (PulseStreamControl *psc,
+ pa_cvolume *cvolume);
+static PulseMonitor *pulse_source_output_create_monitor (PulseStreamControl *psc);
static void
pulse_source_output_class_init (PulseSourceOutputClass *klass)
{
- PulseStreamClass *stream_class;
- PulseClientStreamClass *client_class;
-
- stream_class = PULSE_STREAM_CLASS (klass);
-
- stream_class->reload = pulse_source_output_reload;
- stream_class->set_mute = pulse_source_output_set_mute;
- stream_class->set_volume = pulse_source_output_set_volume;
- stream_class->create_monitor = pulse_source_output_create_monitor;
-
- client_class = PULSE_CLIENT_STREAM_CLASS (klass);
+ PulseStreamControlClass *control_class;
- client_class->set_parent = pulse_source_output_set_parent;
- client_class->remove = pulse_source_output_remove;
+ control_class = PULSE_STREAM_CONTROL_CLASS (klass);
+ control_class->set_mute = pulse_source_output_set_mute;
+ control_class->set_volume = pulse_source_output_set_volume;
+ control_class->create_monitor = pulse_source_output_create_monitor;
}
static void
@@ -74,210 +57,157 @@ pulse_source_output_init (PulseSourceOutput *output)
{
}
-PulseStream *
-pulse_source_output_new (PulseConnection *connection,
- const pa_source_output_info *info,
- PulseStream *parent)
+PulseSourceOutput *
+pulse_source_output_new (PulseSource *source,
+ const pa_source_output_info *info)
{
PulseSourceOutput *output;
+ gchar *name;
+ const gchar *prop;
+ MateMixerAppInfo *app_info = NULL;
- g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
- g_return_val_if_fail (info != NULL, NULL);
-
- /* 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, parent);
+ MateMixerStreamControlFlags flags = MATE_MIXER_STREAM_CONTROL_MUTE_READABLE |
+ MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_MONITOR;
+ MateMixerStreamControlRole role = MATE_MIXER_STREAM_CONTROL_ROLE_UNKNOWN;
- return PULSE_STREAM (output);
-}
+ MateMixerStreamControlMediaRole media_role = MATE_MIXER_STREAM_CONTROL_MEDIA_ROLE_UNKNOWN;
-gboolean
-pulse_source_output_update (PulseStream *pstream,
- const pa_source_output_info *info,
- PulseStream *parent)
-{
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_INPUT |
- MATE_MIXER_STREAM_CLIENT;
- PulseClientStream *pclient;
- const gchar *prop;
- const gchar *description = NULL;
- gchar *name;
+ g_return_val_if_fail (PULSE_IS_SOURCE (source), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
+ /* Many mixer applications query the Pulse client list and use the client
+ * name here, but we use the name only as an identifier, so let's avoid
+ * this unnecessary overhead and use a custom name.
+ * Also make sure to make the name unique by including the PulseAudio index. */
+ name = g_strdup_printf ("pulse-input-control-%lu", (gulong) info->index);
- pclient = PULSE_CLIENT_STREAM (pstream);
+#if PA_CHECK_VERSION(1, 0, 0)
+ if (info->has_volume) {
+ flags |=
+ MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
- /* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (pstream));
+ if (info->volume_writable)
+ flags |= MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE;
+ }
+#else
+ /* Pre-1.0 PulseAudio does not include the has_volume and volume_writable
+ * fields, but does include the volume info, so let's give it a try */
+ flags |=
+ MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL;
+#endif
- /* Many other mixer applications query the Pulse client list and use the
- * client name here, but we use the name only as an identifier, so let's avoid
- * this unnecessary overhead and use a custom name.
- * Also make sure to make the name unique by including the Pulse index. */
- name = g_strdup_printf ("pulse-stream-client-input-%lu", (gulong) info->index);
+ if (info->client != PA_INVALID_INDEX) {
+ app_info = _mate_mixer_app_info_new ();
- pulse_stream_update_name (pstream, name);
- g_free (name);
+ role = MATE_MIXER_STREAM_CONTROL_ROLE_APPLICATION;
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_NAME);
- if (prop != NULL)
- pulse_client_stream_update_app_name (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_NAME);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_name (app_info, prop);
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ID);
- if (prop != NULL)
- pulse_client_stream_update_app_id (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ID);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_id (app_info, prop);
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_VERSION);
- if (prop != NULL)
- pulse_client_stream_update_app_version (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_VERSION);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_version (app_info, prop);
- prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ICON_NAME);
- if (prop != NULL)
- pulse_client_stream_update_app_icon (pclient, prop);
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ICON_NAME);
+ if (prop != NULL)
+ _mate_mixer_app_info_set_icon (app_info, prop);
+ }
prop = pa_proplist_gets (info->proplist, PA_PROP_MEDIA_ROLE);
- if (prop != NULL) {
- MateMixerClientStreamRole role = pulse_convert_media_role_name (prop);
+ if (prop != NULL)
+ media_role = pulse_convert_media_role_name (prop);
- if (role == MATE_MIXER_CLIENT_STREAM_ROLE_EVENT) {
- /* The event description seems to provide much better readable
- * description for event streams */
- prop = pa_proplist_gets (info->proplist, PA_PROP_EVENT_DESCRIPTION);
+ output = g_object_new (PULSE_TYPE_SOURCE_OUTPUT,
+ "name", name,
+ "label", info->name,
+ "flags", flags,
+ "role", role,
+ "media-role", media_role,
+ "index", info->index,
+ "stream", source,
+ NULL);
+ g_free (name);
- if (G_LIKELY (prop != NULL))
- description = prop;
- }
- pulse_client_stream_update_role (pclient, role);
- } else
- pulse_client_stream_update_role (pclient, MATE_MIXER_CLIENT_STREAM_ROLE_NONE);
+ if (app_info != NULL)
+ pulse_stream_control_set_app_info (PULSE_STREAM_CONTROL (output), app_info);
- if (description == NULL)
- description = info->name;
+ pulse_source_output_update (output, info);
+ return output;
+}
- pulse_stream_update_description (pstream, description);
+void
+pulse_source_output_update (PulseSourceOutput *output,
+ const pa_source_output_info *info)
+{
+ g_return_if_fail (PULSE_IS_SOURCE_OUTPUT (output));
+ g_return_if_fail (info != NULL);
- if (info->client != PA_INVALID_INDEX)
- pulse_client_stream_update_flags (pclient, MATE_MIXER_CLIENT_STREAM_APPLICATION);
- else
- pulse_client_stream_update_flags (pclient, MATE_MIXER_CLIENT_STREAM_NO_FLAGS);
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (output));
- if (G_LIKELY (parent != NULL)) {
- pulse_client_stream_update_parent (pclient, MATE_MIXER_STREAM (parent));
- flags |= MATE_MIXER_STREAM_HAS_MONITOR;
- } else
- pulse_client_stream_update_parent (pclient, NULL);
+ _mate_mixer_stream_control_set_mute (MATE_MIXER_STREAM_CONTROL (output),
+ info->mute ? TRUE : FALSE);
#if PA_CHECK_VERSION(1, 0, 0)
- if (info->has_volume) {
- flags |= MATE_MIXER_STREAM_HAS_VOLUME;
-
- if (info->volume_writable)
- flags |= MATE_MIXER_STREAM_CAN_SET_VOLUME;
- }
-
- flags |= MATE_MIXER_STREAM_HAS_MUTE;
-
- /* Flags needed before volume */
- pulse_stream_update_flags (pstream, flags);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
- pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (output),
+ &info->channel_map);
if (info->has_volume)
- pulse_stream_update_volume (pstream, &info->volume, 0);
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (output),
+ &info->volume,
+ 0);
else
- pulse_stream_update_volume (pstream, NULL, 0);
+ pulse_stream_control_set_cvolume (PULSE_STREAM_CONTROL (output),
+ NULL,
+ 0);
#else
- /* Flags needed before volume */
- pulse_stream_update_flags (pstream, flags);
+ pulse_stream_control_set_channel_map (PULSE_STREAM_CONTROL (output),
+ &info->channel_map);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
- pulse_stream_update_volume (pstream, NULL, 0);
+ pulse_stream_control_set_volume (PULSE_STREAM_CONTROL (output),
+ &info->volume,
+ 0);
#endif
- // XXX needs to fix monitor if parent changes
-
- g_object_thaw_notify (G_OBJECT (pstream));
- return TRUE;
-}
-
-static void
-pulse_source_output_reload (PulseStream *pstream)
-{
- g_return_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream));
-
- pulse_connection_load_source_output_info (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream));
+ g_object_thaw_notify (G_OBJECT (output));
}
static gboolean
-pulse_source_output_set_mute (PulseStream *pstream, gboolean mute)
+pulse_source_output_set_mute (PulseStreamControl *psc, gboolean mute)
{
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (psc), FALSE);
- return pulse_connection_set_source_output_mute (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
+ return pulse_connection_set_source_output_mute (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ pulse_stream_control_get_index (psc),
mute);
}
static gboolean
-pulse_source_output_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
+pulse_source_output_set_volume (PulseStreamControl *psc, pa_cvolume *cvolume)
{
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (psc), FALSE);
g_return_val_if_fail (cvolume != NULL, FALSE);
- return pulse_connection_set_source_output_volume (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
+ return pulse_connection_set_source_output_volume (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ pulse_stream_control_get_index (psc),
cvolume);
}
-static gboolean
-pulse_source_output_set_parent (PulseClientStream *pclient, PulseStream *parent)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pclient), FALSE);
-
- pstream = PULSE_STREAM (pclient);
-
- return pulse_connection_move_sink_input (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- pulse_stream_get_index (parent));
-}
-
-static gboolean
-pulse_source_output_remove (PulseClientStream *pclient)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pclient), FALSE);
-
- pstream = PULSE_STREAM (pclient);
-
- return pulse_connection_kill_source_output (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream));
-}
-
static PulseMonitor *
-pulse_source_output_create_monitor (PulseStream *pstream)
+pulse_source_output_create_monitor (PulseStreamControl *psc)
{
- MateMixerStream *parent;
-
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream), NULL);
-
- parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (pstream));
- if (G_UNLIKELY (parent == NULL)) {
- g_debug ("Not creating monitor for client stream %s: not available",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)));
- return NULL;
- }
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (psc), NULL);
- return pulse_connection_create_monitor (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (PULSE_STREAM (parent)),
+ return pulse_connection_create_monitor (PULSE_STREAM_CONTROL_GET_CONNECTION (psc),
+ PULSE_STREAM_CONTROL_GET_STREAM_INDEX (psc),
PA_INVALID_INDEX);
}
diff --git a/backends/pulse/pulse-source-output.h b/backends/pulse/pulse-source-output.h
index 845d439..1037f94 100644
--- a/backends/pulse/pulse-source-output.h
+++ b/backends/pulse/pulse-source-output.h
@@ -23,48 +23,43 @@
#include <pulse/pulseaudio.h>
-#include "pulse-client-stream.h"
-#include "pulse-connection.h"
-#include "pulse-stream.h"
+#include "pulse-stream-control.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
-#define PULSE_TYPE_SOURCE_OUTPUT \
+#define PULSE_TYPE_SOURCE_OUTPUT \
(pulse_source_output_get_type ())
-#define PULSE_SOURCE_OUTPUT(o) \
+#define PULSE_SOURCE_OUTPUT(o) \
(G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SOURCE_OUTPUT, PulseSourceOutput))
-#define PULSE_IS_SOURCE_OUTPUT(o) \
+#define PULSE_IS_SOURCE_OUTPUT(o) \
(G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SOURCE_OUTPUT))
-#define PULSE_SOURCE_OUTPUT_CLASS(k) \
+#define PULSE_SOURCE_OUTPUT_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SOURCE_OUTPUT, PulseSourceOutputClass))
-#define PULSE_IS_SOURCE_OUTPUT_CLASS(k) \
+#define PULSE_IS_SOURCE_OUTPUT_CLASS(k) \
(G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SOURCE_OUTPUT))
-#define PULSE_SOURCE_OUTPUT_GET_CLASS(o) \
+#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;
+typedef struct _PulseSourceOutputClass PulseSourceOutputClass;
struct _PulseSourceOutput
{
- PulseClientStream parent;
+ PulseStreamControl parent;
};
struct _PulseSourceOutputClass
{
- PulseClientStreamClass parent_class;
+ PulseStreamControlClass parent_class;
};
-GType pulse_source_output_get_type (void) G_GNUC_CONST;
+GType pulse_source_output_get_type (void) G_GNUC_CONST;
-PulseStream *pulse_source_output_new (PulseConnection *connection,
- const pa_source_output_info *info,
- PulseStream *parent);
+PulseSourceOutput *pulse_source_output_new (PulseSource *source,
+ const pa_source_output_info *info);
-gboolean pulse_source_output_update (PulseStream *pstream,
- const pa_source_output_info *info,
- PulseStream *parent);
+void pulse_source_output_update (PulseSourceOutput *output,
+ const pa_source_output_info *info);
G_END_DECLS
diff --git a/backends/pulse/pulse-source-switch.c b/backends/pulse/pulse-source-switch.c
new file mode 100644
index 0000000..178702e
--- /dev/null
+++ b/backends/pulse/pulse-source-switch.c
@@ -0,0 +1,76 @@
+/*
+ * 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.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include "pulse-connection.h"
+#include "pulse-port.h"
+#include "pulse-port-switch.h"
+#include "pulse-source-switch.h"
+#include "pulse-stream.h"
+
+static void pulse_source_switch_class_init (PulseSourceSwitchClass *klass);
+static void pulse_source_switch_init (PulseSourceSwitch *swtch);
+
+G_DEFINE_TYPE (PulseSourceSwitch, pulse_source_switch, PULSE_TYPE_PORT_SWITCH)
+
+static gboolean pulse_source_switch_set_active_port (PulsePortSwitch *swtch,
+ PulsePort *port);
+
+static void
+pulse_source_switch_class_init (PulseSourceSwitchClass *klass)
+{
+ PulsePortSwitchClass *switch_class;
+
+ switch_class = PULSE_PORT_SWITCH_CLASS (klass);
+ switch_class->set_active_port = pulse_source_switch_set_active_port;
+}
+
+static void
+pulse_source_switch_init (PulseSourceSwitch *swtch)
+{
+}
+
+PulsePortSwitch *
+pulse_source_switch_new (const gchar *name, const gchar *label, PulseSource *source)
+{
+ return g_object_new (PULSE_TYPE_SOURCE_SWITCH,
+ "name", name,
+ "label", label,
+ "role", MATE_MIXER_SWITCH_ROLE_PORT,
+ "stream", source,
+ NULL);
+}
+
+static gboolean
+pulse_source_switch_set_active_port (PulsePortSwitch *swtch, PulsePort *port)
+{
+ PulseStream *stream;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE_SWITCH (swtch), FALSE);
+ g_return_val_if_fail (PULSE_IS_PORT (port), FALSE);
+
+ stream = pulse_port_switch_get_stream (swtch);
+
+ return pulse_connection_set_source_port (pulse_stream_get_connection (stream),
+ pulse_stream_get_index (stream),
+ pulse_port_get_name (port));
+}
diff --git a/backends/pulse/pulse-source-switch.h b/backends/pulse/pulse-source-switch.h
new file mode 100644
index 0000000..408e872
--- /dev/null
+++ b/backends/pulse/pulse-source-switch.h
@@ -0,0 +1,62 @@
+/*
+ * 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_SWITCH_H
+#define PULSE_SOURCE_SWITCH_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_SOURCE_SWITCH \
+ (pulse_source_switch_get_type ())
+#define PULSE_SOURCE_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_SOURCE_SWITCH, PulseSourceSwitch))
+#define PULSE_IS_SOURCE_SWITCH(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_SOURCE_SWITCH))
+#define PULSE_SOURCE_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SOURCE_SWITCH, PulseSourceSwitchClass))
+#define PULSE_IS_SOURCE_SWITCH_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SOURCE_SWITCH))
+#define PULSE_SOURCE_SWITCH_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SOURCE_SWITCH, PulseSourceSwitchClass))
+
+typedef struct _PulseSourceSwitchClass PulseSourceSwitchClass;
+typedef struct _PulseSourceSwitchPrivate PulseSourceSwitchPrivate;
+
+struct _PulseSourceSwitch
+{
+ PulsePortSwitch parent;
+};
+
+struct _PulseSourceSwitchClass
+{
+ PulsePortSwitchClass parent_class;
+};
+
+GType pulse_source_switch_get_type (void) G_GNUC_CONST;
+
+PulsePortSwitch *pulse_source_switch_new (const gchar *name,
+ const gchar *label,
+ PulseSource *source);
+
+G_END_DECLS
+
+#endif /* PULSE_SOURCE_SWITCH_H */
diff --git a/backends/pulse/pulse-source.c b/backends/pulse/pulse-source.c
index e7dce6f..0d095a7 100644
--- a/backends/pulse/pulse-source.c
+++ b/backends/pulse/pulse-source.c
@@ -16,253 +16,238 @@
*/
#include <glib.h>
+#include <glib/gi18n.h>
#include <glib-object.h>
-
-#include <libmatemixer/matemixer-port.h>
-#include <libmatemixer/matemixer-port-private.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
#include "pulse-device.h"
#include "pulse-monitor.h"
+#include "pulse-port.h"
+#include "pulse-port-switch.h"
#include "pulse-stream.h"
#include "pulse-source.h"
+#include "pulse-source-control.h"
+#include "pulse-source-output.h"
+#include "pulse-source-switch.h"
+
+struct _PulseSourcePrivate
+{
+ GHashTable *outputs;
+ PulsePortSwitch *pswitch;
+ PulseSourceControl *control;
+};
static void pulse_source_class_init (PulseSourceClass *klass);
static void pulse_source_init (PulseSource *source);
+static void pulse_source_dispose (GObject *object);
+static void pulse_source_finalize (GObject *object);
G_DEFINE_TYPE (PulseSource, pulse_source, PULSE_TYPE_STREAM);
-static void pulse_source_reload (PulseStream *pstream);
+static const GList *pulse_source_list_controls (MateMixerStream *mms);
+static const GList *pulse_source_list_switches (MateMixerStream *mms);
-static gboolean pulse_source_set_mute (PulseStream *pstream,
- gboolean mute);
-static gboolean pulse_source_set_volume (PulseStream *pstream,
- pa_cvolume *cvolume);
-static gboolean pulse_source_set_active_port (PulseStream *pstream,
- MateMixerPort *port);
+static void
+pulse_source_class_init (PulseSourceClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerStreamClass *stream_class;
-static PulseMonitor *pulse_source_create_monitor (PulseStream *pstream);
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_source_dispose;
+ object_class->finalize = pulse_source_finalize;
-static void update_ports (PulseStream *pstream,
- pa_source_port_info **ports,
- pa_source_port_info *active);
+ stream_class = MATE_MIXER_STREAM_CLASS (klass);
+ stream_class->list_controls = pulse_source_list_controls;
+ stream_class->list_switches = pulse_source_list_switches;
+
+ g_type_class_add_private (klass, sizeof (PulseSourcePrivate));
+}
static void
-pulse_source_class_init (PulseSourceClass *klass)
+pulse_source_init (PulseSource *source)
+{
+ source->priv = G_TYPE_INSTANCE_GET_PRIVATE (source,
+ PULSE_TYPE_SOURCE,
+ PulseSourcePrivate);
+
+ source->priv->outputs = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+}
+
+static void
+pulse_source_dispose (GObject *object)
{
- PulseStreamClass *stream_class;
+ PulseSource *source;
- stream_class = PULSE_STREAM_CLASS (klass);
+ source = PULSE_SOURCE (object);
- stream_class->reload = pulse_source_reload;
- stream_class->set_mute = pulse_source_set_mute;
- stream_class->set_volume = pulse_source_set_volume;
- stream_class->set_active_port = pulse_source_set_active_port;
- stream_class->create_monitor = pulse_source_create_monitor;
+ g_clear_object (&source->priv->control);
+ g_clear_object (&source->priv->pswitch);
+
+ g_hash_table_remove_all (source->priv->outputs);
+
+ G_OBJECT_CLASS (pulse_source_parent_class)->dispose (object);
}
static void
-pulse_source_init (PulseSource *source)
+pulse_source_finalize (GObject *object)
{
+ PulseSource *source;
+
+ source = PULSE_SOURCE (object);
+
+ g_hash_table_unref (source->priv->outputs);
+
+ G_OBJECT_CLASS (pulse_source_parent_class)->finalize (object);
}
-PulseStream *
+PulseSource *
pulse_source_new (PulseConnection *connection,
const pa_source_info *info,
PulseDevice *device)
{
- PulseStream *stream;
+ PulseSource *source;
g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (info != NULL, NULL);
- /* Consider the sink index as unchanging parameter */
- stream = g_object_new (PULSE_TYPE_SOURCE,
+ source = g_object_new (PULSE_TYPE_SOURCE,
+ "name", info->name,
+ "label", info->description,
+ "device", device,
+ "direction", MATE_MIXER_DIRECTION_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_source_update (stream, info, device);
+ source->priv->control = pulse_source_control_new (source, info);
- return stream;
-}
+ if (info->n_ports > 0) {
+ pa_source_port_info **ports = info->ports;
-gboolean
-pulse_source_update (PulseStream *pstream,
- const pa_source_info *info,
- PulseDevice *device)
-{
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_INPUT |
- MATE_MIXER_STREAM_HAS_MUTE |
- MATE_MIXER_STREAM_HAS_MONITOR |
- MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_CAN_SET_VOLUME |
- MATE_MIXER_STREAM_CAN_SUSPEND;
-
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
-
- /* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (pstream));
-
- pulse_stream_update_name (pstream, info->name);
- pulse_stream_update_description (pstream, info->description);
- pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
-
- /* Stream state */
- switch (info->state) {
- case PA_SOURCE_RUNNING:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_RUNNING);
- break;
- case PA_SOURCE_IDLE:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_IDLE);
- break;
- case PA_SOURCE_SUSPENDED:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_SUSPENDED);
- break;
- default:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_UNKNOWN);
- break;
- }
+ /* Create the port switch */
+ source->priv->pswitch = pulse_source_switch_new ("port", _("Port"), source);
+
+ while (*ports != NULL) {
+ pa_source_port_info *p = *ports++;
+ PulsePort *port;
+ const gchar *icon = NULL;
- /* 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;
+ /* A port may include an icon but in PulseAudio sink and source ports
+ * the property is not included, for this reason ports are also read from
+ * devices where the icons may be present */
+ if (device != NULL) {
+ port = pulse_device_get_port (PULSE_DEVICE (device), p->name);
+ if (port != NULL)
+ icon = mate_mixer_switch_option_get_icon (MATE_MIXER_SWITCH_OPTION (port));
+ }
- /* Flags must be updated before volume */
- pulse_stream_update_flags (pstream, flags);
+ port = pulse_port_new (p->name,
+ p->description,
+ icon,
+ p->priority);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
- pulse_stream_update_volume (pstream, &info->volume, info->base_volume);
+ pulse_port_switch_add_port (source->priv->pswitch, port);
- pulse_stream_update_device (pstream, MATE_MIXER_DEVICE (device));
+ if (p == info->active_port)
+ pulse_port_switch_set_active_port (source->priv->pswitch, port);
+ }
- /* Ports must be updated after device */
- if (info->ports != NULL) {
- update_ports (pstream, info->ports, info->active_port);
+ g_debug ("Created port list for source %s", info->name);
}
- g_object_thaw_notify (G_OBJECT (pstream));
- return TRUE;
-}
+ pulse_source_update (source, info);
-static void
-pulse_source_reload (PulseStream *pstream)
-{
- g_return_if_fail (PULSE_IS_SOURCE (pstream));
-
- pulse_connection_load_source_info (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream));
+ _mate_mixer_stream_set_default_control (MATE_MIXER_STREAM (source),
+ MATE_MIXER_STREAM_CONTROL (source->priv->control));
+ return source;
}
-static gboolean
-pulse_source_set_mute (PulseStream *pstream, gboolean mute)
+void
+pulse_source_add_output (PulseSource *source, const pa_source_output_info *info)
{
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
-
- return pulse_connection_set_source_mute (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- mute);
+ PulseSourceOutput *output;
+
+ /* This function is used for both creating and refreshing source outputs */
+ output = g_hash_table_lookup (source->priv->outputs, GINT_TO_POINTER (info->index));
+ if (output == NULL) {
+ const gchar *name;
+
+ output = pulse_source_output_new (source, info);
+ g_hash_table_insert (source->priv->outputs,
+ GINT_TO_POINTER (info->index),
+ output);
+
+ name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (output));
+ g_signal_emit_by_name (G_OBJECT (source),
+ "control-added",
+ name);
+ } else
+ pulse_source_output_update (output, info);
}
-static gboolean
-pulse_source_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
+void
+pulse_source_remove_output (PulseSource *source, guint32 index)
{
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
- g_return_val_if_fail (cvolume != NULL, FALSE);
+ PulseSourceOutput *output;
+ const gchar *name;
- return pulse_connection_set_source_volume (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- cvolume);
-}
+ output = g_hash_table_lookup (source->priv->outputs, GINT_TO_POINTER (index));
+ if G_UNLIKELY (output == NULL)
+ return;
-static gboolean
-pulse_source_set_active_port (PulseStream *pstream, MateMixerPort *port)
-{
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
+ name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (output));
- return pulse_connection_set_source_port (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- mate_mixer_port_get_name (port));
+ g_hash_table_remove (source->priv->outputs, GINT_TO_POINTER (index));
+ g_signal_emit_by_name (G_OBJECT (source),
+ "control-removed",
+ name);
}
-static PulseMonitor *
-pulse_source_create_monitor (PulseStream *pstream)
+void
+pulse_source_update (PulseSource *source,
+ const pa_source_info *info)
{
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), NULL);
-
- return pulse_connection_create_monitor (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- PA_INVALID_INDEX);
+ g_return_if_fail (PULSE_IS_SOURCE (source));
+ g_return_if_fail (info != NULL);
+
+ /* The switch doesn't allow being unset, PulseAudio should always include
+ * the active port name if the are any ports available */
+ if (info->active_port != NULL)
+ pulse_port_switch_set_active_port_by_name (source->priv->pswitch,
+ info->active_port->name);
}
-static void
-update_ports (PulseStream *pstream,
- pa_source_port_info **ports,
- pa_source_port_info *active)
+static const GList *
+pulse_source_list_controls (MateMixerStream *mms)
{
- MateMixerPort *port;
- MateMixerDevice *device;
- GHashTable *hash;
-
- hash = pulse_stream_get_ports (pstream);
+ GList *list;
- while (*ports != NULL) {
- MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
- pa_source_port_info *info = *ports;
- const gchar *icon = NULL;
+ g_return_val_if_fail (PULSE_IS_SOURCE (mms), NULL);
- device = mate_mixer_stream_get_device (MATE_MIXER_STREAM (pstream));
- if (device != NULL) {
- port = mate_mixer_device_get_port (device, info->name);
-
- if (port != NULL) {
- flags = mate_mixer_port_get_flags (port);
- icon = mate_mixer_port_get_icon (port);
- }
- }
+ // XXX
+ list = g_hash_table_get_values (PULSE_SOURCE (mms)->priv->outputs);
+ if (list != NULL)
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
-#if PA_CHECK_VERSION(2, 0, 0)
- if (info->available == PA_PORT_AVAILABLE_YES)
- flags |= MATE_MIXER_PORT_AVAILABLE;
- else
- flags &= ~MATE_MIXER_PORT_AVAILABLE;
-#endif
-
- port = g_hash_table_lookup (hash, info->name);
-
- if (port != NULL) {
- /* Update existing port */
- _mate_mixer_port_update_description (port, info->description);
- _mate_mixer_port_update_icon (port, icon);
- _mate_mixer_port_update_priority (port, info->priority);
- _mate_mixer_port_update_flags (port, flags);
- } else {
- /* Add previously unknown port to the hash table */
- port = _mate_mixer_port_new (info->name,
- info->description,
- icon,
- info->priority,
- flags);
-
- g_hash_table_insert (hash, g_strdup (info->name), port);
- }
+ return g_list_prepend (list, g_object_ref (PULSE_SOURCE (mms)->priv->control));
+}
- ports++;
- }
+static const GList *
+pulse_source_list_switches (MateMixerStream *mms)
+{
+ g_return_val_if_fail (PULSE_IS_SOURCE (mms), NULL);
- /* Active port */
- if (G_LIKELY (active != NULL))
- port = g_hash_table_lookup (hash, active->name);
- else
- port = NULL;
+ // XXX
+ if (PULSE_SOURCE (mms)->priv->pswitch != NULL)
+ return g_list_prepend (NULL, PULSE_SOURCE (mms)->priv->pswitch);
- pulse_stream_update_active_port (pstream, port);
+ return NULL;
}
diff --git a/backends/pulse/pulse-source.h b/backends/pulse/pulse-source.h
index 9abf6d8..fdc3d5e 100644
--- a/backends/pulse/pulse-source.h
+++ b/backends/pulse/pulse-source.h
@@ -23,9 +23,8 @@
#include <pulse/pulseaudio.h>
-#include "pulse-connection.h"
-#include "pulse-device.h"
#include "pulse-stream.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
@@ -42,12 +41,15 @@ G_BEGIN_DECLS
#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;
+
+ /*< private >*/
+ PulseSourcePrivate *priv;
};
struct _PulseSourceClass
@@ -55,15 +57,20 @@ struct _PulseSourceClass
PulseStreamClass parent_class;
};
-GType pulse_source_get_type (void) G_GNUC_CONST;
+GType pulse_source_get_type (void) G_GNUC_CONST;
+
+PulseSource *pulse_source_new (PulseConnection *connection,
+ const pa_source_info *info,
+ PulseDevice *device);
+
+void pulse_source_add_output (PulseSource *source,
+ const pa_source_output_info *info);
-PulseStream *pulse_source_new (PulseConnection *connection,
- const pa_source_info *info,
- PulseDevice *device);
+void pulse_source_remove_output (PulseSource *source,
+ guint32 index);
-gboolean pulse_source_update (PulseStream *pstream,
- const pa_source_info *info,
- PulseDevice *device);
+void pulse_source_update (PulseSource *source,
+ const pa_source_info *info);
G_END_DECLS
diff --git a/backends/pulse/pulse-stream-control.c b/backends/pulse/pulse-stream-control.c
new file mode 100644
index 0000000..fa17e6b
--- /dev/null
+++ b/backends/pulse/pulse-stream-control.c
@@ -0,0 +1,744 @@
+/*
+ * 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.h>
+#include <libmatemixer/matemixer-private.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-connection.h"
+#include "pulse-helpers.h"
+#include "pulse-monitor.h"
+#include "pulse-stream-control.h"
+
+struct _PulseStreamControlPrivate
+{
+ guint32 index;
+ guint volume;
+ pa_cvolume cvolume;
+ pa_volume_t base_volume;
+ pa_channel_map channel_map;
+ PulseConnection *connection;
+ PulseMonitor *monitor;
+ MateMixerAppInfo *app_info;
+};
+
+enum {
+ PROP_0,
+ PROP_INDEX,
+ PROP_CONNECTION,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+static void pulse_stream_control_class_init (PulseStreamControlClass *klass);
+
+static void pulse_stream_control_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void pulse_stream_control_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void pulse_stream_control_init (PulseStreamControl *control);
+static void pulse_stream_control_dispose (GObject *object);
+static void pulse_stream_control_finalize (GObject *object);
+
+G_DEFINE_ABSTRACT_TYPE (PulseStreamControl, pulse_stream_control, MATE_MIXER_TYPE_STREAM_CONTROL)
+
+static MateMixerAppInfo * pulse_stream_control_get_app_info (MateMixerStreamControl *mmsc);
+
+static gboolean pulse_stream_control_set_mute (MateMixerStreamControl *mmsc,
+ gboolean mute);
+
+static guint pulse_stream_control_get_num_channels (MateMixerStreamControl *mmsc);
+
+static guint pulse_stream_control_get_volume (MateMixerStreamControl *mmsc);
+static gboolean pulse_stream_control_set_volume (MateMixerStreamControl *mmsc,
+ guint volume);
+
+static gdouble pulse_stream_control_get_decibel (MateMixerStreamControl *mmsc);
+static gboolean pulse_stream_control_set_decibel (MateMixerStreamControl *mmsc,
+ gdouble decibel);
+
+static guint pulse_stream_control_get_channel_volume (MateMixerStreamControl *mmsc,
+ guint channel);
+static gboolean pulse_stream_control_set_channel_volume (MateMixerStreamControl *mmsc,
+ guint channel,
+ guint volume);
+
+static gdouble pulse_stream_control_get_channel_decibel (MateMixerStreamControl *mmsc,
+ guint channel);
+static gboolean pulse_stream_control_set_channel_decibel (MateMixerStreamControl *mmsc,
+ guint channel,
+ gdouble decibel);
+
+static MateMixerChannelPosition pulse_stream_control_get_channel_position (MateMixerStreamControl *mmsc,
+ guint channel);
+static gboolean pulse_stream_control_has_channel_position (MateMixerStreamControl *mmsc,
+ MateMixerChannelPosition position);
+
+static gboolean pulse_stream_control_set_balance (MateMixerStreamControl *mmsc,
+ gfloat balance);
+
+static gboolean pulse_stream_control_set_fade (MateMixerStreamControl *mmsc,
+ gfloat fade);
+
+static gboolean pulse_stream_control_get_monitor_enabled (MateMixerStreamControl *mmsc);
+static gboolean pulse_stream_control_set_monitor_enabled (MateMixerStreamControl *mmsc,
+ gboolean enabled);
+
+static guint pulse_stream_control_get_min_volume (MateMixerStreamControl *mmsc);
+static guint pulse_stream_control_get_max_volume (MateMixerStreamControl *mmsc);
+static guint pulse_stream_control_get_normal_volume (MateMixerStreamControl *mmsc);
+static guint pulse_stream_control_get_base_volume (MateMixerStreamControl *mmsc);
+
+static void on_monitor_value (PulseMonitor *monitor,
+ gdouble value,
+ PulseStreamControl *control);
+
+static void set_balance_fade (PulseStreamControl *control);
+
+static gboolean set_cvolume (PulseStreamControl *control,
+ pa_cvolume *cvolume);
+
+static void
+pulse_stream_control_class_init (PulseStreamControlClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerStreamControlClass *control_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_stream_control_dispose;
+ object_class->finalize = pulse_stream_control_finalize;
+ object_class->get_property = pulse_stream_control_get_property;
+ object_class->set_property = pulse_stream_control_set_property;
+
+ control_class = MATE_MIXER_STREAM_CONTROL_CLASS (klass);
+ control_class->get_app_info = pulse_stream_control_get_app_info;
+ control_class->set_mute = pulse_stream_control_set_mute;
+ control_class->get_num_channels = pulse_stream_control_get_num_channels;
+ control_class->get_volume = pulse_stream_control_get_volume;
+ control_class->set_volume = pulse_stream_control_set_volume;
+ control_class->get_decibel = pulse_stream_control_get_decibel;
+ control_class->set_decibel = pulse_stream_control_set_decibel;
+ control_class->get_channel_volume = pulse_stream_control_get_channel_volume;
+ control_class->set_channel_volume = pulse_stream_control_set_channel_volume;
+ control_class->get_channel_decibel = pulse_stream_control_get_channel_decibel;
+ control_class->set_channel_decibel = pulse_stream_control_set_channel_decibel;
+ control_class->get_channel_position = pulse_stream_control_get_channel_position;
+ control_class->has_channel_position = pulse_stream_control_has_channel_position;
+ control_class->set_balance = pulse_stream_control_set_balance;
+ control_class->set_fade = pulse_stream_control_set_fade;
+ control_class->get_monitor_enabled = pulse_stream_control_get_monitor_enabled;
+ control_class->set_monitor_enabled = pulse_stream_control_set_monitor_enabled;
+ control_class->get_min_volume = pulse_stream_control_get_min_volume;
+ control_class->get_max_volume = pulse_stream_control_get_max_volume;
+ control_class->get_normal_volume = pulse_stream_control_get_normal_volume;
+ control_class->get_base_volume = pulse_stream_control_get_base_volume;
+
+ properties[PROP_INDEX] =
+ g_param_spec_uint ("index",
+ "Index",
+ "Index of the stream control",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_CONNECTION] =
+ g_param_spec_object ("connection",
+ "Connection",
+ "PulseAudio connection",
+ PULSE_TYPE_CONNECTION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (object_class, sizeof (PulseStreamControlPrivate));
+}
+
+static void
+pulse_stream_control_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PulseStreamControl *control;
+
+ control = PULSE_STREAM_CONTROL (object);
+
+ switch (param_id) {
+ case PROP_INDEX:
+ g_value_set_uint (value, control->priv->index);
+ break;
+ case PROP_CONNECTION:
+ g_value_set_object (value, control->priv->connection);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_stream_control_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PulseStreamControl *control;
+
+ control = PULSE_STREAM_CONTROL (object);
+
+ switch (param_id) {
+ case PROP_INDEX:
+ control->priv->index = g_value_get_uint (value);
+ break;
+ case PROP_CONNECTION:
+ control->priv->connection = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_stream_control_init (PulseStreamControl *control)
+{
+ control->priv = G_TYPE_INSTANCE_GET_PRIVATE (control,
+ PULSE_TYPE_STREAM_CONTROL,
+ PulseStreamControlPrivate);
+
+ /* Initialize empty volume and channel map structures, they will be used
+ * if the stream does not support volume */
+ pa_cvolume_init (&control->priv->cvolume);
+
+ pa_channel_map_init (&control->priv->channel_map);
+}
+
+static void
+pulse_stream_control_dispose (GObject *object)
+{
+ PulseStreamControl *control;
+
+ control = PULSE_STREAM_CONTROL (object);
+
+ g_clear_object (&control->priv->monitor);
+ g_clear_object (&control->priv->connection);
+
+ G_OBJECT_CLASS (pulse_stream_control_parent_class)->dispose (object);
+}
+
+static void
+pulse_stream_control_finalize (GObject *object)
+{
+ PulseStreamControl *control;
+
+ control = PULSE_STREAM_CONTROL (object);
+
+ if (control->priv->app_info != NULL)
+ _mate_mixer_app_info_free (control->priv->app_info);
+
+ G_OBJECT_CLASS (pulse_stream_control_parent_class)->finalize (object);
+}
+
+guint32
+pulse_stream_control_get_index (PulseStreamControl *control)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), 0);
+
+ return control->priv->index;
+}
+
+PulseConnection *
+pulse_stream_control_get_connection (PulseStreamControl *control)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), NULL);
+
+ return control->priv->connection;
+}
+
+PulseMonitor *
+pulse_stream_control_get_monitor (PulseStreamControl *control)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), NULL);
+
+ return control->priv->monitor;
+}
+
+const pa_cvolume *
+pulse_stream_control_get_cvolume (PulseStreamControl *control)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), NULL);
+
+ return &control->priv->cvolume;
+}
+
+const pa_channel_map *
+pulse_stream_control_get_channel_map (PulseStreamControl *control)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (control), NULL);
+
+ return &control->priv->channel_map;
+}
+
+void
+pulse_stream_control_set_app_info (PulseStreamControl *control, MateMixerAppInfo *info)
+{
+ g_return_if_fail (PULSE_IS_STREAM_CONTROL (control));
+
+ if G_UNLIKELY (control->priv->app_info)
+ _mate_mixer_app_info_free (control->priv->app_info);
+
+ control->priv->app_info = info;
+}
+
+void
+pulse_stream_control_set_channel_map (PulseStreamControl *control, const pa_channel_map *map)
+{
+ MateMixerStreamControlFlags flags;
+
+ g_return_if_fail (PULSE_IS_STREAM_CONTROL (control));
+ g_return_if_fail (map != NULL);
+
+ flags = mate_mixer_stream_control_get_flags (MATE_MIXER_STREAM_CONTROL (control));
+
+ if (pa_channel_map_valid (map)) {
+ if (pa_channel_map_can_balance (map))
+ flags |= MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
+ else
+ flags &= ~MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
+
+ if (pa_channel_map_can_fade (map))
+ flags |= MATE_MIXER_STREAM_CONTROL_CAN_FADE;
+ else
+ flags &= ~MATE_MIXER_STREAM_CONTROL_CAN_FADE;
+
+ control->priv->channel_map = *map;
+ } else {
+ flags &= ~(MATE_MIXER_STREAM_CONTROL_CAN_BALANCE | MATE_MIXER_STREAM_CONTROL_CAN_FADE);
+
+ /* If the channel map is not valid, create an empty channel map, which
+ * also won't validate, but at least we know what it is */
+ pa_channel_map_init (&control->priv->channel_map);
+ }
+
+ _mate_mixer_stream_control_set_flags (MATE_MIXER_STREAM_CONTROL (control), flags);
+}
+
+void
+pulse_stream_control_set_cvolume (PulseStreamControl *control,
+ const pa_cvolume *cvolume,
+ pa_volume_t base_volume)
+{
+ MateMixerStreamControlFlags flags;
+
+ g_return_if_fail (PULSE_IS_STREAM_CONTROL (control));
+
+ /* The base volume is not a property */
+ control->priv->base_volume = base_volume;
+
+ flags = mate_mixer_stream_control_get_flags (MATE_MIXER_STREAM_CONTROL (control));
+
+ g_object_freeze_notify (G_OBJECT (control));
+
+ if (cvolume != NULL && pa_cvolume_valid (cvolume)) {
+ /* Decibel volume and volume settability flags must be provided by
+ * the implementation */
+ flags |= MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE;
+
+ if (pa_cvolume_equal (&control->priv->cvolume, cvolume) == 0) {
+ control->priv->cvolume = *cvolume;
+ control->priv->volume = (guint) pa_cvolume_max (&control->priv->cvolume);
+
+ g_object_notify (G_OBJECT (control), "volume");
+ }
+ } else {
+ flags &= ~(MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE |
+ MATE_MIXER_STREAM_CONTROL_HAS_DECIBEL);
+
+ /* If the cvolume is not valid, create an empty cvolume, which also
+ * won't validate, but at least we know what it is */
+ pa_cvolume_init (&control->priv->cvolume);
+
+ if (control->priv->volume != (guint) PA_VOLUME_MUTED) {
+ control->priv->volume = (guint) PA_VOLUME_MUTED;
+
+ g_object_notify (G_OBJECT (control), "volume");
+ }
+ }
+
+ _mate_mixer_stream_control_set_flags (MATE_MIXER_STREAM_CONTROL (control), flags);
+
+ /* Changing volume may change the balance and fade values as well */
+ set_balance_fade (control);
+
+ g_object_thaw_notify (G_OBJECT (control));
+}
+
+static MateMixerAppInfo *
+pulse_stream_control_get_app_info (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), NULL);
+
+ return PULSE_STREAM_CONTROL (mmsc)->priv->app_info;
+}
+
+static gboolean
+pulse_stream_control_set_mute (MateMixerStreamControl *mmsc, gboolean mute)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ return PULSE_STREAM_CONTROL_GET_CLASS (mmsc)->set_mute (PULSE_STREAM_CONTROL (mmsc), mute);
+}
+
+static guint
+pulse_stream_control_get_num_channels (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), 0);
+
+ return PULSE_STREAM_CONTROL (mmsc)->priv->channel_map.channels;
+}
+
+static guint
+pulse_stream_control_get_volume (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
+
+ return PULSE_STREAM_CONTROL (mmsc)->priv->volume;
+}
+
+static gboolean
+pulse_stream_control_set_volume (MateMixerStreamControl *mmsc, guint volume)
+{
+ PulseStreamControl *control;
+ pa_cvolume cvolume;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+ cvolume = control->priv->cvolume;
+
+ if (pa_cvolume_scale (&cvolume, (pa_volume_t) volume) == NULL)
+ return FALSE;
+
+ return set_cvolume (control, &cvolume);
+}
+
+static gdouble
+pulse_stream_control_get_decibel (MateMixerStreamControl *mmsc)
+{
+ gdouble value;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), -MATE_MIXER_INFINITY);
+
+ value = pa_sw_volume_to_dB (pulse_stream_control_get_volume (mmsc));
+
+ /* PA_VOLUME_MUTED is converted to PA_DECIBEL_MININFTY */
+ return (value == PA_DECIBEL_MININFTY) ? -MATE_MIXER_INFINITY : value;
+}
+
+static gboolean
+pulse_stream_control_set_decibel (MateMixerStreamControl *mmsc, gdouble decibel)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ return pulse_stream_control_set_volume (mmsc,
+ pa_sw_volume_from_dB (decibel));
+}
+
+static guint
+pulse_stream_control_get_channel_volume (MateMixerStreamControl *mmsc, guint channel)
+{
+ PulseStreamControl *control;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (channel >= control->priv->cvolume.channels)
+ return (guint) PA_VOLUME_MUTED;
+
+ return (guint) control->priv->cvolume.values[channel];
+}
+
+static gboolean
+pulse_stream_control_set_channel_volume (MateMixerStreamControl *mmsc, guint channel, guint volume)
+{
+ PulseStreamControl *control;
+ pa_cvolume cvolume;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (channel >= control->priv->cvolume.channels)
+ return FALSE;
+
+ /* This is safe, because the cvolume is validated by set_cvolume() */
+ cvolume = control->priv->cvolume;
+ cvolume.values[channel] = (pa_volume_t) volume;
+
+ return set_cvolume (control, &cvolume);
+}
+
+static gdouble
+pulse_stream_control_get_channel_decibel (MateMixerStreamControl *mmsc, guint channel)
+{
+ PulseStreamControl *control;
+ gdouble value;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), -MATE_MIXER_INFINITY);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (channel >= control->priv->cvolume.channels)
+ return -MATE_MIXER_INFINITY;
+
+ value = pa_sw_volume_to_dB (control->priv->cvolume.values[channel]);
+
+ return (value == PA_DECIBEL_MININFTY) ? -MATE_MIXER_INFINITY : value;
+}
+
+static gboolean
+pulse_stream_control_set_channel_decibel (MateMixerStreamControl *mmsc,
+ guint channel,
+ gdouble decibel)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ return pulse_stream_control_set_channel_volume (mmsc,
+ channel,
+ pa_sw_volume_from_dB (decibel));
+}
+
+static MateMixerChannelPosition
+pulse_stream_control_get_channel_position (MateMixerStreamControl *mmsc, guint channel)
+{
+ PulseStreamControl *control;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), MATE_MIXER_CHANNEL_UNKNOWN);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (channel >= control->priv->channel_map.channels)
+ return MATE_MIXER_CHANNEL_UNKNOWN;
+
+ return pulse_convert_position_to_pulse (control->priv->channel_map.map[channel]);
+}
+
+static gboolean
+pulse_stream_control_has_channel_position (MateMixerStreamControl *mmsc,
+ MateMixerChannelPosition position)
+{
+ PulseStreamControl *control;
+ pa_channel_position_t p;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ /* Handle invalid position as a special case, otherwise this function would
+ * return TRUE for e.g. unknown index in a default channel map */
+ p = pulse_convert_position_to_pulse (position);
+
+ if (p == PA_CHANNEL_POSITION_INVALID)
+ return FALSE;
+
+ if (pa_channel_map_has_position (&control->priv->channel_map, p) != 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static gboolean
+pulse_stream_control_set_balance (MateMixerStreamControl *mmsc, gfloat balance)
+{
+ PulseStreamControl *control;
+ pa_cvolume cvolume;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+ cvolume = control->priv->cvolume;
+
+ if (pa_cvolume_set_balance (&cvolume, &control->priv->channel_map, balance) == NULL)
+ return FALSE;
+
+ return set_cvolume (control, &cvolume);
+}
+
+static gboolean
+pulse_stream_control_set_fade (MateMixerStreamControl *mmsc, gfloat fade)
+{
+ PulseStreamControl *control;
+ pa_cvolume cvolume;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+ cvolume = control->priv->cvolume;
+
+ if (pa_cvolume_set_fade (&cvolume, &control->priv->channel_map, fade) == NULL)
+ return FALSE;
+
+ return set_cvolume (control, &cvolume);
+}
+
+static gboolean
+pulse_stream_control_get_monitor_enabled (MateMixerStreamControl *mmsc)
+{
+ PulseStreamControl *control;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (control->priv->monitor != NULL)
+ return pulse_monitor_get_enabled (control->priv->monitor);
+
+ return FALSE;
+}
+
+static gboolean
+pulse_stream_control_set_monitor_enabled (MateMixerStreamControl *mmsc, gboolean enabled)
+{
+ PulseStreamControl *control;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), FALSE);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (enabled == TRUE) {
+ if (control->priv->monitor == NULL) {
+ control->priv->monitor =
+ PULSE_STREAM_CONTROL_GET_CLASS (control)->create_monitor (control);
+
+ if G_UNLIKELY (control->priv->monitor == NULL)
+ return FALSE;
+
+ g_signal_connect (G_OBJECT (control->priv->monitor),
+ "value",
+ G_CALLBACK (on_monitor_value),
+ control);
+ }
+ } else {
+ if (control->priv->monitor == NULL)
+ return FALSE;
+ }
+ return pulse_monitor_set_enabled (control->priv->monitor, enabled);
+}
+
+static guint
+pulse_stream_control_get_min_volume (MateMixerStreamControl *mmsc)
+{
+ return (guint) PA_VOLUME_MUTED;
+}
+
+static guint
+pulse_stream_control_get_max_volume (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
+
+ return (guint) PA_VOLUME_UI_MAX;
+}
+
+static guint
+pulse_stream_control_get_normal_volume (MateMixerStreamControl *mmsc)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
+
+ return (guint) PA_VOLUME_NORM;
+}
+
+static guint
+pulse_stream_control_get_base_volume (MateMixerStreamControl *mmsc)
+{
+ PulseStreamControl *control;
+
+ g_return_val_if_fail (PULSE_IS_STREAM_CONTROL (mmsc), (guint) PA_VOLUME_MUTED);
+
+ control = PULSE_STREAM_CONTROL (mmsc);
+
+ if (control->priv->base_volume > 0)
+ return control->priv->base_volume;
+ else
+ return (guint) PA_VOLUME_NORM;
+}
+
+static void
+on_monitor_value (PulseMonitor *monitor, gdouble value, PulseStreamControl *control)
+{
+ g_signal_emit_by_name (G_OBJECT (control),
+ "monitor-value",
+ value);
+}
+
+static void
+set_balance_fade (PulseStreamControl *control)
+{
+ gfloat value;
+
+ /* PulseAudio returns the default 0.0f value on error, so skip checking validity
+ * of the channel map and cvolume */
+ value = pa_cvolume_get_balance (&control->priv->cvolume,
+ &control->priv->channel_map);
+
+ _mate_mixer_stream_control_set_balance (MATE_MIXER_STREAM_CONTROL (control), value);
+
+ value = pa_cvolume_get_fade (&control->priv->cvolume,
+ &control->priv->channel_map);
+
+ _mate_mixer_stream_control_set_fade (MATE_MIXER_STREAM_CONTROL (control), value);
+}
+
+static gboolean
+set_cvolume (PulseStreamControl *control, pa_cvolume *cvolume)
+{
+ PulseStreamControlClass *klass;
+
+ if (pa_cvolume_valid (cvolume) == 0)
+ return FALSE;
+ if (pa_cvolume_equal (cvolume, &control->priv->cvolume) != 0)
+ return TRUE;
+
+ klass = PULSE_STREAM_CONTROL_GET_CLASS (control);
+
+ if (klass->set_volume (control, cvolume) == FALSE)
+ return FALSE;
+
+ control->priv->cvolume = *cvolume;
+ control->priv->volume = (guint) pa_cvolume_max (cvolume);
+
+ g_object_notify (G_OBJECT (control), "volume");
+
+ /* Changing volume may change the balance and fade values as well */
+ set_balance_fade (control);
+ return TRUE;
+}
diff --git a/backends/pulse/pulse-stream-control.h b/backends/pulse/pulse-stream-control.h
new file mode 100644
index 0000000..abc3f98
--- /dev/null
+++ b/backends/pulse/pulse-stream-control.h
@@ -0,0 +1,94 @@
+/*
+ * 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_STREAM_CONTROL_H
+#define PULSE_STREAM_CONTROL_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libmatemixer/matemixer.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "pulse-types.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_STREAM_CONTROL \
+ (pulse_stream_control_get_type ())
+#define PULSE_STREAM_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_STREAM_CONTROL, PulseStreamControl))
+#define PULSE_IS_STREAM_CONTROL(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_STREAM_CONTROL))
+#define PULSE_STREAM_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_STREAM_CONTROL, PulseStreamControlClass))
+#define PULSE_IS_STREAM_CONTROL_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_STREAM_CONTROL))
+#define PULSE_STREAM_CONTROL_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_STREAM_CONTROL, PulseStreamControlClass))
+
+#define PULSE_STREAM_CONTROL_GET_CONNECTION(psc) \
+ (pulse_stream_get_connection (PULSE_STREAM (mate_mixer_stream_control_get_stream (MATE_MIXER_STREAM_CONTROL (psc)))))
+#define PULSE_STREAM_CONTROL_GET_STREAM_INDEX(psc) \
+ (pulse_stream_get_index (PULSE_STREAM (mate_mixer_stream_control_get_stream (MATE_MIXER_STREAM_CONTROL (psc)))))
+
+typedef struct _PulseStreamControlClass PulseStreamControlClass;
+typedef struct _PulseStreamControlPrivate PulseStreamControlPrivate;
+
+struct _PulseStreamControl
+{
+ MateMixerStreamControl parent;
+
+ /*< private >*/
+ PulseStreamControlPrivate *priv;
+};
+
+struct _PulseStreamControlClass
+{
+ MateMixerStreamControlClass parent_class;
+
+ /*< private >*/
+ gboolean (*set_mute) (PulseStreamControl *control,
+ gboolean mute);
+ gboolean (*set_volume) (PulseStreamControl *control,
+ pa_cvolume *volume);
+
+ PulseMonitor *(*create_monitor) (PulseStreamControl *control);
+};
+
+GType pulse_stream_control_get_type (void) G_GNUC_CONST;
+
+guint32 pulse_stream_control_get_index (PulseStreamControl *control);
+
+PulseConnection * pulse_stream_control_get_connection (PulseStreamControl *control);
+PulseMonitor * pulse_stream_control_get_monitor (PulseStreamControl *control);
+
+const pa_cvolume * pulse_stream_control_get_cvolume (PulseStreamControl *control);
+const pa_channel_map *pulse_stream_control_get_channel_map (PulseStreamControl *control);
+
+void pulse_stream_control_set_app_info (PulseStreamControl *stream,
+ MateMixerAppInfo *info);
+
+void pulse_stream_control_set_channel_map (PulseStreamControl *control,
+ const pa_channel_map *map);
+void pulse_stream_control_set_cvolume (PulseStreamControl *control,
+ const pa_cvolume *cvolume,
+ pa_volume_t base_volume);
+
+G_END_DECLS
+
+#endif /* PULSE_STREAM_CONTROL_H */
diff --git a/backends/pulse/pulse-stream.c b/backends/pulse/pulse-stream.c
index fb738ad..752c3e6 100644
--- a/backends/pulse/pulse-stream.c
+++ b/backends/pulse/pulse-stream.c
@@ -15,62 +15,34 @@
* 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-device.h>
-#include <libmatemixer/matemixer-enums.h>
-#include <libmatemixer/matemixer-stream.h>
-#include <libmatemixer/matemixer-port.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
+#include "pulse-device.h"
#include "pulse-helpers.h"
#include "pulse-monitor.h"
+#include "pulse-port.h"
#include "pulse-stream.h"
struct _PulseStreamPrivate
{
- guint32 index;
- gchar *name;
- gchar *description;
- MateMixerDevice *device;
- MateMixerStreamFlags flags;
- MateMixerStreamState state;
- gboolean mute;
- guint volume;
- pa_cvolume cvolume;
- pa_volume_t base_volume;
- pa_channel_map channel_map;
- gfloat balance;
- gfloat fade;
- GHashTable *ports;
- GList *ports_list;
- MateMixerPort *port;
- PulseConnection *connection;
- PulseMonitor *monitor;
- gchar *monitor_name;
+ guint32 index;
+ PulseConnection *connection;
};
enum {
PROP_0,
- PROP_NAME,
- PROP_DESCRIPTION,
- PROP_DEVICE,
- PROP_FLAGS,
- PROP_STATE,
- PROP_MUTE,
- PROP_VOLUME,
- PROP_BALANCE,
- PROP_FADE,
- PROP_ACTIVE_PORT,
PROP_INDEX,
- PROP_CONNECTION
+ PROP_CONNECTION,
+ N_PROPERTIES
};
-static void mate_mixer_stream_interface_init (MateMixerStreamInterface *iface);
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
static void pulse_stream_class_init (PulseStreamClass *klass);
@@ -83,174 +55,45 @@ static void pulse_stream_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec);
-static void pulse_stream_init (PulseStream *pstream);
+static void pulse_stream_init (PulseStream *stream);
static void pulse_stream_dispose (GObject *object);
-static void pulse_stream_finalize (GObject *object);
-
-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 const gchar * pulse_stream_get_name (MateMixerStream *stream);
-static const gchar * pulse_stream_get_description (MateMixerStream *stream);
-static MateMixerDevice * pulse_stream_get_device (MateMixerStream *stream);
-static MateMixerStreamFlags pulse_stream_get_flags (MateMixerStream *stream);
-static MateMixerStreamState pulse_stream_get_state (MateMixerStream *stream);
-
-static gboolean pulse_stream_get_mute (MateMixerStream *stream);
-static gboolean pulse_stream_set_mute (MateMixerStream *stream,
- gboolean mute);
-
-static guint pulse_stream_get_num_channels (MateMixerStream *stream);
-
-static guint pulse_stream_get_volume (MateMixerStream *stream);
-static gboolean pulse_stream_set_volume (MateMixerStream *stream,
- guint volume);
-
-static gdouble pulse_stream_get_decibel (MateMixerStream *stream);
-static gboolean pulse_stream_set_decibel (MateMixerStream *stream,
- gdouble decibel);
-
-static guint pulse_stream_get_channel_volume (MateMixerStream *stream,
- guint channel);
-static gboolean pulse_stream_set_channel_volume (MateMixerStream *stream,
- guint channel,
- guint volume);
-
-static gdouble pulse_stream_get_channel_decibel (MateMixerStream *stream,
- guint channel);
-static gboolean pulse_stream_set_channel_decibel (MateMixerStream *stream,
- guint channel,
- gdouble decibel);
-
-static MateMixerChannelPosition pulse_stream_get_channel_position (MateMixerStream *stream,
- guint channel);
-static gboolean pulse_stream_has_channel_position (MateMixerStream *stream,
- MateMixerChannelPosition position);
-
-static gfloat pulse_stream_get_balance (MateMixerStream *stream);
-static gboolean pulse_stream_set_balance (MateMixerStream *stream,
- gfloat balance);
-
-static gfloat pulse_stream_get_fade (MateMixerStream *stream);
-static gboolean pulse_stream_set_fade (MateMixerStream *stream,
- gfloat fade);
-
-static gboolean pulse_stream_suspend (MateMixerStream *stream);
-static gboolean pulse_stream_resume (MateMixerStream *stream);
-static gboolean pulse_stream_monitor_start (MateMixerStream *stream);
-static void pulse_stream_monitor_stop (MateMixerStream *stream);
-static gboolean pulse_stream_monitor_is_running (MateMixerStream *stream);
-static gboolean pulse_stream_monitor_set_name (MateMixerStream *stream,
- const gchar *name);
-
-static const GList * pulse_stream_list_ports (MateMixerStream *stream);
-
-static MateMixerPort * pulse_stream_get_active_port (MateMixerStream *stream);
-static gboolean pulse_stream_set_active_port (MateMixerStream *stream,
- MateMixerPort *port);
-
-static guint pulse_stream_get_min_volume (MateMixerStream *stream);
-static guint pulse_stream_get_max_volume (MateMixerStream *stream);
-static guint pulse_stream_get_normal_volume (MateMixerStream *stream);
-static guint pulse_stream_get_base_volume (MateMixerStream *stream);
-
-static void on_monitor_value (PulseMonitor *monitor,
- gdouble value,
- PulseStream *pstream);
-
-static gboolean update_balance_fade (PulseStream *pstream);
-
-static gboolean set_cvolume (PulseStream *pstream,
- pa_cvolume *cvolume);
-
-static gint compare_ports (gconstpointer a,
- gconstpointer b);
-
-static void
-mate_mixer_stream_interface_init (MateMixerStreamInterface *iface)
-{
- iface->get_name = pulse_stream_get_name;
- iface->get_description = pulse_stream_get_description;
- iface->get_device = pulse_stream_get_device;
- iface->get_flags = pulse_stream_get_flags;
- iface->get_state = pulse_stream_get_state;
- iface->get_mute = pulse_stream_get_mute;
- iface->set_mute = pulse_stream_set_mute;
- iface->get_num_channels = pulse_stream_get_num_channels;
- iface->get_volume = pulse_stream_get_volume;
- iface->set_volume = pulse_stream_set_volume;
- iface->get_decibel = pulse_stream_get_decibel;
- iface->set_decibel = pulse_stream_set_decibel;
- iface->get_channel_volume = pulse_stream_get_channel_volume;
- iface->set_channel_volume = pulse_stream_set_channel_volume;
- iface->get_channel_decibel = pulse_stream_get_channel_decibel;
- iface->set_channel_decibel = pulse_stream_set_channel_decibel;
- iface->get_channel_position = pulse_stream_get_channel_position;
- iface->has_channel_position = pulse_stream_has_channel_position;
- iface->get_balance = pulse_stream_get_balance;
- iface->set_balance = pulse_stream_set_balance;
- iface->get_fade = pulse_stream_get_fade;
- iface->set_fade = pulse_stream_set_fade;
- iface->suspend = pulse_stream_suspend;
- iface->resume = pulse_stream_resume;
- iface->monitor_start = pulse_stream_monitor_start;
- iface->monitor_stop = pulse_stream_monitor_stop;
- iface->monitor_is_running = pulse_stream_monitor_is_running;
- iface->monitor_set_name = pulse_stream_monitor_set_name;
- iface->list_ports = pulse_stream_list_ports;
- iface->get_active_port = pulse_stream_get_active_port;
- iface->set_active_port = pulse_stream_set_active_port;
- iface->get_min_volume = pulse_stream_get_min_volume;
- iface->get_max_volume = pulse_stream_get_max_volume;
- iface->get_normal_volume = pulse_stream_get_normal_volume;
- iface->get_base_volume = pulse_stream_get_base_volume;
-}
+G_DEFINE_ABSTRACT_TYPE (PulseStream, pulse_stream, MATE_MIXER_TYPE_STREAM)
static void
pulse_stream_class_init (PulseStreamClass *klass)
{
- GObjectClass *object_class;
+ GObjectClass *object_class;
+ MateMixerStreamClass *stream_class;
object_class = G_OBJECT_CLASS (klass);
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_DEVICE, "device");
- g_object_class_override_property (object_class, PROP_FLAGS, "flags");
- g_object_class_override_property (object_class, PROP_STATE, "state");
- g_object_class_override_property (object_class, PROP_MUTE, "mute");
- g_object_class_override_property (object_class, PROP_VOLUME, "volume");
- 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");
+ stream_class = MATE_MIXER_STREAM_CLASS (klass);
+
+ properties[PROP_INDEX] =
+ g_param_spec_uint ("index",
+ "Index",
+ "Index of the stream",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_CONNECTION] =
+ g_param_spec_object ("connection",
+ "Connection",
+ "PulseAudio connection",
+ PULSE_TYPE_CONNECTION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
g_type_class_add_private (object_class, sizeof (PulseStreamPrivate));
}
@@ -261,46 +104,16 @@ pulse_stream_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
- PulseStream *pstream;
+ PulseStream *stream;
- pstream = PULSE_STREAM (object);
+ stream = PULSE_STREAM (object);
switch (param_id) {
- case PROP_NAME:
- g_value_set_string (value, pstream->priv->name);
- break;
- case PROP_DESCRIPTION:
- g_value_set_string (value, pstream->priv->description);
- break;
- case PROP_DEVICE:
- g_value_set_object (value, pstream->priv->device);
- break;
- case PROP_FLAGS:
- g_value_set_flags (value, pstream->priv->flags);
- break;
- case PROP_STATE:
- g_value_set_enum (value, pstream->priv->state);
- break;
- case PROP_MUTE:
- g_value_set_boolean (value, pstream->priv->mute);
- break;
- case PROP_VOLUME:
- g_value_set_uint (value, pstream->priv->volume);
- break;
- case PROP_BALANCE:
- g_value_set_float (value, pstream->priv->balance);
- break;
- case PROP_FADE:
- g_value_set_float (value, pstream->priv->fade);
- break;
- case PROP_ACTIVE_PORT:
- g_value_set_object (value, pstream->priv->port);
- break;
case PROP_INDEX:
- g_value_set_uint (value, pstream->priv->index);
+ g_value_set_uint (value, stream->priv->index);
break;
case PROP_CONNECTION:
- g_value_set_object (value, pstream->priv->connection);
+ g_value_set_object (value, stream->priv->connection);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -314,17 +127,16 @@ pulse_stream_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
- PulseStream *pstream;
+ PulseStream *stream;
- pstream = PULSE_STREAM (object);
+ stream = PULSE_STREAM (object);
switch (param_id) {
case PROP_INDEX:
- pstream->priv->index = g_value_get_uint (value);
+ stream->priv->index = g_value_get_uint (value);
break;
case PROP_CONNECTION:
- /* Construct-only object */
- pstream->priv->connection = g_value_dup_object (value);
+ stream->priv->connection = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -333,962 +145,51 @@ pulse_stream_set_property (GObject *object,
}
static void
-pulse_stream_init (PulseStream *pstream)
+pulse_stream_init (PulseStream *stream)
{
- pstream->priv = G_TYPE_INSTANCE_GET_PRIVATE (pstream,
- PULSE_TYPE_STREAM,
- PulseStreamPrivate);
-
- pstream->priv->ports = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- g_object_unref);
-
- /* Initialize empty volume and channel map structures, they will be used
- * if the stream does not support volume */
- pa_cvolume_init (&pstream->priv->cvolume);
-
- pa_channel_map_init (&pstream->priv->channel_map);
+ stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
+ PULSE_TYPE_STREAM,
+ PulseStreamPrivate);
}
static void
pulse_stream_dispose (GObject *object)
{
- PulseStream *pstream;
+ PulseStream *stream;
- pstream = PULSE_STREAM (object);
+ stream = PULSE_STREAM (object);
- if (pstream->priv->ports_list != NULL) {
- g_list_free_full (pstream->priv->ports_list, g_object_unref);
- pstream->priv->ports_list = NULL;
- }
- g_hash_table_remove_all (pstream->priv->ports);
-
- g_clear_object (&pstream->priv->port);
- g_clear_object (&pstream->priv->device);
- g_clear_object (&pstream->priv->monitor);
- g_clear_object (&pstream->priv->connection);
+ g_clear_object (&stream->priv->connection);
G_OBJECT_CLASS (pulse_stream_parent_class)->dispose (object);
}
-static void
-pulse_stream_finalize (GObject *object)
-{
- PulseStream *pstream;
-
- pstream = PULSE_STREAM (object);
-
- g_free (pstream->priv->name);
- g_free (pstream->priv->description);
- g_free (pstream->priv->monitor_name);
-
- g_hash_table_destroy (pstream->priv->ports);
-
- G_OBJECT_CLASS (pulse_stream_parent_class)->finalize (object);
-}
-
guint32
-pulse_stream_get_index (PulseStream *pstream)
+pulse_stream_get_index (PulseStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), 0);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
- return pstream->priv->index;
+ return stream->priv->index;
}
PulseConnection *
-pulse_stream_get_connection (PulseStream *pstream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
-
- return pstream->priv->connection;
-}
-
-PulseMonitor *
-pulse_stream_get_monitor (PulseStream *pstream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
-
- return pstream->priv->monitor;
-}
-
-const pa_cvolume *
-pulse_stream_get_cvolume (PulseStream *pstream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
-
- return &pstream->priv->cvolume;
-}
-
-const pa_channel_map *
-pulse_stream_get_channel_map (PulseStream *pstream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
-
- return &pstream->priv->channel_map;
-}
-
-GHashTable *
-pulse_stream_get_ports (PulseStream *pstream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
-
- return pstream->priv->ports;
-}
-
-gboolean
-pulse_stream_update_name (PulseStream *pstream, const gchar *name)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- /* Allow the name to be NULL */
- if (g_strcmp0 (name, pstream->priv->name) != 0) {
- g_free (pstream->priv->name);
- pstream->priv->name = g_strdup (name);
-
- g_object_notify (G_OBJECT (pstream), "name");
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-pulse_stream_update_description (PulseStream *pstream, const gchar *description)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- /* Allow the description to be NULL */
- if (g_strcmp0 (description, pstream->priv->description) != 0) {
- g_free (pstream->priv->description);
- pstream->priv->description = g_strdup (description);
-
- g_object_notify (G_OBJECT (pstream), "description");
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-pulse_stream_update_device (PulseStream *pstream, MateMixerDevice *device)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- if (pstream->priv->device != device) {
- g_clear_object (&pstream->priv->device);
-
- if (G_LIKELY (device != NULL))
- pstream->priv->device = g_object_ref (device);
-
- g_object_notify (G_OBJECT (pstream), "device");
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-pulse_stream_update_flags (PulseStream *pstream, MateMixerStreamFlags flags)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- if (pstream->priv->flags != flags) {
- pstream->priv->flags = flags;
-
- g_object_notify (G_OBJECT (pstream), "flags");
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-pulse_stream_update_state (PulseStream *pstream, MateMixerStreamState state)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- if (pstream->priv->state != state) {
- pstream->priv->state = state;
-
- g_object_notify (G_OBJECT (pstream), "state");
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-pulse_stream_update_channel_map (PulseStream *pstream, const pa_channel_map *map)
-{
- MateMixerStreamFlags flags;
-
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
- g_return_val_if_fail (map != NULL, FALSE);
-
- flags = pstream->priv->flags;
-
- if (pa_channel_map_valid (map)) {
- if (pa_channel_map_can_balance (map))
- flags |= MATE_MIXER_STREAM_CAN_BALANCE;
- else
- flags &= ~MATE_MIXER_STREAM_CAN_BALANCE;
-
- if (pa_channel_map_can_fade (map))
- flags |= MATE_MIXER_STREAM_CAN_FADE;
- else
- flags &= ~MATE_MIXER_STREAM_CAN_FADE;
-
- pstream->priv->channel_map = *map;
- } else {
- flags &= ~(MATE_MIXER_STREAM_CAN_BALANCE | MATE_MIXER_STREAM_CAN_FADE);
-
- /* If the channel map is not valid, create an empty channel map, which
- * also won't validate, but at least we know what it is */
- pa_channel_map_init (&pstream->priv->channel_map);
- }
-
- pulse_stream_update_flags (pstream, flags);
- return TRUE;
-}
-
-gboolean
-pulse_stream_update_volume (PulseStream *pstream,
- const pa_cvolume *cvolume,
- pa_volume_t base_volume)
-{
- MateMixerStreamFlags flags;
-
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- /* The base volume is not a property */
- pstream->priv->base_volume = base_volume;
-
- flags = pstream->priv->flags;
-
- if (cvolume != NULL && pa_cvolume_valid (cvolume)) {
- /* Decibel volume and volume settability flags must be provided by
- * the implementation */
- flags |= MATE_MIXER_STREAM_HAS_VOLUME;
-
- if (pa_cvolume_equal (&pstream->priv->cvolume, cvolume) == 0) {
- pstream->priv->cvolume = *cvolume;
- pstream->priv->volume = (guint) pa_cvolume_max (&pstream->priv->cvolume);
-
- g_object_notify (G_OBJECT (pstream), "volume");
- }
- } else {
- flags &= ~(MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME |
- MATE_MIXER_STREAM_CAN_SET_VOLUME);
-
- /* If the cvolume is not valid, create an empty cvolume, which also
- * won't validate, but at least we know what it is */
- pa_cvolume_init (&pstream->priv->cvolume);
-
- if (pstream->priv->volume != (guint) PA_VOLUME_MUTED) {
- pstream->priv->volume = (guint) PA_VOLUME_MUTED;
-
- g_object_notify (G_OBJECT (pstream), "volume");
- }
- }
-
- pulse_stream_update_flags (pstream, flags);
-
- /* Changing volume may change the balance and fade values as well */
- update_balance_fade (pstream);
- return TRUE;
-}
-
-gboolean
-pulse_stream_update_mute (PulseStream *pstream, gboolean mute)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
-
- if (pstream->priv->mute != mute) {
- pstream->priv->mute = mute;
-
- g_object_notify (G_OBJECT (pstream), "mute");
- return TRUE;
- }
- return FALSE;
-}
-
-gboolean
-pulse_stream_update_active_port (PulseStream *pstream, MateMixerPort *port)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
-
- if (pstream->priv->port != port) {
- if (pstream->priv->port != NULL)
- g_clear_object (&pstream->priv->port);
-
- if (port != NULL)
- pstream->priv->port = g_object_ref (port);
-
- g_object_notify (G_OBJECT (pstream), "active-port");
- return TRUE;
- }
- return FALSE;
-}
-
-static const gchar *
-pulse_stream_get_name (MateMixerStream *stream)
+pulse_stream_get_connection (PulseStream *stream)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
- return PULSE_STREAM (stream)->priv->name;
+ return stream->priv->connection;
}
-static const gchar *
-pulse_stream_get_description (MateMixerStream *stream)
+PulseDevice *
+pulse_stream_get_device (PulseStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
-
- return PULSE_STREAM (stream)->priv->description;
-}
+ MateMixerDevice *device;
-static MateMixerDevice *
-pulse_stream_get_device (MateMixerStream *stream)
-{
g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
- return PULSE_STREAM (stream)->priv->device;
-}
-
-static MateMixerStreamFlags
-pulse_stream_get_flags (MateMixerStream *stream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_STREAM_NO_FLAGS);
-
- return PULSE_STREAM (stream)->priv->flags;
-}
-
-static MateMixerStreamState
-pulse_stream_get_state (MateMixerStream *stream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_STREAM_STATE_UNKNOWN);
-
- return PULSE_STREAM (stream)->priv->state;
-}
-
-static gboolean
-pulse_stream_get_mute (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_MUTE))
- return FALSE;
-
- return pstream->priv->mute;
-}
-
-static gboolean
-pulse_stream_set_mute (MateMixerStream *stream, gboolean mute)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_MUTE))
- return FALSE;
-
- if (pstream->priv->mute != mute) {
- PulseStreamClass *klass = PULSE_STREAM_GET_CLASS (pstream);
-
- if (klass->set_mute (pstream, mute) == FALSE)
- return FALSE;
-
- pstream->priv->mute = mute;
-
- g_object_notify (G_OBJECT (stream), "mute");
- }
- return TRUE;
-}
-
-static guint
-pulse_stream_get_num_channels (MateMixerStream *stream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
-
- return PULSE_STREAM (stream)->priv->channel_map.channels;
-}
-
-static guint
-pulse_stream_get_volume (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
- return (guint) PA_VOLUME_MUTED;
-
- return pstream->priv->volume;
-}
-
-static gboolean
-pulse_stream_set_volume (MateMixerStream *stream, guint volume)
-{
- PulseStream *pstream;
- pa_cvolume cvolume;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SET_VOLUME))
- return FALSE;
-
- cvolume = pstream->priv->cvolume;
-
- if (pa_cvolume_scale (&cvolume, (pa_volume_t) volume) == NULL)
- return FALSE;
-
- return set_cvolume (pstream, &cvolume);
-}
-
-static gdouble
-pulse_stream_get_decibel (MateMixerStream *stream)
-{
- PulseStream *pstream;
- gdouble value;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), -MATE_MIXER_INFINITY);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
- return -MATE_MIXER_INFINITY;
-
- value = pa_sw_volume_to_dB (pulse_stream_get_volume (stream));
-
- /* PA_VOLUME_MUTED is converted to PA_DECIBEL_MININFTY */
- return (value == PA_DECIBEL_MININFTY) ? -MATE_MIXER_INFINITY : value;
-}
-
-static gboolean
-pulse_stream_set_decibel (MateMixerStream *stream, gdouble decibel)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME) ||
- !(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SET_VOLUME))
- return FALSE;
-
- return pulse_stream_set_volume (stream, pa_sw_volume_from_dB (decibel));
-}
-
-static guint
-pulse_stream_get_channel_volume (MateMixerStream *stream, guint channel)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
- return (guint) PA_VOLUME_MUTED;
-
- if (channel >= pstream->priv->cvolume.channels)
- return (guint) PA_VOLUME_MUTED;
-
- return (guint) pstream->priv->cvolume.values[channel];
-}
-
-static gboolean
-pulse_stream_set_channel_volume (MateMixerStream *stream, guint channel, guint volume)
-{
- PulseStream *pstream;
- pa_cvolume cvolume;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SET_VOLUME))
- return FALSE;
-
- if (channel >= pstream->priv->cvolume.channels)
- return FALSE;
-
- /* This is safe, because the cvolume is validated by set_cvolume() */
- cvolume = pstream->priv->cvolume;
- cvolume.values[channel] = (pa_volume_t) volume;
-
- return set_cvolume (pstream, &cvolume);
-}
-
-static gdouble
-pulse_stream_get_channel_decibel (MateMixerStream *stream, guint channel)
-{
- PulseStream *pstream;
- gdouble value;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), -MATE_MIXER_INFINITY);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
- return -MATE_MIXER_INFINITY;
-
- if (channel >= pstream->priv->cvolume.channels)
- return -MATE_MIXER_INFINITY;
-
- value = pa_sw_volume_to_dB (pstream->priv->cvolume.values[channel]);
-
- return (value == PA_DECIBEL_MININFTY) ? -MATE_MIXER_INFINITY : value;
-}
-
-static gboolean
-pulse_stream_set_channel_decibel (MateMixerStream *stream,
- guint channel,
- gdouble decibel)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME) ||
- !(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SET_VOLUME))
- return FALSE;
-
- return pulse_stream_set_channel_volume (stream, channel, pa_sw_volume_from_dB (decibel));
-}
-
-static MateMixerChannelPosition
-pulse_stream_get_channel_position (MateMixerStream *stream, guint channel)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_CHANNEL_UNKNOWN);
-
- pstream = PULSE_STREAM (stream);
-
- if (channel >= pstream->priv->channel_map.channels)
- return MATE_MIXER_CHANNEL_UNKNOWN;
-
- return pulse_convert_position_to_pulse (pstream->priv->channel_map.map[channel]);
-}
-
-static gboolean
-pulse_stream_has_channel_position (MateMixerStream *stream,
- MateMixerChannelPosition position)
-{
- PulseStream *pstream;
- pa_channel_position_t p;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- /* Handle invalid position as a special case, otherwise this function would
- * return TRUE for e.g. unknown index in a default channel map */
- p = pulse_convert_position_to_pulse (position);
-
- if (p == PA_CHANNEL_POSITION_INVALID)
- return FALSE;
-
- if (pa_channel_map_has_position (&pstream->priv->channel_map, p) != 0)
- return TRUE;
- else
- return FALSE;
-}
-
-static gfloat
-pulse_stream_get_balance (MateMixerStream *stream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0f);
-
- return PULSE_STREAM (stream)->priv->balance;
-}
-
-static gboolean
-pulse_stream_set_balance (MateMixerStream *stream, gfloat balance)
-{
- PulseStream *pstream;
- pa_cvolume cvolume;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_BALANCE))
- return FALSE;
-
- cvolume = pstream->priv->cvolume;
-
- if (pa_cvolume_set_balance (&cvolume, &pstream->priv->channel_map, balance) == NULL)
- return FALSE;
-
- return set_cvolume (pstream, &cvolume);
-}
-
-static gfloat
-pulse_stream_get_fade (MateMixerStream *stream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0f);
-
- return PULSE_STREAM (stream)->priv->fade;
-}
-
-static gboolean
-pulse_stream_set_fade (MateMixerStream *stream, gfloat fade)
-{
- PulseStream *pstream;
- pa_cvolume cvolume;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_FADE))
- return FALSE;
-
- cvolume = pstream->priv->cvolume;
-
- if (pa_cvolume_set_fade (&cvolume, &pstream->priv->channel_map, fade) == NULL)
- return FALSE;
-
- return set_cvolume (pstream, &cvolume);
-}
-
-static gboolean
-pulse_stream_suspend (MateMixerStream *stream)
-{
- PulseStream *pstream;
- PulseStreamClass *klass;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND))
- return FALSE;
-
- if (pstream->priv->state == MATE_MIXER_STREAM_STATE_SUSPENDED)
- return FALSE;
-
- klass = PULSE_STREAM_GET_CLASS (pstream);
-
- if (klass->suspend (pstream) == FALSE)
- return FALSE;
-
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_SUSPENDED);
- return TRUE;
-}
-
-static gboolean
-pulse_stream_resume (MateMixerStream *stream)
-{
- PulseStream *pstream;
- PulseStreamClass *klass;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND))
- return FALSE;
-
- if (pstream->priv->state != MATE_MIXER_STREAM_STATE_SUSPENDED)
- return FALSE;
-
- klass = PULSE_STREAM_GET_CLASS (pstream);
-
- if (klass->resume (pstream) == FALSE)
- return FALSE;
-
- /* The state when resumed should be either RUNNING or IDLE, let's assume
- * IDLE for now and request an immediate update */
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_IDLE);
-
- klass->reload (pstream);
- return TRUE;
-}
-
-static gboolean
-pulse_stream_monitor_start (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_MONITOR))
- return FALSE;
-
- if (pstream->priv->monitor == NULL) {
- pstream->priv->monitor = PULSE_STREAM_GET_CLASS (pstream)->create_monitor (pstream);
-
- if (G_UNLIKELY (pstream->priv->monitor == NULL))
- return FALSE;
-
- pulse_monitor_set_name (pstream->priv->monitor,
- pstream->priv->monitor_name);
-
- g_signal_connect (G_OBJECT (pstream->priv->monitor),
- "value",
- G_CALLBACK (on_monitor_value),
- pstream);
- }
-
- return pulse_monitor_set_enabled (pstream->priv->monitor, TRUE);
-}
-
-static void
-pulse_stream_monitor_stop (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_if_fail (PULSE_IS_STREAM (stream));
-
- pstream = PULSE_STREAM (stream);
-
- if (pstream->priv->monitor != NULL)
- pulse_monitor_set_enabled (pstream->priv->monitor, FALSE);
-}
-
-static gboolean
-pulse_stream_monitor_is_running (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (pstream->priv->monitor != NULL)
- return pulse_monitor_get_enabled (pstream->priv->monitor);
-
- return FALSE;
-}
-
-static gboolean
-pulse_stream_monitor_set_name (MateMixerStream *stream, const gchar *name)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- if (pstream->priv->monitor != NULL)
- pulse_monitor_set_name (pstream->priv->monitor, name);
-
- pstream->priv->monitor_name = g_strdup (name);
- return TRUE;
-}
-
-static const GList *
-pulse_stream_list_ports (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
-
- pstream = PULSE_STREAM (stream);
-
- if (pstream->priv->ports_list == NULL) {
- GList *list = g_hash_table_get_values (pstream->priv->ports);
-
- if (list != NULL) {
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- pstream->priv->ports_list = g_list_sort (list, compare_ports);
- }
- }
-
- return (const GList *) pstream->priv->ports_list;
-}
-
-static MateMixerPort *
-pulse_stream_get_active_port (MateMixerStream *stream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
-
- return PULSE_STREAM (stream)->priv->port;
-}
-
-static gboolean
-pulse_stream_set_active_port (MateMixerStream *stream, MateMixerPort *port)
-{
- PulseStream *pstream;
- PulseStreamClass *klass;
- const gchar *name;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
-
- pstream = PULSE_STREAM (stream);
-
- /* Make sure the port comes from this stream */
- name = mate_mixer_port_get_name (port);
-
- if (g_hash_table_lookup (pstream->priv->ports, name) == NULL) {
- g_warning ("Port %s does not belong to stream %s",
- mate_mixer_port_get_name (port),
- mate_mixer_stream_get_name (stream));
- return FALSE;
- }
-
- klass = PULSE_STREAM_GET_CLASS (pstream);
-
- /* Change the port */
- if (klass->set_active_port (pstream, port) == FALSE)
- return FALSE;
-
- if (pstream->priv->port != NULL)
- g_object_unref (pstream->priv->port);
-
- pstream->priv->port = g_object_ref (port);
-
- g_object_notify (G_OBJECT (stream), "active-port");
- return TRUE;
-}
-
-static guint
-pulse_stream_get_min_volume (MateMixerStream *stream)
-{
- return (guint) PA_VOLUME_MUTED;
-}
-
-static guint
-pulse_stream_get_max_volume (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
- return (guint) PA_VOLUME_MUTED;
-
- return (guint) PA_VOLUME_UI_MAX;
-}
-
-static guint
-pulse_stream_get_normal_volume (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
- return (guint) PA_VOLUME_MUTED;
-
- return (guint) PA_VOLUME_NORM;
-}
-
-static guint
-pulse_stream_get_base_volume (MateMixerStream *stream)
-{
- PulseStream *pstream;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
-
- pstream = PULSE_STREAM (stream);
-
- if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
- return (guint) PA_VOLUME_MUTED;
-
- if (pstream->priv->base_volume > 0)
- return pstream->priv->base_volume;
- else
- return (guint) PA_VOLUME_NORM;
-}
-
-static void
-on_monitor_value (PulseMonitor *monitor, gdouble value, PulseStream *pstream)
-{
- g_signal_emit_by_name (G_OBJECT (pstream),
- "monitor-value",
- value);
-}
-
-static gboolean
-update_balance_fade (PulseStream *pstream)
-{
- gfloat fade;
- gfloat balance;
- gboolean changed = FALSE;
-
- /* The PulseAudio return the default 0.0f values on errors, so skip checking
- * validity of the channel map and volume */
- balance = pa_cvolume_get_balance (&pstream->priv->cvolume,
- &pstream->priv->channel_map);
-
- if (pstream->priv->balance != balance) {
- pstream->priv->balance = balance;
-
- g_object_notify (G_OBJECT (pstream), "balance");
- changed = TRUE;
- }
-
- fade = pa_cvolume_get_fade (&pstream->priv->cvolume,
- &pstream->priv->channel_map);
-
- if (pstream->priv->fade != fade) {
- pstream->priv->fade = fade;
-
- g_object_notify (G_OBJECT (pstream), "fade");
- changed = TRUE;
- }
-
- return changed;
-}
-
-static gboolean
-set_cvolume (PulseStream *pstream, pa_cvolume *cvolume)
-{
- PulseStreamClass *klass;
-
- if (pa_cvolume_valid (cvolume) == 0)
- return FALSE;
- if (pa_cvolume_equal (cvolume, &pstream->priv->cvolume) != 0)
- return TRUE;
-
- klass = PULSE_STREAM_GET_CLASS (pstream);
-
- if (klass->set_volume (pstream, cvolume) == FALSE)
- return FALSE;
-
- pstream->priv->cvolume = *cvolume;
- pstream->priv->volume = (guint) pa_cvolume_max (cvolume);
-
- g_object_notify (G_OBJECT (pstream), "volume");
-
- /* Changing volume may change the balance and fade values as well */
- update_balance_fade (pstream);
- return TRUE;
-}
-
-static gint
-compare_ports (gconstpointer a, gconstpointer b)
-{
- MateMixerPort *p1 = MATE_MIXER_PORT (a);
- MateMixerPort *p2 = MATE_MIXER_PORT (b);
+ device = mate_mixer_stream_get_device (MATE_MIXER_STREAM (stream));
+ if (device != NULL)
+ return PULSE_DEVICE (device);
- gint ret = (gint) (mate_mixer_port_get_priority (p2) -
- mate_mixer_port_get_priority (p1));
- if (ret != 0)
- return ret;
- else
- return strcmp (mate_mixer_port_get_name (p1),
- mate_mixer_port_get_name (p2));
+ return NULL;
}
diff --git a/backends/pulse/pulse-stream.h b/backends/pulse/pulse-stream.h
index e4c6a00..eafe457 100644
--- a/backends/pulse/pulse-stream.h
+++ b/backends/pulse/pulse-stream.h
@@ -20,15 +20,11 @@
#include <glib.h>
#include <glib-object.h>
-
-#include <libmatemixer/matemixer-device.h>
-#include <libmatemixer/matemixer-port.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
#include <pulse/pulseaudio.h>
-#include "pulse-connection.h"
-#include "pulse-monitor.h"
+#include "pulse-types.h"
G_BEGIN_DECLS
@@ -45,13 +41,12 @@ G_BEGIN_DECLS
#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;
+ MateMixerStream parent;
/*< private >*/
PulseStreamPrivate *priv;
@@ -59,58 +54,15 @@ struct _PulseStream
struct _PulseStreamClass
{
- GObjectClass parent_class;
-
- /*< private >*/
- /* Virtual table */
- void (*reload) (PulseStream *stream);
-
- gboolean (*set_mute) (PulseStream *stream,
- gboolean mute);
- gboolean (*set_volume) (PulseStream *stream,
- pa_cvolume *volume);
-
- gboolean (*set_active_port) (PulseStream *stream,
- MateMixerPort *port);
-
- gboolean (*suspend) (PulseStream *stream);
- gboolean (*resume) (PulseStream *stream);
-
- PulseMonitor *(*create_monitor) (PulseStream *stream);
+ MateMixerStreamClass parent_class;
};
-GType pulse_stream_get_type (void) G_GNUC_CONST;
-
-guint32 pulse_stream_get_index (PulseStream *pstream);
-PulseConnection * pulse_stream_get_connection (PulseStream *pstream);
-PulseMonitor * pulse_stream_get_monitor (PulseStream *pstream);
-GHashTable * pulse_stream_get_ports (PulseStream *pstream);
-
-const pa_cvolume * pulse_stream_get_cvolume (PulseStream *pstream);
-const pa_channel_map *pulse_stream_get_channel_map (PulseStream *pstream);
-
-gboolean pulse_stream_update_name (PulseStream *pstream,
- const gchar *name);
-gboolean pulse_stream_update_description (PulseStream *pstream,
- const gchar *description);
-gboolean pulse_stream_update_device (PulseStream *pstream,
- MateMixerDevice *device);
-gboolean pulse_stream_update_flags (PulseStream *pstream,
- MateMixerStreamFlags flags);
-gboolean pulse_stream_update_state (PulseStream *pstream,
- MateMixerStreamState state);
-
-gboolean pulse_stream_update_channel_map (PulseStream *pstream,
- const pa_channel_map *map);
-gboolean pulse_stream_update_volume (PulseStream *pstream,
- const pa_cvolume *volume,
- pa_volume_t base_volume);
+GType pulse_stream_get_type (void) G_GNUC_CONST;
-gboolean pulse_stream_update_mute (PulseStream *pstream,
- gboolean mute);
+guint32 pulse_stream_get_index (PulseStream *stream);
+PulseConnection *pulse_stream_get_connection (PulseStream *stream);
-gboolean pulse_stream_update_active_port (PulseStream *pstream,
- MateMixerPort *port);
+PulseDevice * pulse_stream_get_device (PulseStream *stream);
G_END_DECLS
diff --git a/backends/pulse/pulse-types.h b/backends/pulse/pulse-types.h
new file mode 100644
index 0000000..c664268
--- /dev/null
+++ b/backends/pulse/pulse-types.h
@@ -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/>.
+ */
+
+#ifndef PULSE_TYPES_H
+#define PULSE_TYPES_H
+
+G_BEGIN_DECLS
+
+typedef struct _PulseBackend PulseBackend;
+typedef struct _PulseConnection PulseConnection;
+typedef struct _PulseDevice PulseDevice;
+typedef struct _PulseDeviceProfile PulseDeviceProfile;
+typedef struct _PulseDeviceSwitch PulseDeviceSwitch;
+typedef struct _PulseExtStream PulseExtStream;
+typedef struct _PulseMonitor PulseMonitor;
+typedef struct _PulsePort PulsePort;
+typedef struct _PulsePortSwitch PulsePortSwitch;
+typedef struct _PulseSink PulseSink;
+typedef struct _PulseSinkControl PulseSinkControl;
+typedef struct _PulseSinkInput PulseSinkInput;
+typedef struct _PulseSinkSwitch PulseSinkSwitch;
+typedef struct _PulseSource PulseSource;
+typedef struct _PulseSourceControl PulseSourceControl;
+typedef struct _PulseSourceOutput PulseSourceOutput;
+typedef struct _PulseSourceSwitch PulseSourceSwitch;
+typedef struct _PulseStream PulseStream;
+typedef struct _PulseStreamControl PulseStreamControl;
+
+G_END_DECLS
+
+#endif /* PULSE_TYPES_H */