summaryrefslogtreecommitdiff
path: root/backends/pulse/pulse-sink.c
diff options
context:
space:
mode:
Diffstat (limited to 'backends/pulse/pulse-sink.c')
-rw-r--r--backends/pulse/pulse-sink.c246
1 files changed, 161 insertions, 85 deletions
diff --git a/backends/pulse/pulse-sink.c b/backends/pulse/pulse-sink.c
index 53ed64f..b7a440b 100644
--- a/backends/pulse/pulse-sink.c
+++ b/backends/pulse/pulse-sink.c
@@ -19,11 +19,11 @@
#include <glib-object.h>
#include <libmatemixer/matemixer-stream.h>
-#include <libmatemixer/matemixer-port.h>
#include <pulse/pulseaudio.h>
#include "pulse-connection.h"
+#include "pulse-monitor.h"
#include "pulse-stream.h"
#include "pulse-sink.h"
@@ -32,27 +32,20 @@ struct _PulseSinkPrivate
guint32 index_monitor;
};
-enum {
- PROP_0,
- N_PROPERTIES
-};
-
-static gboolean sink_set_mute (MateMixerStream *stream,
- gboolean mute);
-static gboolean sink_set_volume (MateMixerStream *stream,
- pa_cvolume *volume);
-static gboolean sink_set_active_port (MateMixerStream *stream,
- const gchar *port_name);
+static void pulse_sink_class_init (PulseSinkClass *klass);
+static void pulse_sink_init (PulseSink *sink);
G_DEFINE_TYPE (PulseSink, pulse_sink, PULSE_TYPE_STREAM);
-static void
-pulse_sink_init (PulseSink *sink)
-{
- sink->priv = G_TYPE_INSTANCE_GET_PRIVATE (sink,
- PULSE_TYPE_SINK,
- PulseSinkPrivate);
-}
+static gboolean sink_set_mute (MateMixerStream *stream,
+ gboolean mute);
+static gboolean sink_set_volume (MateMixerStream *stream,
+ pa_cvolume *volume);
+static gboolean sink_set_active_port (MateMixerStream *stream,
+ const gchar *port);
+static gboolean sink_suspend (MateMixerStream *stream);
+static gboolean sink_resume (MateMixerStream *stream);
+static PulseMonitor *sink_create_monitor (MateMixerStream *stream);
static void
pulse_sink_class_init (PulseSinkClass *klass)
@@ -64,43 +57,30 @@ pulse_sink_class_init (PulseSinkClass *klass)
stream_class->set_mute = sink_set_mute;
stream_class->set_volume = sink_set_volume;
stream_class->set_active_port = sink_set_active_port;
+ stream_class->suspend = sink_suspend;
+ stream_class->resume = sink_resume;
+ stream_class->create_monitor = sink_create_monitor;
g_type_class_add_private (klass, sizeof (PulseSinkPrivate));
}
+static void
+pulse_sink_init (PulseSink *sink)
+{
+ sink->priv = G_TYPE_INSTANCE_GET_PRIVATE (sink,
+ PULSE_TYPE_SINK,
+ PulseSinkPrivate);
+
+ sink->priv->index_monitor = PA_INVALID_INDEX;
+}
+
PulseStream *
pulse_sink_new (PulseConnection *connection, const pa_sink_info *info)
{
PulseSink *sink;
- GList *ports = NULL;
- int i;
-
- /* Convert the list of sink ports to a GList of MateMixerPorts */
- for (i = 0; i < info->n_ports; i++) {
- MateMixerPort *port;
- MateMixerPortStatus status = MATE_MIXER_PORT_UNKNOWN_STATUS;
- pa_sink_port_info *p_info = info->ports[i];
-
-#if PA_CHECK_VERSION(2, 0, 0)
- switch (p_info->available) {
- case PA_PORT_AVAILABLE_YES:
- status = MATE_MIXER_PORT_AVAILABLE;
- break;
- case PA_PORT_AVAILABLE_NO:
- status = MATE_MIXER_PORT_UNAVAILABLE;
- break;
- default:
- break;
- }
-#endif
- port = mate_mixer_port_new (p_info->name,
- p_info->description,
- NULL,
- p_info->priority,
- status);
- ports = g_list_prepend (ports, port);
- }
+ g_return_val_if_fail (PULSE_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (info != NULL, NULL);
/* Consider the sink index as unchanging parameter */
sink = g_object_new (PULSE_TYPE_SINK,
@@ -108,58 +88,78 @@ pulse_sink_new (PulseConnection *connection, const pa_sink_info *info)
"index", info->index,
NULL);
- /* According to the PulseAudio code, the list of sink port never changes with
- * updates.
- * This may be not future-proof, but checking and validating the list of ports on
- * each update would be an expensive operation, so let's set the list only during
- * the construction */
- pulse_stream_update_ports (PULSE_STREAM (sink), g_list_reverse (ports));
-
/* Other data may change at any time, so let's make a use of our update function */
pulse_sink_update (PULSE_STREAM (sink), info);
return PULSE_STREAM (sink);
}
+guint32
+pulse_sink_get_monitor_index (PulseStream *stream)
+{
+ g_return_val_if_fail (PULSE_IS_SINK (stream), PA_INVALID_INDEX);
+
+ return PULSE_SINK (stream)->priv->index_monitor;
+}
+
gboolean
pulse_sink_update (PulseStream *stream, const pa_sink_info *info)
{
- PulseSink *sink;
- MateMixerStreamFlags flags = MATE_MIXER_STREAM_OUTPUT |
- MATE_MIXER_STREAM_HAS_MUTE |
- MATE_MIXER_STREAM_HAS_VOLUME |
- MATE_MIXER_STREAM_CAN_SET_VOLUME;
+ MateMixerStreamFlags flags = MATE_MIXER_STREAM_OUTPUT |
+ MATE_MIXER_STREAM_HAS_MUTE |
+ MATE_MIXER_STREAM_HAS_VOLUME |
+ MATE_MIXER_STREAM_HAS_MONITOR |
+ MATE_MIXER_STREAM_CAN_SET_VOLUME |
+ MATE_MIXER_STREAM_CAN_SUSPEND;
+ PulseSink *sink;
+ GList *ports = NULL;
+ guint32 i;
g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
- sink = PULSE_SINK (stream);
-
/* Let all the information update before emitting notify signals */
g_object_freeze_notify (G_OBJECT (stream));
pulse_stream_update_name (stream, info->name);
pulse_stream_update_description (stream, info->description);
pulse_stream_update_mute (stream, info->mute ? TRUE : FALSE);
- pulse_stream_update_channel_map (stream, &info->channel_map);
- pulse_stream_update_volume_extended (stream,
- &info->volume,
- info->base_volume,
- info->n_volume_steps);
+
+ /* List of ports */
+ for (i = 0; i < info->n_ports; i++) {
+ MateMixerPortFlags flags = MATE_MIXER_PORT_NO_FLAGS;
+
+#if PA_CHECK_VERSION(2, 0, 0)
+ if (info->ports[i]->available == PA_PORT_AVAILABLE_YES)
+ flags |= MATE_MIXER_PORT_AVAILABLE;
+#endif
+ ports = g_list_prepend (ports,
+ mate_mixer_port_new (info->ports[i]->name,
+ info->ports[i]->description,
+ NULL,
+ info->ports[i]->priority,
+ flags));
+ }
+ pulse_stream_update_ports (stream, ports);
+
+ /* Active port */
if (info->active_port)
pulse_stream_update_active_port (stream, info->active_port->name);
+ else
+ pulse_stream_update_active_port (stream, NULL);
+ /* Stream state */
switch (info->state) {
case PA_SINK_RUNNING:
- pulse_stream_update_status (stream, MATE_MIXER_STREAM_RUNNING);
+ pulse_stream_update_state (stream, MATE_MIXER_STREAM_RUNNING);
break;
case PA_SINK_IDLE:
- pulse_stream_update_status (stream, MATE_MIXER_STREAM_IDLE);
+ pulse_stream_update_state (stream, MATE_MIXER_STREAM_IDLE);
break;
case PA_SINK_SUSPENDED:
- pulse_stream_update_status (stream, MATE_MIXER_STREAM_SUSPENDED);
+ pulse_stream_update_state (stream, MATE_MIXER_STREAM_SUSPENDED);
break;
default:
- pulse_stream_update_status (stream, MATE_MIXER_STREAM_UNKNOWN_STATUS);
+ pulse_stream_update_state (stream, MATE_MIXER_STREAM_UNKNOWN_STATE);
break;
}
@@ -169,21 +169,35 @@ pulse_sink_update (PulseStream *stream, const pa_sink_info *info)
if (info->flags & PA_SINK_FLAT_VOLUME)
flags |= MATE_MIXER_STREAM_HAS_FLAT_VOLUME;
- if (info->monitor_source_name)
- flags |= MATE_MIXER_STREAM_OUTPUT_MONITOR;
-
if (pa_channel_map_can_balance (&info->channel_map))
flags |= MATE_MIXER_STREAM_CAN_BALANCE;
if (pa_channel_map_can_fade (&info->channel_map))
flags |= MATE_MIXER_STREAM_CAN_FADE;
+ /* Flags must be updated before volume */
pulse_stream_update_flags (stream, flags);
+ pulse_stream_update_volume_extended (stream,
+ &info->volume,
+ &info->channel_map,
+ info->base_volume,
+ info->n_volume_steps);
+
+ sink = PULSE_SINK (stream);
+
+ /* Handle change of monitoring source index */
+ // XXX probably call this each time to validate
if (sink->priv->index_monitor != info->monitor_source) {
- sink->priv->index_monitor = info->monitor_source;
+ PulseMonitor *monitor;
+
+ monitor = pulse_stream_get_monitor (PULSE_STREAM (stream));
- // TODO: provide a property
- // g_object_notify (G_OBJECT (stream), "monitor");
+ if (monitor)
+ pulse_monitor_update_index (monitor,
+ info->monitor_source,
+ PA_INVALID_INDEX);
+
+ sink->priv->index_monitor = info->monitor_source;
}
g_object_thaw_notify (G_OBJECT (stream));
@@ -193,31 +207,93 @@ pulse_sink_update (PulseStream *stream, const pa_sink_info *info)
static gboolean
sink_set_mute (MateMixerStream *stream, gboolean mute)
{
+ PulseStream *pulse;
+
g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
- return pulse_connection_set_sink_mute (pulse_stream_get_connection (PULSE_STREAM (stream)),
- pulse_stream_get_index (PULSE_STREAM (stream)),
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_set_sink_mute (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
mute);
}
static gboolean
sink_set_volume (MateMixerStream *stream, pa_cvolume *volume)
{
+ PulseStream *pulse;
+
g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
g_return_val_if_fail (volume != NULL, FALSE);
- return pulse_connection_set_sink_volume (pulse_stream_get_connection (PULSE_STREAM (stream)),
- pulse_stream_get_index (PULSE_STREAM (stream)),
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_set_sink_volume (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
volume);
}
static gboolean
-sink_set_active_port (MateMixerStream *stream, const gchar *port_name)
+sink_set_active_port (MateMixerStream *stream, const gchar *port)
{
+ PulseStream *pulse;
+
g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
- g_return_val_if_fail (port_name != NULL, FALSE);
+ g_return_val_if_fail (port != NULL, FALSE);
+
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_set_sink_port (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
+ port);
+}
+
+static gboolean
+sink_suspend (MateMixerStream *stream)
+{
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
+
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_suspend_sink (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
+ TRUE);
+}
+
+static gboolean
+sink_resume (MateMixerStream *stream)
+{
+ PulseStream *pulse;
+
+ g_return_val_if_fail (PULSE_IS_SINK (stream), FALSE);
+
+ pulse = PULSE_STREAM (stream);
+
+ return pulse_connection_suspend_sink (pulse_stream_get_connection (pulse),
+ pulse_stream_get_index (pulse),
+ FALSE);
+}
+
+static PulseMonitor *
+sink_create_monitor (MateMixerStream *stream)
+{
+ PulseStream *pulse;
+ guint32 index;
+
+ g_return_val_if_fail (PULSE_IS_SINK (stream), NULL);
+
+ pulse = PULSE_STREAM (stream);
+ index = pulse_sink_get_monitor_index (pulse);
+
+ if (G_UNLIKELY (index == PA_INVALID_INDEX)) {
+ g_debug ("Not creating monitor for stream %s as it is not available",
+ mate_mixer_stream_get_name (stream));
+ return NULL;
+ }
- return pulse_connection_set_sink_port (pulse_stream_get_connection (PULSE_STREAM (stream)),
- pulse_stream_get_index (PULSE_STREAM (stream)),
- port_name);
+ return pulse_connection_create_monitor (pulse_stream_get_connection (pulse),
+ index,
+ PA_INVALID_INDEX);
}