summaryrefslogtreecommitdiff
path: root/backends/pulse/pulse-source.c
diff options
context:
space:
mode:
Diffstat (limited to 'backends/pulse/pulse-source.c')
-rw-r--r--backends/pulse/pulse-source.c339
1 files changed, 162 insertions, 177 deletions
diff --git a/backends/pulse/pulse-source.c b/backends/pulse/pulse-source.c
index e7dce6f..0d095a7 100644
--- a/backends/pulse/pulse-source.c
+++ b/backends/pulse/pulse-source.c
@@ -16,253 +16,238 @@
*/
#include <glib.h>
+#include <glib/gi18n.h>
#include <glib-object.h>
-
-#include <libmatemixer/matemixer-port.h>
-#include <libmatemixer/matemixer-port-private.h>
-#include <libmatemixer/matemixer-stream.h>
+#include <libmatemixer/matemixer.h>
+#include <libmatemixer/matemixer-private.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
#include "pulse-device.h"
#include "pulse-monitor.h"
+#include "pulse-port.h"
+#include "pulse-port-switch.h"
#include "pulse-stream.h"
#include "pulse-source.h"
+#include "pulse-source-control.h"
+#include "pulse-source-output.h"
+#include "pulse-source-switch.h"
+
+struct _PulseSourcePrivate
+{
+ GHashTable *outputs;
+ PulsePortSwitch *pswitch;
+ PulseSourceControl *control;
+};
static void pulse_source_class_init (PulseSourceClass *klass);
static void pulse_source_init (PulseSource *source);
+static void pulse_source_dispose (GObject *object);
+static void pulse_source_finalize (GObject *object);
G_DEFINE_TYPE (PulseSource, pulse_source, PULSE_TYPE_STREAM);
-static void pulse_source_reload (PulseStream *pstream);
+static const GList *pulse_source_list_controls (MateMixerStream *mms);
+static const GList *pulse_source_list_switches (MateMixerStream *mms);
-static gboolean pulse_source_set_mute (PulseStream *pstream,
- gboolean mute);
-static gboolean pulse_source_set_volume (PulseStream *pstream,
- pa_cvolume *cvolume);
-static gboolean pulse_source_set_active_port (PulseStream *pstream,
- MateMixerPort *port);
+static void
+pulse_source_class_init (PulseSourceClass *klass)
+{
+ GObjectClass *object_class;
+ MateMixerStreamClass *stream_class;
-static PulseMonitor *pulse_source_create_monitor (PulseStream *pstream);
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = pulse_source_dispose;
+ object_class->finalize = pulse_source_finalize;
-static void update_ports (PulseStream *pstream,
- pa_source_port_info **ports,
- pa_source_port_info *active);
+ stream_class = MATE_MIXER_STREAM_CLASS (klass);
+ stream_class->list_controls = pulse_source_list_controls;
+ stream_class->list_switches = pulse_source_list_switches;
+
+ g_type_class_add_private (klass, sizeof (PulseSourcePrivate));
+}
static void
-pulse_source_class_init (PulseSourceClass *klass)
+pulse_source_init (PulseSource *source)
+{
+ source->priv = G_TYPE_INSTANCE_GET_PRIVATE (source,
+ PULSE_TYPE_SOURCE,
+ PulseSourcePrivate);
+
+ source->priv->outputs = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ g_object_unref);
+}
+
+static void
+pulse_source_dispose (GObject *object)
{
- PulseStreamClass *stream_class;
+ PulseSource *source;
- stream_class = PULSE_STREAM_CLASS (klass);
+ source = PULSE_SOURCE (object);
- stream_class->reload = pulse_source_reload;
- stream_class->set_mute = pulse_source_set_mute;
- stream_class->set_volume = pulse_source_set_volume;
- stream_class->set_active_port = pulse_source_set_active_port;
- stream_class->create_monitor = pulse_source_create_monitor;
+ g_clear_object (&source->priv->control);
+ g_clear_object (&source->priv->pswitch);
+
+ g_hash_table_remove_all (source->priv->outputs);
+
+ G_OBJECT_CLASS (pulse_source_parent_class)->dispose (object);
}
static void
-pulse_source_init (PulseSource *source)
+pulse_source_finalize (GObject *object)
{
+ PulseSource *source;
+
+ source = PULSE_SOURCE (object);
+
+ g_hash_table_unref (source->priv->outputs);
+
+ G_OBJECT_CLASS (pulse_source_parent_class)->finalize (object);
}
-PulseStream *
+PulseSource *
pulse_source_new (PulseConnection *connection,
const pa_source_info *info,
PulseDevice *device)
{
- PulseStream *stream;
+ PulseSource *source;
g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (info != NULL, NULL);
- /* Consider the sink index as unchanging parameter */
- stream = g_object_new (PULSE_TYPE_SOURCE,
+ source = g_object_new (PULSE_TYPE_SOURCE,
+ "name", info->name,
+ "label", info->description,
+ "device", device,
+ "direction", MATE_MIXER_DIRECTION_INPUT,
"connection", connection,
"index", info->index,
NULL);
- /* Other data may change at any time, so let's make a use of our update function */
- pulse_source_update (stream, info, device);
+ source->priv->control = pulse_source_control_new (source, info);
- return stream;
-}
+ if (info->n_ports > 0) {
+ pa_source_port_info **ports = info->ports;
-gboolean
-pulse_source_update (PulseStream *pstream,
- const pa_source_info *info,
- PulseDevice *device)
-{
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_INPUT |
- MATE_MIXER_STREAM_HAS_MUTE |
- MATE_MIXER_STREAM_HAS_MONITOR |
- MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_CAN_SET_VOLUME |
- MATE_MIXER_STREAM_CAN_SUSPEND;
-
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
- g_return_val_if_fail (info != NULL, FALSE);
-
- /* Let all the information update before emitting notify signals */
- g_object_freeze_notify (G_OBJECT (pstream));
-
- pulse_stream_update_name (pstream, info->name);
- pulse_stream_update_description (pstream, info->description);
- pulse_stream_update_mute (pstream, info->mute ? TRUE : FALSE);
-
- /* Stream state */
- switch (info->state) {
- case PA_SOURCE_RUNNING:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_RUNNING);
- break;
- case PA_SOURCE_IDLE:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_IDLE);
- break;
- case PA_SOURCE_SUSPENDED:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_SUSPENDED);
- break;
- default:
- pulse_stream_update_state (pstream, MATE_MIXER_STREAM_STATE_UNKNOWN);
- break;
- }
+ /* Create the port switch */
+ source->priv->pswitch = pulse_source_switch_new ("port", _("Port"), source);
+
+ while (*ports != NULL) {
+ pa_source_port_info *p = *ports++;
+ PulsePort *port;
+ const gchar *icon = NULL;
- /* Build the flag list */
- if (info->flags & PA_SINK_DECIBEL_VOLUME)
- flags |= MATE_MIXER_STREAM_HAS_DECIBEL_VOLUME;
- if (info->flags & PA_SINK_FLAT_VOLUME)
- flags |= MATE_MIXER_STREAM_HAS_FLAT_VOLUME;
+ /* A port may include an icon but in PulseAudio sink and source ports
+ * the property is not included, for this reason ports are also read from
+ * devices where the icons may be present */
+ if (device != NULL) {
+ port = pulse_device_get_port (PULSE_DEVICE (device), p->name);
+ if (port != NULL)
+ icon = mate_mixer_switch_option_get_icon (MATE_MIXER_SWITCH_OPTION (port));
+ }
- /* Flags must be updated before volume */
- pulse_stream_update_flags (pstream, flags);
+ port = pulse_port_new (p->name,
+ p->description,
+ icon,
+ p->priority);
- pulse_stream_update_channel_map (pstream, &info->channel_map);
- pulse_stream_update_volume (pstream, &info->volume, info->base_volume);
+ pulse_port_switch_add_port (source->priv->pswitch, port);
- pulse_stream_update_device (pstream, MATE_MIXER_DEVICE (device));
+ if (p == info->active_port)
+ pulse_port_switch_set_active_port (source->priv->pswitch, port);
+ }
- /* Ports must be updated after device */
- if (info->ports != NULL) {
- update_ports (pstream, info->ports, info->active_port);
+ g_debug ("Created port list for source %s", info->name);
}
- g_object_thaw_notify (G_OBJECT (pstream));
- return TRUE;
-}
+ pulse_source_update (source, info);
-static void
-pulse_source_reload (PulseStream *pstream)
-{
- g_return_if_fail (PULSE_IS_SOURCE (pstream));
-
- pulse_connection_load_source_info (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream));
+ _mate_mixer_stream_set_default_control (MATE_MIXER_STREAM (source),
+ MATE_MIXER_STREAM_CONTROL (source->priv->control));
+ return source;
}
-static gboolean
-pulse_source_set_mute (PulseStream *pstream, gboolean mute)
+void
+pulse_source_add_output (PulseSource *source, const pa_source_output_info *info)
{
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
-
- return pulse_connection_set_source_mute (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- mute);
+ PulseSourceOutput *output;
+
+ /* This function is used for both creating and refreshing source outputs */
+ output = g_hash_table_lookup (source->priv->outputs, GINT_TO_POINTER (info->index));
+ if (output == NULL) {
+ const gchar *name;
+
+ output = pulse_source_output_new (source, info);
+ g_hash_table_insert (source->priv->outputs,
+ GINT_TO_POINTER (info->index),
+ output);
+
+ name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (output));
+ g_signal_emit_by_name (G_OBJECT (source),
+ "control-added",
+ name);
+ } else
+ pulse_source_output_update (output, info);
}
-static gboolean
-pulse_source_set_volume (PulseStream *pstream, pa_cvolume *cvolume)
+void
+pulse_source_remove_output (PulseSource *source, guint32 index)
{
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
- g_return_val_if_fail (cvolume != NULL, FALSE);
+ PulseSourceOutput *output;
+ const gchar *name;
- return pulse_connection_set_source_volume (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- cvolume);
-}
+ output = g_hash_table_lookup (source->priv->outputs, GINT_TO_POINTER (index));
+ if G_UNLIKELY (output == NULL)
+ return;
-static gboolean
-pulse_source_set_active_port (PulseStream *pstream, MateMixerPort *port)
-{
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), FALSE);
- g_return_val_if_fail (MATE_MIXER_IS_PORT (port), FALSE);
+ name = mate_mixer_stream_control_get_name (MATE_MIXER_STREAM_CONTROL (output));
- return pulse_connection_set_source_port (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- mate_mixer_port_get_name (port));
+ g_hash_table_remove (source->priv->outputs, GINT_TO_POINTER (index));
+ g_signal_emit_by_name (G_OBJECT (source),
+ "control-removed",
+ name);
}
-static PulseMonitor *
-pulse_source_create_monitor (PulseStream *pstream)
+void
+pulse_source_update (PulseSource *source,
+ const pa_source_info *info)
{
- g_return_val_if_fail (PULSE_IS_SOURCE (pstream), NULL);
-
- return pulse_connection_create_monitor (pulse_stream_get_connection (pstream),
- pulse_stream_get_index (pstream),
- PA_INVALID_INDEX);
+ g_return_if_fail (PULSE_IS_SOURCE (source));
+ g_return_if_fail (info != NULL);
+
+ /* The switch doesn't allow being unset, PulseAudio should always include
+ * the active port name if the are any ports available */
+ if (info->active_port != NULL)
+ pulse_port_switch_set_active_port_by_name (source->priv->pswitch,
+ info->active_port->name);
}
-static void
-update_ports (PulseStream *pstream,
- pa_source_port_info **ports,
- pa_source_port_info *active)
+static const GList *
+pulse_source_list_controls (MateMixerStream *mms)
{
- MateMixerPort *port;
- MateMixerDevice *device;
- GHashTable *hash;
-
- hash = pulse_stream_get_ports (pstream);
+ GList *list;
- while (*ports != NULL) {
- MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
- pa_source_port_info *info = *ports;
- const gchar *icon = NULL;
+ g_return_val_if_fail (PULSE_IS_SOURCE (mms), NULL);
- device = mate_mixer_stream_get_device (MATE_MIXER_STREAM (pstream));
- if (device != NULL) {
- port = mate_mixer_device_get_port (device, info->name);
-
- if (port != NULL) {
- flags = mate_mixer_port_get_flags (port);
- icon = mate_mixer_port_get_icon (port);
- }
- }
+ // XXX
+ list = g_hash_table_get_values (PULSE_SOURCE (mms)->priv->outputs);
+ if (list != NULL)
+ g_list_foreach (list, (GFunc) g_object_ref, NULL);
-#if PA_CHECK_VERSION(2, 0, 0)
- if (info->available == PA_PORT_AVAILABLE_YES)
- flags |= MATE_MIXER_PORT_AVAILABLE;
- else
- flags &= ~MATE_MIXER_PORT_AVAILABLE;
-#endif
-
- port = g_hash_table_lookup (hash, info->name);
-
- if (port != NULL) {
- /* Update existing port */
- _mate_mixer_port_update_description (port, info->description);
- _mate_mixer_port_update_icon (port, icon);
- _mate_mixer_port_update_priority (port, info->priority);
- _mate_mixer_port_update_flags (port, flags);
- } else {
- /* Add previously unknown port to the hash table */
- port = _mate_mixer_port_new (info->name,
- info->description,
- icon,
- info->priority,
- flags);
-
- g_hash_table_insert (hash, g_strdup (info->name), port);
- }
+ return g_list_prepend (list, g_object_ref (PULSE_SOURCE (mms)->priv->control));
+}
- ports++;
- }
+static const GList *
+pulse_source_list_switches (MateMixerStream *mms)
+{
+ g_return_val_if_fail (PULSE_IS_SOURCE (mms), NULL);
- /* Active port */
- if (G_LIKELY (active != NULL))
- port = g_hash_table_lookup (hash, active->name);
- else
- port = NULL;
+ // XXX
+ if (PULSE_SOURCE (mms)->priv->pswitch != NULL)
+ return g_list_prepend (NULL, PULSE_SOURCE (mms)->priv->pswitch);
- pulse_stream_update_active_port (pstream, port);
+ return NULL;
}