summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Ratajsky <[email protected]>2014-07-18 15:41:59 +0200
committerMichal Ratajsky <[email protected]>2014-07-18 15:41:59 +0200
commit56c76128b0144a5c61e77d2a7aec07a337cfb66d (patch)
treef67ce44025881578cf6de3332064c214da176a23
parent85070f3b97a3213d75a7bebf86ad973aaa21c55b (diff)
downloadlibmatemixer-56c76128b0144a5c61e77d2a7aec07a337cfb66d.tar.bz2
libmatemixer-56c76128b0144a5c61e77d2a7aec07a337cfb66d.tar.xz
PulseAudio fixes and API updates
-rw-r--r--backends/null/null-backend.h8
-rw-r--r--backends/pulse/Makefile.am2
-rw-r--r--backends/pulse/pulse-backend.c1104
-rw-r--r--backends/pulse/pulse-backend.h2
-rw-r--r--backends/pulse/pulse-client-stream.c243
-rw-r--r--backends/pulse/pulse-client-stream.h41
-rw-r--r--backends/pulse/pulse-connection.c790
-rw-r--r--backends/pulse/pulse-connection.h241
-rw-r--r--backends/pulse/pulse-device.c376
-rw-r--r--backends/pulse/pulse-ext-stream.c301
-rw-r--r--backends/pulse/pulse-ext-stream.h71
-rw-r--r--backends/pulse/pulse-helpers.c88
-rw-r--r--backends/pulse/pulse-helpers.h6
-rw-r--r--backends/pulse/pulse-monitor.c303
-rw-r--r--backends/pulse/pulse-monitor.h11
-rw-r--r--backends/pulse/pulse-sink-input.c206
-rw-r--r--backends/pulse/pulse-sink-input.h2
-rw-r--r--backends/pulse/pulse-sink.c288
-rw-r--r--backends/pulse/pulse-sink.h4
-rw-r--r--backends/pulse/pulse-source-output.c196
-rw-r--r--backends/pulse/pulse-source-output.h2
-rw-r--r--backends/pulse/pulse-source.c225
-rw-r--r--backends/pulse/pulse-source.h2
-rw-r--r--backends/pulse/pulse-stream.c1285
-rw-r--r--backends/pulse/pulse-stream.h86
-rw-r--r--configure.ac2
-rw-r--r--docs/reference/Makefile.am2
-rw-r--r--docs/reference/libmatemixer-sections.txt16
-rw-r--r--docs/reference/libmatemixer.types6
-rw-r--r--examples/monitor.c182
-rw-r--r--libmatemixer/Makefile.am2
-rw-r--r--libmatemixer/matemixer-backend-module.c48
-rw-r--r--libmatemixer/matemixer-backend-module.h3
-rw-r--r--libmatemixer/matemixer-backend.c51
-rw-r--r--libmatemixer/matemixer-backend.h11
-rw-r--r--libmatemixer/matemixer-client-stream.c64
-rw-r--r--libmatemixer/matemixer-client-stream.h46
-rw-r--r--libmatemixer/matemixer-control.c517
-rw-r--r--libmatemixer/matemixer-control.h36
-rw-r--r--libmatemixer/matemixer-device-profile-private.h44
-rw-r--r--libmatemixer/matemixer-device-profile.c142
-rw-r--r--libmatemixer/matemixer-device-profile.h18
-rw-r--r--libmatemixer/matemixer-device.c99
-rw-r--r--libmatemixer/matemixer-device.h48
-rw-r--r--libmatemixer/matemixer-enum-types.c67
-rw-r--r--libmatemixer/matemixer-enum-types.h6
-rw-r--r--libmatemixer/matemixer-enums.h139
-rw-r--r--libmatemixer/matemixer-port-private.h45
-rw-r--r--libmatemixer/matemixer-port.c143
-rw-r--r--libmatemixer/matemixer-port.h16
-rw-r--r--libmatemixer/matemixer-stream.c103
-rw-r--r--libmatemixer/matemixer-stream.h129
-rw-r--r--libmatemixer/matemixer.c111
53 files changed, 5138 insertions, 2841 deletions
diff --git a/backends/null/null-backend.h b/backends/null/null-backend.h
index ae5f087..505dd80 100644
--- a/backends/null/null-backend.h
+++ b/backends/null/null-backend.h
@@ -15,13 +15,13 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef MATEMIXER_NULL_BACKEND_H
-#define MATEMIXER_NULL_BACKEND_H
+#ifndef NULL_BACKEND_H
+#define NULL_BACKEND_H
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-backend.h>
+#include <libmatemixer/matemixer-backend-module.h>
#define NULL_TYPE_BACKEND \
(null_backend_get_type ())
@@ -55,4 +55,4 @@ GType null_backend_get_type (void) G_GNUC_CONST;
void backend_module_init (GTypeModule *module);
const MateMixerBackendInfo *backend_module_get_info (void);
-#endif /* MATEMIXER_NULL_H */
+#endif /* NULL_BACKEND_H */
diff --git a/backends/pulse/Makefile.am b/backends/pulse/Makefile.am
index 3b632a5..0e5a4d6 100644
--- a/backends/pulse/Makefile.am
+++ b/backends/pulse/Makefile.am
@@ -22,6 +22,8 @@ libmatemixer_pulse_la_SOURCES = \
pulse-enums.h \
pulse-enum-types.c \
pulse-enum-types.h \
+ pulse-ext-stream.c \
+ pulse-ext-stream.h \
pulse-helpers.c \
pulse-helpers.h \
pulse-monitor.c \
diff --git a/backends/pulse/pulse-backend.c b/backends/pulse/pulse-backend.c
index da73396..0494545 100644
--- a/backends/pulse/pulse-backend.c
+++ b/backends/pulse/pulse-backend.c
@@ -24,11 +24,13 @@
#include <libmatemixer/matemixer-stream.h>
#include <pulse/pulseaudio.h>
+#include <pulse/ext-stream-restore.h>
#include "pulse-backend.h"
#include "pulse-connection.h"
#include "pulse-device.h"
#include "pulse-enums.h"
+#include "pulse-ext-stream.h"
#include "pulse-stream.h"
#include "pulse-sink.h"
#include "pulse-sink-input.h"
@@ -50,10 +52,8 @@ struct _PulseBackendPrivate
MateMixerStream *default_sink;
MateMixerStream *default_source;
GHashTable *devices;
- GHashTable *sinks;
- GHashTable *sink_inputs;
- GHashTable *sources;
- GHashTable *source_outputs;
+ GHashTable *streams;
+ GHashTable *ext_streams;
MateMixerState state;
PulseConnection *connection;
};
@@ -85,90 +85,102 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED (PulseBackend, pulse_backend,
G_IMPLEMENT_INTERFACE_DYNAMIC (MATE_MIXER_TYPE_BACKEND,
mate_mixer_backend_interface_init))
-static gboolean backend_open (MateMixerBackend *backend);
-static void backend_close (MateMixerBackend *backend);
-
-static MateMixerState backend_get_state (MateMixerBackend *backend);
-
-static void backend_set_data (MateMixerBackend *backend,
- const MateMixerBackendData *data);
-
-static GList * backend_list_devices (MateMixerBackend *backend);
-static GList * backend_list_streams (MateMixerBackend *backend);
-
-static MateMixerStream *backend_get_default_input_stream (MateMixerBackend *backend);
-static gboolean backend_set_default_input_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
-
-static MateMixerStream *backend_get_default_output_stream (MateMixerBackend *backend);
-static gboolean backend_set_default_output_stream (MateMixerBackend *backend,
- MateMixerStream *stream);
-
-static void backend_connection_state_cb (PulseConnection *connection,
- GParamSpec *pspec,
- PulseBackend *pulse);
-
-static void backend_server_info_cb (PulseConnection *connection,
- const pa_server_info *info,
- PulseBackend *pulse);
-
-static void backend_card_info_cb (PulseConnection *connection,
- const pa_card_info *info,
- PulseBackend *pulse);
-static void backend_card_removed_cb (PulseConnection *connection,
- guint index,
- PulseBackend *pulse);
-static void backend_sink_info_cb (PulseConnection *connection,
- const pa_sink_info *info,
- PulseBackend *pulse);
-static void backend_sink_removed_cb (PulseConnection *connection,
- guint index,
- PulseBackend *pulse);
-static void backend_sink_input_info_cb (PulseConnection *connection,
- const pa_sink_input_info *info,
- PulseBackend *pulse);
-static void backend_sink_input_removed_cb (PulseConnection *connection,
- guint index,
- PulseBackend *pulse);
-static void backend_source_info_cb (PulseConnection *connection,
- const pa_source_info *info,
- PulseBackend *pulse);
-static void backend_source_removed_cb (PulseConnection *connection,
- guint index,
- PulseBackend *pulse);
-static void backend_source_output_info_cb (PulseConnection *connection,
- const pa_source_output_info *info,
- PulseBackend *pulse);
-static void backend_source_output_removed_cb (PulseConnection *connection,
- guint index,
- PulseBackend *pulse);
-
-static gboolean backend_try_reconnect (PulseBackend *pulse);
-static void backend_remove_connect_source (PulseBackend *pulse);
-
-static void backend_mark_hanging (PulseBackend *pulse);
-static void backend_mark_hanging_hash (GHashTable *hash);
-
-static void backend_remove_hanging (PulseBackend *pulse);
-static void backend_remove_hanging_hash (PulseBackend *pulse,
- GHashTable *hash);
-
-static void backend_remove_device (PulseBackend *pulse,
- PulseDevice *device);
-static void backend_remove_stream (PulseBackend *pulse,
- GHashTable *hash,
- PulseStream *stream);
-
-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_names (gpointer key,
- gpointer value,
- gpointer user_data);
+static gboolean pulse_backend_open (MateMixerBackend *backend);
+static void pulse_backend_close (MateMixerBackend *backend);
+
+static MateMixerState pulse_backend_get_state (MateMixerBackend *backend);
+
+static void pulse_backend_set_data (MateMixerBackend *backend,
+ const MateMixerBackendData *data);
+
+static GList * pulse_backend_list_devices (MateMixerBackend *backend);
+static GList * pulse_backend_list_streams (MateMixerBackend *backend);
+static GList * pulse_backend_list_cached_streams (MateMixerBackend *backend);
+
+static MateMixerStream *pulse_backend_get_default_input_stream (MateMixerBackend *backend);
+static gboolean pulse_backend_set_default_input_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
+
+static MateMixerStream *pulse_backend_get_default_output_stream (MateMixerBackend *backend);
+static gboolean pulse_backend_set_default_output_stream (MateMixerBackend *backend,
+ MateMixerStream *stream);
+
+static void on_connection_state_notify (PulseConnection *connection,
+ GParamSpec *pspec,
+ PulseBackend *pulse);
+
+static void on_connection_server_info (PulseConnection *connection,
+ const pa_server_info *info,
+ PulseBackend *pulse);
+
+static void on_connection_card_info (PulseConnection *connection,
+ const pa_card_info *info,
+ PulseBackend *pulse);
+static void on_connection_card_removed (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse);
+static void on_connection_sink_info (PulseConnection *connection,
+ const pa_sink_info *info,
+ PulseBackend *pulse);
+static void on_connection_sink_removed (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse);
+static void on_connection_sink_input_info (PulseConnection *connection,
+ const pa_sink_input_info *info,
+ PulseBackend *pulse);
+static void on_connection_sink_input_removed (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse);
+static void on_connection_source_info (PulseConnection *connection,
+ const pa_source_info *info,
+ PulseBackend *pulse);
+static void on_connection_source_removed (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse);
+static void on_connection_source_output_info (PulseConnection *connection,
+ const pa_source_output_info *info,
+ PulseBackend *pulse);
+static void on_connection_source_output_removed (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse);
+static void on_connection_ext_stream_loading (PulseConnection *connection,
+ PulseBackend *pulse);
+static void on_connection_ext_stream_loaded (PulseConnection *connection,
+ PulseBackend *pulse);
+static void on_connection_ext_stream_info (PulseConnection *connection,
+ const pa_ext_stream_restore_info *info,
+ PulseBackend *pulse);
+
+static gboolean connect_source_reconnect (PulseBackend *pulse);
+static void connect_source_remove (PulseBackend *pulse);
+
+static void check_pending_sink (PulseBackend *pulse,
+ PulseStream *stream);
+static void check_pending_source (PulseBackend *pulse,
+ PulseStream *stream);
+
+static void mark_hanging (PulseBackend *pulse);
+static void mark_hanging_hash (GHashTable *hash);
+
+static void unmark_hanging (PulseBackend *pulse,
+ GObject *object);
+
+static void remove_hanging (PulseBackend *pulse);
+static void remove_device (PulseBackend *pulse,
+ PulseDevice *device);
+static void remove_stream (PulseBackend *pulse,
+ PulseStream *stream);
+
+static void change_state (PulseBackend *backend,
+ MateMixerState state);
+
+static gint compare_devices (gconstpointer a,
+ gconstpointer b);
+static gint compare_streams (gconstpointer a,
+ gconstpointer b);
+static gboolean compare_stream_names (gpointer key,
+ gpointer value,
+ gpointer user_data);
static MateMixerBackendInfo info;
@@ -192,16 +204,17 @@ backend_module_get_info (void)
static void
mate_mixer_backend_interface_init (MateMixerBackendInterface *iface)
{
- iface->open = backend_open;
- iface->close = backend_close;
- iface->get_state = backend_get_state;
- iface->set_data = backend_set_data;
- iface->list_devices = backend_list_devices;
- iface->list_streams = backend_list_streams;
- iface->get_default_input_stream = backend_get_default_input_stream;
- iface->set_default_input_stream = backend_set_default_input_stream;
- iface->get_default_output_stream = backend_get_default_output_stream;
- iface->set_default_output_stream = backend_set_default_output_stream;
+ iface->open = pulse_backend_open;
+ iface->close = pulse_backend_close;
+ iface->get_state = pulse_backend_get_state;
+ iface->set_data = pulse_backend_set_data;
+ iface->list_devices = pulse_backend_list_devices;
+ iface->list_streams = pulse_backend_list_streams;
+ iface->list_cached_streams = pulse_backend_list_cached_streams;
+ iface->get_default_input_stream = pulse_backend_get_default_input_stream;
+ iface->set_default_input_stream = pulse_backend_set_default_input_stream;
+ iface->get_default_output_stream = pulse_backend_get_default_output_stream;
+ iface->set_default_output_stream = pulse_backend_set_default_output_stream;
}
static void
@@ -260,40 +273,28 @@ pulse_backend_init (PulseBackend *pulse)
PULSE_TYPE_BACKEND,
PulseBackendPrivate);
- /* These hash tables store PulseDevice and PulseStream instances, the key
- * is the PulseAudio index which is not unique across different stream
- * types, hence the separate hash tables */
+ /* These hash tables store PulseDevice and PulseStream instances */
pulse->priv->devices =
g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL,
g_object_unref);
- pulse->priv->sinks =
- g_hash_table_new_full (g_direct_hash,
- g_direct_equal,
- NULL,
+ pulse->priv->streams =
+ g_hash_table_new_full (g_int64_hash,
+ g_int64_equal,
+ g_free,
g_object_unref);
- pulse->priv->sink_inputs =
- g_hash_table_new_full (g_direct_hash,
- g_direct_equal,
- NULL,
- g_object_unref);
- pulse->priv->sources =
- g_hash_table_new_full (g_direct_hash,
- g_direct_equal,
- NULL,
- g_object_unref);
- pulse->priv->source_outputs =
- g_hash_table_new_full (g_direct_hash,
- g_direct_equal,
- NULL,
+ pulse->priv->ext_streams =
+ g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
g_object_unref);
}
static void
pulse_backend_dispose (GObject *object)
{
- backend_close (MATE_MIXER_BACKEND (object));
+ pulse_backend_close (MATE_MIXER_BACKEND (object));
G_OBJECT_CLASS (pulse_backend_parent_class)->dispose (object);
}
@@ -312,16 +313,14 @@ pulse_backend_finalize (GObject *object)
g_free (pulse->priv->server_address);
g_hash_table_destroy (pulse->priv->devices);
- g_hash_table_destroy (pulse->priv->sinks);
- g_hash_table_destroy (pulse->priv->sink_inputs);
- g_hash_table_destroy (pulse->priv->sources);
- g_hash_table_destroy (pulse->priv->source_outputs);
+ g_hash_table_destroy (pulse->priv->streams);
+ g_hash_table_destroy (pulse->priv->ext_streams);
G_OBJECT_CLASS (pulse_backend_parent_class)->finalize (object);
}
static gboolean
-backend_open (MateMixerBackend *backend)
+pulse_backend_open (MateMixerBackend *backend)
{
PulseBackend *pulse;
PulseConnection *connection;
@@ -345,75 +344,87 @@ backend_open (MateMixerBackend *backend)
* but it sets up the PulseAudio structures, which might fail in an
* unlikely case */
if (G_UNLIKELY (connection == NULL)) {
- backend_change_state (pulse, MATE_MIXER_STATE_FAILED);
+ change_state (pulse, MATE_MIXER_STATE_FAILED);
return FALSE;
}
- g_signal_connect (connection,
+ g_signal_connect (G_OBJECT (connection),
"notify::state",
- G_CALLBACK (backend_connection_state_cb),
+ G_CALLBACK (on_connection_state_notify),
pulse);
- g_signal_connect (connection,
+ g_signal_connect (G_OBJECT (connection),
"server-info",
- G_CALLBACK (backend_server_info_cb),
+ G_CALLBACK (on_connection_server_info),
pulse);
- g_signal_connect (connection,
+ g_signal_connect (G_OBJECT (connection),
"card-info",
- G_CALLBACK (backend_card_info_cb),
+ G_CALLBACK (on_connection_card_info),
pulse);
- g_signal_connect (connection,
+ g_signal_connect (G_OBJECT (connection),
"card-removed",
- G_CALLBACK (backend_card_removed_cb),
+ G_CALLBACK (on_connection_card_removed),
pulse);
- g_signal_connect (connection,
+ g_signal_connect (G_OBJECT (connection),
"sink-info",
- G_CALLBACK (backend_sink_info_cb),
+ G_CALLBACK (on_connection_sink_info),
pulse);
- g_signal_connect (connection,
+ g_signal_connect (G_OBJECT (connection),
"sink-removed",
- G_CALLBACK (backend_sink_removed_cb),
+ G_CALLBACK (on_connection_sink_removed),
pulse);
- g_signal_connect (connection,
+ g_signal_connect (G_OBJECT (connection),
"sink-input-info",
- G_CALLBACK (backend_sink_input_info_cb),
+ G_CALLBACK (on_connection_sink_input_info),
pulse);
- g_signal_connect (connection,
+ g_signal_connect (G_OBJECT (connection),
"sink-input-removed",
- G_CALLBACK (backend_sink_input_removed_cb),
+ G_CALLBACK (on_connection_sink_input_removed),
pulse);
- g_signal_connect (connection,
+ g_signal_connect (G_OBJECT (connection),
"source-info",
- G_CALLBACK (backend_source_info_cb),
+ G_CALLBACK (on_connection_source_info),
pulse);
- g_signal_connect (connection,
+ g_signal_connect (G_OBJECT (connection),
"source-removed",
- G_CALLBACK (backend_source_removed_cb),
+ G_CALLBACK (on_connection_source_removed),
pulse);
- g_signal_connect (connection,
+ g_signal_connect (G_OBJECT (connection),
"source-output-info",
- G_CALLBACK (backend_source_output_info_cb),
+ G_CALLBACK (on_connection_source_output_info),
pulse);
- g_signal_connect (connection,
+ g_signal_connect (G_OBJECT (connection),
"source-output-removed",
- G_CALLBACK (backend_source_output_removed_cb),
+ G_CALLBACK (on_connection_source_output_removed),
+ pulse);
+ g_signal_connect (G_OBJECT (connection),
+ "ext-stream-loading",
+ G_CALLBACK (on_connection_ext_stream_loading),
+ pulse);
+ g_signal_connect (G_OBJECT (connection),
+ "ext-stream-loaded",
+ G_CALLBACK (on_connection_ext_stream_loaded),
pulse);
+ g_signal_connect (G_OBJECT (connection),
+ "ext-stream-info",
+ G_CALLBACK (on_connection_ext_stream_info),
+ pulse);
+
+ change_state (pulse, MATE_MIXER_STATE_CONNECTING);
/* Connect to the PulseAudio server, this might fail either instantly or
* asynchronously, for example when remote connection timeouts */
- if (!pulse_connection_connect (connection, FALSE)) {
+ if (pulse_connection_connect (connection, FALSE) == FALSE) {
g_object_unref (connection);
- backend_change_state (pulse, MATE_MIXER_STATE_FAILED);
+ change_state (pulse, MATE_MIXER_STATE_FAILED);
return FALSE;
}
pulse->priv->connection = connection;
-
- backend_change_state (pulse, MATE_MIXER_STATE_CONNECTING);
return TRUE;
}
static void
-backend_close (MateMixerBackend *backend)
+pulse_backend_close (MateMixerBackend *backend)
{
PulseBackend *pulse;
@@ -421,24 +432,29 @@ backend_close (MateMixerBackend *backend)
pulse = PULSE_BACKEND (backend);
- backend_remove_connect_source (pulse);
+ connect_source_remove (pulse);
+
+ if (pulse->priv->connection != NULL) {
+ g_signal_handlers_disconnect_by_data (G_OBJECT (pulse->priv->connection),
+ pulse);
+
+ g_clear_object (&pulse->priv->connection);
+ }
- // XXX disconnect from notifies
- g_clear_object (&pulse->priv->connection);
g_clear_object (&pulse->priv->default_sink);
g_clear_object (&pulse->priv->default_source);
g_hash_table_remove_all (pulse->priv->devices);
- g_hash_table_remove_all (pulse->priv->sinks);
- g_hash_table_remove_all (pulse->priv->sink_inputs);
- g_hash_table_remove_all (pulse->priv->sources);
- g_hash_table_remove_all (pulse->priv->source_outputs);
+ g_hash_table_remove_all (pulse->priv->streams);
+ g_hash_table_remove_all (pulse->priv->ext_streams);
- backend_change_state (pulse, MATE_MIXER_STATE_IDLE);
+ pulse->priv->connected_once = FALSE;
+
+ change_state (pulse, MATE_MIXER_STATE_IDLE);
}
static MateMixerState
-backend_get_state (MateMixerBackend *backend)
+pulse_backend_get_state (MateMixerBackend *backend)
{
g_return_val_if_fail (PULSE_IS_BACKEND (backend), MATE_MIXER_STATE_UNKNOWN);
@@ -446,7 +462,7 @@ backend_get_state (MateMixerBackend *backend)
}
static void
-backend_set_data (MateMixerBackend *backend, const MateMixerBackendData *data)
+pulse_backend_set_data (MateMixerBackend *backend, const MateMixerBackendData *data)
{
PulseBackend *pulse;
@@ -469,45 +485,61 @@ backend_set_data (MateMixerBackend *backend, const MateMixerBackendData *data)
}
static GList *
-backend_list_devices (MateMixerBackend *backend)
+pulse_backend_list_devices (MateMixerBackend *backend)
{
GList *list;
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
- /* Always create a new current list, caching is done in the main library */
+ /* Convert the hash table to a sorted linked list, this list is expected
+ * to be cached in the main library */
list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->devices);
+ if (list != NULL) {
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
-
- return g_list_sort (list, backend_compare_devices);
+ return g_list_sort (list, compare_devices);
+ }
+ return NULL;
}
static GList *
-backend_list_streams (MateMixerBackend *backend)
+pulse_backend_list_streams (MateMixerBackend *backend)
{
- GList *list;
- PulseBackend *pulse;
+ GList *list;
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
- pulse = PULSE_BACKEND (backend);
+ /* Convert the hash table to a sorted linked list, this list is expected
+ * to be cached in the main library */
+ list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->streams);
+ if (list != NULL) {
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ return g_list_sort (list, compare_streams);
+ }
+ return NULL;
+}
- /* 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,
- g_hash_table_get_values (pulse->priv->sources));
- list = g_list_concat (list,
- g_hash_table_get_values (pulse->priv->source_outputs));
+static GList *
+pulse_backend_list_cached_streams (MateMixerBackend *backend)
+{
+ GList *list;
- g_list_foreach (list, (GFunc) g_object_ref, NULL);
+ g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
+
+ /* Convert the hash table to a sorted linked list, this list is expected
+ * to be cached in the main library */
+ list = g_hash_table_get_values (PULSE_BACKEND (backend)->priv->ext_streams);
+ if (list != NULL) {
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
- return g_list_sort (list, backend_compare_streams);
+ return g_list_sort (list, compare_streams);
+ }
+ return NULL;
}
static MateMixerStream *
-backend_get_default_input_stream (MateMixerBackend *backend)
+pulse_backend_get_default_input_stream (MateMixerBackend *backend)
{
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
@@ -515,30 +547,38 @@ backend_get_default_input_stream (MateMixerBackend *backend)
}
static gboolean
-backend_set_default_input_stream (MateMixerBackend *backend, MateMixerStream *stream)
+pulse_backend_set_default_input_stream (MateMixerBackend *backend,
+ MateMixerStream *stream)
{
PulseBackend *pulse;
+ const gchar *name;
g_return_val_if_fail (PULSE_IS_BACKEND (backend), FALSE);
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SOURCE (stream), FALSE);
pulse = PULSE_BACKEND (backend);
- if (G_UNLIKELY (!PULSE_IS_SOURCE (stream))) {
- g_warn_if_reached ();
+ name = mate_mixer_stream_get_name (stream);
+ if (pulse_connection_set_default_source (pulse->priv->connection, name) == FALSE)
return FALSE;
- }
- if (!pulse_connection_set_default_source (pulse->priv->connection,
- mate_mixer_stream_get_name (stream)))
- return FALSE;
+ if (pulse->priv->default_source != NULL)
+ g_object_unref (pulse->priv->default_source);
+
+ pulse->priv->default_source = g_object_ref (stream);
+
+ /* We might be in the process of setting a default source for which the details
+ * are not yet known, make sure the change does not happen */
+ g_object_set_data (G_OBJECT (pulse),
+ "backend-pending-source",
+ NULL);
g_object_notify (G_OBJECT (pulse), "default-input");
return TRUE;
}
static MateMixerStream *
-backend_get_default_output_stream (MateMixerBackend *backend)
+pulse_backend_get_default_output_stream (MateMixerBackend *backend)
{
g_return_val_if_fail (PULSE_IS_BACKEND (backend), NULL);
@@ -546,55 +586,64 @@ backend_get_default_output_stream (MateMixerBackend *backend)
}
static gboolean
-backend_set_default_output_stream (MateMixerBackend *backend, MateMixerStream *stream)
+pulse_backend_set_default_output_stream (MateMixerBackend *backend,
+ MateMixerStream *stream)
{
PulseBackend *pulse;
+ const gchar *name;
g_return_val_if_fail (PULSE_IS_BACKEND (backend), FALSE);
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
pulse = PULSE_BACKEND (backend);
- if (G_UNLIKELY (!PULSE_IS_SINK (stream))) {
- g_warn_if_reached ();
+ name = mate_mixer_stream_get_name (stream);
+ if (pulse_connection_set_default_sink (pulse->priv->connection, name) == FALSE)
return FALSE;
- }
- if (!pulse_connection_set_default_sink (pulse->priv->connection,
- mate_mixer_stream_get_name (stream)))
- return FALSE;
+ if (pulse->priv->default_sink != NULL)
+ g_object_unref (pulse->priv->default_sink);
+
+ pulse->priv->default_sink = g_object_ref (stream);
+
+ /* We might be in the process of setting a default sink for which the details
+ * are not yet known, make sure the change does not happen */
+ g_object_set_data (G_OBJECT (pulse),
+ "backend-pending-sink",
+ NULL);
g_object_notify (G_OBJECT (pulse), "default-output");
return TRUE;
}
static void
-backend_connection_state_cb (PulseConnection *connection,
- GParamSpec *pspec,
- PulseBackend *pulse)
+on_connection_state_notify (PulseConnection *connection,
+ GParamSpec *pspec,
+ PulseBackend *pulse)
{
PulseConnectionState state = pulse_connection_get_state (connection);
switch (state) {
case PULSE_CONNECTION_DISCONNECTED:
- if (pulse->priv->connected_once) {
+ if (pulse->priv->connected_once == TRUE) {
/* We managed to connect once before, try to reconnect and if it
* fails immediately, use a timeout source.
* All current devices and streams are marked as hanging as it is
- * unknown whether they are still available, stream callbacks will
- * unmark them and remaining unavailable streams will be removed
- * when the CONNECTED state is reached. */
- backend_mark_hanging (pulse);
- backend_change_state (pulse, MATE_MIXER_STATE_CONNECTING);
-
- if (!pulse->priv->connect_source &&
- !pulse_connection_connect (connection, TRUE)) {
+ * unknown whether they are still available.
+ * Stream callbacks will unmark available streams and remaining
+ * unavailable streams will be removed when the CONNECTED state
+ * is reached. */
+ mark_hanging (pulse);
+ change_state (pulse, MATE_MIXER_STATE_CONNECTING);
+
+ if (pulse->priv->connect_source == NULL &&
+ pulse_connection_connect (connection, TRUE) == FALSE) {
pulse->priv->connect_source = g_timeout_source_new (200);
g_source_set_callback (pulse->priv->connect_source,
- (GSourceFunc) backend_try_reconnect,
+ (GSourceFunc) connect_source_reconnect,
pulse,
- (GDestroyNotify) backend_remove_connect_source);
+ (GDestroyNotify) connect_source_remove);
g_source_attach (pulse->priv->connect_source,
g_main_context_get_thread_default ());
@@ -603,30 +652,30 @@ backend_connection_state_cb (PulseConnection *connection,
}
/* First connection attempt has failed */
- backend_change_state (pulse, MATE_MIXER_STATE_FAILED);
+ change_state (pulse, MATE_MIXER_STATE_FAILED);
break;
case PULSE_CONNECTION_CONNECTING:
case PULSE_CONNECTION_AUTHORIZING:
case PULSE_CONNECTION_LOADING:
- backend_change_state (pulse, MATE_MIXER_STATE_CONNECTING);
+ change_state (pulse, MATE_MIXER_STATE_CONNECTING);
break;
case PULSE_CONNECTION_CONNECTED:
- if (pulse->priv->connected_once)
- backend_remove_hanging (pulse);
+ if (pulse->priv->connected_once == TRUE)
+ remove_hanging (pulse);
else
pulse->priv->connected_once = TRUE;
- backend_change_state (pulse, MATE_MIXER_STATE_READY);
+ change_state (pulse, MATE_MIXER_STATE_READY);
break;
}
}
static void
-backend_server_info_cb (PulseConnection *connection,
- const pa_server_info *info,
- PulseBackend *pulse)
+on_connection_server_info (PulseConnection *connection,
+ const pa_server_info *info,
+ PulseBackend *pulse)
{
const gchar *name_source = NULL;
const gchar *name_sink = NULL;
@@ -634,55 +683,94 @@ backend_server_info_cb (PulseConnection *connection,
if (pulse->priv->default_source != NULL)
name_source = mate_mixer_stream_get_name (pulse->priv->default_source);
- // XXX
- // default input might be monitor !!!
-
- if (g_strcmp0 (name_source, info->default_source_name)) {
+ if (g_strcmp0 (name_source, info->default_source_name) != 0) {
if (pulse->priv->default_source != NULL)
g_clear_object (&pulse->priv->default_source);
if (info->default_source_name != NULL) {
- MateMixerStream *stream = g_hash_table_find (pulse->priv->sources,
- backend_compare_stream_names,
+ MateMixerStream *stream = g_hash_table_find (pulse->priv->streams,
+ compare_stream_names,
(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)) {
+ /* It is possible that we are unaware of the default stream, either
+ * because the stream details have not arrived yet, or because we chose
+ * to ignore the stream.
+ * When this happens, remember the name of the stream and wait for the
+ * stream info callback. */
+ if (stream != NULL) {
pulse->priv->default_source = g_object_ref (stream);
- g_debug ("Default input stream changed to %s", info->default_source_name);
+ g_object_set_data (G_OBJECT (pulse),
+ "backend-pending-source",
+ NULL);
- g_object_notify (G_OBJECT (pulse), "default-input");
- } else
- g_debug ("Default input stream %s not yet known",
+ g_debug ("Default input stream changed to %s", info->default_source_name);
+ } else {
+ g_debug ("Default input stream changed to unknown stream %s",
info->default_source_name);
- }
+
+ g_object_set_data_full (G_OBJECT (pulse),
+ "backend-pending-source",
+ g_strdup (info->default_source_name),
+ g_free);
+
+ /* In most cases (for example changing profile) the stream info
+ * arrives by itself, but do not rely on it and request it explicitely.
+ * In the meantime, keep the default stream set to NULL, which is
+ * important as we cannot guarantee that the info arrives and we use it. */
+ pulse_connection_load_source_info_name (pulse->priv->connection,
+ info->default_source_name);
+ }
+ } else
+ g_debug ("Default input stream unset");
+
+ g_object_notify (G_OBJECT (pulse), "default-input");
}
if (pulse->priv->default_sink != NULL)
name_sink = mate_mixer_stream_get_name (pulse->priv->default_sink);
- if (g_strcmp0 (name_sink, info->default_sink_name)) {
+ if (g_strcmp0 (name_sink, info->default_sink_name) != 0) {
if (pulse->priv->default_sink != NULL)
g_clear_object (&pulse->priv->default_sink);
if (info->default_sink_name != NULL) {
- MateMixerStream *stream = g_hash_table_find (pulse->priv->sinks,
- backend_compare_stream_names,
+ MateMixerStream *stream = g_hash_table_find (pulse->priv->streams,
+ compare_stream_names,
(gpointer) info->default_sink_name);
- if (G_LIKELY (stream != NULL)) {
+
+ /* It is possible that we are unaware of the default stream, either
+ * because the stream details have not arrived yet, or because we chose
+ * to ignore the stream.
+ * When this happens, remember the name of the stream and wait for the
+ * stream info callback. */
+ if (stream != NULL) {
pulse->priv->default_sink = g_object_ref (stream);
+ g_object_set_data (G_OBJECT (pulse),
+ "backend-pending-sink",
+ NULL);
+
g_debug ("Default output stream changed to %s", info->default_sink_name);
- g_object_notify (G_OBJECT (pulse), "default-output");
- } else
- g_debug ("Default output stream %s not yet known",
+ } else {
+ g_debug ("Default output stream changed to unknown stream %s",
info->default_sink_name);
- }
+
+ g_object_set_data_full (G_OBJECT (pulse),
+ "backend-pending-sink",
+ g_strdup (info->default_sink_name),
+ g_free);
+
+ /* In most cases (for example changing profile) the stream info
+ * arrives by itself, but do not rely on it and request it explicitely.
+ * In the meantime, keep the default stream set to NULL, which is
+ * important as we cannot guarantee that the info arrives and we use it. */
+ pulse_connection_load_sink_info_name (pulse->priv->connection,
+ info->default_sink_name);
+ }
+ } else
+ g_debug ("Default output stream unset");
+
+ g_object_notify (G_OBJECT (pulse), "default-output");
}
if (pulse->priv->state != MATE_MIXER_STATE_READY)
@@ -693,401 +781,533 @@ backend_server_info_cb (PulseConnection *connection,
}
static void
-backend_card_info_cb (PulseConnection *connection,
- const pa_card_info *info,
- PulseBackend *pulse)
+on_connection_card_info (PulseConnection *connection,
+ const pa_card_info *info,
+ PulseBackend *pulse)
{
- gpointer p;
PulseDevice *device;
- p = g_hash_table_lookup (pulse->priv->devices, GINT_TO_POINTER (info->index));
- if (p == NULL) {
+ device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (info->index));
+ if (device == NULL) {
device = pulse_device_new (connection, info);
-
if (G_UNLIKELY (device == NULL))
return;
- g_hash_table_insert (pulse->priv->devices,
- GINT_TO_POINTER (info->index),
- device);
+ g_hash_table_insert (pulse->priv->devices, GUINT_TO_POINTER (info->index), device);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "device-added",
+ mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
} else {
- device = PULSE_DEVICE (p);
pulse_device_update (device, info);
- }
- if (pulse->priv->connected_once) {
/* The object might be hanging if reconnecting is in progress, remove the
* hanging flag to prevent it from being removed when connected */
- if (pulse->priv->state != MATE_MIXER_STATE_READY)
- g_object_steal_data (G_OBJECT (device), "hanging");
-
- g_signal_emit_by_name (G_OBJECT (pulse),
- (p == NULL)
- ? "device-added"
- : "device-changed",
- mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
+ unmark_hanging (pulse, G_OBJECT (device));
}
}
static void
-backend_card_removed_cb (PulseConnection *connection,
- guint index,
- PulseBackend *pulse)
+on_connection_card_removed (PulseConnection *connection,
+ guint index,
+ PulseBackend *pulse)
{
- gpointer p;
+ PulseDevice *device;
- p = g_hash_table_lookup (pulse->priv->devices, GINT_TO_POINTER (index));
- if (G_UNLIKELY (p == NULL))
+ device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (index));
+ if (G_UNLIKELY (device == NULL))
return;
- backend_remove_device (pulse, PULSE_DEVICE (p));
+ remove_device (pulse, device);
}
+/* PulseAudio uses 32-bit integers as indices for sinks, sink inputs, sources and
+ * source inputs, these indices are not unique among the different kinds of streams,
+ * but we want to keep all of them in a single hash table. Allow this by using 64-bit
+ * hash table keys, use the lower 32 bits for the PulseAudio index and some of the
+ * higher bits to indicate what kind of stream it is. */
+enum {
+ HASH_BIT_SINK = (1ULL << 63),
+ HASH_BIT_SINK_INPUT = (1ULL << 62),
+ HASH_BIT_SOURCE = (1ULL << 61),
+ HASH_BIT_SOURCE_OUTPUT = (1ULL << 60)
+};
+#define HASH_ID_SINK(idx) (((idx) & 0xffffffff) | HASH_BIT_SINK)
+#define HASH_ID_SINK_INPUT(idx) (((idx) & 0xffffffff) | HASH_BIT_SINK_INPUT)
+#define HASH_ID_SOURCE(idx) (((idx) & 0xffffffff) | HASH_BIT_SOURCE)
+#define HASH_ID_SOURCE_OUTPUT(idx) (((idx) & 0xffffffff) | HASH_BIT_SOURCE_OUTPUT)
+
static void
-backend_sink_info_cb (PulseConnection *connection,
- const pa_sink_info *info,
- PulseBackend *pulse)
+on_connection_sink_info (PulseConnection *connection,
+ const pa_sink_info *info,
+ PulseBackend *pulse)
{
PulseDevice *device = NULL;
PulseStream *stream;
- gpointer p = NULL;
+ gint64 index = HASH_ID_SINK (info->index);
if (info->card != PA_INVALID_INDEX)
- p = g_hash_table_lookup (pulse->priv->devices, GINT_TO_POINTER (info->card));
- if (p)
- device = PULSE_DEVICE (p);
+ device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (info->card));
- p = g_hash_table_lookup (pulse->priv->sinks, GINT_TO_POINTER (info->index));
- if (p == NULL) {
+ stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ if (stream == NULL) {
stream = pulse_sink_new (connection, info, device);
-
if (G_UNLIKELY (stream == NULL))
return;
- g_hash_table_insert (pulse->priv->sinks,
- GINT_TO_POINTER (info->index),
- stream);
+ g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+
+ /* We might be waiting for this sink to set it as the default */
+ check_pending_sink (pulse, stream);
} else {
- stream = PULSE_STREAM (p);
pulse_sink_update (stream, info, device);
- }
- if (pulse->priv->connected_once) {
/* The object might be hanging if reconnecting is in progress, remove the
* hanging flag to prevent it from being removed when connected */
- if (pulse->priv->state != MATE_MIXER_STATE_READY)
- g_object_steal_data (G_OBJECT (stream), "hanging");
-
- g_signal_emit_by_name (G_OBJECT (pulse),
- (p == NULL)
- ? "stream-added"
- : "stream-changed",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ unmark_hanging (pulse, G_OBJECT (stream));
}
}
static void
-backend_sink_removed_cb (PulseConnection *connection,
- guint index,
- PulseBackend *pulse)
+on_connection_sink_removed (PulseConnection *connection,
+ guint idx,
+ PulseBackend *pulse)
{
- gpointer p;
+ PulseStream *stream;
+ gint64 index = HASH_ID_SINK (idx);
- p = g_hash_table_lookup (pulse->priv->sinks, GINT_TO_POINTER (index));
- if (G_UNLIKELY (p == NULL))
+ stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ if (G_UNLIKELY (stream == NULL))
return;
- backend_remove_stream (pulse, pulse->priv->sinks, PULSE_STREAM (p));
+ remove_stream (pulse, stream);
}
static void
-backend_sink_input_info_cb (PulseConnection *connection,
- const pa_sink_input_info *info,
- PulseBackend *pulse)
+on_connection_sink_input_info (PulseConnection *connection,
+ const pa_sink_input_info *info,
+ PulseBackend *pulse)
{
PulseStream *stream;
- gpointer p;
- gpointer parent = NULL;
+ PulseStream *parent = NULL;
+ gint64 index;
+
+ if (G_LIKELY (info->sink != PA_INVALID_INDEX)) {
+ index = HASH_ID_SINK (info->sink);
- if (G_LIKELY (info->sink)) {
- parent = g_hash_table_lookup (pulse->priv->sinks, GINT_TO_POINTER (info->sink));
+ parent = g_hash_table_lookup (pulse->priv->streams, &index);
if (G_UNLIKELY (parent == NULL))
g_debug ("Unknown parent %d of PulseAudio sink input %s",
info->sink,
info->name);
}
- p = g_hash_table_lookup (pulse->priv->sink_inputs, GINT_TO_POINTER (info->index));
- if (p == NULL) {
- stream = pulse_sink_input_new (connection, info, parent);
+ index = HASH_ID_SINK_INPUT (info->index);
+ stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ if (stream == NULL) {
+ stream = pulse_sink_input_new (connection, info, parent);
if (G_UNLIKELY (stream == NULL))
return;
- g_hash_table_insert (pulse->priv->sink_inputs,
- GINT_TO_POINTER (info->index),
- stream);
+ g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
} else {
- stream = PULSE_STREAM (p);
pulse_sink_input_update (stream, info, parent);
- }
- if (pulse->priv->connected_once) {
/* The object might be hanging if reconnecting is in progress, remove the
* hanging flag to prevent it from being removed when connected */
- if (pulse->priv->state != MATE_MIXER_STATE_READY)
- g_object_steal_data (G_OBJECT (stream), "hanging");
-
- g_signal_emit_by_name (G_OBJECT (pulse),
- (p == NULL)
- ? "stream-added"
- : "stream-changed",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ unmark_hanging (pulse, G_OBJECT (stream));
}
}
static void
-backend_sink_input_removed_cb (PulseConnection *connection,
- guint index,
- PulseBackend *pulse)
+on_connection_sink_input_removed (PulseConnection *connection,
+ guint idx,
+ PulseBackend *pulse)
{
- gpointer p;
+ PulseStream *stream;
+ gint64 index = HASH_ID_SINK_INPUT (idx);
- p = g_hash_table_lookup (pulse->priv->sink_inputs, GINT_TO_POINTER (index));
- if (G_UNLIKELY (p == NULL))
+ stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ if (G_UNLIKELY (stream == NULL))
return;
- backend_remove_stream (pulse, pulse->priv->sink_inputs, PULSE_STREAM (p));
+ remove_stream (pulse, stream);
}
static void
-backend_source_info_cb (PulseConnection *connection,
- const pa_source_info *info,
- PulseBackend *pulse)
+on_connection_source_info (PulseConnection *connection,
+ const pa_source_info *info,
+ PulseBackend *pulse)
{
PulseDevice *device = NULL;
PulseStream *stream;
- gpointer p = NULL;
+ gint64 index = HASH_ID_SOURCE (info->index);
/* Skip monitor streams */
if (info->monitor_of_sink != PA_INVALID_INDEX)
return;
if (info->card != PA_INVALID_INDEX)
- p = g_hash_table_lookup (pulse->priv->devices, GINT_TO_POINTER (info->card));
- if (p)
- device = PULSE_DEVICE (p);
+ device = g_hash_table_lookup (pulse->priv->devices, GUINT_TO_POINTER (info->card));
- p = g_hash_table_lookup (pulse->priv->sources, GINT_TO_POINTER (info->index));
- if (p == NULL) {
+ stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ if (stream == NULL) {
stream = pulse_source_new (connection, info, device);
-
if (G_UNLIKELY (stream == NULL))
return;
- g_hash_table_insert (pulse->priv->sources,
- GINT_TO_POINTER (info->index),
- stream);
+ g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+
+ /* We might be waiting for this source to set it as the default */
+ check_pending_source (pulse, stream);
} else {
- stream = PULSE_STREAM (p);
pulse_source_update (stream, info, device);
- }
- if (pulse->priv->connected_once) {
/* The object might be hanging if reconnecting is in progress, remove the
* hanging flag to prevent it from being removed when connected */
- if (pulse->priv->state != MATE_MIXER_STATE_READY)
- g_object_steal_data (G_OBJECT (stream), "hanging");
-
- g_signal_emit_by_name (G_OBJECT (pulse),
- (p == NULL)
- ? "stream-added"
- : "stream-changed",
- mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ unmark_hanging (pulse, G_OBJECT (stream));
}
}
static void
-backend_source_removed_cb (PulseConnection *connection,
- guint index,
- PulseBackend *pulse)
+on_connection_source_removed (PulseConnection *connection,
+ guint idx,
+ PulseBackend *pulse)
{
- gpointer p;
+ PulseStream *stream;
+ gint64 index = HASH_ID_SOURCE (idx);
- p = g_hash_table_lookup (pulse->priv->sources, GINT_TO_POINTER (index));
- if (G_UNLIKELY (p == NULL))
+ stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ if (G_UNLIKELY (stream == NULL))
return;
- backend_remove_stream (pulse, pulse->priv->sources, PULSE_STREAM (p));
+ remove_stream (pulse, stream);
}
static void
-backend_source_output_info_cb (PulseConnection *connection,
- const pa_source_output_info *info,
- PulseBackend *pulse)
+on_connection_source_output_info (PulseConnection *connection,
+ const pa_source_output_info *info,
+ PulseBackend *pulse)
{
PulseStream *stream;
- gpointer p;
- gpointer parent = NULL;
+ PulseStream *parent = NULL;
+ gint64 index;
- if (G_LIKELY (info->source)) {
- parent = g_hash_table_lookup (pulse->priv->sources, GINT_TO_POINTER (info->source));
+ if (G_LIKELY (info->source != PA_INVALID_INDEX)) {
+ index = HASH_ID_SOURCE (info->source);
- /* Probably a monitor source that we have skipped */
+ /* Most likely a monitor source that we have skipped */
+ parent = g_hash_table_lookup (pulse->priv->streams, &index);
if (parent == NULL)
return;
}
- p = g_hash_table_lookup (pulse->priv->source_outputs, GINT_TO_POINTER (info->index));
- if (p == NULL) {
+ index = HASH_ID_SOURCE_OUTPUT (info->index);
+
+ stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ if (stream == NULL) {
stream = pulse_source_output_new (connection, info, parent);
if (G_UNLIKELY (stream == NULL))
return;
- g_hash_table_insert (pulse->priv->source_outputs,
- GINT_TO_POINTER (info->index),
- stream);
+ g_hash_table_insert (pulse->priv->streams, g_memdup (&index, 8), stream);
+
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "stream-added",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
} else {
- stream = PULSE_STREAM (p);
pulse_source_output_update (stream, info, parent);
- }
- if (pulse->priv->connected_once) {
/* The object might be hanging if reconnecting is in progress, remove the
* hanging flag to prevent it from being removed when connected */
- if (pulse->priv->state != MATE_MIXER_STATE_READY)
- g_object_steal_data (G_OBJECT (stream), "hanging");
+ unmark_hanging (pulse, G_OBJECT (stream));
+ }
+}
+
+static void
+on_connection_source_output_removed (PulseConnection *connection,
+ guint idx,
+ PulseBackend *pulse)
+{
+ PulseStream *stream;
+ gint64 index = HASH_ID_SOURCE_OUTPUT (idx);
+
+ stream = g_hash_table_lookup (pulse->priv->streams, &index);
+ if (G_UNLIKELY (stream == NULL))
+ return;
+
+ remove_stream (pulse, stream);
+}
+
+static void
+on_connection_ext_stream_info (PulseConnection *connection,
+ const pa_ext_stream_restore_info *info,
+ PulseBackend *pulse)
+{
+ PulseStream *stream;
+ PulseStream *parent = NULL;
+
+ if (G_LIKELY (info->device != NULL))
+ parent = g_hash_table_find (pulse->priv->streams, compare_stream_names,
+ (gpointer) info->device);
+
+ stream = g_hash_table_lookup (pulse->priv->ext_streams, info->name);
+ if (stream == NULL) {
+ stream = pulse_ext_stream_new (connection, info, parent);
+ if (G_UNLIKELY (stream == NULL))
+ return;
+
+ g_hash_table_insert (pulse->priv->ext_streams, g_strdup (info->name), stream);
g_signal_emit_by_name (G_OBJECT (pulse),
- (p == NULL)
- ? "stream-added"
- : "stream-changed",
+ "cached-stream-added",
mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
+ } else {
+ pulse_ext_stream_update (stream, info, parent);
+
+ /* The object might be hanging if ext-streams are being loaded, remove
+ * the hanging flag to prevent it from being removed */
+ unmark_hanging (pulse, G_OBJECT (stream));
}
}
static void
-backend_source_output_removed_cb (PulseConnection *connection,
- guint index,
- PulseBackend *pulse)
+on_connection_ext_stream_loading (PulseConnection *connection, PulseBackend *pulse)
{
- gpointer p;
+ mark_hanging_hash (pulse->priv->ext_streams);
+}
- p = g_hash_table_lookup (pulse->priv->source_outputs, GINT_TO_POINTER (index));
- if (G_UNLIKELY (p == NULL))
- return;
+static void
+on_connection_ext_stream_loaded (PulseConnection *connection, PulseBackend *pulse)
+{
+ GHashTableIter iter;
+ gpointer value;
+
+ g_hash_table_iter_init (&iter, pulse->priv->ext_streams);
- backend_remove_stream (pulse, pulse->priv->source_outputs, PULSE_STREAM (p));
+ while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE) {
+ guint hanging =
+ GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (value), "backend-hanging"));
+
+ if (hanging == 1) {
+ gchar *name = g_strdup ((const gchar *) value);
+
+ g_hash_table_remove (pulse->priv->ext_streams, (gconstpointer) name);
+ g_signal_emit_by_name (G_OBJECT (pulse),
+ "cached-stream-removed",
+ name);
+ g_free (name);
+ }
+ }
}
static gboolean
-backend_try_reconnect (PulseBackend *pulse)
+connect_source_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, TRUE);
+ if (pulse_connection_connect (pulse->priv->connection, TRUE) == TRUE) {
+ connect_source_remove (pulse);
+ return FALSE;
+ }
+ return TRUE;
}
static void
-backend_remove_connect_source (PulseBackend *pulse)
+connect_source_remove (PulseBackend *pulse)
{
g_clear_pointer (&pulse->priv->connect_source, g_source_unref);
}
static void
-backend_mark_hanging (PulseBackend *pulse)
+check_pending_sink (PulseBackend *pulse, PulseStream *stream)
{
- backend_mark_hanging_hash (pulse->priv->devices);
- backend_mark_hanging_hash (pulse->priv->sinks);
- backend_mark_hanging_hash (pulse->priv->sink_inputs);
- backend_mark_hanging_hash (pulse->priv->sources);
- backend_mark_hanging_hash (pulse->priv->source_outputs);
+ const gchar *pending;
+ const gchar *name;
+
+ /* See if the currently added sream matches the default input stream
+ * we are waiting for */
+ pending = g_object_get_data (G_OBJECT (pulse), "backend-pending-sink");
+ if (pending == NULL)
+ return;
+
+ name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
+ if (g_strcmp0 (pending, name) != 0)
+ return;
+
+ pulse->priv->default_sink = g_object_ref (stream);
+ g_object_set_data (G_OBJECT (pulse),
+ "backend-pending-sink",
+ NULL);
+
+ g_debug ("Default output stream changed to pending stream %s", name);
+
+ g_object_notify (G_OBJECT (pulse), "default-output");
}
static void
-backend_mark_hanging_hash (GHashTable *hash)
+check_pending_source (PulseBackend *pulse, PulseStream *stream)
{
- GHashTableIter iter;
- gpointer value;
+ const gchar *pending;
+ const gchar *name;
- g_hash_table_iter_init (&iter, hash);
+ /* See if the currently added sream matches the default input stream
+ * we are waiting for */
+ pending = g_object_get_data (G_OBJECT (pulse), "backend-pending-source");
+ if (pending == NULL)
+ return;
+
+ name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream));
+ if (g_strcmp0 (pending, name) != 0)
+ return;
- while (g_hash_table_iter_next (&iter, NULL, &value))
- g_object_set_data (G_OBJECT (value), "hanging", GINT_TO_POINTER (1));
+ pulse->priv->default_source = g_object_ref (stream);
+ g_object_set_data (G_OBJECT (pulse),
+ "backend-pending-source",
+ NULL);
+
+ g_debug ("Default input stream changed to pending stream %s", name);
+
+ g_object_notify (G_OBJECT (pulse), "default-input");
+}
+
+static void
+mark_hanging (PulseBackend *pulse)
+{
+ /* Mark devices and streams as hanging, ext-streams are handled separately */
+ mark_hanging_hash (pulse->priv->devices);
+ mark_hanging_hash (pulse->priv->streams);
}
static void
-backend_remove_hanging (PulseBackend *pulse)
+mark_hanging_hash (GHashTable *hash)
{
GHashTableIter iter;
gpointer value;
- g_hash_table_iter_init (&iter, pulse->priv->devices);
+ g_hash_table_iter_init (&iter, hash);
- while (g_hash_table_iter_next (&iter, NULL, &value))
- if (g_object_get_data (G_OBJECT (value), "hanging"))
- backend_remove_device (pulse, PULSE_DEVICE (value));
+ while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE)
+ g_object_set_data (G_OBJECT (value), "backend-hanging", GUINT_TO_POINTER (1));
+}
+
+static void
+unmark_hanging (PulseBackend *pulse, GObject *object)
+{
+ if (pulse->priv->connected_once == FALSE)
+ return;
+ if (pulse->priv->state == MATE_MIXER_STATE_READY)
+ return;
- backend_remove_hanging_hash (pulse, pulse->priv->sinks);
- backend_remove_hanging_hash (pulse, pulse->priv->sink_inputs);
- backend_remove_hanging_hash (pulse, pulse->priv->sources);
- backend_remove_hanging_hash (pulse, pulse->priv->source_outputs);
+ g_object_steal_data (object, "backend-hanging");
}
static void
-backend_remove_hanging_hash (PulseBackend *pulse, GHashTable *hash)
+remove_hanging (PulseBackend *pulse)
{
GHashTableIter iter;
gpointer value;
- g_hash_table_iter_init (&iter, hash);
+ g_hash_table_iter_init (&iter, pulse->priv->devices);
+
+ while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE) {
+ guint hanging =
+ GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (value), "backend-hanging"));
- while (g_hash_table_iter_next (&iter, NULL, &value))
- if (g_object_get_data (G_OBJECT (value), "hanging"))
- backend_remove_stream (pulse, hash, PULSE_STREAM (value));
+ if (hanging == 1)
+ remove_device (pulse, PULSE_DEVICE (value));
+ }
+
+ g_hash_table_iter_init (&iter, pulse->priv->streams);
+
+ while (g_hash_table_iter_next (&iter, NULL, &value) == TRUE) {
+ guint hanging =
+ GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (value), "backend-hanging"));
+
+ if (hanging == 1)
+ remove_stream (pulse, PULSE_STREAM (value));
+ }
}
static void
-backend_remove_device (PulseBackend *pulse, PulseDevice *device)
+remove_device (PulseBackend *pulse, PulseDevice *device)
{
gchar *name;
name = g_strdup (mate_mixer_device_get_name (MATE_MIXER_DEVICE (device)));
g_hash_table_remove (pulse->priv->devices,
- GINT_TO_POINTER (pulse_device_get_index (device)));
+ GUINT_TO_POINTER (pulse_device_get_index (device)));
g_signal_emit_by_name (G_OBJECT (pulse), "device-removed", name);
g_free (name);
}
static void
-backend_remove_stream (PulseBackend *pulse, GHashTable *hash, PulseStream *stream)
+remove_stream (PulseBackend *pulse, PulseStream *stream)
{
- gchar *name;
-
- /* Make sure we do not end up with invalid default streams, but this is
- * very unlikely to happen */
- if (G_UNLIKELY (MATE_MIXER_STREAM (stream) == pulse->priv->default_sink)) {
+ gchar *name;
+ guint32 idx;
+ gint64 index;
+ gboolean reload = FALSE;
+
+ /* The removed stream might be one of the default streams, this happens
+ * especially when switching profiles, after which PulseAudio removes the
+ * old streams and creates new ones with different names */
+ if (MATE_MIXER_STREAM (stream) == pulse->priv->default_sink) {
g_clear_object (&pulse->priv->default_sink);
+
g_object_notify (G_OBJECT (pulse), "default-output");
+ reload = TRUE;
}
- else if (G_UNLIKELY (MATE_MIXER_STREAM (stream) == pulse->priv->default_source)) {
+ else if (MATE_MIXER_STREAM (stream) == pulse->priv->default_source) {
g_clear_object (&pulse->priv->default_source);
+
g_object_notify (G_OBJECT (pulse), "default-input");
+ reload = TRUE;
}
+ idx = pulse_stream_get_index (stream);
+
+ if (PULSE_IS_SINK (stream))
+ index = HASH_ID_SINK (idx);
+ else if (PULSE_IS_SINK_INPUT (stream))
+ index = HASH_ID_SINK_INPUT (idx);
+ else if (PULSE_IS_SOURCE (stream))
+ index = HASH_ID_SOURCE (idx);
+ else
+ index = HASH_ID_SOURCE_OUTPUT (idx);
+
name = g_strdup (mate_mixer_stream_get_name (MATE_MIXER_STREAM (stream)));
- g_hash_table_remove (hash, GINT_TO_POINTER (pulse_stream_get_index (stream)));
+ g_hash_table_remove (pulse->priv->streams, &index);
+
+ /* PulseAudio usually sends a server info update by itself when default
+ * stream changes, but there is at least one case when it does not - setting
+ * a card profile to off, so to be sure request an update explicitely */
+ if (reload == TRUE)
+ pulse_connection_load_server_info (pulse->priv->connection);
g_signal_emit_by_name (G_OBJECT (pulse), "stream-removed", name);
g_free (name);
}
static void
-backend_change_state (PulseBackend *backend, MateMixerState state)
+change_state (PulseBackend *backend, MateMixerState state)
{
if (backend->priv->state == state)
return;
@@ -1098,21 +1318,21 @@ backend_change_state (PulseBackend *backend, MateMixerState state)
}
static gint
-backend_compare_devices (gconstpointer a, gconstpointer b)
+compare_devices (gconstpointer a, gconstpointer b)
{
return strcmp (mate_mixer_device_get_name (MATE_MIXER_DEVICE (a)),
mate_mixer_device_get_name (MATE_MIXER_DEVICE (b)));
}
static gint
-backend_compare_streams (gconstpointer a, gconstpointer b)
+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_names (gpointer key, gpointer value, gpointer user_data)
+compare_stream_names (gpointer key, gpointer value, gpointer user_data)
{
MateMixerStream *stream = MATE_MIXER_STREAM (value);
diff --git a/backends/pulse/pulse-backend.h b/backends/pulse/pulse-backend.h
index 48fffc6..bd1face 100644
--- a/backends/pulse/pulse-backend.h
+++ b/backends/pulse/pulse-backend.h
@@ -21,7 +21,7 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-backend.h>
+#include <libmatemixer/matemixer-backend-module.h>
#define PULSE_TYPE_BACKEND \
(pulse_backend_get_type ())
diff --git a/backends/pulse/pulse-client-stream.c b/backends/pulse/pulse-client-stream.c
index 8c9312a..d725146 100644
--- a/backends/pulse/pulse-client-stream.c
+++ b/backends/pulse/pulse-client-stream.c
@@ -15,11 +15,12 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#include <string.h>
#include <glib.h>
#include <glib-object.h>
-#include <string.h>
#include <libmatemixer/matemixer-client-stream.h>
+#include <libmatemixer/matemixer-enums.h>
#include <libmatemixer/matemixer-stream.h>
#include <pulse/pulseaudio.h>
@@ -29,24 +30,33 @@
struct _PulseClientStreamPrivate
{
- gchar *app_name;
- gchar *app_id;
- gchar *app_version;
- gchar *app_icon;
- MateMixerStream *parent;
+ gchar *app_name;
+ gchar *app_id;
+ gchar *app_version;
+ gchar *app_icon;
+ MateMixerStream *parent;
+ MateMixerClientStreamFlags flags;
+ MateMixerClientStreamRole role;
};
-enum
-{
+enum {
PROP_0,
+ PROP_CLIENT_FLAGS,
+ PROP_ROLE,
PROP_PARENT,
PROP_APP_NAME,
PROP_APP_ID,
PROP_APP_VERSION,
- PROP_APP_ICON,
- N_PROPERTIES
+ PROP_APP_ICON
};
+enum {
+ REMOVED,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0, };
+
static void mate_mixer_client_stream_interface_init (MateMixerClientStreamInterface *iface);
static void pulse_client_stream_class_init (PulseClientStreamClass *klass);
@@ -64,26 +74,32 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (PulseClientStream, pulse_client_stream, PULSE_
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 MateMixerClientStreamFlags pulse_client_stream_get_flags (MateMixerClientStream *client);
+static MateMixerClientStreamRole pulse_client_stream_get_role (MateMixerClientStream *client);
+
+static MateMixerStream * pulse_client_stream_get_parent (MateMixerClientStream *client);
+static gboolean pulse_client_stream_set_parent (MateMixerClientStream *client,
+ MateMixerStream *parent);
-static 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 gboolean pulse_client_stream_remove (MateMixerClientStream *client);
+
+static const gchar * pulse_client_stream_get_app_name (MateMixerClientStream *client);
+static const gchar * pulse_client_stream_get_app_id (MateMixerClientStream *client);
+static const gchar * pulse_client_stream_get_app_version (MateMixerClientStream *client);
+static const gchar * pulse_client_stream_get_app_icon (MateMixerClientStream *client);
static void
mate_mixer_client_stream_interface_init (MateMixerClientStreamInterface *iface)
{
- iface->get_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;
+ iface->get_flags = pulse_client_stream_get_flags;
+ iface->get_role = pulse_client_stream_get_role;
+ iface->get_parent = pulse_client_stream_get_parent;
+ iface->set_parent = pulse_client_stream_set_parent;
+ iface->remove = pulse_client_stream_remove;
+ iface->get_app_name = pulse_client_stream_get_app_name;
+ iface->get_app_id = pulse_client_stream_get_app_id;
+ iface->get_app_version = pulse_client_stream_get_app_version;
+ iface->get_app_icon = pulse_client_stream_get_app_icon;
}
static void
@@ -96,6 +112,20 @@ pulse_client_stream_class_init (PulseClientStreamClass *klass)
object_class->finalize = pulse_client_stream_finalize;
object_class->get_property = pulse_client_stream_get_property;
+ signals[REMOVED] =
+ g_signal_new ("removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseClientStreamClass, removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0,
+ G_TYPE_NONE);
+
+ g_object_class_override_property (object_class, PROP_CLIENT_FLAGS, "client-flags");
+ g_object_class_override_property (object_class, PROP_ROLE, "role");
g_object_class_override_property (object_class, PROP_PARENT, "parent");
g_object_class_override_property (object_class, PROP_APP_NAME, "app-name");
g_object_class_override_property (object_class, PROP_APP_ID, "app-id");
@@ -116,6 +146,12 @@ pulse_client_stream_get_property (GObject *object,
client = PULSE_CLIENT_STREAM (object);
switch (param_id) {
+ case PROP_CLIENT_FLAGS:
+ g_value_set_flags (value, client->priv->flags);
+ break;
+ case PROP_ROLE:
+ g_value_set_enum (value, client->priv->role);
+ break;
case PROP_PARENT:
g_value_set_object (value, client->priv->parent);
break;
@@ -173,79 +209,123 @@ pulse_client_stream_finalize (GObject *object)
}
gboolean
-pulse_client_stream_update_parent (PulseClientStream *client, MateMixerStream *parent)
+pulse_client_stream_update_flags (PulseClientStream *pclient,
+ MateMixerClientStreamFlags flags)
{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
+
+ if (pclient->priv->flags != flags) {
+ pclient->priv->flags = flags;
+
+ g_object_notify (G_OBJECT (pclient), "client-flags");
+ }
+ return TRUE;
+}
- if (client->priv->parent != parent) {
- g_clear_object (&client->priv->parent);
+gboolean
+pulse_client_stream_update_parent (PulseClientStream *pclient, MateMixerStream *parent)
+{
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
+
+ if (pclient->priv->parent != parent) {
+ g_clear_object (&pclient->priv->parent);
if (G_LIKELY (parent != NULL))
- client->priv->parent = g_object_ref (parent);
+ pclient->priv->parent = g_object_ref (parent);
- g_object_notify (G_OBJECT (client), "parent");
+ g_object_notify (G_OBJECT (pclient), "parent");
}
return TRUE;
}
gboolean
-pulse_client_stream_update_app_name (PulseClientStream *client, const gchar *app_name)
+pulse_client_stream_update_role (PulseClientStream *pclient,
+ MateMixerClientStreamRole role)
{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
- if (g_strcmp0 (client->priv->app_name, app_name)) {
- g_free (client->priv->app_name);
- client->priv->app_name = g_strdup (app_name);
+ if (pclient->priv->role != role) {
+ pclient->priv->role = role;
- g_object_notify (G_OBJECT (client), "app-name");
+ g_object_notify (G_OBJECT (pclient), "role");
}
return TRUE;
}
gboolean
-pulse_client_stream_update_app_id (PulseClientStream *client, const gchar *app_id)
+pulse_client_stream_update_app_name (PulseClientStream *pclient, const gchar *app_name)
{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
- if (g_strcmp0 (client->priv->app_id, app_id)) {
- g_free (client->priv->app_id);
- client->priv->app_id = g_strdup (app_id);
+ if (g_strcmp0 (pclient->priv->app_name, app_name) != 0) {
+ g_free (pclient->priv->app_name);
+ pclient->priv->app_name = g_strdup (app_name);
- g_object_notify (G_OBJECT (client), "app-id");
+ g_object_notify (G_OBJECT (pclient), "app-name");
}
return TRUE;
}
gboolean
-pulse_client_stream_update_app_version (PulseClientStream *client, const gchar *app_version)
+pulse_client_stream_update_app_id (PulseClientStream *pclient, const gchar *app_id)
{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
- if (g_strcmp0 (client->priv->app_version, app_version)) {
- g_free (client->priv->app_version);
- client->priv->app_version = g_strdup (app_version);
+ if (g_strcmp0 (pclient->priv->app_id, app_id) != 0) {
+ g_free (pclient->priv->app_id);
+ pclient->priv->app_id = g_strdup (app_id);
- g_object_notify (G_OBJECT (client), "app-version");
+ g_object_notify (G_OBJECT (pclient), "app-id");
}
return TRUE;
}
gboolean
-pulse_client_stream_update_app_icon (PulseClientStream *client, const gchar *app_icon)
+pulse_client_stream_update_app_version (PulseClientStream *pclient, const gchar *app_version)
{
- g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
- if (g_strcmp0 (client->priv->app_icon, app_icon)) {
- g_free (client->priv->app_icon);
- client->priv->app_icon = g_strdup (app_icon);
+ if (g_strcmp0 (pclient->priv->app_version, app_version) != 0) {
+ g_free (pclient->priv->app_version);
+ pclient->priv->app_version = g_strdup (app_version);
- g_object_notify (G_OBJECT (client), "app-icon");
+ g_object_notify (G_OBJECT (pclient), "app-version");
}
return TRUE;
}
+gboolean
+pulse_client_stream_update_app_icon (PulseClientStream *pclient, const gchar *app_icon)
+{
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (pclient), FALSE);
+
+ if (g_strcmp0 (pclient->priv->app_icon, app_icon) != 0) {
+ g_free (pclient->priv->app_icon);
+ pclient->priv->app_icon = g_strdup (app_icon);
+
+ g_object_notify (G_OBJECT (pclient), "app-icon");
+ }
+ return TRUE;
+}
+
+static MateMixerClientStreamFlags
+pulse_client_stream_get_flags (MateMixerClientStream *client)
+{
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_NO_FLAGS);
+
+ return PULSE_CLIENT_STREAM (client)->priv->flags;
+}
+
+static MateMixerClientStreamRole
+pulse_client_stream_get_role (MateMixerClientStream *client)
+{
+ g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_ROLE_NONE);
+
+ return PULSE_CLIENT_STREAM (client)->priv->role;
+}
+
static MateMixerStream *
-client_stream_get_parent (MateMixerClientStream *client)
+pulse_client_stream_get_parent (MateMixerClientStream *client)
{
g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
@@ -253,23 +333,58 @@ client_stream_get_parent (MateMixerClientStream *client)
}
static gboolean
-client_stream_set_parent (MateMixerClientStream *client, MateMixerStream *parent)
+pulse_client_stream_set_parent (MateMixerClientStream *client, MateMixerStream *parent)
{
+ PulseClientStream *pclient;
+ PulseClientStreamClass *klass;
+
g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (parent), FALSE);
+
+ pclient = PULSE_CLIENT_STREAM (client);
+ klass = PULSE_CLIENT_STREAM_GET_CLASS (pclient);
+
+ if (pclient->priv->parent == parent)
+ return TRUE;
+
+ if (klass->set_parent (pclient, PULSE_STREAM (parent)) == FALSE)
+ return FALSE;
+
+ if (pclient->priv->parent != NULL)
+ g_object_unref (pclient->priv->parent);
+
+ /* It is allowed for the parent to be NULL when the instance is created, but
+ * changing the parent requires a valid parent stream */
+ pclient->priv->parent = g_object_ref (parent);
- return PULSE_CLIENT_STREAM_GET_CLASS (client)->set_parent (client, parent);
+ g_object_notify (G_OBJECT (client), "parent");
+ return TRUE;
}
static gboolean
-client_stream_remove (MateMixerClientStream *client)
+pulse_client_stream_remove (MateMixerClientStream *client)
{
+ PulseClientStream *pclient;
+ PulseClientStreamClass *klass;
+
g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), FALSE);
- return PULSE_CLIENT_STREAM_GET_CLASS (client)->remove (client);
+ pclient = PULSE_CLIENT_STREAM (client);
+ klass = PULSE_CLIENT_STREAM_GET_CLASS (pclient);
+
+ if (klass->remove (pclient) == FALSE)
+ return FALSE;
+
+ // XXX handle this in the backend
+ g_signal_emit (G_OBJECT (client),
+ signals[REMOVED],
+ 0);
+
+ return TRUE;
}
static const gchar *
-client_stream_get_app_name (MateMixerClientStream *client)
+pulse_client_stream_get_app_name (MateMixerClientStream *client)
{
g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
@@ -277,7 +392,7 @@ client_stream_get_app_name (MateMixerClientStream *client)
}
static const gchar *
-client_stream_get_app_id (MateMixerClientStream *client)
+pulse_client_stream_get_app_id (MateMixerClientStream *client)
{
g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
@@ -285,7 +400,7 @@ client_stream_get_app_id (MateMixerClientStream *client)
}
static const gchar *
-client_stream_get_app_version (MateMixerClientStream *client)
+pulse_client_stream_get_app_version (MateMixerClientStream *client)
{
g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
@@ -293,7 +408,7 @@ client_stream_get_app_version (MateMixerClientStream *client)
}
static const gchar *
-client_stream_get_app_icon (MateMixerClientStream *client)
+pulse_client_stream_get_app_icon (MateMixerClientStream *client)
{
g_return_val_if_fail (PULSE_IS_CLIENT_STREAM (client), NULL);
diff --git a/backends/pulse/pulse-client-stream.h b/backends/pulse/pulse-client-stream.h
index 61e9c4d..fe24dc3 100644
--- a/backends/pulse/pulse-client-stream.h
+++ b/backends/pulse/pulse-client-stream.h
@@ -22,6 +22,7 @@
#include <glib-object.h>
#include <libmatemixer/matemixer-client-stream.h>
+#include <libmatemixer/matemixer-enums.h>
#include <libmatemixer/matemixer-stream.h>
#include "pulse-stream.h"
@@ -57,24 +58,36 @@ struct _PulseClientStreamClass
{
PulseStreamClass parent_class;
- gboolean (*set_parent) (MateMixerClientStream *client,
- MateMixerStream *stream);
- gboolean (*remove) (MateMixerClientStream *client);
+ /*< private >*/
+ /* Virtual table */
+ gboolean (*set_parent) (PulseClientStream *pclient,
+ PulseStream *pstream);
+
+ gboolean (*remove) (PulseClientStream *pclient);
+
+ /* Signals */
+ void (*removed) (PulseClientStream *pclient);
};
GType pulse_client_stream_get_type (void) G_GNUC_CONST;
-gboolean pulse_client_stream_update_parent (PulseClientStream *client,
- MateMixerStream *parent);
-
-gboolean pulse_client_stream_update_app_name (PulseClientStream *client,
- const gchar *app_name);
-gboolean pulse_client_stream_update_app_id (PulseClientStream *client,
- const gchar *app_id);
-gboolean pulse_client_stream_update_app_version (PulseClientStream *client,
- const gchar *app_version);
-gboolean pulse_client_stream_update_app_icon (PulseClientStream *client,
- const gchar *app_icon);
+gboolean pulse_client_stream_update_flags (PulseClientStream *pclient,
+ MateMixerClientStreamFlags flags);
+
+gboolean pulse_client_stream_update_role (PulseClientStream *pclient,
+ MateMixerClientStreamRole role);
+
+gboolean pulse_client_stream_update_parent (PulseClientStream *pclient,
+ MateMixerStream *parent);
+
+gboolean pulse_client_stream_update_app_name (PulseClientStream *pclient,
+ const gchar *app_name);
+gboolean pulse_client_stream_update_app_id (PulseClientStream *pclient,
+ const gchar *app_id);
+gboolean pulse_client_stream_update_app_version (PulseClientStream *pclient,
+ const gchar *app_version);
+gboolean pulse_client_stream_update_app_icon (PulseClientStream *pclient,
+ const gchar *app_icon);
G_END_DECLS
diff --git a/backends/pulse/pulse-connection.c b/backends/pulse/pulse-connection.c
index 9002f09..cc39caf 100644
--- a/backends/pulse/pulse-connection.c
+++ b/backends/pulse/pulse-connection.c
@@ -15,13 +15,14 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#include <unistd.h>
+#include <sys/types.h>
#include <glib.h>
#include <glib-object.h>
-#include <sys/types.h>
-#include <unistd.h>
#include <pulse/pulseaudio.h>
#include <pulse/glib-mainloop.h>
+#include <pulse/ext-stream-restore.h>
#include "pulse-connection.h"
#include "pulse-enums.h"
@@ -35,6 +36,8 @@ struct _PulseConnectionPrivate
pa_context *context;
pa_proplist *proplist;
pa_glib_mainloop *mainloop;
+ gboolean ext_streams_loading;
+ gboolean ext_streams_dirty;
PulseConnectionState state;
};
@@ -59,6 +62,9 @@ enum {
SINK_INPUT_REMOVED,
SOURCE_OUTPUT_INFO,
SOURCE_OUTPUT_REMOVED,
+ EXT_STREAM_LOADING,
+ EXT_STREAM_LOADED,
+ EXT_STREAM_INFO,
N_SIGNALS
};
@@ -80,47 +86,53 @@ 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 gchar *create_app_name (void);
+
+static gboolean load_lists (PulseConnection *connection);
+static gboolean load_list_finished (PulseConnection *connection);
+
+static void pulse_state_cb (pa_context *c,
+ void *userdata);
+static void pulse_subscribe_cb (pa_context *c,
+ pa_subscription_event_type_t t,
+ uint32_t idx,
+ void *userdata);
+
+static void pulse_restore_subscribe_cb (pa_context *c,
+ void *userdata);
+static void pulse_server_info_cb (pa_context *c,
+ const pa_server_info *info,
+ void *userdata);
+static void pulse_card_info_cb (pa_context *c,
+ const pa_card_info *info,
+ int eol,
+ void *userdata);
+static void pulse_sink_info_cb (pa_context *c,
+ const pa_sink_info *info,
+ int eol,
+ void *userdata);
+static void pulse_source_info_cb (pa_context *c,
+ const pa_source_info *info,
+ int eol,
+ void *userdata);
+static void pulse_sink_input_info_cb (pa_context *c,
+ const pa_sink_input_info *info,
+ int eol,
+ void *userdata);
+static void pulse_source_output_info_cb (pa_context *c,
+ const pa_source_output_info *info,
+ int eol,
+ void *userdata);
+static void pulse_ext_stream_restore_cb (pa_context *c,
+ const pa_ext_stream_restore_info *info,
+ int eol,
+ void *userdata);
+
+static void change_state (PulseConnection *connection,
+ PulseConnectionState state);
+
+static gboolean process_pulse_operation (PulseConnection *connection,
+ pa_operation *op);
static void
pulse_connection_class_init (PulseConnectionClass *klass)
@@ -150,6 +162,8 @@ pulse_connection_class_init (PulseConnectionClass *klass)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
signals[SERVER_INFO] =
g_signal_new ("server-info",
G_TYPE_FROM_CLASS (object_class),
@@ -282,7 +296,41 @@ pulse_connection_class_init (PulseConnectionClass *klass)
1,
G_TYPE_UINT);
- g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+ signals[EXT_STREAM_LOADING] =
+ g_signal_new ("ext-stream-loading",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, ext_stream_loading),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0,
+ G_TYPE_NONE);
+
+ signals[EXT_STREAM_LOADED] =
+ g_signal_new ("ext-stream-loaded",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, ext_stream_loaded),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0,
+ G_TYPE_NONE);
+
+ signals[EXT_STREAM_INFO] =
+ g_signal_new ("ext-stream-info",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PulseConnectionClass, ext_stream_info),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
g_type_class_add_private (object_class, sizeof (PulseConnectionPrivate));
}
@@ -382,7 +430,7 @@ pulse_connection_new (const gchar *app_name,
pa_proplist_sets (proplist, PA_PROP_APPLICATION_NAME, app_name);
} else {
/* Set a sensible default name when application does not provide one */
- gchar *name = connection_get_app_name ();
+ gchar *name = create_app_name ();
pa_proplist_sets (proplist, PA_PROP_APPLICATION_NAME, name);
g_free (name);
@@ -427,9 +475,9 @@ pulse_connection_connect (PulseConnection *connection, gboolean wait_for_daemon)
/* Set function to monitor status changes */
pa_context_set_state_callback (context,
- connection_state_cb,
+ pulse_state_cb,
connection);
- if (wait_for_daemon)
+ if (wait_for_daemon == TRUE)
flags = PA_CONTEXT_NOFAIL;
/* Initiate a connection, state changes will be delivered asynchronously */
@@ -438,7 +486,7 @@ pulse_connection_connect (PulseConnection *connection, gboolean wait_for_daemon)
flags,
NULL) == 0) {
connection->priv->context = context;
- connection_change_state (connection, PULSE_CONNECTION_CONNECTING);
+ change_state (connection, PULSE_CONNECTION_CONNECTING);
return TRUE;
}
@@ -458,8 +506,10 @@ pulse_connection_disconnect (PulseConnection *connection)
connection->priv->context = NULL;
connection->priv->outstanding = 0;
+ connection->priv->ext_streams_loading = FALSE;
+ connection->priv->ext_streams_dirty = FALSE;
- connection_change_state (connection, PULSE_CONNECTION_DISCONNECTED);
+ change_state (connection, PULSE_CONNECTION_DISCONNECTED);
}
PulseConnectionState
@@ -470,6 +520,248 @@ pulse_connection_get_state (PulseConnection *connection)
return connection->priv->state;
}
+gboolean
+pulse_connection_load_server_info (PulseConnection *connection)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ if (connection->priv->state != PULSE_CONNECTION_LOADING &&
+ connection->priv->state != PULSE_CONNECTION_CONNECTED)
+ return FALSE;
+
+ op = pa_context_get_server_info (connection->priv->context,
+ pulse_server_info_cb,
+ connection);
+
+ return process_pulse_operation (connection, op);
+}
+
+gboolean
+pulse_connection_load_card_info (PulseConnection *connection, guint32 index)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ if (connection->priv->state != PULSE_CONNECTION_LOADING &&
+ connection->priv->state != PULSE_CONNECTION_CONNECTED)
+ return FALSE;
+
+ if (index == PA_INVALID_INDEX)
+ op = pa_context_get_card_info_by_index (connection->priv->context,
+ index,
+ pulse_card_info_cb,
+ connection);
+ else
+ op = pa_context_get_card_info_list (connection->priv->context,
+ pulse_card_info_cb,
+ connection);
+
+ return process_pulse_operation (connection, op);
+}
+
+gboolean
+pulse_connection_load_card_info_name (PulseConnection *connection, const gchar *name)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ if (connection->priv->state != PULSE_CONNECTION_LOADING &&
+ connection->priv->state != PULSE_CONNECTION_CONNECTED)
+ return FALSE;
+
+ op = pa_context_get_card_info_by_name (connection->priv->context,
+ name,
+ pulse_card_info_cb,
+ connection);
+
+ return process_pulse_operation (connection, op);
+}
+
+gboolean
+pulse_connection_load_sink_info (PulseConnection *connection, guint32 index)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ if (connection->priv->state != PULSE_CONNECTION_LOADING &&
+ connection->priv->state != PULSE_CONNECTION_CONNECTED)
+ return FALSE;
+
+ if (index == PA_INVALID_INDEX)
+ op = pa_context_get_sink_info_by_index (connection->priv->context,
+ index,
+ pulse_sink_info_cb,
+ connection);
+ else
+ op = pa_context_get_sink_info_list (connection->priv->context,
+ pulse_sink_info_cb,
+ connection);
+
+ return process_pulse_operation (connection, op);
+}
+
+gboolean
+pulse_connection_load_sink_info_name (PulseConnection *connection, const gchar *name)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ if (connection->priv->state != PULSE_CONNECTION_LOADING &&
+ connection->priv->state != PULSE_CONNECTION_CONNECTED)
+ return FALSE;
+
+ op = pa_context_get_sink_info_by_name (connection->priv->context,
+ name,
+ pulse_sink_info_cb,
+ connection);
+
+ return process_pulse_operation (connection, op);
+}
+
+gboolean
+pulse_connection_load_sink_input_info (PulseConnection *connection, guint32 index)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ if (connection->priv->state != PULSE_CONNECTION_LOADING &&
+ connection->priv->state != PULSE_CONNECTION_CONNECTED)
+ return FALSE;
+
+ if (index == PA_INVALID_INDEX)
+ op = pa_context_get_sink_input_info (connection->priv->context,
+ index,
+ pulse_sink_input_info_cb,
+ connection);
+ else
+ op = pa_context_get_sink_input_info_list (connection->priv->context,
+ pulse_sink_input_info_cb,
+ connection);
+
+ return process_pulse_operation (connection, op);
+}
+
+gboolean
+pulse_connection_load_source_info (PulseConnection *connection, guint32 index)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ if (connection->priv->state != PULSE_CONNECTION_LOADING &&
+ connection->priv->state != PULSE_CONNECTION_CONNECTED)
+ return FALSE;
+
+ if (index == PA_INVALID_INDEX)
+ op = pa_context_get_source_info_by_index (connection->priv->context,
+ index,
+ pulse_source_info_cb,
+ connection);
+ else
+ op = pa_context_get_source_info_list (connection->priv->context,
+ pulse_source_info_cb,
+ connection);
+
+ return process_pulse_operation (connection, op);
+}
+
+gboolean
+pulse_connection_load_source_info_name (PulseConnection *connection, const gchar *name)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ if (connection->priv->state != PULSE_CONNECTION_LOADING &&
+ connection->priv->state != PULSE_CONNECTION_CONNECTED)
+ return FALSE;
+
+ op = pa_context_get_source_info_by_name (connection->priv->context,
+ name,
+ pulse_source_info_cb,
+ connection);
+
+ return process_pulse_operation (connection, op);
+}
+
+gboolean
+pulse_connection_load_source_output_info (PulseConnection *connection, guint32 index)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ if (connection->priv->state != PULSE_CONNECTION_LOADING &&
+ connection->priv->state != PULSE_CONNECTION_CONNECTED)
+ return FALSE;
+
+ if (index == PA_INVALID_INDEX)
+ op = pa_context_get_source_output_info (connection->priv->context,
+ index,
+ pulse_source_output_info_cb,
+ connection);
+ else
+ op = pa_context_get_source_output_info_list (connection->priv->context,
+ pulse_source_output_info_cb,
+ connection);
+
+ return process_pulse_operation (connection, op);
+}
+
+gboolean
+pulse_connection_load_ext_stream_info (PulseConnection *connection)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ if (connection->priv->state != PULSE_CONNECTION_LOADING &&
+ connection->priv->state != PULSE_CONNECTION_CONNECTED)
+ return FALSE;
+
+ /* When we receive a request to load the list of ext-streams, see if
+ * loading is already in progress and if it is, wait until the current
+ * loading finishes.
+ * The PulseBackend class relies on this behaviour to ensure it always
+ * contains a correct list of ext-streams, also PulseAudio always sends
+ * a list of all streams in the database and these requests may arrive
+ * very often, so this also optimizaes the amount of traffic. */
+ if (connection->priv->ext_streams_loading == TRUE) {
+ connection->priv->ext_streams_dirty = TRUE;
+ return TRUE;
+ }
+
+ connection->priv->ext_streams_dirty = FALSE;
+ connection->priv->ext_streams_loading = TRUE;
+ g_signal_emit (G_OBJECT (connection),
+ signals[EXT_STREAM_LOADING],
+ 0);
+
+ op = pa_ext_stream_restore_read (connection->priv->context,
+ pulse_ext_stream_restore_cb,
+ connection);
+
+ if (process_pulse_operation (connection, op) == FALSE) {
+ connection->priv->ext_streams_loading = FALSE;
+
+ g_signal_emit (G_OBJECT (connection),
+ signals[EXT_STREAM_LOADED],
+ 0);
+ return FALSE;
+ }
+ return TRUE;
+}
+
PulseMonitor *
pulse_connection_create_monitor (PulseConnection *connection,
guint32 index_source,
@@ -482,13 +774,11 @@ pulse_connection_create_monitor (PulseConnection *connection,
return pulse_monitor_new (connection->priv->context,
connection->priv->proplist,
+ NULL,
index_source,
index_sink_input);
}
-// XXX watch for some operation failures and eventually reload data
-// to restore the previous state
-
gboolean
pulse_connection_set_default_sink (PulseConnection *connection,
const gchar *name)
@@ -504,7 +794,7 @@ pulse_connection_set_default_sink (PulseConnection *connection,
name,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -522,7 +812,7 @@ pulse_connection_set_default_source (PulseConnection *connection,
name,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -542,7 +832,7 @@ pulse_connection_set_card_profile (PulseConnection *connection,
profile,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -562,7 +852,7 @@ pulse_connection_set_sink_mute (PulseConnection *connection,
(int) mute,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -582,7 +872,7 @@ pulse_connection_set_sink_volume (PulseConnection *connection,
volume,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -602,7 +892,7 @@ pulse_connection_set_sink_port (PulseConnection *connection,
port,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -622,7 +912,7 @@ pulse_connection_set_sink_input_mute (PulseConnection *connection,
(int) mute,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -642,7 +932,7 @@ pulse_connection_set_sink_input_volume (PulseConnection *connection,
volume,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -662,7 +952,7 @@ pulse_connection_set_source_mute (PulseConnection *connection,
(int) mute,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -682,7 +972,7 @@ pulse_connection_set_source_volume (PulseConnection *connection,
volume,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -702,7 +992,7 @@ pulse_connection_set_source_port (PulseConnection *connection,
port,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -723,7 +1013,7 @@ pulse_connection_set_source_output_mute (PulseConnection *connection,
(int) mute,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
#else
return FALSE;
#endif
@@ -747,7 +1037,7 @@ pulse_connection_set_source_output_volume (PulseConnection *connection,
volume,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
#else
return FALSE;
#endif
@@ -770,7 +1060,7 @@ pulse_connection_suspend_sink (PulseConnection *connection,
(int) suspend,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -790,7 +1080,7 @@ pulse_connection_suspend_source (PulseConnection *connection,
(int) suspend,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -810,7 +1100,7 @@ pulse_connection_move_sink_input (PulseConnection *connection,
sink_index,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -830,7 +1120,7 @@ pulse_connection_move_source_output (PulseConnection *connection,
source_index,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -848,7 +1138,7 @@ pulse_connection_kill_sink_input (PulseConnection *connection,
index,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
}
gboolean
@@ -866,14 +1156,59 @@ pulse_connection_kill_source_output (PulseConnection *connection,
index,
NULL, NULL);
- return connection_process_operation (connection, op);
+ return process_pulse_operation (connection, op);
+}
+
+gboolean
+pulse_connection_write_ext_stream (PulseConnection *connection,
+ const pa_ext_stream_restore_info *info)
+{
+ pa_operation *op;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
+ return FALSE;
+
+ op = pa_ext_stream_restore_write (connection->priv->context,
+ PA_UPDATE_REPLACE,
+ info, 1,
+ TRUE,
+ NULL, NULL);
+
+ return process_pulse_operation (connection, op);
+}
+
+gboolean
+pulse_connection_delete_ext_stream (PulseConnection *connection,
+ const gchar *name)
+{
+ pa_operation *op;
+ gchar **names;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), FALSE);
+
+ if (connection->priv->state != PULSE_CONNECTION_CONNECTED)
+ return FALSE;
+
+ names = g_new (gchar *, 2);
+ names[0] = (gchar *) name;
+ names[1] = NULL;
+
+ op = pa_ext_stream_restore_delete (connection->priv->context,
+ (const char * const *) names,
+ NULL, NULL);
+
+ g_strfreev (names);
+
+ return process_pulse_operation (connection, op);
}
static gchar *
-connection_get_app_name (void)
+create_app_name (void)
{
- const char *name_app;
- char name_buf[256];
+ const gchar *name_app;
+ char name_buf[256];
/* Inspired by GStreamer's pulse plugin */
name_app = g_get_application_name ();
@@ -887,9 +1222,9 @@ connection_get_app_name (void)
}
static gboolean
-connection_load_lists (PulseConnection *connection)
+load_lists (PulseConnection *connection)
{
- GList *ops = NULL;
+ GSList *ops = NULL;
pa_operation *op;
if (G_UNLIKELY (connection->priv->outstanding > 0)) {
@@ -898,60 +1233,95 @@ connection_load_lists (PulseConnection *connection)
}
op = pa_context_get_card_info_list (connection->priv->context,
- connection_card_info_cb,
+ pulse_card_info_cb,
connection);
if (G_UNLIKELY (op == NULL))
goto error;
- ops = g_list_prepend (ops, op);
+ ops = g_slist_prepend (ops, op);
op = pa_context_get_sink_info_list (connection->priv->context,
- connection_sink_info_cb,
+ pulse_sink_info_cb,
connection);
if (G_UNLIKELY (op == NULL))
goto error;
- ops = g_list_prepend (ops, op);
+ ops = g_slist_prepend (ops, op);
op = pa_context_get_sink_input_info_list (connection->priv->context,
- connection_sink_input_info_cb,
+ pulse_sink_input_info_cb,
connection);
if (G_UNLIKELY (op == NULL))
goto error;
- ops = g_list_prepend (ops, op);
+ ops = g_slist_prepend (ops, op);
op = pa_context_get_source_info_list (connection->priv->context,
- connection_source_info_cb,
+ pulse_source_info_cb,
connection);
if (G_UNLIKELY (op == NULL))
goto error;
- ops = g_list_prepend (ops, op);
+ ops = g_slist_prepend (ops, op);
op = pa_context_get_source_output_info_list (connection->priv->context,
- connection_source_output_info_cb,
+ pulse_source_output_info_cb,
connection);
if (G_UNLIKELY (op == NULL))
goto error;
- ops = g_list_prepend (ops, op);
-
- g_list_foreach (ops, (GFunc) pa_operation_unref, NULL);
- g_list_free (ops);
+ ops = g_slist_prepend (ops, op);
connection->priv->outstanding = 5;
+
+ /* This might not always be supported */
+ op = pa_ext_stream_restore_read (connection->priv->context,
+ pulse_ext_stream_restore_cb,
+ connection);
+ if (op != NULL) {
+ ops = g_slist_prepend (ops, op);
+ connection->priv->outstanding++;
+ }
+
+ g_slist_foreach (ops, (GFunc) pa_operation_unref, NULL);
+ g_slist_free (ops);
+
return TRUE;
error:
- g_list_foreach (ops, (GFunc) pa_operation_cancel, NULL);
- g_list_foreach (ops, (GFunc) pa_operation_unref, NULL);
- g_list_free (ops);
+ g_slist_foreach (ops, (GFunc) pa_operation_cancel, NULL);
+ g_slist_foreach (ops, (GFunc) pa_operation_unref, NULL);
+ g_slist_free (ops);
return FALSE;
}
+static gboolean
+load_list_finished (PulseConnection *connection)
+{
+ /* Decrement the number of outstanding requests as a list has just been
+ * downloaded; when the number reaches 0, server information is requested
+ * as the final step in the connection process */
+ connection->priv->outstanding--;
+
+ if (G_UNLIKELY (connection->priv->outstanding < 0)) {
+ g_warn_if_reached ();
+ connection->priv->outstanding = 0;
+ }
+
+ if (connection->priv->outstanding == 0) {
+ gboolean ret = pulse_connection_load_server_info (connection);
+
+ if (G_UNLIKELY (ret == FALSE)) {
+ pulse_connection_disconnect (connection);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
static void
-connection_state_cb (pa_context *c, void *userdata)
+pulse_state_cb (pa_context *c, void *userdata)
{
PulseConnection *connection;
pa_context_state_t state;
@@ -971,6 +1341,20 @@ connection_state_cb (pa_context *c, void *userdata)
/* We are connected, let's subscribe to notifications and load the
* initial lists */
+ pa_context_set_subscribe_callback (connection->priv->context,
+ pulse_subscribe_cb,
+ connection);
+ pa_ext_stream_restore_set_subscribe_cb (connection->priv->context,
+ pulse_restore_subscribe_cb,
+ connection);
+
+ op = pa_ext_stream_restore_subscribe (connection->priv->context,
+ TRUE,
+ NULL, NULL);
+
+ /* Keep going if this operation fails */
+ process_pulse_operation (connection, op);
+
op = pa_context_subscribe (connection->priv->context,
PA_SUBSCRIPTION_MASK_SERVER |
PA_SUBSCRIPTION_MASK_CARD |
@@ -979,26 +1363,14 @@ connection_state_cb (pa_context *c, void *userdata)
PA_SUBSCRIPTION_MASK_SINK_INPUT |
PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT,
NULL, NULL);
- if (op != NULL) {
- pa_context_set_subscribe_callback (connection->priv->context,
- connection_subscribe_cb,
- connection);
- pa_operation_unref (op);
-
- if (connection_load_lists (connection) == TRUE) {
- connection_change_state (connection, PULSE_CONNECTION_LOADING);
- return;
- }
- /* Treat as a connection failure */
- state = PA_CONTEXT_FAILED;
- } else {
- g_warning ("Failed to subscribe to PulseAudio notifications: %s",
- pa_strerror (pa_context_errno (connection->priv->context)));
+ if (process_pulse_operation (connection, op) == TRUE) {
+ change_state (connection, PULSE_CONNECTION_LOADING);
- /* Treat as a connection failure */
+ if (load_lists (connection) == FALSE)
+ state = PA_CONTEXT_FAILED;
+ } else
state = PA_CONTEXT_FAILED;
- }
}
if (state == PA_CONTEXT_TERMINATED || state == PA_CONTEXT_FAILED) {
@@ -1008,105 +1380,93 @@ connection_state_cb (pa_context *c, void *userdata)
}
if (state == PA_CONTEXT_CONNECTING)
- connection_change_state (connection, PULSE_CONNECTION_CONNECTING);
+ change_state (connection, PULSE_CONNECTION_CONNECTING);
else if (state == PA_CONTEXT_AUTHORIZING ||
state == PA_CONTEXT_SETTING_NAME)
- connection_change_state (connection, PULSE_CONNECTION_AUTHORIZING);
+ change_state (connection, PULSE_CONNECTION_AUTHORIZING);
}
static void
-connection_subscribe_cb (pa_context *c,
- pa_subscription_event_type_t t,
- uint32_t idx,
- void *userdata)
+pulse_subscribe_cb (pa_context *c,
+ pa_subscription_event_type_t t,
+ uint32_t idx,
+ void *userdata)
{
PulseConnection *connection;
- pa_operation *op;
connection = PULSE_CONNECTION (userdata);
switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
+ case PA_SUBSCRIPTION_EVENT_SERVER:
+ pulse_connection_load_server_info (connection);
+ break;
+
case PA_SUBSCRIPTION_EVENT_CARD:
- if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
g_signal_emit (G_OBJECT (connection),
signals[CARD_REMOVED],
0,
idx);
- } else {
- op = pa_context_get_card_info_by_index (connection->priv->context,
- idx,
- connection_card_info_cb,
- connection);
- connection_process_operation (connection, op);
- }
+ else
+ pulse_connection_load_card_info (connection, idx);
break;
case PA_SUBSCRIPTION_EVENT_SINK:
- if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
g_signal_emit (G_OBJECT (connection),
signals[SINK_REMOVED],
0,
idx);
- } else {
- op = pa_context_get_sink_info_by_index (connection->priv->context,
- idx,
- connection_sink_info_cb,
- connection);
- connection_process_operation (connection, op);
- }
+ else
+ pulse_connection_load_sink_info (connection, idx);
break;
case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
- if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
g_signal_emit (G_OBJECT (connection),
signals[SINK_INPUT_REMOVED],
0,
idx);
- } else {
- op = pa_context_get_sink_input_info (connection->priv->context,
- idx,
- connection_sink_input_info_cb,
- connection);
- connection_process_operation (connection, op);
- }
+ else
+ pulse_connection_load_sink_input_info (connection, idx);
break;
case PA_SUBSCRIPTION_EVENT_SOURCE:
- if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
g_signal_emit (G_OBJECT (connection),
signals[SOURCE_REMOVED],
0,
idx);
- } else {
- op = pa_context_get_source_info_by_index (connection->priv->context,
- idx,
- connection_source_info_cb,
- connection);
- connection_process_operation (connection, op);
- }
+ else
+ pulse_connection_load_source_info (connection, idx);
break;
case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
- if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
g_signal_emit (G_OBJECT (connection),
signals[SOURCE_OUTPUT_REMOVED],
0,
idx);
- } else {
- op = pa_context_get_source_output_info (connection->priv->context,
- idx,
- connection_source_output_info_cb,
- connection);
- connection_process_operation (connection, op);
- }
+ else
+ pulse_connection_load_source_output_info (connection, idx);
break;
}
}
static void
-connection_server_info_cb (pa_context *c,
- const pa_server_info *info,
- void *userdata)
+pulse_restore_subscribe_cb (pa_context *c, void *userdata)
+{
+ PulseConnection *connection;
+
+ connection = PULSE_CONNECTION (userdata);
+
+ pulse_connection_load_ext_stream_info (connection);
+}
+
+static void
+pulse_server_info_cb (pa_context *c,
+ const pa_server_info *info,
+ void *userdata)
{
PulseConnection *connection;
@@ -1120,14 +1480,14 @@ connection_server_info_cb (pa_context *c,
/* 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);
+ change_state (connection, PULSE_CONNECTION_CONNECTED);
}
static void
-connection_card_info_cb (pa_context *c,
- const pa_card_info *info,
- int eol,
- void *userdata)
+pulse_card_info_cb (pa_context *c,
+ const pa_card_info *info,
+ int eol,
+ void *userdata)
{
PulseConnection *connection;
@@ -1135,7 +1495,7 @@ connection_card_info_cb (pa_context *c,
if (eol) {
if (connection->priv->state == PULSE_CONNECTION_LOADING)
- connection_list_loaded (connection);
+ load_list_finished (connection);
return;
}
@@ -1146,10 +1506,10 @@ connection_card_info_cb (pa_context *c,
}
static void
-connection_sink_info_cb (pa_context *c,
- const pa_sink_info *info,
- int eol,
- void *userdata)
+pulse_sink_info_cb (pa_context *c,
+ const pa_sink_info *info,
+ int eol,
+ void *userdata)
{
PulseConnection *connection;
@@ -1157,7 +1517,7 @@ connection_sink_info_cb (pa_context *c,
if (eol) {
if (connection->priv->state == PULSE_CONNECTION_LOADING)
- connection_list_loaded (connection);
+ load_list_finished (connection);
return;
}
@@ -1168,10 +1528,10 @@ connection_sink_info_cb (pa_context *c,
}
static void
-connection_sink_input_info_cb (pa_context *c,
- const pa_sink_input_info *info,
- int eol,
- void *userdata)
+pulse_sink_input_info_cb (pa_context *c,
+ const pa_sink_input_info *info,
+ int eol,
+ void *userdata)
{
PulseConnection *connection;
@@ -1179,7 +1539,7 @@ connection_sink_input_info_cb (pa_context *c,
if (eol) {
if (connection->priv->state == PULSE_CONNECTION_LOADING)
- connection_list_loaded (connection);
+ load_list_finished (connection);
return;
}
@@ -1190,10 +1550,10 @@ connection_sink_input_info_cb (pa_context *c,
}
static void
-connection_source_info_cb (pa_context *c,
- const pa_source_info *info,
- int eol,
- void *userdata)
+pulse_source_info_cb (pa_context *c,
+ const pa_source_info *info,
+ int eol,
+ void *userdata)
{
PulseConnection *connection;
@@ -1201,7 +1561,7 @@ connection_source_info_cb (pa_context *c,
if (eol) {
if (connection->priv->state == PULSE_CONNECTION_LOADING)
- connection_list_loaded (connection);
+ load_list_finished (connection);
return;
}
@@ -1212,10 +1572,10 @@ connection_source_info_cb (pa_context *c,
}
static void
-connection_source_output_info_cb (pa_context *c,
- const pa_source_output_info *info,
- int eol,
- void *userdata)
+pulse_source_output_info_cb (pa_context *c,
+ const pa_source_output_info *info,
+ int eol,
+ void *userdata)
{
PulseConnection *connection;
@@ -1223,7 +1583,7 @@ connection_source_output_info_cb (pa_context *c,
if (eol) {
if (connection->priv->state == PULSE_CONNECTION_LOADING)
- connection_list_loaded (connection);
+ load_list_finished (connection);
return;
}
@@ -1234,43 +1594,51 @@ connection_source_output_info_cb (pa_context *c,
}
static void
-connection_change_state (PulseConnection *connection, PulseConnectionState state)
+pulse_ext_stream_restore_cb (pa_context *c,
+ const pa_ext_stream_restore_info *info,
+ int eol,
+ void *userdata)
{
- if (connection->priv->state == state)
- return;
+ PulseConnection *connection;
- connection->priv->state = state;
+ connection = PULSE_CONNECTION (userdata);
- g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
-}
+ if (eol) {
+ connection->priv->ext_streams_loading = FALSE;
+ g_signal_emit (G_OBJECT (connection),
+ signals[EXT_STREAM_LOADED],
+ 0);
-static void
-connection_list_loaded (PulseConnection *connection)
-{
- /* Decrement the number of outstanding requests as a list has just been
- * downloaded; when the number reaches 0, server information is requested
- * as the final step in the connection process */
- connection->priv->outstanding--;
+ if (connection->priv->state == PULSE_CONNECTION_LOADING) {
+ if (load_list_finished (connection) == FALSE)
+ return;
+ }
- if (G_UNLIKELY (connection->priv->outstanding < 0)) {
- g_warn_if_reached ();
- connection->priv->outstanding = 0;
+ if (connection->priv->ext_streams_dirty == TRUE)
+ pulse_connection_load_ext_stream_info (connection);
+
+ return;
}
- if (connection->priv->outstanding == 0) {
- pa_operation *op;
+ g_signal_emit (G_OBJECT (connection),
+ signals[EXT_STREAM_INFO],
+ 0,
+ info);
+}
+
+static void
+change_state (PulseConnection *connection, PulseConnectionState state)
+{
+ if (connection->priv->state == state)
+ return;
- op = pa_context_get_server_info (connection->priv->context,
- connection_server_info_cb,
- connection);
+ connection->priv->state = state;
- if (G_UNLIKELY (connection_process_operation (connection, op) == FALSE))
- pulse_connection_disconnect (connection);
- }
+ g_object_notify_by_pspec (G_OBJECT (connection), properties[PROP_STATE]);
}
static gboolean
-connection_process_operation (PulseConnection *connection, pa_operation *op)
+process_pulse_operation (PulseConnection *connection, pa_operation *op)
{
if (G_UNLIKELY (op == NULL)) {
g_warning ("PulseAudio operation failed: %s",
diff --git a/backends/pulse/pulse-connection.h b/backends/pulse/pulse-connection.h
index ae7b3d3..b9119fd 100644
--- a/backends/pulse/pulse-connection.h
+++ b/backends/pulse/pulse-connection.h
@@ -22,6 +22,7 @@
#include <glib-object.h>
#include <pulse/pulseaudio.h>
+#include <pulse/ext-stream-restore.h>
#include "pulse-enums.h"
#include "pulse-monitor.h"
@@ -57,110 +58,152 @@ struct _PulseConnectionClass
{
GObjectClass parent_class;
+ /*< private >*/
/* 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);
+ 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);
+
+ void (*ext_stream_loading) (PulseConnection *connection);
+ void (*ext_stream_loaded) (PulseConnection *connection);
+ void (*ext_stream_info) (PulseConnection *connection,
+ const pa_ext_stream_restore_info *info);
};
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,
- gboolean wait_for_daemon);
-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);
+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,
+ gboolean wait_for_daemon);
+void pulse_connection_disconnect (PulseConnection *connection);
+
+PulseConnectionState pulse_connection_get_state (PulseConnection *connection);
+
+gboolean pulse_connection_load_server_info (PulseConnection *connection);
+
+gboolean pulse_connection_load_card_info (PulseConnection *connection,
+ guint32 index);
+gboolean pulse_connection_load_card_info_name (PulseConnection *connection,
+ const gchar *name);
+
+gboolean pulse_connection_load_sink_info (PulseConnection *connection,
+ guint32 index);
+gboolean pulse_connection_load_sink_info_name (PulseConnection *connection,
+ const gchar *name);
+
+gboolean pulse_connection_load_sink_input_info (PulseConnection *connection,
+ guint32 index);
+
+gboolean pulse_connection_load_source_info (PulseConnection *connection,
+ guint32 index);
+gboolean pulse_connection_load_source_info_name (PulseConnection *connection,
+ const gchar *name);
+
+gboolean pulse_connection_load_source_output_info (PulseConnection *connection,
+ guint32 index);
+
+gboolean pulse_connection_load_ext_stream_info (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);
+
+gboolean pulse_connection_write_ext_stream (PulseConnection *connection,
+ const pa_ext_stream_restore_info *info);
+
+gboolean pulse_connection_delete_ext_stream (PulseConnection *connection,
+ const gchar *name);
G_END_DECLS
diff --git a/backends/pulse/pulse-device.c b/backends/pulse/pulse-device.c
index 368d85b..96e06c8 100644
--- a/backends/pulse/pulse-device.c
+++ b/backends/pulse/pulse-device.c
@@ -15,14 +15,16 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#include <string.h>
#include <glib.h>
#include <glib-object.h>
-#include <string.h>
#include <libmatemixer/matemixer-device.h>
#include <libmatemixer/matemixer-device-profile.h>
+#include <libmatemixer/matemixer-device-profile-private.h>
#include <libmatemixer/matemixer-enums.h>
#include <libmatemixer/matemixer-port.h>
+#include <libmatemixer/matemixer-port-private.h>
#include <pulse/pulseaudio.h>
@@ -34,27 +36,23 @@ struct _PulseDevicePrivate
guint32 index;
gchar *name;
gchar *description;
- GList *profiles;
- GList *ports;
- GList *streams;
- gboolean streams_sorted;
gchar *icon;
+ GHashTable *ports;
+ GList *ports_list;
+ GHashTable *profiles;
+ GList *profiles_list;
PulseConnection *connection;
MateMixerDeviceProfile *profile;
};
-enum
-{
+enum {
PROP_0,
PROP_NAME,
PROP_DESCRIPTION,
PROP_ICON,
- PROP_PORTS,
- PROP_PROFILES,
PROP_ACTIVE_PROFILE,
PROP_INDEX,
- PROP_CONNECTION,
- N_PROPERTIES
+ PROP_CONNECTION
};
static void mate_mixer_device_interface_init (MateMixerDeviceInterface *iface);
@@ -78,35 +76,50 @@ 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);
+#if PA_CHECK_VERSION (5, 0, 0)
+typedef pa_card_profile_info2 _pa_card_profile_info;
+#else
+typedef pa_card_profile_info _pa_card_profile_info;
+#endif
+
+static const gchar * pulse_device_get_name (MateMixerDevice *device);
+static const gchar * pulse_device_get_description (MateMixerDevice *device);
+static const gchar * pulse_device_get_icon (MateMixerDevice *device);
-static const GList * device_list_ports (MateMixerDevice *device);
-static const GList * device_list_profiles (MateMixerDevice *device);
+static MateMixerPort * pulse_device_get_port (MateMixerDevice *device,
+ const gchar *name);
+static MateMixerDeviceProfile *pulse_device_get_profile (MateMixerDevice *device,
+ const gchar *name);
-static MateMixerDeviceProfile *device_get_active_profile (MateMixerDevice *device);
-static gboolean device_set_active_profile (MateMixerDevice *device,
- const gchar *profile);
+static const GList * pulse_device_list_ports (MateMixerDevice *device);
+static const GList * pulse_device_list_profiles (MateMixerDevice *device);
-static gint device_compare_ports (gconstpointer a,
- gconstpointer b);
-static gint device_compare_profiles (gconstpointer a,
- gconstpointer b);
+static MateMixerDeviceProfile *pulse_device_get_active_profile (MateMixerDevice *device);
+static gboolean pulse_device_set_active_profile (MateMixerDevice *device,
+ MateMixerDeviceProfile *profile);
-static void device_free_ports (PulseDevice *device);
-static void device_free_profiles (PulseDevice *device);
+static void update_port (PulseDevice *device,
+ pa_card_port_info *p_info);
+static void update_profile (PulseDevice *device,
+ _pa_card_profile_info *p_info);
+
+static gint compare_ports (gconstpointer a,
+ gconstpointer b);
+static gint compare_profiles (gconstpointer a,
+ gconstpointer b);
static void
mate_mixer_device_interface_init (MateMixerDeviceInterface *iface)
{
- iface->get_name = device_get_name;
- iface->get_description = device_get_description;
- iface->get_icon = device_get_icon;
- iface->list_ports = device_list_ports;
- iface->list_profiles = device_list_profiles;
- iface->get_active_profile = device_get_active_profile;
- iface->set_active_profile = device_set_active_profile;
+ iface->get_name = pulse_device_get_name;
+ iface->get_description = pulse_device_get_description;
+ iface->get_icon = pulse_device_get_icon;
+ iface->get_port = pulse_device_get_port;
+ iface->get_profile = pulse_device_get_profile;
+ iface->list_ports = pulse_device_list_ports;
+ iface->list_profiles = pulse_device_list_profiles;
+ iface->get_active_profile = pulse_device_get_active_profile;
+ iface->set_active_profile = pulse_device_set_active_profile;
}
static void
@@ -144,8 +157,6 @@ pulse_device_class_init (PulseDeviceClass *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_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));
@@ -171,12 +182,6 @@ 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;
@@ -222,6 +227,16 @@ pulse_device_init (PulseDevice *device)
device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
PULSE_TYPE_DEVICE,
PulseDevicePrivate);
+
+ device->priv->ports = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
+
+ device->priv->profiles = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
}
static void
@@ -231,9 +246,19 @@ pulse_device_dispose (GObject *object)
device = PULSE_DEVICE (object);
- device_free_ports (device);
- device_free_profiles (device);
+ if (device->priv->ports_list != NULL) {
+ g_list_free_full (device->priv->ports_list, g_object_unref);
+ device->priv->ports_list = NULL;
+ }
+ g_hash_table_remove_all (device->priv->ports);
+ if (device->priv->profiles_list != NULL) {
+ g_list_free_full (device->priv->profiles_list, g_object_unref);
+ device->priv->profiles_list = NULL;
+ }
+ g_hash_table_remove_all (device->priv->profiles);
+
+ g_clear_object (&device->priv->profile);
g_clear_object (&device->priv->connection);
G_OBJECT_CLASS (pulse_device_parent_class)->dispose (object);
@@ -250,6 +275,9 @@ pulse_device_finalize (GObject *object)
g_free (device->priv->description);
g_free (device->priv->icon);
+ g_hash_table_destroy (device->priv->ports);
+ g_hash_table_destroy (device->priv->profiles);
+
G_OBJECT_CLASS (pulse_device_parent_class)->finalize (object);
}
@@ -276,6 +304,7 @@ pulse_device_new (PulseConnection *connection, const pa_card_info *info)
gboolean
pulse_device_update (PulseDevice *device, const pa_card_info *info)
{
+ MateMixerDeviceProfile *profile = NULL;
const gchar *prop;
guint32 i;
@@ -286,7 +315,7 @@ pulse_device_update (PulseDevice *device, const pa_card_info *info)
g_object_freeze_notify (G_OBJECT (device));
/* Name */
- if (g_strcmp0 (device->priv->name, info->name)) {
+ if (g_strcmp0 (device->priv->name, info->name) != 0) {
g_free (device->priv->name);
device->priv->name = g_strdup (info->name);
@@ -299,7 +328,7 @@ pulse_device_update (PulseDevice *device, const pa_card_info *info)
if (G_UNLIKELY (prop == NULL))
prop = info->name;
- if (g_strcmp0 (device->priv->description, prop)) {
+ if (g_strcmp0 (device->priv->description, prop) != 0) {
g_free (device->priv->description);
device->priv->description = g_strdup (prop);
@@ -312,49 +341,23 @@ pulse_device_update (PulseDevice *device, const pa_card_info *info)
if (G_UNLIKELY (prop == NULL))
prop = "audio-card";
- if (g_strcmp0 (device->priv->icon, prop)) {
+ if (g_strcmp0 (device->priv->icon, prop) != 0) {
g_free (device->priv->icon);
device->priv->icon = g_strdup (prop);
g_object_notify (G_OBJECT (device), "icon");
}
+#if PA_CHECK_VERSION (2, 0, 0)
/* List of ports */
- 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));
+ update_port (device, info->ports[i]);
}
- device->priv->ports = g_list_sort (device->priv->ports, device_compare_ports);
-
- g_object_notify (G_OBJECT (device), "ports");
+#endif
/* List of profiles */
- device_free_profiles (device);
-
for (i = 0; i < info->n_profiles; i++) {
- MateMixerDeviceProfile *profile;
-
-#if PA_CHECK_VERSION(5, 0, 0)
+#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
@@ -366,28 +369,28 @@ pulse_device_update (PulseDevice *device, const pa_card_info *info)
/* The old profile list is an array of structs, not pointers */
pa_card_profile_info *p_info = &info->profiles[i];
#endif
- profile = mate_mixer_device_profile_new (
- p_info->name,
- p_info->description,
- p_info->priority,
- p_info->n_sources,
- p_info->n_sinks);
-
- if (device->priv->profile == NULL) {
-#if PA_CHECK_VERSION(5, 0, 0)
- if (!g_strcmp0 (p_info->name, info->active_profile2->name))
- device->priv->profile = g_object_ref (profile);
+ update_profile (device, p_info);
+ }
+
+ /* Figure out whether the currently active profile has changed */
+ profile = NULL;
+
+#if PA_CHECK_VERSION (5, 0, 0)
+ if (G_LIKELY (info->active_profile2 != NULL))
+ profile = g_hash_table_lookup (device->priv->profiles, info->active_profile2->name);
#else
- if (!g_strcmp0 (p_info->name, info->active_profile->name))
- device->priv->profile = g_object_ref (profile);
+ if (G_LIKELY (info->active_profile != NULL))
+ profile = g_hash_table_lookup (device->priv->profiles, info->active_profile->name);
#endif
- }
- device->priv->profiles = g_list_prepend (device->priv->profiles, profile);
- }
- device->priv->profiles = g_list_sort (device->priv->profiles,
- device_compare_profiles);
- g_object_notify (G_OBJECT (device), "profiles");
+ if (profile != device->priv->profile) {
+ g_clear_object (&device->priv->profile);
+
+ if (G_LIKELY (profile != NULL))
+ device->priv->profile = g_object_ref (profile);
+
+ g_object_notify (G_OBJECT (device), "active-profile");
+ }
g_object_thaw_notify (G_OBJECT (device));
return TRUE;
@@ -410,7 +413,7 @@ pulse_device_get_index (PulseDevice *device)
}
static const gchar *
-device_get_name (MateMixerDevice *device)
+pulse_device_get_name (MateMixerDevice *device)
{
g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
@@ -418,7 +421,7 @@ device_get_name (MateMixerDevice *device)
}
static const gchar *
-device_get_description (MateMixerDevice *device)
+pulse_device_get_description (MateMixerDevice *device)
{
g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
@@ -426,31 +429,77 @@ device_get_description (MateMixerDevice *device)
}
static const gchar *
-device_get_icon (MateMixerDevice *device)
+pulse_device_get_icon (MateMixerDevice *device)
{
g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
return PULSE_DEVICE (device)->priv->icon;
}
+static MateMixerPort *
+pulse_device_get_port (MateMixerDevice *device, const gchar *name)
+{
+ g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ return g_hash_table_lookup (PULSE_DEVICE (device)->priv->ports, name);
+}
+
+static MateMixerDeviceProfile *
+pulse_device_get_profile (MateMixerDevice *device, const gchar *name)
+{
+ g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ return g_hash_table_lookup (PULSE_DEVICE (device)->priv->profiles, name);
+}
+
static const GList *
-device_list_ports (MateMixerDevice *device)
+pulse_device_list_ports (MateMixerDevice *device)
{
+ PulseDevice *pulse;
+
g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
- return (const GList *) PULSE_DEVICE (device)->priv->ports;
+ pulse = PULSE_DEVICE (device);
+
+ if (pulse->priv->ports_list == NULL) {
+ GList *list = g_hash_table_get_values (pulse->priv->ports);
+
+ if (list != NULL) {
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ pulse->priv->ports_list = g_list_sort (list, compare_ports);
+ }
+ }
+
+ return (const GList *) pulse->priv->ports_list;
}
static const GList *
-device_list_profiles (MateMixerDevice *device)
+pulse_device_list_profiles (MateMixerDevice *device)
{
+ PulseDevice *pulse;
+
g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
- return (const GList *) PULSE_DEVICE (device)->priv->profiles;
+ pulse = PULSE_DEVICE (device);
+
+ if (pulse->priv->profiles_list == NULL) {
+ GList *list = g_hash_table_get_values (pulse->priv->profiles);
+
+ if (list != NULL) {
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ pulse->priv->profiles_list = g_list_sort (list, compare_profiles);
+ }
+ }
+
+ return (const GList *) pulse->priv->profiles_list;
}
static MateMixerDeviceProfile *
-device_get_active_profile (MateMixerDevice *device)
+pulse_device_get_active_profile (MateMixerDevice *device)
{
g_return_val_if_fail (PULSE_IS_DEVICE (device), NULL);
@@ -458,18 +507,103 @@ device_get_active_profile (MateMixerDevice *device)
}
static gboolean
-device_set_active_profile (MateMixerDevice *device, const gchar *profile)
+pulse_device_set_active_profile (MateMixerDevice *device, MateMixerDeviceProfile *profile)
{
+ PulseDevice *pulse;
+ const gchar *name;
+ gboolean ret;
+
g_return_val_if_fail (PULSE_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (profile != NULL, FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
+
+ pulse = PULSE_DEVICE (device);
+
+ name = mate_mixer_device_profile_get_name (profile);
+
+ /* Make sure the profile belongs to the device */
+ if (g_hash_table_lookup (pulse->priv->profiles, name) == NULL) {
+ g_warning ("Profile %s does not belong to device %s", name, pulse->priv->name);
+ return FALSE;
+ }
+
+ ret = pulse_connection_set_card_profile (pulse->priv->connection,
+ pulse->priv->name,
+ name);
+ if (ret == TRUE) {
+ if (pulse->priv->profile != NULL)
+ g_object_unref (pulse->priv->profile);
+
+ pulse->priv->profile = g_object_ref (profile);
+
+ g_object_notify (G_OBJECT (device), "active-profile");
+ }
+ return ret;
+}
+
+static void
+update_port (PulseDevice *device, pa_card_port_info *p_info)
+{
+ MateMixerPort *port;
+ MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
+ const gchar *icon;
+
+ icon = pa_proplist_gets (p_info->proplist, "device.icon_name");
+
+ if (p_info->available == PA_PORT_AVAILABLE_YES)
+ flags |= MATE_MIXER_PORT_AVAILABLE;
+
+ if (p_info->direction & PA_DIRECTION_INPUT)
+ flags |= MATE_MIXER_PORT_INPUT;
+ if (p_info->direction & PA_DIRECTION_OUTPUT)
+ flags |= MATE_MIXER_PORT_OUTPUT;
+
+ port = g_hash_table_lookup (device->priv->ports, p_info->name);
+
+ if (port != NULL) {
+ /* Update existing port */
+ _mate_mixer_port_update_description (port, p_info->description);
+ _mate_mixer_port_update_icon (port, icon);
+ _mate_mixer_port_update_priority (port, p_info->priority);
+ _mate_mixer_port_update_flags (port, flags);
+ } else {
+ /* Add previously unknown port to the hash table */
+ port = _mate_mixer_port_new (p_info->name,
+ p_info->description,
+ icon,
+ p_info->priority,
+ flags);
+
+ g_hash_table_insert (device->priv->ports, g_strdup (p_info->name), port);
+ }
+}
+
+static void
+update_profile (PulseDevice *device, _pa_card_profile_info *p_info)
+{
+ MateMixerDeviceProfile *profile;
- return pulse_connection_set_card_profile (PULSE_DEVICE (device)->priv->connection,
- PULSE_DEVICE (device)->priv->name,
- profile);
+ profile = g_hash_table_lookup (device->priv->profiles, p_info->name);
+
+ if (profile != NULL) {
+ /* Update existing profile */
+ _mate_mixer_device_profile_update_description (profile, p_info->description);
+ _mate_mixer_device_profile_update_priority (profile, p_info->priority);
+ _mate_mixer_device_profile_update_num_input_streams (profile, p_info->n_sources);
+ _mate_mixer_device_profile_update_num_output_streams (profile, p_info->n_sinks);
+ } else {
+ /* Add previously unknown profile to the hash table */
+ profile = _mate_mixer_device_profile_new (p_info->name,
+ p_info->description,
+ p_info->priority,
+ p_info->n_sources,
+ p_info->n_sinks);
+
+ g_hash_table_insert (device->priv->profiles, g_strdup (p_info->name), profile);
+ }
}
static gint
-device_compare_ports (gconstpointer a, gconstpointer b)
+compare_ports (gconstpointer a, gconstpointer b)
{
MateMixerPort *p1 = MATE_MIXER_PORT (a);
MateMixerPort *p2 = MATE_MIXER_PORT (b);
@@ -484,7 +618,7 @@ device_compare_ports (gconstpointer a, gconstpointer b)
}
static gint
-device_compare_profiles (gconstpointer a, gconstpointer b)
+compare_profiles (gconstpointer a, gconstpointer b)
{
MateMixerDeviceProfile *p1 = MATE_MIXER_DEVICE_PROFILE (a);
MateMixerDeviceProfile *p2 = MATE_MIXER_DEVICE_PROFILE (b);
@@ -497,27 +631,3 @@ device_compare_profiles (gconstpointer a, gconstpointer b)
return strcmp (mate_mixer_device_profile_get_name (p1),
mate_mixer_device_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);
-
- device->priv->profiles = NULL;
-}
diff --git a/backends/pulse/pulse-ext-stream.c b/backends/pulse/pulse-ext-stream.c
new file mode 100644
index 0000000..96164e8
--- /dev/null
+++ b/backends/pulse/pulse-ext-stream.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libmatemixer/matemixer-client-stream.h>
+#include <libmatemixer/matemixer-enums.h>
+#include <libmatemixer/matemixer-stream.h>
+
+#include <pulse/pulseaudio.h>
+#include <pulse/ext-stream-restore.h>
+
+#include "pulse-connection.h"
+#include "pulse-client-stream.h"
+#include "pulse-ext-stream.h"
+#include "pulse-helpers.h"
+#include "pulse-sink.h"
+#include "pulse-source.h"
+#include "pulse-stream.h"
+
+static void pulse_ext_stream_class_init (PulseExtStreamClass *klass);
+static void pulse_ext_stream_init (PulseExtStream *ext);
+
+G_DEFINE_TYPE (PulseExtStream, pulse_ext_stream, PULSE_TYPE_CLIENT_STREAM);
+
+static void pulse_ext_stream_reload (PulseStream *pstream);
+
+static gboolean pulse_ext_stream_set_mute (PulseStream *pstream,
+ gboolean mute);
+static gboolean pulse_ext_stream_set_volume (PulseStream *pstream,
+ pa_cvolume *cvolume);
+static gboolean pulse_ext_stream_set_parent (PulseClientStream *pclient,
+ PulseStream *parent);
+static gboolean pulse_ext_stream_remove (PulseClientStream *pclient);
+
+static void
+pulse_ext_stream_class_init (PulseExtStreamClass *klass)
+{
+ PulseStreamClass *stream_class;
+ PulseClientStreamClass *client_class;
+
+ stream_class = PULSE_STREAM_CLASS (klass);
+
+ stream_class->reload = pulse_ext_stream_reload;
+ stream_class->set_mute = pulse_ext_stream_set_mute;
+ stream_class->set_volume = pulse_ext_stream_set_volume;
+
+ client_class = PULSE_CLIENT_STREAM_CLASS (klass);
+
+ client_class->set_parent = pulse_ext_stream_set_parent;
+ client_class->remove = pulse_ext_stream_remove;
+}
+
+static void
+pulse_ext_stream_init (PulseExtStream *ext)
+{
+}
+
+PulseStream *
+pulse_ext_stream_new (PulseConnection *connection,
+ const pa_ext_stream_restore_info *info,
+ PulseStream *parent)
+{
+ PulseStream *ext;
+
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
+
+ ext = g_object_new (PULSE_TYPE_EXT_STREAM,
+ "connection", connection,
+ NULL);
+
+ /* Consider the stream name as unchanging parameter */
+ pulse_stream_update_name (ext, info->name);
+
+ /* Other data may change at any time, so let's make a use of our update function */
+ pulse_ext_stream_update (ext, info, parent);
+
+ return ext;
+}
+
+gboolean
+pulse_ext_stream_update (PulseStream *pstream,
+ const pa_ext_stream_restore_info *info,
+ PulseStream *parent)
+{
+ MateMixerClientStreamRole role = MATE_MIXER_CLIENT_STREAM_ROLE_NONE;
+ MateMixerStreamFlags flags = MATE_MIXER_STREAM_CLIENT |
+ MATE_MIXER_STREAM_HAS_VOLUME |
+ MATE_MIXER_STREAM_HAS_MUTE |
+ MATE_MIXER_STREAM_CAN_SET_VOLUME;
+ MateMixerClientStreamFlags client_flags =
+ MATE_MIXER_CLIENT_STREAM_CACHED;
+
+ PulseClientStream *pclient;
+ gchar *suffix;
+
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (pstream), FALSE);
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ pclient = PULSE_CLIENT_STREAM (pstream);
+
+ suffix = strchr (info->name, ':');
+ if (suffix != NULL)
+ suffix++;
+
+ /* Let all the information update before emitting notify signals */
+ g_object_freeze_notify (G_OBJECT (pstream));
+
+ if (g_str_has_prefix (info->name, "sink-input"))
+ flags |= MATE_MIXER_STREAM_OUTPUT;
+ else if (g_str_has_prefix (info->name, "source-output"))
+ flags |= MATE_MIXER_STREAM_INPUT;
+ else
+ g_debug ("Unknown ext-stream %s", info->name);
+
+ if (strstr (info->name, "-by-media-role:")) {
+ if (G_LIKELY (suffix != NULL))
+ role = pulse_convert_media_role_name (suffix);
+ }
+ else if (strstr (info->name, "-by-application-name:")) {
+ client_flags |= MATE_MIXER_CLIENT_STREAM_APPLICATION;
+
+ if (G_LIKELY (suffix != NULL))
+ pulse_client_stream_update_app_name (pclient, suffix);
+ }
+ else if (strstr (info->name, "-by-application-id:")) {
+ client_flags |= MATE_MIXER_CLIENT_STREAM_APPLICATION;
+
+ if (G_LIKELY (suffix != NULL))
+ pulse_client_stream_update_app_id (pclient, suffix);
+ }
+
+ /* Flags needed before volume */
+ pulse_stream_update_flags (pstream, flags);
+
+ pulse_stream_update_channel_map (pstream, &info->channel_map);
+ pulse_stream_update_volume (pstream, &info->volume, 0);
+
+ pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
+
+ pulse_client_stream_update_flags (pclient, client_flags);
+ pulse_client_stream_update_role (pclient, role);
+
+ if (parent != NULL)
+ pulse_client_stream_update_parent (pclient, MATE_MIXER_STREAM (parent));
+ else
+ pulse_client_stream_update_parent (pclient, NULL);
+
+ g_object_thaw_notify (G_OBJECT (pstream));
+ return TRUE;
+}
+
+static void
+pulse_ext_stream_reload (PulseStream *pstream)
+{
+ g_return_if_fail (PULSE_IS_EXT_STREAM (pstream));
+
+ pulse_connection_load_ext_stream_info (pulse_stream_get_connection (pstream));
+}
+
+static gboolean
+pulse_ext_stream_set_mute (PulseStream *pstream, gboolean mute)
+{
+ MateMixerStream *parent;
+ const pa_channel_map *map;
+ const pa_cvolume *cvolume;
+ pa_ext_stream_restore_info info;
+
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (pstream), FALSE);
+
+ info.name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream));
+ info.mute = mute;
+
+ map = pulse_stream_get_channel_map (pstream);
+ if (map != NULL)
+ info.channel_map = *map;
+ else
+ pa_channel_map_init (&info.channel_map);
+
+ cvolume = pulse_stream_get_cvolume (pstream);
+ if (cvolume != NULL)
+ info.volume = *cvolume;
+ else
+ pa_cvolume_init (&info.volume);
+
+ parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (pstream));
+ if (parent != NULL)
+ info.device = mate_mixer_stream_get_name (parent);
+ else
+ info.device = NULL;
+
+ return pulse_connection_write_ext_stream (pulse_stream_get_connection (pstream), &info);
+}
+
+static gboolean
+pulse_ext_stream_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
+{
+ MateMixerStream *parent;
+ const pa_channel_map *map;
+ pa_ext_stream_restore_info info;
+
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (pstream), FALSE);
+ g_return_val_if_fail (cvolume != NULL, FALSE);
+
+ info.name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream));
+ info.mute = mate_mixer_stream_get_mute (MATE_MIXER_STREAM (pstream));
+
+ map = pulse_stream_get_channel_map (pstream);
+ if (map != NULL)
+ info.channel_map = *map;
+ else
+ pa_channel_map_init (&info.channel_map);
+
+ parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (pstream));
+ if (parent != NULL)
+ info.device = mate_mixer_stream_get_name (parent);
+ else
+ info.device = NULL;
+
+ info.volume = *cvolume;
+
+ return pulse_connection_write_ext_stream (pulse_stream_get_connection (pstream), &info);
+}
+
+static gboolean
+pulse_ext_stream_set_parent (PulseClientStream *pclient, PulseStream *parent)
+{
+ MateMixerStreamFlags flags;
+ PulseStream *pstream;
+ const pa_channel_map *map;
+ const pa_cvolume *cvolume;
+ pa_ext_stream_restore_info info;
+
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (pclient), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (parent), FALSE);
+
+ flags = mate_mixer_stream_get_flags (MATE_MIXER_STREAM (pclient));
+
+ /* Validate the parent stream */
+ if (flags & MATE_MIXER_STREAM_INPUT && !PULSE_IS_SOURCE (parent)) {
+ g_warning ("Could not change stream parent to %s: not a parent input stream",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (parent)));
+ return FALSE;
+ } else if (!PULSE_IS_SINK (parent)) {
+ g_warning ("Could not change stream parent to %s: not a parent output stream",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (parent)));
+ return FALSE;
+ }
+
+ pstream = PULSE_STREAM (pclient);
+
+ info.name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream));
+ info.mute = mate_mixer_stream_get_mute (MATE_MIXER_STREAM (pstream));
+
+ map = pulse_stream_get_channel_map (pstream);
+ if (map != NULL)
+ info.channel_map = *map;
+ else
+ pa_channel_map_init (&info.channel_map);
+
+ cvolume = pulse_stream_get_cvolume (pstream);
+ if (cvolume != NULL)
+ info.volume = *cvolume;
+ else
+ pa_cvolume_init (&info.volume);
+
+ info.device = mate_mixer_stream_get_name (MATE_MIXER_STREAM (parent));
+
+ return pulse_connection_write_ext_stream (pulse_stream_get_connection (pstream), &info);
+}
+
+static gboolean
+pulse_ext_stream_remove (PulseClientStream *pclient)
+{
+ PulseStream *pstream;
+ const gchar *name;
+
+ g_return_val_if_fail (PULSE_IS_EXT_STREAM (pclient), FALSE);
+
+ pstream = PULSE_STREAM (pclient);
+ name = mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream));
+
+ return pulse_connection_delete_ext_stream (pulse_stream_get_connection (pstream), name);
+}
diff --git a/backends/pulse/pulse-ext-stream.h b/backends/pulse/pulse-ext-stream.h
new file mode 100644
index 0000000..e8dabb6
--- /dev/null
+++ b/backends/pulse/pulse-ext-stream.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PULSE_EXT_STREAM_H
+#define PULSE_EXT_STREAM_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <pulse/pulseaudio.h>
+#include <pulse/ext-stream-restore.h>
+
+#include "pulse-client-stream.h"
+#include "pulse-connection.h"
+#include "pulse-stream.h"
+
+G_BEGIN_DECLS
+
+#define PULSE_TYPE_EXT_STREAM \
+ (pulse_ext_stream_get_type ())
+#define PULSE_EXT_STREAM(o) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((o), PULSE_TYPE_EXT_STREAM, PulseExtStream))
+#define PULSE_IS_EXT_STREAM(o) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), PULSE_TYPE_EXT_STREAM))
+#define PULSE_EXT_STREAM_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_CAST ((k), PULSE_TYPE_EXT_STREAM, PulseExtStreamClass))
+#define PULSE_IS_EXT_STREAM_CLASS(k) \
+ (G_TYPE_CHECK_CLASS_TYPE ((k), PULSE_TYPE_EXT_STREAM))
+#define PULSE_EXT_STREAM_GET_CLASS(o) \
+ (G_TYPE_INSTANCE_GET_CLASS ((o), PULSE_TYPE_EXT_STREAM, PulseExtStreamClass))
+
+typedef struct _PulseExtStream PulseExtStream;
+typedef struct _PulseExtStreamClass PulseExtStreamClass;
+
+struct _PulseExtStream
+{
+ PulseClientStream parent;
+};
+
+struct _PulseExtStreamClass
+{
+ PulseClientStreamClass parent_class;
+};
+
+GType pulse_ext_stream_get_type (void) G_GNUC_CONST;
+
+PulseStream *pulse_ext_stream_new (PulseConnection *connection,
+ const pa_ext_stream_restore_info *info,
+ PulseStream *parent);
+
+gboolean pulse_ext_stream_update (PulseStream *pstream,
+ const pa_ext_stream_restore_info *info,
+ PulseStream *parent);
+
+G_END_DECLS
+
+#endif /* PULSE_EXT_STREAM_H */
diff --git a/backends/pulse/pulse-helpers.c b/backends/pulse/pulse-helpers.c
index ca39d8f..577f2c6 100644
--- a/backends/pulse/pulse-helpers.c
+++ b/backends/pulse/pulse-helpers.c
@@ -15,9 +15,11 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#include <string.h>
#include <glib.h>
#include <libmatemixer/matemixer-enums.h>
+
#include <pulse/pulseaudio.h>
#include "pulse-helpers.h"
@@ -28,44 +30,44 @@ typedef struct {
} PositionMap;
static PositionMap const position_map[] = {
- { MATE_MIXER_CHANNEL_UNKNOWN_POSITION, PA_CHANNEL_POSITION_INVALID },
- { MATE_MIXER_CHANNEL_MONO, PA_CHANNEL_POSITION_MONO },
- { MATE_MIXER_CHANNEL_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_LEFT },
- { MATE_MIXER_CHANNEL_FRONT_RIGHT, PA_CHANNEL_POSITION_FRONT_RIGHT },
- { MATE_MIXER_CHANNEL_FRONT_CENTER, PA_CHANNEL_POSITION_FRONT_CENTER },
- { MATE_MIXER_CHANNEL_LFE, PA_CHANNEL_POSITION_LFE },
- { MATE_MIXER_CHANNEL_BACK_LEFT, PA_CHANNEL_POSITION_REAR_LEFT },
- { MATE_MIXER_CHANNEL_BACK_RIGHT, PA_CHANNEL_POSITION_REAR_RIGHT },
- { MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER, PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER },
- { MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER, PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER },
- { MATE_MIXER_CHANNEL_BACK_CENTER, PA_CHANNEL_POSITION_REAR_CENTER },
- { MATE_MIXER_CHANNEL_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_LEFT },
- { MATE_MIXER_CHANNEL_SIDE_RIGHT, PA_CHANNEL_POSITION_SIDE_RIGHT },
- { MATE_MIXER_CHANNEL_TOP_FRONT_LEFT, PA_CHANNEL_POSITION_TOP_FRONT_LEFT },
- { MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT, PA_CHANNEL_POSITION_TOP_FRONT_RIGHT },
- { MATE_MIXER_CHANNEL_TOP_FRONT_CENTER, PA_CHANNEL_POSITION_TOP_FRONT_CENTER },
- { MATE_MIXER_CHANNEL_TOP_CENTER, PA_CHANNEL_POSITION_TOP_CENTER },
- { MATE_MIXER_CHANNEL_TOP_BACK_LEFT, PA_CHANNEL_POSITION_TOP_REAR_LEFT },
- { MATE_MIXER_CHANNEL_TOP_BACK_RIGHT, PA_CHANNEL_POSITION_TOP_REAR_RIGHT },
- { MATE_MIXER_CHANNEL_TOP_BACK_CENTER, PA_CHANNEL_POSITION_TOP_REAR_CENTER },
+ { MATE_MIXER_CHANNEL_UNKNOWN, PA_CHANNEL_POSITION_INVALID },
+ { MATE_MIXER_CHANNEL_MONO, PA_CHANNEL_POSITION_MONO },
+ { MATE_MIXER_CHANNEL_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_LEFT },
+ { MATE_MIXER_CHANNEL_FRONT_RIGHT, PA_CHANNEL_POSITION_FRONT_RIGHT },
+ { MATE_MIXER_CHANNEL_FRONT_CENTER, PA_CHANNEL_POSITION_FRONT_CENTER },
+ { MATE_MIXER_CHANNEL_LFE, PA_CHANNEL_POSITION_LFE },
+ { MATE_MIXER_CHANNEL_BACK_LEFT, PA_CHANNEL_POSITION_REAR_LEFT },
+ { MATE_MIXER_CHANNEL_BACK_RIGHT, PA_CHANNEL_POSITION_REAR_RIGHT },
+ { MATE_MIXER_CHANNEL_BACK_CENTER, PA_CHANNEL_POSITION_REAR_CENTER },
+ { MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER, PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER },
+ { MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER, PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER },
+ { MATE_MIXER_CHANNEL_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_LEFT },
+ { MATE_MIXER_CHANNEL_SIDE_RIGHT, PA_CHANNEL_POSITION_SIDE_RIGHT },
+ { MATE_MIXER_CHANNEL_TOP_FRONT_LEFT, PA_CHANNEL_POSITION_TOP_FRONT_LEFT },
+ { MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT, PA_CHANNEL_POSITION_TOP_FRONT_RIGHT },
+ { MATE_MIXER_CHANNEL_TOP_FRONT_CENTER, PA_CHANNEL_POSITION_TOP_FRONT_CENTER },
+ { MATE_MIXER_CHANNEL_TOP_CENTER, PA_CHANNEL_POSITION_TOP_CENTER },
+ { MATE_MIXER_CHANNEL_TOP_BACK_LEFT, PA_CHANNEL_POSITION_TOP_REAR_LEFT },
+ { MATE_MIXER_CHANNEL_TOP_BACK_RIGHT, PA_CHANNEL_POSITION_TOP_REAR_RIGHT },
+ { MATE_MIXER_CHANNEL_TOP_BACK_CENTER, PA_CHANNEL_POSITION_TOP_REAR_CENTER },
};
MateMixerChannelPosition
pulse_convert_position_from_pulse (pa_channel_position_t position)
{
- int i;
+ guint i;
for (i = 0; i < G_N_ELEMENTS (position_map); i++) {
if (position == position_map[i].pa_position)
return position_map[i].mm_position;
}
- return MATE_MIXER_CHANNEL_UNKNOWN_POSITION;
+ return MATE_MIXER_CHANNEL_UNKNOWN;
}
pa_channel_position_t
pulse_convert_position_to_pulse (MateMixerChannelPosition position)
{
- int i;
+ guint i;
for (i = 0; i < G_N_ELEMENTS (position_map); i++) {
if (position == position_map[i].mm_position)
@@ -73,3 +75,43 @@ pulse_convert_position_to_pulse (MateMixerChannelPosition position)
}
return PA_CHANNEL_POSITION_INVALID;
}
+
+MateMixerClientStreamRole
+pulse_convert_media_role_name (const gchar *name)
+{
+ if (!strcmp (name, "video")) {
+ return MATE_MIXER_CLIENT_STREAM_ROLE_VIDEO;
+ }
+ else if (!strcmp (name, "music")) {
+ return MATE_MIXER_CLIENT_STREAM_ROLE_MUSIC;
+ }
+ else if (!strcmp (name, "game")) {
+ return MATE_MIXER_CLIENT_STREAM_ROLE_GAME;
+ }
+ else if (!strcmp (name, "event")) {
+ return MATE_MIXER_CLIENT_STREAM_ROLE_EVENT;
+ }
+ else if (!strcmp (name, "phone")) {
+ return MATE_MIXER_CLIENT_STREAM_ROLE_PHONE;
+ }
+ else if (!strcmp (name, "animation")) {
+ return MATE_MIXER_CLIENT_STREAM_ROLE_ANIMATION;
+ }
+ else if (!strcmp (name, "production")) {
+ return MATE_MIXER_CLIENT_STREAM_ROLE_PRODUCTION;
+ }
+ else if (!strcmp (name, "a11y")) {
+ return MATE_MIXER_CLIENT_STREAM_ROLE_A11Y;
+ }
+ else if (!strcmp (name, "test")) {
+ return MATE_MIXER_CLIENT_STREAM_ROLE_TEST;
+ }
+ else if (!strcmp (name, "abstract")) {
+ return MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT;
+ }
+ else if (!strcmp (name, "filter")) {
+ return MATE_MIXER_CLIENT_STREAM_ROLE_FILTER;
+ }
+
+ return MATE_MIXER_CLIENT_STREAM_ROLE_NONE;
+}
diff --git a/backends/pulse/pulse-helpers.h b/backends/pulse/pulse-helpers.h
index efc8fc9..7ccd753 100644
--- a/backends/pulse/pulse-helpers.h
+++ b/backends/pulse/pulse-helpers.h
@@ -26,8 +26,10 @@
G_BEGIN_DECLS
-MateMixerChannelPosition pulse_convert_position_from_pulse (pa_channel_position_t position);
-pa_channel_position_t pulse_convert_position_to_pulse (MateMixerChannelPosition position);
+MateMixerChannelPosition pulse_convert_position_from_pulse (pa_channel_position_t position);
+pa_channel_position_t pulse_convert_position_to_pulse (MateMixerChannelPosition position);
+
+MateMixerClientStreamRole pulse_convert_media_role_name (const gchar *name);
G_END_DECLS
diff --git a/backends/pulse/pulse-monitor.c b/backends/pulse/pulse-monitor.c
index 041f903..3d5b4a8 100644
--- a/backends/pulse/pulse-monitor.c
+++ b/backends/pulse/pulse-monitor.c
@@ -34,23 +34,44 @@ struct _PulseMonitorPrivate
};
enum {
+ PROP_0,
+ PROP_ENABLED,
+ PROP_NAME,
+ PROP_INDEX_SOURCE,
+ PROP_INDEX_SINK_INPUT,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+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);
+static void pulse_monitor_class_init (PulseMonitorClass *klass);
+
+static void pulse_monitor_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void pulse_monitor_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void pulse_monitor_init (PulseMonitor *monitor);
+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 gboolean stream_connect (PulseMonitor *monitor);
+
+static void stream_read_cb (pa_stream *stream,
+ size_t length,
+ void *userdata);
static void
pulse_monitor_class_init (PulseMonitorClass *klass)
@@ -58,7 +79,50 @@ pulse_monitor_class_init (PulseMonitorClass *klass)
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = pulse_monitor_finalize;
+ object_class->finalize = pulse_monitor_finalize;
+ object_class->get_property = pulse_monitor_get_property;
+ object_class->set_property = pulse_monitor_set_property;
+
+ properties[PROP_ENABLED] =
+ g_param_spec_boolean ("enabled",
+ "Enabled",
+ "Monitor enabled",
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_NAME] =
+ g_param_spec_string ("name",
+ "Name",
+ "Name of the monitor",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_INDEX_SOURCE] =
+ g_param_spec_uint ("index-source",
+ "Index of source",
+ "Index of the PulseAudio source",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_INDEX_SINK_INPUT] =
+ g_param_spec_uint ("index-sink-input",
+ "Index of sink input",
+ "Index of the PulseAudio sink input",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
signals[VALUE] =
g_signal_new ("value",
@@ -76,6 +140,61 @@ pulse_monitor_class_init (PulseMonitorClass *klass)
}
static void
+pulse_monitor_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PulseMonitor *monitor;
+
+ monitor = PULSE_MONITOR (object);
+
+ switch (param_id) {
+ case PROP_ENABLED:
+ g_value_set_boolean (value, monitor->priv->enabled);
+ break;
+ case PROP_NAME:
+ g_value_set_string (value, monitor->priv->name);
+ break;
+ case PROP_INDEX_SOURCE:
+ g_value_set_uint (value, monitor->priv->index_source);
+ break;
+ case PROP_INDEX_SINK_INPUT:
+ g_value_set_uint (value, monitor->priv->index_sink_input);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pulse_monitor_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PulseMonitor *monitor;
+
+ monitor = PULSE_MONITOR (object);
+
+ switch (param_id) {
+ case PROP_NAME:
+ pulse_monitor_set_name (monitor, g_value_get_string (value));
+ break;
+ case PROP_INDEX_SOURCE:
+ monitor->priv->index_source = g_value_get_uint (value);
+ break;
+ case PROP_INDEX_SINK_INPUT:
+ monitor->priv->index_sink_input = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
pulse_monitor_init (PulseMonitor *monitor)
{
monitor->priv = G_TYPE_INSTANCE_GET_PRIVATE (monitor,
@@ -90,70 +209,46 @@ pulse_monitor_finalize (GObject *object)
monitor = PULSE_MONITOR (object);
- if (monitor->priv->stream)
+ /* The pulse stream may exist if the monitor is running */
+ if (monitor->priv->stream != NULL) {
+ pa_stream_disconnect (monitor->priv->stream);
pa_stream_unref (monitor->priv->stream);
+ }
pa_context_unref (monitor->priv->context);
pa_proplist_free (monitor->priv->proplist);
+ g_free (monitor->priv->name);
+
G_OBJECT_CLASS (pulse_monitor_parent_class)->finalize (object);
}
PulseMonitor *
pulse_monitor_new (pa_context *context,
pa_proplist *proplist,
+ const gchar *name,
guint32 index_source,
guint32 index_sink_input)
{
PulseMonitor *monitor;
- monitor = g_object_new (PULSE_TYPE_MONITOR, NULL);
+ g_return_val_if_fail (context != NULL, NULL);
+ g_return_val_if_fail (proplist != NULL, NULL);
+
+ monitor = g_object_new (PULSE_TYPE_MONITOR,
+ "name", name,
+ "index-source", index_source,
+ "index-sink-input", index_sink_input,
+ NULL);
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);
-
- // XXX stream must be destroyed on disable, re-enabling does not work, this
- // is just a quick temporary solution
- pa_stream_unref (monitor->priv->stream);
- monitor->priv->stream = NULL;
-
- monitor->priv->enabled = FALSE;
-}
-
-gboolean
-pulse_monitor_is_enabled (PulseMonitor *monitor)
+pulse_monitor_get_enabled (PulseMonitor *monitor)
{
g_return_val_if_fail (PULSE_IS_MONITOR (monitor), FALSE);
@@ -161,30 +256,27 @@ pulse_monitor_is_enabled (PulseMonitor *monitor)
}
gboolean
-pulse_monitor_update_index (PulseMonitor *monitor,
- guint32 index_source,
- guint32 index_sink_input)
+pulse_monitor_set_enabled (PulseMonitor *monitor, gboolean enabled)
{
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)
+ if (enabled == monitor->priv->enabled)
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);
+ if (enabled) {
+ monitor->priv->enabled = stream_connect (monitor);
- /* Unset the Pulse stream to let enabling recreate it */
- g_clear_pointer (&monitor->priv->stream, pa_stream_unref);
+ if (monitor->priv->enabled == FALSE)
+ return FALSE;
+ } else {
+ pa_stream_disconnect (monitor->priv->stream);
+ pa_stream_unref (monitor->priv->stream);
- 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);
+ monitor->priv->stream = NULL;
+ monitor->priv->enabled = FALSE;
}
+ g_object_notify_by_pspec (G_OBJECT (monitor), properties[PROP_ENABLED]);
+
return TRUE;
}
@@ -201,21 +293,32 @@ pulse_monitor_set_name (PulseMonitor *monitor, const gchar *name)
{
g_return_val_if_fail (PULSE_IS_MONITOR (monitor), FALSE);
- g_free (monitor->priv->name);
+ if (g_strcmp0 (name, monitor->priv->name) != 0) {
+ g_free (monitor->priv->name);
+ monitor->priv->name = g_strdup (name);
- monitor->priv->name = g_strdup (name);
+ g_object_notify_by_pspec (G_OBJECT (monitor), properties[PROP_NAME]);
+ }
return TRUE;
}
static gboolean
-monitor_prepare (PulseMonitor *monitor)
+stream_connect (PulseMonitor *monitor)
{
pa_sample_spec spec;
+ pa_buffer_attr attr;
const gchar *name;
+ gchar *idx;
+ int ret;
- spec.channels = 1;
- spec.format = PA_SAMPLE_FLOAT32;
- spec.rate = 25;
+ attr.maxlength = (guint32) -1;
+ attr.tlength = 0;
+ attr.prebuf = 0;
+ attr.minreq = 0;
+ attr.fragsize = sizeof (gfloat);
+ spec.channels = 1;
+ spec.format = PA_SAMPLE_FLOAT32;
+ spec.rate = 25;
if (monitor->priv->name != NULL)
name = monitor->priv->name;
@@ -230,60 +333,58 @@ monitor_prepare (PulseMonitor *monitor)
monitor->priv->proplist);
if (G_UNLIKELY (monitor->priv->stream == NULL)) {
- g_warning ("Failed to create PulseAudio monitor: %s",
+ g_warning ("Failed to create peak monitor: %s",
pa_strerror (pa_context_errno (monitor->priv->context)));
return FALSE;
}
+ /* Set sink input index for the stream, source outputs are not supported */
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,
+ stream_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);
+ /* Source index must be passed as a string */
+ idx = g_strdup_printf ("%u", monitor->priv->index_source);
+ ret = pa_stream_connect_record (monitor->priv->stream,
+ idx,
+ &attr,
+ PA_STREAM_DONT_MOVE |
+ PA_STREAM_PEAK_DETECT |
+ PA_STREAM_ADJUST_LATENCY);
+ g_free (idx);
if (ret < 0) {
- g_warning ("Failed to connect PulseAudio monitor: %s", pa_strerror (ret));
+ g_warning ("Failed to connect peak monitor: %s", pa_strerror (ret));
return FALSE;
}
return TRUE;
}
static void
-monitor_read_cb (pa_stream *stream, size_t length, void *userdata)
+stream_read_cb (pa_stream *stream, size_t length, void *userdata)
{
const void *data;
+ /* Read the next fragment from the buffer (for recording streams).
+ *
+ * If there is data at the current read index, data will point to the
+ * actual data and length will contain the size of the data in bytes
+ * (which can be less or more than a complete fragment).
+ *
+ * If there is no data at the current read index, it means that either
+ * the buffer is empty or it contains a hole (that is, the write index
+ * is ahead of the read index but there's no data where the read index
+ * points at). If the buffer is empty, data will be NULL and length will
+ * be 0. If there is a hole, data will be NULL and length will contain
+ * the length of the hole. */
if (pa_stream_peek (stream, &data, &length) < 0)
return;
- if (data) {
+ if (data != NULL) {
gdouble v = ((const gfloat *) data)[length / sizeof (gfloat) - 1];
g_signal_emit (G_OBJECT (userdata),
@@ -294,6 +395,6 @@ monitor_read_cb (pa_stream *stream, size_t length, void *userdata)
/* pa_stream_drop() should not be called if the buffer is empty, but it
* should be called if there is a hole */
- if (length)
+ if (length > 0)
pa_stream_drop (stream);
}
diff --git a/backends/pulse/pulse-monitor.h b/backends/pulse/pulse-monitor.h
index b3f6f89..41147f5 100644
--- a/backends/pulse/pulse-monitor.h
+++ b/backends/pulse/pulse-monitor.h
@@ -63,21 +63,18 @@ GType pulse_monitor_get_type (void) G_GNUC_CONST;
PulseMonitor *pulse_monitor_new (pa_context *context,
pa_proplist *proplist,
+ const gchar *name,
guint32 index_source,
guint32 index_sink_input);
-gboolean pulse_monitor_enable (PulseMonitor *monitor);
-void pulse_monitor_disable (PulseMonitor *monitor);
-gboolean pulse_monitor_is_enabled (PulseMonitor *monitor);
+gboolean pulse_monitor_get_enabled (PulseMonitor *monitor);
+gboolean pulse_monitor_set_enabled (PulseMonitor *monitor,
+ gboolean enabled);
const gchar * pulse_monitor_get_name (PulseMonitor *monitor);
gboolean pulse_monitor_set_name (PulseMonitor *monitor,
const gchar *name);
-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 051b351..54cd3b3 100644
--- a/backends/pulse/pulse-sink-input.c
+++ b/backends/pulse/pulse-sink-input.c
@@ -20,12 +20,14 @@
#include <glib-object.h>
#include <libmatemixer/matemixer-client-stream.h>
+#include <libmatemixer/matemixer-enums.h>
#include <libmatemixer/matemixer-stream.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
#include "pulse-client-stream.h"
+#include "pulse-helpers.h"
#include "pulse-monitor.h"
#include "pulse-sink.h"
#include "pulse-sink-input.h"
@@ -36,14 +38,16 @@ static void pulse_sink_input_init (PulseSinkInput *input);
G_DEFINE_TYPE (PulseSinkInput, pulse_sink_input, PULSE_TYPE_CLIENT_STREAM);
-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_reload (PulseStream *pstream);
+
+static gboolean pulse_sink_input_set_mute (PulseStream *pstream,
+ gboolean mute);
+static gboolean pulse_sink_input_set_volume (PulseStream *pstream,
+ pa_cvolume *cvolume);
+static gboolean pulse_sink_input_set_parent (PulseClientStream *pclient,
+ PulseStream *parent);
+static gboolean pulse_sink_input_remove (PulseClientStream *pclient);
+static PulseMonitor *pulse_sink_input_create_monitor (PulseStream *pstream);
static void
pulse_sink_input_class_init (PulseSinkInputClass *klass)
@@ -53,14 +57,15 @@ 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->create_monitor = sink_input_create_monitor;
+ stream_class->reload = pulse_sink_input_reload;
+ stream_class->set_mute = pulse_sink_input_set_mute;
+ stream_class->set_volume = pulse_sink_input_set_volume;
+ stream_class->create_monitor = pulse_sink_input_create_monitor;
client_class = PULSE_CLIENT_STREAM_CLASS (klass);
- client_class->set_parent = sink_input_set_parent;
- client_class->remove = sink_input_remove;
+ client_class->set_parent = pulse_sink_input_set_parent;
+ client_class->remove = pulse_sink_input_remove;
}
static void
@@ -91,7 +96,7 @@ pulse_sink_input_new (PulseConnection *connection,
}
gboolean
-pulse_sink_input_update (PulseStream *stream,
+pulse_sink_input_update (PulseStream *pstream,
const pa_sink_input_info *info,
PulseStream *parent)
{
@@ -99,66 +104,81 @@ pulse_sink_input_update (PulseStream *stream,
MATE_MIXER_STREAM_CLIENT |
MATE_MIXER_STREAM_HAS_MUTE |
MATE_MIXER_STREAM_HAS_MONITOR;
- gchar *name;
+ PulseClientStream *pclient;
+ const gchar *prop;
+ const gchar *description = NULL;
+ gchar *name;
- const gchar *prop;
- const gchar *description = NULL;
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (pstream), FALSE);
+ g_return_val_if_fail (info != NULL, FALSE);
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), FALSE);
+ pclient = PULSE_CLIENT_STREAM (pstream);
/* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (stream));
+ g_object_freeze_notify (G_OBJECT (pstream));
/* 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. */
+ * Also make sure to make the name unique by including the PulseAudio index. */
name = g_strdup_printf ("pulse-stream-client-output-%lu", (gulong) info->index);
- pulse_stream_update_name (stream, name);
+ pulse_stream_update_name (pstream, name);
g_free (name);
prop = pa_proplist_gets (info->proplist, PA_PROP_MEDIA_ROLE);
+ if (prop != NULL) {
+ MateMixerClientStreamRole role = pulse_convert_media_role_name (prop);
- if (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 (role == MATE_MIXER_CLIENT_STREAM_ROLE_EVENT) {
+ /* The event description seems to provide much better readable
+ * description for event streams */
+ prop = pa_proplist_gets (info->proplist, PA_PROP_EVENT_DESCRIPTION);
- if (G_LIKELY (prop != NULL))
- description = prop;
+ if (G_LIKELY (prop != NULL))
+ description = prop;
+ }
+ pulse_client_stream_update_role (pclient, role);
+ } else
+ pulse_client_stream_update_role (pclient, MATE_MIXER_CLIENT_STREAM_ROLE_NONE);
- flags |= MATE_MIXER_STREAM_EVENT;
- }
if (description == NULL)
description = info->name;
- pulse_stream_update_description (stream, description);
- pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
+ pulse_stream_update_description (pstream, description);
+ pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
if (info->client != PA_INVALID_INDEX)
- flags |= MATE_MIXER_STREAM_APPLICATION;
+ pulse_client_stream_update_flags (pclient, MATE_MIXER_CLIENT_STREAM_APPLICATION);
+ else
+ pulse_client_stream_update_flags (pclient, MATE_MIXER_CLIENT_STREAM_NO_FLAGS);
+
+ if (G_LIKELY (parent != NULL)) {
+ if (pulse_sink_get_monitor_index (parent) != PA_INVALID_INDEX)
+ flags |= MATE_MIXER_STREAM_HAS_MONITOR;
- if (pa_channel_map_can_balance (&info->channel_map))
- flags |= MATE_MIXER_STREAM_CAN_BALANCE;
- if (pa_channel_map_can_fade (&info->channel_map))
- flags |= MATE_MIXER_STREAM_CAN_FADE;
+ pulse_client_stream_update_parent (pclient, MATE_MIXER_STREAM (parent));
+ } else
+ pulse_client_stream_update_parent (pclient, NULL);
#if PA_CHECK_VERSION(1, 0, 0)
- if (info->has_volume)
+ 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;
+
+ if (info->volume_writable)
+ flags |= MATE_MIXER_STREAM_CAN_SET_VOLUME;
+ }
/* Flags needed before volume */
- pulse_stream_update_flags (stream, flags);
+ pulse_stream_update_flags (pstream, flags);
+ pulse_stream_update_channel_map (pstream, &info->channel_map);
if (info->has_volume)
- pulse_stream_update_volume (stream, &info->volume, &info->channel_map, 0);
+ pulse_stream_update_volume (pstream, &info->volume, 0);
else
- pulse_stream_update_volume (stream, NULL, &info->channel_map, 0);
+ pulse_stream_update_volume (pstream, NULL, 0);
#else
/* Pre-1.0 PulseAudio does not include the has_volume and volume_writable
* fields, but does include the volume info, so let's give it a try */
@@ -168,127 +188,121 @@ pulse_sink_input_update (PulseStream *stream,
MATE_MIXER_STREAM_CAN_SET_VOLUME;
/* Flags needed before volume */
- pulse_stream_update_flags (stream, flags);
+ pulse_stream_update_flags (pstream, flags);
+ pulse_stream_update_channel_map (pstream, &info->channel_map);
- pulse_stream_update_volume (stream, &info->volume, &info->channel_map, 0);
+ pulse_stream_update_volume (pstream, &info->volume, 0);
#endif
prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_NAME);
if (prop != NULL)
- pulse_client_stream_update_app_name (PULSE_CLIENT_STREAM (stream), prop);
+ pulse_client_stream_update_app_name (pclient, prop);
prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ID);
if (prop != NULL)
- pulse_client_stream_update_app_id (PULSE_CLIENT_STREAM (stream), prop);
+ pulse_client_stream_update_app_id (pclient, prop);
prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_VERSION);
if (prop != NULL)
- pulse_client_stream_update_app_version (PULSE_CLIENT_STREAM (stream), prop);
+ pulse_client_stream_update_app_version (pclient, prop);
prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ICON_NAME);
if (prop != NULL)
- pulse_client_stream_update_app_icon (PULSE_CLIENT_STREAM (stream), prop);
-
- if (G_LIKELY (parent != NULL))
- pulse_client_stream_update_parent (PULSE_CLIENT_STREAM (stream),
- MATE_MIXER_STREAM (parent));
- else
- pulse_client_stream_update_parent (PULSE_CLIENT_STREAM (stream), NULL);
+ pulse_client_stream_update_app_icon (pclient, prop);
// XXX needs to fix monitor if parent changes
- g_object_thaw_notify (G_OBJECT (stream));
+ g_object_thaw_notify (G_OBJECT (pstream));
return TRUE;
}
-static gboolean
-sink_input_set_mute (MateMixerStream *stream, gboolean mute)
+static void
+pulse_sink_input_reload (PulseStream *pstream)
{
- PulseStream *pulse;
+ g_return_if_fail (PULSE_IS_SINK_INPUT (pstream));
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), FALSE);
+ pulse_connection_load_sink_input_info (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream));
+}
- pulse = PULSE_STREAM (stream);
+static gboolean
+pulse_sink_input_set_mute (PulseStream *pstream, gboolean mute)
+{
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (pstream), FALSE);
- return pulse_connection_set_sink_input_mute (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
+ return pulse_connection_set_sink_input_mute (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
mute);
}
static gboolean
-sink_input_set_volume (MateMixerStream *stream, pa_cvolume *volume)
+pulse_sink_input_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
{
- PulseStream *pulse;
-
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), FALSE);
- g_return_val_if_fail (volume != NULL, FALSE);
-
- pulse = PULSE_STREAM (stream);
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (pstream), FALSE);
+ g_return_val_if_fail (cvolume != NULL, FALSE);
- return pulse_connection_set_sink_input_volume (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
- volume);
+ return pulse_connection_set_sink_input_volume (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
+ cvolume);
}
static gboolean
-sink_input_set_parent (MateMixerClientStream *stream, MateMixerStream *parent)
+pulse_sink_input_set_parent (PulseClientStream *pclient, PulseStream *parent)
{
- PulseStream *pulse;
+ PulseStream *pstream;
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (pclient), FALSE);
- if (G_UNLIKELY (!PULSE_IS_SINK (parent))) {
+ if (!PULSE_IS_SINK (parent)) {
g_warning ("Could not change stream parent to %s: not a parent output stream",
- mate_mixer_stream_get_name (parent));
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (parent)));
return FALSE;
}
- pulse = PULSE_STREAM (stream);
+ pstream = PULSE_STREAM (pclient);
- return pulse_connection_move_sink_input (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
- pulse_stream_get_index (PULSE_STREAM (parent)));
+ return pulse_connection_move_sink_input (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
+ pulse_stream_get_index (parent));
}
static gboolean
-sink_input_remove (MateMixerClientStream *stream)
+pulse_sink_input_remove (PulseClientStream *pclient)
{
- PulseStream *pulse;
+ PulseStream *pstream;
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (pclient), FALSE);
- pulse = PULSE_STREAM (stream);
+ pstream = PULSE_STREAM (pclient);
- return pulse_connection_kill_sink_input (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse));
+ return pulse_connection_kill_sink_input (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream));
}
static PulseMonitor *
-sink_input_create_monitor (MateMixerStream *stream)
+pulse_sink_input_create_monitor (PulseStream *pstream)
{
MateMixerStream *parent;
- PulseStream *pulse;
guint32 index;
- g_return_val_if_fail (PULSE_IS_SINK_INPUT (stream), NULL);
+ g_return_val_if_fail (PULSE_IS_SINK_INPUT (pstream), NULL);
- parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (stream));
+ parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (pstream));
if (G_UNLIKELY (parent == NULL)) {
g_debug ("Not creating monitor for client stream %s as it is not available",
- mate_mixer_stream_get_name (stream));
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)));
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));
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)));
return NULL;
}
- return pulse_connection_create_monitor (pulse_stream_get_connection (pulse),
+ return pulse_connection_create_monitor (pulse_stream_get_connection (pstream),
index,
- pulse_stream_get_index (pulse));
+ pulse_stream_get_index (pstream));
}
diff --git a/backends/pulse/pulse-sink-input.h b/backends/pulse/pulse-sink-input.h
index a498999..1e5004b 100644
--- a/backends/pulse/pulse-sink-input.h
+++ b/backends/pulse/pulse-sink-input.h
@@ -61,7 +61,7 @@ PulseStream *pulse_sink_input_new (PulseConnection *connection,
const pa_sink_input_info *info,
PulseStream *parent);
-gboolean pulse_sink_input_update (PulseStream *stream,
+gboolean pulse_sink_input_update (PulseStream *pstream,
const pa_sink_input_info *info,
PulseStream *parent);
diff --git a/backends/pulse/pulse-sink.c b/backends/pulse/pulse-sink.c
index 27d1466..0f828b1 100644
--- a/backends/pulse/pulse-sink.c
+++ b/backends/pulse/pulse-sink.c
@@ -18,6 +18,8 @@
#include <glib.h>
#include <glib-object.h>
+#include <libmatemixer/matemixer-port.h>
+#include <libmatemixer/matemixer-port-private.h>
#include <libmatemixer/matemixer-stream.h>
#include <pulse/pulseaudio.h>
@@ -38,15 +40,23 @@ static void pulse_sink_init (PulseSink *sink);
G_DEFINE_TYPE (PulseSink, pulse_sink, PULSE_TYPE_STREAM);
-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_reload (PulseStream *pstream);
+
+static gboolean pulse_sink_set_mute (PulseStream *pstream,
+ gboolean mute);
+static gboolean pulse_sink_set_volume (PulseStream *pstream,
+ pa_cvolume *cvolume);
+static gboolean pulse_sink_set_active_port (PulseStream *pstream,
+ MateMixerPort *port);
+
+static gboolean pulse_sink_suspend (PulseStream *pstream);
+static gboolean pulse_sink_resume (PulseStream *pstream);
+
+static PulseMonitor *pulse_sink_create_monitor (PulseStream *pstream);
+
+static void update_ports (PulseStream *pstream,
+ pa_sink_port_info **ports,
+ pa_sink_port_info *active);
static void
pulse_sink_class_init (PulseSinkClass *klass)
@@ -55,12 +65,13 @@ pulse_sink_class_init (PulseSinkClass *klass)
stream_class = PULSE_STREAM_CLASS (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;
+ stream_class->reload = pulse_sink_reload;
+ stream_class->set_mute = pulse_sink_set_mute;
+ stream_class->set_volume = pulse_sink_set_volume;
+ stream_class->set_active_port = pulse_sink_set_active_port;
+ stream_class->suspend = pulse_sink_suspend;
+ stream_class->resume = pulse_sink_resume;
+ stream_class->create_monitor = pulse_sink_create_monitor;
g_type_class_add_private (klass, sizeof (PulseSinkPrivate));
}
@@ -98,71 +109,46 @@ pulse_sink_new (PulseConnection *connection,
}
guint32
-pulse_sink_get_monitor_index (PulseStream *stream)
+pulse_sink_get_monitor_index (PulseStream *pstream)
{
- g_return_val_if_fail (PULSE_IS_SINK (stream), PA_INVALID_INDEX);
+ g_return_val_if_fail (PULSE_IS_SINK (pstream), PA_INVALID_INDEX);
- return PULSE_SINK (stream)->priv->index_monitor;
+ return PULSE_SINK (pstream)->priv->index_monitor;
}
gboolean
-pulse_sink_update (PulseStream *stream, const pa_sink_info *info, PulseDevice *device)
+pulse_sink_update (PulseStream *pstream, const pa_sink_info *info, PulseDevice *device)
{
MateMixerStreamFlags flags = MATE_MIXER_STREAM_OUTPUT |
MATE_MIXER_STREAM_HAS_MUTE |
MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_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);
+ g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
+ g_return_val_if_fail (info != NULL, FALSE);
/* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (stream));
+ g_object_freeze_notify (G_OBJECT (pstream));
- pulse_stream_update_name (stream, info->name);
- pulse_stream_update_description (stream, info->description);
- pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
-
- /* 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);
+ pulse_stream_update_name (pstream, info->name);
+ pulse_stream_update_description (pstream, info->description);
+ pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
/* Stream state */
switch (info->state) {
case PA_SINK_RUNNING:
- pulse_stream_update_state (stream, MATE_MIXER_STREAM_RUNNING);
+ pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_RUNNING);
break;
case PA_SINK_IDLE:
- pulse_stream_update_state (stream, MATE_MIXER_STREAM_IDLE);
+ pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_IDLE);
break;
case PA_SINK_SUSPENDED:
- pulse_stream_update_state (stream, MATE_MIXER_STREAM_SUSPENDED);
+ pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_SUSPENDED);
break;
default:
- pulse_stream_update_state (stream, MATE_MIXER_STREAM_UNKNOWN_STATE);
+ pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_UNKNOWN);
break;
}
@@ -172,132 +158,172 @@ pulse_sink_update (PulseStream *stream, const pa_sink_info *info, PulseDevice *d
if (info->flags & PA_SINK_FLAT_VOLUME)
flags |= MATE_MIXER_STREAM_HAS_FLAT_VOLUME;
- if (pa_channel_map_can_balance (&info->channel_map))
- flags |= MATE_MIXER_STREAM_CAN_BALANCE;
- if (pa_channel_map_can_fade (&info->channel_map))
- flags |= MATE_MIXER_STREAM_CAN_FADE;
+ sink = PULSE_SINK (pstream);
- /* Flags must be updated before volume */
- pulse_stream_update_flags (stream, flags);
-
- pulse_stream_update_volume (stream,
- &info->volume,
- &info->channel_map,
- info->base_volume);
-
- pulse_stream_update_device (stream, MATE_MIXER_DEVICE (device));
+ if (sink->priv->index_monitor == PA_INVALID_INDEX)
+ sink->priv->index_monitor = info->monitor_source;
- sink = PULSE_SINK (stream);
+ if (sink->priv->index_monitor != PA_INVALID_INDEX)
+ flags |= MATE_MIXER_STREAM_HAS_MONITOR;
- /* Handle change of monitoring source index */
- // XXX probably call this each time to validate
- if (sink->priv->index_monitor != info->monitor_source) {
- PulseMonitor *monitor;
+ /* Flags must be updated before volume */
+ pulse_stream_update_flags (pstream, flags);
- monitor = pulse_stream_get_monitor (PULSE_STREAM (stream));
+ pulse_stream_update_channel_map (pstream, &info->channel_map);
+ pulse_stream_update_volume (pstream, &info->volume, info->base_volume);
- if (monitor)
- pulse_monitor_update_index (monitor,
- info->monitor_source,
- PA_INVALID_INDEX);
+ pulse_stream_update_device (pstream, MATE_MIXER_DEVICE (device));
- sink->priv->index_monitor = info->monitor_source;
+ /* Ports must be updated after device */
+ if (info->ports != NULL) {
+ update_ports (pstream, info->ports, info->active_port);
}
- g_object_thaw_notify (G_OBJECT (stream));
+ g_object_thaw_notify (G_OBJECT (pstream));
return TRUE;
}
-static gboolean
-sink_set_mute (MateMixerStream *stream, gboolean mute)
+static void
+pulse_sink_reload (PulseStream *pstream)
{
- PulseStream *pulse;
+ g_return_if_fail (PULSE_IS_SINK (pstream));
- g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
+ pulse_connection_load_sink_info (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream));
+}
- pulse = PULSE_STREAM (stream);
+static gboolean
+pulse_sink_set_mute (PulseStream *pstream, gboolean mute)
+{
+ g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
- return pulse_connection_set_sink_mute (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
+ return pulse_connection_set_sink_mute (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
mute);
}
static gboolean
-sink_set_volume (MateMixerStream *stream, pa_cvolume *volume)
+pulse_sink_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
{
- PulseStream *pulse;
-
- g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
- g_return_val_if_fail (volume != NULL, FALSE);
+ g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
+ g_return_val_if_fail (cvolume != NULL, FALSE);
- pulse = PULSE_STREAM (stream);
-
- return pulse_connection_set_sink_volume (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
- volume);
+ return pulse_connection_set_sink_volume (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
+ cvolume);
}
static gboolean
-sink_set_active_port (MateMixerStream *stream, const gchar *port)
+pulse_sink_set_active_port (PulseStream *pstream, MateMixerPort *port)
{
- PulseStream *pulse;
-
- g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
- g_return_val_if_fail (port != NULL, FALSE);
+ g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
- pulse = PULSE_STREAM (stream);
-
- return pulse_connection_set_sink_port (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
- port);
+ return pulse_connection_set_sink_port (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
+ mate_mixer_port_get_name (port));
}
static gboolean
-sink_suspend (MateMixerStream *stream)
+pulse_sink_suspend (PulseStream *pstream)
{
- PulseStream *pulse;
-
- g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
- pulse = PULSE_STREAM (stream);
-
- return pulse_connection_suspend_sink (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
+ return pulse_connection_suspend_sink (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
TRUE);
}
static gboolean
-sink_resume (MateMixerStream *stream)
+pulse_sink_resume (PulseStream *pstream)
{
- PulseStream *pulse;
-
- g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
-
- pulse = PULSE_STREAM (stream);
+ g_return_val_if_fail (PULSE_IS_SINK (pstream), FALSE);
- return pulse_connection_suspend_sink (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
+ return pulse_connection_suspend_sink (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
FALSE);
}
static PulseMonitor *
-sink_create_monitor (MateMixerStream *stream)
+pulse_sink_create_monitor (PulseStream *pstream)
{
- PulseStream *pulse;
- guint32 index;
+ guint32 index;
- g_return_val_if_fail (PULSE_IS_SINK (stream), NULL);
+ g_return_val_if_fail (PULSE_IS_SINK (pstream), NULL);
- pulse = PULSE_STREAM (stream);
- index = pulse_sink_get_monitor_index (pulse);
+ index = pulse_sink_get_monitor_index (pstream);
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));
+ g_debug ("Not creating monitor for stream %s: not available",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)));
return NULL;
}
- return pulse_connection_create_monitor (pulse_stream_get_connection (pulse),
+ return pulse_connection_create_monitor (pulse_stream_get_connection (pstream),
index,
PA_INVALID_INDEX);
}
+
+static void
+update_ports (PulseStream *pstream,
+ pa_sink_port_info **ports,
+ pa_sink_port_info *active)
+{
+ MateMixerPort *port;
+ MateMixerDevice *device;
+ GHashTable *hash;
+
+ hash = pulse_stream_get_ports (pstream);
+
+ while (*ports != NULL) {
+ MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
+ pa_sink_port_info *info = *ports;
+ const gchar *icon = NULL;
+
+ device = mate_mixer_stream_get_device (MATE_MIXER_STREAM (pstream));
+ if (device != NULL) {
+ port = mate_mixer_device_get_port (device, info->name);
+
+ if (port != NULL) {
+ flags = mate_mixer_port_get_flags (port);
+ icon = mate_mixer_port_get_icon (port);
+ }
+ }
+
+#if PA_CHECK_VERSION(2, 0, 0)
+ if (info->available == PA_PORT_AVAILABLE_YES)
+ flags |= MATE_MIXER_PORT_AVAILABLE;
+ else
+ flags &= ~MATE_MIXER_PORT_AVAILABLE;
+#endif
+
+ port = g_hash_table_lookup (hash, info->name);
+
+ if (port != NULL) {
+ /* Update existing port */
+ _mate_mixer_port_update_description (port, info->description);
+ _mate_mixer_port_update_icon (port, icon);
+ _mate_mixer_port_update_priority (port, info->priority);
+ _mate_mixer_port_update_flags (port, flags);
+ } else {
+ /* Add previously unknown port to the hash table */
+ port = _mate_mixer_port_new (info->name,
+ info->description,
+ icon,
+ info->priority,
+ flags);
+
+ g_hash_table_insert (hash, g_strdup (info->name), port);
+ }
+
+ ports++;
+ }
+
+ /* Active port */
+ if (G_LIKELY (active != NULL))
+ port = g_hash_table_lookup (hash, active->name);
+ else
+ port = NULL;
+
+ pulse_stream_update_active_port (pstream, port);
+}
diff --git a/backends/pulse/pulse-sink.h b/backends/pulse/pulse-sink.h
index 7265a7c..c0631ca 100644
--- a/backends/pulse/pulse-sink.h
+++ b/backends/pulse/pulse-sink.h
@@ -65,9 +65,9 @@ PulseStream *pulse_sink_new (PulseConnection *connection,
const pa_sink_info *info,
PulseDevice *device);
-guint32 pulse_sink_get_monitor_index (PulseStream *stream);
+guint32 pulse_sink_get_monitor_index (PulseStream *pstream);
-gboolean pulse_sink_update (PulseStream *stream,
+gboolean pulse_sink_update (PulseStream *pstream,
const pa_sink_info *info,
PulseDevice *device);
diff --git a/backends/pulse/pulse-source-output.c b/backends/pulse/pulse-source-output.c
index 3f3c3ae..c46b65b 100644
--- a/backends/pulse/pulse-source-output.c
+++ b/backends/pulse/pulse-source-output.c
@@ -26,6 +26,7 @@
#include "pulse-connection.h"
#include "pulse-client-stream.h"
+#include "pulse-helpers.h"
#include "pulse-monitor.h"
#include "pulse-stream.h"
#include "pulse-source.h"
@@ -36,14 +37,18 @@ static void pulse_source_output_init (PulseSourceOutput *output);
G_DEFINE_TYPE (PulseSourceOutput, pulse_source_output, PULSE_TYPE_CLIENT_STREAM);
-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_reload (PulseStream *pstream);
+
+static gboolean pulse_source_output_set_mute (PulseStream *pstream,
+ gboolean mute);
+static gboolean pulse_source_output_set_volume (PulseStream *pstream,
+ pa_cvolume *cvolume);
+
+static gboolean pulse_source_output_set_parent (PulseClientStream *pclient,
+ PulseStream *parent);
+static gboolean pulse_source_output_remove (PulseClientStream *pclient);
+
+static PulseMonitor *pulse_source_output_create_monitor (PulseStream *pstream);
static void
pulse_source_output_class_init (PulseSourceOutputClass *klass)
@@ -53,14 +58,15 @@ pulse_source_output_class_init (PulseSourceOutputClass *klass)
stream_class = PULSE_STREAM_CLASS (klass);
- stream_class->set_mute = source_output_set_mute;
- stream_class->set_volume = source_output_set_volume;
- stream_class->create_monitor = source_output_create_monitor;
+ stream_class->reload = pulse_source_output_reload;
+ stream_class->set_mute = pulse_source_output_set_mute;
+ stream_class->set_volume = pulse_source_output_set_volume;
+ stream_class->create_monitor = pulse_source_output_create_monitor;
client_class = PULSE_CLIENT_STREAM_CLASS (klass);
- client_class->set_parent = source_output_set_parent;
- client_class->remove = source_output_remove;
+ client_class->set_parent = pulse_source_output_set_parent;
+ client_class->remove = pulse_source_output_remove;
}
static void
@@ -91,21 +97,24 @@ pulse_source_output_new (PulseConnection *connection,
}
gboolean
-pulse_source_output_update (PulseStream *stream,
+pulse_source_output_update (PulseStream *pstream,
const pa_source_output_info *info,
PulseStream *parent)
{
MateMixerStreamFlags flags = MATE_MIXER_STREAM_INPUT |
MATE_MIXER_STREAM_CLIENT;
- gchar *name;
+ PulseClientStream *pclient;
+ const gchar *prop;
+ const gchar *description = NULL;
+ gchar *name;
- const gchar *prop;
- const gchar *description = NULL;
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream), FALSE);
+ g_return_val_if_fail (info != NULL, FALSE);
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), FALSE);
+ pclient = PULSE_CLIENT_STREAM (pstream);
/* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (stream));
+ g_object_freeze_notify (G_OBJECT (pstream));
/* 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
@@ -113,159 +122,168 @@ pulse_source_output_update (PulseStream *stream,
* 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);
- pulse_stream_update_name (stream, name);
+ pulse_stream_update_name (pstream, name);
g_free (name);
prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_NAME);
if (prop != NULL)
- pulse_client_stream_update_app_name (PULSE_CLIENT_STREAM (stream), prop);
+ pulse_client_stream_update_app_name (pclient, prop);
prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ID);
if (prop != NULL)
- pulse_client_stream_update_app_id (PULSE_CLIENT_STREAM (stream), prop);
+ pulse_client_stream_update_app_id (pclient, prop);
prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_VERSION);
if (prop != NULL)
- pulse_client_stream_update_app_version (PULSE_CLIENT_STREAM (stream), prop);
+ pulse_client_stream_update_app_version (pclient, prop);
prop = pa_proplist_gets (info->proplist, PA_PROP_APPLICATION_ICON_NAME);
if (prop != NULL)
- pulse_client_stream_update_app_icon (PULSE_CLIENT_STREAM (stream), prop);
+ pulse_client_stream_update_app_icon (pclient, prop);
prop = pa_proplist_gets (info->proplist, PA_PROP_MEDIA_ROLE);
+ if (prop != NULL) {
+ MateMixerClientStreamRole role = pulse_convert_media_role_name (prop);
- if (prop != NULL && !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 (role == MATE_MIXER_CLIENT_STREAM_ROLE_EVENT) {
+ /* The event description seems to provide much better readable
+ * description for event streams */
+ prop = pa_proplist_gets (info->proplist, PA_PROP_EVENT_DESCRIPTION);
- if (G_LIKELY (prop != NULL))
- description = prop;
+ if (G_LIKELY (prop != NULL))
+ description = prop;
+ }
+ pulse_client_stream_update_role (pclient, role);
+ } else
+ pulse_client_stream_update_role (pclient, MATE_MIXER_CLIENT_STREAM_ROLE_NONE);
- flags |= MATE_MIXER_STREAM_EVENT;
- }
if (description == NULL)
description = info->name;
- pulse_stream_update_description (stream, description);
+ pulse_stream_update_description (pstream, description);
if (info->client != PA_INVALID_INDEX)
- flags |= MATE_MIXER_STREAM_APPLICATION;
+ pulse_client_stream_update_flags (pclient, MATE_MIXER_CLIENT_STREAM_APPLICATION);
+ else
+ pulse_client_stream_update_flags (pclient, MATE_MIXER_CLIENT_STREAM_NO_FLAGS);
- if (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;
+ if (G_LIKELY (parent != NULL)) {
+ pulse_client_stream_update_parent (pclient, MATE_MIXER_STREAM (parent));
+ flags |= MATE_MIXER_STREAM_HAS_MONITOR;
+ } else
+ pulse_client_stream_update_parent (pclient, NULL);
#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);
+ /* Flags needed before volume */
+ pulse_stream_update_flags (pstream, flags);
+ pulse_stream_update_channel_map (pstream, &info->channel_map);
+ pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
if (info->has_volume)
- pulse_stream_update_volume (stream, &info->volume, &info->channel_map, 0);
+ pulse_stream_update_volume (pstream, &info->volume, 0);
else
- pulse_stream_update_volume (stream, NULL, &info->channel_map, 0);
+ pulse_stream_update_volume (pstream, NULL, 0);
#else
- pulse_stream_update_flags (stream, flags);
- pulse_stream_update_volume (stream, NULL, &info->channel_map, 0);
-#endif
+ /* Flags needed before volume */
+ pulse_stream_update_flags (pstream, flags);
- if (G_LIKELY (parent != NULL))
- pulse_client_stream_update_parent (PULSE_CLIENT_STREAM (stream),
- MATE_MIXER_STREAM (parent));
- else
- pulse_client_stream_update_parent (PULSE_CLIENT_STREAM (stream), NULL);
+ pulse_stream_update_channel_map (pstream, &info->channel_map);
+ pulse_stream_update_volume (pstream, NULL, 0);
+#endif
// XXX needs to fix monitor if parent changes
- g_object_thaw_notify (G_OBJECT (stream));
+ g_object_thaw_notify (G_OBJECT (pstream));
return TRUE;
}
-static gboolean
-source_output_set_mute (MateMixerStream *stream, gboolean mute)
+static void
+pulse_source_output_reload (PulseStream *pstream)
{
- PulseStream *pulse;
+ g_return_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream));
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), FALSE);
+ pulse_connection_load_source_output_info (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream));
+}
- pulse = PULSE_STREAM (stream);
+static gboolean
+pulse_source_output_set_mute (PulseStream *pstream, gboolean mute)
+{
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream), FALSE);
- return pulse_connection_set_source_output_mute (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
+ return pulse_connection_set_source_output_mute (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
mute);
}
static gboolean
-source_output_set_volume (MateMixerStream *stream, pa_cvolume *volume)
+pulse_source_output_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
{
- PulseStream *pulse;
-
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), FALSE);
- g_return_val_if_fail (volume != NULL, FALSE);
-
- pulse = PULSE_STREAM (stream);
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream), FALSE);
+ g_return_val_if_fail (cvolume != NULL, FALSE);
- return pulse_connection_set_source_output_volume (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
- volume);
+ return pulse_connection_set_source_output_volume (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
+ cvolume);
}
static gboolean
-source_output_set_parent (MateMixerClientStream *stream, MateMixerStream *parent)
+pulse_source_output_set_parent (PulseClientStream *pclient, PulseStream *parent)
{
- PulseStream *pulse;
+ PulseStream *pstream;
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pclient), FALSE);
- if (G_UNLIKELY (!PULSE_IS_SOURCE (parent))) {
+ if (!PULSE_IS_SOURCE (parent)) {
g_warning ("Could not change stream parent to %s: not a parent input stream",
- mate_mixer_stream_get_name (parent));
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (parent)));
return FALSE;
}
- pulse = PULSE_STREAM (stream);
+ pstream = PULSE_STREAM (pclient);
- return pulse_connection_move_sink_input (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
- pulse_stream_get_index (PULSE_STREAM (parent)));
+ return pulse_connection_move_sink_input (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
+ pulse_stream_get_index (parent));
}
static gboolean
-source_output_remove (MateMixerClientStream *stream)
+pulse_source_output_remove (PulseClientStream *pclient)
{
- PulseStream *pulse;
+ PulseStream *pstream;
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pclient), FALSE);
- pulse = PULSE_STREAM (stream);
+ pstream = PULSE_STREAM (pclient);
- return pulse_connection_kill_source_output (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse));
+ return pulse_connection_kill_source_output (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream));
}
static PulseMonitor *
-source_output_create_monitor (MateMixerStream *stream)
+pulse_source_output_create_monitor (PulseStream *pstream)
{
MateMixerStream *parent;
- g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (stream), NULL);
+ g_return_val_if_fail (PULSE_IS_SOURCE_OUTPUT (pstream), NULL);
- parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (stream));
+ parent = mate_mixer_client_stream_get_parent (MATE_MIXER_CLIENT_STREAM (pstream));
if (G_UNLIKELY (parent == NULL)) {
- g_debug ("Not creating monitor for client stream %s as it is not available",
- mate_mixer_stream_get_name (stream));
+ g_debug ("Not creating monitor for client stream %s: not available",
+ mate_mixer_stream_get_name (MATE_MIXER_STREAM (pstream)));
return NULL;
}
- return pulse_connection_create_monitor (pulse_stream_get_connection (PULSE_STREAM (stream)),
+ return pulse_connection_create_monitor (pulse_stream_get_connection (pstream),
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 69efae0..845d439 100644
--- a/backends/pulse/pulse-source-output.h
+++ b/backends/pulse/pulse-source-output.h
@@ -62,7 +62,7 @@ PulseStream *pulse_source_output_new (PulseConnection *connec
const pa_source_output_info *info,
PulseStream *parent);
-gboolean pulse_source_output_update (PulseStream *stream,
+gboolean pulse_source_output_update (PulseStream *pstream,
const pa_source_output_info *info,
PulseStream *parent);
diff --git a/backends/pulse/pulse-source.c b/backends/pulse/pulse-source.c
index b443402..e7dce6f 100644
--- a/backends/pulse/pulse-source.c
+++ b/backends/pulse/pulse-source.c
@@ -18,8 +18,9 @@
#include <glib.h>
#include <glib-object.h>
-#include <libmatemixer/matemixer-stream.h>
#include <libmatemixer/matemixer-port.h>
+#include <libmatemixer/matemixer-port-private.h>
+#include <libmatemixer/matemixer-stream.h>
#include <pulse/pulseaudio.h>
@@ -34,13 +35,20 @@ static void pulse_source_init (PulseSource *source);
G_DEFINE_TYPE (PulseSource, pulse_source, PULSE_TYPE_STREAM);
-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_reload (PulseStream *pstream);
+
+static gboolean pulse_source_set_mute (PulseStream *pstream,
+ gboolean mute);
+static gboolean pulse_source_set_volume (PulseStream *pstream,
+ pa_cvolume *cvolume);
+static gboolean pulse_source_set_active_port (PulseStream *pstream,
+ MateMixerPort *port);
+
+static PulseMonitor *pulse_source_create_monitor (PulseStream *pstream);
+
+static void update_ports (PulseStream *pstream,
+ pa_source_port_info **ports,
+ pa_source_port_info *active);
static void
pulse_source_class_init (PulseSourceClass *klass)
@@ -49,10 +57,11 @@ pulse_source_class_init (PulseSourceClass *klass)
stream_class = PULSE_STREAM_CLASS (klass);
- stream_class->set_mute = source_set_mute;
- stream_class->set_volume = source_set_volume;
- stream_class->set_active_port = source_set_active_port;
- stream_class->create_monitor = source_create_monitor;
+ stream_class->reload = pulse_source_reload;
+ stream_class->set_mute = pulse_source_set_mute;
+ stream_class->set_volume = pulse_source_set_volume;
+ stream_class->set_active_port = pulse_source_set_active_port;
+ stream_class->create_monitor = pulse_source_create_monitor;
}
static void
@@ -83,63 +92,40 @@ pulse_source_new (PulseConnection *connection,
}
gboolean
-pulse_source_update (PulseStream *stream,
+pulse_source_update (PulseStream *pstream,
const pa_source_info *info,
PulseDevice *device)
{
MateMixerStreamFlags flags = MATE_MIXER_STREAM_INPUT |
MATE_MIXER_STREAM_HAS_MUTE |
+ MATE_MIXER_STREAM_HAS_MONITOR |
MATE_MIXER_STREAM_HAS_VOLUME |
MATE_MIXER_STREAM_CAN_SET_VOLUME |
MATE_MIXER_STREAM_CAN_SUSPEND;
- GList *ports = NULL;
- guint32 i;
- g_return_val_if_fail (PULSE_IS_SOURCE (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
+ g_return_val_if_fail (info != NULL, FALSE);
/* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (stream));
-
- pulse_stream_update_name (stream, info->name);
- pulse_stream_update_description (stream, info->description);
- pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
+ g_object_freeze_notify (G_OBJECT (pstream));
- /* 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);
+ pulse_stream_update_name (pstream, info->name);
+ pulse_stream_update_description (pstream, info->description);
+ pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
/* Stream state */
switch (info->state) {
case PA_SOURCE_RUNNING:
- pulse_stream_update_state (stream, MATE_MIXER_STREAM_RUNNING);
+ pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_RUNNING);
break;
case PA_SOURCE_IDLE:
- pulse_stream_update_state (stream, MATE_MIXER_STREAM_IDLE);
+ pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_IDLE);
break;
case PA_SOURCE_SUSPENDED:
- pulse_stream_update_state (stream, MATE_MIXER_STREAM_SUSPENDED);
+ pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_SUSPENDED);
break;
default:
- pulse_stream_update_state (stream, MATE_MIXER_STREAM_UNKNOWN_STATE);
+ pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_UNKNOWN);
break;
}
@@ -149,79 +135,134 @@ pulse_source_update (PulseStream *stream,
if (info->flags & PA_SINK_FLAT_VOLUME)
flags |= MATE_MIXER_STREAM_HAS_FLAT_VOLUME;
- if (pa_channel_map_can_balance (&info->channel_map))
- flags |= MATE_MIXER_STREAM_CAN_BALANCE;
- if (pa_channel_map_can_fade (&info->channel_map))
- flags |= MATE_MIXER_STREAM_CAN_FADE;
-
/* Flags must be updated before volume */
- pulse_stream_update_flags (stream, flags);
+ pulse_stream_update_flags (pstream, flags);
+
+ pulse_stream_update_channel_map (pstream, &info->channel_map);
+ pulse_stream_update_volume (pstream, &info->volume, info->base_volume);
- pulse_stream_update_volume (stream,
- &info->volume,
- &info->channel_map,
- info->base_volume);
+ pulse_stream_update_device (pstream, MATE_MIXER_DEVICE (device));
- pulse_stream_update_device (stream, MATE_MIXER_DEVICE (device));
+ /* Ports must be updated after device */
+ if (info->ports != NULL) {
+ update_ports (pstream, info->ports, info->active_port);
+ }
- g_object_thaw_notify (G_OBJECT (stream));
+ g_object_thaw_notify (G_OBJECT (pstream));
return TRUE;
}
-static gboolean
-source_set_mute (MateMixerStream *stream, gboolean mute)
+static void
+pulse_source_reload (PulseStream *pstream)
{
- PulseStream *pulse;
+ g_return_if_fail (PULSE_IS_SOURCE (pstream));
- g_return_val_if_fail (PULSE_IS_SOURCE (stream), FALSE);
+ pulse_connection_load_source_info (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream));
+}
- pulse = PULSE_STREAM (stream);
+static gboolean
+pulse_source_set_mute (PulseStream *pstream, gboolean mute)
+{
+ g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
- return pulse_connection_set_source_mute (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
+ return pulse_connection_set_source_mute (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
mute);
}
static gboolean
-source_set_volume (MateMixerStream *stream, pa_cvolume *volume)
+pulse_source_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
{
- PulseStream *pulse;
-
- g_return_val_if_fail (PULSE_IS_SOURCE (stream), FALSE);
- g_return_val_if_fail (volume != NULL, FALSE);
-
- pulse = PULSE_STREAM (stream);
+ g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
+ g_return_val_if_fail (cvolume != NULL, FALSE);
- return pulse_connection_set_source_volume (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
- volume);
+ return pulse_connection_set_source_volume (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
+ cvolume);
}
static gboolean
-source_set_active_port (MateMixerStream *stream, const gchar *port_name)
+pulse_source_set_active_port (PulseStream *pstream, MateMixerPort *port)
{
- PulseStream *pulse;
+ g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
- 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 (pstream),
+ pulse_stream_get_index (pstream),
+ mate_mixer_port_get_name (port));
+}
- pulse = PULSE_STREAM (stream);
+static PulseMonitor *
+pulse_source_create_monitor (PulseStream *pstream)
+{
+ g_return_val_if_fail (PULSE_IS_SOURCE (pstream), NULL);
- return pulse_connection_set_source_port (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
- port_name);
+ return pulse_connection_create_monitor (pulse_stream_get_connection (pstream),
+ pulse_stream_get_index (pstream),
+ PA_INVALID_INDEX);
}
-static PulseMonitor *
-source_create_monitor (MateMixerStream *stream)
+static void
+update_ports (PulseStream *pstream,
+ pa_source_port_info **ports,
+ pa_source_port_info *active)
{
- PulseStream *pulse;
+ MateMixerPort *port;
+ MateMixerDevice *device;
+ GHashTable *hash;
- g_return_val_if_fail (PULSE_IS_SOURCE (stream), NULL);
+ hash = pulse_stream_get_ports (pstream);
- pulse = PULSE_STREAM (stream);
+ while (*ports != NULL) {
+ MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
+ pa_source_port_info *info = *ports;
+ const gchar *icon = NULL;
- return pulse_connection_create_monitor (pulse_stream_get_connection (pulse),
- pulse_stream_get_index (pulse),
- PA_INVALID_INDEX);
+ device = mate_mixer_stream_get_device (MATE_MIXER_STREAM (pstream));
+ if (device != NULL) {
+ port = mate_mixer_device_get_port (device, info->name);
+
+ if (port != NULL) {
+ flags = mate_mixer_port_get_flags (port);
+ icon = mate_mixer_port_get_icon (port);
+ }
+ }
+
+#if PA_CHECK_VERSION(2, 0, 0)
+ if (info->available == PA_PORT_AVAILABLE_YES)
+ flags |= MATE_MIXER_PORT_AVAILABLE;
+ else
+ flags &= ~MATE_MIXER_PORT_AVAILABLE;
+#endif
+
+ port = g_hash_table_lookup (hash, info->name);
+
+ if (port != NULL) {
+ /* Update existing port */
+ _mate_mixer_port_update_description (port, info->description);
+ _mate_mixer_port_update_icon (port, icon);
+ _mate_mixer_port_update_priority (port, info->priority);
+ _mate_mixer_port_update_flags (port, flags);
+ } else {
+ /* Add previously unknown port to the hash table */
+ port = _mate_mixer_port_new (info->name,
+ info->description,
+ icon,
+ info->priority,
+ flags);
+
+ g_hash_table_insert (hash, g_strdup (info->name), port);
+ }
+
+ ports++;
+ }
+
+ /* Active port */
+ if (G_LIKELY (active != NULL))
+ port = g_hash_table_lookup (hash, active->name);
+ else
+ port = NULL;
+
+ pulse_stream_update_active_port (pstream, port);
}
diff --git a/backends/pulse/pulse-source.h b/backends/pulse/pulse-source.h
index fc64fe7..9abf6d8 100644
--- a/backends/pulse/pulse-source.h
+++ b/backends/pulse/pulse-source.h
@@ -61,7 +61,7 @@ PulseStream *pulse_source_new (PulseConnection *connection,
const pa_source_info *info,
PulseDevice *device);
-gboolean pulse_source_update (PulseStream *stream,
+gboolean pulse_source_update (PulseStream *pstream,
const pa_source_info *info,
PulseDevice *device);
diff --git a/backends/pulse/pulse-stream.c b/backends/pulse/pulse-stream.c
index c7ac52a..fb738ad 100644
--- a/backends/pulse/pulse-stream.c
+++ b/backends/pulse/pulse-stream.c
@@ -15,12 +15,6 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-// XXX
-// - make sure all functions work correctly with flags
-// - make sure all functions notify
-// - figure out whether functions should g_warning on errors
-// - distinguish MateMixer and Pulse variable names
-
#include <string.h>
#include <glib.h>
#include <glib-object.h>
@@ -40,19 +34,20 @@
struct _PulseStreamPrivate
{
guint32 index;
- guint32 index_device;
gchar *name;
gchar *description;
MateMixerDevice *device;
MateMixerStreamFlags flags;
MateMixerStreamState state;
gboolean mute;
- pa_cvolume volume;
+ guint volume;
+ pa_cvolume cvolume;
pa_volume_t base_volume;
pa_channel_map channel_map;
gfloat balance;
gfloat fade;
- GList *ports;
+ GHashTable *ports;
+ GList *ports_list;
MateMixerPort *port;
PulseConnection *connection;
PulseMonitor *monitor;
@@ -67,142 +62,197 @@ enum {
PROP_FLAGS,
PROP_STATE,
PROP_MUTE,
- PROP_NUM_CHANNELS,
PROP_VOLUME,
PROP_BALANCE,
PROP_FADE,
- PROP_PORTS,
PROP_ACTIVE_PORT,
PROP_INDEX,
- PROP_CONNECTION,
- N_PROPERTIES
+ PROP_CONNECTION
};
-static void mate_mixer_stream_interface_init (MateMixerStreamInterface *iface);
-static void pulse_stream_class_init (PulseStreamClass *klass);
-static void pulse_stream_init (PulseStream *stream);
-static void pulse_stream_dispose (GObject *object);
-static void pulse_stream_finalize (GObject *object);
+static void mate_mixer_stream_interface_init (MateMixerStreamInterface *iface);
+
+static void pulse_stream_class_init (PulseStreamClass *klass);
+
+static void pulse_stream_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void pulse_stream_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void pulse_stream_init (PulseStream *pstream);
+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 MateMixerDevice * stream_get_device (MateMixerStream *stream);
-static MateMixerStreamFlags stream_get_flags (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);
-static guint stream_get_num_channels (MateMixerStream *stream);
-static guint stream_get_volume (MateMixerStream *stream);
-static gboolean stream_set_volume (MateMixerStream *stream,
- guint volume);
-static gdouble stream_get_decibel (MateMixerStream *stream);
-static gboolean stream_set_decibel (MateMixerStream *stream,
- gdouble decibel);
-static MateMixerChannelPosition stream_get_channel_position (MateMixerStream *stream,
- guint channel);
-static guint stream_get_channel_volume (MateMixerStream *stream,
- guint channel);
-static gboolean stream_set_channel_volume (MateMixerStream *stream,
- guint channel,
- guint volume);
-static gdouble stream_get_channel_decibel (MateMixerStream *stream,
- guint channel);
-static gboolean stream_set_channel_decibel (MateMixerStream *stream,
- guint channel,
- gdouble decibel);
-static gboolean stream_has_position (MateMixerStream *stream,
- MateMixerChannelPosition position);
-static guint stream_get_position_volume (MateMixerStream *stream,
- MateMixerChannelPosition position);
-static gboolean stream_set_position_volume (MateMixerStream *stream,
- MateMixerChannelPosition position,
- guint volume);
-static gdouble stream_get_position_decibel (MateMixerStream *stream,
- MateMixerChannelPosition position);
-static gboolean stream_set_position_decibel (MateMixerStream *stream,
- MateMixerChannelPosition position,
- gdouble decibel);
-static gfloat stream_get_balance (MateMixerStream *stream);
-static gboolean stream_set_balance (MateMixerStream *stream,
- gfloat balance);
-static gfloat stream_get_fade (MateMixerStream *stream);
-static gboolean stream_set_fade (MateMixerStream *stream,
- gfloat 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 gboolean stream_monitor_set_name (MateMixerStream *stream,
- const gchar *name);
-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_name);
-
-static guint stream_get_min_volume (MateMixerStream *stream);
-static guint stream_get_max_volume (MateMixerStream *stream);
-static guint stream_get_normal_volume (MateMixerStream *stream);
-static guint stream_get_base_volume (MateMixerStream *stream);
-
-static gboolean stream_set_cvolume (MateMixerStream *stream,
- pa_cvolume *volume);
-static gint stream_compare_ports (gconstpointer a,
- gconstpointer b);
+static const gchar * pulse_stream_get_name (MateMixerStream *stream);
+static const gchar * pulse_stream_get_description (MateMixerStream *stream);
+static MateMixerDevice * pulse_stream_get_device (MateMixerStream *stream);
+static MateMixerStreamFlags pulse_stream_get_flags (MateMixerStream *stream);
+static MateMixerStreamState pulse_stream_get_state (MateMixerStream *stream);
+
+static gboolean pulse_stream_get_mute (MateMixerStream *stream);
+static gboolean pulse_stream_set_mute (MateMixerStream *stream,
+ gboolean mute);
+
+static guint pulse_stream_get_num_channels (MateMixerStream *stream);
+
+static guint pulse_stream_get_volume (MateMixerStream *stream);
+static gboolean pulse_stream_set_volume (MateMixerStream *stream,
+ guint volume);
+
+static gdouble pulse_stream_get_decibel (MateMixerStream *stream);
+static gboolean pulse_stream_set_decibel (MateMixerStream *stream,
+ gdouble decibel);
+
+static guint pulse_stream_get_channel_volume (MateMixerStream *stream,
+ guint channel);
+static gboolean pulse_stream_set_channel_volume (MateMixerStream *stream,
+ guint channel,
+ guint volume);
+
+static gdouble pulse_stream_get_channel_decibel (MateMixerStream *stream,
+ guint channel);
+static gboolean pulse_stream_set_channel_decibel (MateMixerStream *stream,
+ guint channel,
+ gdouble decibel);
+
+static MateMixerChannelPosition pulse_stream_get_channel_position (MateMixerStream *stream,
+ guint channel);
+static gboolean pulse_stream_has_channel_position (MateMixerStream *stream,
+ MateMixerChannelPosition position);
+
+static gfloat pulse_stream_get_balance (MateMixerStream *stream);
+static gboolean pulse_stream_set_balance (MateMixerStream *stream,
+ gfloat balance);
+
+static gfloat pulse_stream_get_fade (MateMixerStream *stream);
+static gboolean pulse_stream_set_fade (MateMixerStream *stream,
+ gfloat fade);
+
+static gboolean pulse_stream_suspend (MateMixerStream *stream);
+static gboolean pulse_stream_resume (MateMixerStream *stream);
+
+static gboolean pulse_stream_monitor_start (MateMixerStream *stream);
+static void pulse_stream_monitor_stop (MateMixerStream *stream);
+static gboolean pulse_stream_monitor_is_running (MateMixerStream *stream);
+static gboolean pulse_stream_monitor_set_name (MateMixerStream *stream,
+ const gchar *name);
+
+static const GList * pulse_stream_list_ports (MateMixerStream *stream);
+
+static MateMixerPort * pulse_stream_get_active_port (MateMixerStream *stream);
+static gboolean pulse_stream_set_active_port (MateMixerStream *stream,
+ MateMixerPort *port);
+
+static guint pulse_stream_get_min_volume (MateMixerStream *stream);
+static guint pulse_stream_get_max_volume (MateMixerStream *stream);
+static guint pulse_stream_get_normal_volume (MateMixerStream *stream);
+static guint pulse_stream_get_base_volume (MateMixerStream *stream);
+
+static void on_monitor_value (PulseMonitor *monitor,
+ gdouble value,
+ PulseStream *pstream);
+
+static gboolean update_balance_fade (PulseStream *pstream);
+
+static gboolean set_cvolume (PulseStream *pstream,
+ pa_cvolume *cvolume);
+
+static gint compare_ports (gconstpointer a,
+ gconstpointer b);
static void
mate_mixer_stream_interface_init (MateMixerStreamInterface *iface)
{
- iface->get_name = stream_get_name;
- iface->get_description = stream_get_description;
- iface->get_device = stream_get_device;
- iface->get_flags = stream_get_flags;
- 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;
- iface->get_volume = stream_get_volume;
- iface->set_volume = stream_set_volume;
- iface->get_decibel = stream_get_decibel;
- iface->set_decibel = stream_set_decibel;
- iface->get_channel_position = stream_get_channel_position;
- iface->get_channel_volume = stream_get_channel_volume;
- iface->set_channel_volume = stream_set_channel_volume;
- iface->get_channel_decibel = stream_get_channel_decibel;
- iface->set_channel_decibel = stream_set_channel_decibel;
- iface->has_position = stream_has_position;
- iface->get_position_volume = stream_get_position_volume;
- iface->set_position_volume = stream_set_position_volume;
- iface->get_position_decibel = stream_get_position_decibel;
- iface->set_position_decibel = stream_set_position_decibel;
- iface->get_balance = stream_get_balance;
- iface->set_balance = stream_set_balance;
- iface->get_fade = stream_get_fade;
- iface->set_fade = stream_set_fade;
- iface->suspend = stream_suspend;
- iface->resume = stream_resume;
- iface->monitor_start = stream_monitor_start;
- iface->monitor_stop = stream_monitor_stop;
- iface->monitor_is_running = stream_monitor_is_running;
- iface->monitor_set_name = stream_monitor_set_name;
- iface->list_ports = stream_list_ports;
- iface->get_active_port = stream_get_active_port;
- iface->set_active_port = stream_set_active_port;
- iface->get_min_volume = stream_get_min_volume;
- iface->get_max_volume = stream_get_max_volume;
- iface->get_normal_volume = stream_get_normal_volume;
- iface->get_base_volume = stream_get_base_volume;
+ iface->get_name = pulse_stream_get_name;
+ iface->get_description = pulse_stream_get_description;
+ iface->get_device = pulse_stream_get_device;
+ iface->get_flags = pulse_stream_get_flags;
+ iface->get_state = pulse_stream_get_state;
+ iface->get_mute = pulse_stream_get_mute;
+ iface->set_mute = pulse_stream_set_mute;
+ iface->get_num_channels = pulse_stream_get_num_channels;
+ iface->get_volume = pulse_stream_get_volume;
+ iface->set_volume = pulse_stream_set_volume;
+ iface->get_decibel = pulse_stream_get_decibel;
+ iface->set_decibel = pulse_stream_set_decibel;
+ iface->get_channel_volume = pulse_stream_get_channel_volume;
+ iface->set_channel_volume = pulse_stream_set_channel_volume;
+ iface->get_channel_decibel = pulse_stream_get_channel_decibel;
+ iface->set_channel_decibel = pulse_stream_set_channel_decibel;
+ iface->get_channel_position = pulse_stream_get_channel_position;
+ iface->has_channel_position = pulse_stream_has_channel_position;
+ iface->get_balance = pulse_stream_get_balance;
+ iface->set_balance = pulse_stream_set_balance;
+ iface->get_fade = pulse_stream_get_fade;
+ iface->set_fade = pulse_stream_set_fade;
+ iface->suspend = pulse_stream_suspend;
+ iface->resume = pulse_stream_resume;
+ iface->monitor_start = pulse_stream_monitor_start;
+ iface->monitor_stop = pulse_stream_monitor_stop;
+ iface->monitor_is_running = pulse_stream_monitor_is_running;
+ iface->monitor_set_name = pulse_stream_monitor_set_name;
+ iface->list_ports = pulse_stream_list_ports;
+ iface->get_active_port = pulse_stream_get_active_port;
+ iface->set_active_port = pulse_stream_set_active_port;
+ iface->get_min_volume = pulse_stream_get_min_volume;
+ iface->get_max_volume = pulse_stream_get_max_volume;
+ iface->get_normal_volume = pulse_stream_get_normal_volume;
+ iface->get_base_volume = pulse_stream_get_base_volume;
+}
+
+static void
+pulse_stream_class_init (PulseStreamClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_stream_dispose;
+ object_class->finalize = pulse_stream_finalize;
+ object_class->get_property = pulse_stream_get_property;
+ object_class->set_property = pulse_stream_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_INDEX,
+ g_param_spec_uint ("index",
+ "Index",
+ "Stream index",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ PROP_CONNECTION,
+ g_param_spec_object ("connection",
+ "Connection",
+ "PulseAudio connection",
+ PULSE_TYPE_CONNECTION,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_override_property (object_class, PROP_NAME, "name");
+ g_object_class_override_property (object_class, PROP_DESCRIPTION, "description");
+ g_object_class_override_property (object_class, PROP_DEVICE, "device");
+ g_object_class_override_property (object_class, PROP_FLAGS, "flags");
+ g_object_class_override_property (object_class, PROP_STATE, "state");
+ g_object_class_override_property (object_class, PROP_MUTE, "mute");
+ g_object_class_override_property (object_class, PROP_VOLUME, "volume");
+ g_object_class_override_property (object_class, PROP_BALANCE, "balance");
+ g_object_class_override_property (object_class, PROP_FADE, "fade");
+ g_object_class_override_property (object_class, PROP_ACTIVE_PORT, "active-port");
+
+ g_type_class_add_private (object_class, sizeof (PulseStreamPrivate));
}
static void
@@ -211,52 +261,46 @@ pulse_stream_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
- PulseStream *stream;
+ PulseStream *pstream;
- stream = PULSE_STREAM (object);
+ pstream = PULSE_STREAM (object);
switch (param_id) {
case PROP_NAME:
- g_value_set_string (value, stream->priv->name);
+ g_value_set_string (value, pstream->priv->name);
break;
case PROP_DESCRIPTION:
- g_value_set_string (value, stream->priv->description);
+ g_value_set_string (value, pstream->priv->description);
break;
case PROP_DEVICE:
- g_value_set_object (value, stream->priv->device);
+ g_value_set_object (value, pstream->priv->device);
break;
case PROP_FLAGS:
- g_value_set_flags (value, stream->priv->flags);
+ g_value_set_flags (value, pstream->priv->flags);
break;
case PROP_STATE:
- g_value_set_enum (value, stream->priv->state);
+ g_value_set_enum (value, pstream->priv->state);
break;
case PROP_MUTE:
- g_value_set_boolean (value, stream->priv->mute);
- break;
- case PROP_NUM_CHANNELS:
- g_value_set_uint (value, stream_get_num_channels (MATE_MIXER_STREAM (stream)));
+ g_value_set_boolean (value, pstream->priv->mute);
break;
case PROP_VOLUME:
- g_value_set_int64 (value, stream_get_volume (MATE_MIXER_STREAM (stream)));
+ g_value_set_uint (value, pstream->priv->volume);
break;
case PROP_BALANCE:
- g_value_set_float (value, stream->priv->balance);
+ g_value_set_float (value, pstream->priv->balance);
break;
case PROP_FADE:
- g_value_set_float (value, stream->priv->fade);
- break;
- case PROP_PORTS:
- g_value_set_pointer (value, stream->priv->ports);
+ g_value_set_float (value, pstream->priv->fade);
break;
case PROP_ACTIVE_PORT:
- g_value_set_object (value, stream->priv->port);
+ g_value_set_object (value, pstream->priv->port);
break;
case PROP_INDEX:
- g_value_set_uint (value, stream->priv->index);
+ g_value_set_uint (value, pstream->priv->index);
break;
case PROP_CONNECTION:
- g_value_set_object (value, stream->priv->connection);
+ g_value_set_object (value, pstream->priv->connection);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -270,17 +314,17 @@ pulse_stream_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
- PulseStream *stream;
+ PulseStream *pstream;
- stream = PULSE_STREAM (object);
+ pstream = PULSE_STREAM (object);
switch (param_id) {
case PROP_INDEX:
- stream->priv->index = g_value_get_uint (value);
+ pstream->priv->index = g_value_get_uint (value);
break;
case PROP_CONNECTION:
/* Construct-only object */
- stream->priv->connection = g_value_dup_object (value);
+ pstream->priv->connection = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -289,78 +333,41 @@ pulse_stream_set_property (GObject *object,
}
static void
-pulse_stream_class_init (PulseStreamClass *klass)
+pulse_stream_init (PulseStream *pstream)
{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->dispose = pulse_stream_dispose;
- object_class->finalize = pulse_stream_finalize;
- object_class->get_property = pulse_stream_get_property;
- object_class->set_property = pulse_stream_set_property;
-
- g_object_class_install_property (object_class,
- PROP_INDEX,
- g_param_spec_uint ("index",
- "Index",
- "Stream index",
- 0,
- G_MAXUINT,
- 0,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ pstream->priv = G_TYPE_INSTANCE_GET_PRIVATE (pstream,
+ PULSE_TYPE_STREAM,
+ PulseStreamPrivate);
- 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));
+ pstream->priv->ports = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
- g_object_class_override_property (object_class, PROP_NAME, "name");
- g_object_class_override_property (object_class, PROP_DESCRIPTION, "description");
- g_object_class_override_property (object_class, PROP_DEVICE, "device");
- g_object_class_override_property (object_class, PROP_FLAGS, "flags");
- g_object_class_override_property (object_class, PROP_STATE, "state");
- g_object_class_override_property (object_class, PROP_MUTE, "mute");
- g_object_class_override_property (object_class, PROP_NUM_CHANNELS, "num-channels");
- g_object_class_override_property (object_class, PROP_VOLUME, "volume");
- g_object_class_override_property (object_class, PROP_BALANCE, "balance");
- g_object_class_override_property (object_class, PROP_FADE, "fade");
- g_object_class_override_property (object_class, PROP_PORTS, "ports");
- g_object_class_override_property (object_class, PROP_ACTIVE_PORT, "active-port");
-
- g_type_class_add_private (object_class, sizeof (PulseStreamPrivate));
-}
+ /* Initialize empty volume and channel map structures, they will be used
+ * if the stream does not support volume */
+ pa_cvolume_init (&pstream->priv->cvolume);
-static void
-pulse_stream_init (PulseStream *stream)
-{
- stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
- PULSE_TYPE_STREAM,
- PulseStreamPrivate);
+ pa_channel_map_init (&pstream->priv->channel_map);
}
static void
pulse_stream_dispose (GObject *object)
{
- PulseStream *stream;
+ PulseStream *pstream;
- stream = PULSE_STREAM (object);
+ pstream = PULSE_STREAM (object);
- if (stream->priv->ports) {
- g_list_free_full (stream->priv->ports, g_object_unref);
- stream->priv->ports = NULL;
+ if (pstream->priv->ports_list != NULL) {
+ g_list_free_full (pstream->priv->ports_list, g_object_unref);
+ pstream->priv->ports_list = NULL;
}
+ g_hash_table_remove_all (pstream->priv->ports);
- g_clear_object (&stream->priv->port);
- g_clear_object (&stream->priv->device);
- g_clear_object (&stream->priv->monitor);
- g_clear_object (&stream->priv->connection);
+ g_clear_object (&pstream->priv->port);
+ g_clear_object (&pstream->priv->device);
+ g_clear_object (&pstream->priv->monitor);
+ g_clear_object (&pstream->priv->connection);
G_OBJECT_CLASS (pulse_stream_parent_class)->dispose (object);
}
@@ -368,220 +375,261 @@ pulse_stream_dispose (GObject *object)
static void
pulse_stream_finalize (GObject *object)
{
- PulseStream *stream;
+ PulseStream *pstream;
- stream = PULSE_STREAM (object);
+ pstream = PULSE_STREAM (object);
- g_free (stream->priv->name);
- g_free (stream->priv->description);
+ g_free (pstream->priv->name);
+ g_free (pstream->priv->description);
+ g_free (pstream->priv->monitor_name);
+
+ g_hash_table_destroy (pstream->priv->ports);
G_OBJECT_CLASS (pulse_stream_parent_class)->finalize (object);
}
guint32
-pulse_stream_get_index (PulseStream *stream)
+pulse_stream_get_index (PulseStream *pstream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), 0);
- return stream->priv->index;
+ return pstream->priv->index;
}
PulseConnection *
-pulse_stream_get_connection (PulseStream *stream)
+pulse_stream_get_connection (PulseStream *pstream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
- return stream->priv->connection;
+ return pstream->priv->connection;
}
PulseMonitor *
-pulse_stream_get_monitor (PulseStream *stream)
+pulse_stream_get_monitor (PulseStream *pstream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
- return stream->priv->monitor;
+ return pstream->priv->monitor;
+}
+
+const pa_cvolume *
+pulse_stream_get_cvolume (PulseStream *pstream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
+
+ return &pstream->priv->cvolume;
+}
+
+const pa_channel_map *
+pulse_stream_get_channel_map (PulseStream *pstream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
+
+ return &pstream->priv->channel_map;
+}
+
+GHashTable *
+pulse_stream_get_ports (PulseStream *pstream)
+{
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), NULL);
+
+ return pstream->priv->ports;
}
gboolean
-pulse_stream_update_name (PulseStream *stream, const gchar *name)
+pulse_stream_update_name (PulseStream *pstream, const gchar *name)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
/* Allow the name to be NULL */
- if (g_strcmp0 (name, stream->priv->name)) {
- g_free (stream->priv->name);
- stream->priv->name = g_strdup (name);
+ if (g_strcmp0 (name, pstream->priv->name) != 0) {
+ g_free (pstream->priv->name);
+ pstream->priv->name = g_strdup (name);
- g_object_notify (G_OBJECT (stream), "name");
+ g_object_notify (G_OBJECT (pstream), "name");
+ return TRUE;
}
- return TRUE;
+ return FALSE;
}
gboolean
-pulse_stream_update_description (PulseStream *stream, const gchar *description)
+pulse_stream_update_description (PulseStream *pstream, const gchar *description)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
/* Allow the description to be NULL */
- if (g_strcmp0 (description, stream->priv->description)) {
- g_free (stream->priv->description);
- stream->priv->description = g_strdup (description);
+ if (g_strcmp0 (description, pstream->priv->description) != 0) {
+ g_free (pstream->priv->description);
+ pstream->priv->description = g_strdup (description);
- g_object_notify (G_OBJECT (stream), "description");
+ g_object_notify (G_OBJECT (pstream), "description");
+ return TRUE;
}
- return TRUE;
+ return FALSE;
}
gboolean
-pulse_stream_update_device (PulseStream *stream, MateMixerDevice *device)
+pulse_stream_update_device (PulseStream *pstream, MateMixerDevice *device)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
- if (stream->priv->device != device) {
- g_clear_object (&stream->priv->device);
+ if (pstream->priv->device != device) {
+ g_clear_object (&pstream->priv->device);
if (G_LIKELY (device != NULL))
- stream->priv->device = g_object_ref (device);
+ pstream->priv->device = g_object_ref (device);
- g_object_notify (G_OBJECT (stream), "device");
+ g_object_notify (G_OBJECT (pstream), "device");
+ return TRUE;
}
- return TRUE;
+ return FALSE;
}
gboolean
-pulse_stream_update_flags (PulseStream *stream, MateMixerStreamFlags flags)
+pulse_stream_update_flags (PulseStream *pstream, MateMixerStreamFlags flags)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
+
+ if (pstream->priv->flags != flags) {
+ pstream->priv->flags = flags;
- if (stream->priv->flags != flags) {
- stream->priv->flags = flags;
- g_object_notify (G_OBJECT (stream), "flags");
+ g_object_notify (G_OBJECT (pstream), "flags");
+ return TRUE;
}
- return TRUE;
+ return FALSE;
}
gboolean
-pulse_stream_update_state (PulseStream *stream, MateMixerStreamState state)
+pulse_stream_update_state (PulseStream *pstream, MateMixerStreamState state)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
- if (stream->priv->state != state) {
- stream->priv->state = state;
- g_object_notify (G_OBJECT (stream), "state");
+ if (pstream->priv->state != state) {
+ pstream->priv->state = state;
+
+ g_object_notify (G_OBJECT (pstream), "state");
+ return TRUE;
}
- return TRUE;
+ return FALSE;
}
gboolean
-pulse_stream_update_mute (PulseStream *stream, gboolean mute)
+pulse_stream_update_channel_map (PulseStream *pstream, const pa_channel_map *map)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ MateMixerStreamFlags flags;
- if (stream->priv->mute != mute) {
- stream->priv->mute = mute;
- g_object_notify (G_OBJECT (stream), "mute");
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
+ g_return_val_if_fail (map != NULL, FALSE);
+
+ flags = pstream->priv->flags;
+
+ if (pa_channel_map_valid (map)) {
+ if (pa_channel_map_can_balance (map))
+ flags |= MATE_MIXER_STREAM_CAN_BALANCE;
+ else
+ flags &= ~MATE_MIXER_STREAM_CAN_BALANCE;
+
+ if (pa_channel_map_can_fade (map))
+ flags |= MATE_MIXER_STREAM_CAN_FADE;
+ else
+ flags &= ~MATE_MIXER_STREAM_CAN_FADE;
+
+ pstream->priv->channel_map = *map;
+ } else {
+ flags &= ~(MATE_MIXER_STREAM_CAN_BALANCE | MATE_MIXER_STREAM_CAN_FADE);
+
+ /* If the channel map is not valid, create an empty channel map, which
+ * also won't validate, but at least we know what it is */
+ pa_channel_map_init (&pstream->priv->channel_map);
}
+
+ pulse_stream_update_flags (pstream, flags);
return TRUE;
}
gboolean
-pulse_stream_update_volume (PulseStream *stream,
- const pa_cvolume *volume,
- const pa_channel_map *map,
- pa_volume_t base_volume)
+pulse_stream_update_volume (PulseStream *pstream,
+ const pa_cvolume *cvolume,
+ pa_volume_t base_volume)
{
- gfloat fade = 0.0f;
- gfloat balance = 0.0f;
+ MateMixerStreamFlags flags;
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
- /* The channel map should be always present, but volume is not always
- * supported and might be NULL */
- if (G_LIKELY (map != NULL)) {
- if (!pa_channel_map_equal (&stream->priv->channel_map, map))
- stream->priv->channel_map = *map;
- }
+ /* The base volume is not a property */
+ pstream->priv->base_volume = base_volume;
- if (volume != NULL) {
- if (!pa_cvolume_equal (&stream->priv->volume, volume)) {
- stream->priv->volume = *volume;
+ flags = pstream->priv->flags;
- g_object_notify (G_OBJECT (stream), "volume");
- }
+ if (cvolume != NULL && pa_cvolume_valid (cvolume)) {
+ /* Decibel volume and volume settability flags must be provided by
+ * the implementation */
+ flags |= MATE_MIXER_STREAM_HAS_VOLUME;
- stream->priv->base_volume = (base_volume > 0)
- ? base_volume
- : PA_VOLUME_NORM;
+ if (pa_cvolume_equal (&pstream->priv->cvolume, cvolume) == 0) {
+ pstream->priv->cvolume = *cvolume;
+ pstream->priv->volume = (guint) pa_cvolume_max (&pstream->priv->cvolume);
- /* Fade and balance need a valid channel map and volume, otherwise
- * compare against the default values */
- fade = pa_cvolume_get_fade (volume, &stream->priv->channel_map);
- balance = pa_cvolume_get_balance (volume, &stream->priv->channel_map);
+ g_object_notify (G_OBJECT (pstream), "volume");
+ }
} else {
- stream->priv->base_volume = PA_VOLUME_NORM;
- }
+ flags &= ~(MATE_MIXER_STREAM_HAS_VOLUME |
+ MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME |
+ MATE_MIXER_STREAM_CAN_SET_VOLUME);
- if (stream->priv->balance != balance) {
- stream->priv->balance = balance;
- g_object_notify (G_OBJECT (stream), "balance");
- }
+ /* If the cvolume is not valid, create an empty cvolume, which also
+ * won't validate, but at least we know what it is */
+ pa_cvolume_init (&pstream->priv->cvolume);
+
+ if (pstream->priv->volume != (guint) PA_VOLUME_MUTED) {
+ pstream->priv->volume = (guint) PA_VOLUME_MUTED;
- if (stream->priv->fade != fade) {
- stream->priv->fade = fade;
- g_object_notify (G_OBJECT (stream), "fade");
+ g_object_notify (G_OBJECT (pstream), "volume");
+ }
}
+
+ pulse_stream_update_flags (pstream, flags);
+
+ /* Changing volume may change the balance and fade values as well */
+ update_balance_fade (pstream);
return TRUE;
}
gboolean
-pulse_stream_update_ports (PulseStream *stream, GList *ports)
+pulse_stream_update_mute (PulseStream *pstream, gboolean mute)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
- if (stream->priv->ports)
- g_list_free_full (stream->priv->ports, g_object_unref);
+ if (pstream->priv->mute != mute) {
+ pstream->priv->mute = mute;
- if (ports)
- stream->priv->ports = g_list_sort (ports, stream_compare_ports);
- else
- stream->priv->ports = NULL;
-
- g_object_notify (G_OBJECT (stream), "ports");
- return TRUE;
+ g_object_notify (G_OBJECT (pstream), "mute");
+ return TRUE;
+ }
+ return FALSE;
}
gboolean
-pulse_stream_update_active_port (PulseStream *stream, const gchar *port_name)
+pulse_stream_update_active_port (PulseStream *pstream, MateMixerPort *port)
{
- GList *list;
- MateMixerPort *port = NULL;
+ g_return_val_if_fail (PULSE_IS_STREAM (pstream), FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- list = stream->priv->ports;
- while (list) {
- port = MATE_MIXER_PORT (list->data);
-
- if (!g_strcmp0 (mate_mixer_port_get_name (port), port_name))
- break;
-
- port = NULL;
- list = list->next;
- }
+ if (pstream->priv->port != port) {
+ if (pstream->priv->port != NULL)
+ g_clear_object (&pstream->priv->port);
- if (stream->priv->port != port) {
- if (stream->priv->port)
- g_clear_object (&stream->priv->port);
- if (port)
- stream->priv->port = g_object_ref (port);
+ if (port != NULL)
+ pstream->priv->port = g_object_ref (port);
- g_object_notify (G_OBJECT (stream), "active-port");
+ g_object_notify (G_OBJECT (pstream), "active-port");
+ return TRUE;
}
- return TRUE;
+ return FALSE;
}
static const gchar *
-stream_get_name (MateMixerStream *stream)
+pulse_stream_get_name (MateMixerStream *stream)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
@@ -589,7 +637,7 @@ stream_get_name (MateMixerStream *stream)
}
static const gchar *
-stream_get_description (MateMixerStream *stream)
+pulse_stream_get_description (MateMixerStream *stream)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
@@ -597,7 +645,7 @@ stream_get_description (MateMixerStream *stream)
}
static MateMixerDevice *
-stream_get_device (MateMixerStream *stream)
+pulse_stream_get_device (MateMixerStream *stream)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
@@ -605,7 +653,7 @@ stream_get_device (MateMixerStream *stream)
}
static MateMixerStreamFlags
-stream_get_flags (MateMixerStream *stream)
+pulse_stream_get_flags (MateMixerStream *stream)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_STREAM_NO_FLAGS);
@@ -613,269 +661,253 @@ stream_get_flags (MateMixerStream *stream)
}
static MateMixerStreamState
-stream_get_state (MateMixerStream *stream)
+pulse_stream_get_state (MateMixerStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_STREAM_UNKNOWN_STATE);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_STREAM_STATE_UNKNOWN);
return PULSE_STREAM (stream)->priv->state;
}
static gboolean
-stream_get_mute (MateMixerStream *stream)
+pulse_stream_get_mute (MateMixerStream *stream)
{
+ PulseStream *pstream;
+
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- return PULSE_STREAM (stream)->priv->mute;
+ pstream = PULSE_STREAM (stream);
+
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_MUTE))
+ return FALSE;
+
+ return pstream->priv->mute;
}
static gboolean
-stream_set_mute (MateMixerStream *stream, gboolean mute)
+pulse_stream_set_mute (MateMixerStream *stream, gboolean mute)
{
- PulseStream *pulse;
+ PulseStream *pstream;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- pulse = PULSE_STREAM (stream);
+ pstream = PULSE_STREAM (stream);
+
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_MUTE))
+ return FALSE;
- if (pulse->priv->mute != mute) {
- if (PULSE_STREAM_GET_CLASS (stream)->set_mute (stream, mute) == FALSE)
+ if (pstream->priv->mute != mute) {
+ PulseStreamClass *klass = PULSE_STREAM_GET_CLASS (pstream);
+
+ if (klass->set_mute (pstream, mute) == FALSE)
return FALSE;
- pulse->priv->mute = mute;
+ pstream->priv->mute = mute;
+
g_object_notify (G_OBJECT (stream), "mute");
}
return TRUE;
}
static guint
-stream_get_num_channels (MateMixerStream *stream)
+pulse_stream_get_num_channels (MateMixerStream *stream)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
- return PULSE_STREAM (stream)->priv->volume.channels;
+ return PULSE_STREAM (stream)->priv->channel_map.channels;
}
static guint
-stream_get_volume (MateMixerStream *stream)
+pulse_stream_get_volume (MateMixerStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
+ PulseStream *pstream;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
+
+ pstream = PULSE_STREAM (stream);
- return (guint) pa_cvolume_max (&PULSE_STREAM (stream)->priv->volume);
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
+ return (guint) PA_VOLUME_MUTED;
+
+ return pstream->priv->volume;
}
static gboolean
-stream_set_volume (MateMixerStream *stream, guint volume)
+pulse_stream_set_volume (MateMixerStream *stream, guint volume)
{
- PulseStream *pulse;
- pa_cvolume cvolume;
+ PulseStream *pstream;
+ pa_cvolume cvolume;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_CAN_SET_VOLUME))
+ pstream = PULSE_STREAM (stream);
+
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SET_VOLUME))
return FALSE;
- pulse = PULSE_STREAM (stream);
- cvolume = pulse->priv->volume;
+ cvolume = pstream->priv->cvolume;
if (pa_cvolume_scale (&cvolume, (pa_volume_t) volume) == NULL)
return FALSE;
- return stream_set_cvolume (stream, &cvolume);
+ return set_cvolume (pstream, &cvolume);
}
static gdouble
-stream_get_decibel (MateMixerStream *stream)
+pulse_stream_get_decibel (MateMixerStream *stream)
{
- gdouble value;
+ PulseStream *pstream;
+ gdouble value;
g_return_val_if_fail (PULSE_IS_STREAM (stream), -MATE_MIXER_INFINITY);
- if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
+ pstream = PULSE_STREAM (stream);
+
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
return -MATE_MIXER_INFINITY;
- value = pa_sw_volume_to_dB (stream_get_volume (stream));
+ value = pa_sw_volume_to_dB (pulse_stream_get_volume (stream));
+ /* PA_VOLUME_MUTED is converted to PA_DECIBEL_MININFTY */
return (value == PA_DECIBEL_MININFTY) ? -MATE_MIXER_INFINITY : value;
}
static gboolean
-stream_set_decibel (MateMixerStream *stream, gdouble decibel)
+pulse_stream_set_decibel (MateMixerStream *stream, gdouble decibel)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME) ||
- !(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_CAN_SET_VOLUME))
- return FALSE;
-
- return stream_set_volume (stream, pa_sw_volume_from_dB (decibel));
-}
+ PulseStream *pstream;
-static MateMixerChannelPosition
-stream_get_channel_position (MateMixerStream *stream, guint channel)
-{
- PulseStream *pulse;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_CHANNEL_UNKNOWN_POSITION);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- pulse = PULSE_STREAM (stream);
+ pstream = PULSE_STREAM (stream);
- if (channel >= pulse->priv->channel_map.channels)
- return MATE_MIXER_CHANNEL_UNKNOWN_POSITION;
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME) ||
+ !(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SET_VOLUME))
+ return FALSE;
- return pulse_convert_position_to_pulse (pulse->priv->channel_map.map[channel]);
+ return pulse_stream_set_volume (stream, pa_sw_volume_from_dB (decibel));
}
static guint
-stream_get_channel_volume (MateMixerStream *stream, guint channel)
+pulse_stream_get_channel_volume (MateMixerStream *stream, guint channel)
{
- PulseStream *pulse;
+ PulseStream *pstream;
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
+
+ pstream = PULSE_STREAM (stream);
- pulse = PULSE_STREAM (stream);
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
+ return (guint) PA_VOLUME_MUTED;
- if (channel >= pulse->priv->volume.channels)
- return stream_get_min_volume (stream);
+ if (channel >= pstream->priv->cvolume.channels)
+ return (guint) PA_VOLUME_MUTED;
- return (guint) pulse->priv->volume.values[channel];
+ return (guint) pstream->priv->cvolume.values[channel];
}
static gboolean
-stream_set_channel_volume (MateMixerStream *stream, guint channel, guint volume)
+pulse_stream_set_channel_volume (MateMixerStream *stream, guint channel, guint volume)
{
- PulseStream *pulse;
- pa_cvolume cvolume;
+ PulseStream *pstream;
+ pa_cvolume cvolume;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- pulse = PULSE_STREAM (stream);
- cvolume = pulse->priv->volume;
+ pstream = PULSE_STREAM (stream);
+
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SET_VOLUME))
+ return FALSE;
- if (channel >= pulse->priv->volume.channels)
+ if (channel >= pstream->priv->cvolume.channels)
return FALSE;
+ /* This is safe, because the cvolume is validated by set_cvolume() */
+ cvolume = pstream->priv->cvolume;
cvolume.values[channel] = (pa_volume_t) volume;
- return stream_set_cvolume (stream, &cvolume);
+ return set_cvolume (pstream, &cvolume);
}
static gdouble
-stream_get_channel_decibel (MateMixerStream *stream, guint channel)
+pulse_stream_get_channel_decibel (MateMixerStream *stream, guint channel)
{
- PulseStream *pulse;
+ PulseStream *pstream;
gdouble value;
g_return_val_if_fail (PULSE_IS_STREAM (stream), -MATE_MIXER_INFINITY);
- if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
- return -MATE_MIXER_INFINITY;
+ pstream = PULSE_STREAM (stream);
- pulse = PULSE_STREAM (stream);
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
+ return -MATE_MIXER_INFINITY;
- if (channel >= pulse->priv->volume.channels)
+ if (channel >= pstream->priv->cvolume.channels)
return -MATE_MIXER_INFINITY;
- value = pa_sw_volume_to_dB (pulse->priv->volume.values[channel]);
+ value = pa_sw_volume_to_dB (pstream->priv->cvolume.values[channel]);
return (value == PA_DECIBEL_MININFTY) ? -MATE_MIXER_INFINITY : value;
}
static gboolean
-stream_set_channel_decibel (MateMixerStream *stream,
- guint channel,
- gdouble decibel)
+pulse_stream_set_channel_decibel (MateMixerStream *stream,
+ guint channel,
+ gdouble decibel)
{
+ PulseStream *pstream;
+
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME) ||
- !(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_CAN_SET_VOLUME))
+ pstream = PULSE_STREAM (stream);
+
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME) ||
+ !(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SET_VOLUME))
return FALSE;
- return stream_set_channel_volume (stream, channel, pa_sw_volume_from_dB (decibel));
+ return pulse_stream_set_channel_volume (stream, channel, pa_sw_volume_from_dB (decibel));
}
-static gboolean
-stream_has_position (MateMixerStream *stream, MateMixerChannelPosition position)
+static MateMixerChannelPosition
+pulse_stream_get_channel_position (MateMixerStream *stream, guint channel)
{
- PulseStream *pulse;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
-
- pulse = PULSE_STREAM (stream);
+ PulseStream *pstream;
- return pa_channel_map_has_position (&pulse->priv->channel_map,
- pulse_convert_position_to_pulse (position));
-}
-
-static guint
-stream_get_position_volume (MateMixerStream *stream,
- MateMixerChannelPosition position)
-{
- PulseStream *pulse;
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), MATE_MIXER_CHANNEL_UNKNOWN);
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
+ pstream = PULSE_STREAM (stream);
- pulse = PULSE_STREAM (stream);
+ if (channel >= pstream->priv->channel_map.channels)
+ return MATE_MIXER_CHANNEL_UNKNOWN;
- return pa_cvolume_get_position (&pulse->priv->volume,
- &pulse->priv->channel_map,
- pulse_convert_position_to_pulse (position));
+ return pulse_convert_position_to_pulse (pstream->priv->channel_map.map[channel]);
}
static gboolean
-stream_set_position_volume (MateMixerStream *stream,
- MateMixerChannelPosition position,
- guint volume)
+pulse_stream_has_channel_position (MateMixerStream *stream,
+ MateMixerChannelPosition position)
{
- PulseStream *pulse;
- pa_cvolume cvolume;
+ PulseStream *pstream;
+ pa_channel_position_t p;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- pulse = PULSE_STREAM (stream);
- cvolume = pulse->priv->volume;
-
- if (!pa_cvolume_set_position (&cvolume,
- &pulse->priv->channel_map,
- pulse_convert_position_to_pulse (position),
- (pa_volume_t) volume))
- return FALSE;
-
- return stream_set_cvolume (stream, &cvolume);
-}
-
-static gdouble
-stream_get_position_decibel (MateMixerStream *stream,
- MateMixerChannelPosition position)
-{
- gdouble value;
-
- g_return_val_if_fail (PULSE_IS_STREAM (stream), -MATE_MIXER_INFINITY);
-
- if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME))
- return -MATE_MIXER_INFINITY;
-
- value = pa_sw_volume_to_dB (stream_get_position_volume (stream, position));
+ pstream = PULSE_STREAM (stream);
- return (value == PA_DECIBEL_MININFTY) ? -MATE_MIXER_INFINITY : value;
-}
-
-static gboolean
-stream_set_position_decibel (MateMixerStream *stream,
- MateMixerChannelPosition position,
- gdouble decibel)
-{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
+ /* Handle invalid position as a special case, otherwise this function would
+ * return TRUE for e.g. unknown index in a default channel map */
+ p = pulse_convert_position_to_pulse (position);
- if (!(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME) ||
- !(mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_CAN_SET_VOLUME))
+ if (p == PA_CHANNEL_POSITION_INVALID)
return FALSE;
- return stream_set_position_volume (stream, position, pa_sw_volume_from_dB (decibel));
+ if (pa_channel_map_has_position (&pstream->priv->channel_map, p) != 0)
+ return TRUE;
+ else
+ return FALSE;
}
static gfloat
-stream_get_balance (MateMixerStream *stream)
+pulse_stream_get_balance (MateMixerStream *stream)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0f);
@@ -883,24 +915,28 @@ stream_get_balance (MateMixerStream *stream)
}
static gboolean
-stream_set_balance (MateMixerStream *stream, gfloat balance)
+pulse_stream_set_balance (MateMixerStream *stream, gfloat balance)
{
- PulseStream *pulse;
+ PulseStream *pstream;
pa_cvolume cvolume;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- pulse = PULSE_STREAM (stream);
- cvolume = pulse->priv->volume;
+ pstream = PULSE_STREAM (stream);
+
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_BALANCE))
+ return FALSE;
+
+ cvolume = pstream->priv->cvolume;
- if (pa_cvolume_set_balance (&cvolume, &pulse->priv->channel_map, balance) == NULL)
+ if (pa_cvolume_set_balance (&cvolume, &pstream->priv->channel_map, balance) == NULL)
return FALSE;
- return stream_set_cvolume (stream, &cvolume);
+ return set_cvolume (pstream, &cvolume);
}
static gfloat
-stream_get_fade (MateMixerStream *stream)
+pulse_stream_get_fade (MateMixerStream *stream)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), 0.0f);
@@ -908,138 +944,178 @@ stream_get_fade (MateMixerStream *stream)
}
static gboolean
-stream_set_fade (MateMixerStream *stream, gfloat fade)
+pulse_stream_set_fade (MateMixerStream *stream, gfloat fade)
{
- PulseStream *pulse;
+ PulseStream *pstream;
pa_cvolume cvolume;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- pulse = PULSE_STREAM (stream);
- cvolume = pulse->priv->volume;
+ pstream = PULSE_STREAM (stream);
- if (pa_cvolume_set_fade (&cvolume, &pulse->priv->channel_map, fade) == NULL)
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_FADE))
return FALSE;
- return stream_set_cvolume (stream, &cvolume);
+ cvolume = pstream->priv->cvolume;
+
+ if (pa_cvolume_set_fade (&cvolume, &pstream->priv->channel_map, fade) == NULL)
+ return FALSE;
+
+ return set_cvolume (pstream, &cvolume);
}
static gboolean
-stream_suspend (MateMixerStream *stream)
+pulse_stream_suspend (MateMixerStream *stream)
{
+ PulseStream *pstream;
+ PulseStreamClass *klass;
+
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- if (!(PULSE_STREAM (stream)->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND))
+ pstream = PULSE_STREAM (stream);
+
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND))
return FALSE;
- return PULSE_STREAM_GET_CLASS (stream)->suspend (stream);
+ if (pstream->priv->state == MATE_MIXER_STREAM_STATE_SUSPENDED)
+ return FALSE;
+
+ klass = PULSE_STREAM_GET_CLASS (pstream);
+
+ if (klass->suspend (pstream) == FALSE)
+ return FALSE;
+
+ pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_SUSPENDED);
+ return TRUE;
}
static gboolean
-stream_resume (MateMixerStream *stream)
+pulse_stream_resume (MateMixerStream *stream)
{
+ PulseStream *pstream;
+ PulseStreamClass *klass;
+
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- if (!(PULSE_STREAM (stream)->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND))
+ pstream = PULSE_STREAM (stream);
+
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_CAN_SUSPEND))
+ return FALSE;
+
+ if (pstream->priv->state != MATE_MIXER_STREAM_STATE_SUSPENDED)
return FALSE;
- return PULSE_STREAM_GET_CLASS (stream)->resume (stream);
+ klass = PULSE_STREAM_GET_CLASS (pstream);
+
+ if (klass->resume (pstream) == FALSE)
+ return FALSE;
+
+ /* The state when resumed should be either RUNNING or IDLE, let's assume
+ * IDLE for now and request an immediate update */
+ pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_IDLE);
+
+ klass->reload (pstream);
+ return TRUE;
}
static gboolean
-stream_monitor_start (MateMixerStream *stream)
+pulse_stream_monitor_start (MateMixerStream *stream)
{
- PulseStream *pulse;
+ PulseStream *pstream;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- pulse = PULSE_STREAM (stream);
+ pstream = PULSE_STREAM (stream);
- if (!pulse->priv->monitor) {
- pulse->priv->monitor = PULSE_STREAM_GET_CLASS (stream)->create_monitor (stream);
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_MONITOR))
+ return FALSE;
+
+ if (pstream->priv->monitor == NULL) {
+ pstream->priv->monitor = PULSE_STREAM_GET_CLASS (pstream)->create_monitor (pstream);
- if (G_UNLIKELY (pulse->priv->monitor == NULL))
+ if (G_UNLIKELY (pstream->priv->monitor == NULL))
return FALSE;
- pulse_monitor_set_name (pulse->priv->monitor,
- pulse->priv->monitor_name);
+ pulse_monitor_set_name (pstream->priv->monitor,
+ pstream->priv->monitor_name);
- g_signal_connect (G_OBJECT (pulse->priv->monitor),
+ g_signal_connect (G_OBJECT (pstream->priv->monitor),
"value",
- G_CALLBACK (stream_monitor_value),
- stream);
+ G_CALLBACK (on_monitor_value),
+ pstream);
}
- g_debug ("Enabling monitor for stream %s", pulse->priv->name);
- return pulse_monitor_enable (pulse->priv->monitor);
+ return pulse_monitor_set_enabled (pstream->priv->monitor, TRUE);
}
static void
-stream_monitor_stop (MateMixerStream *stream)
+pulse_stream_monitor_stop (MateMixerStream *stream)
{
- PulseStream *pulse;
+ PulseStream *pstream;
g_return_if_fail (PULSE_IS_STREAM (stream));
- pulse = PULSE_STREAM (stream);
-
- if (pulse->priv->monitor &&
- pulse_monitor_is_enabled (pulse->priv->monitor)) {
- g_debug ("Disabling monitor for stream %s", pulse->priv->name);
+ pstream = PULSE_STREAM (stream);
- pulse_monitor_disable (pulse->priv->monitor);
- }
+ if (pstream->priv->monitor != NULL)
+ pulse_monitor_set_enabled (pstream->priv->monitor, FALSE);
}
static gboolean
-stream_monitor_is_running (MateMixerStream *stream)
+pulse_stream_monitor_is_running (MateMixerStream *stream)
{
- PulseStream *pulse;
+ PulseStream *pstream;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- pulse = PULSE_STREAM (stream);
+ pstream = PULSE_STREAM (stream);
- if (pulse->priv->monitor)
- return pulse_monitor_is_enabled (pulse->priv->monitor);
+ if (pstream->priv->monitor != NULL)
+ return pulse_monitor_get_enabled (pstream->priv->monitor);
return FALSE;
}
static gboolean
-stream_monitor_set_name (MateMixerStream *stream, const gchar *name)
+pulse_stream_monitor_set_name (MateMixerStream *stream, const gchar *name)
{
- PulseStream *pulse;
+ PulseStream *pstream;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- pulse = PULSE_STREAM (stream);
+ pstream = PULSE_STREAM (stream);
- if (pulse->priv->monitor)
- pulse_monitor_set_name (pulse->priv->monitor, name);
+ if (pstream->priv->monitor != NULL)
+ pulse_monitor_set_name (pstream->priv->monitor, name);
- pulse->priv->monitor_name = g_strdup (name);
+ pstream->priv->monitor_name = g_strdup (name);
return TRUE;
}
-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)
+pulse_stream_list_ports (MateMixerStream *stream)
{
+ PulseStream *pstream;
+
g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
- return (const GList *) PULSE_STREAM (stream)->priv->ports;
+ pstream = PULSE_STREAM (stream);
+
+ if (pstream->priv->ports_list == NULL) {
+ GList *list = g_hash_table_get_values (pstream->priv->ports);
+
+ if (list != NULL) {
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
+
+ pstream->priv->ports_list = g_list_sort (list, compare_ports);
+ }
+ }
+
+ return (const GList *) pstream->priv->ports_list;
}
static MateMixerPort *
-stream_get_active_port (MateMixerStream *stream)
+pulse_stream_get_active_port (MateMixerStream *stream)
{
g_return_val_if_fail (PULSE_IS_STREAM (stream), NULL);
@@ -1047,90 +1123,163 @@ stream_get_active_port (MateMixerStream *stream)
}
static gboolean
-stream_set_active_port (MateMixerStream *stream, const gchar *port_name)
+pulse_stream_set_active_port (MateMixerStream *stream, MateMixerPort *port)
{
- PulseStream *pulse;
- GList *list;
- MateMixerPort *port = NULL;
+ PulseStream *pstream;
+ PulseStreamClass *klass;
+ const gchar *name;
g_return_val_if_fail (PULSE_IS_STREAM (stream), FALSE);
- g_return_val_if_fail (port_name != NULL, FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
- pulse = PULSE_STREAM (stream);
- list = pulse->priv->ports;
- while (list) {
- port = MATE_MIXER_PORT (list->data);
+ pstream = PULSE_STREAM (stream);
- if (!g_strcmp0 (mate_mixer_port_get_name (port), port_name))
- break;
+ /* Make sure the port comes from this stream */
+ name = mate_mixer_port_get_name (port);
- port = NULL;
- list = list->next;
+ if (g_hash_table_lookup (pstream->priv->ports, name) == NULL) {
+ g_warning ("Port %s does not belong to stream %s",
+ mate_mixer_port_get_name (port),
+ mate_mixer_stream_get_name (stream));
+ return FALSE;
}
- if (port == NULL ||
- PULSE_STREAM_GET_CLASS (stream)->set_active_port (stream, port_name) == FALSE)
+ klass = PULSE_STREAM_GET_CLASS (pstream);
+
+ /* Change the port */
+ if (klass->set_active_port (pstream, port) == FALSE)
return FALSE;
- if (pulse->priv->port)
- g_object_unref (pulse->priv->port);
+ if (pstream->priv->port != NULL)
+ g_object_unref (pstream->priv->port);
- pulse->priv->port = g_object_ref (port);
+ pstream->priv->port = g_object_ref (port);
g_object_notify (G_OBJECT (stream), "active-port");
return TRUE;
}
static guint
-stream_get_min_volume (MateMixerStream *stream)
+pulse_stream_get_min_volume (MateMixerStream *stream)
{
return (guint) PA_VOLUME_MUTED;
}
static guint
-stream_get_max_volume (MateMixerStream *stream)
+pulse_stream_get_max_volume (MateMixerStream *stream)
{
+ PulseStream *pstream;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
+
+ pstream = PULSE_STREAM (stream);
+
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
+ return (guint) PA_VOLUME_MUTED;
+
return (guint) PA_VOLUME_UI_MAX;
}
static guint
-stream_get_normal_volume (MateMixerStream *stream)
+pulse_stream_get_normal_volume (MateMixerStream *stream)
{
+ PulseStream *pstream;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
+
+ pstream = PULSE_STREAM (stream);
+
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
+ return (guint) PA_VOLUME_MUTED;
+
return (guint) PA_VOLUME_NORM;
}
static guint
-stream_get_base_volume (MateMixerStream *stream)
+pulse_stream_get_base_volume (MateMixerStream *stream)
{
- g_return_val_if_fail (PULSE_IS_STREAM (stream), 0);
+ PulseStream *pstream;
+
+ g_return_val_if_fail (PULSE_IS_STREAM (stream), (guint) PA_VOLUME_MUTED);
+
+ pstream = PULSE_STREAM (stream);
+
+ if (!(pstream->priv->flags & MATE_MIXER_STREAM_HAS_VOLUME))
+ return (guint) PA_VOLUME_MUTED;
+
+ if (pstream->priv->base_volume > 0)
+ return pstream->priv->base_volume;
+ else
+ return (guint) PA_VOLUME_NORM;
+}
+
+static void
+on_monitor_value (PulseMonitor *monitor, gdouble value, PulseStream *pstream)
+{
+ g_signal_emit_by_name (G_OBJECT (pstream),
+ "monitor-value",
+ value);
+}
+
+static gboolean
+update_balance_fade (PulseStream *pstream)
+{
+ gfloat fade;
+ gfloat balance;
+ gboolean changed = FALSE;
+
+ /* The PulseAudio return the default 0.0f values on errors, so skip checking
+ * validity of the channel map and volume */
+ balance = pa_cvolume_get_balance (&pstream->priv->cvolume,
+ &pstream->priv->channel_map);
+
+ if (pstream->priv->balance != balance) {
+ pstream->priv->balance = balance;
- return PULSE_STREAM (stream)->priv->base_volume;
+ g_object_notify (G_OBJECT (pstream), "balance");
+ changed = TRUE;
+ }
+
+ fade = pa_cvolume_get_fade (&pstream->priv->cvolume,
+ &pstream->priv->channel_map);
+
+ if (pstream->priv->fade != fade) {
+ pstream->priv->fade = fade;
+
+ g_object_notify (G_OBJECT (pstream), "fade");
+ changed = TRUE;
+ }
+
+ return changed;
}
static gboolean
-stream_set_cvolume (MateMixerStream *stream, pa_cvolume *volume)
+set_cvolume (PulseStream *pstream, pa_cvolume *cvolume)
{
- PulseStream *pulse;
+ PulseStreamClass *klass;
- if (!pa_cvolume_valid (volume))
+ if (pa_cvolume_valid (cvolume) == 0)
return FALSE;
+ if (pa_cvolume_equal (cvolume, &pstream->priv->cvolume) != 0)
+ return TRUE;
- pulse = PULSE_STREAM (stream);
+ klass = PULSE_STREAM_GET_CLASS (pstream);
- if (!pa_cvolume_equal (volume, &pulse->priv->volume)) {
- if (PULSE_STREAM_GET_CLASS (stream)->set_volume (stream, volume) == FALSE)
- return FALSE;
+ if (klass->set_volume (pstream, cvolume) == FALSE)
+ return FALSE;
- pulse->priv->volume = *volume;
- g_object_notify (G_OBJECT (stream), "volume");
+ pstream->priv->cvolume = *cvolume;
+ pstream->priv->volume = (guint) pa_cvolume_max (cvolume);
- // XXX notify fade and balance
- }
+ g_object_notify (G_OBJECT (pstream), "volume");
+
+ /* Changing volume may change the balance and fade values as well */
+ update_balance_fade (pstream);
return TRUE;
}
static gint
-stream_compare_ports (gconstpointer a, gconstpointer b)
+compare_ports (gconstpointer a, gconstpointer b)
{
MateMixerPort *p1 = MATE_MIXER_PORT (a);
MateMixerPort *p2 = MATE_MIXER_PORT (b);
diff --git a/backends/pulse/pulse-stream.h b/backends/pulse/pulse-stream.h
index aa296ea..e4c6a00 100644
--- a/backends/pulse/pulse-stream.h
+++ b/backends/pulse/pulse-stream.h
@@ -22,6 +22,7 @@
#include <glib-object.h>
#include <libmatemixer/matemixer-device.h>
+#include <libmatemixer/matemixer-port.h>
#include <libmatemixer/matemixer-stream.h>
#include <pulse/pulseaudio.h>
@@ -60,51 +61,56 @@ struct _PulseStreamClass
{
GObjectClass parent_class;
- gboolean (*set_mute) (MateMixerStream *stream,
- gboolean mute);
- gboolean (*set_volume) (MateMixerStream *stream,
- pa_cvolume *volume);
+ /*< private >*/
+ /* Virtual table */
+ void (*reload) (PulseStream *stream);
+
+ gboolean (*set_mute) (PulseStream *stream,
+ gboolean mute);
+ gboolean (*set_volume) (PulseStream *stream,
+ pa_cvolume *volume);
- gboolean (*set_active_port) (MateMixerStream *stream,
- const gchar *port_name);
+ gboolean (*set_active_port) (PulseStream *stream,
+ MateMixerPort *port);
- gboolean (*suspend) (MateMixerStream *stream);
- gboolean (*resume) (MateMixerStream *stream);
+ gboolean (*suspend) (PulseStream *stream);
+ gboolean (*resume) (PulseStream *stream);
- PulseMonitor *(*create_monitor) (MateMixerStream *stream);
+ PulseMonitor *(*create_monitor) (PulseStream *stream);
};
-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_device (PulseStream *stream,
- MateMixerDevice *device);
-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,
- pa_volume_t base_volume);
-
-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 *pstream);
+PulseConnection * pulse_stream_get_connection (PulseStream *pstream);
+PulseMonitor * pulse_stream_get_monitor (PulseStream *pstream);
+GHashTable * pulse_stream_get_ports (PulseStream *pstream);
+
+const pa_cvolume * pulse_stream_get_cvolume (PulseStream *pstream);
+const pa_channel_map *pulse_stream_get_channel_map (PulseStream *pstream);
+
+gboolean pulse_stream_update_name (PulseStream *pstream,
+ const gchar *name);
+gboolean pulse_stream_update_description (PulseStream *pstream,
+ const gchar *description);
+gboolean pulse_stream_update_device (PulseStream *pstream,
+ MateMixerDevice *device);
+gboolean pulse_stream_update_flags (PulseStream *pstream,
+ MateMixerStreamFlags flags);
+gboolean pulse_stream_update_state (PulseStream *pstream,
+ MateMixerStreamState state);
+
+gboolean pulse_stream_update_channel_map (PulseStream *pstream,
+ const pa_channel_map *map);
+gboolean pulse_stream_update_volume (PulseStream *pstream,
+ const pa_cvolume *volume,
+ pa_volume_t base_volume);
+
+gboolean pulse_stream_update_mute (PulseStream *pstream,
+ gboolean mute);
+
+gboolean pulse_stream_update_active_port (PulseStream *pstream,
+ MateMixerPort *port);
G_END_DECLS
diff --git a/configure.ac b/configure.ac
index d698330..675667d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -68,8 +68,6 @@ PKG_CHECK_MODULES(GLIB, [
gobject-2.0 >= $GLIB_REQUIRED_VERSION
gmodule-2.0 >= $GLIB_REQUIRED_VERSION
])
-AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
-AC_PATH_PROG(GLIB_MKENUMS, glib-mkenums)
GTK_DOC_CHECK([1.10], [--flavour no-tmpl])
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index b444738..9c58b70 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -55,7 +55,9 @@ EXTRA_HFILES=
IGNORE_HFILES= \
matemixer-backend.h \
matemixer-backend-module.h \
+ matemixer-device-profile-private.h \
matemixer-enum-types.h \
+ matemixer-port-private.h \
matemixer-private.h
# Images to copy into HTML directory.
diff --git a/docs/reference/libmatemixer-sections.txt b/docs/reference/libmatemixer-sections.txt
index b719470..5807f76 100644
--- a/docs/reference/libmatemixer-sections.txt
+++ b/docs/reference/libmatemixer-sections.txt
@@ -9,8 +9,12 @@ LIBMATEMIXER_CHECK_VERSION
<SECTION>
<FILE>matemixer-client-stream</FILE>
<TITLE>MateMixerClientStream</TITLE>
+MateMixerClientStreamFlags
+MateMixerClientStreamRole
MateMixerClientStream
MateMixerClientStreamInterface
+mate_mixer_client_stream_get_flags
+mate_mixer_client_stream_get_role
mate_mixer_client_stream_get_parent
mate_mixer_client_stream_set_parent
mate_mixer_client_stream_remove
@@ -44,8 +48,10 @@ mate_mixer_control_close
mate_mixer_control_get_state
mate_mixer_control_get_device
mate_mixer_control_get_stream
+mate_mixer_control_get_cached_stream
mate_mixer_control_list_devices
mate_mixer_control_list_streams
+mate_mixer_control_list_cached_streams
mate_mixer_control_get_default_input_stream
mate_mixer_control_set_default_input_stream
mate_mixer_control_get_default_output_stream
@@ -73,6 +79,8 @@ MateMixerDeviceInterface
mate_mixer_device_get_name
mate_mixer_device_get_description
mate_mixer_device_get_icon
+mate_mixer_device_get_port
+mate_mixer_device_get_profile
mate_mixer_device_list_ports
mate_mixer_device_list_profiles
mate_mixer_device_get_active_profile
@@ -89,7 +97,6 @@ mate_mixer_device_get_type
<FILE>matemixer-device-profile</FILE>
<TITLE>MateMixerDeviceProfile</TITLE>
MateMixerDeviceProfile
-mate_mixer_device_profile_new
mate_mixer_device_profile_get_name
mate_mixer_device_profile_get_description
mate_mixer_device_profile_get_priority
@@ -113,7 +120,6 @@ MateMixerDeviceProfilePrivate
<TITLE>MateMixerPort</TITLE>
MateMixerPortFlags
MateMixerPort
-mate_mixer_port_new
mate_mixer_port_get_name
mate_mixer_port_get_description
mate_mixer_port_get_icon
@@ -158,11 +164,7 @@ mate_mixer_stream_get_channel_volume
mate_mixer_stream_set_channel_volume
mate_mixer_stream_get_channel_decibel
mate_mixer_stream_set_channel_decibel
-mate_mixer_stream_has_position
-mate_mixer_stream_get_position_volume
-mate_mixer_stream_set_position_volume
-mate_mixer_stream_get_position_decibel
-mate_mixer_stream_set_position_decibel
+mate_mixer_stream_has_channel_position
mate_mixer_stream_get_balance
mate_mixer_stream_set_balance
mate_mixer_stream_get_fade
diff --git a/docs/reference/libmatemixer.types b/docs/reference/libmatemixer.types
deleted file mode 100644
index 714c773..0000000
--- a/docs/reference/libmatemixer.types
+++ /dev/null
@@ -1,6 +0,0 @@
-mate_mixer_client_stream_get_type
-mate_mixer_control_get_type
-mate_mixer_device_get_type
-mate_mixer_device_profile_get_type
-mate_mixer_port_get_type
-mate_mixer_stream_get_type
diff --git a/examples/monitor.c b/examples/monitor.c
index e3ab0d6..3267b36 100644
--- a/examples/monitor.c
+++ b/examples/monitor.c
@@ -36,16 +36,58 @@ create_app_string (const gchar *app_name,
{
GString *string;
- string = g_string_new (app_name);
+ string = g_string_new ("");
- if (app_version)
- g_string_append_printf (string, " %s", app_version);
- if (app_id)
- g_string_append_printf (string, " (%s)", app_id);
+ if (app_name != NULL) {
+ g_string_append (string, app_name);
+
+ if (app_version != NULL)
+ g_string_append_printf (string, " %s", app_version);
+ if (app_id != NULL)
+ g_string_append_printf (string, " (%s)", app_id);
+ }
+ else if (app_id != NULL) {
+ g_string_append (string, app_id);
+
+ if (app_version != NULL)
+ g_string_append_printf (string, " %s", app_version);
+ }
return g_string_free (string, FALSE);
}
+static const gchar *
+create_role_string (MateMixerClientStreamRole role)
+{
+ switch (role) {
+ case MATE_MIXER_CLIENT_STREAM_ROLE_NONE:
+ return "None";
+ case MATE_MIXER_CLIENT_STREAM_ROLE_VIDEO:
+ return "Video";
+ case MATE_MIXER_CLIENT_STREAM_ROLE_MUSIC:
+ return "Music";
+ case MATE_MIXER_CLIENT_STREAM_ROLE_GAME:
+ return "Game";
+ case MATE_MIXER_CLIENT_STREAM_ROLE_EVENT:
+ return "Event";
+ case MATE_MIXER_CLIENT_STREAM_ROLE_PHONE:
+ return "Phone";
+ case MATE_MIXER_CLIENT_STREAM_ROLE_ANIMATION:
+ return "Animation";
+ case MATE_MIXER_CLIENT_STREAM_ROLE_PRODUCTION:
+ return "Production";
+ case MATE_MIXER_CLIENT_STREAM_ROLE_A11Y:
+ return "A11y";
+ case MATE_MIXER_CLIENT_STREAM_ROLE_TEST:
+ return "Test";
+ case MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT:
+ return "Abstract";
+ case MATE_MIXER_CLIENT_STREAM_ROLE_FILTER:
+ return "Filter";
+ }
+ return "Unknown";
+}
+
static gchar *
create_volume_bar (MateMixerStream *stream, double *percent)
{
@@ -103,7 +145,7 @@ print_devices (void)
g_print (" |-| Port %s\n"
" |-| Description : %s\n"
" |-| Icon Name : %s\n"
- " |-| Priority : %lu\n"
+ " |-| Priority : %u\n"
" |-| Status : \n\n",
mate_mixer_port_get_name (port),
mate_mixer_port_get_description (port),
@@ -150,14 +192,21 @@ print_streams (void)
streams = mate_mixer_control_list_streams (control);
while (streams) {
- MateMixerStream *stream = MATE_MIXER_STREAM (streams->data);
- gchar *volume_bar;
- gdouble volume;
-
- /* Ignore event streams */
- if (mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_EVENT) {
- streams = streams->next;
- continue;
+ MateMixerStream *stream = MATE_MIXER_STREAM (streams->data);
+ MateMixerClientStream *client = NULL;
+ gchar *volume_bar;
+ gdouble volume;
+
+ if (mate_mixer_stream_get_flags (stream) & MATE_MIXER_STREAM_CLIENT) {
+ /* The application-specific details are accessible through the client
+ * interface, which all client streams implement */
+ client = MATE_MIXER_CLIENT_STREAM (stream);
+
+ /* Ignore event streams */
+ if (mate_mixer_client_stream_get_role (client) == MATE_MIXER_CLIENT_STREAM_ROLE_EVENT) {
+ streams = streams->next;
+ continue;
+ }
}
volume_bar = create_volume_bar (stream, &volume);
@@ -178,20 +227,19 @@ 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;
+ if (client != NULL) {
+ MateMixerClientStreamFlags client_flags;
- /* The application-specific details are accessible through the client
- * interface, which all client streams implement */
- client = MATE_MIXER_CLIENT_STREAM (stream);
+ client_flags = mate_mixer_client_stream_get_flags (client);
- 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));
+ if (client_flags & MATE_MIXER_CLIENT_STREAM_APPLICATION) {
+ gchar *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 (" |-| Application : %s\n", app);
+ g_free (app);
+ }
}
g_print ("\n");
@@ -204,7 +252,7 @@ print_streams (void)
g_print (" |-| Port %s\n"
" |-| Description : %s\n"
" |-| Icon Name : %s\n"
- " |-| Priority : %lu\n"
+ " |-| Priority : %u\n"
" |-| Status : \n\n",
mate_mixer_port_get_name (port),
mate_mixer_port_get_description (port),
@@ -219,6 +267,59 @@ print_streams (void)
}
static void
+print_cached_streams (void)
+{
+ const GList *streams;
+
+ streams = mate_mixer_control_list_cached_streams (control);
+
+ while (streams) {
+ MateMixerStream *stream = MATE_MIXER_STREAM (streams->data);
+ MateMixerClientStream *client;
+ MateMixerClientStreamFlags client_flags;
+ MateMixerClientStreamRole client_role;
+ gchar *volume_bar;
+ gdouble volume;
+
+ client = MATE_MIXER_CLIENT_STREAM (stream);
+ client_flags = mate_mixer_client_stream_get_flags (client);
+ client_role = mate_mixer_client_stream_get_role (client);
+
+ volume_bar = create_volume_bar (stream, &volume);
+
+ g_print ("Cached stream %s\n"
+ " |-| Role : %s\n"
+ " |-| Volume : %s %.1f %%\n"
+ " |-| Muted : %s\n"
+ " |-| Channels : %d\n"
+ " |-| Balance : %.1f\n"
+ " |-| Fade : %.1f\n",
+ mate_mixer_stream_get_name (stream),
+ create_role_string (client_role),
+ volume_bar,
+ volume,
+ mate_mixer_stream_get_mute (stream) ? "Yes" : "No",
+ mate_mixer_stream_get_num_channels (stream),
+ mate_mixer_stream_get_balance (stream),
+ mate_mixer_stream_get_fade (stream));
+
+ if (client_flags & MATE_MIXER_CLIENT_STREAM_APPLICATION) {
+ gchar *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);
+
+ streams = streams->next;
+ }
+}
+
+static void
connected (void)
{
g_print ("Connected using the %s backend.\n\n",
@@ -226,6 +327,7 @@ connected (void)
print_devices ();
print_streams ();
+ print_cached_streams ();
g_print ("Waiting for events. Hit CTRL+C to quit.\n");
}
@@ -257,12 +359,6 @@ device_added_cb (MateMixerControl *control, const gchar *name)
}
static void
-device_changed_cb (MateMixerControl *control, const gchar *name)
-{
- g_print ("Device changed: %s\n", name);
-}
-
-static void
device_removed_cb (MateMixerControl *control, const gchar *name)
{
g_print ("Device removed: %s\n", name);
@@ -275,12 +371,6 @@ stream_added_cb (MateMixerControl *control, const gchar *name)
}
static void
-stream_changed_cb (MateMixerControl *control, const gchar *name)
-{
- g_print ("Stream changed: %s\n", name);
-}
-
-static void
stream_removed_cb (MateMixerControl *control, const gchar *name)
{
g_print ("Stream removed: %s\n", name);
@@ -358,27 +448,19 @@ int main (int argc, char *argv[])
return 1;
}
- g_signal_connect (control,
+ g_signal_connect (G_OBJECT (control),
"device-added",
G_CALLBACK (device_added_cb),
NULL);
- g_signal_connect (control,
- "device-changed",
- G_CALLBACK (device_changed_cb),
- NULL);
- g_signal_connect (control,
+ g_signal_connect (G_OBJECT (control),
"device-removed",
G_CALLBACK (device_removed_cb),
NULL);
- g_signal_connect (control,
+ g_signal_connect (G_OBJECT (control),
"stream-added",
G_CALLBACK (stream_added_cb),
NULL);
- g_signal_connect (control,
- "stream-changed",
- G_CALLBACK (stream_changed_cb),
- NULL);
- g_signal_connect (control,
+ g_signal_connect (G_OBJECT (control),
"stream-removed",
G_CALLBACK (stream_removed_cb),
NULL);
diff --git a/libmatemixer/Makefile.am b/libmatemixer/Makefile.am
index 538592f..8c219d4 100644
--- a/libmatemixer/Makefile.am
+++ b/libmatemixer/Makefile.am
@@ -32,9 +32,11 @@ libmatemixer_la_SOURCES = \
matemixer-control.c \
matemixer-device.c \
matemixer-device-profile.c \
+ matemixer-device-profile-private.h \
matemixer-enum-types.c \
matemixer-enum-types.h \
matemixer-port.c \
+ matemixer-port-private.h \
matemixer-stream.c
libmatemixer_la_LIBADD = $(GLIB_LIBS)
diff --git a/libmatemixer/matemixer-backend-module.c b/libmatemixer/matemixer-backend-module.c
index e0707c1..a3146d2 100644
--- a/libmatemixer/matemixer-backend-module.c
+++ b/libmatemixer/matemixer-backend-module.c
@@ -36,24 +36,23 @@ struct _MateMixerBackendModulePrivate
enum {
PROP_0,
- PROP_PATH,
- N_PROPERTIES
+ PROP_PATH
};
-static void mate_mixer_backend_module_class_init (MateMixerBackendModuleClass *klass);
+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 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 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);
+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);
@@ -77,7 +76,7 @@ mate_mixer_backend_module_class_init (MateMixerBackendModuleClass *klass)
g_param_spec_string ("path",
"Path",
"File path to the module",
- 0,
+ NULL,
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
@@ -145,12 +144,13 @@ mate_mixer_backend_module_dispose (GObject *object)
module = MATE_MIXER_BACKEND_MODULE (object);
- if (module->priv->loaded) {
+ if (module->priv->loaded == TRUE) {
/* Keep the module alive and avoid calling the parent dispose, which
* would do the same thing and also produce a warning */
g_object_ref (object);
return;
}
+
G_OBJECT_CLASS (mate_mixer_backend_module_parent_class)->dispose (object);
}
@@ -199,6 +199,7 @@ const MateMixerBackendInfo *
mate_mixer_backend_module_get_info (MateMixerBackendModule *module)
{
g_return_val_if_fail (MATE_MIXER_IS_BACKEND_MODULE (module), NULL);
+ g_return_val_if_fail (module->priv->loaded == TRUE, NULL);
return module->priv->get_info ();
}
@@ -226,7 +227,7 @@ backend_module_load (GTypeModule *type_module)
module = MATE_MIXER_BACKEND_MODULE (type_module);
- if (!module->priv->loaded) {
+ if (module->priv->loaded == FALSE) {
module->priv->gmodule = g_module_open (module->priv->path,
G_MODULE_BIND_LAZY |
G_MODULE_BIND_LOCAL);
@@ -239,12 +240,12 @@ backend_module_load (GTypeModule *type_module)
}
/* Validate library symbols that each backend module must provide */
- if (!g_module_symbol (module->priv->gmodule,
- "backend_module_init",
- (gpointer *) &module->priv->init) ||
- !g_module_symbol (module->priv->gmodule,
- "backend_module_get_info",
- (gpointer *) &module->priv->get_info)) {
+ if (g_module_symbol (module->priv->gmodule,
+ "backend_module_init",
+ (gpointer *) &module->priv->init) == FALSE ||
+ g_module_symbol (module->priv->gmodule,
+ "backend_module_get_info",
+ (gpointer *) &module->priv->get_info) == FALSE) {
g_warning ("Failed to load backend module %s: %s",
module->priv->path,
g_module_error ());
@@ -283,6 +284,7 @@ backend_module_load (GTypeModule *type_module)
/* This function was called before, so avoid loading and initialize only */
module->priv->init (type_module);
}
+
return TRUE;
}
diff --git a/libmatemixer/matemixer-backend-module.h b/libmatemixer/matemixer-backend-module.h
index e654413..62b0a43 100644
--- a/libmatemixer/matemixer-backend-module.h
+++ b/libmatemixer/matemixer-backend-module.h
@@ -21,6 +21,8 @@
#include <glib.h>
#include <glib-object.h>
+#include "matemixer-enums.h"
+
G_BEGIN_DECLS
typedef struct {
@@ -63,6 +65,7 @@ struct _MateMixerBackendModuleClass
GType mate_mixer_backend_module_get_type (void) G_GNUC_CONST;
MateMixerBackendModule * mate_mixer_backend_module_new (const gchar *path);
+
const MateMixerBackendInfo *mate_mixer_backend_module_get_info (MateMixerBackendModule *module);
const gchar * mate_mixer_backend_module_get_path (MateMixerBackendModule *module);
diff --git a/libmatemixer/matemixer-backend.c b/libmatemixer/matemixer-backend.c
index 32f7f1b..be5c704 100644
--- a/libmatemixer/matemixer-backend.c
+++ b/libmatemixer/matemixer-backend.c
@@ -25,11 +25,11 @@
enum {
DEVICE_ADDED,
- DEVICE_CHANGED,
DEVICE_REMOVED,
STREAM_ADDED,
- STREAM_CHANGED,
STREAM_REMOVED,
+ CACHED_STREAM_ADDED,
+ CACHED_STREAM_REMOVED,
N_SIGNALS
};
@@ -77,11 +77,11 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)
1,
G_TYPE_STRING);
- signals[DEVICE_CHANGED] =
- g_signal_new ("device-changed",
+ signals[DEVICE_REMOVED] =
+ g_signal_new ("device-removed",
G_TYPE_FROM_INTERFACE (iface),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, device_changed),
+ G_STRUCT_OFFSET (MateMixerBackendInterface, device_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -89,11 +89,11 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)
1,
G_TYPE_STRING);
- signals[DEVICE_REMOVED] =
- g_signal_new ("device-removed",
+ signals[STREAM_ADDED] =
+ g_signal_new ("stream-added",
G_TYPE_FROM_INTERFACE (iface),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, device_removed),
+ G_STRUCT_OFFSET (MateMixerBackendInterface, stream_added),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -101,11 +101,11 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)
1,
G_TYPE_STRING);
- signals[STREAM_ADDED] =
- g_signal_new ("stream-added",
+ signals[STREAM_REMOVED] =
+ g_signal_new ("stream-removed",
G_TYPE_FROM_INTERFACE (iface),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, stream_added),
+ G_STRUCT_OFFSET (MateMixerBackendInterface, stream_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -113,11 +113,11 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)
1,
G_TYPE_STRING);
- signals[STREAM_CHANGED] =
- g_signal_new ("stream-changed",
+ signals[CACHED_STREAM_ADDED] =
+ g_signal_new ("cached-stream-added",
G_TYPE_FROM_INTERFACE (iface),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, stream_changed),
+ G_STRUCT_OFFSET (MateMixerBackendInterface, cached_stream_added),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -125,11 +125,11 @@ mate_mixer_backend_default_init (MateMixerBackendInterface *iface)
1,
G_TYPE_STRING);
- signals[STREAM_REMOVED] =
- g_signal_new ("stream-removed",
+ signals[CACHED_STREAM_REMOVED] =
+ g_signal_new ("cached-stream-removed",
G_TYPE_FROM_INTERFACE (iface),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerBackendInterface, stream_removed),
+ G_STRUCT_OFFSET (MateMixerBackendInterface, cached_stream_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -156,6 +156,7 @@ mate_mixer_backend_open (MateMixerBackend *backend)
{
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), FALSE);
+ /* Implementation required */
return MATE_MIXER_BACKEND_GET_INTERFACE (backend)->open (backend);
}
@@ -177,6 +178,7 @@ mate_mixer_backend_get_state (MateMixerBackend *backend)
{
g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), MATE_MIXER_STATE_UNKNOWN);
+ /* Implementation required */
return MATE_MIXER_BACKEND_GET_INTERFACE (backend)->get_state (backend);
}
@@ -210,6 +212,21 @@ mate_mixer_backend_list_streams (MateMixerBackend *backend)
return NULL;
}
+GList *
+mate_mixer_backend_list_cached_streams (MateMixerBackend *backend)
+{
+ MateMixerBackendInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_BACKEND (backend), NULL);
+
+ iface = MATE_MIXER_BACKEND_GET_INTERFACE (backend);
+
+ if (iface->list_cached_streams)
+ return iface->list_cached_streams (backend);
+
+ return NULL;
+}
+
MateMixerStream *
mate_mixer_backend_get_default_input_stream (MateMixerBackend *backend)
{
diff --git a/libmatemixer/matemixer-backend.h b/libmatemixer/matemixer-backend.h
index 559f256..8bedfe0 100644
--- a/libmatemixer/matemixer-backend.h
+++ b/libmatemixer/matemixer-backend.h
@@ -52,6 +52,7 @@ struct _MateMixerBackendInterface
GTypeInterface parent_iface;
/*< private >*/
+ /* Virtual table */
void (*set_data) (MateMixerBackend *backend,
const MateMixerBackendData *data);
@@ -62,6 +63,7 @@ struct _MateMixerBackendInterface
GList *(*list_devices) (MateMixerBackend *backend);
GList *(*list_streams) (MateMixerBackend *backend);
+ GList *(*list_cached_streams) (MateMixerBackend *backend);
MateMixerStream *(*get_default_input_stream) (MateMixerBackend *backend);
gboolean (*set_default_input_stream) (MateMixerBackend *backend,
@@ -74,16 +76,16 @@ struct _MateMixerBackendInterface
/* Signals */
void (*device_added) (MateMixerBackend *backend,
const gchar *name);
- void (*device_changed) (MateMixerBackend *backend,
- const gchar *name);
void (*device_removed) (MateMixerBackend *backend,
const gchar *name);
void (*stream_added) (MateMixerBackend *backend,
const gchar *name);
- void (*stream_changed) (MateMixerBackend *backend,
- const gchar *name);
void (*stream_removed) (MateMixerBackend *backend,
const gchar *name);
+ void (*cached_stream_added) (MateMixerBackend *backend,
+ const gchar *name);
+ void (*cached_stream_removed) (MateMixerBackend *backend,
+ const gchar *name);
};
GType mate_mixer_backend_get_type (void) G_GNUC_CONST;
@@ -98,6 +100,7 @@ MateMixerState mate_mixer_backend_get_state (MateMixerBackend
GList * mate_mixer_backend_list_devices (MateMixerBackend *backend);
GList * mate_mixer_backend_list_streams (MateMixerBackend *backend);
+GList * mate_mixer_backend_list_cached_streams (MateMixerBackend *backend);
MateMixerStream *mate_mixer_backend_get_default_input_stream (MateMixerBackend *backend);
gboolean mate_mixer_backend_set_default_input_stream (MateMixerBackend *backend,
diff --git a/libmatemixer/matemixer-client-stream.c b/libmatemixer/matemixer-client-stream.c
index 74b3e15..3ff3c54 100644
--- a/libmatemixer/matemixer-client-stream.c
+++ b/libmatemixer/matemixer-client-stream.c
@@ -19,11 +19,13 @@
#include <glib-object.h>
#include "matemixer-client-stream.h"
+#include "matemixer-enums.h"
+#include "matemixer-enum-types.h"
#include "matemixer-stream.h"
/**
* SECTION:matemixer-client-stream
- * @short_description: An interface providing extra functionality for client streams
+ * @short_description: Interface providing extra functionality for client streams
* @see_also: #MateMixerStream
* @include: libmatemixer/matemixer.h
*
@@ -39,6 +41,24 @@ static void
mate_mixer_client_stream_default_init (MateMixerClientStreamInterface *iface)
{
g_object_interface_install_property (iface,
+ g_param_spec_flags ("client-flags",
+ "Client flags",
+ "Capability flags of the client stream",
+ MATE_MIXER_TYPE_CLIENT_STREAM_FLAGS,
+ MATE_MIXER_CLIENT_STREAM_NO_FLAGS,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
+ g_param_spec_enum ("role",
+ "Role",
+ "Role of the client stream",
+ MATE_MIXER_TYPE_CLIENT_STREAM_ROLE,
+ MATE_MIXER_CLIENT_STREAM_ROLE_NONE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_interface_install_property (iface,
g_param_spec_object ("parent",
"Parent",
"Parent stream of the client stream",
@@ -80,12 +100,52 @@ mate_mixer_client_stream_default_init (MateMixerClientStreamInterface *iface)
}
/**
+ * mate_mixer_client_stream_get_flags:
+ * @client: a #MateMixerClientStream
+ *
+ */
+MateMixerClientStreamFlags
+mate_mixer_client_stream_get_flags (MateMixerClientStream *client)
+{
+ MateMixerClientStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_NO_FLAGS);
+
+ iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
+
+ if (iface->get_flags)
+ return iface->get_flags (client);
+
+ return MATE_MIXER_CLIENT_STREAM_NO_FLAGS;
+}
+
+/**
+ * mate_mixer_client_stream_get_role:
+ * @client: a #MateMixerClientStream
+ *
+ */
+MateMixerClientStreamRole
+mate_mixer_client_stream_get_role (MateMixerClientStream *client)
+{
+ MateMixerClientStreamInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CLIENT_STREAM (client), MATE_MIXER_CLIENT_STREAM_ROLE_NONE);
+
+ iface = MATE_MIXER_CLIENT_STREAM_GET_INTERFACE (client);
+
+ if (iface->get_role)
+ return iface->get_role (client);
+
+ return MATE_MIXER_CLIENT_STREAM_ROLE_NONE;
+}
+
+/**
* mate_mixer_client_stream_get_parent:
* @client: a #MateMixerClientStream
*
* Gets the parent stream of the client stream.
*
- * Returns: a #MateMixerStream or %NULL on failure.
+ * Returns: a #MateMixerStream or %NULL if the parent stream is not known.
*/
MateMixerStream *
mate_mixer_client_stream_get_parent (MateMixerClientStream *client)
diff --git a/libmatemixer/matemixer-client-stream.h b/libmatemixer/matemixer-client-stream.h
index 1375cb3..fae5934 100644
--- a/libmatemixer/matemixer-client-stream.h
+++ b/libmatemixer/matemixer-client-stream.h
@@ -21,6 +21,7 @@
#include <glib.h>
#include <glib-object.h>
+#include <libmatemixer/matemixer-enums.h>
#include <libmatemixer/matemixer-stream.h>
G_BEGIN_DECLS
@@ -42,26 +43,37 @@ struct _MateMixerClientStreamInterface
GTypeInterface parent_iface;
/*< 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);
+ /* Virtual table */
+ MateMixerClientStreamFlags (*get_flags) (MateMixerClientStream *client);
+ MateMixerClientStreamRole (*get_role) (MateMixerClientStream *client);
+
+ 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;
+
+MateMixerClientStreamFlags mate_mixer_client_stream_get_flags (MateMixerClientStream *client);
+MateMixerClientStreamRole mate_mixer_client_stream_get_role (MateMixerClientStream *client);
+
+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);
+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 6aac624..b501f1e 100644
--- a/libmatemixer/matemixer-control.c
+++ b/libmatemixer/matemixer-control.c
@@ -31,6 +31,7 @@
/**
* SECTION:matemixer-control
+ * @short_description:The main class for interfacing with the library
* @include: libmatemixer/matemixer.h
*/
@@ -38,6 +39,7 @@ struct _MateMixerControlPrivate
{
GList *devices;
GList *streams;
+ GList *cached_streams;
gboolean backend_chosen;
MateMixerState state;
MateMixerBackend *backend;
@@ -63,74 +65,76 @@ static GParamSpec *properties[N_PROPERTIES] = { NULL, };
enum {
DEVICE_ADDED,
- DEVICE_CHANGED,
DEVICE_REMOVED,
STREAM_ADDED,
- STREAM_CHANGED,
STREAM_REMOVED,
+ CACHED_STREAM_ADDED,
+ CACHED_STREAM_REMOVED,
N_SIGNALS
};
static guint signals[N_SIGNALS] = { 0, };
-static void mate_mixer_control_class_init (MateMixerControlClass *klass);
+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_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);
+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 void control_backend_state_cb (MateMixerBackend *backend,
- GParamSpec *pspec,
- MateMixerControl *control);
-
-static void control_backend_device_added_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-static void control_backend_device_changed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-static void control_backend_device_removed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-
-static void control_backend_stream_added_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-static void control_backend_stream_changed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-static void control_backend_stream_removed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control);
-
-static void control_backend_default_input_cb (MateMixerBackend *backend,
- GParamSpec *pspec,
- MateMixerControl *control);
-static void control_backend_default_output_cb (MateMixerBackend *backend,
- GParamSpec *pspec,
- 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 void on_backend_state_notify (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerControl *control);
+
+static void on_backend_device_added (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+static void on_backend_device_removed (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+
+static void on_backend_stream_added (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+static void on_backend_stream_removed (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+
+static void on_backend_cached_stream_added (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+static void on_backend_cached_stream_removed (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control);
+
+static void on_backend_default_input_notify (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerControl *control);
+static void on_backend_default_output_notify (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerControl *control);
+
+static gboolean try_next_backend (MateMixerControl *control);
+
+static void change_state (MateMixerControl *control,
+ MateMixerState state);
+
+static void close_control (MateMixerControl *control);
+
+static void free_backend (MateMixerControl *control);
+static void free_devices (MateMixerControl *control);
+static void free_streams (MateMixerControl *control);
+static void free_cached_streams (MateMixerControl *control);
static void
mate_mixer_control_class_init (MateMixerControlClass *klass)
@@ -219,14 +223,14 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
"Default input",
"Default input stream",
MATE_MIXER_TYPE_STREAM,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ G_PARAM_READWRITE | 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_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
@@ -250,18 +254,17 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
G_TYPE_STRING);
/**
- * MateMixerControl::device-changed:
+ * MateMixerControl::device-removed:
* @control: a #MateMixerControl
- * @name: name of the changed device
+ * @name: name of the removed device
*
- * The signal is emitted each time a change occurs on one of the known
- * devices.
+ * The signal is emitted each time a device is removed from the system.
*/
- signals[DEVICE_CHANGED] =
- g_signal_new ("device-changed",
+ signals[DEVICE_REMOVED] =
+ g_signal_new ("device-removed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, device_changed),
+ G_STRUCT_OFFSET (MateMixerControlClass, device_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -270,17 +273,17 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
G_TYPE_STRING);
/**
- * MateMixerControl::device-removed:
+ * MateMixerControl::stream-added:
* @control: a #MateMixerControl
- * @name: name of the removed device
+ * @name: name of the added stream
*
- * The signal is emitted each time a device is removed from the system.
+ * The signal is emitted each time a stream is created.
*/
- signals[DEVICE_REMOVED] =
- g_signal_new ("device-removed",
+ signals[STREAM_ADDED] =
+ g_signal_new ("stream-added",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, device_removed),
+ G_STRUCT_OFFSET (MateMixerControlClass, stream_added),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -289,17 +292,17 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
G_TYPE_STRING);
/**
- * MateMixerControl::stream-added:
+ * MateMixerControl::stream-removed:
* @control: a #MateMixerControl
- * @name: name of the added stream
+ * @name: name of the removed stream
*
- * The signal is emitted each time a stream is added to the system.
+ * The signal is emitted each time a stream is removed.
*/
- signals[STREAM_ADDED] =
- g_signal_new ("stream-added",
+ signals[STREAM_REMOVED] =
+ g_signal_new ("stream-removed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, stream_added),
+ G_STRUCT_OFFSET (MateMixerControlClass, stream_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -308,18 +311,17 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
G_TYPE_STRING);
/**
- * MateMixerControl::stream-changed:
+ * MateMixerControl::cached-stream-added:
* @control: a #MateMixerControl
- * @name: name of the changed stream
+ * @name: name of the added cached stream
*
- * The signal is emitted each time a change occurs on one of the known
- * streams.
+ * The signal is emitted each time a cached stream is created.
*/
- signals[STREAM_CHANGED] =
- g_signal_new ("stream-changed",
+ signals[CACHED_STREAM_ADDED] =
+ g_signal_new ("cached-stream-added",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, stream_changed),
+ G_STRUCT_OFFSET (MateMixerControlClass, cached_stream_added),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -332,13 +334,13 @@ mate_mixer_control_class_init (MateMixerControlClass *klass)
* @control: a #MateMixerControl
* @name: name of the removed stream
*
- * The signal is emitted each time a stream is removed from the system.
+ * The signal is emitted each time a stream is removed.
*/
- signals[STREAM_REMOVED] =
- g_signal_new ("stream-removed",
+ signals[CACHED_STREAM_REMOVED] =
+ g_signal_new ("cached-stream-removed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MateMixerControlClass, stream_removed),
+ G_STRUCT_OFFSET (MateMixerControlClass, cached_stream_removed),
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,
@@ -416,6 +418,12 @@ mate_mixer_control_set_property (GObject *object,
case PROP_SERVER_ADDRESS:
mate_mixer_control_set_server_address (control, g_value_get_string (value));
break;
+ case PROP_DEFAULT_INPUT:
+ mate_mixer_control_set_default_input_stream (control, g_value_get_object (value));
+ break;
+ case PROP_DEFAULT_OUTPUT:
+ mate_mixer_control_set_default_output_stream (control, g_value_get_object (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -433,7 +441,7 @@ mate_mixer_control_init (MateMixerControl *control)
static void
mate_mixer_control_dispose (GObject *object)
{
- control_close (MATE_MIXER_CONTROL (object));
+ close_control (MATE_MIXER_CONTROL (object));
G_OBJECT_CLASS (mate_mixer_control_parent_class)->dispose (object);
}
@@ -465,10 +473,11 @@ mate_mixer_control_finalize (GObject *object)
MateMixerControl *
mate_mixer_control_new (void)
{
- if (!mate_mixer_is_initialized ()) {
+ if (mate_mixer_is_initialized () == FALSE) {
g_critical ("The library has not been initialized");
return NULL;
}
+
return g_object_new (MATE_MIXER_TYPE_CONTROL, NULL);
}
@@ -504,7 +513,8 @@ mate_mixer_control_set_backend_type (MateMixerControl *control,
return FALSE;
modules = mate_mixer_get_modules ();
- while (modules) {
+
+ while (modules != NULL) {
module = MATE_MIXER_BACKEND_MODULE (modules->data);
info = mate_mixer_backend_module_get_info (module);
@@ -540,11 +550,13 @@ mate_mixer_control_set_app_name (MateMixerControl *control, const gchar *app_nam
control->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- g_free (control->priv->backend_data.app_name);
+ if (g_strcmp0 (control->priv->backend_data.app_name, app_name) != 0) {
+ g_free (control->priv->backend_data.app_name);
- control->priv->backend_data.app_name = g_strdup (app_name);
+ control->priv->backend_data.app_name = g_strdup (app_name);
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_NAME]);
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_NAME]);
+ }
return TRUE;
}
@@ -571,11 +583,13 @@ mate_mixer_control_set_app_id (MateMixerControl *control, const gchar *app_id)
control->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- g_free (control->priv->backend_data.app_id);
+ if (g_strcmp0 (control->priv->backend_data.app_id, app_id) != 0) {
+ g_free (control->priv->backend_data.app_id);
- control->priv->backend_data.app_id = g_strdup (app_id);
+ control->priv->backend_data.app_id = g_strdup (app_id);
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_ID]);
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_ID]);
+ }
return TRUE;
}
@@ -602,11 +616,13 @@ mate_mixer_control_set_app_version (MateMixerControl *control, const gchar *app_
control->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- g_free (control->priv->backend_data.app_version);
+ if (g_strcmp0 (control->priv->backend_data.app_version, app_version) != 0) {
+ g_free (control->priv->backend_data.app_version);
- control->priv->backend_data.app_version = g_strdup (app_version);
+ control->priv->backend_data.app_version = g_strdup (app_version);
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_VERSION]);
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_VERSION]);
+ }
return TRUE;
}
@@ -633,11 +649,13 @@ mate_mixer_control_set_app_icon (MateMixerControl *control, const gchar *app_ico
control->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- g_free (control->priv->backend_data.app_icon);
+ if (g_strcmp0 (control->priv->backend_data.app_icon, app_icon) != 0) {
+ g_free (control->priv->backend_data.app_icon);
- control->priv->backend_data.app_icon = g_strdup (app_icon);
+ control->priv->backend_data.app_icon = g_strdup (app_icon);
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_ICON]);
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_APP_ICON]);
+ }
return TRUE;
}
@@ -665,11 +683,13 @@ mate_mixer_control_set_server_address (MateMixerControl *control, const gchar *a
control->priv->state == MATE_MIXER_STATE_READY)
return FALSE;
- g_free (control->priv->backend_data.server_address);
+ if (g_strcmp0 (control->priv->backend_data.server_address, address) != 0) {
+ g_free (control->priv->backend_data.server_address);
- control->priv->backend_data.server_address = g_strdup (address);
+ control->priv->backend_data.server_address = g_strdup (address);
- g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_SERVER_ADDRESS]);
+ g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_SERVER_ADDRESS]);
+ }
return TRUE;
}
@@ -718,7 +738,7 @@ mate_mixer_control_open (MateMixerControl *control)
modules = mate_mixer_get_modules ();
if (control->priv->backend_type != MATE_MIXER_BACKEND_UNKNOWN) {
- while (modules) {
+ while (modules != NULL) {
const MateMixerBackendInfo *info;
module = MATE_MIXER_BACKEND_MODULE (modules->data);
@@ -736,7 +756,7 @@ mate_mixer_control_open (MateMixerControl *control)
}
if (module == NULL) {
/* Most likely the selected backend is not installed */
- control_change_state (control, MATE_MIXER_STATE_FAILED);
+ change_state (control, MATE_MIXER_STATE_FAILED);
return FALSE;
}
@@ -750,19 +770,19 @@ mate_mixer_control_open (MateMixerControl *control)
/* This transitional state is always present, it will change to MATE_MIXER_STATE_READY
* or MATE_MIXER_STATE_FAILED either instantly or asynchronously */
- control_change_state (control, MATE_MIXER_STATE_CONNECTING);
+ change_state (control, MATE_MIXER_STATE_CONNECTING);
/* The backend initialization might fail in case it is known right now that
* the backend is unusable */
- if (!mate_mixer_backend_open (control->priv->backend)) {
+ if (mate_mixer_backend_open (control->priv->backend) == FALSE) {
if (control->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN) {
/* User didn't request a specific backend, so try another one */
- return control_try_next_backend (control);
+ return try_next_backend (control);
}
/* User requested a specific backend and it failed */
- control_close (control);
- control_change_state (control, MATE_MIXER_STATE_FAILED);
+ close_control (control);
+ change_state (control, MATE_MIXER_STATE_FAILED);
return FALSE;
}
@@ -773,17 +793,20 @@ mate_mixer_control_open (MateMixerControl *control)
/* This would be a backend bug */
g_warn_if_reached ();
- control_close (control);
- control_change_state (control, MATE_MIXER_STATE_FAILED);
+ if (control->priv->backend_type == MATE_MIXER_BACKEND_UNKNOWN)
+ return try_next_backend (control);
+
+ close_control (control);
+ change_state (control, MATE_MIXER_STATE_FAILED);
return FALSE;
}
- g_signal_connect (control->priv->backend,
+ g_signal_connect (G_OBJECT (control->priv->backend),
"notify::state",
- G_CALLBACK (control_backend_state_cb),
+ G_CALLBACK (on_backend_state_notify),
control);
- control_change_state (control, state);
+ change_state (control, state);
return TRUE;
}
@@ -799,8 +822,8 @@ 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);
+ close_control (control);
+ change_state (control, MATE_MIXER_STATE_IDLE);
}
/**
@@ -837,10 +860,10 @@ mate_mixer_control_get_device (MateMixerControl *control, const gchar *name)
g_return_val_if_fail (name != NULL, NULL);
list = mate_mixer_control_list_devices (control);
- while (list) {
+ while (list != NULL) {
MateMixerDevice *device = MATE_MIXER_DEVICE (list->data);
- if (!strcmp (name, mate_mixer_device_get_name (device)))
+ if (strcmp (name, mate_mixer_device_get_name (device)) == 0)
return device;
list = list->next;
@@ -866,10 +889,36 @@ mate_mixer_control_get_stream (MateMixerControl *control, const gchar *name)
g_return_val_if_fail (name != NULL, NULL);
list = mate_mixer_control_list_streams (control);
+ while (list != NULL) {
+ MateMixerStream *stream = MATE_MIXER_STREAM (list->data);
+
+ if (strcmp (name, mate_mixer_stream_get_name (stream)) == 0)
+ return stream;
+
+ list = list->next;
+ }
+ return NULL;
+}
+
+/**
+ * mate_mixer_control_get_cached_stream:
+ * @control: a #MateMixerControl
+ * @name: a stream name
+ *
+ */
+MateMixerStream *
+mate_mixer_control_get_cached_stream (MateMixerControl *control, const gchar *name)
+{
+ const GList *list;
+
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ list = mate_mixer_control_list_cached_streams (control);
while (list) {
MateMixerStream *stream = MATE_MIXER_STREAM (list->data);
- if (!strcmp (name, mate_mixer_stream_get_name (stream)))
+ if (strcmp (name, mate_mixer_stream_get_name (stream)) == 0)
return stream;
list = list->next;
@@ -938,6 +987,28 @@ mate_mixer_control_list_streams (MateMixerControl *control)
}
/**
+ * mate_mixer_control_list_cached_streams:
+ * @control: a #MateMixerControl
+ *
+ */
+const GList *
+mate_mixer_control_list_cached_streams (MateMixerControl *control)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), 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 */
+ if (control->priv->cached_streams == NULL)
+ control->priv->cached_streams =
+ mate_mixer_backend_list_cached_streams (MATE_MIXER_BACKEND (control->priv->backend));
+
+ return (const GList *) control->priv->cached_streams;
+}
+
+/**
* mate_mixer_control_get_default_input_stream:
* @control: a #MateMixerControl
*
@@ -1057,7 +1128,7 @@ mate_mixer_control_get_backend_name (MateMixerControl *control)
{
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), NULL);
- if (!control->priv->backend_chosen)
+ if (control->priv->backend_chosen == FALSE)
return NULL;
return mate_mixer_backend_module_get_info (control->priv->module)->name;
@@ -1077,16 +1148,16 @@ mate_mixer_control_get_backend_type (MateMixerControl *control)
{
g_return_val_if_fail (MATE_MIXER_IS_CONTROL (control), MATE_MIXER_BACKEND_UNKNOWN);
- if (!control->priv->backend_chosen)
+ if (control->priv->backend_chosen == FALSE)
return MATE_MIXER_BACKEND_UNKNOWN;
return mate_mixer_backend_module_get_info (control->priv->module)->backend_type;
}
static void
-control_backend_state_cb (MateMixerBackend *backend,
- GParamSpec *pspec,
- MateMixerControl *control)
+on_backend_state_notify (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerControl *control)
{
MateMixerState state = mate_mixer_backend_get_state (backend);
@@ -1095,19 +1166,20 @@ control_backend_state_cb (MateMixerBackend *backend,
g_debug ("Backend %s changed state to CONNECTING",
mate_mixer_backend_module_get_info (control->priv->module)->name);
- if (control->priv->backend_chosen) {
+ if (control->priv->backend_chosen == TRUE) {
/* Invalidate cached data when reconnecting */
- control_free_devices (control);
- control_free_devices (control);
+ free_devices (control);
+ free_streams (control);
+ free_cached_streams (control);
}
- control_change_state (control, state);
+ 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);
+ change_state (control, state);
break;
case MATE_MIXER_STATE_FAILED:
@@ -1116,11 +1188,11 @@ control_backend_state_cb (MateMixerBackend *backend,
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);
+ try_next_backend (control);
} else {
/* User requested a specific backend and it failed */
- control_close (control);
- control_change_state (control, state);
+ close_control (control);
+ change_state (control, state);
}
break;
@@ -1130,11 +1202,11 @@ control_backend_state_cb (MateMixerBackend *backend,
}
static void
-control_backend_device_added_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control)
+on_backend_device_added (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
{
- control_free_devices (control);
+ free_devices (control);
g_signal_emit (G_OBJECT (control),
signals[DEVICE_ADDED],
@@ -1143,107 +1215,110 @@ control_backend_device_added_cb (MateMixerBackend *backend,
}
static void
-control_backend_device_changed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control)
+on_backend_device_removed (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
{
+ free_devices (control);
+
g_signal_emit (G_OBJECT (control),
- signals[DEVICE_CHANGED],
+ signals[DEVICE_REMOVED],
0,
name);
}
static void
-control_backend_device_removed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control)
+on_backend_stream_added (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
{
- control_free_devices (control);
+ free_streams (control);
g_signal_emit (G_OBJECT (control),
- signals[DEVICE_REMOVED],
+ signals[STREAM_ADDED],
0,
name);
}
static void
-control_backend_stream_added_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control)
+on_backend_stream_removed (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
{
- control_free_streams (control);
+ free_streams (control);
g_signal_emit (G_OBJECT (control),
- signals[STREAM_ADDED],
+ signals[STREAM_REMOVED],
0,
name);
}
static void
-control_backend_stream_changed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control)
+on_backend_cached_stream_added (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
{
+ free_cached_streams (control);
+
g_signal_emit (G_OBJECT (control),
- signals[STREAM_CHANGED],
+ signals[CACHED_STREAM_ADDED],
0,
name);
}
static void
-control_backend_stream_removed_cb (MateMixerBackend *backend,
- const gchar *name,
- MateMixerControl *control)
+on_backend_cached_stream_removed (MateMixerBackend *backend,
+ const gchar *name,
+ MateMixerControl *control)
{
- control_free_streams (control);
+ free_cached_streams (control);
g_signal_emit (G_OBJECT (control),
- signals[STREAM_REMOVED],
+ signals[CACHED_STREAM_REMOVED],
0,
name);
}
static void
-control_backend_default_input_cb (MateMixerBackend *backend,
- GParamSpec *pspec,
- MateMixerControl *control)
+on_backend_default_input_notify (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerControl *control)
{
g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_DEFAULT_INPUT]);
}
static void
-control_backend_default_output_cb (MateMixerBackend *backend,
- GParamSpec *pspec,
- MateMixerControl *control)
+on_backend_default_output_notify (MateMixerBackend *backend,
+ GParamSpec *pspec,
+ MateMixerControl *control)
{
g_object_notify_by_pspec (G_OBJECT (control), properties[PROP_DEFAULT_OUTPUT]);
}
static gboolean
-control_try_next_backend (MateMixerControl *control)
+try_next_backend (MateMixerControl *control)
{
const GList *modules;
MateMixerBackendModule *module = NULL;
MateMixerState state;
modules = mate_mixer_get_modules ();
- while (modules) {
+
+ while (modules != NULL) {
if (control->priv->module == modules->data) {
/* Found the last tested backend, try to use the next one with a lower
* priority unless we have reached the end of the list */
- if (modules->next)
+ if (modules->next != NULL)
module = MATE_MIXER_BACKEND_MODULE (modules->next->data);
break;
}
modules = modules->next;
}
- control_close (control);
+ close_control (control);
if (module == NULL) {
- /* This shouldn't happen under normal circumstances as the lowest
- * priority module is the "Null" module which never fails to initialize,
- * but in a broken installation this module could be missing */
- control_change_state (control, MATE_MIXER_STATE_FAILED);
+ /* We have tried all the modules and all of them failed */
+ change_state (control, MATE_MIXER_STATE_FAILED);
return FALSE;
}
@@ -1253,8 +1328,10 @@ control_try_next_backend (MateMixerControl *control)
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);
+ /* Try to open this backend and in case of failure keep trying until we find
+ * one that works or reach the end of the list */
+ if (mate_mixer_backend_open (control->priv->backend) == FALSE)
+ return try_next_backend (control);
state = mate_mixer_backend_get_state (control->priv->backend);
@@ -1263,64 +1340,63 @@ control_try_next_backend (MateMixerControl *control)
/* This would be a backend bug */
g_warn_if_reached ();
- control_close (control);
- return control_try_next_backend (control);
+ return try_next_backend (control);
}
- g_signal_connect (control->priv->backend,
+ g_signal_connect (G_OBJECT (control->priv->backend),
"notify::state",
- G_CALLBACK (control_backend_state_cb),
+ G_CALLBACK (on_backend_state_notify),
control);
- control_change_state (control, state);
+ change_state (control, state);
return TRUE;
}
static void
-control_change_state (MateMixerControl *control, MateMixerState state)
+change_state (MateMixerControl *control, MateMixerState state)
{
if (control->priv->state == state)
return;
control->priv->state = state;
- if (state == MATE_MIXER_STATE_READY && !control->priv->backend_chosen) {
+ if (state == MATE_MIXER_STATE_READY && control->priv->backend_chosen == FALSE) {
/* 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;
* 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,
+ g_signal_connect (G_OBJECT (control->priv->backend),
"device-added",
- G_CALLBACK (control_backend_device_added_cb),
- control);
- g_signal_connect (control->priv->backend,
- "device-changed",
- G_CALLBACK (control_backend_device_changed_cb),
+ G_CALLBACK (on_backend_device_added),
control);
- g_signal_connect (control->priv->backend,
+ g_signal_connect (G_OBJECT (control->priv->backend),
"device-removed",
- G_CALLBACK (control_backend_device_removed_cb),
+ G_CALLBACK (on_backend_device_removed),
control);
- g_signal_connect (control->priv->backend,
+ g_signal_connect (G_OBJECT (control->priv->backend),
"stream-added",
- G_CALLBACK (control_backend_stream_added_cb),
+ G_CALLBACK (on_backend_stream_added),
control);
- g_signal_connect (control->priv->backend,
- "stream-changed",
- G_CALLBACK (control_backend_stream_changed_cb),
- control);
- g_signal_connect (control->priv->backend,
+ g_signal_connect (G_OBJECT (control->priv->backend),
"stream-removed",
- G_CALLBACK (control_backend_stream_removed_cb),
+ G_CALLBACK (on_backend_stream_removed),
+ control);
+ g_signal_connect (G_OBJECT (control->priv->backend),
+ "cached-stream-added",
+ G_CALLBACK (on_backend_cached_stream_added),
+ control);
+ g_signal_connect (G_OBJECT (control->priv->backend),
+ "cached-stream-removed",
+ G_CALLBACK (on_backend_cached_stream_removed),
control);
- g_signal_connect (control->priv->backend,
+ g_signal_connect (G_OBJECT (control->priv->backend),
"notify::default-input",
- G_CALLBACK (control_backend_default_input_cb),
+ G_CALLBACK (on_backend_default_input_notify),
control);
- g_signal_connect (control->priv->backend,
+ g_signal_connect (G_OBJECT (control->priv->backend),
"notify::default-output",
- G_CALLBACK (control_backend_default_output_cb),
+ G_CALLBACK (on_backend_default_output_notify),
control);
control->priv->backend_chosen = TRUE;
@@ -1330,28 +1406,34 @@ control_change_state (MateMixerControl *control, MateMixerState state)
}
static void
-control_close (MateMixerControl *control)
+close_control (MateMixerControl *control)
{
- control_free_backend (control);
- control_free_devices (control);
- control_free_streams (control);
+ free_backend (control);
+ free_devices (control);
+ free_streams (control);
+ free_cached_streams (control);
g_clear_object (&control->priv->module);
+
+ control->priv->backend_chosen = FALSE;
}
static void
-control_free_backend (MateMixerControl *control)
+free_backend (MateMixerControl *control)
{
if (control->priv->backend == NULL)
return;
+ g_signal_handlers_disconnect_by_data (G_OBJECT (control->priv->backend),
+ control);
+
mate_mixer_backend_close (control->priv->backend);
g_clear_object (&control->priv->backend);
}
static void
-control_free_devices (MateMixerControl *control)
+free_devices (MateMixerControl *control)
{
if (control->priv->devices == NULL)
return;
@@ -1362,7 +1444,7 @@ control_free_devices (MateMixerControl *control)
}
static void
-control_free_streams (MateMixerControl *control)
+free_streams (MateMixerControl *control)
{
if (control->priv->streams == NULL)
return;
@@ -1371,3 +1453,14 @@ control_free_streams (MateMixerControl *control)
control->priv->streams = NULL;
}
+
+static void
+free_cached_streams (MateMixerControl *control)
+{
+ if (control->priv->cached_streams == NULL)
+ return;
+
+ g_list_free_full (control->priv->cached_streams, g_object_unref);
+
+ control->priv->cached_streams = NULL;
+}
diff --git a/libmatemixer/matemixer-control.h b/libmatemixer/matemixer-control.h
index 5598ade..e6d3afa 100644
--- a/libmatemixer/matemixer-control.h
+++ b/libmatemixer/matemixer-control.h
@@ -68,21 +68,29 @@ struct _MateMixerControlClass
GObjectClass parent_class;
/*< private >*/
- void (*device_added) (MateMixerControl *control,
- const gchar *name);
- void (*device_changed) (MateMixerControl *control,
- const gchar *name);
- void (*device_removed) (MateMixerControl *control,
- const gchar *name);
- void (*stream_added) (MateMixerControl *control,
- const gchar *name);
- void (*stream_changed) (MateMixerControl *control,
- const gchar *name);
- void (*stream_removed) (MateMixerControl *control,
- const gchar *name);
+ /* Signals */
+ void (*device_added) (MateMixerControl *control,
+ const gchar *name);
+ void (*device_changed) (MateMixerControl *control,
+ const gchar *name);
+ void (*device_removed) (MateMixerControl *control,
+ const gchar *name);
+ void (*stream_added) (MateMixerControl *control,
+ const gchar *name);
+ void (*stream_changed) (MateMixerControl *control,
+ const gchar *name);
+ void (*stream_removed) (MateMixerControl *control,
+ const gchar *name);
+ void (*cached_stream_added) (MateMixerControl *control,
+ const gchar *name);
+ void (*cached_stream_changed) (MateMixerControl *control,
+ const gchar *name);
+ void (*cached_stream_removed) (MateMixerControl *control,
+ const gchar *name);
};
GType mate_mixer_control_get_type (void) G_GNUC_CONST;
+
MateMixerControl * mate_mixer_control_new (void);
gboolean mate_mixer_control_set_backend_type (MateMixerControl *control,
@@ -97,6 +105,7 @@ gboolean mate_mixer_control_set_app_icon (MateMixerCon
const gchar *app_icon);
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);
@@ -106,9 +115,12 @@ MateMixerDevice * mate_mixer_control_get_device (MateMixerCon
const gchar *name);
MateMixerStream * mate_mixer_control_get_stream (MateMixerControl *control,
const gchar *name);
+MateMixerStream * mate_mixer_control_get_cached_stream (MateMixerControl *control,
+ const gchar *name);
const GList * mate_mixer_control_list_devices (MateMixerControl *control);
const GList * mate_mixer_control_list_streams (MateMixerControl *control);
+const GList * mate_mixer_control_list_cached_streams (MateMixerControl *control);
MateMixerStream * mate_mixer_control_get_default_input_stream (MateMixerControl *control);
gboolean mate_mixer_control_set_default_input_stream (MateMixerControl *control,
diff --git a/libmatemixer/matemixer-device-profile-private.h b/libmatemixer/matemixer-device-profile-private.h
new file mode 100644
index 0000000..403c7d7
--- /dev/null
+++ b/libmatemixer/matemixer-device-profile-private.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_DEVICE_PROFILE_PRIVATE_H
+#define MATEMIXER_DEVICE_PROFILE_PRIVATE_H
+
+#include <glib.h>
+
+#include "matemixer-device-profile.h"
+
+G_BEGIN_DECLS
+
+MateMixerDeviceProfile *_mate_mixer_device_profile_new (const gchar *name,
+ const gchar *description,
+ guint priority,
+ guint input_streams,
+ guint output_streams);
+
+gboolean _mate_mixer_device_profile_update_description (MateMixerDeviceProfile *profile,
+ const gchar *description);
+gboolean _mate_mixer_device_profile_update_priority (MateMixerDeviceProfile *profile,
+ guint priority);
+gboolean _mate_mixer_device_profile_update_num_input_streams (MateMixerDeviceProfile *profile,
+ guint num);
+gboolean _mate_mixer_device_profile_update_num_output_streams (MateMixerDeviceProfile *profile,
+ guint num);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_DEVICE_PROFILE_PRIVATE_H */
diff --git a/libmatemixer/matemixer-device-profile.c b/libmatemixer/matemixer-device-profile.c
index e229b6a..0485740 100644
--- a/libmatemixer/matemixer-device-profile.c
+++ b/libmatemixer/matemixer-device-profile.c
@@ -19,9 +19,11 @@
#include <glib-object.h>
#include "matemixer-device-profile.h"
+#include "matemixer-device-profile-private.h"
/**
* SECTION:matemixer-device-profile
+ * @short_description: Device profile
* @include: libmatemixer/matemixer.h
*/
@@ -46,19 +48,19 @@ enum {
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
-static void mate_mixer_device_profile_class_init (MateMixerDeviceProfileClass *klass);
+static void mate_mixer_device_profile_class_init (MateMixerDeviceProfileClass *klass);
-static void mate_mixer_device_profile_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec);
-static void mate_mixer_device_profile_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec);
+static void mate_mixer_device_profile_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void mate_mixer_device_profile_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
-static void mate_mixer_device_profile_init (MateMixerDeviceProfile *profile);
-static void mate_mixer_device_profile_finalize (GObject *object);
+static void mate_mixer_device_profile_init (MateMixerDeviceProfile *profile);
+static void mate_mixer_device_profile_finalize (GObject *object);
G_DEFINE_TYPE (MateMixerDeviceProfile, mate_mixer_device_profile, G_TYPE_OBJECT);
@@ -215,22 +217,10 @@ mate_mixer_device_profile_finalize (GObject *object)
G_OBJECT_CLASS (mate_mixer_device_profile_parent_class)->finalize (object);
}
-MateMixerDeviceProfile *
-mate_mixer_device_profile_new (const gchar *name,
- const gchar *description,
- guint priority,
- guint input_streams,
- guint output_streams)
-{
- return g_object_new (MATE_MIXER_TYPE_DEVICE_PROFILE,
- "name", name,
- "description", description,
- "priority", priority,
- "num-input-streams", input_streams,
- "num-output-streams", output_streams,
- NULL);
-}
-
+/**
+ * mate_mixer_device_profile_get_name:
+ * @profile: a #MateMixerDeviceProfile
+ */
const gchar *
mate_mixer_device_profile_get_name (MateMixerDeviceProfile *profile)
{
@@ -239,6 +229,10 @@ mate_mixer_device_profile_get_name (MateMixerDeviceProfile *profile)
return profile->priv->name;
}
+/**
+ * mate_mixer_device_profile_get_description:
+ * @profile: a #MateMixerDeviceProfile
+ */
const gchar *
mate_mixer_device_profile_get_description (MateMixerDeviceProfile *profile)
{
@@ -247,6 +241,10 @@ mate_mixer_device_profile_get_description (MateMixerDeviceProfile *profile)
return profile->priv->description;
}
+/**
+ * mate_mixer_device_profile_get_priority:
+ * @profile: a #MateMixerDeviceProfile
+ */
guint
mate_mixer_device_profile_get_priority (MateMixerDeviceProfile *profile)
{
@@ -255,6 +253,10 @@ mate_mixer_device_profile_get_priority (MateMixerDeviceProfile *profile)
return profile->priv->priority;
}
+/**
+ * mate_mixer_device_profile_get_num_input_streams:
+ * @profile: a #MateMixerDeviceProfile
+ */
guint
mate_mixer_device_profile_get_num_input_streams (MateMixerDeviceProfile *profile)
{
@@ -263,6 +265,10 @@ mate_mixer_device_profile_get_num_input_streams (MateMixerDeviceProfile *profile
return profile->priv->num_input_streams;
}
+/**
+ * mate_mixer_device_profile_get_num_output_streams:
+ * @profile: a #MateMixerDeviceProfile
+ */
guint
mate_mixer_device_profile_get_num_output_streams (MateMixerDeviceProfile *profile)
{
@@ -270,3 +276,85 @@ mate_mixer_device_profile_get_num_output_streams (MateMixerDeviceProfile *profil
return profile->priv->num_output_streams;
}
+
+MateMixerDeviceProfile *
+_mate_mixer_device_profile_new (const gchar *name,
+ const gchar *description,
+ guint priority,
+ guint input_streams,
+ guint output_streams)
+{
+ return g_object_new (MATE_MIXER_TYPE_DEVICE_PROFILE,
+ "name", name,
+ "description", description,
+ "priority", priority,
+ "num-input-streams", input_streams,
+ "num-output-streams", output_streams,
+ NULL);
+}
+
+gboolean
+_mate_mixer_device_profile_update_description (MateMixerDeviceProfile *profile,
+ const gchar *description)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
+
+ if (g_strcmp0 (profile->priv->description, description) != 0) {
+ g_free (profile->priv->description);
+
+ profile->priv->description = g_strdup (description);
+
+ g_object_notify_by_pspec (G_OBJECT (profile), properties[PROP_DESCRIPTION]);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+_mate_mixer_device_profile_update_priority (MateMixerDeviceProfile *profile,
+ guint priority)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
+
+ if (profile->priv->priority != priority) {
+ profile->priv->priority = priority;
+
+ g_object_notify_by_pspec (G_OBJECT (profile), properties[PROP_PRIORITY]);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+_mate_mixer_device_profile_update_num_input_streams (MateMixerDeviceProfile *profile,
+ guint num)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
+
+ if (profile->priv->num_input_streams != num) {
+ profile->priv->num_input_streams = num;
+
+ g_object_notify_by_pspec (G_OBJECT (profile), properties[PROP_NUM_INPUT_STREAMS]);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+_mate_mixer_device_profile_update_num_output_streams (MateMixerDeviceProfile *profile,
+ guint num)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
+
+ if (profile->priv->num_output_streams != num) {
+ profile->priv->num_output_streams = num;
+
+ g_object_notify_by_pspec (G_OBJECT (profile), properties[PROP_NUM_OUTPUT_STREAMS]);
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/libmatemixer/matemixer-device-profile.h b/libmatemixer/matemixer-device-profile.h
index 6a4368b..e8fae19 100644
--- a/libmatemixer/matemixer-device-profile.h
+++ b/libmatemixer/matemixer-device-profile.h
@@ -53,19 +53,13 @@ struct _MateMixerDeviceProfileClass
GObjectClass parent_class;
};
-GType mate_mixer_device_profile_get_type (void) G_GNUC_CONST;
+GType mate_mixer_device_profile_get_type (void) G_GNUC_CONST;
-MateMixerDeviceProfile *mate_mixer_device_profile_new (const gchar *name,
- const gchar *description,
- guint priority,
- guint input_streams,
- guint output_streams);
-
-const gchar * mate_mixer_device_profile_get_name (MateMixerDeviceProfile *profile);
-const gchar * mate_mixer_device_profile_get_description (MateMixerDeviceProfile *profile);
-guint mate_mixer_device_profile_get_priority (MateMixerDeviceProfile *profile);
-guint mate_mixer_device_profile_get_num_input_streams (MateMixerDeviceProfile *profile);
-guint mate_mixer_device_profile_get_num_output_streams (MateMixerDeviceProfile *profile);
+const gchar *mate_mixer_device_profile_get_name (MateMixerDeviceProfile *profile);
+const gchar *mate_mixer_device_profile_get_description (MateMixerDeviceProfile *profile);
+guint mate_mixer_device_profile_get_priority (MateMixerDeviceProfile *profile);
+guint mate_mixer_device_profile_get_num_input_streams (MateMixerDeviceProfile *profile);
+guint mate_mixer_device_profile_get_num_output_streams (MateMixerDeviceProfile *profile);
G_END_DECLS
diff --git a/libmatemixer/matemixer-device.c b/libmatemixer/matemixer-device.c
index 00a848a..0406709 100644
--- a/libmatemixer/matemixer-device.c
+++ b/libmatemixer/matemixer-device.c
@@ -20,9 +20,11 @@
#include "matemixer-device.h"
#include "matemixer-device-profile.h"
+#include "matemixer-port.h"
/**
* SECTION:matemixer-device
+ * @short_description: Hardware or software device in the sound system
* @include: libmatemixer/matemixer.h
*/
@@ -34,7 +36,7 @@ mate_mixer_device_default_init (MateMixerDeviceInterface *iface)
g_object_interface_install_property (iface,
g_param_spec_string ("name",
"Name",
- "Name of the sound device",
+ "Name of the device",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
@@ -42,7 +44,7 @@ mate_mixer_device_default_init (MateMixerDeviceInterface *iface)
g_object_interface_install_property (iface,
g_param_spec_string ("description",
"Description",
- "Description of the sound device",
+ "Description of the device",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
@@ -56,36 +58,31 @@ mate_mixer_device_default_init (MateMixerDeviceInterface *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_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",
+ "The currently active profile of the device",
MATE_MIXER_TYPE_DEVICE_PROFILE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
}
+/**
+ * mate_mixer_device_get_name:
+ * @device: a #MateMixerDevice
+ */
const gchar *
mate_mixer_device_get_name (MateMixerDevice *device)
{
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
+ /* Implementation required */
return MATE_MIXER_DEVICE_GET_INTERFACE (device)->get_name (device);
}
+/**
+ * mate_mixer_device_get_description:
+ * @device: a #MateMixerDevice
+ */
const gchar *
mate_mixer_device_get_description (MateMixerDevice *device)
{
@@ -101,6 +98,10 @@ mate_mixer_device_get_description (MateMixerDevice *device)
return NULL;
}
+/**
+ * mate_mixer_device_get_icon:
+ * @device: a #MateMixerDevice
+ */
const gchar *
mate_mixer_device_get_icon (MateMixerDevice *device)
{
@@ -116,6 +117,52 @@ mate_mixer_device_get_icon (MateMixerDevice *device)
return NULL;
}
+/**
+ * mate_mixer_device_get_port:
+ * @device: a #MateMixerDevice
+ * @name: a port name
+ */
+MateMixerPort *
+mate_mixer_device_get_port (MateMixerDevice *device, const gchar *name)
+{
+ MateMixerDeviceInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
+
+ if (iface->get_port)
+ return iface->get_port (device, name);
+
+ return NULL;
+}
+
+/**
+ * mate_mixer_device_get_profile:
+ * @device: a #MateMixerDevice
+ * @name: a profile name
+ */
+MateMixerDeviceProfile *
+mate_mixer_device_get_profile (MateMixerDevice *device, const gchar *name)
+{
+ MateMixerDeviceInterface *iface;
+
+ g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
+
+ if (iface->get_profile)
+ return iface->get_profile (device, name);
+
+ return NULL;
+}
+
+/**
+ * mate_mixer_device_list_ports:
+ * @device: a #MateMixerDevice
+ */
const GList *
mate_mixer_device_list_ports (MateMixerDevice *device)
{
@@ -131,6 +178,10 @@ mate_mixer_device_list_ports (MateMixerDevice *device)
return NULL;
}
+/**
+ * mate_mixer_device_list_profiles:
+ * @device: a #MateMixerDevice
+ */
const GList *
mate_mixer_device_list_profiles (MateMixerDevice *device)
{
@@ -146,6 +197,10 @@ mate_mixer_device_list_profiles (MateMixerDevice *device)
return NULL;
}
+/**
+ * mate_mixer_device_get_active_profile:
+ * @device: a #MateMixerDevice
+ */
MateMixerDeviceProfile *
mate_mixer_device_get_active_profile (MateMixerDevice *device)
{
@@ -161,13 +216,19 @@ mate_mixer_device_get_active_profile (MateMixerDevice *device)
return NULL;
}
+/**
+ * mate_mixer_device_set_active_profile:
+ * @device: a #MateMixerDevice
+ * @profile: a #MateMixerDeviceProfile
+ */
gboolean
-mate_mixer_device_set_active_profile (MateMixerDevice *device, const gchar *profile)
+mate_mixer_device_set_active_profile (MateMixerDevice *device,
+ MateMixerDeviceProfile *profile)
{
MateMixerDeviceInterface *iface;
g_return_val_if_fail (MATE_MIXER_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (profile != NULL, FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_DEVICE_PROFILE (profile), FALSE);
iface = MATE_MIXER_DEVICE_GET_INTERFACE (device);
diff --git a/libmatemixer/matemixer-device.h b/libmatemixer/matemixer-device.h
index ef283f1..340496b 100644
--- a/libmatemixer/matemixer-device.h
+++ b/libmatemixer/matemixer-device.h
@@ -22,6 +22,7 @@
#include <glib-object.h>
#include <libmatemixer/matemixer-device-profile.h>
+#include <libmatemixer/matemixer-port.h>
G_BEGIN_DECLS
@@ -42,29 +43,42 @@ struct _MateMixerDeviceInterface
GTypeInterface parent_iface;
/*< private >*/
- const gchar *(*get_name) (MateMixerDevice *device);
- const gchar *(*get_description) (MateMixerDevice *device);
- const gchar *(*get_icon) (MateMixerDevice *device);
- const GList *(*list_streams) (MateMixerDevice *device);
- const GList *(*list_ports) (MateMixerDevice *device);
- const GList *(*list_profiles) (MateMixerDevice *device);
- MateMixerDeviceProfile *(*get_active_profile) (MateMixerDevice *device);
- gboolean (*set_active_profile) (MateMixerDevice *device,
- const gchar *profile);
+ /* Virtual table */
+ const gchar *(*get_name) (MateMixerDevice *device);
+ const gchar *(*get_description) (MateMixerDevice *device);
+ const gchar *(*get_icon) (MateMixerDevice *device);
+
+ MateMixerPort *(*get_port) (MateMixerDevice *device,
+ const gchar *name);
+ MateMixerDeviceProfile *(*get_profile) (MateMixerDevice *device,
+ const gchar *name);
+
+ const GList *(*list_streams) (MateMixerDevice *device);
+ const GList *(*list_ports) (MateMixerDevice *device);
+ const GList *(*list_profiles) (MateMixerDevice *device);
+
+ MateMixerDeviceProfile *(*get_active_profile) (MateMixerDevice *device);
+ gboolean (*set_active_profile) (MateMixerDevice *device,
+ MateMixerDeviceProfile *profile);
};
GType mate_mixer_device_get_type (void) G_GNUC_CONST;
-const 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 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);
+
+MateMixerPort * mate_mixer_device_get_port (MateMixerDevice *device,
+ const gchar *name);
+MateMixerDeviceProfile *mate_mixer_device_get_profile (MateMixerDevice *device,
+ const gchar *name);
-const GList * mate_mixer_device_list_ports (MateMixerDevice *device);
-const GList * mate_mixer_device_list_profiles (MateMixerDevice *device);
+const GList * mate_mixer_device_list_ports (MateMixerDevice *device);
+const GList * mate_mixer_device_list_profiles (MateMixerDevice *device);
-MateMixerDeviceProfile *mate_mixer_device_get_active_profile (MateMixerDevice *device);
-gboolean mate_mixer_device_set_active_profile (MateMixerDevice *device,
- const gchar *profile);
+MateMixerDeviceProfile *mate_mixer_device_get_active_profile (MateMixerDevice *device);
+gboolean mate_mixer_device_set_active_profile (MateMixerDevice *device,
+ MateMixerDeviceProfile *profile);
G_END_DECLS
diff --git a/libmatemixer/matemixer-enum-types.c b/libmatemixer/matemixer-enum-types.c
index 0f60a6a..339b673 100644
--- a/libmatemixer/matemixer-enum-types.c
+++ b/libmatemixer/matemixer-enum-types.c
@@ -94,16 +94,14 @@ mate_mixer_stream_flags_get_type (void)
{ MATE_MIXER_STREAM_INPUT, "MATE_MIXER_STREAM_INPUT", "input" },
{ MATE_MIXER_STREAM_OUTPUT, "MATE_MIXER_STREAM_OUTPUT", "output" },
{ MATE_MIXER_STREAM_CLIENT, "MATE_MIXER_STREAM_CLIENT", "client" },
- { MATE_MIXER_STREAM_APPLICATION, "MATE_MIXER_STREAM_APPLICATION", "application" },
- { 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_SET_VOLUME, "MATE_MIXER_STREAM_CAN_SET_VOLUME", "can-set-volume" },
{ MATE_MIXER_STREAM_CAN_BALANCE, "MATE_MIXER_STREAM_CAN_BALANCE", "can-balance" },
{ MATE_MIXER_STREAM_CAN_FADE, "MATE_MIXER_STREAM_CAN_FADE", "can-fade" },
- { MATE_MIXER_STREAM_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 }
};
@@ -121,10 +119,10 @@ mate_mixer_stream_state_get_type (void)
if (etype == 0) {
static const GEnumValue values[] = {
- { 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" },
+ { MATE_MIXER_STREAM_STATE_UNKNOWN, "MATE_MIXER_STREAM_STATE_UNKNOWN", "unknown" },
+ { MATE_MIXER_STREAM_STATE_RUNNING, "MATE_MIXER_STREAM_STATE_RUNNING", "running" },
+ { MATE_MIXER_STREAM_STATE_IDLE, "MATE_MIXER_STREAM_STATE_IDLE", "idle" },
+ { MATE_MIXER_STREAM_STATE_SUSPENDED, "MATE_MIXER_STREAM_STATE_SUSPENDED", "suspended" },
{ 0, NULL, NULL }
};
etype = g_enum_register_static (
@@ -135,13 +133,60 @@ mate_mixer_stream_state_get_type (void)
}
GType
+mate_mixer_client_stream_flags_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GFlagsValue values[] = {
+ { MATE_MIXER_CLIENT_STREAM_NO_FLAGS, "MATE_MIXER_CLIENT_STREAM_NO_FLAGS", "no-flags" },
+ { MATE_MIXER_CLIENT_STREAM_APPLICATION, "MATE_MIXER_CLIENT_STREAM_APPLICATION", "application" },
+ { MATE_MIXER_CLIENT_STREAM_CACHED, "MATE_MIXER_CLIENT_STREAM_CACHED", "cached" },
+ { 0, NULL, NULL }
+ };
+ etype = g_flags_register_static (
+ g_intern_static_string ("MateMixerClientStreamFlags"),
+ values);
+ }
+ return etype;
+}
+
+GType
+mate_mixer_client_stream_role_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ { MATE_MIXER_CLIENT_STREAM_ROLE_NONE, "MATE_MIXER_CLIENT_STREAM_ROLE_NONE", "none" },
+ { MATE_MIXER_CLIENT_STREAM_ROLE_VIDEO, "MATE_MIXER_CLIENT_STREAM_ROLE_VIDEO", "video" },
+ { MATE_MIXER_CLIENT_STREAM_ROLE_MUSIC, "MATE_MIXER_CLIENT_STREAM_ROLE_MUSIC", "music" },
+ { MATE_MIXER_CLIENT_STREAM_ROLE_GAME, "MATE_MIXER_CLIENT_STREAM_ROLE_GAME", "game" },
+ { MATE_MIXER_CLIENT_STREAM_ROLE_EVENT, "MATE_MIXER_CLIENT_STREAM_ROLE_EVENT", "event" },
+ { MATE_MIXER_CLIENT_STREAM_ROLE_PHONE, "MATE_MIXER_CLIENT_STREAM_ROLE_PHONE", "phone" },
+ { MATE_MIXER_CLIENT_STREAM_ROLE_ANIMATION, "MATE_MIXER_CLIENT_STREAM_ROLE_ANIMATION", "animation" },
+ { MATE_MIXER_CLIENT_STREAM_ROLE_PRODUCTION, "MATE_MIXER_CLIENT_STREAM_ROLE_PRODUCTION", "production" },
+ { MATE_MIXER_CLIENT_STREAM_ROLE_A11Y, "MATE_MIXER_CLIENT_STREAM_ROLE_A11Y", "a11y" },
+ { MATE_MIXER_CLIENT_STREAM_ROLE_TEST, "MATE_MIXER_CLIENT_STREAM_ROLE_TEST", "test" },
+ { MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT, "MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT", "abstract" },
+ { MATE_MIXER_CLIENT_STREAM_ROLE_FILTER, "MATE_MIXER_CLIENT_STREAM_ROLE_FILTER", "filter" },
+ { 0, NULL, NULL }
+ };
+ etype = g_enum_register_static (
+ g_intern_static_string ("MateMixerClientStreamRole"),
+ values);
+ }
+ return etype;
+}
+
+GType
mate_mixer_channel_position_get_type (void)
{
static GType etype = 0;
if (etype == 0) {
static const GEnumValue values[] = {
- { MATE_MIXER_CHANNEL_UNKNOWN_POSITION, "MATE_MIXER_CHANNEL_UNKNOWN_POSITION", "unknown-position" },
+ { MATE_MIXER_CHANNEL_UNKNOWN, "MATE_MIXER_CHANNEL_UNKNOWN", "unknown" },
{ MATE_MIXER_CHANNEL_MONO, "MATE_MIXER_CHANNEL_MONO", "mono" },
{ MATE_MIXER_CHANNEL_FRONT_LEFT, "MATE_MIXER_CHANNEL_FRONT_LEFT", "front-left" },
{ MATE_MIXER_CHANNEL_FRONT_RIGHT, "MATE_MIXER_CHANNEL_FRONT_RIGHT", "front-right" },
@@ -149,9 +194,9 @@ mate_mixer_channel_position_get_type (void)
{ MATE_MIXER_CHANNEL_LFE, "MATE_MIXER_CHANNEL_LFE", "lfe" },
{ MATE_MIXER_CHANNEL_BACK_LEFT, "MATE_MIXER_CHANNEL_BACK_LEFT", "back-left" },
{ MATE_MIXER_CHANNEL_BACK_RIGHT, "MATE_MIXER_CHANNEL_BACK_RIGHT", "back-right" },
- { MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER, "MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER", "front-left-center" },
- { MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER, "MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER", "front-right-center" },
- { MATE_MIXER_CHANNEL_BACK_CENTER, "MATE_MIXER_CHANNEL_BACK_CENTER", "back-center" },
+ { MATE_MIXER_CHANNEL_BACK_CENTER, "MATE_MIXER_STREAM_BACK_CENTER", "back-center" },
+ { MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER, "MATE_MIXER_STREAM_FRONT_LEFT_CENTER", "front-left-center" },
+ { MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER, "MATE_MIXER_STREAM_FRONT_RIGHT_CENTER", "front-right-center" },
{ MATE_MIXER_CHANNEL_SIDE_LEFT, "MATE_MIXER_CHANNEL_SIDE_LEFT", "side-left" },
{ MATE_MIXER_CHANNEL_SIDE_RIGHT, "MATE_MIXER_CHANNEL_SIDE_RIGHT", "side-right" },
{ MATE_MIXER_CHANNEL_TOP_FRONT_LEFT, "MATE_MIXER_CHANNEL_TOP_FRONT_LEFT", "top-front-left" },
diff --git a/libmatemixer/matemixer-enum-types.h b/libmatemixer/matemixer-enum-types.h
index 7b6fcf0..03c1297 100644
--- a/libmatemixer/matemixer-enum-types.h
+++ b/libmatemixer/matemixer-enum-types.h
@@ -43,6 +43,12 @@ GType mate_mixer_stream_flags_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_CLIENT_STREAM_FLAGS (mate_mixer_client_stream_flags_get_type ())
+GType mate_mixer_client_stream_flags_get_type (void) G_GNUC_CONST;
+
+#define MATE_MIXER_TYPE_CLIENT_STREAM_ROLE (mate_mixer_client_stream_role_get_type ())
+GType mate_mixer_client_stream_role_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 4753aaf..a6326ce 100644
--- a/libmatemixer/matemixer-enums.h
+++ b/libmatemixer/matemixer-enums.h
@@ -23,8 +23,16 @@
* https://bugzilla.gnome.org/show_bug.cgi?id=621942
*/
+/**
+ * MateMixerState:
+ * @MATE_MIXER_STATE_IDLE:
+ * @MATE_MIXER_STATE_CONNECTING:
+ * @MATE_MIXER_STATE_READY:
+ * @MATE_MIXER_STATE_FAILED:
+ * @MATE_MIXER_STATE_UNKNOWN:
+ */
typedef enum {
- MATE_MIXER_STATE_IDLE = 0,
+ MATE_MIXER_STATE_IDLE,
MATE_MIXER_STATE_CONNECTING,
MATE_MIXER_STATE_READY,
MATE_MIXER_STATE_FAILED,
@@ -46,11 +54,18 @@ typedef enum {
* "real" backends fail to initialize.
*/
typedef enum {
- MATE_MIXER_BACKEND_UNKNOWN = 0,
+ MATE_MIXER_BACKEND_UNKNOWN,
MATE_MIXER_BACKEND_PULSEAUDIO,
MATE_MIXER_BACKEND_NULL
} MateMixerBackendType;
+/**
+ * MateMixerPortFlags:
+ * @MATE_MIXER_PORT_NO_FLAGS:
+ * @MATE_MIXER_PORT_AVAILABLE:
+ * @MATE_MIXER_PORT_INPUT:
+ * @MATE_MIXER_PORT_OUTPUT:
+ */
typedef enum { /*< flags >*/
MATE_MIXER_PORT_NO_FLAGS = 0,
MATE_MIXER_PORT_AVAILABLE = 1 << 0,
@@ -58,33 +73,119 @@ typedef enum { /*< flags >*/
MATE_MIXER_PORT_OUTPUT = 1 << 2
} MateMixerPortFlags;
+/**
+ * MateMixerStreamFlags:
+ * @MATE_MIXER_STREAM_NO_FLAGS:
+ * @MATE_MIXER_STREAM_INPUT:
+ * @MATE_MIXER_STREAM_OUTPUT:
+ * @MATE_MIXER_STREAM_CLIENT:
+ * @MATE_MIXER_STREAM_HAS_MUTE:
+ * @MATE_MIXER_STREAM_HAS_VOLUME:
+ * @MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME:
+ * @MATE_MIXER_STREAM_HAS_FLAT_VOLUME:
+ * @MATE_MIXER_STREAM_HAS_MONITOR:
+ * @MATE_MIXER_STREAM_CAN_SET_VOLUME:
+ * @MATE_MIXER_STREAM_CAN_BALANCE:
+ * @MATE_MIXER_STREAM_CAN_FADE:
+ * @MATE_MIXER_STREAM_CAN_SUSPEND:
+ */
typedef enum { /*< flags >*/
MATE_MIXER_STREAM_NO_FLAGS = 0,
MATE_MIXER_STREAM_INPUT = 1 << 0,
MATE_MIXER_STREAM_OUTPUT = 1 << 1,
MATE_MIXER_STREAM_CLIENT = 1 << 2,
- MATE_MIXER_STREAM_APPLICATION = 1 << 3,
- MATE_MIXER_STREAM_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_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
+ MATE_MIXER_STREAM_HAS_MUTE = 1 << 3,
+ MATE_MIXER_STREAM_HAS_VOLUME = 1 << 4,
+ MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME = 1 << 5,
+ MATE_MIXER_STREAM_HAS_FLAT_VOLUME = 1 << 6,
+ MATE_MIXER_STREAM_HAS_MONITOR = 1 << 7,
+ MATE_MIXER_STREAM_CAN_SET_VOLUME = 1 << 8,
+ MATE_MIXER_STREAM_CAN_BALANCE = 1 << 9,
+ MATE_MIXER_STREAM_CAN_FADE = 1 << 10,
+ MATE_MIXER_STREAM_CAN_SUSPEND = 1 << 11
} MateMixerStreamFlags;
+/**
+ * MateMixerStreamState:
+ * @MATE_MIXER_STREAM_STATE_UNKNOWN:
+ * @MATE_MIXER_STREAM_STATE_RUNNING:
+ * @MATE_MIXER_STREAM_STATE_IDLE:
+ * @MATE_MIXER_STREAM_STATE_SUSPENDED:
+ */
typedef enum {
- MATE_MIXER_STREAM_UNKNOWN_STATE,
- MATE_MIXER_STREAM_RUNNING,
- MATE_MIXER_STREAM_IDLE,
- MATE_MIXER_STREAM_SUSPENDED
+ MATE_MIXER_STREAM_STATE_UNKNOWN,
+ MATE_MIXER_STREAM_STATE_RUNNING,
+ MATE_MIXER_STREAM_STATE_IDLE,
+ MATE_MIXER_STREAM_STATE_SUSPENDED
} MateMixerStreamState;
+/**
+ * MateMixerClientStreamFlags:
+ * @MATE_MIXER_CLIENT_STREAM_NO_FLAGS:
+ * @MATE_MIXER_CLIENT_STREAM_APPLICATION:
+ * @MATE_MIXER_CLIENT_STREAM_CACHED:
+ */
+typedef enum { /*< flags >*/
+ MATE_MIXER_CLIENT_STREAM_NO_FLAGS = 0,
+ MATE_MIXER_CLIENT_STREAM_APPLICATION = 1 << 0,
+ MATE_MIXER_CLIENT_STREAM_CACHED = 1 << 1,
+} MateMixerClientStreamFlags;
+
+/**
+ * MateMixerClientStreamRole:
+ * @MATE_MIXER_CLIENT_STREAM_ROLE_NONE:
+ * @MATE_MIXER_CLIENT_STREAM_ROLE_VIDEO:
+ * @MATE_MIXER_CLIENT_STREAM_ROLE_MUSIC:
+ * @MATE_MIXER_CLIENT_STREAM_ROLE_GAME:
+ * @MATE_MIXER_CLIENT_STREAM_ROLE_EVENT:
+ * @MATE_MIXER_CLIENT_STREAM_ROLE_PHONE:
+ * @MATE_MIXER_CLIENT_STREAM_ROLE_ANIMATION:
+ * @MATE_MIXER_CLIENT_STREAM_ROLE_PRODUCTION:
+ * @MATE_MIXER_CLIENT_STREAM_ROLE_A11Y:
+ * @MATE_MIXER_CLIENT_STREAM_ROLE_TEST:
+ * @MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT:
+ * @MATE_MIXER_CLIENT_STREAM_ROLE_FILTER:
+ */
+typedef enum {
+ MATE_MIXER_CLIENT_STREAM_ROLE_NONE,
+ MATE_MIXER_CLIENT_STREAM_ROLE_VIDEO,
+ MATE_MIXER_CLIENT_STREAM_ROLE_MUSIC,
+ MATE_MIXER_CLIENT_STREAM_ROLE_GAME,
+ MATE_MIXER_CLIENT_STREAM_ROLE_EVENT,
+ MATE_MIXER_CLIENT_STREAM_ROLE_PHONE,
+ MATE_MIXER_CLIENT_STREAM_ROLE_ANIMATION,
+ MATE_MIXER_CLIENT_STREAM_ROLE_PRODUCTION,
+ MATE_MIXER_CLIENT_STREAM_ROLE_A11Y,
+ MATE_MIXER_CLIENT_STREAM_ROLE_TEST,
+ MATE_MIXER_CLIENT_STREAM_ROLE_ABSTRACT,
+ MATE_MIXER_CLIENT_STREAM_ROLE_FILTER
+} MateMixerClientStreamRole;
+
+/**
+ * MateMixerChannelPosition:
+ * @MATE_MIXER_CHANNEL_UNKNOWN:
+ * @MATE_MIXER_CHANNEL_MONO:
+ * @MATE_MIXER_CHANNEL_FRONT_LEFT:
+ * @MATE_MIXER_CHANNEL_FRONT_RIGHT:
+ * @MATE_MIXER_CHANNEL_FRONT_CENTER:
+ * @MATE_MIXER_CHANNEL_LFE:
+ * @MATE_MIXER_CHANNEL_BACK_LEFT:
+ * @MATE_MIXER_CHANNEL_BACK_RIGHT:
+ * @MATE_MIXER_CHANNEL_BACK_CENTER:
+ * @MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER:
+ * @MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER:
+ * @MATE_MIXER_CHANNEL_SIDE_LEFT:
+ * @MATE_MIXER_CHANNEL_SIDE_RIGHT:
+ * @MATE_MIXER_CHANNEL_TOP_FRONT_LEFT:
+ * @MATE_MIXER_CHANNEL_TOP_FRONT_RIGHT:
+ * @MATE_MIXER_CHANNEL_TOP_FRONT_CENTER:
+ * @MATE_MIXER_CHANNEL_TOP_CENTER:
+ * @MATE_MIXER_CHANNEL_TOP_BACK_LEFT:
+ * @MATE_MIXER_CHANNEL_TOP_BACK_RIGHT:
+ * @MATE_MIXER_CHANNEL_TOP_BACK_CENTER:
+ */
typedef enum {
- MATE_MIXER_CHANNEL_UNKNOWN_POSITION,
+ MATE_MIXER_CHANNEL_UNKNOWN,
MATE_MIXER_CHANNEL_MONO,
MATE_MIXER_CHANNEL_FRONT_LEFT,
MATE_MIXER_CHANNEL_FRONT_RIGHT,
@@ -92,9 +193,9 @@ typedef enum {
MATE_MIXER_CHANNEL_LFE,
MATE_MIXER_CHANNEL_BACK_LEFT,
MATE_MIXER_CHANNEL_BACK_RIGHT,
+ MATE_MIXER_CHANNEL_BACK_CENTER,
MATE_MIXER_CHANNEL_FRONT_LEFT_CENTER,
MATE_MIXER_CHANNEL_FRONT_RIGHT_CENTER,
- MATE_MIXER_CHANNEL_BACK_CENTER,
MATE_MIXER_CHANNEL_SIDE_LEFT,
MATE_MIXER_CHANNEL_SIDE_RIGHT,
MATE_MIXER_CHANNEL_TOP_FRONT_LEFT,
diff --git a/libmatemixer/matemixer-port-private.h b/libmatemixer/matemixer-port-private.h
new file mode 100644
index 0000000..a696d27
--- /dev/null
+++ b/libmatemixer/matemixer-port-private.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 Michal Ratajsky <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MATEMIXER_PORT_PRIVATE_H
+#define MATEMIXER_PORT_PRIVATE_H
+
+#include <glib.h>
+
+#include "matemixer-enums.h"
+#include "matemixer-port.h"
+
+G_BEGIN_DECLS
+
+MateMixerPort *_mate_mixer_port_new (const gchar *name,
+ const gchar *description,
+ const gchar *icon,
+ guint priority,
+ MateMixerPortFlags flags);
+
+gboolean _mate_mixer_port_update_description (MateMixerPort *port,
+ const gchar *description);
+gboolean _mate_mixer_port_update_icon (MateMixerPort *port,
+ const gchar *icon);
+gboolean _mate_mixer_port_update_priority (MateMixerPort *port,
+ guint priority);
+gboolean _mate_mixer_port_update_flags (MateMixerPort *port,
+ MateMixerPortFlags flags);
+
+G_END_DECLS
+
+#endif /* MATEMIXER_PORT_PRIVATE_H */
diff --git a/libmatemixer/matemixer-port.c b/libmatemixer/matemixer-port.c
index 3a7670d..f89a8bb 100644
--- a/libmatemixer/matemixer-port.c
+++ b/libmatemixer/matemixer-port.c
@@ -21,6 +21,7 @@
#include "matemixer-enums.h"
#include "matemixer-enum-types.h"
#include "matemixer-port.h"
+#include "matemixer-port-private.h"
/**
* SECTION:matemixer-port
@@ -32,7 +33,7 @@ struct _MateMixerPortPrivate
gchar *name;
gchar *description;
gchar *icon;
- gulong priority;
+ guint priority;
MateMixerPortFlags flags;
};
@@ -102,15 +103,15 @@ mate_mixer_port_class_init (MateMixerPortClass *klass)
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);
+ g_param_spec_uint ("priority",
+ "Priority",
+ "Priority of the port",
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
properties[PROP_FLAGS] =
g_param_spec_flags ("flags",
@@ -148,7 +149,7 @@ mate_mixer_port_get_property (GObject *object,
g_value_set_string (value, port->priv->icon);
break;
case PROP_PRIORITY:
- g_value_set_ulong (value, port->priv->priority);
+ g_value_set_uint (value, port->priv->priority);
break;
case PROP_FLAGS:
g_value_set_flags (value, port->priv->flags);
@@ -183,7 +184,7 @@ mate_mixer_port_set_property (GObject *object,
port->priv->icon = g_strdup (g_value_get_string (value));
break;
case PROP_PRIORITY:
- port->priv->priority = g_value_get_ulong (value);
+ port->priv->priority = g_value_get_uint (value);
break;
case PROP_FLAGS:
port->priv->flags = g_value_get_flags (value);
@@ -216,22 +217,10 @@ mate_mixer_port_finalize (GObject *object)
G_OBJECT_CLASS (mate_mixer_port_parent_class)->finalize (object);
}
-MateMixerPort *
-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,
- "flags", flags,
- NULL);
-}
-
+/**
+ * mate_mixer_port_get_name:
+ * @port: a #MateMixerPort
+ */
const gchar *
mate_mixer_port_get_name (MateMixerPort *port)
{
@@ -240,6 +229,10 @@ mate_mixer_port_get_name (MateMixerPort *port)
return port->priv->name;
}
+/**
+ * mate_mixer_port_get_description:
+ * @port: a #MateMixerPort
+ */
const gchar *
mate_mixer_port_get_description (MateMixerPort *port)
{
@@ -248,6 +241,10 @@ mate_mixer_port_get_description (MateMixerPort *port)
return port->priv->description;
}
+/**
+ * mate_mixer_port_get_icon:
+ * @port: a #MateMixerPort
+ */
const gchar *
mate_mixer_port_get_icon (MateMixerPort *port)
{
@@ -256,7 +253,11 @@ mate_mixer_port_get_icon (MateMixerPort *port)
return port->priv->icon;
}
-gulong
+/**
+ * mate_mixer_port_get_priority:
+ * @port: a #MateMixerPort
+ */
+guint
mate_mixer_port_get_priority (MateMixerPort *port)
{
g_return_val_if_fail (MATE_MIXER_IS_PORT (port), 0);
@@ -264,6 +265,10 @@ mate_mixer_port_get_priority (MateMixerPort *port)
return port->priv->priority;
}
+/**
+ * mate_mixer_port_get_flags:
+ * @port: a #MateMixerPort
+ */
MateMixerPortFlags
mate_mixer_port_get_flags (MateMixerPort *port)
{
@@ -271,3 +276,83 @@ mate_mixer_port_get_flags (MateMixerPort *port)
return port->priv->flags;
}
+
+MateMixerPort *
+_mate_mixer_port_new (const gchar *name,
+ const gchar *description,
+ const gchar *icon,
+ guint priority,
+ MateMixerPortFlags flags)
+{
+ return g_object_new (MATE_MIXER_TYPE_PORT,
+ "name", name,
+ "description", description,
+ "icon", icon,
+ "priority", priority,
+ "flags", flags,
+ NULL);
+}
+
+gboolean
+_mate_mixer_port_update_description (MateMixerPort *port, const gchar *description)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
+
+ if (g_strcmp0 (port->priv->description, description) != 0) {
+ g_free (port->priv->description);
+
+ port->priv->description = g_strdup (description);
+
+ g_object_notify_by_pspec (G_OBJECT (port), properties[PROP_DESCRIPTION]);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+_mate_mixer_port_update_icon (MateMixerPort *port, const gchar *icon)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
+
+ if (g_strcmp0 (port->priv->icon, icon) != 0) {
+ g_free (port->priv->icon);
+
+ port->priv->icon = g_strdup (icon);
+
+ g_object_notify_by_pspec (G_OBJECT (port), properties[PROP_ICON]);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+_mate_mixer_port_update_priority (MateMixerPort *port, guint priority)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
+
+ if (port->priv->priority != priority) {
+ port->priv->priority = priority;
+
+ g_object_notify_by_pspec (G_OBJECT (port), properties[PROP_PRIORITY]);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+_mate_mixer_port_update_flags (MateMixerPort *port, MateMixerPortFlags flags)
+{
+ g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
+
+ if (port->priv->flags != flags) {
+ port->priv->flags = flags;
+
+ g_object_notify_by_pspec (G_OBJECT (port), properties[PROP_FLAGS]);
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/libmatemixer/matemixer-port.h b/libmatemixer/matemixer-port.h
index bda13ad..61f16f5 100644
--- a/libmatemixer/matemixer-port.h
+++ b/libmatemixer/matemixer-port.h
@@ -57,17 +57,11 @@ struct _MateMixerPortClass
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);
-MateMixerPortFlags mate_mixer_port_get_flags (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);
+guint mate_mixer_port_get_priority (MateMixerPort *port);
+MateMixerPortFlags mate_mixer_port_get_flags (MateMixerPort *port);
G_END_DECLS
diff --git a/libmatemixer/matemixer-stream.c b/libmatemixer/matemixer-stream.c
index 6f63217..6bec2be 100644
--- a/libmatemixer/matemixer-stream.c
+++ b/libmatemixer/matemixer-stream.c
@@ -79,7 +79,7 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
"State",
"Current state of the stream",
MATE_MIXER_TYPE_STREAM_STATE,
- MATE_MIXER_STREAM_UNKNOWN_STATE,
+ MATE_MIXER_STREAM_STATE_UNKNOWN,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
@@ -92,16 +92,6 @@ mate_mixer_stream_default_init (MateMixerStreamInterface *iface)
G_PARAM_STATIC_STRINGS));
g_object_interface_install_property (iface,
- g_param_spec_uint ("num-channels",
- "Number of channels",
- "Number of volume channels in the stream",
- 0,
- G_MAXUINT,
- 0,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
-
- g_object_interface_install_property (iface,
g_param_spec_uint ("volume",
"Volume",
"Volume of the stream",
@@ -132,13 +122,6 @@ 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",
@@ -215,14 +198,14 @@ mate_mixer_stream_get_state (MateMixerStream *stream)
{
MateMixerStreamInterface *iface;
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_UNKNOWN_STATE);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_STREAM_STATE_UNKNOWN);
iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
if (iface->get_state)
return iface->get_state (stream);
- return MATE_MIXER_STREAM_UNKNOWN_STATE;
+ return MATE_MIXER_STREAM_STATE_UNKNOWN;
}
gboolean
@@ -335,14 +318,14 @@ mate_mixer_stream_get_channel_position (MateMixerStream *stream, guint channel)
{
MateMixerStreamInterface *iface;
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_CHANNEL_UNKNOWN_POSITION);
+ g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_CHANNEL_UNKNOWN);
iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
if (iface->get_channel_position)
return iface->get_channel_position (stream, channel);
- return MATE_MIXER_CHANNEL_UNKNOWN_POSITION;
+ return MATE_MIXER_CHANNEL_UNKNOWN;
}
guint
@@ -410,83 +393,17 @@ mate_mixer_stream_set_channel_decibel (MateMixerStream *stream,
}
gboolean
-mate_mixer_stream_has_position (MateMixerStream *stream,
- MateMixerChannelPosition position)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->has_position)
- return iface->has_position (stream, position);
-
- return FALSE;
-}
-
-guint
-mate_mixer_stream_get_position_volume (MateMixerStream *stream,
- MateMixerChannelPosition position)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), 0);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_position_volume)
- return iface->get_position_volume (stream, position);
-
- return 0;
-}
-
-gboolean
-mate_mixer_stream_set_position_volume (MateMixerStream *stream,
- MateMixerChannelPosition position,
- guint volume)
-{
- MateMixerStreamInterface *iface;
-
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->set_position_volume)
- return iface->set_position_volume (stream, position, volume);
-
- return FALSE;
-}
-
-gdouble
-mate_mixer_stream_get_position_decibel (MateMixerStream *stream,
+mate_mixer_stream_has_channel_position (MateMixerStream *stream,
MateMixerChannelPosition position)
{
MateMixerStreamInterface *iface;
- g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), -MATE_MIXER_INFINITY);
-
- iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
-
- if (iface->get_position_decibel)
- return iface->get_position_decibel (stream, position);
-
- return -MATE_MIXER_INFINITY;
-}
-
-gboolean
-mate_mixer_stream_set_position_decibel (MateMixerStream *stream,
- MateMixerChannelPosition position,
- gdouble decibel)
-{
- MateMixerStreamInterface *iface;
-
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
- if (iface->set_position_decibel)
- return iface->set_position_decibel (stream, position, decibel);
+ if (iface->has_channel_position)
+ return iface->has_channel_position (stream, position);
return FALSE;
}
@@ -670,12 +587,12 @@ mate_mixer_stream_get_active_port (MateMixerStream *stream)
}
gboolean
-mate_mixer_stream_set_active_port (MateMixerStream *stream, const gchar *port)
+mate_mixer_stream_set_active_port (MateMixerStream *stream, MateMixerPort *port)
{
MateMixerStreamInterface *iface;
g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), FALSE);
- g_return_val_if_fail (port != NULL, FALSE);
+ g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
iface = MATE_MIXER_STREAM_GET_INTERFACE (stream);
diff --git a/libmatemixer/matemixer-stream.h b/libmatemixer/matemixer-stream.h
index 40a4463..e91a2a5 100644
--- a/libmatemixer/matemixer-stream.h
+++ b/libmatemixer/matemixer-stream.h
@@ -51,6 +51,7 @@ struct _MateMixerStreamInterface
GTypeInterface parent_iface;
/*< private >*/
+ /* Virtual table */
const gchar * (*get_name) (MateMixerStream *stream);
const gchar * (*get_description) (MateMixerStream *stream);
MateMixerDevice * (*get_device) (MateMixerStream *stream);
@@ -78,18 +79,8 @@ struct _MateMixerStreamInterface
gboolean (*set_channel_decibel) (MateMixerStream *stream,
guint channel,
gdouble decibel);
- gboolean (*has_position) (MateMixerStream *stream,
+ gboolean (*has_channel_position) (MateMixerStream *stream,
MateMixerChannelPosition position);
- guint (*get_position_volume) (MateMixerStream *stream,
- MateMixerChannelPosition position);
- gboolean (*set_position_volume) (MateMixerStream *stream,
- MateMixerChannelPosition position,
- guint volume);
- gdouble (*get_position_decibel) (MateMixerStream *stream,
- MateMixerChannelPosition position);
- gboolean (*set_position_decibel) (MateMixerStream *stream,
- MateMixerChannelPosition position,
- gdouble decibel);
gfloat (*get_balance) (MateMixerStream *stream);
gboolean (*set_balance) (MateMixerStream *stream,
gfloat balance);
@@ -106,7 +97,7 @@ struct _MateMixerStreamInterface
const GList * (*list_ports) (MateMixerStream *stream);
MateMixerPort * (*get_active_port) (MateMixerStream *stream);
gboolean (*set_active_port) (MateMixerStream *stream,
- const gchar *port);
+ MateMixerPort *port);
guint (*get_min_volume) (MateMixerStream *stream);
guint (*get_max_volume) (MateMixerStream *stream);
guint (*get_normal_volume) (MateMixerStream *stream);
@@ -117,86 +108,74 @@ struct _MateMixerStreamInterface
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);
-MateMixerDevice * mate_mixer_stream_get_device (MateMixerStream *stream);
-MateMixerStreamFlags mate_mixer_stream_get_flags (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,
- gboolean mute);
+GType mate_mixer_stream_get_type (void) G_GNUC_CONST;
-guint mate_mixer_stream_get_num_channels (MateMixerStream *stream);
+const gchar * mate_mixer_stream_get_name (MateMixerStream *stream);
+const gchar * mate_mixer_stream_get_description (MateMixerStream *stream);
+MateMixerDevice * mate_mixer_stream_get_device (MateMixerStream *stream);
+MateMixerStreamFlags mate_mixer_stream_get_flags (MateMixerStream *stream);
+MateMixerStreamState mate_mixer_stream_get_state (MateMixerStream *stream);
-guint mate_mixer_stream_get_volume (MateMixerStream *stream);
-gboolean mate_mixer_stream_set_volume (MateMixerStream *stream,
- guint volume);
+gboolean mate_mixer_stream_get_mute (MateMixerStream *stream);
+gboolean mate_mixer_stream_set_mute (MateMixerStream *stream,
+ gboolean mute);
-gdouble mate_mixer_stream_get_decibel (MateMixerStream *stream);
-gboolean mate_mixer_stream_set_decibel (MateMixerStream *stream,
- gdouble decibel);
+guint mate_mixer_stream_get_num_channels (MateMixerStream *stream);
-MateMixerChannelPosition mate_mixer_stream_get_channel_position (MateMixerStream *stream,
- guint channel);
+guint mate_mixer_stream_get_volume (MateMixerStream *stream);
+gboolean mate_mixer_stream_set_volume (MateMixerStream *stream,
+ guint volume);
-guint mate_mixer_stream_get_channel_volume (MateMixerStream *stream,
- guint channel);
-gboolean mate_mixer_stream_set_channel_volume (MateMixerStream *stream,
- guint channel,
- guint volume);
+gdouble mate_mixer_stream_get_decibel (MateMixerStream *stream);
+gboolean mate_mixer_stream_set_decibel (MateMixerStream *stream,
+ gdouble decibel);
-gdouble mate_mixer_stream_get_channel_decibel (MateMixerStream *stream,
- guint channel);
-gboolean mate_mixer_stream_set_channel_decibel (MateMixerStream *stream,
- guint channel,
- gdouble decibel);
+MateMixerChannelPosition mate_mixer_stream_get_channel_position (MateMixerStream *stream,
+ guint channel);
-gboolean mate_mixer_stream_has_position (MateMixerStream *stream,
- MateMixerChannelPosition position);
+guint mate_mixer_stream_get_channel_volume (MateMixerStream *stream,
+ guint channel);
+gboolean mate_mixer_stream_set_channel_volume (MateMixerStream *stream,
+ guint channel,
+ guint volume);
-guint mate_mixer_stream_get_position_volume (MateMixerStream *stream,
- MateMixerChannelPosition position);
-gboolean mate_mixer_stream_set_position_volume (MateMixerStream *stream,
- MateMixerChannelPosition position,
- guint volume);
+gdouble mate_mixer_stream_get_channel_decibel (MateMixerStream *stream,
+ guint channel);
+gboolean mate_mixer_stream_set_channel_decibel (MateMixerStream *stream,
+ guint channel,
+ gdouble decibel);
-gdouble mate_mixer_stream_get_position_decibel (MateMixerStream *stream,
- MateMixerChannelPosition position);
-gboolean mate_mixer_stream_set_position_decibel (MateMixerStream *stream,
- MateMixerChannelPosition position,
- gdouble decibel);
+gboolean mate_mixer_stream_has_channel_position (MateMixerStream *stream,
+ MateMixerChannelPosition position);
-gfloat mate_mixer_stream_get_balance (MateMixerStream *stream);
-gboolean mate_mixer_stream_set_balance (MateMixerStream *stream,
- gfloat balance);
+gfloat mate_mixer_stream_get_balance (MateMixerStream *stream);
+gboolean mate_mixer_stream_set_balance (MateMixerStream *stream,
+ gfloat balance);
-gfloat mate_mixer_stream_get_fade (MateMixerStream *stream);
-gboolean mate_mixer_stream_set_fade (MateMixerStream *stream,
- gfloat fade);
+gfloat mate_mixer_stream_get_fade (MateMixerStream *stream);
+gboolean mate_mixer_stream_set_fade (MateMixerStream *stream,
+ gfloat fade);
-gboolean mate_mixer_stream_suspend (MateMixerStream *stream);
-gboolean mate_mixer_stream_resume (MateMixerStream *stream);
+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_start (MateMixerStream *stream);
+void mate_mixer_stream_monitor_stop (MateMixerStream *stream);
-gboolean mate_mixer_stream_monitor_is_running (MateMixerStream *stream);
-gboolean mate_mixer_stream_monitor_set_name (MateMixerStream *stream,
- const gchar *name);
+gboolean mate_mixer_stream_monitor_is_running (MateMixerStream *stream);
+gboolean mate_mixer_stream_monitor_set_name (MateMixerStream *stream,
+ const gchar *name);
-const GList * mate_mixer_stream_list_ports (MateMixerStream *stream);
+const GList * mate_mixer_stream_list_ports (MateMixerStream *stream);
-MateMixerPort * mate_mixer_stream_get_active_port (MateMixerStream *stream);
-gboolean mate_mixer_stream_set_active_port (MateMixerStream *stream,
- const gchar *port);
+MateMixerPort * mate_mixer_stream_get_active_port (MateMixerStream *stream);
+gboolean mate_mixer_stream_set_active_port (MateMixerStream *stream,
+ MateMixerPort *port);
-guint mate_mixer_stream_get_min_volume (MateMixerStream *stream);
-guint mate_mixer_stream_get_max_volume (MateMixerStream *stream);
-guint mate_mixer_stream_get_normal_volume (MateMixerStream *stream);
-guint mate_mixer_stream_get_base_volume (MateMixerStream *stream);
+guint mate_mixer_stream_get_min_volume (MateMixerStream *stream);
+guint mate_mixer_stream_get_max_volume (MateMixerStream *stream);
+guint mate_mixer_stream_get_normal_volume (MateMixerStream *stream);
+guint mate_mixer_stream_get_base_volume (MateMixerStream *stream);
G_END_DECLS
diff --git a/libmatemixer/matemixer.c b/libmatemixer/matemixer.c
index 8965599..0ca09b9 100644
--- a/libmatemixer/matemixer.c
+++ b/libmatemixer/matemixer.c
@@ -25,11 +25,19 @@
#include "matemixer-private.h"
#include "matemixer-backend-module.h"
-static void mixer_load_modules (void);
-static gint mixer_compare_modules (gconstpointer a, gconstpointer b);
+/**
+ * SECTION:matemixer
+ * @short_description: Library initialization and support functions
+ * @title: MateMixer
+ * @include: libmatemixer/matemixer.h
+ */
+
+static void load_modules (void);
+static gint compare_modules (gconstpointer a,
+ gconstpointer b);
-static GList *mixer_modules = NULL;
-static gboolean mixer_initialized = FALSE;
+static GList *modules = NULL;
+static gboolean initialized = FALSE;
/**
* mate_mixer_init:
@@ -43,89 +51,89 @@ static gboolean mixer_initialized = FALSE;
gboolean
mate_mixer_init (void)
{
- if (!mixer_initialized) {
- mixer_load_modules ();
-
- if (mixer_modules) {
- GList *list;
-
- list = mixer_modules;
- while (list) {
- GTypeModule *module = G_TYPE_MODULE (list->data);
- GList *next = list->next;
-
- /* Attempt to load the module and remove it from the list
- * if it isn't usable */
- if (!g_type_module_use (module)) {
- g_object_unref (module);
- mixer_modules = g_list_delete_link (mixer_modules, list);
- }
- list = next;
- }
+ if (initialized == TRUE)
+ return TRUE;
+
+ load_modules ();
+
+ if (modules != NULL) {
+ GList *list = modules;
- if (mixer_modules) {
- /* Sort the usable modules by their priority */
- mixer_modules = g_list_sort (mixer_modules, mixer_compare_modules);
- mixer_initialized = TRUE;
- } else
- g_critical ("No usable backend modules have been found");
+ while (list != NULL) {
+ GTypeModule *module = G_TYPE_MODULE (list->data);
+ GList *next = list->next;
+
+ /* Load the plugin and remove it from the list if it fails */
+ if (g_type_module_use (module) == FALSE) {
+ g_object_unref (module);
+ modules = g_list_delete_link (modules, list);
+ }
+ list = next;
}
- }
- return mixer_initialized;
+ if (modules != NULL) {
+ /* Sort the usable modules by priority */
+ modules = g_list_sort (modules, compare_modules);
+ initialized = TRUE;
+ } else
+ g_critical ("No usable backend modules have been found");
+ } else
+ g_critical ("No backend modules have been found");
+
+ return initialized;
}
/**
* mate_mixer_is_initialized:
*
- * Returns TRUE if the library has been initialized.
+ * Returns %TRUE if the library has been initialized.
*
- * Returns: %TRUE or %FALSE
+ * Returns: %TRUE or %FALSE.
*/
gboolean
mate_mixer_is_initialized (void)
{
- return mixer_initialized;
+ return initialized;
}
/**
* mate_mixer_deinit:
*
- * Deinitializes the library. You should call this function when you do not need
- * to use the library any longer or before exitting the application.
+ * Deinitializes the library. You should call this function when you are done
+ * using the library.
*/
void
mate_mixer_deinit (void)
{
GList *list;
- if (!mixer_initialized)
+ if (initialized == FALSE)
return;
- list = mixer_modules;
- while (list) {
+ list = modules;
+ while (list != NULL) {
g_type_module_unuse (G_TYPE_MODULE (list->data));
list = list->next;
}
- mixer_initialized = FALSE;
+ initialized = FALSE;
}
/* Internal function: return a list of loaded backend modules */
const GList *
mate_mixer_get_modules (void)
{
- return (const GList *) mixer_modules;
+ return (const GList *) modules;
}
static void
-mixer_load_modules (void)
+load_modules (void)
{
static gboolean loaded = FALSE;
- if (loaded)
+ if (loaded == TRUE)
return;
- if (g_module_supported ()) {
+ if (G_LIKELY (g_module_supported () == TRUE)) {
GDir *dir;
GError *error = NULL;
@@ -138,34 +146,29 @@ mixer_load_modules (void)
while ((name = g_dir_read_name (dir)) != NULL) {
gchar *file;
- if (!g_str_has_suffix (name, "." G_MODULE_SUFFIX))
+ if (g_str_has_suffix (name, "." G_MODULE_SUFFIX) == FALSE)
continue;
file = g_build_filename (LIBMATEMIXER_BACKEND_DIR, name, NULL);
- mixer_modules = g_list_prepend (mixer_modules,
- mate_mixer_backend_module_new (file));
+ modules = g_list_prepend (modules, mate_mixer_backend_module_new (file));
g_free (file);
}
- if (mixer_modules == NULL)
- g_critical ("No backend modules have been found");
-
g_dir_close (dir);
} else {
g_critical ("%s", error->message);
g_error_free (error);
}
} else {
- g_critical ("Unable to load backend modules: GModule is not supported in your system");
+ g_critical ("Unable to load backend modules: not supported");
}
loaded = TRUE;
}
-/* GCompareFunc function to sort backend modules by the priority, higher number means
- * higher priority */
+/* Backend modules sorting function, higher priority number means higher priority */
static gint
-mixer_compare_modules (gconstpointer a, gconstpointer b)
+compare_modules (gconstpointer a, gconstpointer b)
{
const MateMixerBackendInfo *info1, *info2;