summaryrefslogtreecommitdiff
path: root/backends/oss/oss-stream-control.c
diff options
context:
space:
mode:
Diffstat (limited to 'backends/oss/oss-stream-control.c')
-rw-r--r--backends/oss/oss-stream-control.c200
1 files changed, 117 insertions, 83 deletions
diff --git a/backends/oss/oss-stream-control.c b/backends/oss/oss-stream-control.c
index 5161528..0307fc7 100644
--- a/backends/oss/oss-stream-control.c
+++ b/backends/oss/oss-stream-control.c
@@ -26,27 +26,28 @@
#include "oss-common.h"
#include "oss-stream-control.h"
+#define OSS_VOLUME_JOIN(left,right) (((left) & 0xFF) | (((right) & 0xFF) << 8))
+
+#define OSS_VOLUME_JOIN_SAME(volume) (OSS_VOLUME_JOIN ((volume), (volume)))
+#define OSS_VOLUME_JOIN_ARRAY(volume) (OSS_VOLUME_JOIN ((volume[0]), (volume[1])))
+
+#define OSS_VOLUME_TAKE_LEFT(volume) ((volume) & 0xFF)
+#define OSS_VOLUME_TAKE_RIGHT(volume) (((volume) >> 8) & 0xFF)
+
struct _OssStreamControlPrivate
{
- gint fd;
- gint devnum;
- guint volume[2];
- gfloat balance;
- gboolean stereo;
- MateMixerStreamControlRole role;
- MateMixerStreamControlFlags flags;
+ gint fd;
+ gint devnum;
+ guint8 volume[2];
+ gboolean stereo;
};
static void oss_stream_control_class_init (OssStreamControlClass *klass);
-
static void oss_stream_control_init (OssStreamControl *control);
static void oss_stream_control_finalize (GObject *object);
G_DEFINE_TYPE (OssStreamControl, oss_stream_control, MATE_MIXER_TYPE_STREAM_CONTROL)
-static gboolean oss_stream_control_set_mute (MateMixerStreamControl *mmsc,
- gboolean mute);
-
static guint oss_stream_control_get_num_channels (MateMixerStreamControl *mmsc);
static guint oss_stream_control_get_volume (MateMixerStreamControl *mmsc);
@@ -73,7 +74,9 @@ static guint oss_stream_control_get_max_volume (MateMix
static guint oss_stream_control_get_normal_volume (MateMixerStreamControl *mmsc);
static guint oss_stream_control_get_base_volume (MateMixerStreamControl *mmsc);
-static gboolean write_volume (OssStreamControl *control,
+static void read_balance (OssStreamControl *control);
+
+static gboolean write_and_set_volume (OssStreamControl *control,
gint volume);
static void
@@ -86,14 +89,13 @@ oss_stream_control_class_init (OssStreamControlClass *klass)
object_class->finalize = oss_stream_control_finalize;
control_class = MATE_MIXER_STREAM_CONTROL_CLASS (klass);
- control_class->set_mute = oss_stream_control_set_mute;
control_class->get_num_channels = oss_stream_control_get_num_channels;
control_class->get_volume = oss_stream_control_get_volume;
control_class->set_volume = oss_stream_control_set_volume;
control_class->get_channel_volume = oss_stream_control_get_channel_volume;
control_class->set_channel_volume = oss_stream_control_set_channel_volume;
- control_class->get_channel_position = oss_stream_control_get_channel_position;
control_class->has_channel_position = oss_stream_control_has_channel_position;
+ control_class->get_channel_position = oss_stream_control_get_channel_position;
control_class->set_balance = oss_stream_control_set_balance;
control_class->get_min_volume = oss_stream_control_get_min_volume;
control_class->get_max_volume = oss_stream_control_get_max_volume;
@@ -118,7 +120,8 @@ oss_stream_control_finalize (GObject *object)
control = OSS_STREAM_CONTROL (object);
- close (control->priv->fd);
+ if (control->priv->fd != -1)
+ close (control->priv->fd);
G_OBJECT_CLASS (oss_stream_control_parent_class)->finalize (object);
}
@@ -127,6 +130,7 @@ OssStreamControl *
oss_stream_control_new (const gchar *name,
const gchar *label,
MateMixerStreamControlRole role,
+ OssStream *stream,
gint fd,
gint devnum,
gboolean stereo)
@@ -134,8 +138,11 @@ oss_stream_control_new (const gchar *name,
OssStreamControl *control;
MateMixerStreamControlFlags flags;
- flags = MATE_MIXER_STREAM_CONTROL_HAS_VOLUME |
- MATE_MIXER_STREAM_CONTROL_CAN_SET_VOLUME;
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (label != NULL, NULL);
+
+ flags = MATE_MIXER_STREAM_CONTROL_VOLUME_READABLE |
+ MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE;
if (stereo == TRUE)
flags |= MATE_MIXER_STREAM_CONTROL_CAN_BALANCE;
@@ -143,6 +150,8 @@ oss_stream_control_new (const gchar *name,
"name", name,
"label", label,
"flags", flags,
+ "role", role,
+ "stream", stream,
NULL);
control->priv->fd = fd;
@@ -151,52 +160,50 @@ oss_stream_control_new (const gchar *name,
return control;
}
-gboolean
-oss_stream_control_update (OssStreamControl *control)
+gint
+oss_stream_control_get_devnum (OssStreamControl *control)
{
- gint v;
- gint ret;
+ g_return_val_if_fail (OSS_IS_STREAM_CONTROL (control), 0);
- g_return_val_if_fail (OSS_IS_STREAM_CONTROL (control), FALSE);
+ return control->priv->devnum;
+}
- ret = ioctl (control->priv->fd, MIXER_READ (control->priv->devnum), &v);
- if (ret < 0) {
- g_warning ("Failed to read volume: %s", g_strerror (errno));
- return FALSE;
- }
+void
+oss_stream_control_load (OssStreamControl *control)
+{
+ gint v, ret;
- control->priv->volume[0] = v & 0xFF;
+ g_return_if_fail (OSS_IS_STREAM_CONTROL (control));
- if (control->priv->stereo == TRUE) {
- gfloat balance;
- guint left;
- guint right;
-
- control->priv->volume[1] = (v >> 8) & 0xFF;
-
- /* Calculate balance */
- left = control->priv->volume[0];
- right = control->priv->volume[1];
- if (left == right)
- balance = 0.0f;
- else if (left > right)
- balance = -1.0f + ((gfloat) right / (gfloat) left);
- else
- balance = +1.0f - ((gfloat) left / (gfloat) right);
+ if G_UNLIKELY (control->priv->fd == -1)
+ return;
+
+ ret = ioctl (control->priv->fd, MIXER_READ (control->priv->devnum), &v);
+ if (ret == -1)
+ return;
+
+ if (v != OSS_VOLUME_JOIN_ARRAY (control->priv->volume)) {
+ control->priv->volume[0] = OSS_VOLUME_TAKE_LEFT (v);
+ if (control->priv->stereo == TRUE)
+ control->priv->volume[1] = OSS_VOLUME_TAKE_RIGHT (v);
- _mate_mixer_stream_control_set_balance (MATE_MIXER_STREAM_CONTROL (control),
- balance);
+ g_object_notify (G_OBJECT (control), "volume");
}
- return TRUE;
+
+ if (control->priv->stereo == TRUE)
+ read_balance (control);
}
-static gboolean
-oss_stream_control_set_mute (MateMixerStreamControl *mmsc, gboolean mute)
+void
+oss_stream_control_close (OssStreamControl *control)
{
- g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);
+ g_return_if_fail (OSS_IS_STREAM_CONTROL (control));
- // TODO
- return TRUE;
+ if (control->priv->fd == -1)
+ return;
+
+ close (control->priv->fd);
+ control->priv->fd = -1;
}
static guint
@@ -226,17 +233,15 @@ static gboolean
oss_stream_control_set_volume (MateMixerStreamControl *mmsc, guint volume)
{
OssStreamControl *control;
- gint v;
g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);
control = OSS_STREAM_CONTROL (mmsc);
- v = CLAMP (volume, 0, 100);
- if (control->priv->stereo == TRUE)
- v |= (volume & 0xFF) << 8;
+ if G_UNLIKELY (control->priv->fd == -1)
+ return FALSE;
- return write_volume (control, v);
+ return write_and_set_volume (control, OSS_VOLUME_JOIN_SAME (CLAMP (volume, 0, 100)));
}
static guint
@@ -269,27 +274,26 @@ oss_stream_control_set_channel_volume (MateMixerStreamControl *mmsc,
g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);
control = OSS_STREAM_CONTROL (mmsc);
- volume = CLAMP (volume, 0, 100);
- if (control->priv->stereo == TRUE) {
- if (channel > 1)
- return FALSE;
+ if G_UNLIKELY (control->priv->fd == -1)
+ return FALSE;
+ if (channel > 1 || (control->priv->stereo == FALSE && channel > 0))
+ return FALSE;
- /* Stereo channel volume - left channel is in the lowest 8 bits and
+ volume = CLAMP (volume, 0, 100);
+
+ if (control->priv->stereo == TRUE) {
+ /* Stereo channel volume - left channel is in the lower 8 bits and
* right channel is in the higher 8 bits */
if (channel == 0)
- v = volume | (control->priv->volume[1] << 8);
+ v = OSS_VOLUME_JOIN (volume, control->priv->volume[1]);
else
- v = control->priv->volume[0] | (volume << 8);
+ v = OSS_VOLUME_JOIN (control->priv->volume[0], volume);
} else {
- if (channel > 0)
- return FALSE;
-
- /* Single channel volume - only lowest 8 bits are used */
+ /* Single channel volume - only lower 8 bits are used */
v = volume;
}
-
- return write_volume (control, v);
+ return write_and_set_volume (control, v);
}
static MateMixerChannelPosition
@@ -334,24 +338,24 @@ oss_stream_control_set_balance (MateMixerStreamControl *mmsc, gfloat balance)
{
OssStreamControl *control;
guint max;
- gint v;
+ gint volume[2];
g_return_val_if_fail (OSS_IS_STREAM_CONTROL (mmsc), FALSE);
control = OSS_STREAM_CONTROL (mmsc);
+ if G_UNLIKELY (control->priv->fd == -1)
+ return FALSE;
+
max = MAX (control->priv->volume[0], control->priv->volume[1]);
if (balance <= 0) {
- control->priv->volume[1] = (balance + 1.0f) * max;
- control->priv->volume[0] = max;
+ volume[1] = (balance + 1.0f) * max;
+ volume[0] = max;
} else {
- control->priv->volume[0] = (1.0f - balance) * max;
- control->priv->volume[1] = max;
+ volume[0] = (1.0f - balance) * max;
+ volume[1] = max;
}
-
- v = control->priv->volume[0] | (control->priv->volume[1] << 8);
-
- return write_volume (control, v);
+ return write_and_set_volume (control, OSS_VOLUME_JOIN_ARRAY (volume));
}
static guint
@@ -378,15 +382,45 @@ oss_stream_control_get_base_volume (MateMixerStreamControl *mmsc)
return 100;
}
+static void
+read_balance (OssStreamControl *control)
+{
+ gfloat balance;
+ guint left = control->priv->volume[0];
+ guint right = control->priv->volume[1];
+
+ if (left == right)
+ balance = 0.0f;
+ else if (left > right)
+ balance = -1.0f + ((gfloat) right / (gfloat) left);
+ else
+ balance = +1.0f - ((gfloat) left / (gfloat) right);
+
+ _mate_mixer_stream_control_set_balance (MATE_MIXER_STREAM_CONTROL (control),
+ balance);
+}
+
static gboolean
-write_volume (OssStreamControl *control, gint volume)
+write_and_set_volume (OssStreamControl *control, gint volume)
{
gint ret;
+ /* Nothing to do? */
+ if (volume == OSS_VOLUME_JOIN_ARRAY (control->priv->volume))
+ return TRUE;
+
ret = ioctl (control->priv->fd, MIXER_WRITE (control->priv->devnum), &volume);
- if (ret < 0) {
- g_warning ("Failed to set volume: %s", g_strerror (errno));
+ if (ret == -1)
return FALSE;
- }
+
+ oss_stream_control_load (control);
+ return TRUE;
+
+ /* The ioctl may make adjustments to the passed volume, so make sure we have
+ * the correct value saved */
+ control->priv->volume[0] = OSS_VOLUME_TAKE_LEFT (volume);
+ control->priv->volume[1] = OSS_VOLUME_TAKE_RIGHT (volume);
+
+ g_object_notify (G_OBJECT (control), "volume");
return TRUE;
}