summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/null/null-backend.c16
-rw-r--r--backends/null/null-backend.h6
-rw-r--r--backends/pulse/Makefile.am2
-rw-r--r--backends/pulse/pulse-backend.c354
-rw-r--r--backends/pulse/pulse-backend.h12
-rw-r--r--backends/pulse/pulse-client-stream.c263
-rw-r--r--backends/pulse/pulse-client-stream.h28
-rw-r--r--backends/pulse/pulse-connection.c633
-rw-r--r--backends/pulse/pulse-connection.h204
-rw-r--r--backends/pulse/pulse-device.c402
-rw-r--r--backends/pulse/pulse-device.h3
-rw-r--r--backends/pulse/pulse-helpers.h2
-rw-r--r--backends/pulse/pulse-monitor.c271
-rw-r--r--backends/pulse/pulse-monitor.h79
-rw-r--r--backends/pulse/pulse-sink-input.c223
-rw-r--r--backends/pulse/pulse-sink-input.h21
-rw-r--r--backends/pulse/pulse-sink.c246
-rw-r--r--backends/pulse/pulse-sink.h20
-rw-r--r--backends/pulse/pulse-source-output.c198
-rw-r--r--backends/pulse/pulse-source-output.h12
-rw-r--r--backends/pulse/pulse-source.c170
-rw-r--r--backends/pulse/pulse-source.h10
-rw-r--r--backends/pulse/pulse-stream.c479
-rw-r--r--backends/pulse/pulse-stream.h91
-rw-r--r--configure.ac3
-rw-r--r--docs/reference/Makefile.am2
-rw-r--r--docs/reference/libmatemixer-docs.xml1
-rw-r--r--docs/reference/libmatemixer-sections.txt57
-rw-r--r--examples/monitor.c137
-rw-r--r--libmatemixer/Makefile.am2
-rw-r--r--libmatemixer/matemixer-backend-module.c193
-rw-r--r--libmatemixer/matemixer-backend-module.h7
-rw-r--r--libmatemixer/matemixer-backend.c179
-rw-r--r--libmatemixer/matemixer-backend.h15
-rw-r--r--libmatemixer/matemixer-client-stream.c173
-rw-r--r--libmatemixer/matemixer-client-stream.h31
-rw-r--r--libmatemixer/matemixer-control.c857
-rw-r--r--libmatemixer/matemixer-control.h14
-rw-r--r--libmatemixer/matemixer-device.c52
-rw-r--r--libmatemixer/matemixer-device.h8
-rw-r--r--libmatemixer/matemixer-enum-types.c23
-rw-r--r--libmatemixer/matemixer-enum-types.h8
-rw-r--r--libmatemixer/matemixer-enums.h39
-rw-r--r--libmatemixer/matemixer-port.c183
-rw-r--r--libmatemixer/matemixer-port.h33
-rw-r--r--libmatemixer/matemixer-profile.c115
-rw-r--r--libmatemixer/matemixer-profile.h11
-rw-r--r--libmatemixer/matemixer-stream.c173
-rw-r--r--libmatemixer/matemixer-stream.h26
-rw-r--r--libmatemixer/matemixer-version.h (renamed from libmatemixer/matemixer-version.h.in)32
-rw-r--r--libmatemixer/matemixer.c6
-rw-r--r--libmatemixer/matemixer.h6
52 files changed, 4023 insertions, 2108 deletions
diff --git a/backends/null/null-backend.c b/backends/null/null-backend.c
index f8c22c8..46c5fbf 100644
--- a/backends/null/null-backend.c
+++ b/backends/null/null-backend.c
@@ -15,11 +15,14 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+// XXX implement properties from MateMixerBackend
+
#include <glib.h>
#include <glib-object.h>
#include <libmatemixer/matemixer-backend.h>
#include <libmatemixer/matemixer-backend-module.h>
+#include <libmatemixer/matemixer-enums.h>
#include "null-backend.h"
@@ -28,17 +31,17 @@
static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface);
+static void null_backend_class_init (NullBackendClass *klass);
+static void null_backend_class_finalize (NullBackendClass *klass);
+static void null_backend_init (NullBackend *null);
+
G_DEFINE_DYNAMIC_TYPE_EXTENDED (NullBackend, null_backend,
G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE_DYNAMIC (MATE_MIXER_TYPE_BACKEND,
mate_mixer_backend_interface_init))
-static void null_backend_class_init (NullBackendClass *klass);
-static void null_backend_class_finalize (NullBackendClass *klass);
-static void null_backend_init (NullBackend *null);
-
-static gboolean backend_open (MateMixerBackend *backend);
-static MateMixerState backend_get_state (MateMixerBackend *backend);
+static gboolean backend_open (MateMixerBackend *backend);
+static MateMixerState backend_get_state (MateMixerBackend *backend);
static MateMixerBackendInfo info;
@@ -69,7 +72,6 @@ mate_mixer_backend_interface_init (MateMixerBackendInterface *iface)
static void
null_backend_class_init (NullBackendClass *klass)
{
- // XXX is it needed to have this function? shouldn't it call parent method if empty?
}
/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE_EXTENDED() */
diff --git a/backends/null/null-backend.h b/backends/null/null-backend.h
index 2d718e3..ae5f087 100644
--- a/backends/null/null-backend.h
+++ b/backends/null/null-backend.h
@@ -32,7 +32,7 @@
#define NULL_BACKEND_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), NULL_TYPE_BACKEND, NullBackendClass))
#define NULL_IS_BACKEND_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), NULL_TYPE_BACKEND))
+ (G_TYPE_CHECK_CLASS_TYPE ((k), NULL_TYPE_BACKEND))
#define NULL_BACKEND_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), NULL_TYPE_BACKEND, NullBackendClass))
@@ -41,14 +41,12 @@ typedef struct _NullBackendClass NullBackendClass;
struct _NullBackend
{
- /*< private >*/
GObject parent;
};
struct _NullBackendClass
{
- /*< private >*/
- GObjectClass parent;
+ GObjectClass parent_class;
};
GType null_backend_get_type (void) G_GNUC_CONST;
diff --git a/backends/pulse/Makefile.am b/backends/pulse/Makefile.am
index fe0d459..3b632a5 100644
--- a/backends/pulse/Makefile.am
+++ b/backends/pulse/Makefile.am
@@ -24,6 +24,8 @@ libmatemixer_pulse_la_SOURCES = \
pulse-enum-types.h \
pulse-helpers.c \
pulse-helpers.h \
+ pulse-monitor.c \
+ pulse-monitor.h \
pulse-stream.c \
pulse-stream.h \
pulse-sink.c \
diff --git a/backends/pulse/pulse-backend.c b/backends/pulse/pulse-backend.c
index 79a69a0..8ed7342 100644
--- a/backends/pulse/pulse-backend.c
+++ b/backends/pulse/pulse-backend.c
@@ -21,6 +21,7 @@
#include <libmatemixer/matemixer-backend.h>
#include <libmatemixer/matemixer-backend-module.h>
+#include <libmatemixer/matemixer-stream.h>
#include <pulse/pulseaudio.h>
@@ -44,10 +45,11 @@ struct _PulseBackendPrivate
gchar *app_version;
gchar *app_icon;
gchar *server_address;
- gchar *default_sink;
- gchar *default_source;
+ gboolean connected_once;
+ GSource *connect_source;
+ MateMixerStream *default_sink;
+ MateMixerStream *default_source;
GHashTable *devices;
- GHashTable *cards;
GHashTable *sinks;
GHashTable *sink_inputs;
GHashTable *sources;
@@ -59,11 +61,25 @@ struct _PulseBackendPrivate
enum {
PROP_0,
PROP_STATE,
+ PROP_DEFAULT_INPUT,
+ PROP_DEFAULT_OUTPUT,
N_PROPERTIES
};
static void mate_mixer_backend_interface_init (MateMixerBackendInterface *iface);
+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,
@@ -127,10 +143,18 @@ static void backend_source_output_removed_cb (PulseConnection
guint index,
PulseBackend *pulse);
+static gboolean backend_try_reconnect (PulseBackend *pulse);
+static void backend_remove_connect_source (PulseBackend *pulse);
+static void backend_change_state (PulseBackend *backend,
+ MateMixerState state);
+
static gint backend_compare_devices (gconstpointer a,
gconstpointer b);
static gint backend_compare_streams (gconstpointer a,
gconstpointer b);
+static gboolean backend_compare_stream_name (gpointer key,
+ gpointer value,
+ gpointer user_data);
static MateMixerBackendInfo info;
@@ -167,6 +191,29 @@ mate_mixer_backend_interface_init (MateMixerBackendInterface *iface)
}
static void
+pulse_backend_class_init (PulseBackendClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_backend_dispose;
+ object_class->finalize = pulse_backend_finalize;
+ object_class->get_property = pulse_backend_get_property;
+
+ g_object_class_override_property (object_class, PROP_STATE, "state");
+ g_object_class_override_property (object_class, PROP_DEFAULT_INPUT, "default-input");
+ g_object_class_override_property (object_class, PROP_DEFAULT_OUTPUT, "default-output");
+
+ g_type_class_add_private (object_class, sizeof (PulseBackendPrivate));
+}
+
+/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE_EXTENDED() */
+static void
+pulse_backend_class_finalize (PulseBackendClass *klass)
+{
+}
+
+static void
pulse_backend_get_property (GObject *object,
guint param_id,
GValue *value,
@@ -180,6 +227,12 @@ pulse_backend_get_property (GObject *object,
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;
@@ -192,16 +245,12 @@ pulse_backend_init (PulseBackend *pulse)
pulse->priv = G_TYPE_INSTANCE_GET_PRIVATE (pulse,
PULSE_TYPE_BACKEND,
PulseBackendPrivate);
+
pulse->priv->devices =
g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL,
g_object_unref);
- pulse->priv->cards =
- g_hash_table_new_full (g_direct_hash,
- g_direct_equal,
- NULL,
- g_object_unref);
pulse->priv->sinks =
g_hash_table_new_full (g_direct_hash,
g_direct_equal,
@@ -227,41 +276,7 @@ pulse_backend_init (PulseBackend *pulse)
static void
pulse_backend_dispose (GObject *object)
{
- PulseBackend *pulse;
-
- pulse = PULSE_BACKEND (object);
-
- if (pulse->priv->devices) {
- g_hash_table_destroy (pulse->priv->devices);
- pulse->priv->devices = NULL;
- }
-
- if (pulse->priv->cards) {
- g_hash_table_destroy (pulse->priv->cards);
- pulse->priv->cards = NULL;
- }
-
- if (pulse->priv->sinks) {
- g_hash_table_destroy (pulse->priv->sinks);
- pulse->priv->devices = NULL;
- }
-
- if (pulse->priv->sink_inputs) {
- g_hash_table_destroy (pulse->priv->sink_inputs);
- pulse->priv->devices = NULL;
- }
-
- if (pulse->priv->sources) {
- g_hash_table_destroy (pulse->priv->sources);
- pulse->priv->devices = NULL;
- }
-
- if (pulse->priv->source_outputs) {
- g_hash_table_destroy (pulse->priv->source_outputs);
- pulse->priv->source_outputs = NULL;
- }
-
- g_clear_object (&pulse->priv->connection);
+ backend_close (MATE_MIXER_BACKEND (object));
G_OBJECT_CLASS (pulse_backend_parent_class)->dispose (object);
}
@@ -282,27 +297,6 @@ pulse_backend_finalize (GObject *object)
G_OBJECT_CLASS (pulse_backend_parent_class)->finalize (object);
}
-static void
-pulse_backend_class_init (PulseBackendClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = pulse_backend_dispose;
- object_class->finalize = pulse_backend_finalize;
- object_class->get_property = pulse_backend_get_property;
-
- g_object_class_override_property (object_class, PROP_STATE, "state");
-
- g_type_class_add_private (klass, sizeof (PulseBackendPrivate));
-}
-
-/* Called in the code generated by G_DEFINE_DYNAMIC_TYPE_EXTENDED() */
-static void
-pulse_backend_class_finalize (PulseBackendClass *klass)
-{
-}
-
static gboolean
backend_open (MateMixerBackend *backend)
{
@@ -321,6 +315,10 @@ backend_open (MateMixerBackend *backend)
pulse->priv->app_version,
pulse->priv->app_icon,
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)) {
pulse->priv->state = MATE_MIXER_STATE_FAILED;
return FALSE;
@@ -375,6 +373,8 @@ backend_open (MateMixerBackend *backend)
G_CALLBACK (backend_source_output_removed_cb),
pulse);
+ /* Connect to the PulseAudio server, this might fail either instantly or
+ * asynchronously, for example when remote connection timeouts */
if (!pulse_connection_connect (connection)) {
pulse->priv->state = MATE_MIXER_STATE_FAILED;
g_object_unref (connection);
@@ -388,9 +388,48 @@ backend_open (MateMixerBackend *backend)
static void
backend_close (MateMixerBackend *backend)
{
+ PulseBackend *pulse;
+
g_return_if_fail (PULSE_IS_BACKEND (backend));
- g_clear_object (&PULSE_BACKEND (backend)->priv->connection);
+ pulse = PULSE_BACKEND (backend);
+
+ if (pulse->priv->connection) {
+ g_signal_handlers_disconnect_by_data (pulse->priv->connection, pulse);
+
+ pulse_connection_disconnect (pulse->priv->connection);
+ g_clear_object (&pulse->priv->connection);
+ }
+
+ if (pulse->priv->devices) {
+ g_hash_table_destroy (pulse->priv->devices);
+ pulse->priv->devices = NULL;
+ }
+
+ if (pulse->priv->sinks) {
+ g_hash_table_destroy (pulse->priv->sinks);
+ pulse->priv->sinks = NULL;
+ }
+
+ if (pulse->priv->sink_inputs) {
+ g_hash_table_destroy (pulse->priv->sink_inputs);
+ pulse->priv->sink_inputs = NULL;
+ }
+
+ if (pulse->priv->sources) {
+ g_hash_table_destroy (pulse->priv->sources);
+ pulse->priv->sources = NULL;
+ }
+
+ if (pulse->priv->source_outputs) {
+ g_hash_table_destroy (pulse->priv->source_outputs);
+ pulse->priv->source_outputs = NULL;
+ }
+
+ g_clear_object (&pulse->priv->default_sink);
+ g_clear_object (&pulse->priv->default_source);
+
+ backend_change_state (pulse, MATE_MIXER_STATE_IDLE);
}
static MateMixerState
@@ -406,18 +445,19 @@ backend_set_data (MateMixerBackend *backend, const MateMixerBackendData *data)
{
PulseBackend *pulse;
- if (data == NULL)
- return;
-
g_return_if_fail (PULSE_IS_BACKEND (backend));
pulse = PULSE_BACKEND (backend);
- g_free (data->app_name);
- g_free (data->app_id);
- g_free (data->app_version);
- g_free (data->app_icon);
- g_free (data->server_address);
+ g_clear_pointer (&pulse->priv->app_name, g_free);
+ g_clear_pointer (&pulse->priv->app_id, g_free);
+ g_clear_pointer (&pulse->priv->app_version, g_free);
+ g_clear_pointer (&pulse->priv->app_icon, g_free);
+ g_clear_pointer (&pulse->priv->server_address, g_free);
+
+ /* Allow to unset the details by passing NULL data */
+ if (G_UNLIKELY (data == NULL))
+ return;
pulse->priv->app_name = g_strdup (data->app_name);
pulse->priv->app_id = g_strdup (data->app_id);
@@ -433,6 +473,7 @@ backend_list_devices (MateMixerBackend *backend)
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
+ /* Always create a new current list, caching is done in the main library */
list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->devices);
g_list_foreach (list, (GFunc) g_object_ref, NULL);
@@ -450,6 +491,7 @@ backend_list_streams (MateMixerBackend *backend)
pulse = PULSE_BACKEND (backend);
+ /* Always create a new current list, caching is done in the main library */
list = g_list_concat (g_hash_table_get_values (pulse->priv->sinks),
g_hash_table_get_values (pulse->priv->sink_inputs));
list = g_list_concat (list,
@@ -465,7 +507,9 @@ backend_list_streams (MateMixerBackend *backend)
static MateMixerStream *
backend_get_default_input_stream (MateMixerBackend *backend)
{
- return NULL;
+ g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
+
+ return PULSE_BACKEND (backend)->priv->default_source;
}
static gboolean
@@ -473,8 +517,8 @@ backend_set_default_input_stream (MateMixerBackend *backend, MateMixerStream *st
{
PulseBackend *pulse;
- g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
- g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
+ g_return_val_if_fail (PULSE_IS_BACKEND (backend), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
pulse = PULSE_BACKEND (backend);
@@ -485,7 +529,9 @@ backend_set_default_input_stream (MateMixerBackend *backend, MateMixerStream *st
static MateMixerStream *
backend_get_default_output_stream (MateMixerBackend *backend)
{
- return NULL;
+ g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
+
+ return PULSE_BACKEND (backend)->priv->default_sink;
}
static gboolean
@@ -493,8 +539,8 @@ backend_set_default_output_stream (MateMixerBackend *backend, MateMixerStream *s
{
PulseBackend *pulse;
- g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
- g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
+ g_return_val_if_fail (PULSE_IS_BACKEND (backend), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
pulse = PULSE_BACKEND (backend);
@@ -511,17 +557,39 @@ backend_connection_state_cb (PulseConnection *connection,
switch (state) {
case PULSE_CONNECTION_DISCONNECTED:
+ if (pulse->priv->connected_once) {
+ /* We managed to connect once before, try to reconnect and if it
+ * fails immediately, use an idle source;
+ * in case the idle source already exists, just let it try again */
+ if (!pulse->priv->connect_source &&
+ !pulse_connection_connect (connection)) {
+ pulse->priv->connect_source = g_idle_source_new ();
+
+ g_source_set_callback (pulse->priv->connect_source,
+ (GSourceFunc) backend_try_reconnect,
+ pulse,
+ (GDestroyNotify) backend_remove_connect_source);
+
+ g_source_attach (pulse->priv->connect_source,
+ g_main_context_get_thread_default ());
+ }
+ break;
+ }
+
+ /* First connection attempt has failed */
+ backend_change_state (pulse, MATE_MIXER_STATE_FAILED);
break;
+
case PULSE_CONNECTION_CONNECTING:
- break;
case PULSE_CONNECTION_AUTHORIZING:
- break;
case PULSE_CONNECTION_LOADING:
+ backend_change_state (pulse, MATE_MIXER_STATE_CONNECTING);
break;
+
case PULSE_CONNECTION_CONNECTED:
- pulse->priv->state = MATE_MIXER_STATE_READY;
+ pulse->priv->connected_once = TRUE;
- g_object_notify (G_OBJECT (pulse), "state");
+ backend_change_state (pulse, MATE_MIXER_STATE_READY);
break;
}
}
@@ -531,21 +599,64 @@ backend_server_info_cb (PulseConnection *connection,
const pa_server_info *info,
PulseBackend *pulse)
{
- // XXX add property
-
- if (g_strcmp0 (pulse->priv->default_sink, info->default_sink_name)) {
- g_free (pulse->priv->default_sink);
-
- pulse->priv->default_sink = g_strdup (info->default_sink_name);
- // g_object_notify (G_OBJECT (pulse), "default-output");
+ const gchar *name_source = NULL;
+ const gchar *name_sink = NULL;
+
+ if (pulse->priv->default_source)
+ name_source = mate_mixer_stream_get_name (pulse->priv->default_source);
+ if (pulse->priv->default_sink)
+ name_sink = mate_mixer_stream_get_name (pulse->priv->default_sink);
+
+ if (g_strcmp0 (name_source, info->default_source_name)) {
+ if (pulse->priv->default_source)
+ g_clear_object (&pulse->priv->default_source);
+
+ if (info->default_source_name != NULL) {
+ MateMixerStream *stream = g_hash_table_find (pulse->priv->sources,
+ backend_compare_stream_name,
+ (gpointer) info->default_source_name);
+
+ /* It is theoretically possible to receive a server info notification
+ * before the stream lists are fully downloaded, this should not be
+ * a problem as a newer notification will arrive later after the
+ * streams are read.
+ * Of course this will only work if Pulse delivers notifications in
+ * the correct order, but it seems it does. */
+ if (G_LIKELY (stream != NULL)) {
+ pulse->priv->default_source = g_object_ref (stream);
+ g_debug ("Default input stream changed to %s", info->default_source_name);
+
+ g_object_notify (G_OBJECT (pulse), "default-output");
+ } else
+ g_debug ("Default input stream %s not yet known",
+ info->default_source_name);
+ }
}
- if (g_strcmp0 (pulse->priv->default_source, info->default_source_name)) {
- g_free (pulse->priv->default_source);
-
- pulse->priv->default_source = g_strdup (info->default_source_name);
- // g_object_notify (G_OBJECT (pulse), "default-input");
+ if (g_strcmp0 (name_sink, info->default_sink_name)) {
+ if (pulse->priv->default_sink)
+ g_clear_object (&pulse->priv->default_sink);
+
+ if (info->default_sink_name != NULL) {
+ MateMixerStream *stream = g_hash_table_find (pulse->priv->sinks,
+ backend_compare_stream_name,
+ (gpointer) info->default_sink_name);
+ if (G_LIKELY (stream != NULL)) {
+ pulse->priv->default_sink = g_object_ref (stream);
+ g_debug ("Default output stream changed to %s", info->default_sink_name);
+
+ g_object_notify (G_OBJECT (pulse), "default-output");
+ } else
+ g_debug ("Default output stream %s not yet known",
+ info->default_sink_name);
+ }
}
+
+ if (pulse->priv->state != MATE_MIXER_STATE_READY)
+ g_debug ("Sound server is %s version %s, running on %s",
+ info->server_name,
+ info->server_version,
+ info->host_name);
}
static void
@@ -557,12 +668,12 @@ backend_card_info_cb (PulseConnection *connection,
p = g_hash_table_lookup (pulse->priv->devices, GINT_TO_POINTER (info->index));
if (!p) {
- PulseDevice *device;
+ PulseDevice *device = pulse_device_new (connection, info);
- device = pulse_device_new (connection, info);
g_hash_table_insert (pulse->priv->devices,
GINT_TO_POINTER (pulse_device_get_index (device)),
device);
+
g_signal_emit_by_name (G_OBJECT (pulse),
"device-added",
mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
@@ -606,9 +717,8 @@ backend_sink_info_cb (PulseConnection *connection,
p = g_hash_table_lookup (pulse->priv->sinks, GINT_TO_POINTER (info->index));
if (!p) {
- PulseStream *stream;
+ PulseStream *stream = pulse_sink_new (connection, info);
- stream = pulse_sink_new (connection, info);
g_hash_table_insert (pulse->priv->sinks,
GINT_TO_POINTER (pulse_stream_get_index (stream)),
stream);
@@ -653,12 +763,15 @@ backend_sink_input_info_cb (PulseConnection *connection,
PulseBackend *pulse)
{
gpointer p;
+ gpointer parent;
+
+ parent = g_hash_table_lookup (pulse->priv->sinks, GINT_TO_POINTER (info->sink));
p = g_hash_table_lookup (pulse->priv->sink_inputs, GINT_TO_POINTER (info->index));
if (!p) {
PulseStream *stream;
- stream = pulse_sink_input_new (connection, info);
+ stream = pulse_sink_input_new (connection, info, parent);
g_hash_table_insert (pulse->priv->sink_inputs,
GINT_TO_POINTER (pulse_stream_get_index (stream)),
stream);
@@ -667,7 +780,7 @@ backend_sink_input_info_cb (PulseConnection *connection,
"stream-added",
mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
} else {
- pulse_sink_input_update (p, info);
+ pulse_sink_input_update (p, info, parent);
g_signal_emit_by_name (G_OBJECT (pulse),
"stream-changed",
@@ -708,6 +821,9 @@ backend_source_info_cb (PulseConnection *connection,
if (!p) {
PulseStream *stream;
+ if (info->monitor_of_sink != PA_INVALID_INDEX)
+ return;
+
stream = pulse_source_new (connection, info);
g_hash_table_insert (pulse->priv->sources,
GINT_TO_POINTER (pulse_stream_get_index (stream)),
@@ -733,6 +849,8 @@ backend_source_removed_cb (PulseConnection *connection,
gpointer p;
gchar *name;
+ // XXX set parent
+
p = g_hash_table_lookup (pulse->priv->sources, GINT_TO_POINTER (index));
if (G_UNLIKELY (p == NULL))
return;
@@ -797,6 +915,32 @@ backend_source_output_removed_cb (PulseConnection *connection,
g_free (name);
}
+static gboolean
+backend_try_reconnect (PulseBackend *pulse)
+{
+ /* When the connect call succeeds, return FALSE to remove the idle source
+ * and wait for the connection state notifications, otherwise this function
+ * will be called again */
+ return !pulse_connection_connect (pulse->priv->connection);
+}
+
+static void
+backend_remove_connect_source (PulseBackend *pulse)
+{
+ g_clear_pointer (&pulse->priv->connect_source, g_source_unref);
+}
+
+static void
+backend_change_state (PulseBackend *backend, MateMixerState state)
+{
+ if (backend->priv->state == state)
+ return;
+
+ backend->priv->state = state;
+
+ g_object_notify (G_OBJECT (backend), "state");
+}
+
static gint
backend_compare_devices (gconstpointer a, gconstpointer b)
{
@@ -810,3 +954,11 @@ backend_compare_streams (gconstpointer a, gconstpointer b)
return strcmp (mate_mixer_stream_get_name (MATE_MIXER_STREAM (a)),
mate_mixer_stream_get_name (MATE_MIXER_STREAM (b)));
}
+
+static gboolean
+backend_compare_stream_name (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);
+}
diff --git a/backends/pulse/pulse-backend.h b/backends/pulse/pulse-backend.h
index 64be9b7..813d359 100644
--- a/backends/pulse/pulse-backend.h
+++ b/backends/pulse/pulse-backend.h
@@ -21,6 +21,8 @@
#include <glib.h>
#include <glib-object.h>
+#include <libmatemixer/matemixer-backend.h>
+
#define PULSE_TYPE_BACKEND \
(pulse_backend_get_type ())
#define PULSE_BACKEND(o) \
@@ -30,7 +32,7 @@
#define PULSE_BACKEND_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_BACKEND, PulseBackendClass))
#define PULSE_IS_BACKEND_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_BACKEND))
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_BACKEND))
#define PULSE_BACKEND_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_BACKEND, PulseBackendClass))
@@ -40,15 +42,15 @@ typedef struct _PulseBackendPrivate PulseBackendPrivate;
struct _PulseBackend
{
+ GObject parent;
+
/*< private >*/
- GObject parent;
- PulseBackendPrivate *priv;
+ PulseBackendPrivate *priv;
};
struct _PulseBackendClass
{
- /*< private >*/
- GObjectClass parent;
+ GObjectClass 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
index ebeec99..a597e69 100644
--- a/backends/pulse/pulse-client-stream.c
+++ b/backends/pulse/pulse-client-stream.c
@@ -20,14 +20,18 @@
#include <string.h>
#include <libmatemixer/matemixer-client-stream.h>
+#include <libmatemixer/matemixer-stream.h>
#include <pulse/pulseaudio.h>
#include "pulse-client-stream.h"
-#include "pulse-stream.h"
struct _PulseClientStreamPrivate
{
+ gchar *app_name;
+ gchar *app_id;
+ gchar *app_version;
+ gchar *app_icon;
MateMixerStream *parent;
};
@@ -35,30 +39,69 @@ enum
{
PROP_0,
PROP_PARENT,
+ PROP_APP_NAME,
+ PROP_APP_ID,
+ PROP_APP_VERSION,
+ PROP_APP_ICON,
N_PROPERTIES
};
-static void mate_mixer_client_stream_interface_init (MateMixerClientStreamInterface *iface);
-static void pulse_client_stream_class_init (PulseClientStreamClass *klass);
-static void pulse_client_stream_init (PulseClientStream *client);
-static void pulse_client_stream_dispose (GObject *object);
+static void mate_mixer_client_stream_interface_init (MateMixerClientStreamInterface *iface);
-/* Interface implementation */
-static MateMixerStream *stream_client_get_parent (MateMixerClientStream *client);
-static gboolean stream_client_set_parent (MateMixerClientStream *client,
- MateMixerStream *parent);
-static gboolean stream_client_remove (MateMixerClientStream *client);
+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 MateMixerStream *client_stream_get_parent (MateMixerClientStream *client);
+static gboolean client_stream_set_parent (MateMixerClientStream *client,
+ MateMixerStream *parent);
+static gboolean client_stream_remove (MateMixerClientStream *client);
+
+static const gchar * client_stream_get_app_name (MateMixerClientStream *client);
+static const gchar * client_stream_get_app_id (MateMixerClientStream *client);
+static const gchar * client_stream_get_app_version (MateMixerClientStream *client);
+static const gchar * client_stream_get_app_icon (MateMixerClientStream *client);
+
static void
mate_mixer_client_stream_interface_init (MateMixerClientStreamInterface *iface)
{
- iface->get_parent = stream_client_get_parent;
- iface->set_parent = stream_client_set_parent;
- iface->remove = stream_client_remove;
+ iface->get_parent = client_stream_get_parent;
+ iface->set_parent = client_stream_set_parent;
+ iface->remove = client_stream_remove;
+ iface->get_app_name = client_stream_get_app_name;
+ iface->get_app_id = client_stream_get_app_id;
+ iface->get_app_version = client_stream_get_app_version;
+ iface->get_app_icon = 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;
+
+ 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
@@ -75,6 +118,18 @@ pulse_client_stream_get_property (GObject *object,
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;
@@ -82,28 +137,6 @@ pulse_client_stream_get_property (GObject *object,
}
static void
-pulse_client_stream_class_init (PulseClientStreamClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = pulse_client_stream_dispose;
- object_class->get_property = pulse_client_stream_get_property;
-
- g_object_class_install_property (object_class,
- PROP_PARENT,
- g_param_spec_object ("parent",
- "Parent",
- "Parent stream of the client stream",
- MATE_MIXER_TYPE_STREAM,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
-
- g_type_class_add_private (object_class, sizeof (PulseClientStreamPrivate));
-}
-
-static void
pulse_client_stream_init (PulseClientStream *client)
{
client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client,
@@ -123,8 +156,120 @@ pulse_client_stream_dispose (GObject *object)
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_parent (MateMixerClientStream *client,
+ MateMixerStream *parent)
+{
+ PulseClientStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
+
+ pulse = PULSE_CLIENT_STREAM (client);
+
+ if (pulse->priv->parent != parent) {
+ g_clear_object (&pulse->priv->parent);
+
+ if (G_LIKELY (parent != NULL))
+ pulse->priv->parent = g_object_ref (parent);
+
+ g_object_notify (G_OBJECT (client), "parent");
+ }
+ return TRUE;
+}
+
+gboolean
+pulse_client_stream_update_app_name (MateMixerClientStream *client,
+ const gchar *app_name)
+{
+ PulseClientStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
+
+ pulse = PULSE_CLIENT_STREAM (client);
+
+ if (g_strcmp0 (pulse->priv->app_name, app_name)) {
+ g_free (pulse->priv->app_name);
+ pulse->priv->app_name = g_strdup (app_name);
+
+ g_object_notify (G_OBJECT (client), "app-name");
+ }
+ return TRUE;
+}
+
+gboolean
+pulse_client_stream_update_app_id (MateMixerClientStream *client,
+ const gchar *app_id)
+{
+ PulseClientStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
+
+ pulse = PULSE_CLIENT_STREAM (client);
+
+ if (g_strcmp0 (pulse->priv->app_id, app_id)) {
+ g_free (pulse->priv->app_id);
+ pulse->priv->app_id = g_strdup (app_id);
+
+ g_object_notify (G_OBJECT (client), "app-id");
+ }
+ return TRUE;
+}
+
+gboolean
+pulse_client_stream_update_app_version (MateMixerClientStream *client,
+ const gchar *app_version)
+{
+ PulseClientStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
+
+ pulse = PULSE_CLIENT_STREAM (client);
+
+ if (g_strcmp0 (pulse->priv->app_version, app_version)) {
+ g_free (pulse->priv->app_version);
+ pulse->priv->app_version = g_strdup (app_version);
+
+ g_object_notify (G_OBJECT (client), "app-version");
+ }
+ return TRUE;
+}
+
+gboolean
+pulse_client_stream_update_app_icon (MateMixerClientStream *client,
+ const gchar *app_icon)
+{
+ PulseClientStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
+
+ pulse = PULSE_CLIENT_STREAM (client);
+
+ if (g_strcmp0 (pulse->priv->app_icon, app_icon)) {
+ g_free (pulse->priv->app_icon);
+ pulse->priv->app_icon = g_strdup (app_icon);
+
+ g_object_notify (G_OBJECT (client), "app-icon");
+ }
+ return TRUE;
+}
+
static MateMixerStream *
-stream_client_get_parent (MateMixerClientStream *client)
+client_stream_get_parent (MateMixerClientStream *client)
{
g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
@@ -132,15 +277,49 @@ stream_client_get_parent (MateMixerClientStream *client)
}
static gboolean
-stream_client_set_parent (MateMixerClientStream *client, MateMixerStream *parent)
+client_stream_set_parent (MateMixerClientStream *client, MateMixerStream *parent)
{
- // TODO
- return TRUE;
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
+
+ return PULSE_CLIENT_STREAM_GET_CLASS (client)->set_parent (client, parent);
}
static gboolean
-stream_client_remove (MateMixerClientStream *client)
+client_stream_remove (MateMixerClientStream *client)
{
- // TODO
- return TRUE;
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
+
+ return PULSE_CLIENT_STREAM_GET_CLASS (client)->remove (client);
+}
+
+static const gchar *
+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 *
+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 *
+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 *
+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
index cf801ce..c24a535 100644
--- a/backends/pulse/pulse-client-stream.h
+++ b/backends/pulse/pulse-client-stream.h
@@ -22,8 +22,7 @@
#include <glib-object.h>
#include <libmatemixer/matemixer-client-stream.h>
-
-#include <pulse/pulseaudio.h>
+#include <libmatemixer/matemixer-stream.h>
#include "pulse-stream.h"
@@ -38,7 +37,7 @@ G_BEGIN_DECLS
#define PULSE_CLIENT_STREAM_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_CLIENT_STREAM, PulseClientStreamClass))
#define PULSE_IS_CLIENT_STREAM_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_CLIENT_STREAM))
+ (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))
@@ -50,19 +49,32 @@ struct _PulseClientStream
{
PulseStream parent;
+ /*< private >*/
PulseClientStreamPrivate *priv;
};
struct _PulseClientStreamClass
{
- PulseStreamClass parent;
+ PulseStreamClass parent_class;
- gboolean (*set_parent) (MateMixerClientStream *client,
- MateMixerStream *stream);
- gboolean (*remove) (MateMixerClientStream *client);
+ gboolean (*set_parent) (MateMixerClientStream *client,
+ MateMixerStream *stream);
+ gboolean (*remove) (MateMixerClientStream *client);
};
-GType pulse_client_stream_get_type (void) G_GNUC_CONST;
+GType pulse_client_stream_get_type (void) G_GNUC_CONST;
+
+gboolean pulse_client_stream_update_parent (MateMixerClientStream *client,
+ MateMixerStream *parent);
+
+gboolean pulse_client_stream_update_app_name (MateMixerClientStream *client,
+ const gchar *app_name);
+gboolean pulse_client_stream_update_app_id (MateMixerClientStream *client,
+ const gchar *app_id);
+gboolean pulse_client_stream_update_app_version (MateMixerClientStream *client,
+ const gchar *app_version);
+gboolean pulse_client_stream_update_app_icon (MateMixerClientStream *client,
+ const gchar *app_icon);
G_END_DECLS
diff --git a/backends/pulse/pulse-connection.c b/backends/pulse/pulse-connection.c
index ec172ca..4289660 100644
--- a/backends/pulse/pulse-connection.c
+++ b/backends/pulse/pulse-connection.c
@@ -26,14 +26,14 @@
#include "pulse-connection.h"
#include "pulse-enums.h"
#include "pulse-enum-types.h"
+#include "pulse-monitor.h"
struct _PulseConnectionPrivate
{
gchar *server;
guint outstanding;
- gboolean reconnect;
- gboolean connected_once;
pa_context *context;
+ pa_proplist *proplist;
pa_glib_mainloop *mainloop;
PulseConnectionState state;
};
@@ -41,11 +41,12 @@ struct _PulseConnectionPrivate
enum {
PROP_0,
PROP_SERVER,
- PROP_RECONNECT,
PROP_STATE,
N_PROPERTIES
};
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
enum {
SERVER_INFO,
CARD_INFO,
@@ -61,55 +62,229 @@ enum {
N_SIGNALS
};
-static gchar *connection_get_app_name (void);
-static gboolean connection_load_lists (PulseConnection *connection);
-
-static void connection_state_cb (pa_context *c,
- void *userdata);
-static void connection_subscribe_cb (pa_context *c,
- pa_subscription_event_type_t t,
- uint32_t idx,
- void *userdata);
-static void connection_server_info_cb (pa_context *c,
- const pa_server_info *info,
- void *userdata);
-static void connection_card_info_cb (pa_context *c,
- const pa_card_info *info,
- int eol,
- void *userdata);
-static void connection_sink_info_cb (pa_context *c,
- const pa_sink_info *info,
- int eol,
- void *userdata);
-static void connection_source_info_cb (pa_context *c,
- const pa_source_info *info,
- int eol,
- void *userdata);
-static void connection_sink_input_info_cb (pa_context *c,
- const pa_sink_input_info *info,
- int eol,
- void *userdata);
-static void connection_source_output_info_cb (pa_context *c,
- const pa_source_output_info *info,
- int eol,
- void *userdata);
-
-static void connection_list_loaded (PulseConnection *connection);
-static gboolean connection_process_operation (PulseConnection *connection,
- pa_operation *op);
+static guint signals[N_SIGNALS] = { 0, };
-G_DEFINE_TYPE (PulseConnection, pulse_connection, G_TYPE_OBJECT);
+static void pulse_connection_class_init (PulseConnectionClass *klass);
-static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+static void pulse_connection_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void pulse_connection_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
-static guint signals[N_SIGNALS] = { 0, };
+static void pulse_connection_init (PulseConnection *connection);
+static void pulse_connection_finalize (GObject *object);
+
+G_DEFINE_TYPE (PulseConnection, pulse_connection, G_TYPE_OBJECT);
+
+static gchar *connection_get_app_name (void);
+
+static gboolean connection_load_lists (PulseConnection *connection);
+
+static void connection_state_cb (pa_context *c,
+ void *userdata);
+static void connection_subscribe_cb (pa_context *c,
+ pa_subscription_event_type_t t,
+ uint32_t idx,
+ void *userdata);
+static void connection_server_info_cb (pa_context *c,
+ const pa_server_info *info,
+ void *userdata);
+static void connection_card_info_cb (pa_context *c,
+ const pa_card_info *info,
+ int eol,
+ void *userdata);
+static void connection_sink_info_cb (pa_context *c,
+ const pa_sink_info *info,
+ int eol,
+ void *userdata);
+static void connection_source_info_cb (pa_context *c,
+ const pa_source_info *info,
+ int eol,
+ void *userdata);
+static void connection_sink_input_info_cb (pa_context *c,
+ const pa_sink_input_info *info,
+ int eol,
+ void *userdata);
+static void connection_source_output_info_cb (pa_context *c,
+ const pa_source_output_info *info,
+ int eol,
+ void *userdata);
+
+static void connection_change_state (PulseConnection *connection,
+ PulseConnectionState state);
+
+static void connection_list_loaded (PulseConnection *connection);
+
+static gboolean connection_process_operation (PulseConnection *connection,
+ pa_operation *op);
static void
-pulse_connection_init (PulseConnection *connection)
+pulse_connection_class_init (PulseConnectionClass *klass)
{
- connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection,
- PULSE_TYPE_CONNECTION,
- PulseConnectionPrivate);
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = pulse_connection_finalize;
+ object_class->get_property = pulse_connection_get_property;
+ object_class->set_property = pulse_connection_set_property;
+
+ properties[PROP_SERVER] =
+ g_param_spec_string ("server",
+ "Server",
+ "PulseAudio server to connect to",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_STATE] =
+ g_param_spec_enum ("state",
+ "State",
+ "Connection state",
+ PULSE_TYPE_CONNECTION_STATE,
+ PULSE_CONNECTION_DISCONNECTED,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ signals[SERVER_INFO] =
+ g_signal_new ("server-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, server_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[CARD_INFO] =
+ g_signal_new ("card-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, card_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[CARD_REMOVED] =
+ g_signal_new ("card-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, card_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ signals[SINK_INFO] =
+ g_signal_new ("sink-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, sink_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[SINK_REMOVED] =
+ g_signal_new ("sink-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, sink_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ signals[SINK_INPUT_INFO] =
+ g_signal_new ("sink-input-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, sink_input_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[SINK_INPUT_REMOVED] =
+ g_signal_new ("sink-input-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, sink_input_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ signals[SOURCE_INFO] =
+ g_signal_new ("source-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, source_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[SOURCE_REMOVED] =
+ g_signal_new ("source-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, source_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ signals[SOURCE_OUTPUT_INFO] =
+ g_signal_new ("source-output-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, source_output_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[SOURCE_OUTPUT_REMOVED] =
+ g_signal_new ("source-output-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, source_output_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (object_class, sizeof (PulseConnectionPrivate));
}
static void
@@ -126,9 +301,6 @@ pulse_connection_get_property (GObject *object,
case PROP_SERVER:
g_value_set_string (value, connection->priv->server);
break;
- case PROP_RECONNECT:
- g_value_set_boolean (value, connection->priv->reconnect);
- break;
case PROP_STATE:
g_value_set_enum (value, connection->priv->state);
break;
@@ -150,12 +322,8 @@ pulse_connection_set_property (GObject *object,
switch (param_id) {
case PROP_SERVER:
- g_free (connection->priv->server);
-
- connection->priv->server = g_value_dup_string (value);
- break;
- case PROP_RECONNECT:
- connection->priv->reconnect = g_value_get_boolean (value);
+ /* Construct-only string */
+ connection->priv->server = g_strdup (g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -164,6 +332,14 @@ pulse_connection_set_property (GObject *object,
}
static void
+pulse_connection_init (PulseConnection *connection)
+{
+ connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection,
+ PULSE_TYPE_CONNECTION,
+ PulseConnectionPrivate);
+}
+
+static void
pulse_connection_finalize (GObject *object)
{
PulseConnection *connection;
@@ -172,165 +348,12 @@ pulse_connection_finalize (GObject *object)
g_free (connection->priv->server);
- G_OBJECT_CLASS (pulse_connection_parent_class)->finalize (object);
-}
+ pa_context_unref (connection->priv->context);
+ pa_proplist_free (connection->priv->proplist);
-static void
-pulse_connection_class_init (PulseConnectionClass *klass)
-{
- GObjectClass *object_class;
+ pa_glib_mainloop_free (connection->priv->mainloop);
- object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = pulse_connection_finalize;
- object_class->get_property = pulse_connection_get_property;
- object_class->set_property = pulse_connection_set_property;
-
- properties[PROP_SERVER] = g_param_spec_string ("server",
- "Server",
- "PulseAudio server to connect to",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_RECONNECT] = g_param_spec_boolean ("reconnect",
- "Reconnect",
- "Try to reconnect when connection is lost",
- TRUE,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_STATE] = g_param_spec_enum ("state",
- "State",
- "Connection state",
- PULSE_TYPE_CONNECTION_STATE,
- PULSE_CONNECTION_DISCONNECTED,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- signals[SERVER_INFO] = g_signal_new ("server-info",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, server_info),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[CARD_INFO] = g_signal_new ("card-info",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, card_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[CARD_REMOVED] = g_signal_new ("card-removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, card_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE,
- 1,
- G_TYPE_UINT);
-
- signals[SINK_INFO] = g_signal_new ("sink-info",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, sink_info),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[SINK_REMOVED] = g_signal_new ("sink-removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, sink_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE,
- 1,
- G_TYPE_UINT);
-
- signals[SINK_INPUT_INFO] = g_signal_new ("sink-input-info",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, sink_input_info),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[SINK_INPUT_REMOVED] = g_signal_new ("sink-input-removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, sink_input_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE,
- 1,
- G_TYPE_UINT);
-
- signals[SOURCE_INFO] = g_signal_new ("source-info",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, source_info),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[SOURCE_REMOVED] = g_signal_new ("source-removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, source_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE,
- 1,
- G_TYPE_UINT);
-
- signals[SOURCE_OUTPUT_INFO] = g_signal_new ("source-output-info",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, source_output_info),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE,
- 1,
- G_TYPE_POINTER);
-
- signals[SOURCE_OUTPUT_REMOVED] = g_signal_new ("source-output-removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PulseConnectionClass, source_output_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE,
- 1,
- G_TYPE_UINT);
-
- g_object_class_install_properties (object_class, N_PROPERTIES, properties);
-
- g_type_class_add_private (object_class, sizeof (PulseConnectionPrivate));
+ G_OBJECT_CLASS (pulse_connection_parent_class)->finalize (object);
}
PulseConnection *
@@ -351,6 +374,9 @@ pulse_connection_new (const gchar *app_name,
return NULL;
}
+ /* Create a property list to hold information about the application,
+ * the list will be kept with the connection as it may be reused later
+ * when creating PulseAudio streams */
proplist = pa_proplist_new ();
if (app_name)
pa_proplist_sets (proplist, PA_PROP_APPLICATION_NAME, app_name);
@@ -366,80 +392,90 @@ pulse_connection_new (const gchar *app_name,
app_name,
proplist);
} else {
+ /* Try to set some sensible default name when application does not
+ * provide a name */
gchar *name = connection_get_app_name ();
context = pa_context_new_with_proplist (pa_glib_mainloop_get_api (mainloop),
name,
proplist);
-
g_free (name);
}
- pa_proplist_free (proplist);
if (G_UNLIKELY (context == NULL)) {
g_warning ("Failed to create PulseAudio context");
+
pa_glib_mainloop_free (mainloop);
+ pa_proplist_free (proplist);
return NULL;
}
connection = g_object_new (PULSE_TYPE_CONNECTION,
"server", server_address,
- "reconnect", TRUE,
NULL);
+ /* Set function to monitor status changes */
+ pa_context_set_state_callback (context,
+ connection_state_cb,
+ connection);
+
connection->priv->mainloop = mainloop;
connection->priv->context = context;
+ connection->priv->proplist = proplist;
+
return connection;
}
gboolean
pulse_connection_connect (PulseConnection *connection)
{
- int ret;
-
g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
if (connection->priv->state != PULSE_CONNECTION_DISCONNECTED)
return TRUE;
- /* Set function to monitor status changes */
- pa_context_set_state_callback (connection->priv->context,
- connection_state_cb,
- connection);
-
- /* Initiate a connection, this call does not guarantee the connection
- * to be established and usable */
- ret = pa_context_connect (connection->priv->context, NULL, PA_CONTEXT_NOFLAGS, NULL);
- if (ret < 0) {
- g_warning ("Failed to connect to PulseAudio server: %s", pa_strerror (ret));
+ /* Initiate a connection, state changes will be delivered asynchronously */
+ if (pa_context_connect (connection->priv->context,
+ connection->priv->server,
+ PA_CONTEXT_NOFLAGS,
+ NULL) == 0)
+ return TRUE;
+ else
return FALSE;
- }
- return TRUE;
}
void
pulse_connection_disconnect (PulseConnection *connection)
{
- g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+ g_return_if_fail (PULSE_IS_CONNECTION (connection));
if (connection->priv->state == PULSE_CONNECTION_DISCONNECTED)
return;
pa_context_disconnect (connection->priv->context);
- connection->priv->state = PULSE_CONNECTION_DISCONNECTED;
-
- g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
+ connection_change_state (connection, PULSE_CONNECTION_DISCONNECTED);
}
PulseConnectionState
pulse_connection_get_state (PulseConnection *connection)
{
- g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), PULSE_CONNECTION_DISCONNECTED);
return connection->priv->state;
}
+PulseMonitor *
+pulse_connection_create_monitor (PulseConnection *connection,
+ guint32 index_source,
+ guint32 index_sink_input)
+{
+ return pulse_monitor_new (connection->priv->context,
+ connection->priv->proplist,
+ index_source,
+ index_sink_input);
+}
+
gboolean
pulse_connection_set_default_sink (PulseConnection *connection,
const gchar *name)
@@ -666,6 +702,40 @@ pulse_connection_set_source_output_volume (PulseConnection *connection,
}
gboolean
+pulse_connection_suspend_sink (PulseConnection *connection,
+ guint32 index,
+ gboolean suspend)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ op = pa_context_suspend_sink_by_index (connection->priv->context,
+ index,
+ (int) suspend,
+ NULL, NULL);
+
+ return connection_process_operation (connection, op);
+}
+
+gboolean
+pulse_connection_suspend_source (PulseConnection *connection,
+ guint32 index,
+ gboolean suspend)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ op = pa_context_suspend_source_by_index (connection->priv->context,
+ index,
+ (int) suspend,
+ NULL, NULL);
+
+ return connection_process_operation (connection, op);
+}
+
+gboolean
pulse_connection_move_sink_input (PulseConnection *connection,
guint32 index,
guint32 sink_index)
@@ -755,19 +825,10 @@ connection_load_lists (PulseConnection *connection)
g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
if (G_UNLIKELY (connection->priv->outstanding)) {
- /* This can only mean a bug */
g_warn_if_reached ();
return FALSE;
}
- op = pa_context_get_server_info (connection->priv->context,
- connection_server_info_cb,
- connection);
- if (G_UNLIKELY (op == NULL))
- goto error;
-
- ops = g_list_prepend (ops, op);
-
op = pa_context_get_card_info_list (connection->priv->context,
connection_card_info_cb,
connection);
@@ -834,9 +895,16 @@ connection_state_cb (pa_context *c, void *userdata)
if (state == PA_CONTEXT_READY) {
pa_operation *op;
- // XXX check state
+ if (connection->priv->state == PULSE_CONNECTION_LOADING ||
+ connection->priv->state == PULSE_CONNECTION_CONNECTED) {
+ g_warn_if_reached ();
+ return;
+ }
+ /* We are connected, let's subscribe to notifications and load the
+ * initial lists */
op = pa_context_subscribe (connection->priv->context,
+ PA_SUBSCRIPTION_MASK_SERVER |
PA_SUBSCRIPTION_MASK_CARD |
PA_SUBSCRIPTION_MASK_SINK |
PA_SUBSCRIPTION_MASK_SOURCE |
@@ -844,25 +912,22 @@ connection_state_cb (pa_context *c, void *userdata)
PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT,
NULL, NULL);
if (op) {
- connection->priv->state = PULSE_CONNECTION_LOADING;
- connection->priv->connected_once = TRUE;
-
pa_context_set_subscribe_callback (connection->priv->context,
connection_subscribe_cb,
connection);
pa_operation_unref (op);
connection_load_lists (connection);
+ connection_change_state (connection, PULSE_CONNECTION_LOADING);
+ return;
+ }
- g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
- } else {
- /* If we could not subscribe to notifications, we consider it the
- * same as a connection failture */
- g_warning ("Failed to subscribe to PulseAudio notifications: %s",
- pa_strerror (pa_context_errno (connection->priv->context)));
+ /* If we could not subscribe to notifications, we consider it the
+ * same as a connection failture */
+ g_warning ("Failed to subscribe to PulseAudio notifications: %s",
+ pa_strerror (pa_context_errno (connection->priv->context)));
- state = PA_CONTEXT_FAILED;
- }
+ state = PA_CONTEXT_FAILED;
}
if (state == PA_CONTEXT_TERMINATED || state == PA_CONTEXT_FAILED) {
@@ -870,10 +935,14 @@ connection_state_cb (pa_context *c, void *userdata)
* change which should not normally happen, because the signal subscription
* is cancelled before disconnecting */
pulse_connection_disconnect (connection);
-
- if (connection->priv->connected_once && connection->priv->reconnect)
- pulse_connection_connect (connection);
+ return;
}
+
+ if (state == PA_CONTEXT_CONNECTING)
+ connection_change_state (connection, PULSE_CONNECTION_CONNECTING);
+ else if (state == PA_CONTEXT_AUTHORIZING ||
+ state == PA_CONTEXT_SETTING_NAME)
+ connection_change_state (connection, PULSE_CONNECTION_AUTHORIZING);
}
static void
@@ -970,10 +1039,19 @@ connection_server_info_cb (pa_context *c,
const pa_server_info *info,
void *userdata)
{
- g_signal_emit (G_OBJECT (userdata),
+ PulseConnection *connection;
+
+ connection = PULSE_CONNECTION (userdata);
+
+ g_signal_emit (G_OBJECT (connection),
signals[SERVER_INFO],
0,
info);
+
+ /* This notification may arrive at any time, but it also finalizes the
+ * connection process */
+ if (connection->priv->state == PULSE_CONNECTION_LOADING)
+ connection_change_state (connection, PULSE_CONNECTION_CONNECTED);
}
static void
@@ -1008,13 +1086,16 @@ connection_sink_info_cb (pa_context *c,
connection = PULSE_CONNECTION (userdata);
- if (eol)
- connection_list_loaded (connection);
- else
- g_signal_emit (G_OBJECT (connection),
- signals[SINK_INFO],
- 0,
- info);
+ if (eol) {
+ if (connection->priv->state == PULSE_CONNECTION_LOADING)
+ connection_list_loaded (connection);
+ return;
+ }
+
+ g_signal_emit (G_OBJECT (connection),
+ signals[SINK_INFO],
+ 0,
+ info);
}
static void
@@ -1084,6 +1165,17 @@ connection_source_output_info_cb (pa_context *c,
}
static void
+connection_change_state (PulseConnection *connection, PulseConnectionState state)
+{
+ if (connection->priv->state == state)
+ return;
+
+ connection->priv->state = state;
+
+ g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
+}
+
+static void
connection_list_loaded (PulseConnection *connection)
{
connection->priv->outstanding--;
@@ -1093,9 +1185,14 @@ connection_list_loaded (PulseConnection *connection)
connection->priv->outstanding = 0;
}
if (connection->priv->outstanding == 0) {
- connection->priv->state = PULSE_CONNECTION_CONNECTED;
+ pa_operation *op;
+
+ op = pa_context_get_server_info (connection->priv->context,
+ connection_server_info_cb,
+ connection);
- g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
+ if (G_UNLIKELY (!connection_process_operation (connection, op)))
+ pulse_connection_disconnect (connection);
}
}
diff --git a/backends/pulse/pulse-connection.h b/backends/pulse/pulse-connection.h
index 922b65a..b3f01b7 100644
--- a/backends/pulse/pulse-connection.h
+++ b/backends/pulse/pulse-connection.h
@@ -24,6 +24,7 @@
#include <pulse/pulseaudio.h>
#include "pulse-enums.h"
+#include "pulse-monitor.h"
G_BEGIN_DECLS
@@ -36,7 +37,7 @@ G_BEGIN_DECLS
#define PULSE_CONNECTION_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_CONNECTION, PulseConnectionClass))
#define PULSE_IS_CONNECTION_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_CONNECTION))
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_CONNECTION))
#define PULSE_CONNECTION_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_CONNECTION, PulseConnectionClass))
@@ -48,110 +49,117 @@ struct _PulseConnection
{
GObject parent;
+ /*< private >*/
PulseConnectionPrivate *priv;
};
struct _PulseConnectionClass
{
- GObjectClass parent;
-
- void (*server_info) (PulseConnection *connection,
- const pa_server_info *info);
- void (*card_info) (PulseConnection *connection,
- const pa_card_info *info);
- void (*card_removed) (PulseConnection *connection,
- guint32 index);
- void (*sink_info) (PulseConnection *connection,
- const pa_sink_info *info);
- void (*sink_removed) (PulseConnection *connection,
- guint32 index);
- void (*sink_input_info) (PulseConnection *connection,
- const pa_sink_input_info *info);
- void (*sink_input_removed) (PulseConnection *connection,
- guint32 index);
- void (*source_info) (PulseConnection *connection,
- const pa_source_info *info);
- void (*source_removed) (PulseConnection *connection,
- guint32 index);
- void (*source_output_info) (PulseConnection *connection,
- const pa_source_output_info *info);
- void (*source_output_removed) (PulseConnection *connection,
- guint32 index);
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (*server_info) (PulseConnection *connection,
+ const pa_server_info *info);
+ void (*card_info) (PulseConnection *connection,
+ const pa_card_info *info);
+ void (*card_removed) (PulseConnection *connection,
+ guint32 index);
+ void (*sink_info) (PulseConnection *connection,
+ const pa_sink_info *info);
+ void (*sink_removed) (PulseConnection *connection,
+ guint32 index);
+ void (*sink_input_info) (PulseConnection *connection,
+ const pa_sink_input_info *info);
+ void (*sink_input_removed) (PulseConnection *connection,
+ guint32 index);
+ void (*source_info) (PulseConnection *connection,
+ const pa_source_info *info);
+ void (*source_removed) (PulseConnection *connection,
+ guint32 index);
+ void (*source_output_info) (PulseConnection *connection,
+ const pa_source_output_info *info);
+ void (*source_output_removed) (PulseConnection *connection,
+ guint32 index);
};
-GType pulse_connection_get_type (void) G_GNUC_CONST;
-
-PulseConnection *pulse_connection_new (const gchar *app_name,
- const gchar *app_id,
- const gchar *app_version,
- const gchar *app_icon,
- const gchar *server_address);
-
-gboolean pulse_connection_connect (PulseConnection *connection);
-void pulse_connection_disconnect (PulseConnection *connection);
-
-PulseConnectionState pulse_connection_get_state (PulseConnection *connection);
-
-gboolean pulse_connection_set_default_sink (PulseConnection *connection,
- const gchar *name);
-
-gboolean pulse_connection_set_default_source (PulseConnection *connection,
- const gchar *name);
-
-gboolean pulse_connection_set_card_profile (PulseConnection *connection,
- const gchar *device,
- const gchar *profile);
-
-gboolean pulse_connection_set_sink_mute (PulseConnection *connection,
- guint32 index,
- gboolean mute);
-gboolean pulse_connection_set_sink_volume (PulseConnection *connection,
- guint32 index,
- const pa_cvolume *volume);
-gboolean pulse_connection_set_sink_port (PulseConnection *connection,
- guint32 index,
- const gchar *port);
-
-gboolean pulse_connection_set_sink_input_mute (PulseConnection *connection,
- guint32 index,
- gboolean mute);
-
-gboolean pulse_connection_set_sink_input_volume (PulseConnection *connection,
- guint32 index,
- const pa_cvolume *volume);
-
-
-gboolean pulse_connection_set_source_mute (PulseConnection *connection,
- guint32 index,
- gboolean mute);
-gboolean pulse_connection_set_source_volume (PulseConnection *connection,
- guint32 index,
- const pa_cvolume *volume);
-gboolean pulse_connection_set_source_port (PulseConnection *connection,
- guint32 index,
- const gchar *port);
-
-gboolean pulse_connection_set_source_output_mute (PulseConnection *connection,
- guint32 index,
- gboolean mute);
-
-gboolean pulse_connection_set_source_output_volume (PulseConnection *connection,
- guint32 index,
- const pa_cvolume *volume);
-
-gboolean pulse_connection_move_sink_input (PulseConnection *connection,
- guint32 index,
- guint32 sink_index);
-
-gboolean pulse_connection_move_source_output (PulseConnection *connection,
- guint32 index,
- guint32 source_index);
-
-gboolean pulse_connection_kill_sink_input (PulseConnection *connection,
- guint32 index);
-
-gboolean pulse_connection_kill_source_output (PulseConnection *connection,
- guint32 index);
+GType pulse_connection_get_type (void) G_GNUC_CONST;
+
+PulseConnection * pulse_connection_new (const gchar *app_name,
+ const gchar *app_id,
+ const gchar *app_version,
+ const gchar *app_icon,
+ const gchar *server_address);
+
+gboolean pulse_connection_connect (PulseConnection *connection);
+void pulse_connection_disconnect (PulseConnection *connection);
+
+PulseConnectionState pulse_connection_get_state (PulseConnection *connection);
+
+PulseMonitor * pulse_connection_create_monitor (PulseConnection *connection,
+ guint32 index_source,
+ guint32 index_sink_input);
+
+gboolean pulse_connection_set_default_sink (PulseConnection *connection,
+ const gchar *name);
+gboolean pulse_connection_set_default_source (PulseConnection *connection,
+ const gchar *name);
+
+gboolean pulse_connection_set_card_profile (PulseConnection *connection,
+ const gchar *device,
+ const gchar *profile);
+
+gboolean pulse_connection_set_sink_mute (PulseConnection *connection,
+ guint32 index,
+ gboolean mute);
+gboolean pulse_connection_set_sink_volume (PulseConnection *connection,
+ guint32 index,
+ const pa_cvolume *volume);
+gboolean pulse_connection_set_sink_port (PulseConnection *connection,
+ guint32 index,
+ const gchar *port);
+
+gboolean pulse_connection_set_sink_input_mute (PulseConnection *connection,
+ guint32 index,
+ gboolean mute);
+gboolean pulse_connection_set_sink_input_volume (PulseConnection *connection,
+ guint32 index,
+ const pa_cvolume *volume);
+
+gboolean pulse_connection_set_source_mute (PulseConnection *connection,
+ guint32 index,
+ gboolean mute);
+gboolean pulse_connection_set_source_volume (PulseConnection *connection,
+ guint32 index,
+ const pa_cvolume *volume);
+gboolean pulse_connection_set_source_port (PulseConnection *connection,
+ guint32 index,
+ const gchar *port);
+
+gboolean pulse_connection_set_source_output_mute (PulseConnection *connection,
+ guint32 index,
+ gboolean mute);
+gboolean pulse_connection_set_source_output_volume (PulseConnection *connection,
+ guint32 index,
+ const pa_cvolume *volume);
+
+gboolean pulse_connection_suspend_sink (PulseConnection *connection,
+ guint32 index,
+ gboolean suspend);
+gboolean pulse_connection_suspend_source (PulseConnection *connection,
+ guint32 index,
+ gboolean suspend);
+
+gboolean pulse_connection_move_sink_input (PulseConnection *connection,
+ guint32 index,
+ guint32 sink_index);
+gboolean pulse_connection_move_source_output (PulseConnection *connection,
+ guint32 index,
+ guint32 source_index);
+
+gboolean pulse_connection_kill_sink_input (PulseConnection *connection,
+ guint32 index);
+gboolean pulse_connection_kill_source_output (PulseConnection *connection,
+ guint32 index);
G_END_DECLS
diff --git a/backends/pulse/pulse-device.c b/backends/pulse/pulse-device.c
index ad17f21..d15972e 100644
--- a/backends/pulse/pulse-device.c
+++ b/backends/pulse/pulse-device.c
@@ -17,8 +17,10 @@
#include <glib.h>
#include <glib-object.h>
+#include <string.h>
#include <libmatemixer/matemixer-device.h>
+#include <libmatemixer/matemixer-enums.h>
#include <libmatemixer/matemixer-port.h>
#include <libmatemixer/matemixer-profile.h>
@@ -26,6 +28,7 @@
#include "pulse-connection.h"
#include "pulse-device.h"
+#include "pulse-stream.h"
struct _PulseDevicePrivate
{
@@ -34,6 +37,8 @@ struct _PulseDevicePrivate
gchar *description;
GList *profiles;
GList *ports;
+ GList *streams;
+ gboolean streams_sorted;
gchar *icon;
PulseConnection *connection;
MateMixerProfile *profile;
@@ -45,36 +50,60 @@ enum
PROP_NAME,
PROP_DESCRIPTION,
PROP_ICON,
+ PROP_PORTS,
+ PROP_PROFILES,
PROP_ACTIVE_PROFILE,
+ PROP_INDEX,
+ PROP_CONNECTION,
N_PROPERTIES
};
static void mate_mixer_device_interface_init (MateMixerDeviceInterface *iface);
-static const gchar * device_get_name (MateMixerDevice *device);
-static const gchar * device_get_description (MateMixerDevice *device);
-static const gchar * device_get_icon (MateMixerDevice *device);
+static void pulse_device_class_init (PulseDeviceClass *klass);
-static const GList * device_list_streams (MateMixerDevice *device);
+static void pulse_device_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void pulse_device_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
-static const GList * device_list_ports (MateMixerDevice *device);
-static const GList * device_list_profiles (MateMixerDevice *device);
-static MateMixerProfile *device_get_active_profile (MateMixerDevice *device);
-
-static gboolean device_set_active_profile (MateMixerDevice *device,
- const gchar *name);
+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))
+static const gchar * device_get_name (MateMixerDevice *device);
+static const gchar * device_get_description (MateMixerDevice *device);
+static const gchar * device_get_icon (MateMixerDevice *device);
+
+static const GList * device_list_ports (MateMixerDevice *device);
+static const GList * device_list_profiles (MateMixerDevice *device);
+
+static MateMixerProfile *device_get_active_profile (MateMixerDevice *device);
+static gboolean device_set_active_profile (MateMixerDevice *device,
+ const gchar *profile);
+
+static gint device_compare_ports (gconstpointer a,
+ gconstpointer b);
+static gint device_compare_profiles (gconstpointer a,
+ gconstpointer b);
+
+static void device_free_ports (PulseDevice *device);
+static void device_free_profiles (PulseDevice *device);
+
static void
mate_mixer_device_interface_init (MateMixerDeviceInterface *iface)
{
iface->get_name = device_get_name;
iface->get_description = device_get_description;
iface->get_icon = device_get_icon;
- iface->list_streams = device_list_streams;
iface->list_ports = device_list_ports;
iface->list_profiles = device_list_profiles;
iface->get_active_profile = device_get_active_profile;
@@ -82,11 +111,45 @@ mate_mixer_device_interface_init (MateMixerDeviceInterface *iface)
}
static void
-pulse_device_init (PulseDevice *device)
+pulse_device_class_init (PulseDeviceClass *klass)
{
- device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
- PULSE_TYPE_DEVICE,
- PulseDevicePrivate);
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_device_dispose;
+ object_class->finalize = pulse_device_finalize;
+ object_class->get_property = pulse_device_get_property;
+ object_class->set_property = pulse_device_set_property;
+
+ g_object_class_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_PORTS, "ports");
+ g_object_class_override_property (object_class, PROP_PROFILES, "profiles");
+ g_object_class_override_property (object_class, PROP_ACTIVE_PROFILE, "active-profile");
+
+ g_type_class_add_private (object_class, sizeof (PulseDevicePrivate));
}
static void
@@ -109,9 +172,21 @@ pulse_device_get_property (GObject *object,
case PROP_ICON:
g_value_set_string (value, device->priv->icon);
break;
+ case PROP_PORTS:
+ g_value_set_pointer (value, device->priv->ports);
+ break;
+ case PROP_PROFILES:
+ g_value_set_pointer (value, device->priv->profiles);
+ 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;
+ case PROP_CONNECTION:
+ g_value_set_object (value, device->priv->connection);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -129,14 +204,12 @@ pulse_device_set_property (GObject *object,
device = PULSE_DEVICE (object);
switch (param_id) {
- case PROP_NAME:
- device->priv->name = g_strdup (g_value_get_string (value));
- break;
- case PROP_DESCRIPTION:
- device->priv->description = g_strdup (g_value_get_string (value));
+ case PROP_INDEX:
+ device->priv->index = g_value_get_uint (value);
break;
- case PROP_ICON:
- device->priv->icon = g_strdup (g_value_get_string (value));
+ case PROP_CONNECTION:
+ /* Construct-only object property */
+ device->priv->connection = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -145,23 +218,23 @@ pulse_device_set_property (GObject *object,
}
static void
+pulse_device_init (PulseDevice *device)
+{
+ device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
+ PULSE_TYPE_DEVICE,
+ PulseDevicePrivate);
+}
+
+static void
pulse_device_dispose (GObject *object)
{
PulseDevice *device;
device = PULSE_DEVICE (object);
- if (device->priv->profiles != NULL) {
- g_list_free_full (device->priv->profiles, g_object_unref);
- device->priv->profiles = NULL;
- }
+ device_free_ports (device);
+ device_free_profiles (device);
- if (device->priv->ports != NULL) {
- g_list_free_full (device->priv->ports, g_object_unref);
- device->priv->ports = NULL;
- }
-
- g_clear_object (&device->priv->profile);
g_clear_object (&device->priv->connection);
G_OBJECT_CLASS (pulse_device_parent_class)->dispose (object);
@@ -181,46 +254,113 @@ pulse_device_finalize (GObject *object)
G_OBJECT_CLASS (pulse_device_parent_class)->finalize (object);
}
-static void
-pulse_device_class_init (PulseDeviceClass *klass)
+PulseDevice *
+pulse_device_new (PulseConnection *connection, const pa_card_info *info)
{
- GObjectClass *object_class;
+ PulseDevice *device;
- object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = pulse_device_dispose;
- object_class->finalize = pulse_device_finalize;
- object_class->get_property = pulse_device_get_property;
- object_class->set_property = pulse_device_set_property;
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
- 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");
+ /* Consider the device index as unchanging parameter */
+ device = g_object_new (PULSE_TYPE_DEVICE,
+ "connection", connection,
+ "index", info->index,
+ NULL);
- g_type_class_add_private (object_class, sizeof (PulseDevicePrivate));
+ /* Other data may change at any time, so let's make a use of our update function */
+ pulse_device_update (device, info);
+
+ return device;
}
-PulseDevice *
-pulse_device_new (PulseConnection *connection, const pa_card_info *info)
+gboolean
+pulse_device_update (PulseDevice *device, const pa_card_info *info)
{
- PulseDevice *device;
- MateMixerProfile *active_profile = NULL;
- GList *profiles = NULL;
- GList *ports = NULL;
- guint32 i;
+ const gchar *prop;
+ guint32 i;
- g_return_val_if_fail (info != NULL, NULL);
+ 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)) {
+ 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)) {
+ 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)) {
+ g_free (device->priv->icon);
+ device->priv->icon = g_strdup (prop);
+
+ g_object_notify (G_OBJECT (device), "icon");
+ }
+
+ /* List of ports */
+ device_free_ports (device);
+
+ for (i = 0; i < info->n_ports; i++) {
+ MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
+
+ prop = pa_proplist_gets (info->ports[i]->proplist, "device.icon_name");
+
+#if PA_CHECK_VERSION(2, 0, 0)
+ if (info->ports[i]->available == PA_PORT_AVAILABLE_YES)
+ flags |= MATE_MIXER_PORT_AVAILABLE;
+
+ if (info->ports[i]->direction & PA_DIRECTION_INPUT)
+ flags |= MATE_MIXER_PORT_INPUT;
+ if (info->ports[i]->direction & PA_DIRECTION_OUTPUT)
+ flags |= MATE_MIXER_PORT_OUTPUT;
+#endif
+ device->priv->ports =
+ g_list_prepend (device->priv->ports,
+ mate_mixer_port_new (info->ports[i]->name,
+ info->ports[i]->description,
+ prop,
+ info->ports[i]->priority,
+ flags));
+ }
+ device->priv->ports = g_list_sort (device->priv->ports, device_compare_ports);
+
+ g_object_notify (G_OBJECT (device), "ports");
+
+ /* List of profiles */
+ device_free_profiles (device);
- /* Create a list of card profiles */
for (i = 0; i < info->n_profiles; i++) {
MateMixerProfile *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 */
+ /* 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
@@ -232,78 +372,23 @@ pulse_device_new (PulseConnection *connection, const pa_card_info *info)
p_info->description,
p_info->priority);
+ if (device->priv->profile == NULL) {
#if PA_CHECK_VERSION(5, 0, 0)
- if (!g_strcmp0 (p_info->name, info->active_profile2->name))
- active_profile = g_object_ref (profile);
+ if (!g_strcmp0 (p_info->name, info->active_profile2->name))
+ device->priv->profile = g_object_ref (profile);
#else
- if (!g_strcmp0 (p_info->name, info->active_profile->name))
- active_profile = g_object_ref (profile);
+ if (!g_strcmp0 (p_info->name, info->active_profile->name))
+ device->priv->profile = g_object_ref (profile);
#endif
- profiles = g_list_prepend (profiles, profile);
- }
-
- /* Keep the profiles in the same order as in PulseAudio */
- if (profiles)
- profiles = g_list_reverse (profiles);
-
- /* Create a list of card ports */
- for (i = 0; i < info->n_ports; i++) {
- MateMixerPort *port;
- MateMixerPortStatus status = MATE_MIXER_PORT_UNKNOWN_STATUS;
- pa_card_port_info *p_info = info->ports[i];
-
-#if PA_CHECK_VERSION(2, 0, 0)
- switch (p_info->available) {
- case PA_PORT_AVAILABLE_YES:
- status = MATE_MIXER_PORT_AVAILABLE;
- break;
- case PA_PORT_AVAILABLE_NO:
- status = MATE_MIXER_PORT_UNAVAILABLE;
- break;
- default:
- break;
}
-#endif
- port = mate_mixer_port_new (p_info->name,
- p_info->description,
- pa_proplist_gets (p_info->proplist, "device.icon_name"),
- p_info->priority,
- status);
-
- ports = g_list_prepend (ports, port);
+ device->priv->profiles = g_list_prepend (device->priv->profiles, profile);
}
+ device->priv->profiles = g_list_sort (device->priv->profiles,
+ device_compare_profiles);
- /* Keep the ports in the same order as in PulseAudio */
- if (ports)
- ports = g_list_reverse (ports);
-
- device = g_object_new (PULSE_TYPE_DEVICE,
- "name", info->name,
- "description", pa_proplist_gets (info->proplist, "device.description"),
- "icon", pa_proplist_gets (info->proplist, "device.icon_name"),
- NULL);
+ g_object_notify (G_OBJECT (device), "profiles");
- if (profiles) {
- device->priv->profiles = profiles;
-
- if (G_LIKELY (active_profile))
- device->priv->profile = g_object_ref (active_profile);
- }
-
- device->priv->index = info->index;
- device->priv->ports = ports;
- device->priv->connection = g_object_ref (connection);
-
- return device;
-}
-
-gboolean
-pulse_device_update (PulseDevice *device, const pa_card_info *info)
-{
- g_return_val_if_fail (PULSE_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
-
- // TODO: update status, active_profile, maybe others?
+ g_object_thaw_notify (G_OBJECT (device));
return TRUE;
}
@@ -348,13 +433,6 @@ device_get_icon (MateMixerDevice *device)
}
static const GList *
-device_list_streams (MateMixerDevice *device)
-{
- // TODO
- return NULL;
-}
-
-static const GList *
device_list_ports (MateMixerDevice *device)
{
g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
@@ -379,16 +457,66 @@ device_get_active_profile (MateMixerDevice *device)
}
static gboolean
-device_set_active_profile (MateMixerDevice *device, const gchar *name)
+device_set_active_profile (MateMixerDevice *device, const gchar *profile)
{
- PulseDevicePrivate *priv;
-
g_return_val_if_fail (PULSE_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (name != NULL, FALSE);
+ g_return_val_if_fail (profile != NULL, FALSE);
- priv = PULSE_DEVICE (device)->priv;
+ return pulse_connection_set_card_profile (PULSE_DEVICE (device)->priv->connection,
+ PULSE_DEVICE (device)->priv->name,
+ profile);
+}
+
+static gint
+device_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));
+}
+
+static gint
+device_compare_profiles (gconstpointer a, gconstpointer b)
+{
+ MateMixerProfile *p1 = MATE_MIXER_PROFILE (a);
+ MateMixerProfile *p2 = MATE_MIXER_PROFILE (b);
+
+ gint ret = (gint) (mate_mixer_profile_get_priority (p2) -
+ mate_mixer_profile_get_priority (p1));
+ if (ret != 0)
+ return ret;
+ else
+ return strcmp (mate_mixer_profile_get_name (p1),
+ mate_mixer_profile_get_name (p2));
+}
+
+static void
+device_free_ports (PulseDevice *device)
+{
+ if (device->priv->ports == NULL)
+ return;
+
+ g_list_free_full (device->priv->ports, g_object_unref);
+
+ device->priv->ports = NULL;
+}
+
+static void
+device_free_profiles (PulseDevice *device)
+{
+ if (device->priv->profiles == NULL)
+ return;
+
+ g_list_free_full (device->priv->profiles, g_object_unref);
+
+ g_clear_object (&device->priv->profile);
- return pulse_connection_set_card_profile (priv->connection,
- priv->name,
- name);
+ device->priv->profiles = NULL;
}
diff --git a/backends/pulse/pulse-device.h b/backends/pulse/pulse-device.h
index b862879..94c331f 100644
--- a/backends/pulse/pulse-device.h
+++ b/backends/pulse/pulse-device.h
@@ -36,7 +36,7 @@ G_BEGIN_DECLS
#define PULSE_DEVICE_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_DEVICE, PulseDeviceClass))
#define PULSE_IS_DEVICE_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_DEVICE))
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_DEVICE))
#define PULSE_DEVICE_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_IS_DEVICE, PulseDeviceClass))
@@ -48,6 +48,7 @@ struct _PulseDevice
{
GObject parent;
+ /*< private >*/
PulseDevicePrivate *priv;
};
diff --git a/backends/pulse/pulse-helpers.h b/backends/pulse/pulse-helpers.h
index 36cc0c1..978fd38 100644
--- a/backends/pulse/pulse-helpers.h
+++ b/backends/pulse/pulse-helpers.h
@@ -25,7 +25,7 @@
#include <pulse/pulseaudio.h>
- G_BEGIN_DECLS
+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);
diff --git a/backends/pulse/pulse-monitor.c b/backends/pulse/pulse-monitor.c
new file mode 100644
index 0000000..21613d0
--- /dev/null
+++ b/backends/pulse/pulse-monitor.c
@@ -0,0 +1,271 @@
+/*
+ * 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 <pulse/pulseaudio.h>
+
+#include "pulse-monitor.h"
+
+struct _PulseMonitorPrivate
+{
+ pa_context *context;
+ pa_proplist *proplist;
+ pa_stream *stream;
+ guint32 index_source;
+ guint32 index_sink_input;
+ gboolean enabled;
+};
+
+enum {
+ VALUE,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0, };
+
+static void pulse_monitor_class_init (PulseMonitorClass *klass);
+static void pulse_monitor_init (PulseMonitor *port);
+static void pulse_monitor_finalize (GObject *object);
+
+G_DEFINE_TYPE (PulseMonitor, pulse_monitor, G_TYPE_OBJECT);
+
+static gboolean monitor_prepare (PulseMonitor *monitor);
+static gboolean monitor_connect_record (PulseMonitor *monitor);
+static void monitor_read_cb (pa_stream *stream,
+ size_t length,
+ void *userdata);
+
+static void
+pulse_monitor_class_init (PulseMonitorClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = pulse_monitor_finalize;
+
+ signals[VALUE] =
+ g_signal_new ("value",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseMonitorClass, value),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__DOUBLE,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_DOUBLE);
+
+ g_type_class_add_private (object_class, sizeof (PulseMonitorPrivate));
+}
+
+static void
+pulse_monitor_init (PulseMonitor *monitor)
+{
+ monitor->priv = G_TYPE_INSTANCE_GET_PRIVATE (monitor,
+ PULSE_TYPE_MONITOR,
+ PulseMonitorPrivate);
+}
+
+static void
+pulse_monitor_finalize (GObject *object)
+{
+ PulseMonitor *monitor;
+
+ monitor = PULSE_MONITOR (object);
+
+ if (monitor->priv->stream)
+ pa_stream_unref (monitor->priv->stream);
+
+ pa_context_unref (monitor->priv->context);
+ pa_proplist_free (monitor->priv->proplist);
+
+ G_OBJECT_CLASS (pulse_monitor_parent_class)->finalize (object);
+}
+
+PulseMonitor *
+pulse_monitor_new (pa_context *context,
+ pa_proplist *proplist,
+ guint32 index_source,
+ guint32 index_sink_input)
+{
+ PulseMonitor *monitor;
+
+ monitor = g_object_new (PULSE_TYPE_MONITOR, NULL);
+
+ monitor->priv->context = pa_context_ref (context);
+ monitor->priv->proplist = pa_proplist_copy (proplist);
+
+ monitor->priv->index_source = index_source;
+ monitor->priv->index_sink_input = index_sink_input;
+
+ return monitor;
+}
+
+gboolean
+pulse_monitor_enable (PulseMonitor *monitor)
+{
+ g_return_val_if_fail (PULSE_IS_MONITOR (monitor), FALSE);
+
+ if (!monitor->priv->enabled) {
+ if (monitor->priv->stream == NULL)
+ monitor_prepare (monitor);
+
+ if (G_LIKELY (monitor->priv->stream != NULL))
+ monitor->priv->enabled = monitor_connect_record (monitor);
+ }
+
+ return monitor->priv->enabled;
+}
+
+void
+pulse_monitor_disable (PulseMonitor *monitor)
+{
+ g_return_if_fail (PULSE_IS_MONITOR (monitor));
+
+ if (!monitor->priv->enabled)
+ return;
+
+ pa_stream_disconnect (monitor->priv->stream);
+
+ monitor->priv->enabled = FALSE;
+}
+
+gboolean
+pulse_monitor_is_enabled (PulseMonitor *monitor)
+{
+ g_return_if_fail (PULSE_IS_MONITOR (monitor));
+
+ return monitor->priv->enabled;
+}
+
+gboolean
+pulse_monitor_update_index (PulseMonitor *monitor,
+ guint32 index_source,
+ guint32 index_sink_input)
+{
+ g_return_val_if_fail (PULSE_IS_MONITOR (monitor), FALSE);
+
+ if (monitor->priv->index_source == index_source &&
+ monitor->priv->index_sink_input == index_sink_input)
+ return TRUE;
+
+ monitor->priv->index_source = index_source;
+ monitor->priv->index_sink_input = index_sink_input;
+
+ if (pulse_monitor_is_enabled (monitor)) {
+ pulse_monitor_disable (monitor);
+
+ /* Unset the Pulse stream to let enable recreate it */
+ g_clear_pointer (&monitor->priv->stream, pa_stream_unref);
+
+ pulse_monitor_enable (monitor);
+ } else if (monitor->priv->stream) {
+ /* Disabled now but was enabled before and still holds source index */
+ g_clear_pointer (&monitor->priv->stream, pa_stream_unref);
+ }
+ return TRUE;
+}
+
+static gboolean
+monitor_prepare (PulseMonitor *monitor)
+{
+ pa_sample_spec spec;
+
+ spec.channels = 1;
+ spec.format = PA_SAMPLE_FLOAT32;
+ spec.rate = 25;
+
+ monitor->priv->stream =
+ pa_stream_new_with_proplist (monitor->priv->context, "Peak detect",
+ &spec,
+ NULL,
+ monitor->priv->proplist);
+
+ if (G_UNLIKELY (monitor->priv->stream == NULL)) {
+ g_warning ("Failed to create PulseAudio monitor: %s",
+ pa_strerror (pa_context_errno (monitor->priv->context)));
+ return FALSE;
+ }
+
+ if (monitor->priv->index_sink_input != PA_INVALID_INDEX)
+ pa_stream_set_monitor_stream (monitor->priv->stream,
+ monitor->priv->index_sink_input);
+
+ pa_stream_set_read_callback (monitor->priv->stream,
+ monitor_read_cb,
+ monitor);
+ return TRUE;
+}
+
+static gboolean
+monitor_connect_record (PulseMonitor *monitor)
+{
+ pa_buffer_attr attr;
+ gchar *name;
+ int ret;
+
+ attr.maxlength = (guint32) -1;
+ attr.tlength = 0;
+ attr.prebuf = 0;
+ attr.minreq = 0;
+ attr.fragsize = sizeof (gfloat);
+
+ name = g_strdup_printf ("%u", monitor->priv->index_source);
+ ret = pa_stream_connect_record (monitor->priv->stream,
+ name,
+ &attr,
+ PA_STREAM_DONT_MOVE |
+ PA_STREAM_PEAK_DETECT |
+ PA_STREAM_ADJUST_LATENCY |
+ PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND);
+ g_free (name);
+
+ if (ret < 0) {
+ g_warning ("Failed to connect PulseAudio monitor: %s", pa_strerror (ret));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+monitor_read_cb (pa_stream *stream, size_t length, void *userdata)
+{
+ const void *data;
+ int ret;
+
+ ret = pa_stream_peek (stream, &data, &length);
+ if (ret < 0) {
+ g_debug ("Failed to read PulseAudio stream data: %s", pa_strerror (ret));
+ return;
+ }
+
+ if (data) {
+ gdouble v = ((const gfloat *) data)[length / sizeof (gfloat) - 1];
+
+ g_signal_emit (G_OBJECT (userdata),
+ signals[VALUE],
+ 0,
+ CLAMP (v, 0, 1));
+ }
+
+ /* pa_stream_drop() should not be called if the buffer is empty, but it
+ * should be called if there is a hole */
+ if (length)
+ pa_stream_drop (stream);
+}
diff --git a/backends/pulse/pulse-monitor.h b/backends/pulse/pulse-monitor.h
new file mode 100644
index 0000000..d82d5cf
--- /dev/null
+++ b/backends/pulse/pulse-monitor.h
@@ -0,0 +1,79 @@
+/*
+ * 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_MONITOR_H
+#define PULSE_MONITOR_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <pulse/pulseaudio.h>
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_MONITOR \
+ (pulse_monitor_get_type ())
+#define PULSE_MONITOR(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_MONITOR, PulseMonitor))
+#define PULSE_IS_MONITOR(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_MONITOR))
+#define PULSE_MONITOR_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_MONITOR, PulseMonitorClass))
+#define PULSE_IS_MONITOR_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_MONITOR))
+#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;
+
+struct _PulseMonitor
+{
+ GObject parent;
+
+ /*< private >*/
+ PulseMonitorPrivate *priv;
+};
+
+struct _PulseMonitorClass
+{
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (*value) (PulseMonitor *monitor,
+ gdouble value);
+};
+
+GType pulse_monitor_get_type (void) G_GNUC_CONST;
+
+PulseMonitor *pulse_monitor_new (pa_context *context,
+ pa_proplist *proplist,
+ guint32 index_source,
+ guint32 index_sink_input);
+
+gboolean pulse_monitor_enable (PulseMonitor *monitor);
+void pulse_monitor_disable (PulseMonitor *monitor);
+gboolean pulse_monitor_is_enabled (PulseMonitor *monitor);
+
+gboolean pulse_monitor_update_index (PulseMonitor *monitor,
+ guint32 index_source,
+ guint32 index_sink_input);
+
+G_END_DECLS
+
+#endif /* PULSE_MONITOR_H */
diff --git a/backends/pulse/pulse-sink-input.c b/backends/pulse/pulse-sink-input.c
index 8540193..74734dc 100644
--- a/backends/pulse/pulse-sink-input.c
+++ b/backends/pulse/pulse-sink-input.c
@@ -15,41 +15,35 @@
* 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-stream.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
#include "pulse-client-stream.h"
+#include "pulse-monitor.h"
+#include "pulse-sink.h"
#include "pulse-sink-input.h"
#include "pulse-stream.h"
-struct _PulseSinkInputPrivate
-{
- guint32 index_monitor;
-};
-
-static gboolean sink_input_set_mute (MateMixerStream *stream,
- gboolean mute);
-static gboolean sink_input_set_volume (MateMixerStream *stream,
- pa_cvolume *volume);
-static gboolean sink_input_set_parent (MateMixerClientStream *stream,
- MateMixerStream *parent);
-
-static gboolean sink_input_remove (MateMixerClientStream *stream);
+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_init (PulseSinkInput *input)
-{
- input->priv = G_TYPE_INSTANCE_GET_PRIVATE (input,
- PULSE_TYPE_SINK_INPUT,
- PulseSinkInputPrivate);
-}
+static gboolean sink_input_set_mute (MateMixerStream *stream,
+ gboolean mute);
+static gboolean sink_input_set_volume (MateMixerStream *stream,
+ pa_cvolume *volume);
+static gboolean sink_input_set_parent (MateMixerClientStream *stream,
+ MateMixerStream *parent);
+static gboolean sink_input_remove (MateMixerClientStream *stream);
+static PulseMonitor *sink_input_create_monitor (MateMixerStream *stream);
static void
pulse_sink_input_class_init (PulseSinkInputClass *klass)
@@ -59,22 +53,31 @@ pulse_sink_input_class_init (PulseSinkInputClass *klass)
stream_class = PULSE_STREAM_CLASS (klass);
- stream_class->set_mute = sink_input_set_mute;
- stream_class->set_volume = sink_input_set_volume;
+ stream_class->set_mute = sink_input_set_mute;
+ stream_class->set_volume = sink_input_set_volume;
+ stream_class->create_monitor = sink_input_create_monitor;
client_class = PULSE_CLIENT_STREAM_CLASS (klass);
client_class->set_parent = sink_input_set_parent;
client_class->remove = sink_input_remove;
+}
- g_type_class_add_private (klass, sizeof (PulseSinkInputPrivate));
+static void
+pulse_sink_input_init (PulseSinkInput *input)
+{
}
PulseStream *
-pulse_sink_input_new (PulseConnection *connection, const pa_sink_input_info *info)
+pulse_sink_input_new (PulseConnection *connection,
+ const pa_sink_input_info *info,
+ PulseStream *parent)
{
PulseSinkInput *input;
+ 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 */
input = g_object_new (PULSE_TYPE_SINK_INPUT,
"connection", connection,
@@ -82,35 +85,56 @@ pulse_sink_input_new (PulseConnection *connection, const pa_sink_input_info *inf
NULL);
/* Other data may change at any time, so let's make a use of our update function */
- pulse_sink_input_update (PULSE_STREAM (input), info);
+ pulse_sink_input_update (PULSE_STREAM (input), info, parent);
return PULSE_STREAM (input);
}
gboolean
-pulse_sink_input_update (PulseStream *stream, const pa_sink_input_info *info)
+pulse_sink_input_update (PulseStream *stream,
+ const pa_sink_input_info *info,
+ PulseStream *parent)
{
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_OUTPUT |
- MATE_MIXER_STREAM_CLIENT |
- MATE_MIXER_STREAM_HAS_MUTE;
+ MateMixerStreamFlags flags = MATE_MIXER_STREAM_OUTPUT |
+ MATE_MIXER_STREAM_CLIENT |
+ MATE_MIXER_STREAM_HAS_MUTE |
+ MATE_MIXER_STREAM_HAS_MONITOR;
+ gchar *name;
+
+ const gchar *prop;
+ const gchar *description = NULL;
g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), FALSE);
/* Let all the information update before emitting notify signals */
g_object_freeze_notify (G_OBJECT (stream));
- pulse_stream_update_name (stream, info->name);
- // pulse_stream_update_description (stream, info->description);
- pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
- pulse_stream_update_channel_map (stream, &info->channel_map);
+ /* 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 Pulse index. */
+ name = g_strdup_printf ("pulse-stream-client-output-%lu", (gulong) info->index);
- /* Build the flag list */
- if (info->has_volume) {
- flags |= MATE_MIXER_STREAM_HAS_VOLUME;
- pulse_stream_update_volume (stream, &info->volume);
+ pulse_stream_update_name (stream, name);
+ g_free (name);
+
+ prop = pa_proplist_gets (info->proplist, PA_PROP_MEDIA_ROLE);
+
+ if (prop != NULL && !strcmp (prop, "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;
+
+ flags |= MATE_MIXER_STREAM_EVENT;
}
- if (info->volume_writable)
- flags |= MATE_MIXER_STREAM_CAN_SET_VOLUME;
+ if (description == NULL)
+ description = info->name;
+
+ pulse_stream_update_description (stream, description);
+ pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
if (info->client != PA_INVALID_INDEX)
flags |= MATE_MIXER_STREAM_APPLICATION;
@@ -120,8 +144,56 @@ pulse_sink_input_update (PulseStream *stream, const pa_sink_input_info *info)
if (pa_channel_map_can_fade (&info->channel_map))
flags |= MATE_MIXER_STREAM_CAN_FADE;
+#if PA_CHECK_VERSION(1, 0, 0)
+ if (info->has_volume)
+ flags |=
+ MATE_MIXER_STREAM_HAS_VOLUME |
+ MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME;
+ if (info->volume_writable)
+ flags |= MATE_MIXER_STREAM_CAN_SET_VOLUME;
+
+ /* Flags needed before volume */
pulse_stream_update_flags (stream, flags);
+ if (info->has_volume)
+ pulse_stream_update_volume (stream, &info->volume, &info->channel_map);
+ else
+ pulse_stream_update_volume (stream, NULL, &info->channel_map);
+#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;
+
+ /* Flags needed before volume */
+ pulse_stream_update_flags (stream, flags);
+
+ pulse_stream_update_volume (stream, &info->volume, &info->channel_map);
+#endif
+
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_NAME);
+ if (prop != NULL)
+ pulse_client_stream_update_app_name (MATE_MIXER_CLIENT_STREAM (stream), prop);
+
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ID);
+ if (prop != NULL)
+ pulse_client_stream_update_app_id (MATE_MIXER_CLIENT_STREAM (stream), prop);
+
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_VERSION);
+ if (prop != NULL)
+ pulse_client_stream_update_app_version (MATE_MIXER_CLIENT_STREAM (stream), prop);
+
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ICON_NAME);
+ if (prop != NULL)
+ pulse_client_stream_update_app_icon (MATE_MIXER_CLIENT_STREAM (stream), prop);
+
+ pulse_client_stream_update_parent (MATE_MIXER_CLIENT_STREAM (stream),
+ MATE_MIXER_STREAM (parent));
+
+ // XXX needs to fix monitor if parent changes
+
g_object_thaw_notify (G_OBJECT (stream));
return TRUE;
}
@@ -129,42 +201,91 @@ pulse_sink_input_update (PulseStream *stream, const pa_sink_input_info *info)
static gboolean
sink_input_set_mute (MateMixerStream *stream, gboolean mute)
{
- PulseStream *ps;
+ PulseStream *pulse;
g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), FALSE);
- ps = PULSE_STREAM (stream);
+ pulse = PULSE_STREAM (stream);
- return pulse_connection_set_sink_input_mute (pulse_stream_get_connection (ps),
- pulse_stream_get_index (ps),
+ return pulse_connection_set_sink_input_mute (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
mute);
}
static gboolean
sink_input_set_volume (MateMixerStream *stream, pa_cvolume *volume)
{
- PulseStream *ps;
+ PulseStream *pulse;
g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), FALSE);
g_return_val_if_fail (volume != NULL, FALSE);
- ps = PULSE_STREAM (stream);
+ pulse = PULSE_STREAM (stream);
- return pulse_connection_set_sink_input_volume (pulse_stream_get_connection (ps),
- pulse_stream_get_index (ps),
+ return pulse_connection_set_sink_input_volume (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
volume);
}
static gboolean
sink_input_set_parent (MateMixerClientStream *stream, MateMixerStream *parent)
{
- // TODO
- return TRUE;
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), FALSE);
+
+ if (G_UNLIKELY (!PULSE_IS_SINK (parent))) {
+ g_warning ("Could not change stream parent to %s: not a parent output stream",
+ mate_mixer_stream_get_name (parent));
+ return FALSE;
+ }
+
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_move_sink_input (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
+ pulse_stream_get_index (PULSE_STREAM (parent)));
}
static gboolean
sink_input_remove (MateMixerClientStream *stream)
{
- // TODO
- return TRUE;
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), FALSE);
+
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_kill_sink_input (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse));
+}
+
+static PulseMonitor *
+sink_input_create_monitor (MateMixerStream *stream)
+{
+ MateMixerStream *parent;
+ PulseStream *pulse;
+ guint32 index;
+
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), NULL);
+
+ parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (stream));
+ if (G_UNLIKELY (parent == NULL)) {
+ g_debug ("Not creating monitor for client stream %s as it is not available",
+ mate_mixer_stream_get_name (stream));
+ return NULL;
+ }
+
+ pulse = PULSE_STREAM (stream);
+ index = pulse_sink_get_monitor_index (PULSE_STREAM (parent));
+
+ 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 (stream));
+ return NULL;
+ }
+
+ return pulse_connection_create_monitor (pulse_stream_get_connection (pulse),
+ index,
+ pulse_stream_get_index (pulse));
}
diff --git a/backends/pulse/pulse-sink-input.h b/backends/pulse/pulse-sink-input.h
index 110ca9c..a498999 100644
--- a/backends/pulse/pulse-sink-input.h
+++ b/backends/pulse/pulse-sink-input.h
@@ -21,11 +21,11 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-stream.h>
-
#include <pulse/pulseaudio.h>
#include "pulse-client-stream.h"
+#include "pulse-connection.h"
+#include "pulse-stream.h"
G_BEGIN_DECLS
@@ -38,33 +38,32 @@ G_BEGIN_DECLS
#define PULSE_SINK_INPUT_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SINK_INPUT, PulseSinkInputClass))
#define PULSE_IS_SINK_INPUT_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SINK_INPUT))
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SINK_INPUT))
#define PULSE_SINK_INPUT_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SINK_INPUT, PulseSinkInputClass))
-typedef struct _PulseSinkInput PulseSinkInput;
-typedef struct _PulseSinkInputClass PulseSinkInputClass;
-typedef struct _PulseSinkInputPrivate PulseSinkInputPrivate;
+typedef struct _PulseSinkInput PulseSinkInput;
+typedef struct _PulseSinkInputClass PulseSinkInputClass;
struct _PulseSinkInput
{
PulseClientStream parent;
-
- PulseSinkInputPrivate *priv;
};
struct _PulseSinkInputClass
{
- PulseClientStreamClass parent;
+ PulseClientStreamClass parent_class;
};
GType pulse_sink_input_get_type (void) G_GNUC_CONST;
PulseStream *pulse_sink_input_new (PulseConnection *connection,
- const pa_sink_input_info *info);
+ const pa_sink_input_info *info,
+ PulseStream *parent);
gboolean pulse_sink_input_update (PulseStream *stream,
- const pa_sink_input_info *info);
+ const pa_sink_input_info *info,
+ PulseStream *parent);
G_END_DECLS
diff --git a/backends/pulse/pulse-sink.c b/backends/pulse/pulse-sink.c
index 53ed64f..b7a440b 100644
--- a/backends/pulse/pulse-sink.c
+++ b/backends/pulse/pulse-sink.c
@@ -19,11 +19,11 @@
#include <glib-object.h>
#include <libmatemixer/matemixer-stream.h>
-#include <libmatemixer/matemixer-port.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
+#include "pulse-monitor.h"
#include "pulse-stream.h"
#include "pulse-sink.h"
@@ -32,27 +32,20 @@ struct _PulseSinkPrivate
guint32 index_monitor;
};
-enum {
- PROP_0,
- N_PROPERTIES
-};
-
-static gboolean sink_set_mute (MateMixerStream *stream,
- gboolean mute);
-static gboolean sink_set_volume (MateMixerStream *stream,
- pa_cvolume *volume);
-static gboolean sink_set_active_port (MateMixerStream *stream,
- const gchar *port_name);
+static void pulse_sink_class_init (PulseSinkClass *klass);
+static void pulse_sink_init (PulseSink *sink);
G_DEFINE_TYPE (PulseSink, pulse_sink, PULSE_TYPE_STREAM);
-static void
-pulse_sink_init (PulseSink *sink)
-{
- sink->priv = G_TYPE_INSTANCE_GET_PRIVATE (sink,
- PULSE_TYPE_SINK,
- PulseSinkPrivate);
-}
+static gboolean sink_set_mute (MateMixerStream *stream,
+ gboolean mute);
+static gboolean sink_set_volume (MateMixerStream *stream,
+ pa_cvolume *volume);
+static gboolean sink_set_active_port (MateMixerStream *stream,
+ const gchar *port);
+static gboolean sink_suspend (MateMixerStream *stream);
+static gboolean sink_resume (MateMixerStream *stream);
+static PulseMonitor *sink_create_monitor (MateMixerStream *stream);
static void
pulse_sink_class_init (PulseSinkClass *klass)
@@ -64,43 +57,30 @@ pulse_sink_class_init (PulseSinkClass *klass)
stream_class->set_mute = sink_set_mute;
stream_class->set_volume = sink_set_volume;
stream_class->set_active_port = sink_set_active_port;
+ stream_class->suspend = sink_suspend;
+ stream_class->resume = sink_resume;
+ stream_class->create_monitor = sink_create_monitor;
g_type_class_add_private (klass, sizeof (PulseSinkPrivate));
}
+static void
+pulse_sink_init (PulseSink *sink)
+{
+ sink->priv = G_TYPE_INSTANCE_GET_PRIVATE (sink,
+ PULSE_TYPE_SINK,
+ PulseSinkPrivate);
+
+ sink->priv->index_monitor = PA_INVALID_INDEX;
+}
+
PulseStream *
pulse_sink_new (PulseConnection *connection, const pa_sink_info *info)
{
PulseSink *sink;
- GList *ports = NULL;
- int i;
-
- /* Convert the list of sink ports to a GList of MateMixerPorts */
- for (i = 0; i < info->n_ports; i++) {
- MateMixerPort *port;
- MateMixerPortStatus status = MATE_MIXER_PORT_UNKNOWN_STATUS;
- pa_sink_port_info *p_info = info->ports[i];
-
-#if PA_CHECK_VERSION(2, 0, 0)
- switch (p_info->available) {
- case PA_PORT_AVAILABLE_YES:
- status = MATE_MIXER_PORT_AVAILABLE;
- break;
- case PA_PORT_AVAILABLE_NO:
- status = MATE_MIXER_PORT_UNAVAILABLE;
- break;
- default:
- break;
- }
-#endif
- port = mate_mixer_port_new (p_info->name,
- p_info->description,
- NULL,
- p_info->priority,
- status);
- ports = g_list_prepend (ports, port);
- }
+ 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 */
sink = g_object_new (PULSE_TYPE_SINK,
@@ -108,58 +88,78 @@ pulse_sink_new (PulseConnection *connection, const pa_sink_info *info)
"index", info->index,
NULL);
- /* According to the PulseAudio code, the list of sink port never changes with
- * updates.
- * This may be not future-proof, but checking and validating the list of ports on
- * each update would be an expensive operation, so let's set the list only during
- * the construction */
- pulse_stream_update_ports (PULSE_STREAM (sink), g_list_reverse (ports));
-
/* Other data may change at any time, so let's make a use of our update function */
pulse_sink_update (PULSE_STREAM (sink), info);
return PULSE_STREAM (sink);
}
+guint32
+pulse_sink_get_monitor_index (PulseStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_SINK (stream), PA_INVALID_INDEX);
+
+ return PULSE_SINK (stream)->priv->index_monitor;
+}
+
gboolean
pulse_sink_update (PulseStream *stream, const pa_sink_info *info)
{
- PulseSink *sink;
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_OUTPUT |
- MATE_MIXER_STREAM_HAS_MUTE |
- MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_CAN_SET_VOLUME;
+ MateMixerStreamFlags flags = MATE_MIXER_STREAM_OUTPUT |
+ MATE_MIXER_STREAM_HAS_MUTE |
+ MATE_MIXER_STREAM_HAS_VOLUME |
+ MATE_MIXER_STREAM_HAS_MONITOR |
+ MATE_MIXER_STREAM_CAN_SET_VOLUME |
+ MATE_MIXER_STREAM_CAN_SUSPEND;
+ PulseSink *sink;
+ GList *ports = NULL;
+ guint32 i;
g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
- sink = PULSE_SINK (stream);
-
/* Let all the information update before emitting notify signals */
g_object_freeze_notify (G_OBJECT (stream));
pulse_stream_update_name (stream, info->name);
pulse_stream_update_description (stream, info->description);
pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
- pulse_stream_update_channel_map (stream, &info->channel_map);
- pulse_stream_update_volume_extended (stream,
- &info->volume,
- info->base_volume,
- info->n_volume_steps);
+
+ /* List of ports */
+ for (i = 0; i < info->n_ports; i++) {
+ MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
+
+#if PA_CHECK_VERSION(2, 0, 0)
+ if (info->ports[i]->available == PA_PORT_AVAILABLE_YES)
+ flags |= MATE_MIXER_PORT_AVAILABLE;
+#endif
+ ports = g_list_prepend (ports,
+ mate_mixer_port_new (info->ports[i]->name,
+ info->ports[i]->description,
+ NULL,
+ info->ports[i]->priority,
+ flags));
+ }
+ pulse_stream_update_ports (stream, ports);
+
+ /* Active port */
if (info->active_port)
pulse_stream_update_active_port (stream, info->active_port->name);
+ else
+ pulse_stream_update_active_port (stream, NULL);
+ /* Stream state */
switch (info->state) {
case PA_SINK_RUNNING:
- pulse_stream_update_status (stream, MATE_MIXER_STREAM_RUNNING);
+ pulse_stream_update_state (stream, MATE_MIXER_STREAM_RUNNING);
break;
case PA_SINK_IDLE:
- pulse_stream_update_status (stream, MATE_MIXER_STREAM_IDLE);
+ pulse_stream_update_state (stream, MATE_MIXER_STREAM_IDLE);
break;
case PA_SINK_SUSPENDED:
- pulse_stream_update_status (stream, MATE_MIXER_STREAM_SUSPENDED);
+ pulse_stream_update_state (stream, MATE_MIXER_STREAM_SUSPENDED);
break;
default:
- pulse_stream_update_status (stream, MATE_MIXER_STREAM_UNKNOWN_STATUS);
+ pulse_stream_update_state (stream, MATE_MIXER_STREAM_UNKNOWN_STATE);
break;
}
@@ -169,21 +169,35 @@ pulse_sink_update (PulseStream *stream, const pa_sink_info *info)
if (info->flags & PA_SINK_FLAT_VOLUME)
flags |= MATE_MIXER_STREAM_HAS_FLAT_VOLUME;
- if (info->monitor_source_name)
- flags |= MATE_MIXER_STREAM_OUTPUT_MONITOR;
-
if (pa_channel_map_can_balance (&info->channel_map))
flags |= MATE_MIXER_STREAM_CAN_BALANCE;
if (pa_channel_map_can_fade (&info->channel_map))
flags |= MATE_MIXER_STREAM_CAN_FADE;
+ /* Flags must be updated before volume */
pulse_stream_update_flags (stream, flags);
+ pulse_stream_update_volume_extended (stream,
+ &info->volume,
+ &info->channel_map,
+ info->base_volume,
+ info->n_volume_steps);
+
+ sink = PULSE_SINK (stream);
+
+ /* Handle change of monitoring source index */
+ // XXX probably call this each time to validate
if (sink->priv->index_monitor != info->monitor_source) {
- sink->priv->index_monitor = info->monitor_source;
+ PulseMonitor *monitor;
+
+ monitor = pulse_stream_get_monitor (PULSE_STREAM (stream));
- // TODO: provide a property
- // g_object_notify (G_OBJECT (stream), "monitor");
+ if (monitor)
+ pulse_monitor_update_index (monitor,
+ info->monitor_source,
+ PA_INVALID_INDEX);
+
+ sink->priv->index_monitor = info->monitor_source;
}
g_object_thaw_notify (G_OBJECT (stream));
@@ -193,31 +207,93 @@ pulse_sink_update (PulseStream *stream, const pa_sink_info *info)
static gboolean
sink_set_mute (MateMixerStream *stream, gboolean mute)
{
+ PulseStream *pulse;
+
g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
- return pulse_connection_set_sink_mute (pulse_stream_get_connection (PULSE_STREAM (stream)),
- pulse_stream_get_index (PULSE_STREAM (stream)),
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_set_sink_mute (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
mute);
}
static gboolean
sink_set_volume (MateMixerStream *stream, pa_cvolume *volume)
{
+ PulseStream *pulse;
+
g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
g_return_val_if_fail (volume != NULL, FALSE);
- return pulse_connection_set_sink_volume (pulse_stream_get_connection (PULSE_STREAM (stream)),
- pulse_stream_get_index (PULSE_STREAM (stream)),
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_set_sink_volume (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
volume);
}
static gboolean
-sink_set_active_port (MateMixerStream *stream, const gchar *port_name)
+sink_set_active_port (MateMixerStream *stream, const gchar *port)
{
+ PulseStream *pulse;
+
g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
- g_return_val_if_fail (port_name != NULL, FALSE);
+ g_return_val_if_fail (port != NULL, FALSE);
+
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_set_sink_port (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
+ port);
+}
+
+static gboolean
+sink_suspend (MateMixerStream *stream)
+{
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
+
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_suspend_sink (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
+ TRUE);
+}
+
+static gboolean
+sink_resume (MateMixerStream *stream)
+{
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
+
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_suspend_sink (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
+ FALSE);
+}
+
+static PulseMonitor *
+sink_create_monitor (MateMixerStream *stream)
+{
+ PulseStream *pulse;
+ guint32 index;
+
+ g_return_val_if_fail (PULSE_IS_SINK (stream), NULL);
+
+ pulse = PULSE_STREAM (stream);
+ index = pulse_sink_get_monitor_index (pulse);
+
+ if (G_UNLIKELY (index == PA_INVALID_INDEX)) {
+ g_debug ("Not creating monitor for stream %s as it is not available",
+ mate_mixer_stream_get_name (stream));
+ return NULL;
+ }
- return pulse_connection_set_sink_port (pulse_stream_get_connection (PULSE_STREAM (stream)),
- pulse_stream_get_index (PULSE_STREAM (stream)),
- port_name);
+ return pulse_connection_create_monitor (pulse_stream_get_connection (pulse),
+ index,
+ PA_INVALID_INDEX);
}
diff --git a/backends/pulse/pulse-sink.h b/backends/pulse/pulse-sink.h
index 22ca41f..e345d48 100644
--- a/backends/pulse/pulse-sink.h
+++ b/backends/pulse/pulse-sink.h
@@ -21,10 +21,9 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-stream.h>
-
#include <pulse/pulseaudio.h>
+#include "pulse-connection.h"
#include "pulse-stream.h"
G_BEGIN_DECLS
@@ -38,7 +37,7 @@ G_BEGIN_DECLS
#define PULSE_SINK_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SINK, PulseSinkClass))
#define PULSE_IS_SINK_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SINK))
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SINK))
#define PULSE_SINK_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SINK, PulseSinkClass))
@@ -50,21 +49,24 @@ struct _PulseSink
{
PulseStream parent;
+ /*< private >*/
PulseSinkPrivate *priv;
};
struct _PulseSinkClass
{
- PulseStreamClass parent;
+ 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);
-PulseStream *pulse_sink_new (PulseConnection *connection,
- const pa_sink_info *info);
+guint32 pulse_sink_get_monitor_index (PulseStream *stream);
-gboolean pulse_sink_update (PulseStream *stream,
- const pa_sink_info *info);
+gboolean pulse_sink_update (PulseStream *stream,
+ const pa_sink_info *info);
G_END_DECLS
diff --git a/backends/pulse/pulse-source-output.c b/backends/pulse/pulse-source-output.c
index 94a4963..50269ce 100644
--- a/backends/pulse/pulse-source-output.c
+++ b/backends/pulse/pulse-source-output.c
@@ -17,44 +17,55 @@
#include <glib.h>
#include <glib-object.h>
+#include <string.h>
+#include <libmatemixer/matemixer-client-stream.h>
#include <libmatemixer/matemixer-stream.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
+#include "pulse-client-stream.h"
+#include "pulse-monitor.h"
#include "pulse-stream.h"
+#include "pulse-source.h"
#include "pulse-source-output.h"
-struct _PulseSourceOutputPrivate
-{
- guint32 index_monitor;
-};
-
-static gboolean source_output_set_mute (MateMixerStream *stream, gboolean mute);
-static gboolean source_output_set_volume (MateMixerStream *stream, pa_cvolume *volume);
+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_STREAM);
+G_DEFINE_TYPE (PulseSourceOutput, pulse_source_output, PULSE_TYPE_CLIENT_STREAM);
-static void
-pulse_source_output_init (PulseSourceOutput *output)
-{
- output->priv = G_TYPE_INSTANCE_GET_PRIVATE (output,
- PULSE_TYPE_SOURCE_OUTPUT,
- PulseSourceOutputPrivate);
-}
+static gboolean source_output_set_mute (MateMixerStream *stream,
+ gboolean mute);
+static gboolean source_output_set_volume (MateMixerStream *stream,
+ pa_cvolume *volume);
+static gboolean source_output_set_parent (MateMixerClientStream *stream,
+ MateMixerStream *parent);
+static gboolean source_output_remove (MateMixerClientStream *stream);
+static PulseMonitor *source_output_create_monitor (MateMixerStream *stream);
static void
pulse_source_output_class_init (PulseSourceOutputClass *klass)
{
- PulseStreamClass *stream_class;
+ PulseStreamClass *stream_class;
+ PulseClientStreamClass *client_class;
stream_class = PULSE_STREAM_CLASS (klass);
- stream_class->set_mute = source_output_set_mute;
- stream_class->set_volume = source_output_set_volume;
+ stream_class->set_mute = source_output_set_mute;
+ stream_class->set_volume = source_output_set_volume;
+ stream_class->create_monitor = source_output_create_monitor;
- g_type_class_add_private (klass, sizeof (PulseSourceOutputPrivate));
+ client_class = PULSE_CLIENT_STREAM_CLASS (klass);
+
+ client_class->set_parent = source_output_set_parent;
+ client_class->remove = source_output_remove;
+}
+
+static void
+pulse_source_output_init (PulseSourceOutput *output)
+{
}
PulseStream *
@@ -62,6 +73,9 @@ pulse_source_output_new (PulseConnection *connection, const pa_source_output_inf
{
PulseSourceOutput *output;
+ 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,
@@ -77,27 +91,59 @@ pulse_source_output_new (PulseConnection *connection, const pa_source_output_inf
gboolean
pulse_source_output_update (PulseStream *stream, const pa_source_output_info *info)
{
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_INPUT |
- MATE_MIXER_STREAM_CLIENT |
- MATE_MIXER_STREAM_HAS_MUTE;
+ MateMixerStreamFlags flags = MATE_MIXER_STREAM_INPUT |
+ MATE_MIXER_STREAM_CLIENT;
+ gchar *name;
+
+ const gchar *prop;
+ const gchar *description = NULL;
g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), FALSE);
/* Let all the information update before emitting notify signals */
g_object_freeze_notify (G_OBJECT (stream));
- pulse_stream_update_name (stream, info->name);
- // pulse_stream_update_description (stream, info->description);
- pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
- pulse_stream_update_channel_map (stream, &info->channel_map);
+ /* 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);
- /* Build the flag list */
- if (info->has_volume) {
- flags |= MATE_MIXER_STREAM_HAS_VOLUME;
- pulse_stream_update_volume (stream, &info->volume);
+ pulse_stream_update_name (stream, name);
+ g_free (name);
+
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_NAME);
+ if (prop != NULL)
+ pulse_client_stream_update_app_name (MATE_MIXER_CLIENT_STREAM (stream), prop);
+
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ID);
+ if (prop != NULL)
+ pulse_client_stream_update_app_id (MATE_MIXER_CLIENT_STREAM (stream), prop);
+
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_VERSION);
+ if (prop != NULL)
+ pulse_client_stream_update_app_version (MATE_MIXER_CLIENT_STREAM (stream), prop);
+
+ prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ICON_NAME);
+ if (prop != NULL)
+ pulse_client_stream_update_app_icon (MATE_MIXER_CLIENT_STREAM (stream), prop);
+
+ prop = pa_proplist_gets (info->proplist, PA_PROP_MEDIA_ROLE);
+
+ if (prop != NULL && !strcmp (prop, "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;
+
+ flags |= MATE_MIXER_STREAM_EVENT;
}
- if (info->volume_writable)
- flags |= MATE_MIXER_STREAM_CAN_SET_VOLUME;
+ if (description == NULL)
+ description = info->name;
+
+ pulse_stream_update_description (stream, description);
if (info->client != PA_INVALID_INDEX)
flags |= MATE_MIXER_STREAM_APPLICATION;
@@ -107,7 +153,27 @@ pulse_source_output_update (PulseStream *stream, const pa_source_output_info *in
if (pa_channel_map_can_fade (&info->channel_map))
flags |= MATE_MIXER_STREAM_CAN_FADE;
+#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;
+
pulse_stream_update_flags (stream, flags);
+ pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
+
+ if (info->has_volume)
+ pulse_stream_update_volume (stream, &info->volume, &info->channel_map);
+ else
+ pulse_stream_update_volume (stream, NULL, &info->channel_map);
+#else
+ pulse_stream_update_flags (stream, flags);
+ pulse_stream_update_volume (stream, NULL, &info->channel_map);
+#endif
+
+ // XXX needs to fix monitor if parent changes
g_object_thaw_notify (G_OBJECT (stream));
return TRUE;
@@ -116,28 +182,80 @@ pulse_source_output_update (PulseStream *stream, const pa_source_output_info *in
static gboolean
source_output_set_mute (MateMixerStream *stream, gboolean mute)
{
- PulseStream *ps;
+ PulseStream *pulse;
g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), FALSE);
- ps = PULSE_STREAM (stream);
+ pulse = PULSE_STREAM (stream);
- return pulse_connection_set_source_output_mute (pulse_stream_get_connection (ps),
- pulse_stream_get_index (ps),
+ return pulse_connection_set_source_output_mute (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
mute);
}
static gboolean
source_output_set_volume (MateMixerStream *stream, pa_cvolume *volume)
{
- PulseStream *ps;
+ PulseStream *pulse;
g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), FALSE);
g_return_val_if_fail (volume != NULL, FALSE);
- ps = PULSE_STREAM (stream);
+ pulse = PULSE_STREAM (stream);
- return pulse_connection_set_source_output_volume (pulse_stream_get_connection (ps),
- pulse_stream_get_index (ps),
+ return pulse_connection_set_source_output_volume (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
volume);
}
+
+static gboolean
+source_output_set_parent (MateMixerClientStream *stream, MateMixerStream *parent)
+{
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), FALSE);
+
+ if (G_UNLIKELY (!PULSE_IS_SOURCE (parent))) {
+ g_warning ("Could not change stream parent to %s: not a parent input stream",
+ mate_mixer_stream_get_name (parent));
+ return FALSE;
+ }
+
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_move_sink_input (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
+ pulse_stream_get_index (PULSE_STREAM (parent)));
+}
+
+static gboolean
+source_output_remove (MateMixerClientStream *stream)
+{
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), FALSE);
+
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_kill_source_output (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse));
+}
+
+static PulseMonitor *
+source_output_create_monitor (MateMixerStream *stream)
+{
+ MateMixerStream *parent;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), NULL);
+
+ parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (stream));
+ if (G_UNLIKELY (parent == NULL)) {
+ g_debug ("Not creating monitor for client stream %s as it is not available",
+ mate_mixer_stream_get_name (stream));
+ return NULL;
+ }
+
+ return pulse_connection_create_monitor (pulse_stream_get_connection (PULSE_STREAM (stream)),
+ pulse_stream_get_index (PULSE_STREAM (parent)),
+ PA_INVALID_INDEX);
+}
diff --git a/backends/pulse/pulse-source-output.h b/backends/pulse/pulse-source-output.h
index 554819f..7413eb1 100644
--- a/backends/pulse/pulse-source-output.h
+++ b/backends/pulse/pulse-source-output.h
@@ -21,10 +21,10 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-stream.h>
-
#include <pulse/pulseaudio.h>
+#include "pulse-client-stream.h"
+#include "pulse-connection.h"
#include "pulse-stream.h"
G_BEGIN_DECLS
@@ -38,7 +38,7 @@ G_BEGIN_DECLS
#define PULSE_SOURCE_OUTPUT_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SOURCE_OUTPUT, PulseSourceOutputClass))
#define PULSE_IS_SOURCE_OUTPUT_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SOURCE_OUTPUT))
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SOURCE_OUTPUT))
#define PULSE_SOURCE_OUTPUT_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SOURCE_OUTPUT, PulseSourceOutputClass))
@@ -48,14 +48,12 @@ typedef struct _PulseSourceOutputPrivate PulseSourceOutputPrivate;
struct _PulseSourceOutput
{
- PulseStream parent;
-
- PulseSourceOutputPrivate *priv;
+ PulseClientStream parent;
};
struct _PulseSourceOutputClass
{
- PulseStreamClass parent;
+ PulseClientStreamClass parent_class;
};
GType pulse_source_output_get_type (void) G_GNUC_CONST;
diff --git a/backends/pulse/pulse-source.c b/backends/pulse/pulse-source.c
index 2aea6b6..e4de5fa 100644
--- a/backends/pulse/pulse-source.c
+++ b/backends/pulse/pulse-source.c
@@ -24,30 +24,22 @@
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
+#include "pulse-monitor.h"
#include "pulse-stream.h"
#include "pulse-source.h"
-struct _PulseSourcePrivate
-{
- guint32 index_monitored_sink;
-};
-
-static gboolean source_set_mute (MateMixerStream *stream,
- gboolean mute);
-static gboolean source_set_volume (MateMixerStream *stream,
- pa_cvolume *volume);
-static gboolean source_set_active_port (MateMixerStream *stream,
- const gchar *port_name);
+static void pulse_source_class_init (PulseSourceClass *klass);
+static void pulse_source_init (PulseSource *source);
G_DEFINE_TYPE (PulseSource, pulse_source, PULSE_TYPE_STREAM);
-static void
-pulse_source_init (PulseSource *source)
-{
- source->priv = G_TYPE_INSTANCE_GET_PRIVATE (source,
- PULSE_TYPE_SOURCE,
- PulseSourcePrivate);
-}
+static gboolean source_set_mute (MateMixerStream *stream,
+ gboolean mute);
+static gboolean source_set_volume (MateMixerStream *stream,
+ pa_cvolume *volume);
+static gboolean source_set_active_port (MateMixerStream *stream,
+ const gchar *port_name);
+static PulseMonitor *source_create_monitor (MateMixerStream *stream);
static void
pulse_source_class_init (PulseSourceClass *klass)
@@ -59,55 +51,28 @@ pulse_source_class_init (PulseSourceClass *klass)
stream_class->set_mute = source_set_mute;
stream_class->set_volume = source_set_volume;
stream_class->set_active_port = source_set_active_port;
+ stream_class->create_monitor = source_create_monitor;
+}
- g_type_class_add_private (klass, sizeof (PulseSourcePrivate));
+static void
+pulse_source_init (PulseSource *source)
+{
}
PulseStream *
pulse_source_new (PulseConnection *connection, const pa_source_info *info)
{
PulseSource *source;
- GList *ports = NULL;
- int i;
-
- for (i = 0; i < info->n_ports; i++) {
- MateMixerPort *port;
- MateMixerPortStatus status = MATE_MIXER_PORT_UNKNOWN_STATUS;
- pa_source_port_info *p_info = info->ports[i];
-#if PA_CHECK_VERSION(2, 0, 0)
- switch (p_info->available) {
- case PA_PORT_AVAILABLE_YES:
- status = MATE_MIXER_PORT_AVAILABLE;
- break;
- case PA_PORT_AVAILABLE_NO:
- status = MATE_MIXER_PORT_UNAVAILABLE;
- break;
- default:
- break;
- }
-#endif
- port = mate_mixer_port_new (p_info->name,
- p_info->description,
- NULL,
- p_info->priority,
- status);
-
- ports = g_list_prepend (ports, port);
- }
+ 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 */
source = g_object_new (PULSE_TYPE_SOURCE,
"connection", connection,
"index", info->index,
NULL);
- /* According to the PulseAudio code, the list of sink port never changes with
- * updates.
- * This may be not future-proof, but checking and validating the list of ports on
- * each update would be an expensive operation, so let's set the list only during
- * the construction */
- pulse_stream_update_ports (PULSE_STREAM (source), g_list_reverse (ports));
-
/* Other data may change at any time, so let's make a use of our update function */
pulse_source_update (PULSE_STREAM (source), info);
@@ -117,42 +82,59 @@ pulse_source_new (PulseConnection *connection, const pa_source_info *info)
gboolean
pulse_source_update (PulseStream *stream, const pa_source_info *info)
{
- PulseSource *source;
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_INPUT |
- MATE_MIXER_STREAM_HAS_MUTE |
- MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_CAN_SET_VOLUME;
+ MateMixerStreamFlags flags = MATE_MIXER_STREAM_INPUT |
+ MATE_MIXER_STREAM_HAS_MUTE |
+ MATE_MIXER_STREAM_HAS_VOLUME |
+ MATE_MIXER_STREAM_CAN_SET_VOLUME |
+ MATE_MIXER_STREAM_CAN_SUSPEND;
+ GList *ports = NULL;
+ guint32 i;
g_return_val_if_fail (PULSE_IS_SOURCE (stream), FALSE);
- source = PULSE_SOURCE (stream);
-
/* Let all the information update before emitting notify signals */
g_object_freeze_notify (G_OBJECT (stream));
pulse_stream_update_name (stream, info->name);
pulse_stream_update_description (stream, info->description);
pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
- pulse_stream_update_channel_map (stream, &info->channel_map);
- pulse_stream_update_volume_extended (stream,
- &info->volume,
- info->base_volume,
- info->n_volume_steps);
+
+ /* List of ports */
+ for (i = 0; i < info->n_ports; i++) {
+ MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
+
+#if PA_CHECK_VERSION(2, 0, 0)
+ if (info->ports[i]->available == PA_PORT_AVAILABLE_YES)
+ flags |= MATE_MIXER_PORT_AVAILABLE;
+#endif
+ ports = g_list_prepend (ports,
+ mate_mixer_port_new (info->ports[i]->name,
+ info->ports[i]->description,
+ NULL,
+ info->ports[i]->priority,
+ flags));
+ }
+ pulse_stream_update_ports (stream, ports);
+
+ /* Active port */
if (info->active_port)
pulse_stream_update_active_port (stream, info->active_port->name);
+ else
+ pulse_stream_update_active_port (stream, NULL);
+ /* Stream state */
switch (info->state) {
case PA_SOURCE_RUNNING:
- pulse_stream_update_status (stream, MATE_MIXER_STREAM_RUNNING);
+ pulse_stream_update_state (stream, MATE_MIXER_STREAM_RUNNING);
break;
case PA_SOURCE_IDLE:
- pulse_stream_update_status (stream, MATE_MIXER_STREAM_IDLE);
+ pulse_stream_update_state (stream, MATE_MIXER_STREAM_IDLE);
break;
case PA_SOURCE_SUSPENDED:
- pulse_stream_update_status (stream, MATE_MIXER_STREAM_SUSPENDED);
+ pulse_stream_update_state (stream, MATE_MIXER_STREAM_SUSPENDED);
break;
default:
- pulse_stream_update_status (stream, MATE_MIXER_STREAM_UNKNOWN_STATUS);
+ pulse_stream_update_state (stream, MATE_MIXER_STREAM_UNKNOWN_STATE);
break;
}
@@ -167,14 +149,14 @@ pulse_source_update (PulseStream *stream, const pa_source_info *info)
if (pa_channel_map_can_fade (&info->channel_map))
flags |= MATE_MIXER_STREAM_CAN_FADE;
+ /* Flags must be updated before volume */
pulse_stream_update_flags (stream, flags);
- if (source->priv->index_monitored_sink != info->monitor_of_sink) {
- source->priv->index_monitored_sink = info->monitor_of_sink;
-
- // TODO: provide a property
- // g_object_notify (G_OBJECT (stream), "monitor");
- }
+ pulse_stream_update_volume_extended (stream,
+ &info->volume,
+ &info->channel_map,
+ info->base_volume,
+ info->n_volume_steps);
g_object_thaw_notify (G_OBJECT (stream));
return TRUE;
@@ -183,31 +165,57 @@ pulse_source_update (PulseStream *stream, const pa_source_info *info)
static gboolean
source_set_mute (MateMixerStream *stream, gboolean mute)
{
+ PulseStream *pulse;
+
g_return_val_if_fail (PULSE_IS_SOURCE (stream), FALSE);
- return pulse_connection_set_source_mute (pulse_stream_get_connection (PULSE_STREAM (stream)),
- pulse_stream_get_index (PULSE_STREAM (stream)),
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_set_source_mute (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
mute);
}
static gboolean
source_set_volume (MateMixerStream *stream, pa_cvolume *volume)
{
+ PulseStream *pulse;
+
g_return_val_if_fail (PULSE_IS_SOURCE (stream), FALSE);
g_return_val_if_fail (volume != NULL, FALSE);
- return pulse_connection_set_source_volume (pulse_stream_get_connection (PULSE_STREAM (stream)),
- pulse_stream_get_index (PULSE_STREAM (stream)),
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_set_source_volume (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
volume);
}
static gboolean
source_set_active_port (MateMixerStream *stream, const gchar *port_name)
{
+ PulseStream *pulse;
+
g_return_val_if_fail (PULSE_IS_SOURCE (stream), FALSE);
g_return_val_if_fail (port_name != NULL, FALSE);
- return pulse_connection_set_source_port (pulse_stream_get_connection (PULSE_STREAM (stream)),
- pulse_stream_get_index (PULSE_STREAM (stream)),
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_set_source_port (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
port_name);
}
+
+static PulseMonitor *
+source_create_monitor (MateMixerStream *stream)
+{
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_SOURCE (stream), NULL);
+
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_create_monitor (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
+ PA_INVALID_INDEX);
+}
diff --git a/backends/pulse/pulse-source.h b/backends/pulse/pulse-source.h
index a8fd13c..499fb2c 100644
--- a/backends/pulse/pulse-source.h
+++ b/backends/pulse/pulse-source.h
@@ -21,10 +21,9 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-stream.h>
-
#include <pulse/pulseaudio.h>
+#include "pulse-connection.h"
#include "pulse-stream.h"
G_BEGIN_DECLS
@@ -38,24 +37,21 @@ G_BEGIN_DECLS
#define PULSE_SOURCE_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_SOURCE, PulseSourceClass))
#define PULSE_IS_SOURCE_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SOURCE))
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_SOURCE))
#define PULSE_SOURCE_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_SOURCE, PulseSourceClass))
typedef struct _PulseSource PulseSource;
typedef struct _PulseSourceClass PulseSourceClass;
-typedef struct _PulseSourcePrivate PulseSourcePrivate;
struct _PulseSource
{
PulseStream parent;
-
- PulseSourcePrivate *priv;
};
struct _PulseSourceClass
{
- PulseStreamClass parent;
+ PulseStreamClass parent_class;
};
GType pulse_source_get_type (void) G_GNUC_CONST;
diff --git a/backends/pulse/pulse-stream.c b/backends/pulse/pulse-stream.c
index 529f2c9..bb50c50 100644
--- a/backends/pulse/pulse-stream.c
+++ b/backends/pulse/pulse-stream.c
@@ -28,6 +28,7 @@
#include "pulse-connection.h"
#include "pulse-helpers.h"
+#include "pulse-monitor.h"
#include "pulse-stream.h"
struct _PulseStreamPrivate
@@ -36,10 +37,9 @@ struct _PulseStreamPrivate
guint32 index_device;
gchar *name;
gchar *description;
- gchar *icon;
MateMixerDevice *device;
MateMixerStreamFlags flags;
- MateMixerStreamStatus status;
+ MateMixerStreamState state;
gboolean mute;
pa_cvolume volume;
pa_volume_t volume_base;
@@ -50,23 +50,22 @@ struct _PulseStreamPrivate
GList *ports;
MateMixerPort *port;
PulseConnection *connection;
+ PulseMonitor *monitor;
};
-enum
-{
+enum {
PROP_0,
PROP_NAME,
PROP_DESCRIPTION,
- PROP_ICON,
PROP_DEVICE,
PROP_FLAGS,
- PROP_STATUS,
+ PROP_STATE,
PROP_MUTE,
PROP_NUM_CHANNELS,
PROP_VOLUME,
- PROP_VOLUME_DB,
PROP_BALANCE,
PROP_FADE,
+ PROP_PORTS,
PROP_ACTIVE_PORT,
PROP_INDEX,
PROP_CONNECTION,
@@ -79,13 +78,16 @@ 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))
+
/* Interface implementation */
static const gchar * stream_get_name (MateMixerStream *stream);
static const gchar * stream_get_description (MateMixerStream *stream);
-static const gchar * stream_get_icon (MateMixerStream *stream);
static MateMixerDevice * stream_get_device (MateMixerStream *stream);
static MateMixerStreamFlags stream_get_flags (MateMixerStream *stream);
-static MateMixerStreamStatus stream_get_status (MateMixerStream *stream);
+static MateMixerStreamState stream_get_state (MateMixerStream *stream);
static gboolean stream_get_mute (MateMixerStream *stream);
static gboolean stream_set_mute (MateMixerStream *stream,
gboolean mute);
@@ -128,27 +130,34 @@ static gboolean stream_set_fade (MateMixerStream
gdouble fade);
static gboolean stream_suspend (MateMixerStream *stream);
static gboolean stream_resume (MateMixerStream *stream);
+
+static gboolean stream_monitor_start (MateMixerStream *stream);
+static void stream_monitor_stop (MateMixerStream *stream);
+static gboolean stream_monitor_is_running (MateMixerStream *stream);
+static void stream_monitor_value (PulseMonitor *monitor,
+ gdouble value,
+ MateMixerStream *stream);
+
static const GList * stream_list_ports (MateMixerStream *stream);
static MateMixerPort * stream_get_active_port (MateMixerStream *stream);
static gboolean stream_set_active_port (MateMixerStream *stream,
const gchar *port);
+
static gint64 stream_get_min_volume (MateMixerStream *stream);
static gint64 stream_get_max_volume (MateMixerStream *stream);
static gint64 stream_get_normal_volume (MateMixerStream *stream);
-G_DEFINE_ABSTRACT_TYPE_WITH_CODE (PulseStream, pulse_stream, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (MATE_MIXER_TYPE_STREAM,
- mate_mixer_stream_interface_init))
+static gboolean stream_set_cvolume (MateMixerStream *stream,
+ pa_cvolume *volume);
static void
mate_mixer_stream_interface_init (MateMixerStreamInterface *iface)
{
iface->get_name = stream_get_name;
iface->get_description = stream_get_description;
- iface->get_icon = stream_get_icon;
iface->get_device = stream_get_device;
iface->get_flags = stream_get_flags;
- iface->get_status = stream_get_status;
+ iface->get_state = stream_get_state;
iface->get_mute = stream_get_mute;
iface->set_mute = stream_set_mute;
iface->get_num_channels = stream_get_num_channels;
@@ -172,6 +181,9 @@ mate_mixer_stream_interface_init (MateMixerStreamInterface *iface)
iface->set_fade = stream_set_fade;
iface->suspend = stream_suspend;
iface->resume = stream_resume;
+ iface->monitor_start = stream_monitor_start;
+ iface->monitor_stop = stream_monitor_stop;
+ iface->monitor_is_running = stream_monitor_is_running;
iface->list_ports = stream_list_ports;
iface->get_active_port = stream_get_active_port;
iface->set_active_port = stream_set_active_port;
@@ -197,17 +209,14 @@ pulse_stream_get_property (GObject *object,
case PROP_DESCRIPTION:
g_value_set_string (value, stream->priv->description);
break;
- case PROP_ICON:
- g_value_set_string (value, stream->priv->icon);
- break;
case PROP_DEVICE:
g_value_set_object (value, stream->priv->device);
break;
case PROP_FLAGS:
g_value_set_flags (value, stream->priv->flags);
break;
- case PROP_STATUS:
- g_value_set_enum (value, stream->priv->status);
+ case PROP_STATE:
+ g_value_set_enum (value, stream->priv->state);
break;
case PROP_MUTE:
g_value_set_boolean (value, stream->priv->mute);
@@ -218,14 +227,14 @@ pulse_stream_get_property (GObject *object,
case PROP_VOLUME:
g_value_set_int64 (value, stream_get_volume (MATE_MIXER_STREAM (stream)));
break;
- case PROP_VOLUME_DB:
- g_value_set_double (value, stream_get_volume_db (MATE_MIXER_STREAM (stream)));
- break;
case PROP_BALANCE:
- g_value_set_double (value, stream->priv->balance);
+ g_value_set_double (value, stream_get_balance (MATE_MIXER_STREAM (stream)));
break;
case PROP_FADE:
- g_value_set_double (value, stream->priv->fade);
+ g_value_set_double (value, stream_get_fade (MATE_MIXER_STREAM (stream)));
+ break;
+ case PROP_PORTS:
+ g_value_set_pointer (value, stream->priv->ports);
break;
case PROP_ACTIVE_PORT:
g_value_set_object (value, stream->priv->port);
@@ -253,37 +262,13 @@ pulse_stream_set_property (GObject *object,
stream = PULSE_STREAM (object);
switch (param_id) {
- case PROP_NAME:
- stream->priv->name = g_strdup (g_value_dup_string (value));
- break;
- case PROP_DESCRIPTION:
- stream->priv->description = g_strdup (g_value_get_string (value));
- break;
- case PROP_ICON:
- stream->priv->icon = g_strdup (g_value_get_string (value));
- break;
- case PROP_DEVICE:
- // XXX may be NULL and the device may become known after the stream,
- // figure this out..
- // stream->priv->device = g_object_ref (g_value_get_object (value));
- break;
- case PROP_FLAGS:
- stream->priv->flags = g_value_get_flags (value);
- break;
- case PROP_STATUS:
- stream->priv->status = g_value_get_enum (value);
- break;
- case PROP_MUTE:
- stream->priv->mute = g_value_get_boolean (value);
- break;
case PROP_INDEX:
stream->priv->index = g_value_get_uint (value);
break;
case PROP_CONNECTION:
+ /* Construct-only object property */
stream->priv->connection = g_value_dup_object (value);
break;
- case PROP_ACTIVE_PORT:
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -312,6 +297,7 @@ pulse_stream_class_init (PulseStreamClass *klass)
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",
@@ -324,16 +310,15 @@ pulse_stream_class_init (PulseStreamClass *klass)
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_DEVICE, "device");
g_object_class_override_property (object_class, PROP_FLAGS, "flags");
- g_object_class_override_property (object_class, PROP_STATUS, "status");
+ g_object_class_override_property (object_class, PROP_STATE, "state");
g_object_class_override_property (object_class, PROP_MUTE, "mute");
g_object_class_override_property (object_class, PROP_NUM_CHANNELS, "num-channels");
g_object_class_override_property (object_class, PROP_VOLUME, "volume");
- g_object_class_override_property (object_class, PROP_VOLUME_DB, "volume-db");
g_object_class_override_property (object_class, PROP_BALANCE, "balance");
g_object_class_override_property (object_class, PROP_FADE, "fade");
+ g_object_class_override_property (object_class, PROP_PORTS, "ports");
g_object_class_override_property (object_class, PROP_ACTIVE_PORT, "active-port");
g_type_class_add_private (object_class, sizeof (PulseStreamPrivate));
@@ -375,7 +360,6 @@ pulse_stream_finalize (GObject *object)
g_free (stream->priv->name);
g_free (stream->priv->description);
- g_free (stream->priv->icon);
G_OBJECT_CLASS (pulse_stream_parent_class)->finalize (object);
}
@@ -396,6 +380,14 @@ pulse_stream_get_connection (PulseStream *stream)
return stream->priv->connection;
}
+PulseMonitor *
+pulse_stream_get_monitor (PulseStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
+
+ return stream->priv->monitor;
+}
+
gboolean
pulse_stream_update_name (PulseStream *stream, const gchar *name)
{
@@ -439,13 +431,13 @@ pulse_stream_update_flags (PulseStream *stream, MateMixerStreamFlags flags)
}
gboolean
-pulse_stream_update_status (PulseStream *stream, MateMixerStreamStatus status)
+pulse_stream_update_state (PulseStream *stream, MateMixerStreamState state)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- if (stream->priv->status != status) {
- stream->priv->status = status;
- g_object_notify (G_OBJECT (stream), "status");
+ if (stream->priv->state != state) {
+ stream->priv->state = state;
+ g_object_notify (G_OBJECT (stream), "state");
}
return TRUE;
}
@@ -463,39 +455,39 @@ pulse_stream_update_mute (PulseStream *stream, gboolean mute)
}
gboolean
-pulse_stream_update_volume (PulseStream *stream, const pa_cvolume *volume)
+pulse_stream_update_volume (PulseStream *stream,
+ const pa_cvolume *volume,
+ const pa_channel_map *map)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- if (!pa_cvolume_equal (&stream->priv->volume, volume)) {
- stream->priv->volume = *volume;
+ /* The channel_map argument is always present, but volume is not always
+ * supported and might be NULL */
+ if (!pa_channel_map_equal (&stream->priv->channel_map, map))
+ stream->priv->channel_map = *map;
+
+ if (volume != NULL) {
+ if (!pa_cvolume_equal (&stream->priv->volume, volume)) {
+ stream->priv->volume = *volume;
- g_object_notify (G_OBJECT (stream), "volume");
+ g_object_notify (G_OBJECT (stream), "volume");
- // XXX probably should notify about volume-db too but the flags may
- // be known later
+ // XXX notify fade, balance if changed
+ }
}
return TRUE;
}
gboolean
-pulse_stream_update_volume_extended (PulseStream *stream,
- const pa_cvolume *volume,
- pa_volume_t volume_base,
- guint32 volume_steps)
+pulse_stream_update_volume_extended (PulseStream *stream,
+ const pa_cvolume *volume,
+ const pa_channel_map *map,
+ pa_volume_t volume_base,
+ guint32 volume_steps)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- // XXX use volume_base and volume_steps
-
- if (!pa_cvolume_equal (&stream->priv->volume, volume)) {
- stream->priv->volume = *volume;
-
- g_object_notify (G_OBJECT (stream), "volume");
-
- // XXX probably should notify about volume-db too but the flags may
- // be known later
- }
+ pulse_stream_update_volume (stream, volume, map);
stream->priv->volume_base = volume_base;
stream->priv->volume_steps = volume_steps;
@@ -503,23 +495,13 @@ pulse_stream_update_volume_extended (PulseStream *stream,
}
gboolean
-pulse_stream_update_channel_map (PulseStream *stream, const pa_channel_map *map)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- if (!pa_channel_map_equal (&stream->priv->channel_map, map))
- stream->priv->channel_map = *map;
-
- return TRUE;
-}
-
-gboolean
pulse_stream_update_ports (PulseStream *stream, GList *ports)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- /* Right now we do not change the list of ports during update */
- g_warn_if_fail (stream->priv->ports == NULL);
+ // XXX sort them
+ if (stream->priv->ports)
+ g_list_free_full (stream->priv->ports, g_object_unref);
stream->priv->ports = ports;
return TRUE;
@@ -555,10 +537,12 @@ pulse_stream_update_active_port (PulseStream *stream, const gchar *port_name)
return TRUE;
}
+// XXX check these functions according to flags
+
static const gchar *
stream_get_name (MateMixerStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
return PULSE_STREAM (stream)->priv->name;
}
@@ -566,23 +550,15 @@ stream_get_name (MateMixerStream *stream)
static const gchar *
stream_get_description (MateMixerStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
return PULSE_STREAM (stream)->priv->description;
}
-static const gchar *
-stream_get_icon (MateMixerStream *stream)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- return PULSE_STREAM (stream)->priv->icon;
-}
-
static MateMixerDevice *
stream_get_device (MateMixerStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
return PULSE_STREAM (stream)->priv->device;
}
@@ -590,17 +566,17 @@ stream_get_device (MateMixerStream *stream)
static MateMixerStreamFlags
stream_get_flags (MateMixerStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_STREAM_NO_FLAGS);
return PULSE_STREAM (stream)->priv->flags;
}
-static MateMixerStreamStatus
-stream_get_status (MateMixerStream *stream)
+static MateMixerStreamState
+stream_get_state (MateMixerStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_STREAM_UNKNOWN_STATE);
- return PULSE_STREAM (stream)->priv->status;
+ return PULSE_STREAM (stream)->priv->state;
}
static gboolean
@@ -614,16 +590,19 @@ stream_get_mute (MateMixerStream *stream)
static gboolean
stream_set_mute (MateMixerStream *stream, gboolean mute)
{
- PulseStream *ps;
+ PulseStream *pulse;
+ gboolean ret = TRUE;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- ps = PULSE_STREAM (stream);
-
- if (ps->priv->mute == mute)
- return TRUE;
+ pulse = PULSE_STREAM (stream);
- return PULSE_STREAM_GET_CLASS (stream)->set_mute (stream, mute);
+ if (pulse->priv->mute != mute) {
+ ret = PULSE_STREAM_GET_CLASS (stream)->set_mute (stream, mute);
+ if (ret)
+ pulse->priv->mute = mute;
+ }
+ return ret;
}
static guint
@@ -645,34 +624,32 @@ stream_get_volume (MateMixerStream *stream)
static gboolean
stream_set_volume (MateMixerStream *stream, gint64 volume)
{
- pa_cvolume cvolume;
- PulseStream *ps;
+ PulseStream *pulse;
+ pa_cvolume cvolume;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- ps = PULSE_STREAM (stream);
- cvolume = ps->priv->volume;
+ if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_CAN_SET_VOLUME))
+ return FALSE;
+
+ pulse = PULSE_STREAM (stream);
+ cvolume = pulse->priv->volume;
if (pa_cvolume_scale (&cvolume, (pa_volume_t) volume) == NULL) {
- g_warning ("Invalid PulseAudio volume value %" G_GINT64_FORMAT, volume);
+ g_warning ("Invalid volume passed to stream %s",
+ mate_mixer_stream_get_name (stream));
return FALSE;
}
-
- /* This is the only function which passes a volume request to the real class, so
- * all the pa_cvolume validations are only done here */
-
-
-
- return PULSE_STREAM_GET_CLASS (stream)->set_volume (stream, &cvolume);
+ return stream_set_cvolume (stream, &cvolume);
}
static gdouble
stream_get_volume_db (MateMixerStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
- return FALSE;
+ return 0;
return pa_sw_volume_to_dB (stream_get_volume (stream));
}
@@ -691,74 +668,72 @@ stream_set_volume_db (MateMixerStream *stream, gdouble volume_db)
static MateMixerChannelPosition
stream_get_channel_position (MateMixerStream *stream, guint channel)
{
- PulseStream *ps;
+ PulseStream *pulse;
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_CHANNEL_UNKNOWN_POSITION);
- ps = PULSE_STREAM (stream);
+ pulse = PULSE_STREAM (stream);
- if (channel >= ps->priv->channel_map.channels) {
- g_warning ("Invalid channel %u of stream %s", channel, ps->priv->name);
+ if (channel >= pulse->priv->channel_map.channels) {
+ g_warning ("Invalid channel %u of stream %s", channel, pulse->priv->name);
return MATE_MIXER_CHANNEL_UNKNOWN_POSITION;
}
- return pulse_convert_position_to_pulse (ps->priv->channel_map.map[channel]);
+ return pulse_convert_position_to_pulse (pulse->priv->channel_map.map[channel]);
}
static gint64
stream_get_channel_volume (MateMixerStream *stream, guint channel)
{
- PulseStream *ps;
+ PulseStream *pulse;
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
- ps = PULSE_STREAM (stream);
+ pulse = PULSE_STREAM (stream);
- if (channel >= ps->priv->volume.channels) {
- g_warning ("Invalid channel %u of stream %s", channel, ps->priv->name);
+ if (channel >= pulse->priv->volume.channels) {
+ g_warning ("Invalid channel %u of stream %s", channel, pulse->priv->name);
return stream_get_min_volume (stream);
}
- return (gint64) ps->priv->volume.values[channel];
+ return (gint64) pulse->priv->volume.values[channel];
}
static gboolean
stream_set_channel_volume (MateMixerStream *stream, guint channel, gint64 volume)
{
- pa_cvolume cvolume;
- PulseStream *pstream;
+ PulseStream *pulse;
+ pa_cvolume cvolume;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- pstream = PULSE_STREAM (stream);
- cvolume = pstream->priv->volume;
+ pulse = PULSE_STREAM (stream);
+ cvolume = pulse->priv->volume;
- if (channel >= pstream->priv->volume.channels) {
- g_warning ("Invalid channel %u of stream %s", channel, pstream->priv->name);
+ if (channel >= pulse->priv->volume.channels) {
+ g_warning ("Invalid channel %u of stream %s", channel, pulse->priv->name);
return FALSE;
}
-
cvolume.values[channel] = (pa_volume_t) volume;
- if (!pa_cvolume_valid (&cvolume)) {
- g_warning ("Invalid PulseAudio volume value %" G_GINT64_FORMAT, volume);
- return FALSE;
- }
- return PULSE_STREAM_GET_CLASS (stream)->set_volume (stream, &cvolume);
+ return stream_set_cvolume (stream, &cvolume);
}
static gdouble
stream_get_channel_volume_db (MateMixerStream *stream, guint channel)
{
- PulseStream *pstream;
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0);
+ if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
+ return 0;
- pstream = PULSE_STREAM (stream);
+ pulse = PULSE_STREAM (stream);
- if (channel >= pstream->priv->volume.channels) {
- g_warning ("Invalid channel %u of stream %s", channel, pstream->priv->name);
- return 0.0;
+ if (channel >= pulse->priv->volume.channels) {
+ g_warning ("Invalid channel %u of stream %s", channel, pulse->priv->name);
+ return 0;
}
- return pa_sw_volume_to_dB (pstream->priv->volume.values[channel]);
+ return pa_sw_volume_to_dB (pulse->priv->volume.values[channel]);
}
static gboolean
@@ -768,6 +743,9 @@ stream_set_channel_volume_db (MateMixerStream *stream,
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
+ return FALSE;
+
return stream_set_channel_volume (stream,
channel,
pa_sw_volume_from_dB (volume_db));
@@ -776,13 +754,13 @@ stream_set_channel_volume_db (MateMixerStream *stream,
static gboolean
stream_has_position (MateMixerStream *stream, MateMixerChannelPosition position)
{
- PulseStreamPrivate *priv;
+ PulseStream *pulse;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- priv = PULSE_STREAM (stream)->priv;
+ pulse = PULSE_STREAM (stream);
- return pa_channel_map_has_position (&priv->channel_map,
+ return pa_channel_map_has_position (&pulse->priv->channel_map,
pulse_convert_position_to_pulse (position));
}
@@ -790,14 +768,14 @@ static gint64
stream_get_position_volume (MateMixerStream *stream,
MateMixerChannelPosition position)
{
- PulseStreamPrivate *priv;
+ PulseStream *pulse;
g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
- priv = PULSE_STREAM (stream)->priv;
+ pulse = PULSE_STREAM (stream);
- return pa_cvolume_get_position (&priv->volume,
- &priv->channel_map,
+ return pa_cvolume_get_position (&pulse->priv->volume,
+ &pulse->priv->channel_map,
pulse_convert_position_to_pulse (position));
}
@@ -806,28 +784,32 @@ stream_set_position_volume (MateMixerStream *stream,
MateMixerChannelPosition position,
gint64 volume)
{
- PulseStreamPrivate *priv;
- pa_cvolume cvolume;
+ PulseStream *pulse;
+ pa_cvolume cvolume;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- priv = PULSE_STREAM (stream)->priv;
- cvolume = priv->volume;
+ pulse = PULSE_STREAM (stream);
+ cvolume = pulse->priv->volume;
if (!pa_cvolume_set_position (&cvolume,
- &priv->channel_map,
+ &pulse->priv->channel_map,
pulse_convert_position_to_pulse (position),
(pa_volume_t) volume)) {
+ // XXX
return FALSE;
}
- return PULSE_STREAM_GET_CLASS (stream)->set_volume (stream, &cvolume);
+ return stream_set_cvolume (stream, &cvolume);
}
static gdouble
stream_get_position_volume_db (MateMixerStream *stream,
MateMixerChannelPosition position)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
+
+ if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
+ return 0;
return pa_sw_volume_to_dB (stream_get_position_volume (stream, position));
}
@@ -839,87 +821,163 @@ stream_set_position_volume_db (MateMixerStream *stream,
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
+ return FALSE;
+
return stream_set_position_volume (stream, position, pa_sw_volume_from_dB (volume_db));
}
static gdouble
stream_get_balance (MateMixerStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0);
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
- return PULSE_STREAM (stream)->priv->balance;
+ pulse = PULSE_STREAM (stream);
+
+ return pa_cvolume_get_balance (&pulse->priv->volume,
+ &pulse->priv->channel_map);
}
static gboolean
stream_set_balance (MateMixerStream *stream, gdouble balance)
{
- PulseStream *pstream;
- pa_cvolume cvolume;
+ PulseStream *pulse;
+ pa_cvolume cvolume;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- pstream = PULSE_STREAM (stream);
- cvolume = pstream->priv->volume;
-
- if (balance == pstream->priv->balance)
- return TRUE;
+ pulse = PULSE_STREAM (stream);
+ cvolume = pulse->priv->volume;
if (pa_cvolume_set_balance (&cvolume,
- &pstream->priv->channel_map,
+ &pulse->priv->channel_map,
(float) balance) == NULL) {
+ // XXX
return FALSE;
}
- return PULSE_STREAM_GET_CLASS (stream)->set_volume (stream, &cvolume);
+ return stream_set_cvolume (stream, &cvolume);
}
static gdouble
stream_get_fade (MateMixerStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
+
+ pulse = PULSE_STREAM (stream);
- return PULSE_STREAM (stream)->priv->fade;
+ return pa_cvolume_get_fade (&pulse->priv->volume,
+ &pulse->priv->channel_map);
}
static gboolean
stream_set_fade (MateMixerStream *stream, gdouble fade)
{
+ PulseStream *pulse;
pa_cvolume cvolume;
- PulseStream *pstream;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- pstream = PULSE_STREAM (stream);
- cvolume = pstream->priv->volume;
-
- if (fade == pstream->priv->fade)
- return TRUE;
+ pulse = PULSE_STREAM (stream);
+ cvolume = pulse->priv->volume;
if (pa_cvolume_set_fade (&cvolume,
- &pstream->priv->channel_map,
+ &pulse->priv->channel_map,
(float) fade) == NULL) {
+ // XXX
return FALSE;
}
- return PULSE_STREAM_GET_CLASS (stream)->set_volume (stream, &cvolume);
+ return stream_set_cvolume (stream, &cvolume);
}
static gboolean
stream_suspend (MateMixerStream *stream)
{
- // TODO
- return TRUE;
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ if (!(PULSE_STREAM (stream)->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND))
+ return FALSE;
+
+ return PULSE_STREAM_GET_CLASS (stream)->suspend (stream);
}
static gboolean
stream_resume (MateMixerStream *stream)
{
- // TODO
- return TRUE;
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ if (!(PULSE_STREAM (stream)->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND))
+ return FALSE;
+
+ return PULSE_STREAM_GET_CLASS (stream)->resume (stream);
+}
+
+static gboolean
+stream_monitor_start (MateMixerStream *stream)
+{
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ pulse = PULSE_STREAM (stream);
+
+ if (!pulse->priv->monitor) {
+ pulse->priv->monitor = PULSE_STREAM_GET_CLASS (stream)->create_monitor (stream);
+
+ if (G_UNLIKELY (pulse->priv->monitor == NULL))
+ return FALSE;
+
+ g_signal_connect (G_OBJECT (pulse->priv->monitor),
+ "value",
+ G_CALLBACK (stream_monitor_value),
+ stream);
+ }
+ return pulse_monitor_enable (pulse->priv->monitor);
+}
+
+static void
+stream_monitor_stop (MateMixerStream *stream)
+{
+ PulseStream *pulse;
+
+ g_return_if_fail (PULSE_IS_STREAM (stream));
+
+ pulse = PULSE_STREAM (stream);
+
+ if (pulse->priv->monitor)
+ pulse_monitor_disable (pulse->priv->monitor);
+}
+
+static gboolean
+stream_monitor_is_running (MateMixerStream *stream)
+{
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+
+ pulse = PULSE_STREAM (stream);
+
+ if (pulse->priv->monitor)
+ return pulse_monitor_is_enabled (pulse->priv->monitor);
+
+ return FALSE;
+}
+
+static void
+stream_monitor_value (PulseMonitor *monitor, gdouble value, MateMixerStream *stream)
+{
+ g_signal_emit_by_name (G_OBJECT (stream),
+ "monitor-value",
+ value);
}
static const GList *
stream_list_ports (MateMixerStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
return (const GList *) PULSE_STREAM (stream)->priv->ports;
}
@@ -927,18 +985,18 @@ stream_list_ports (MateMixerStream *stream)
static MateMixerPort *
stream_get_active_port (MateMixerStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
return PULSE_STREAM (stream)->priv->port;
}
static gboolean
-stream_set_active_port (MateMixerStream *stream, const gchar *port_name)
+stream_set_active_port (MateMixerStream *stream, const gchar *port)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- g_return_val_if_fail (port_name != NULL, FALSE);
+ g_return_val_if_fail (port != NULL, FALSE);
- return PULSE_STREAM_GET_CLASS (stream)->set_active_port (stream, port_name);
+ return PULSE_STREAM_GET_CLASS (stream)->set_active_port (stream, port);
}
static gint64
@@ -958,3 +1016,22 @@ stream_get_normal_volume (MateMixerStream *stream)
{
return (gint64) PA_VOLUME_NORM;
}
+
+static gboolean
+stream_set_cvolume (MateMixerStream *stream, pa_cvolume *volume)
+{
+ PulseStream *pulse;
+ gboolean ret = TRUE;
+
+ if (!pa_cvolume_valid (volume))
+ return FALSE;
+
+ pulse = PULSE_STREAM (stream);
+
+ if (!pa_cvolume_equal (volume, &pulse->priv->volume)) {
+ ret = PULSE_STREAM_GET_CLASS (stream)->set_volume (stream, volume);
+ if (ret)
+ pulse->priv->volume = *volume;
+ }
+ return ret;
+}
diff --git a/backends/pulse/pulse-stream.h b/backends/pulse/pulse-stream.h
index 49eac42..fa0b25b 100644
--- a/backends/pulse/pulse-stream.h
+++ b/backends/pulse/pulse-stream.h
@@ -26,6 +26,7 @@
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
+#include "pulse-monitor.h"
G_BEGIN_DECLS
@@ -38,7 +39,7 @@ G_BEGIN_DECLS
#define PULSE_STREAM_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_STREAM, PulseStreamClass))
#define PULSE_IS_STREAM_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), PULSE_TYPE_STREAM))
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_STREAM))
#define PULSE_STREAM_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_STREAM, PulseStreamClass))
@@ -48,51 +49,63 @@ typedef struct _PulseStreamPrivate PulseStreamPrivate;
struct _PulseStream
{
+ GObject parent;
+
/*< private >*/
- GObject parent;
- PulseStreamPrivate *priv;
+ PulseStreamPrivate *priv;
};
struct _PulseStreamClass
{
- /*< private >*/
- GObjectClass parent;
-
- gboolean (*set_mute) (MateMixerStream *stream,
- gboolean mute);
- gboolean (*set_volume) (MateMixerStream *stream,
- pa_cvolume *volume);
- gboolean (*set_active_port) (MateMixerStream *stream,
- const gchar *port_name);
+ GObjectClass parent_class;
+
+ gboolean (*set_mute) (MateMixerStream *stream,
+ gboolean mute);
+ gboolean (*set_volume) (MateMixerStream *stream,
+ pa_cvolume *volume);
+
+ gboolean (*set_active_port) (MateMixerStream *stream,
+ const gchar *port_name);
+
+ gboolean (*suspend) (MateMixerStream *stream);
+ gboolean (*resume) (MateMixerStream *stream);
+
+ PulseMonitor *(*create_monitor) (MateMixerStream *stream);
};
-GType pulse_stream_get_type (void) G_GNUC_CONST;
-
-guint32 pulse_stream_get_index (PulseStream *stream);
-PulseConnection *pulse_stream_get_connection (PulseStream *stream);
-
-gboolean pulse_stream_update_name (PulseStream *stream,
- const gchar *name);
-gboolean pulse_stream_update_description (PulseStream *stream,
- const gchar *description);
-gboolean pulse_stream_update_flags (PulseStream *stream,
- MateMixerStreamFlags flags);
-gboolean pulse_stream_update_status (PulseStream *stream,
- MateMixerStreamStatus status);
-gboolean pulse_stream_update_mute (PulseStream *stream,
- gboolean mute);
-gboolean pulse_stream_update_volume (PulseStream *stream,
- const pa_cvolume *volume);
-gboolean pulse_stream_update_volume_extended (PulseStream *stream,
- const pa_cvolume *volume,
- pa_volume_t volume_base,
- guint32 volume_steps);
-gboolean pulse_stream_update_channel_map (PulseStream *stream,
- const pa_channel_map *map);
-gboolean pulse_stream_update_ports (PulseStream *stream,
- GList *ports);
-gboolean pulse_stream_update_active_port (PulseStream *stream,
- const gchar *port_name);
+GType pulse_stream_get_type (void) G_GNUC_CONST;
+
+guint32 pulse_stream_get_index (PulseStream *stream);
+PulseConnection *pulse_stream_get_connection (PulseStream *stream);
+PulseMonitor * pulse_stream_get_monitor (PulseStream *stream);
+
+gboolean pulse_stream_update_name (PulseStream *stream,
+ const gchar *name);
+gboolean pulse_stream_update_description (PulseStream *stream,
+ const gchar *description);
+gboolean pulse_stream_update_flags (PulseStream *stream,
+ MateMixerStreamFlags flags);
+gboolean pulse_stream_update_state (PulseStream *stream,
+ MateMixerStreamState state);
+gboolean pulse_stream_update_mute (PulseStream *stream,
+ gboolean mute);
+
+gboolean pulse_stream_update_volume (PulseStream *stream,
+ const pa_cvolume *volume,
+ const pa_channel_map *map);
+gboolean pulse_stream_update_volume_extended (PulseStream *stream,
+ const pa_cvolume *volume,
+ const pa_channel_map *map,
+ pa_volume_t volume_base,
+ guint32 volume_steps);
+
+gboolean pulse_stream_update_channel_map (PulseStream *stream,
+ const pa_channel_map *map);
+
+gboolean pulse_stream_update_ports (PulseStream *stream,
+ GList *ports);
+gboolean pulse_stream_update_active_port (PulseStream *stream,
+ const gchar *port_name);
G_END_DECLS
diff --git a/configure.ac b/configure.ac
index 4925691..3ec28d2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -41,7 +41,7 @@ AC_PROG_INSTALL
# Checks for header files.
AC_HEADER_STDC
-AC_CHECK_HEADERS([string.h sys/types.h unistd.h])
+AC_CHECK_HEADERS([string.h sys/types.h unistd.h locale.h])
# =======================================================================
# Libtool
@@ -154,7 +154,6 @@ AC_SUBST(CFLAGS)
AC_CONFIG_FILES([
Makefile
libmatemixer/Makefile
-libmatemixer/matemixer-version.h
backends/Makefile
backends/null/Makefile
backends/pulse/Makefile
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index d7fe572..b444738 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -23,7 +23,7 @@ SCANGOBJ_OPTIONS=
# Extra options to supply to gtkdoc-scan.
# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
-SCAN_OPTIONS=--rebuild-sections --rebuild-types
+SCAN_OPTIONS=--rebuild-types
# Extra options to supply to gtkdoc-mkdb.
# e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
diff --git a/docs/reference/libmatemixer-docs.xml b/docs/reference/libmatemixer-docs.xml
index 9a073a4..971c1b2 100644
--- a/docs/reference/libmatemixer-docs.xml
+++ b/docs/reference/libmatemixer-docs.xml
@@ -16,7 +16,6 @@
<chapter>
<title>API Reference</title>
<xi:include href="xml/matemixer.xml"/>
- <xi:include href="xml/matemixer-enums.xml"/>
<xi:include href="xml/matemixer-version.xml"/>
<xi:include href="xml/matemixer-client-stream.xml"/>
<xi:include href="xml/matemixer-control.xml"/>
diff --git a/docs/reference/libmatemixer-sections.txt b/docs/reference/libmatemixer-sections.txt
index e109f09..8bd0d99 100644
--- a/docs/reference/libmatemixer-sections.txt
+++ b/docs/reference/libmatemixer-sections.txt
@@ -2,16 +2,21 @@
<FILE>matemixer</FILE>
mate_mixer_init
mate_mixer_deinit
+LIBMATEMIXER_CHECK_VERSION
</SECTION>
<SECTION>
<FILE>matemixer-client-stream</FILE>
<TITLE>MateMixerClientStream</TITLE>
+MateMixerClientStream
MateMixerClientStreamInterface
mate_mixer_client_stream_get_parent
mate_mixer_client_stream_set_parent
mate_mixer_client_stream_remove
-MateMixerClientStream
+mate_mixer_client_stream_get_app_name
+mate_mixer_client_stream_get_app_id
+mate_mixer_client_stream_get_app_version
+mate_mixer_client_stream_get_app_icon
<SUBSECTION Standard>
MATE_MIXER_CLIENT_STREAM
MATE_MIXER_CLIENT_STREAM_GET_INTERFACE
@@ -23,8 +28,9 @@ mate_mixer_client_stream_get_type
<SECTION>
<FILE>matemixer-control</FILE>
<TITLE>MateMixerControl</TITLE>
+MateMixerState
+MateMixerBackendType
MateMixerControl
-MateMixerControlClass
mate_mixer_control_new
mate_mixer_control_set_backend_type
mate_mixer_control_set_app_name
@@ -44,8 +50,8 @@ mate_mixer_control_get_default_output_stream
mate_mixer_control_set_default_output_stream
mate_mixer_control_get_backend_name
mate_mixer_control_get_backend_type
-MateMixerControlPrivate
<SUBSECTION Standard>
+MateMixerControlClass
MATE_MIXER_CONTROL
MATE_MIXER_CONTROL_CLASS
MATE_MIXER_CONTROL_GET_CLASS
@@ -53,21 +59,22 @@ MATE_MIXER_IS_CONTROL
MATE_MIXER_IS_CONTROL_CLASS
MATE_MIXER_TYPE_CONTROL
mate_mixer_control_get_type
+<SUBSECTION Private>
+MateMixerControlPrivate
</SECTION>
<SECTION>
<FILE>matemixer-device</FILE>
<TITLE>MateMixerDevice</TITLE>
+MateMixerDevice
MateMixerDeviceInterface
mate_mixer_device_get_name
mate_mixer_device_get_description
mate_mixer_device_get_icon
-mate_mixer_device_list_streams
mate_mixer_device_list_ports
mate_mixer_device_list_profiles
mate_mixer_device_get_active_profile
mate_mixer_device_set_active_profile
-MateMixerDevice
<SUBSECTION Standard>
MATE_MIXER_DEVICE
MATE_MIXER_DEVICE_GET_INTERFACE
@@ -77,28 +84,18 @@ mate_mixer_device_get_type
</SECTION>
<SECTION>
-<FILE>matemixer-enums</FILE>
-MateMixerState
-MateMixerBackendType
-MateMixerPortStatus
-MateMixerStreamFlags
-MateMixerStreamStatus
-MateMixerChannelPosition
-</SECTION>
-
-<SECTION>
<FILE>matemixer-port</FILE>
<TITLE>MateMixerPort</TITLE>
+MateMixerPortFlags
MateMixerPort
-MateMixerPortClass
mate_mixer_port_new
mate_mixer_port_get_name
mate_mixer_port_get_description
mate_mixer_port_get_icon
mate_mixer_port_get_priority
-mate_mixer_port_get_status
-MateMixerPortPrivate
+mate_mixer_port_get_flags
<SUBSECTION Standard>
+MateMixerPortClass
MATE_MIXER_IS_PORT
MATE_MIXER_IS_PORT_CLASS
MATE_MIXER_PORT
@@ -106,19 +103,20 @@ MATE_MIXER_PORT_CLASS
MATE_MIXER_PORT_GET_CLASS
MATE_MIXER_TYPE_PORT
mate_mixer_port_get_type
+<SUBSECTION Private>
+MateMixerPortPrivate
</SECTION>
<SECTION>
<FILE>matemixer-profile</FILE>
<TITLE>MateMixerProfile</TITLE>
MateMixerProfile
-MateMixerProfileClass
mate_mixer_profile_new
mate_mixer_profile_get_name
mate_mixer_profile_get_description
mate_mixer_profile_get_priority
-MateMixerProfilePrivate
<SUBSECTION Standard>
+MateMixerProfileClass
MATE_MIXER_IS_PROFILE
MATE_MIXER_IS_PROFILE_CLASS
MATE_MIXER_PROFILE
@@ -126,18 +124,23 @@ MATE_MIXER_PROFILE_CLASS
MATE_MIXER_PROFILE_GET_CLASS
MATE_MIXER_TYPE_PROFILE
mate_mixer_profile_get_type
+<SUBSECTION Private>
+MateMixerProfilePrivate
</SECTION>
<SECTION>
<FILE>matemixer-stream</FILE>
<TITLE>MateMixerStream</TITLE>
+MateMixerChannelPosition
+MateMixerStreamFlags
+MateMixerStreamState
+MateMixerStream
MateMixerStreamInterface
mate_mixer_stream_get_name
mate_mixer_stream_get_description
-mate_mixer_stream_get_icon
mate_mixer_stream_get_device
mate_mixer_stream_get_flags
-mate_mixer_stream_get_status
+mate_mixer_stream_get_state
mate_mixer_stream_get_mute
mate_mixer_stream_set_mute
mate_mixer_stream_get_num_channels
@@ -167,7 +170,6 @@ mate_mixer_stream_set_active_port
mate_mixer_stream_get_min_volume
mate_mixer_stream_get_max_volume
mate_mixer_stream_get_normal_volume
-MateMixerStream
<SUBSECTION Standard>
MATE_MIXER_IS_STREAM
MATE_MIXER_STREAM
@@ -176,12 +178,3 @@ MATE_MIXER_TYPE_STREAM
mate_mixer_stream_get_type
</SECTION>
-<SECTION>
-<FILE>matemixer-version</FILE>
-LIBMATEMIXER_MAJOR_VERSION
-LIBMATEMIXER_MINOR_VERSION
-LIBMATEMIXER_MICRO_VERSION
-LIBMATEMIXER_VERSION
-LIBMATEMIXER_CHECK_VERSION
-</SECTION>
-
diff --git a/examples/monitor.c b/examples/monitor.c
index 3759073..a196b6a 100644
--- a/examples/monitor.c
+++ b/examples/monitor.c
@@ -17,12 +17,34 @@
#include <glib.h>
#include <glib-object.h>
-#include <glib-unix.h>
+#include <string.h>
#include <locale.h>
+#ifdef G_OS_UNIX
+#include <glib-unix.h>
+#endif
+
#include <libmatemixer/matemixer.h>
static MateMixerControl *control;
+static GMainLoop *mainloop;
+
+static gchar *
+create_app_string (const gchar *app_name,
+ const gchar *app_id,
+ const gchar *app_version)
+{
+ GString *string;
+
+ string = g_string_new (app_name);
+
+ if (app_version)
+ g_string_append_printf (string, " %s", app_version);
+ if (app_id)
+ g_string_append_printf (string, " (%s)", app_id);
+
+ return g_string_free (string, FALSE);
+}
static gchar *
create_volume_bar (MateMixerStream *stream, double *percent)
@@ -118,31 +140,33 @@ print_devices (void)
static void
print_streams (void)
{
- const GList *streams;
- const GList *ports;
- const GList *profiles;
- MateMixerProfile *active_profile;
+ const GList *streams;
+ const GList *ports;
streams = mate_mixer_control_list_streams (control);
while (streams) {
MateMixerStream *stream = MATE_MIXER_STREAM (streams->data);
- gchar *volume_bar;
- gdouble volume;
+ gchar *volume_bar;
+ gdouble volume;
+
+ /* Ignore event streams */
+ if (mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_EVENT) {
+ streams = streams->next;
+ continue;
+ }
volume_bar = create_volume_bar (stream, &volume);
g_print ("Stream %s\n"
" |-| Description : %s\n"
- " |-| Icon Name : %s\n"
" |-| Volume : %s %.1f %%\n"
" |-| Muted : %s\n"
" |-| Channels : %d\n"
" |-| Balance : %.1f\n"
- " |-| Fade : %.1f\n\n",
+ " |-| Fade : %.1f\n",
mate_mixer_stream_get_name (stream),
mate_mixer_stream_get_description (stream),
- mate_mixer_stream_get_icon (stream),
volume_bar,
volume,
mate_mixer_stream_get_mute (stream) ? "Yes" : "No",
@@ -150,6 +174,23 @@ print_streams (void)
mate_mixer_stream_get_balance (stream),
mate_mixer_stream_get_fade (stream));
+ if (mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_APPLICATION) {
+ MateMixerClientStream *client;
+ gchar *app;
+
+ /* The application-specific details are accessible through the client
+ * interface, which all client streams implement */
+ client = MATE_MIXER_CLIENT_STREAM (stream);
+
+ app = create_app_string (mate_mixer_client_stream_get_app_name (client),
+ mate_mixer_client_stream_get_app_id (client),
+ mate_mixer_client_stream_get_app_version (client));
+
+ g_print (" |-| Application : %s\n", app);
+ g_free (app);
+ }
+
+ g_print ("\n");
g_free (volume_bar);
ports = mate_mixer_stream_list_ports (stream);
@@ -197,44 +238,91 @@ state_cb (void)
connected ();
break;
case MATE_MIXER_STATE_FAILED:
- g_printerr ("aaa");
+ g_printerr ("Connection failed.\n");
+ g_main_loop_quit (mainloop);
break;
default:
- g_assert_not_reached ();
break;
}
}
+#ifdef G_OS_UNIX
static gboolean
signal_cb (gpointer mainloop)
{
g_idle_add ((GSourceFunc) g_main_loop_quit, mainloop);
return FALSE;
}
+#endif
-int main ()
+int main (int argc, char *argv[])
{
MateMixerState state;
- GMainLoop *mainloop;
+ GOptionContext *context;
+ gchar *backend = NULL;
+ gchar *server = NULL;
+ GError *error = NULL;
+
+ GOptionEntry entries[] = {
+ { "backend", 'b', 0, G_OPTION_ARG_STRING, &backend, "Sound system to use (pulse, null)", NULL },
+ { "server", 's', 0, G_OPTION_ARG_STRING, &server, "Sound server address", NULL },
+ { NULL }
+ };
+
+ /* Initialize the library, if the function returns FALSE, it is not usable */
+ if (!mate_mixer_init ())
+ return 1;
- setlocale (LC_ALL, "");
+ context = g_option_context_new ("- libmatemixer monitor");
- /* The library */
+ g_option_context_add_main_entries (context, entries, NULL);
- if (!mate_mixer_init ())
+ if (!g_option_context_parse (context, &argc, &argv, &error)) {
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
return 1;
+ }
+
+ setlocale (LC_ALL, "");
+ /* Set up the controller, through which we access the main functionality */
control = mate_mixer_control_new ();
+ /* Some details about our application, only used with the PulseAudio backend */
mate_mixer_control_set_app_name (control, "MateMixer Monitor");
+ mate_mixer_control_set_app_id (control, "org.mate-desktop.libmatemixer-monitor");
+ mate_mixer_control_set_app_version (control, "1.0");
mate_mixer_control_set_app_icon (control, "multimedia-volume-control");
+ if (backend) {
+ if (!strcmp (backend, "pulse"))
+ mate_mixer_control_set_backend_type (control, MATE_MIXER_BACKEND_PULSE);
+ else if (!strcmp (backend, "null"))
+ mate_mixer_control_set_backend_type (control, MATE_MIXER_BACKEND_NULL);
+ else
+ g_printerr ("Sound system backend '%s' is unknown, it will be auto-detected.",
+ backend);
+
+ g_free (backend);
+ }
+
+ if (server) {
+ mate_mixer_control_set_server_address (control, server);
+ g_free (server);
+ }
+
+ /* Initiate connection to the sound server */
if (!mate_mixer_control_open (control)) {
g_object_unref (control);
mate_mixer_deinit ();
return 1;
}
+ /* If mate_mixer_control_open() returns TRUE, the state will be either
+ * MATE_MIXER_STATE_READY or MATE_MIXER_STATE_CONNECTING.
+ *
+ * In case mate_mixer_control_open() returned FALSE, the current state
+ * would be MATE_MIXER_STATE_FAILED */
state = mate_mixer_control_get_state (control);
switch (state) {
@@ -244,27 +332,28 @@ int main ()
case MATE_MIXER_STATE_CONNECTING:
g_print ("Waiting for connection...\n");
- /* This state means that the result will be determined asynchronously, so
- * let's wait until the state transitions to a different value */
- g_signal_connect (control, "notify::state", G_CALLBACK (state_cb), NULL);
+ /* Wait for the state transition */
+ g_signal_connect (control,
+ "notify::state",
+ G_CALLBACK (state_cb),
+ NULL);
break;
default:
- /* If mate_mixer_control_open() returns TRUE, these two are the only
- * possible states.
- * In case mate_mixer_control_open() returned FALSE, the current state
- * would be MATE_MIXER_STATE_FAILED */
g_assert_not_reached ();
break;
}
mainloop = g_main_loop_new (NULL, FALSE);
+#ifdef G_OS_UNIX
g_unix_signal_add (SIGTERM, signal_cb, mainloop);
g_unix_signal_add (SIGINT, signal_cb, mainloop);
+#endif
g_main_loop_run (mainloop);
g_object_unref (control);
mate_mixer_deinit ();
+
return 0;
}
diff --git a/libmatemixer/Makefile.am b/libmatemixer/Makefile.am
index a45b29c..9d79e9d 100644
--- a/libmatemixer/Makefile.am
+++ b/libmatemixer/Makefile.am
@@ -44,6 +44,4 @@ libmatemixer_la_LDFLAGS = \
-no-undefined \
-export-dynamic
-EXTRA_DIST = matemixer-version.h.in
-
-include $(top_srcdir)/git.mk
diff --git a/libmatemixer/matemixer-backend-module.c b/libmatemixer/matemixer-backend-module.c
index b04ad6f..5825c13 100644
--- a/libmatemixer/matemixer-backend-module.c
+++ b/libmatemixer/matemixer-backend-module.c
@@ -34,16 +34,32 @@ struct _MateMixerBackendModulePrivate
const MateMixerBackendInfo *(*get_info) (void);
};
-static void mate_mixer_backend_module_class_init (MateMixerBackendModuleClass *klass);
-static void mate_mixer_backend_module_init (MateMixerBackendModule *module);
-static void mate_mixer_backend_module_dispose (GObject *object);
-static void mate_mixer_backend_module_finalize (GObject *object);
+enum {
+ PROP_0,
+ PROP_PATH,
+ N_PROPERTIES
+};
+
+static void mate_mixer_backend_module_class_init (MateMixerBackendModuleClass *klass);
+
+static void mate_mixer_backend_module_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void mate_mixer_backend_module_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
-static gboolean mate_mixer_backend_module_load (GTypeModule *gmodule);
-static void mate_mixer_backend_module_unload (GTypeModule *gmodule);
+static void mate_mixer_backend_module_init (MateMixerBackendModule *module);
+static void mate_mixer_backend_module_dispose (GObject *object);
+static void mate_mixer_backend_module_finalize (GObject *object);
G_DEFINE_TYPE (MateMixerBackendModule, mate_mixer_backend_module, G_TYPE_TYPE_MODULE);
+static gboolean backend_module_load (GTypeModule *gmodule);
+static void backend_module_unload (GTypeModule *gmodule);
+
static void
mate_mixer_backend_module_class_init (MateMixerBackendModuleClass *klass)
{
@@ -51,14 +67,67 @@ mate_mixer_backend_module_class_init (MateMixerBackendModuleClass *klass)
GTypeModuleClass *module_class;
object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = mate_mixer_backend_module_dispose;
- object_class->finalize = mate_mixer_backend_module_finalize;
+ object_class->dispose = mate_mixer_backend_module_dispose;
+ object_class->finalize = mate_mixer_backend_module_finalize;
+ object_class->get_property = mate_mixer_backend_module_get_property;
+ object_class->set_property = mate_mixer_backend_module_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_PATH,
+ g_param_spec_string ("path",
+ "Path",
+ "File path to the module",
+ 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
module_class = G_TYPE_MODULE_CLASS (klass);
- module_class->load = mate_mixer_backend_module_load;
- module_class->unload = mate_mixer_backend_module_unload;
+ module_class->load = backend_module_load;
+ module_class->unload = backend_module_unload;
- g_type_class_add_private (klass, sizeof (MateMixerBackendModulePrivate));
+ g_type_class_add_private (object_class, sizeof (MateMixerBackendModulePrivate));
+}
+
+static void
+mate_mixer_backend_module_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerBackendModule *module;
+
+ module = MATE_MIXER_BACKEND_MODULE (object);
+
+ switch (param_id) {
+ case PROP_PATH:
+ g_value_set_string (value, module->priv->path);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+mate_mixer_backend_module_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MateMixerBackendModule *module;
+
+ module = MATE_MIXER_BACKEND_MODULE (object);
+
+ switch (param_id) {
+ case PROP_PATH:
+ /* Construct-only string property */
+ module->priv->path = g_strdup (g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
}
static void
@@ -88,13 +157,70 @@ mate_mixer_backend_module_dispose (GObject *object)
static void
mate_mixer_backend_module_finalize (GObject *object)
{
+ /* This is in fact never called */
g_free (MATE_MIXER_BACKEND_MODULE (object)->priv->path);
G_OBJECT_CLASS (mate_mixer_backend_module_parent_class)->finalize (object);
}
+/**
+ * mate_mixer_backend_module_new:
+ * @path: path to a backend module
+ *
+ * Creates a new #MateMixerBackendModule instance.
+ *
+ * Returns: a new #MateMixerBackendModule instance.
+ */
+MateMixerBackendModule *
+mate_mixer_backend_module_new (const gchar *path)
+{
+ MateMixerBackendModule *module;
+
+ g_return_val_if_fail (path != NULL, NULL);
+
+ module = g_object_new (MATE_MIXER_TYPE_BACKEND_MODULE,
+ "path", path,
+ NULL);
+
+ g_type_module_set_name (G_TYPE_MODULE (module), path);
+
+ return module;
+}
+
+/**
+ * mate_mixer_backend_module_get_info:
+ * @module: a #MateMixerBackendModule
+ *
+ * Gets information about the loaded backend.
+ *
+ * Returns: a #MateMixerBackendInfo.
+ */
+const MateMixerBackendInfo *
+mate_mixer_backend_module_get_info (MateMixerBackendModule *module)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_BACKEND_MODULE (module), NULL);
+
+ return module->priv->get_info ();
+}
+
+/**
+ * mate_mixer_backend_module_get_path:
+ * @module: a #MateMixerBackendModule
+ *
+ * Gets file path to the backend module.
+ *
+ * Returns: string containing the path.
+ */
+const gchar *
+mate_mixer_backend_module_get_path (MateMixerBackendModule *module)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_BACKEND_MODULE (module), NULL);
+
+ return module->priv->path;
+}
+
static gboolean
-mate_mixer_backend_module_load (GTypeModule *type_module)
+backend_module_load (GTypeModule *type_module)
{
MateMixerBackendModule *module;
@@ -127,7 +253,7 @@ mate_mixer_backend_module_load (GTypeModule *type_module)
return FALSE;
}
- /* Optional backend functions */
+ /* Optional backend function */
g_module_symbol (module->priv->gmodule,
"backend_module_deinit",
(gpointer *) &module->priv->deinit);
@@ -135,11 +261,11 @@ mate_mixer_backend_module_load (GTypeModule *type_module)
module->priv->init (type_module);
module->priv->loaded = TRUE;
- /* Make sure get_info() returns something so we can avoid checking it
+ /* Make sure get_info() returns something, so we can avoid checking it
* in other parts of the library */
if (G_UNLIKELY (module->priv->get_info () == NULL)) {
- g_warning ("Backend module %s does not provide module information",
- module->priv->path);
+ g_critical ("Backend module %s does not provide module information",
+ module->priv->path);
/* Close the module but keep the loaded flag to avoid unreffing
* this instance as the GType has most likely been registered */
@@ -154,14 +280,14 @@ mate_mixer_backend_module_load (GTypeModule *type_module)
g_debug ("Loaded backend module %s", module->priv->path);
} else {
- /* This function was called before, so initialize only */
+ /* This function was called before, so avoid loading and initialize only */
module->priv->init (type_module);
}
return TRUE;
}
static void
-mate_mixer_backend_module_unload (GTypeModule *type_module)
+backend_module_unload (GTypeModule *type_module)
{
MateMixerBackendModule *module;
@@ -172,34 +298,3 @@ mate_mixer_backend_module_unload (GTypeModule *type_module)
if (module->priv->deinit)
module->priv->deinit ();
}
-
-MateMixerBackendModule *
-mate_mixer_backend_module_new (const gchar *path)
-{
- MateMixerBackendModule *module;
-
- g_return_val_if_fail (path != NULL, NULL);
-
- module = g_object_newv (MATE_MIXER_TYPE_BACKEND_MODULE, 0, NULL);
- module->priv->path = g_strdup (path);
-
- g_type_module_set_name (G_TYPE_MODULE (module), path);
-
- return module;
-}
-
-const MateMixerBackendInfo *
-mate_mixer_backend_module_get_info (MateMixerBackendModule *module)
-{
- g_return_val_if_fail (MATE_MIXER_IS_BACKEND_MODULE (module), NULL);
-
- return module->priv->get_info ();
-}
-
-const gchar *
-mate_mixer_backend_module_get_path (MateMixerBackendModule *module)
-{
- g_return_val_if_fail (MATE_MIXER_IS_BACKEND_MODULE (module), NULL);
-
- return module->priv->path;
-}
diff --git a/libmatemixer/matemixer-backend-module.h b/libmatemixer/matemixer-backend-module.h
index 61a426d..e654413 100644
--- a/libmatemixer/matemixer-backend-module.h
+++ b/libmatemixer/matemixer-backend-module.h
@@ -21,8 +21,6 @@
#include <glib.h>
#include <glib-object.h>
-#include "matemixer-enums.h"
-
G_BEGIN_DECLS
typedef struct {
@@ -41,7 +39,7 @@ typedef struct {
#define MATE_MIXER_BACKEND_MODULE_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_BACKEND_MODULE, MateMixerBackendModuleClass))
#define MATE_MIXER_IS_BACKEND_MODULE_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_BACKEND_MODULE))
+ (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_BACKEND_MODULE))
#define MATE_MIXER_BACKEND_MODULE_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_BACKEND_MODULE, MateMixerBackendModuleClass))
@@ -53,12 +51,13 @@ struct _MateMixerBackendModule
{
GTypeModule parent;
+ /*< private >*/
MateMixerBackendModulePrivate *priv;
};
struct _MateMixerBackendModuleClass
{
- GTypeModuleClass parent;
+ GTypeModuleClass parent_class;
};
GType mate_mixer_backend_module_get_type (void) G_GNUC_CONST;
diff --git a/libmatemixer/matemixer-backend.c b/libmatemixer/matemixer-backend.c
index 474edd4..32f7f1b 100644
--- a/libmatemixer/matemixer-backend.c
+++ b/libmatemixer/matemixer-backend.c
@@ -43,77 +43,99 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)
g_object_interface_install_property (iface,
g_param_spec_enum ("state",
"State",
- "Backend connection state",
+ "Current backend connection state",
MATE_MIXER_TYPE_STATE,
MATE_MIXER_STATE_IDLE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
- signals[DEVICE_ADDED] = g_signal_new ("device-added",
- G_TYPE_FROM_INTERFACE (iface),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, device_added),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-
- signals[DEVICE_CHANGED] = g_signal_new ("device-changed",
- G_TYPE_FROM_INTERFACE (iface),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, device_changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-
- signals[DEVICE_REMOVED] = g_signal_new ("device-removed",
- G_TYPE_FROM_INTERFACE (iface),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, device_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-
- signals[STREAM_ADDED] = g_signal_new ("stream-added",
- G_TYPE_FROM_INTERFACE (iface),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, stream_added),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-
- signals[STREAM_CHANGED] = g_signal_new ("stream-changed",
- G_TYPE_FROM_INTERFACE (iface),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, stream_changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-
- signals[STREAM_REMOVED] = g_signal_new ("stream-removed",
- G_TYPE_FROM_INTERFACE (iface),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, stream_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
+ g_object_interface_install_property (iface,
+ g_param_spec_object ("default-input",
+ "Default input",
+ "Default input stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_object ("default-output",
+ "Default output",
+ "Default output stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ signals[DEVICE_ADDED] =
+ g_signal_new ("device-added",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerBackendInterface, device_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[DEVICE_CHANGED] =
+ g_signal_new ("device-changed",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerBackendInterface, device_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[DEVICE_REMOVED] =
+ g_signal_new ("device-removed",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerBackendInterface, device_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[STREAM_ADDED] =
+ g_signal_new ("stream-added",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerBackendInterface, stream_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[STREAM_CHANGED] =
+ g_signal_new ("stream-changed",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerBackendInterface, stream_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ signals[STREAM_REMOVED] =
+ g_signal_new ("stream-removed",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerBackendInterface, stream_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
}
void
@@ -129,25 +151,12 @@ mate_mixer_backend_set_data (MateMixerBackend *backend, const MateMixerBackendDa
iface->set_data (backend, data);
}
-/*
- * Required behaviour:
- * if the function returns TRUE, the state must be either MATE_MIXER_STATE_READY or
- * MATE_MIXER_STATE_CONNECTING.
- */
gboolean
mate_mixer_backend_open (MateMixerBackend *backend)
{
- MateMixerBackendInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), FALSE);
- iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
-
- if (!iface->open) {
- g_critical ("Backend module does not implement the open() method");
- return FALSE;
- }
- return iface->open (backend);
+ return MATE_MIXER_BACKEND_GET_INTERFACE (backend)->open (backend);
}
void
@@ -166,17 +175,9 @@ mate_mixer_backend_close (MateMixerBackend *backend)
MateMixerState
mate_mixer_backend_get_state (MateMixerBackend *backend)
{
- MateMixerBackendInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), MATE_MIXER_STATE_UNKNOWN);
- iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
-
- if (!iface->get_state) {
- g_critical ("Backend module does not implement the get_state() method");
- return MATE_MIXER_STATE_UNKNOWN;
- }
- return iface->get_state (backend);
+ return MATE_MIXER_BACKEND_GET_INTERFACE (backend)->get_state (backend);
}
GList *
diff --git a/libmatemixer/matemixer-backend.h b/libmatemixer/matemixer-backend.h
index 1a5418f..559f256 100644
--- a/libmatemixer/matemixer-backend.h
+++ b/libmatemixer/matemixer-backend.h
@@ -21,6 +21,7 @@
#include <glib.h>
#include <glib-object.h>
+#include "matemixer-enums.h"
#include "matemixer-stream.h"
G_BEGIN_DECLS
@@ -48,22 +49,24 @@ typedef struct _MateMixerBackendInterface MateMixerBackendInterface;
struct _MateMixerBackendInterface
{
- GTypeInterface parent;
+ GTypeInterface parent_iface;
- /* Required */
- gboolean (*open) (MateMixerBackend *backend);
- MateMixerState (*get_state) (MateMixerBackend *backend);
-
- /* Optional */
+ /*< private >*/
void (*set_data) (MateMixerBackend *backend,
const MateMixerBackendData *data);
+ gboolean (*open) (MateMixerBackend *backend);
void (*close) (MateMixerBackend *backend);
+
+ MateMixerState (*get_state) (MateMixerBackend *backend);
+
GList *(*list_devices) (MateMixerBackend *backend);
GList *(*list_streams) (MateMixerBackend *backend);
+
MateMixerStream *(*get_default_input_stream) (MateMixerBackend *backend);
gboolean (*set_default_input_stream) (MateMixerBackend *backend,
MateMixerStream *stream);
+
MateMixerStream *(*get_default_output_stream) (MateMixerBackend *backend);
gboolean (*set_default_output_stream) (MateMixerBackend *backend,
MateMixerStream *stream);
diff --git a/libmatemixer/matemixer-client-stream.c b/libmatemixer/matemixer-client-stream.c
index 80f48a9..d05b1bf 100644
--- a/libmatemixer/matemixer-client-stream.c
+++ b/libmatemixer/matemixer-client-stream.c
@@ -21,6 +21,18 @@
#include "matemixer-client-stream.h"
#include "matemixer-stream.h"
+/**
+ * SECTION:matemixer-client-stream
+ * @short_description: An interface providing extra functionality for client streams
+ * @see_also: #MateMixerStream
+ * @include: libmatemixer/matemixer.h
+ *
+ * #MateMixerClientStream represents a special kind of stream, which belongs
+ * to a parent input or output stream.
+ *
+ * A typical example of a client stream is a stream provided by an application.
+ */
+
G_DEFINE_INTERFACE (MateMixerClientStream, mate_mixer_client_stream, G_TYPE_OBJECT)
static void
@@ -31,11 +43,50 @@ mate_mixer_client_stream_default_init (MateMixerClientStreamInterface *iface)
"Parent",
"Parent stream of the client stream",
MATE_MIXER_TYPE_STREAM,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_string ("app-name",
+ "App name",
+ "Name of the client stream application",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_string ("app-id",
+ "App ID",
+ "Identifier of the client stream application",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_string ("app-version",
+ "App version",
+ "Version of the client stream application",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_string ("app-icon",
+ "App icon",
+ "Icon name of the client stream application",
+ NULL,
+ G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
}
+/**
+ * mate_mixer_client_stream_get_parent:
+ * @client: a #MateMixerClientStream
+ *
+ * Gets the parent stream of the client stream.
+ *
+ * Returns: a #MateMixerStream or %NULL on failure.
+ */
MateMixerStream *
mate_mixer_client_stream_get_parent (MateMixerClientStream *client)
{
@@ -51,6 +102,16 @@ mate_mixer_client_stream_get_parent (MateMixerClientStream *client)
return NULL;
}
+/**
+ * mate_mixer_client_stream_set_parent:
+ * @client: a #MateMixerClientStream
+ * @parent: a #MateMixerStream
+ *
+ * Changes the parent stream of the client stream. The parent stream must be a
+ * non-client output stream.
+ *
+ * Returns: %TRUE on success or %FALSE on failure.
+ */
gboolean
mate_mixer_client_stream_set_parent (MateMixerClientStream *client, MateMixerStream *parent)
{
@@ -67,6 +128,14 @@ mate_mixer_client_stream_set_parent (MateMixerClientStream *client, MateMixerStr
return FALSE;
}
+/**
+ * mate_mixer_client_stream_remove:
+ * @client: a #MateMixerClientStream
+ *
+ * Removes the client stream.
+ *
+ * Returns: %TRUE on success or %FALSE on failure.
+ */
gboolean
mate_mixer_client_stream_remove (MateMixerClientStream *client)
{
@@ -81,3 +150,103 @@ mate_mixer_client_stream_remove (MateMixerClientStream *client)
return FALSE;
}
+
+/**
+ * mate_mixer_client_stream_get_app_name:
+ * @client: a #MateMixerClientStream
+ *
+ * Gets the name of the application in case the stream is an application
+ * stream.
+ *
+ * Returns: a string on success, or %NULL if the stream is not an application
+ * stream or if the application does not provide a name.
+ */
+const gchar *
+mate_mixer_client_stream_get_app_name (MateMixerClientStream *client)
+{
+ MateMixerClientStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
+
+ iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
+
+ if (iface->get_app_name)
+ return iface->get_app_name (client);
+
+ return NULL;
+}
+
+/**
+ * mate_mixer_client_stream_get_app_id:
+ * @client: a #MateMixerClientStream
+ *
+ * Gets the identifier (e.g. org.example.app) of the application in case the
+ * stream is an application stream.
+ *
+ * Returns: a string on success, or %NULL if the stream is not an application
+ * stream or if the application does not provide an identifier.
+ */
+const gchar *
+mate_mixer_client_stream_get_app_id (MateMixerClientStream *client)
+{
+ MateMixerClientStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
+
+ iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
+
+ if (iface->get_app_id)
+ return iface->get_app_id (client);
+
+ return NULL;
+}
+
+/**
+ * mate_mixer_client_stream_get_app_version:
+ * @client: a #MateMixerClientStream
+ *
+ * Gets the version of the application in case the stream is an application
+ * stream.
+ *
+ * Returns: a string on success, or %NULL if the stream is not an application
+ * stream or if the application does not provide a version string.
+ */
+const gchar *
+mate_mixer_client_stream_get_app_version (MateMixerClientStream *client)
+{
+ MateMixerClientStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
+
+ iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
+
+ if (iface->get_app_version)
+ return iface->get_app_version (client);
+
+ return NULL;
+}
+
+/**
+ * mate_mixer_client_stream_get_app_icon:
+ * @client: a #MateMixerClientStream
+ *
+ * Gets the XDG icon name of the application in case the stream is an
+ * application stream.
+ *
+ * Returns: a string on success, or %NULL if the stream is not an application
+ * stream or if the application does not provide an icon name.
+ */
+const gchar *
+mate_mixer_client_stream_get_app_icon (MateMixerClientStream *client)
+{
+ MateMixerClientStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), NULL);
+
+ iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
+
+ if (iface->get_app_icon)
+ return iface->get_app_icon (client);
+
+ return NULL;
+}
diff --git a/libmatemixer/matemixer-client-stream.h b/libmatemixer/matemixer-client-stream.h
index 2c690c5..1375cb3 100644
--- a/libmatemixer/matemixer-client-stream.h
+++ b/libmatemixer/matemixer-client-stream.h
@@ -39,20 +39,29 @@ typedef struct _MateMixerClientStreamInterface MateMixerClientStreamInterface;
struct _MateMixerClientStreamInterface
{
- /*< private >*/
- GTypeInterface parent;
+ GTypeInterface parent_iface;
- MateMixerStream *(*get_parent) (MateMixerClientStream *client);
- gboolean (*set_parent) (MateMixerClientStream *client,
- MateMixerStream *stream);
- gboolean (*remove) (MateMixerClientStream *client);
+ /*< private >*/
+ MateMixerStream *(*get_parent) (MateMixerClientStream *client);
+ gboolean (*set_parent) (MateMixerClientStream *client,
+ MateMixerStream *stream);
+ gboolean (*remove) (MateMixerClientStream *client);
+ const gchar *(*get_app_name) (MateMixerClientStream *client);
+ const gchar *(*get_app_id) (MateMixerClientStream *client);
+ const gchar *(*get_app_version) (MateMixerClientStream *client);
+ const gchar *(*get_app_icon) (MateMixerClientStream *client);
};
-GType mate_mixer_client_stream_get_type (void) G_GNUC_CONST;
-MateMixerStream *mate_mixer_client_stream_get_parent (MateMixerClientStream *client);
-gboolean mate_mixer_client_stream_set_parent (MateMixerClientStream *client,
- MateMixerStream *parent);
-gboolean mate_mixer_client_stream_remove (MateMixerClientStream *client);
+GType mate_mixer_client_stream_get_type (void) G_GNUC_CONST;
+MateMixerStream *mate_mixer_client_stream_get_parent (MateMixerClientStream *client);
+gboolean mate_mixer_client_stream_set_parent (MateMixerClientStream *client,
+ MateMixerStream *parent);
+gboolean mate_mixer_client_stream_remove (MateMixerClientStream *client);
+
+const gchar * mate_mixer_client_stream_get_app_name (MateMixerClientStream *client);
+const gchar * mate_mixer_client_stream_get_app_id (MateMixerClientStream *client);
+const gchar * mate_mixer_client_stream_get_app_version (MateMixerClientStream *client);
+const gchar * mate_mixer_client_stream_get_app_icon (MateMixerClientStream *client);
G_END_DECLS
diff --git a/libmatemixer/matemixer-control.c b/libmatemixer/matemixer-control.c
index 3e3045e..3619a94 100644
--- a/libmatemixer/matemixer-control.c
+++ b/libmatemixer/matemixer-control.c
@@ -27,10 +27,16 @@
#include "matemixer-private.h"
#include "matemixer-stream.h"
+/**
+ * SECTION:matemixer-control
+ * @include: libmatemixer/matemixer.h
+ */
+
struct _MateMixerControlPrivate
{
GList *devices;
GList *streams;
+ gboolean backend_chosen;
MateMixerState state;
MateMixerBackend *backend;
MateMixerBackendData backend_data;
@@ -51,6 +57,8 @@ enum {
N_PROPERTIES
};
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
enum {
DEVICE_ADDED,
DEVICE_CHANGED,
@@ -61,43 +69,276 @@ enum {
N_SIGNALS
};
-static void mate_mixer_control_class_init (MateMixerControlClass *klass);
-static void mate_mixer_control_init (MateMixerControl *control);
-static void mate_mixer_control_dispose (GObject *object);
-static void mate_mixer_control_finalize (GObject *object);
-
-static gboolean control_try_next_backend (MateMixerControl *control);
-static void control_change_state (MateMixerControl *control,
- MateMixerState state);
-static void control_state_changed_cb (MateMixerBackend *backend,
- GParamSpec *pspec,
- MateMixerControl *control);
-
-static void control_device_added_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-static void control_device_changed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-static void control_device_removed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-
-static void control_stream_added_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-static void control_stream_changed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-static void control_stream_removed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
+static guint signals[N_SIGNALS] = { 0, };
+
+static void mate_mixer_control_class_init (MateMixerControlClass *klass);
+
+static void mate_mixer_control_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void mate_mixer_control_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void mate_mixer_control_init (MateMixerControl *control);
+static void mate_mixer_control_dispose (GObject *object);
+static void mate_mixer_control_finalize (GObject *object);
G_DEFINE_TYPE (MateMixerControl, mate_mixer_control, G_TYPE_OBJECT);
-static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+static void control_state_changed_cb (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerControl *control);
+
+static void control_device_added_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+static void control_device_changed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+static void control_device_removed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+
+static void control_stream_added_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+static void control_stream_changed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+static void control_stream_removed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+
+static gboolean control_try_next_backend (MateMixerControl *control);
+
+static void control_change_state (MateMixerControl *control,
+ MateMixerState state);
+
+static void control_close (MateMixerControl *control);
+
+static void control_free_backend (MateMixerControl *control);
+static void control_free_devices (MateMixerControl *control);
+static void control_free_streams (MateMixerControl *control);
-static guint signals[N_SIGNALS] = { 0, };
+static void
+mate_mixer_control_class_init (MateMixerControlClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = mate_mixer_control_dispose;
+ object_class->finalize = mate_mixer_control_finalize;
+ object_class->get_property = mate_mixer_control_get_property;
+ object_class->set_property = mate_mixer_control_set_property;
+
+ /**
+ * MateMixerControl:app-name:
+ *
+ * Localized human readable name of the application.
+ */
+ properties[PROP_APP_NAME] =
+ g_param_spec_string ("app-name",
+ "App name",
+ "Application name",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * MateMixerControl:app-id:
+ *
+ * Identifier of the application (e.g. org.example.app).
+ */
+ properties[PROP_APP_ID] =
+ g_param_spec_string ("app-id",
+ "App ID",
+ "Application identifier",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * MateMixerControl:app-version:
+ *
+ * Version of the application.
+ */
+ properties[PROP_APP_VERSION] =
+ g_param_spec_string ("app-version",
+ "App version",
+ "Application version",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * MateMixerControl:app-icon:
+ *
+ * An XDG icon name for the application.
+ */
+ properties[PROP_APP_ICON] =
+ g_param_spec_string ("app-icon",
+ "App icon",
+ "Application icon name",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * MateMixerControl:server-address:
+ *
+ * Address of the sound server to connect to.
+ *
+ * This feature is only supported in the PulseAudio backend. There is
+ * no need to specify an address in order to connect to the local daemon.
+ */
+ properties[PROP_SERVER_ADDRESS] =
+ g_param_spec_string ("server-address",
+ "Server address",
+ "Sound server address",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_STATE] =
+ g_param_spec_enum ("state",
+ "State",
+ "Current backend connection state",
+ MATE_MIXER_TYPE_STATE,
+ MATE_MIXER_STATE_IDLE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DEFAULT_INPUT] =
+ g_param_spec_object ("default-input",
+ "Default input",
+ "Default input stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DEFAULT_OUTPUT] =
+ g_param_spec_object ("default-output",
+ "Default output",
+ "Default output stream",
+ MATE_MIXER_TYPE_STREAM,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ /**
+ * MateMixerControl::device-added:
+ * @control: a #MateMixerControl
+ * @name: name of the added device
+ *
+ * The signal is emitted each time a device is added to the system.
+ */
+ signals[DEVICE_ADDED] =
+ g_signal_new ("device-added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerControlClass, device_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ /**
+ * MateMixerControl::device-changed:
+ * @control: a #MateMixerControl
+ * @name: name of the changed device
+ *
+ * The signal is emitted each time a change occurs on one of the known
+ * devices.
+ */
+ signals[DEVICE_CHANGED] =
+ g_signal_new ("device-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerControlClass, device_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ /**
+ * MateMixerControl::device-removed:
+ * @control: a #MateMixerControl
+ * @name: name of the removed device
+ *
+ * The signal is emitted each time a device is removed from the system.
+ */
+ signals[DEVICE_REMOVED] =
+ g_signal_new ("device-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerControlClass, device_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ /**
+ * MateMixerControl::stream-added:
+ * @control: a #MateMixerControl
+ * @name: name of the added stream
+ *
+ * The signal is emitted each time a stream is added to the system.
+ */
+ signals[STREAM_ADDED] =
+ g_signal_new ("stream-added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerControlClass, stream_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ /**
+ * MateMixerControl::stream-changed:
+ * @control: a #MateMixerControl
+ * @name: name of the changed stream
+ *
+ * The signal is emitted each time a change occurs on one of the known
+ * streams.
+ */
+ signals[STREAM_CHANGED] =
+ g_signal_new ("stream-changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerControlClass, stream_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ /**
+ * MateMixerControl::stream-removed:
+ * @control: a #MateMixerControl
+ * @name: name of the removed stream
+ *
+ * The signal is emitted each time a stream is removed from the system.
+ */
+ signals[STREAM_REMOVED] =
+ g_signal_new ("stream-removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerControlClass, stream_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+
+ g_type_class_add_private (object_class, sizeof (MateMixerControlPrivate));
+}
static void
mate_mixer_control_get_property (GObject *object,
@@ -173,170 +414,6 @@ mate_mixer_control_set_property (GObject *object,
}
static void
-mate_mixer_control_class_init (MateMixerControlClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = mate_mixer_control_dispose;
- object_class->finalize = mate_mixer_control_finalize;
- object_class->get_property = mate_mixer_control_get_property;
- object_class->set_property = mate_mixer_control_set_property;
-
- /**
- * MateMixerControl:app-name:
- *
- * Localized human readable name of the application.
- */
- properties[PROP_APP_NAME] = g_param_spec_string ("app-name",
- "App name",
- "Application name",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
- /**
- * MateMixerControl:app-id:
- *
- * Identifier of the application (e.g. org.example.app).
- */
- properties[PROP_APP_ID] = g_param_spec_string ("app-id",
- "App ID",
- "Application identifier",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
- /**
- * MateMixerControl:app-version:
- *
- * Version of the application.
- */
- properties[PROP_APP_VERSION] = g_param_spec_string ("app-version",
- "App version",
- "Application version",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
- /**
- * MateMixerControl:app-icon:
- *
- * An XDG icon name for the application.
- */
- properties[PROP_APP_ICON] = g_param_spec_string ("app-icon",
- "App icon",
- "Application icon",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- /**
- * MateMixerControl:server-address:
- *
- * Address of the sound server to connect to.
- *
- * This feature is only supported in the PulseAudio backend. There is
- * no need to specify an address in order to connect to the local daemon.
- */
- properties[PROP_SERVER_ADDRESS] = g_param_spec_string ("server-address",
- "Server address",
- "Sound server address",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_STATE] = g_param_spec_enum ("state",
- "State",
- "Current backend connection state",
- MATE_MIXER_TYPE_STATE,
- MATE_MIXER_STATE_IDLE,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_DEFAULT_INPUT] = g_param_spec_object ("default-input",
- "Default input",
- "Default input stream",
- MATE_MIXER_TYPE_STREAM,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_DEFAULT_OUTPUT] = g_param_spec_object ("default-output",
- "Default output",
- "Default output stream",
- MATE_MIXER_TYPE_STREAM,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- signals[DEVICE_ADDED] = g_signal_new ("device-added",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, device_added),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-
- signals[DEVICE_CHANGED] = g_signal_new ("device-changed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, device_changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-
- signals[DEVICE_REMOVED] = g_signal_new ("device-removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, device_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-
- signals[STREAM_ADDED] = g_signal_new ("stream-added",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, stream_added),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-
- signals[STREAM_CHANGED] = g_signal_new ("stream-changed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, stream_changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-
- signals[STREAM_REMOVED] = g_signal_new ("stream-removed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, stream_removed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-
- g_object_class_install_properties (object_class, N_PROPERTIES, properties);
-
- g_type_class_add_private (object_class, sizeof (MateMixerControlPrivate));
-}
-
-static void
mate_mixer_control_init (MateMixerControl *control)
{
control->priv = G_TYPE_INSTANCE_GET_PRIVATE (control,
@@ -347,25 +424,7 @@ mate_mixer_control_init (MateMixerControl *control)
static void
mate_mixer_control_dispose (GObject *object)
{
- MateMixerControl *control;
-
- control = MATE_MIXER_CONTROL (object);
-
- if (control->priv->backend) {
- mate_mixer_backend_close (control->priv->backend);
- g_clear_object (&control->priv->backend);
- }
-
- g_clear_object (&control->priv->module);
-
- if (control->priv->devices) {
- g_list_free_full (control->priv->devices, g_object_unref);
- control->priv->devices = NULL;
- }
- if (control->priv->streams) {
- g_list_free_full (control->priv->streams, g_object_unref);
- control->priv->streams = NULL;
- }
+ control_close (MATE_MIXER_CONTROL (object));
G_OBJECT_CLASS (mate_mixer_control_parent_class)->dispose (object);
}
@@ -394,7 +453,8 @@ mate_mixer_control_finalize (GObject *object)
* Returns: a new #MateMixerControl instance or %NULL if the library has not
* been initialized using mate_mixer_init().
*/
-MateMixerControl *mate_mixer_control_new (void)
+MateMixerControl *
+mate_mixer_control_new (void)
{
if (!mate_mixer_is_initialized ()) {
g_critical ("The library has not been initialized");
@@ -415,7 +475,8 @@ MateMixerControl *mate_mixer_control_new (void)
* @control use the given backend.
*
* This function will fail if support for the backend is not installed in
- * the system.
+ * the system or if the current state is either %MATE_MIXER_STATE_CONNECTING or
+ * %MATE_MIXER_STATE_READY.
*
* Returns: %TRUE on success or %FALSE on failure.
*/
@@ -429,6 +490,10 @@ mate_mixer_control_set_backend_type (MateMixerControl *control,
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+ if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ control->priv->state == MATE_MIXER_STATE_READY)
+ return FALSE;
+
modules = mate_mixer_get_modules ();
while (modules) {
module = MATE_MIXER_BACKEND_MODULE (modules->data);
@@ -634,11 +699,13 @@ mate_mixer_control_open (MateMixerControl *control)
const MateMixerBackendInfo *info = NULL;
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
- g_return_val_if_fail (control->priv->state != MATE_MIXER_STATE_CONNECTING &&
- control->priv->state != MATE_MIXER_STATE_READY, FALSE);
+
+ if (control->priv->state == MATE_MIXER_STATE_CONNECTING ||
+ control->priv->state == MATE_MIXER_STATE_READY)
+ return FALSE;
/* We are going to choose the first backend to try. It will be either the one
- * specified by the user or the one with the highest priority */
+ * specified by the application or the one with the highest priority */
modules = mate_mixer_get_modules ();
if (control->priv->backend_type != MATE_MIXER_BACKEND_UNKNOWN) {
@@ -658,7 +725,6 @@ mate_mixer_control_open (MateMixerControl *control)
/* The highest priority module is on the top of the list */
module = MATE_MIXER_BACKEND_MODULE (modules->data);
}
-
if (module == NULL) {
/* Most likely the selected backend is not installed */
control_change_state (control, MATE_MIXER_STATE_FAILED);
@@ -669,7 +735,7 @@ mate_mixer_control_open (MateMixerControl *control)
info = mate_mixer_backend_module_get_info (module);
control->priv->module = g_object_ref (module);
- control->priv->backend = g_object_newv (info->g_type, 0, NULL);
+ control->priv->backend = g_object_new (info->g_type, NULL);
mate_mixer_backend_set_data (control->priv->backend, &control->priv->backend_data);
@@ -678,7 +744,7 @@ mate_mixer_control_open (MateMixerControl *control)
control_change_state (control, MATE_MIXER_STATE_CONNECTING);
/* The backend initialization might fail in case it is known right now that
- * it is unusable */
+ * the backend is unusable */
if (!mate_mixer_backend_open (control->priv->backend)) {
if (control->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) {
/* User didn't request a specific backend, so try another one */
@@ -686,9 +752,7 @@ mate_mixer_control_open (MateMixerControl *control)
}
/* User requested a specific backend and it failed */
- g_clear_object (&control->priv->module);
- g_clear_object (&control->priv->backend);
-
+ control_close (control);
control_change_state (control, MATE_MIXER_STATE_FAILED);
return FALSE;
}
@@ -697,11 +761,10 @@ mate_mixer_control_open (MateMixerControl *control)
if (G_UNLIKELY (state != MATE_MIXER_STATE_READY &&
state != MATE_MIXER_STATE_CONNECTING)) {
- /* The backend should not be in this state */
+ /* This would a backend bug */
g_warn_if_reached ();
- g_clear_object (&control->priv->module);
- g_clear_object (&control->priv->backend);
+ control_close (control);
control_change_state (control, MATE_MIXER_STATE_FAILED);
return FALSE;
}
@@ -716,6 +779,22 @@ mate_mixer_control_open (MateMixerControl *control)
}
/**
+ * mate_mixer_control_close:
+ * @control: a #MateMixerControl
+ *
+ * Closes connection to the currently used sound system. The state will be
+ * set to %MATE_MIXER_STATE_IDLE.
+ */
+void
+mate_mixer_control_close (MateMixerControl *control)
+{
+ g_return_if_fail (MATE_MIXER_IS_CONTROL (control));
+
+ control_close (control);
+ control_change_state (control, MATE_MIXER_STATE_IDLE);
+}
+
+/**
* mate_mixer_control_get_state:
* @control: a #MateMixerControl
*
@@ -743,12 +822,12 @@ mate_mixer_control_get_state (MateMixerControl *control)
MateMixerDevice *
mate_mixer_control_get_device (MateMixerControl *control, const gchar *name)
{
- GList *list;
+ const GList *list;
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
g_return_val_if_fail (name != NULL, NULL);
- list = control->priv->devices;
+ list = mate_mixer_control_list_devices (control);
while (list) {
MateMixerDevice *device = MATE_MIXER_DEVICE (list->data);
@@ -772,12 +851,12 @@ mate_mixer_control_get_device (MateMixerControl *control, const gchar *name)
MateMixerStream *
mate_mixer_control_get_stream (MateMixerControl *control, const gchar *name)
{
- GList *list;
+ const GList *list;
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
g_return_val_if_fail (name != NULL, NULL);
- list = control->priv->streams;
+ list = mate_mixer_control_list_streams (control);
while (list) {
MateMixerStream *stream = MATE_MIXER_STREAM (list->data);
@@ -806,7 +885,9 @@ const GList *
mate_mixer_control_list_devices (MateMixerControl *control)
{
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
- g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
+
+ if (control->priv->state != MATE_MIXER_STATE_READY)
+ return NULL;
/* This list is cached here and invalidated when the backend notifies us
* about a change */
@@ -834,7 +915,9 @@ const GList *
mate_mixer_control_list_streams (MateMixerControl *control)
{
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
- g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
+
+ if (control->priv->state != MATE_MIXER_STATE_READY)
+ return NULL;
/* This list is cached here and invalidated when the backend notifies us
* about a change */
@@ -859,7 +942,9 @@ MateMixerStream *
mate_mixer_control_get_default_input_stream (MateMixerControl *control)
{
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
- g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
+
+ if (control->priv->state != MATE_MIXER_STATE_READY)
+ return NULL;
return mate_mixer_backend_get_default_input_stream (control->priv->backend);
}
@@ -877,8 +962,10 @@ gboolean
mate_mixer_control_set_default_input_stream (MateMixerControl *control,
MateMixerStream *stream)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
- g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+
+ if (control->priv->state != MATE_MIXER_STATE_READY)
+ return FALSE;
return mate_mixer_backend_set_default_input_stream (control->priv->backend, stream);
}
@@ -897,7 +984,9 @@ MateMixerStream *
mate_mixer_control_get_default_output_stream (MateMixerControl *control)
{
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
- g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
+
+ if (control->priv->state != MATE_MIXER_STATE_READY)
+ return NULL;
return mate_mixer_backend_get_default_output_stream (control->priv->backend);
}
@@ -915,8 +1004,10 @@ gboolean
mate_mixer_control_set_default_output_stream (MateMixerControl *control,
MateMixerStream *stream)
{
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
- g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
+
+ if (control->priv->state != MATE_MIXER_STATE_READY)
+ return FALSE;
return mate_mixer_backend_set_default_input_stream (control->priv->backend, stream);
}
@@ -925,44 +1016,160 @@ mate_mixer_control_set_default_output_stream (MateMixerControl *control,
* mate_mixer_control_get_backend_name:
* @control: a #MateMixerControl
*
- * Gets the name of the currently used backend. The @control must be in the
- * %MATE_MIXER_STATE_READY state.
+ * Gets the name of the currently used backend. This function will not
+ * work until connected to a sound system.
*
* Returns: the name or %NULL on error.
*/
const gchar *
mate_mixer_control_get_backend_name (MateMixerControl *control)
{
- const MateMixerBackendInfo *info;
-
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
- g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, NULL);
- info = mate_mixer_backend_module_get_info (control->priv->module);
+ if (!control->priv->backend_chosen)
+ return NULL;
- return info->name;
+ return mate_mixer_backend_module_get_info (control->priv->module)->name;
}
/**
* mate_mixer_control_get_backend_type:
* @control: a #MateMixerControl
*
- * Gets the type of the currently used backend. The @control must be in the
- * %MATE_MIXER_STATE_READY state.
+ * Gets the type of the currently used backend. This function will not
+ * work until connected to a sound system.
*
* Returns: the backend type or %MATE_MIXER_BACKEND_UNKNOWN on error.
*/
MateMixerBackendType
mate_mixer_control_get_backend_type (MateMixerControl *control)
{
- const MateMixerBackendInfo *info;
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), MATE_MIXER_BACKEND_UNKNOWN);
- g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), FALSE);
- g_return_val_if_fail (control->priv->state == MATE_MIXER_STATE_READY, FALSE);
+ if (!control->priv->backend_chosen)
+ return MATE_MIXER_BACKEND_UNKNOWN;
- info = mate_mixer_backend_module_get_info (control->priv->module);
+ return mate_mixer_backend_module_get_info (control->priv->module)->backend_type;
+}
- return info->backend_type;
+static void
+control_state_changed_cb (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerControl *control)
+{
+ MateMixerState state = mate_mixer_backend_get_state (backend);
+
+ switch (state) {
+ case MATE_MIXER_STATE_CONNECTING:
+ g_debug ("Backend %s changed state to CONNECTING",
+ mate_mixer_backend_module_get_info (control->priv->module)->name);
+
+ if (control->priv->backend_chosen) {
+ /* Invalidate cached data when reconnecting */
+ control_free_devices (control);
+ control_free_devices (control);
+ }
+ control_change_state (control, state);
+ break;
+
+ case MATE_MIXER_STATE_READY:
+ g_debug ("Backend %s changed state to READY",
+ mate_mixer_backend_module_get_info (control->priv->module)->name);
+
+ control_change_state (control, state);
+ break;
+
+ case MATE_MIXER_STATE_FAILED:
+ g_debug ("Backend %s changed state to FAILED",
+ mate_mixer_backend_module_get_info (control->priv->module)->name);
+
+ if (control->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) {
+ /* User didn't request a specific backend, so try another one */
+ control_try_next_backend (control);
+ } else {
+ /* User requested a specific backend and it failed */
+ control_close (control);
+ control_change_state (control, state);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+control_device_added_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
+{
+ control_free_devices (control);
+
+ g_signal_emit (G_OBJECT (control),
+ signals[DEVICE_ADDED],
+ 0,
+ name);
+}
+
+static void
+control_device_changed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
+{
+ g_signal_emit (G_OBJECT (control),
+ signals[DEVICE_CHANGED],
+ 0,
+ name);
+}
+
+static void
+control_device_removed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
+{
+ control_free_devices (control);
+
+ g_signal_emit (G_OBJECT (control),
+ signals[DEVICE_REMOVED],
+ 0,
+ name);
+}
+
+static void
+control_stream_added_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
+{
+ control_free_streams (control);
+
+ g_signal_emit (G_OBJECT (control),
+ signals[STREAM_ADDED],
+ 0,
+ name);
+}
+
+static void
+control_stream_changed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
+{
+ g_signal_emit (G_OBJECT (control),
+ signals[STREAM_CHANGED],
+ 0,
+ name);
+}
+
+static void
+control_stream_removed_cb (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
+{
+ control_free_streams (control);
+
+ g_signal_emit (G_OBJECT (control),
+ signals[STREAM_REMOVED],
+ 0,
+ name);
}
static gboolean
@@ -982,8 +1189,7 @@ control_try_next_backend (MateMixerControl *control)
}
modules = modules->next;
}
- g_clear_object (&control->priv->module);
- g_clear_object (&control->priv->backend);
+ control_close (control);
if (module == NULL) {
/* This shouldn't happen under normal circumstances as the lowest
@@ -995,9 +1201,9 @@ control_try_next_backend (MateMixerControl *control)
control->priv->module = g_object_ref (module);
control->priv->backend =
- g_object_newv (mate_mixer_backend_module_get_info (module)->g_type,
- 0,
- NULL);
+ g_object_new (mate_mixer_backend_module_get_info (module)->g_type, NULL);
+
+ mate_mixer_backend_set_data (control->priv->backend, &control->priv->backend_data);
if (!mate_mixer_backend_open (control->priv->backend))
return control_try_next_backend (control);
@@ -1017,9 +1223,11 @@ control_change_state (MateMixerControl *control, MateMixerState state)
control->priv->state = state;
- if (state == MATE_MIXER_STATE_READY) {
+ if (state == MATE_MIXER_STATE_READY && !control->priv->backend_chosen) {
/* It is safe to connect to the backend signals after reaching the READY
- * state, because the app is not allowed to query any data before that state */
+ * state, because the app is not allowed to query any data before that state;
+ * therefore we won't end up in an inconsistent state by caching a list and
+ * then missing a notification about a change in the list */
g_signal_connect (control->priv->backend,
"device-added",
G_CALLBACK (control_device_added_cb),
@@ -1044,131 +1252,52 @@ control_change_state (MateMixerControl *control, MateMixerState state)
"stream-removed",
G_CALLBACK (control_stream_removed_cb),
control);
- }
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_STATE]);
-}
-
-static void
-control_state_changed_cb (MateMixerBackend *backend,
- GParamSpec *pspec,
- MateMixerControl *control)
-{
- MateMixerState state = mate_mixer_backend_get_state (backend);
-
- switch (state) {
- case MATE_MIXER_STATE_READY:
- control_change_state (control, state);
- break;
-
- case MATE_MIXER_STATE_FAILED:
- control_try_next_backend (control);
- break;
- default:
- break;
- }
-}
-
-static void
-control_device_added_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control)
-{
- if (control->priv->devices) {
- g_list_free_full (control->priv->devices, g_object_unref);
- control->priv->devices = NULL;
+ control->priv->backend_chosen = TRUE;
}
- g_debug ("Device added: %s", name);
-
- g_signal_emit (G_OBJECT (control),
- signals[DEVICE_ADDED],
- 0,
- name);
-}
-
-static void
-control_device_changed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control)
-{
- /* Do not invalidate the list of devices here as the list has not changed,
- * only some properties of a device */
-
- g_debug ("Device changed: %s", name);
-
- g_signal_emit (G_OBJECT (control),
- signals[DEVICE_CHANGED],
- 0,
- name);
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_STATE]);
}
static void
-control_device_removed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control)
+control_close (MateMixerControl *control)
{
- if (control->priv->devices) {
- g_list_free_full (control->priv->devices, g_object_unref);
- control->priv->devices = NULL;
- }
-
- g_debug ("Device removed: %s", name);
+ control_free_backend (control);
+ control_free_devices (control);
+ control_free_streams (control);
- g_signal_emit (G_OBJECT (control),
- signals[DEVICE_REMOVED],
- 0,
- name);
+ g_clear_object (&control->priv->module);
}
static void
-control_stream_added_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control)
+control_free_backend (MateMixerControl *control)
{
- if (control->priv->streams) {
- g_list_free_full (control->priv->streams, g_object_unref);
- control->priv->streams = NULL;
- }
+ if (control->priv->backend == NULL)
+ return;
- g_debug ("Stream added: %s", name);
+ mate_mixer_backend_close (control->priv->backend);
- g_signal_emit (G_OBJECT (control),
- signals[STREAM_ADDED],
- 0,
- name);
+ g_clear_object (&control->priv->backend);
}
static void
-control_stream_changed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control)
+control_free_devices (MateMixerControl *control)
{
- /* Do not invalidate the list of streams here as the list has not changed,
- * only some properties of a stream */
+ if (control->priv->devices == NULL)
+ return;
- g_debug ("Stream changed: %s", name);
+ g_list_free_full (control->priv->devices, g_object_unref);
- g_signal_emit (G_OBJECT (control),
- signals[STREAM_CHANGED],
- 0,
- name);
+ control->priv->devices = NULL;
}
static void
-control_stream_removed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control)
+control_free_streams (MateMixerControl *control)
{
- if (control->priv->streams) {
- g_list_free_full (control->priv->streams, g_object_unref);
- control->priv->streams = NULL;
- }
+ if (control->priv->streams == NULL)
+ return;
- g_debug ("Stream removed: %s", name);
+ g_list_free_full (control->priv->streams, g_object_unref);
- g_signal_emit (G_OBJECT (control),
- signals[STREAM_REMOVED],
- 0,
- name);
+ control->priv->streams = NULL;
}
diff --git a/libmatemixer/matemixer-control.h b/libmatemixer/matemixer-control.h
index ad48768..5598ade 100644
--- a/libmatemixer/matemixer-control.h
+++ b/libmatemixer/matemixer-control.h
@@ -21,6 +21,7 @@
#include <glib.h>
#include <glib-object.h>
+#include <libmatemixer/matemixer-device.h>
#include <libmatemixer/matemixer-enums.h>
#include <libmatemixer/matemixer-stream.h>
@@ -35,7 +36,7 @@ G_BEGIN_DECLS
#define MATE_MIXER_CONTROL_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_CONTROL, MateMixerControlClass))
#define MATE_MIXER_IS_CONTROL_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_CONTROL))
+ (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_CONTROL))
#define MATE_MIXER_CONTROL_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_CONTROL, MateMixerControlClass))
@@ -51,9 +52,10 @@ typedef struct _MateMixerControlPrivate MateMixerControlPrivate;
*/
struct _MateMixerControl
{
+ GObject parent;
+
/*< private >*/
- GObject parent;
- MateMixerControlPrivate *priv;
+ MateMixerControlPrivate *priv;
};
/**
@@ -63,10 +65,9 @@ struct _MateMixerControl
*/
struct _MateMixerControlClass
{
- /*< private >*/
- GObjectClass parent;
+ GObjectClass parent_class;
- /* Signals */
+ /*< private >*/
void (*device_added) (MateMixerControl *control,
const gchar *name);
void (*device_changed) (MateMixerControl *control,
@@ -97,6 +98,7 @@ gboolean mate_mixer_control_set_app_icon (MateMixerCon
gboolean mate_mixer_control_set_server_address (MateMixerControl *control,
const gchar *address);
gboolean mate_mixer_control_open (MateMixerControl *control);
+void mate_mixer_control_close (MateMixerControl *control);
MateMixerState mate_mixer_control_get_state (MateMixerControl *control);
diff --git a/libmatemixer/matemixer-device.c b/libmatemixer/matemixer-device.c
index a022877..e74dc23 100644
--- a/libmatemixer/matemixer-device.c
+++ b/libmatemixer/matemixer-device.c
@@ -21,6 +21,11 @@
#include "matemixer-device.h"
#include "matemixer-profile.h"
+/**
+ * SECTION:matemixer-device
+ * @include: libmatemixer/matemixer.h
+ */
+
G_DEFINE_INTERFACE (MateMixerDevice, mate_mixer_device, G_TYPE_OBJECT)
static void
@@ -31,8 +36,7 @@ mate_mixer_device_default_init (MateMixerDeviceInterface *iface)
"Name",
"Name of the sound device",
NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
+ G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
@@ -40,8 +44,7 @@ mate_mixer_device_default_init (MateMixerDeviceInterface *iface)
"Description",
"Description of the sound device",
NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
+ G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
@@ -49,11 +52,24 @@ mate_mixer_device_default_init (MateMixerDeviceInterface *iface)
"Icon",
"Name of the sound device icon",
NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
+ G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
+ g_param_spec_pointer ("ports",
+ "Ports",
+ "GList of the sound device ports",
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_pointer ("profiles",
+ "Profiles",
+ "GList of the sound device profiles",
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
g_param_spec_object ("active-profile",
"Active profile",
"The currently active profile of the sound device",
@@ -65,16 +81,9 @@ mate_mixer_device_default_init (MateMixerDeviceInterface *iface)
const gchar *
mate_mixer_device_get_name (MateMixerDevice *device)
{
- MateMixerDeviceInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
- iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
-
- if (iface->get_name)
- return iface->get_name (device);
-
- return NULL;
+ return MATE_MIXER_DEVICE_GET_INTERFACE (device)->get_name (device);
}
const gchar *
@@ -108,21 +117,6 @@ mate_mixer_device_get_icon (MateMixerDevice *device)
}
const GList *
-mate_mixer_device_list_streams (MateMixerDevice *device)
-{
- MateMixerDeviceInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
-
- iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
-
- if (iface->list_streams)
- return iface->list_streams (device);
-
- return NULL;
-}
-
-const GList *
mate_mixer_device_list_ports (MateMixerDevice *device)
{
MateMixerDeviceInterface *iface;
diff --git a/libmatemixer/matemixer-device.h b/libmatemixer/matemixer-device.h
index d814847..a1422e3 100644
--- a/libmatemixer/matemixer-device.h
+++ b/libmatemixer/matemixer-device.h
@@ -39,9 +39,9 @@ typedef struct _MateMixerDeviceInterface MateMixerDeviceInterface;
struct _MateMixerDeviceInterface
{
- /*< private >*/
- GTypeInterface parent;
+ GTypeInterface parent_iface;
+ /*< private >*/
const gchar *(*get_name) (MateMixerDevice *device);
const gchar *(*get_description) (MateMixerDevice *device);
const gchar *(*get_icon) (MateMixerDevice *device);
@@ -54,12 +54,14 @@ struct _MateMixerDeviceInterface
};
GType mate_mixer_device_get_type (void) G_GNUC_CONST;
+
const gchar * mate_mixer_device_get_name (MateMixerDevice *device);
const gchar * mate_mixer_device_get_description (MateMixerDevice *device);
const gchar * mate_mixer_device_get_icon (MateMixerDevice *device);
-const GList * mate_mixer_device_list_streams (MateMixerDevice *device);
+
const GList * mate_mixer_device_list_ports (MateMixerDevice *device);
const GList * mate_mixer_device_list_profiles (MateMixerDevice *device);
+
MateMixerProfile *mate_mixer_device_get_active_profile (MateMixerDevice *device);
gboolean mate_mixer_device_set_active_profile (MateMixerDevice *device,
const gchar *profile);
diff --git a/libmatemixer/matemixer-enum-types.c b/libmatemixer/matemixer-enum-types.c
index 43249a3..e353e0c 100644
--- a/libmatemixer/matemixer-enum-types.c
+++ b/libmatemixer/matemixer-enum-types.c
@@ -64,19 +64,20 @@ mate_mixer_backend_type_get_type (void)
}
GType
-mate_mixer_port_status_get_type (void)
+mate_mixer_port_flags_get_type (void)
{
static GType etype = 0;
if (etype == 0) {
- static const GEnumValue values[] = {
- { MATE_MIXER_PORT_UNKNOWN_STATUS, "MATE_MIXER_PORT_UNKNOWN_STATUS", "unknown-status" },
+ static const GFlagsValue values[] = {
+ { MATE_MIXER_PORT_NO_FLAGS, "MATE_MIXER_PORT_NO_FLAGS", "no-flags" },
{ MATE_MIXER_PORT_AVAILABLE, "MATE_MIXER_PORT_AVAILABLE", "available" },
- { MATE_MIXER_PORT_UNAVAILABLE, "MATE_MIXER_PORT_UNAVAILABLE", "unavailable" },
+ { MATE_MIXER_PORT_INPUT, "MATE_MIXER_PORT_INPUT", "input" },
+ { MATE_MIXER_PORT_OUTPUT, "MATE_MIXER_PORT_OUTPUT", "output" },
{ 0, NULL, NULL }
};
- etype = g_enum_register_static (
- g_intern_static_string ("MateMixerPortStatus"),
+ etype = g_flags_register_static (
+ g_intern_static_string ("MateMixerPortFlags"),
values);
}
return etype;
@@ -94,14 +95,16 @@ mate_mixer_stream_flags_get_type (void)
{ MATE_MIXER_STREAM_OUTPUT, "MATE_MIXER_STREAM_OUTPUT", "output" },
{ MATE_MIXER_STREAM_CLIENT, "MATE_MIXER_STREAM_CLIENT", "client" },
{ MATE_MIXER_STREAM_APPLICATION, "MATE_MIXER_STREAM_APPLICATION", "application" },
- { MATE_MIXER_STREAM_OUTPUT_MONITOR, "MATE_MIXER_STREAM_OUTPUT_MONITOR", "output-monitor" },
+ { MATE_MIXER_STREAM_EVENT, "MATE_MIXER_STREAM_EVENT", "event" },
{ MATE_MIXER_STREAM_HAS_MUTE, "MATE_MIXER_STREAM_HAS_MUTE", "has-mute" },
{ MATE_MIXER_STREAM_HAS_VOLUME, "MATE_MIXER_STREAM_HAS_VOLUME", "has-volume" },
{ MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME, "MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME", "has-decibel-volume" },
{ MATE_MIXER_STREAM_HAS_FLAT_VOLUME, "MATE_MIXER_STREAM_HAS_FLAT_VOLUME", "has-flat-volume" },
+ { MATE_MIXER_STREAM_HAS_MONITOR, "MATE_MIXER_STREAM_HAS_MONITOR", "has-monitor" },
{ MATE_MIXER_STREAM_CAN_BALANCE, "MATE_MIXER_STREAM_CAN_BALANCE", "can-balance" },
{ MATE_MIXER_STREAM_CAN_FADE, "MATE_MIXER_STREAM_CAN_FADE", "can-fade" },
{ MATE_MIXER_STREAM_CAN_SET_VOLUME, "MATE_MIXER_STREAM_CAN_SET_VOLUME", "can-set-volume" },
+ { MATE_MIXER_STREAM_CAN_SUSPEND, "MATE_MIXER_STREAM_CAN_SUSPEND", "can-suspend" },
{ 0, NULL, NULL }
};
etype = g_flags_register_static (
@@ -112,20 +115,20 @@ mate_mixer_stream_flags_get_type (void)
}
GType
-mate_mixer_stream_status_get_type (void)
+mate_mixer_stream_state_get_type (void)
{
static GType etype = 0;
if (etype == 0) {
static const GEnumValue values[] = {
- { MATE_MIXER_STREAM_UNKNOWN_STATUS, "MATE_MIXER_STREAM_UNKNOWN_STATUS", "unknown-status" },
+ { MATE_MIXER_STREAM_UNKNOWN_STATE, "MATE_MIXER_STREAM_UNKNOWN_STATE", "unknown-state" },
{ MATE_MIXER_STREAM_RUNNING, "MATE_MIXER_STREAM_RUNNING", "running" },
{ MATE_MIXER_STREAM_IDLE, "MATE_MIXER_STREAM_IDLE", "idle" },
{ MATE_MIXER_STREAM_SUSPENDED, "MATE_MIXER_STREAM_SUSPENDED", "suspended" },
{ 0, NULL, NULL }
};
etype = g_enum_register_static (
- g_intern_static_string ("MateMixerStreamStatus"),
+ g_intern_static_string ("MateMixerStreamState"),
values);
}
return etype;
diff --git a/libmatemixer/matemixer-enum-types.h b/libmatemixer/matemixer-enum-types.h
index 0275c27..7b6fcf0 100644
--- a/libmatemixer/matemixer-enum-types.h
+++ b/libmatemixer/matemixer-enum-types.h
@@ -34,14 +34,14 @@ GType mate_mixer_state_get_type (void) G_GNUC_CONST;
#define MATE_MIXER_TYPE_BACKEND_TYPE (mate_mixer_backend_type_get_type ())
GType mate_mixer_backend_type_get_type (void) G_GNUC_CONST;
-#define MATE_MIXER_TYPE_PORT_STATUS (mate_mixer_port_status_get_type ())
-GType mate_mixer_port_status_get_type (void) G_GNUC_CONST;
+#define MATE_MIXER_TYPE_PORT_FLAGS (mate_mixer_port_flags_get_type ())
+GType mate_mixer_port_flags_get_type (void) G_GNUC_CONST;
#define MATE_MIXER_TYPE_STREAM_FLAGS (mate_mixer_stream_flags_get_type ())
GType mate_mixer_stream_flags_get_type (void) G_GNUC_CONST;
-#define MATE_MIXER_TYPE_STREAM_STATUS (mate_mixer_stream_status_get_type ())
-GType mate_mixer_stream_status_get_type (void) G_GNUC_CONST;
+#define MATE_MIXER_TYPE_STREAM_STATE (mate_mixer_stream_state_get_type ())
+GType mate_mixer_stream_state_get_type (void) G_GNUC_CONST;
#define MATE_MIXER_TYPE_CHANNEL_POSITION (mate_mixer_channel_position_get_type ())
GType mate_mixer_channel_position_get_type (void) G_GNUC_CONST;
diff --git a/libmatemixer/matemixer-enums.h b/libmatemixer/matemixer-enums.h
index 5fc348d..4552141 100644
--- a/libmatemixer/matemixer-enums.h
+++ b/libmatemixer/matemixer-enums.h
@@ -31,17 +31,32 @@ typedef enum {
MATE_MIXER_STATE_UNKNOWN
} MateMixerState;
+/**
+ * MateMixerBackendType:
+ * @MATE_MIXER_BACKEND_UNKNOWN:
+ * Unknown or undefined backend type.
+ * @MATE_MIXER_BACKEND_PULSE:
+ * PulseAudio sound system backend. It has the highest priority and
+ * will be the first one to try unless you select a specific backend
+ * to connect to.
+ * @MATE_MIXER_BACKEND_NULL:
+ * Fallback backend which never fails to initialize, but provides no
+ * functionality. This backend has the lowest priority and will be used
+ * if you do not select a specific backend to connect to and all the
+ * "real" backends fail to initialize.
+ */
typedef enum {
MATE_MIXER_BACKEND_UNKNOWN = 0,
MATE_MIXER_BACKEND_PULSE,
MATE_MIXER_BACKEND_NULL
} MateMixerBackendType;
-typedef enum {
- MATE_MIXER_PORT_UNKNOWN_STATUS,
- MATE_MIXER_PORT_AVAILABLE,
- MATE_MIXER_PORT_UNAVAILABLE
-} MateMixerPortStatus;
+typedef enum { /*< flags >*/
+ MATE_MIXER_PORT_NO_FLAGS = 0,
+ MATE_MIXER_PORT_AVAILABLE = 1 << 0,
+ MATE_MIXER_PORT_INPUT = 1 << 1,
+ MATE_MIXER_PORT_OUTPUT = 1 << 2
+} MateMixerPortFlags;
typedef enum { /*< flags >*/
MATE_MIXER_STREAM_NO_FLAGS = 0,
@@ -49,22 +64,24 @@ typedef enum { /*< flags >*/
MATE_MIXER_STREAM_OUTPUT = 1 << 1,
MATE_MIXER_STREAM_CLIENT = 1 << 2,
MATE_MIXER_STREAM_APPLICATION = 1 << 3,
- MATE_MIXER_STREAM_OUTPUT_MONITOR = 1 << 4,
+ MATE_MIXER_STREAM_EVENT = 1 << 4,
MATE_MIXER_STREAM_HAS_MUTE = 1 << 5,
MATE_MIXER_STREAM_HAS_VOLUME = 1 << 6,
MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME = 1 << 7,
MATE_MIXER_STREAM_HAS_FLAT_VOLUME = 1 << 8,
- MATE_MIXER_STREAM_CAN_BALANCE = 1 << 9,
- MATE_MIXER_STREAM_CAN_FADE = 1 << 10,
- MATE_MIXER_STREAM_CAN_SET_VOLUME = 1 << 11
+ MATE_MIXER_STREAM_HAS_MONITOR = 1 << 9,
+ MATE_MIXER_STREAM_CAN_BALANCE = 1 << 10,
+ MATE_MIXER_STREAM_CAN_FADE = 1 << 11,
+ MATE_MIXER_STREAM_CAN_SET_VOLUME = 1 << 12,
+ MATE_MIXER_STREAM_CAN_SUSPEND = 1 << 13
} MateMixerStreamFlags;
typedef enum {
- MATE_MIXER_STREAM_UNKNOWN_STATUS,
+ MATE_MIXER_STREAM_UNKNOWN_STATE,
MATE_MIXER_STREAM_RUNNING,
MATE_MIXER_STREAM_IDLE,
MATE_MIXER_STREAM_SUSPENDED
-} MateMixerStreamStatus;
+} MateMixerStreamState;
typedef enum {
MATE_MIXER_CHANNEL_UNKNOWN_POSITION,
diff --git a/libmatemixer/matemixer-port.c b/libmatemixer/matemixer-port.c
index 7ac21f7..3a7670d 100644
--- a/libmatemixer/matemixer-port.c
+++ b/libmatemixer/matemixer-port.c
@@ -22,13 +22,18 @@
#include "matemixer-enum-types.h"
#include "matemixer-port.h"
+/**
+ * SECTION:matemixer-port
+ * @include: libmatemixer/matemixer.h
+ */
+
struct _MateMixerPortPrivate
{
- gchar *name;
- gchar *description;
- gchar *icon;
- gulong priority;
- MateMixerPortStatus status;
+ gchar *name;
+ gchar *description;
+ gchar *icon;
+ gulong priority;
+ MateMixerPortFlags flags;
};
enum {
@@ -37,19 +42,92 @@ enum {
PROP_DESCRIPTION,
PROP_ICON,
PROP_PRIORITY,
- PROP_STATUS,
+ PROP_FLAGS,
N_PROPERTIES
};
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
static void mate_mixer_port_class_init (MateMixerPortClass *klass);
-static void mate_mixer_port_init (MateMixerPort *port);
-static void mate_mixer_port_finalize (GObject *object);
+
+static void mate_mixer_port_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void mate_mixer_port_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void mate_mixer_port_init (MateMixerPort *port);
+static void mate_mixer_port_finalize (GObject *object);
G_DEFINE_TYPE (MateMixerPort, mate_mixer_port, G_TYPE_OBJECT);
static void
+mate_mixer_port_class_init (MateMixerPortClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = mate_mixer_port_finalize;
+ object_class->get_property = mate_mixer_port_get_property;
+ object_class->set_property = mate_mixer_port_set_property;
+
+ properties[PROP_NAME] =
+ g_param_spec_string ("name",
+ "Name",
+ "Name of the port",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DESCRIPTION] =
+ g_param_spec_string ("description",
+ "Description",
+ "Description of the port",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ICON] =
+ g_param_spec_string ("icon",
+ "Icon",
+ "Name of the port icon",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_PRIORITY] =
+ g_param_spec_ulong ("priority",
+ "Priority",
+ "Priority of the port",
+ 0,
+ G_MAXULONG,
+ 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_FLAGS] =
+ g_param_spec_flags ("flags",
+ "Flags",
+ "Capability flags of the port",
+ MATE_MIXER_TYPE_PORT_FLAGS,
+ MATE_MIXER_PORT_NO_FLAGS,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (object_class, sizeof (MateMixerPortPrivate));
+}
+
+static void
mate_mixer_port_get_property (GObject *object,
guint param_id,
GValue *value,
@@ -72,8 +150,8 @@ mate_mixer_port_get_property (GObject *object,
case PROP_PRIORITY:
g_value_set_ulong (value, port->priv->priority);
break;
- case PROP_STATUS:
- g_value_set_enum (value, port->priv->status);
+ case PROP_FLAGS:
+ g_value_set_flags (value, port->priv->flags);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -93,19 +171,22 @@ mate_mixer_port_set_property (GObject *object,
switch (param_id) {
case PROP_NAME:
+ /* Construct-only string */
port->priv->name = g_strdup (g_value_get_string (value));
break;
case PROP_DESCRIPTION:
+ /* Construct-only string */
port->priv->description = g_strdup (g_value_get_string (value));
break;
case PROP_ICON:
+ /* Construct-only string */
port->priv->icon = g_strdup (g_value_get_string (value));
break;
case PROP_PRIORITY:
port->priv->priority = g_value_get_ulong (value);
break;
- case PROP_STATUS:
- port->priv->status = g_value_get_enum (value);
+ case PROP_FLAGS:
+ port->priv->flags = g_value_get_flags (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -114,64 +195,6 @@ mate_mixer_port_set_property (GObject *object,
}
static void
-mate_mixer_port_class_init (MateMixerPortClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = mate_mixer_port_finalize;
- object_class->get_property = mate_mixer_port_get_property;
- object_class->set_property = mate_mixer_port_set_property;
-
- properties[PROP_NAME] = g_param_spec_string ("name",
- "Name",
- "Name of the port",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_DESCRIPTION] = g_param_spec_string ("description",
- "Description",
- "Description of the port",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_ICON] = g_param_spec_string ("icon",
- "Icon",
- "Name of the port icon",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_PRIORITY] = g_param_spec_ulong ("priority",
- "Priority",
- "Priority of the port",
- 0,
- G_MAXULONG,
- 0,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_STATUS] = g_param_spec_enum ("status",
- "Status",
- "Status for the port",
- MATE_MIXER_TYPE_PORT_STATUS,
- MATE_MIXER_PORT_UNKNOWN_STATUS,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties (object_class, N_PROPERTIES, properties);
-
- g_type_class_add_private (object_class, sizeof (MateMixerPortPrivate));
-}
-
-static void
mate_mixer_port_init (MateMixerPort *port)
{
port->priv = G_TYPE_INSTANCE_GET_PRIVATE (port,
@@ -194,18 +217,18 @@ mate_mixer_port_finalize (GObject *object)
}
MateMixerPort *
-mate_mixer_port_new (const gchar *name,
- const gchar *description,
- const gchar *icon,
- gulong priority,
- MateMixerPortStatus status)
+mate_mixer_port_new (const gchar *name,
+ const gchar *description,
+ const gchar *icon,
+ gulong priority,
+ MateMixerPortFlags flags)
{
return g_object_new (MATE_MIXER_TYPE_PORT,
"name", name,
"description", description,
"icon", icon,
"priority", priority,
- "status", status,
+ "flags", flags,
NULL);
}
@@ -241,10 +264,10 @@ mate_mixer_port_get_priority (MateMixerPort *port)
return port->priv->priority;
}
-MateMixerPortStatus
-mate_mixer_port_get_status (MateMixerPort *port)
+MateMixerPortFlags
+mate_mixer_port_get_flags (MateMixerPort *port)
{
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), MATE_MIXER_PORT_UNKNOWN_STATUS);
+ g_return_val_if_fail (MATE_MIXER_IS_PORT (port), MATE_MIXER_PORT_NO_FLAGS);
- return port->priv->status;
+ return port->priv->flags;
}
diff --git a/libmatemixer/matemixer-port.h b/libmatemixer/matemixer-port.h
index e0a9f79..bda13ad 100644
--- a/libmatemixer/matemixer-port.h
+++ b/libmatemixer/matemixer-port.h
@@ -34,7 +34,7 @@ G_BEGIN_DECLS
#define MATE_MIXER_PORT_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_PORT, MateMixerPortClass))
#define MATE_MIXER_IS_PORT_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_PORT))
+ (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_PORT))
#define MATE_MIXER_PORT_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_PORT, MateMixerPortClass))
@@ -44,29 +44,30 @@ typedef struct _MateMixerPortPrivate MateMixerPortPrivate;
struct _MateMixerPort
{
+ GObject parent;
+
/*< private >*/
- GObject parent;
- MateMixerPortPrivate *priv;
+ MateMixerPortPrivate *priv;
};
struct _MateMixerPortClass
{
- /*< private >*/
- GObjectClass parent;
+ GObjectClass parent_class;
};
-GType mate_mixer_port_get_type (void) G_GNUC_CONST;
-MateMixerPort * mate_mixer_port_new (const gchar *name,
- const gchar *description,
- const gchar *icon,
- gulong priority,
- MateMixerPortStatus status);
+GType mate_mixer_port_get_type (void) G_GNUC_CONST;
+
+MateMixerPort * mate_mixer_port_new (const gchar *name,
+ const gchar *description,
+ const gchar *icon,
+ gulong priority,
+ MateMixerPortFlags flags);
-const gchar * mate_mixer_port_get_name (MateMixerPort *port);
-const gchar * mate_mixer_port_get_description (MateMixerPort *port);
-const gchar * mate_mixer_port_get_icon (MateMixerPort *port);
-gulong mate_mixer_port_get_priority (MateMixerPort *port);
-MateMixerPortStatus mate_mixer_port_get_status (MateMixerPort *port);
+const gchar * mate_mixer_port_get_name (MateMixerPort *port);
+const gchar * mate_mixer_port_get_description (MateMixerPort *port);
+const gchar * mate_mixer_port_get_icon (MateMixerPort *port);
+gulong mate_mixer_port_get_priority (MateMixerPort *port);
+MateMixerPortFlags mate_mixer_port_get_flags (MateMixerPort *port);
G_END_DECLS
diff --git a/libmatemixer/matemixer-profile.c b/libmatemixer/matemixer-profile.c
index 38f17c7..c98af30 100644
--- a/libmatemixer/matemixer-profile.c
+++ b/libmatemixer/matemixer-profile.c
@@ -20,15 +20,19 @@
#include "matemixer-profile.h"
+/**
+ * SECTION:matemixer-profile
+ * @include: libmatemixer/matemixer.h
+ */
+
struct _MateMixerProfilePrivate
{
- gchar *name;
- gchar *description;
- gulong priority;
+ gchar *name;
+ gchar *description;
+ gulong priority;
};
-enum
-{
+enum {
PROP_0,
PROP_NAME,
PROP_DESCRIPTION,
@@ -39,12 +43,66 @@ enum
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
static void mate_mixer_profile_class_init (MateMixerProfileClass *klass);
-static void mate_mixer_profile_init (MateMixerProfile *profile);
-static void mate_mixer_profile_finalize (GObject *object);
+
+static void mate_mixer_profile_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void mate_mixer_profile_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void mate_mixer_profile_init (MateMixerProfile *profile);
+static void mate_mixer_profile_finalize (GObject *object);
G_DEFINE_TYPE (MateMixerProfile, mate_mixer_profile, G_TYPE_OBJECT);
static void
+mate_mixer_profile_class_init (MateMixerProfileClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = mate_mixer_profile_finalize;
+ object_class->get_property = mate_mixer_profile_get_property;
+ object_class->set_property = mate_mixer_profile_set_property;
+
+ properties[PROP_NAME] =
+ g_param_spec_string ("name",
+ "Name",
+ "Name of the profile",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DESCRIPTION] =
+ g_param_spec_string ("description",
+ "Description",
+ "Description of the profile",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_PRIORITY] =
+ g_param_spec_ulong ("priority",
+ "Priority",
+ "Priority of the profile",
+ 0,
+ G_MAXULONG,
+ 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ g_type_class_add_private (object_class, sizeof (MateMixerProfilePrivate));
+}
+
+static void
mate_mixer_profile_get_property (GObject *object,
guint param_id,
GValue *value,
@@ -82,9 +140,11 @@ mate_mixer_profile_set_property (GObject *object,
switch (param_id) {
case PROP_NAME:
+ /* Construct-only string */
profile->priv->name = g_strdup (g_value_get_string (value));
break;
case PROP_DESCRIPTION:
+ /* Construct-only string */
profile->priv->description = g_strdup (g_value_get_string (value));
break;
case PROP_PRIORITY:
@@ -97,47 +157,6 @@ mate_mixer_profile_set_property (GObject *object,
}
static void
-mate_mixer_profile_class_init (MateMixerProfileClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = mate_mixer_profile_finalize;
- object_class->get_property = mate_mixer_profile_get_property;
- object_class->set_property = mate_mixer_profile_set_property;
-
- properties[PROP_NAME] = g_param_spec_string ("name",
- "Name",
- "Name of the profile",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_DESCRIPTION] = g_param_spec_string ("description",
- "Description",
- "Description of the profile",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_PRIORITY] = g_param_spec_ulong ("priority",
- "Priority",
- "Priority of the profile",
- 0,
- G_MAXULONG,
- 0,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties (object_class, N_PROPERTIES, properties);
-
- g_type_class_add_private (object_class, sizeof (MateMixerProfilePrivate));
-}
-
-static void
mate_mixer_profile_init (MateMixerProfile *profile)
{
profile->priv = G_TYPE_INSTANCE_GET_PRIVATE (profile,
diff --git a/libmatemixer/matemixer-profile.h b/libmatemixer/matemixer-profile.h
index 4ce0d1a..b652085 100644
--- a/libmatemixer/matemixer-profile.h
+++ b/libmatemixer/matemixer-profile.h
@@ -32,7 +32,7 @@ G_BEGIN_DECLS
#define MATE_MIXER_PROFILE_CLASS(k) \
(G_TYPE_CHECK_CLASS_CAST ((k), MATE_MIXER_TYPE_PROFILE, MateMixerProfileClass))
#define MATE_MIXER_IS_PROFILE_CLASS(k) \
- (G_TYPE_CLASS_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_PROFILE))
+ (G_TYPE_CHECK_CLASS_TYPE ((k), MATE_MIXER_TYPE_PROFILE))
#define MATE_MIXER_PROFILE_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), MATE_MIXER_TYPE_PROFILE, MateMixerProfileClass))
@@ -42,18 +42,19 @@ typedef struct _MateMixerProfilePrivate MateMixerProfilePrivate;
struct _MateMixerProfile
{
+ GObject parent;
+
/*< private >*/
- GObject parent;
- MateMixerProfilePrivate *priv;
+ MateMixerProfilePrivate *priv;
};
struct _MateMixerProfileClass
{
- /*< private >*/
- GObjectClass parent;
+ GObjectClass parent_class;
};
GType mate_mixer_profile_get_type (void) G_GNUC_CONST;
+
MateMixerProfile *mate_mixer_profile_new (const gchar *name,
const gchar *description,
gulong priority);
diff --git a/libmatemixer/matemixer-stream.c b/libmatemixer/matemixer-stream.c
index e2c9820..1ad4c50 100644
--- a/libmatemixer/matemixer-stream.c
+++ b/libmatemixer/matemixer-stream.c
@@ -24,6 +24,18 @@
#include "matemixer-port.h"
#include "matemixer-stream.h"
+/**
+ * SECTION:matemixer-stream
+ * @include: libmatemixer/matemixer.h
+ */
+
+enum {
+ MONITOR_VALUE,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0, };
+
G_DEFINE_INTERFACE (MateMixerStream, mate_mixer_stream, G_TYPE_OBJECT)
static void
@@ -34,8 +46,7 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
"Name",
"Name of the stream",
NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
+ G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
@@ -43,17 +54,7 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
"Description",
"Description of the stream",
NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
- g_param_spec_string ("icon",
- "Icon",
- "Name of the stream icon",
- NULL,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
+ G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
@@ -61,8 +62,7 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
"Device",
"Device the stream belongs to",
MATE_MIXER_TYPE_DEVICE,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
+ G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
@@ -71,18 +71,16 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
"Capability flags of the stream",
MATE_MIXER_TYPE_STREAM_FLAGS,
MATE_MIXER_STREAM_NO_FLAGS,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
+ G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
- g_param_spec_enum ("status",
- "Status",
- "Status of the stream",
- MATE_MIXER_TYPE_STREAM_STATUS,
- MATE_MIXER_STREAM_UNKNOWN_STATUS,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
+ g_param_spec_enum ("state",
+ "State",
+ "Current state of the stream",
+ MATE_MIXER_TYPE_STREAM_STATE,
+ MATE_MIXER_STREAM_UNKNOWN_STATE,
+ G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
@@ -90,8 +88,7 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
"Mute",
"Mute state of the stream",
FALSE,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
+ G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
@@ -115,16 +112,6 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
- g_param_spec_double ("volume-db",
- "Volume dB",
- "Volume of the stream in decibels",
- -G_MAXDOUBLE,
- G_MAXDOUBLE,
- 0.0,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
g_param_spec_double ("balance",
"Balance",
"Balance value of the stream",
@@ -145,28 +132,37 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
+ g_param_spec_pointer ("ports",
+ "Ports",
+ "GList of the sound device ports",
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
g_param_spec_object ("active-port",
"Active port",
"The currently active port of the stream",
MATE_MIXER_TYPE_PORT,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
+ G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
+
+ signals[MONITOR_VALUE] =
+ g_signal_new ("monitor-value",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (MateMixerStreamInterface, monitor_value),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__DOUBLE,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_DOUBLE);
}
const gchar *
mate_mixer_stream_get_name (MateMixerStream *stream)
{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_name)
- return iface->get_name (stream);
-
- return NULL;
+ return MATE_MIXER_STREAM_GET_INTERFACE (stream)->get_name (stream);
}
const gchar *
@@ -184,8 +180,8 @@ mate_mixer_stream_get_description (MateMixerStream *stream)
return NULL;
}
-const gchar *
-mate_mixer_stream_get_icon (MateMixerStream *stream)
+MateMixerDevice *
+mate_mixer_stream_get_device (MateMixerStream *stream)
{
MateMixerStreamInterface *iface;
@@ -193,40 +189,40 @@ mate_mixer_stream_get_icon (MateMixerStream *stream)
iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
- if (iface->get_icon)
- return iface->get_icon (stream);
+ if (iface->get_device)
+ return iface->get_device (stream);
return NULL;
}
-MateMixerDevice *
-mate_mixer_stream_get_device (MateMixerStream *stream)
+MateMixerStreamFlags
+mate_mixer_stream_get_flags (MateMixerStream *stream)
{
MateMixerStreamInterface *iface;
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_NO_FLAGS);
iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
- if (iface->get_device)
- return iface->get_device (stream);
+ if (iface->get_flags)
+ return iface->get_flags (stream);
- return NULL;
+ return MATE_MIXER_STREAM_NO_FLAGS;
}
-MateMixerStreamStatus
-mate_mixer_stream_get_status (MateMixerStream *stream)
+MateMixerStreamState
+mate_mixer_stream_get_state (MateMixerStream *stream)
{
MateMixerStreamInterface *iface;
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_UNKNOWN_STATUS);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_UNKNOWN_STATE);
iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
- if (iface->get_status)
- return iface->get_status (stream);
+ if (iface->get_state)
+ return iface->get_state (stream);
- return MATE_MIXER_STREAM_UNKNOWN_STATUS;
+ return MATE_MIXER_STREAM_UNKNOWN_STATE;
}
gboolean
@@ -585,6 +581,49 @@ mate_mixer_stream_resume (MateMixerStream *stream)
return FALSE;
}
+gboolean
+mate_mixer_stream_monitor_start (MateMixerStream *stream)
+{
+ MateMixerStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
+
+ iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+
+ if (iface->monitor_start)
+ return iface->monitor_start (stream);
+
+ return FALSE;
+}
+
+void
+mate_mixer_stream_monitor_stop (MateMixerStream *stream)
+{
+ MateMixerStreamInterface *iface;
+
+ g_return_if_fail (MATE_MIXER_IS_STREAM (stream));
+
+ iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+
+ if (iface->monitor_stop)
+ iface->monitor_stop (stream);
+}
+
+gboolean
+mate_mixer_stream_monitor_is_running (MateMixerStream *stream)
+{
+ MateMixerStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
+
+ iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
+
+ if (iface->monitor_is_running)
+ return iface->monitor_is_running (stream);
+
+ return FALSE;
+}
+
const GList *
mate_mixer_stream_list_ports (MateMixerStream *stream)
{
@@ -616,17 +655,17 @@ mate_mixer_stream_get_active_port (MateMixerStream *stream)
}
gboolean
-mate_mixer_stream_set_active_port (MateMixerStream *stream, const gchar *port_name)
+mate_mixer_stream_set_active_port (MateMixerStream *stream, const gchar *port)
{
MateMixerStreamInterface *iface;
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
- g_return_val_if_fail (port_name != NULL, FALSE);
+ g_return_val_if_fail (port != NULL, FALSE);
iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
if (iface->set_active_port)
- return iface->set_active_port (stream, port_name);
+ return iface->set_active_port (stream, port);
return FALSE;
}
diff --git a/libmatemixer/matemixer-stream.h b/libmatemixer/matemixer-stream.h
index d773398..d39cc43 100644
--- a/libmatemixer/matemixer-stream.h
+++ b/libmatemixer/matemixer-stream.h
@@ -41,15 +41,14 @@ typedef struct _MateMixerStreamInterface MateMixerStreamInterface;
struct _MateMixerStreamInterface
{
- /*< private >*/
- GTypeInterface parent;
+ GTypeInterface parent_iface;
+ /*< private >*/
const gchar * (*get_name) (MateMixerStream *stream);
const gchar * (*get_description) (MateMixerStream *stream);
- const gchar * (*get_icon) (MateMixerStream *stream);
MateMixerDevice * (*get_device) (MateMixerStream *stream);
MateMixerStreamFlags (*get_flags) (MateMixerStream *stream);
- MateMixerStreamStatus (*get_status) (MateMixerStream *stream);
+ MateMixerStreamState (*get_state) (MateMixerStream *stream);
gboolean (*get_mute) (MateMixerStream *stream);
gboolean (*set_mute) (MateMixerStream *stream,
gboolean mute);
@@ -83,7 +82,7 @@ struct _MateMixerStreamInterface
MateMixerChannelPosition position);
gboolean (*set_position_volume_db) (MateMixerStream *stream,
MateMixerChannelPosition position,
- gdouble volume);
+ gdouble volume_db);
gdouble (*get_balance) (MateMixerStream *stream);
gboolean (*set_balance) (MateMixerStream *stream,
gdouble balance);
@@ -92,23 +91,29 @@ struct _MateMixerStreamInterface
gdouble fade);
gboolean (*suspend) (MateMixerStream *stream);
gboolean (*resume) (MateMixerStream *stream);
+ gboolean (*monitor_start) (MateMixerStream *stream);
+ void (*monitor_stop) (MateMixerStream *stream);
+ gboolean (*monitor_is_running) (MateMixerStream *stream);
const GList * (*list_ports) (MateMixerStream *stream);
MateMixerPort * (*get_active_port) (MateMixerStream *stream);
gboolean (*set_active_port) (MateMixerStream *stream,
- const gchar *port_name);
+ const gchar *port);
gint64 (*get_min_volume) (MateMixerStream *stream);
gint64 (*get_max_volume) (MateMixerStream *stream);
gint64 (*get_normal_volume) (MateMixerStream *stream);
+
+ /* Signals */
+ void (*monitor_value) (MateMixerStream *stream,
+ gdouble value);
};
GType mate_mixer_stream_get_type (void) G_GNUC_CONST;
const gchar * mate_mixer_stream_get_name (MateMixerStream *stream);
const gchar * mate_mixer_stream_get_description (MateMixerStream *stream);
-const gchar * mate_mixer_stream_get_icon (MateMixerStream *stream);
MateMixerDevice * mate_mixer_stream_get_device (MateMixerStream *stream);
MateMixerStreamFlags mate_mixer_stream_get_flags (MateMixerStream *stream);
-MateMixerStreamStatus mate_mixer_stream_get_status (MateMixerStream *stream);
+MateMixerStreamState mate_mixer_stream_get_state (MateMixerStream *stream);
gboolean mate_mixer_stream_get_mute (MateMixerStream *stream);
gboolean mate_mixer_stream_set_mute (MateMixerStream *stream,
@@ -165,6 +170,11 @@ gboolean mate_mixer_stream_set_fade (MateMixerStre
gboolean mate_mixer_stream_suspend (MateMixerStream *stream);
gboolean mate_mixer_stream_resume (MateMixerStream *stream);
+gboolean mate_mixer_stream_monitor_start (MateMixerStream *stream);
+void mate_mixer_stream_monitor_stop (MateMixerStream *stream);
+
+gboolean mate_mixer_stream_monitor_is_running (MateMixerStream *stream);
+
const GList * mate_mixer_stream_list_ports (MateMixerStream *stream);
MateMixerPort * mate_mixer_stream_get_active_port (MateMixerStream *stream);
diff --git a/libmatemixer/matemixer-version.h.in b/libmatemixer/matemixer-version.h
index 17ea7b4..ff32f1a 100644
--- a/libmatemixer/matemixer-version.h.in
+++ b/libmatemixer/matemixer-version.h
@@ -18,33 +18,7 @@
#ifndef MATEMIXER_VERSION_H
#define MATEMIXER_VERSION_H
-/**
- * LIBMATEMIXER_MAJOR_VERSION:
- *
- * Libmatemixer major version component (e.g. 1 if %LIBMATEMIXER_VERSION is 1.2.3).
- */
-#define LIBMATEMIXER_MAJOR_VERSION (@LIBMATEMIXER_MAJOR_VERSION@)
-
-/**
- * LIBMATEMIXER_MINOR_VERSION:
- *
- * Libmatemixer minor version component (e.g. 2 if %LIBMATEMIXER_VERSION is 1.2.3).
- */
-#define LIBMATEMIXER_MINOR_VERSION (@LIBMATEMIXER_MINOR_VERSION@)
-
-/**
- * LIBMATEMIXER_MICRO_VERSION:
- *
- * Libmatemixer micro version component (e.g. 3 if %LIBMATEMIXER_VERSION is 1.2.3).
- */
-#define LIBMATEMIXER_MICRO_VERSION (@LIBMATEMIXER_MICRO_VERSION@)
-
-/**
- * LIBMATEMIXER_VERSION:
- *
- * Libmatemixer version.
- */
-#define LIBMATEMIXER_VERSION (@LIBMATEMIXER_VERSION@)
+G_BEGIN_DECLS
/**
* LIBMATEMIXER_CHECK_VERSION:
@@ -61,4 +35,6 @@
(LIBMATEMIXER_MAJOR_VERSION == (major) && LIBMATEMIXER_MINOR_VERSION == (minor) && \
LIBMATEMIXER_MICRO_VERSION >= (micro)))
-#endif /* LIBMATEMIXER_VERSION_H */
+G_END_DECLS
+
+#endif /* MATEMIXER_VERSION_H */
diff --git a/libmatemixer/matemixer.c b/libmatemixer/matemixer.c
index 1e5d4e0..602d5d2 100644
--- a/libmatemixer/matemixer.c
+++ b/libmatemixer/matemixer.c
@@ -37,8 +37,8 @@ static gboolean mixer_initialized = FALSE;
* Initializes the library. You must call this function before using any other
* function from the library.
*
- * Returns: %TRUE on success, or %FALSE if the library installation is broken and
- * does not provide support for any sound systems.
+ * Returns: %TRUE on success or %FALSE if the library installation does not
+ * provide support for any sound system backends.
*/
gboolean
mate_mixer_init (void)
@@ -52,7 +52,7 @@ mate_mixer_init (void)
list = mixer_modules;
while (list) {
GTypeModule *module = G_TYPE_MODULE (list->data);
- GList *next = list->next;
+ GList *next = list->next;
/* Attempt to load the module and remove it from the list
* if it isn't usable */
diff --git a/libmatemixer/matemixer.h b/libmatemixer/matemixer.h
index 99df233..a36c89c 100644
--- a/libmatemixer/matemixer.h
+++ b/libmatemixer/matemixer.h
@@ -19,10 +19,16 @@
#define MATEMIXER_H
#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-client-stream.h>
#include <libmatemixer/matemixer-control.h>
#include <libmatemixer/matemixer-device.h>
#include <libmatemixer/matemixer-enums.h>
+#include <libmatemixer/matemixer-port.h>
+#include <libmatemixer/matemixer-profile.h>
#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer-version.h>
G_BEGIN_DECLS