summaryrefslogtreecommitdiffstats
path: root/polyp/ctl_polyp.c
diff options
context:
space:
mode:
Diffstat (limited to 'polyp/ctl_polyp.c')
-rw-r--r--polyp/ctl_polyp.c264
1 files changed, 211 insertions, 53 deletions
diff --git a/polyp/ctl_polyp.c b/polyp/ctl_polyp.c
index 16043bf..aba002b 100644
--- a/polyp/ctl_polyp.c
+++ b/polyp/ctl_polyp.c
@@ -30,15 +30,23 @@ typedef struct snd_ctl_polyp {
snd_polyp_t *p;
- char *device;
+ char *source;
+ char *sink;
- pa_cvolume volume;
+ pa_cvolume sink_volume;
+ pa_cvolume source_volume;
+
+ int sink_muted;
+ int source_muted;
int subscribed;
int updated;
} snd_ctl_polyp_t;
-#define MIXER_NAME "Master"
+#define SOURCE_VOL_NAME "Capture Volume"
+#define SOURCE_MUTE_NAME "Capture Switch"
+#define SINK_VOL_NAME "Master Playback Volume"
+#define SINK_MUTE_NAME "Master Playback Switch"
static void sink_info_cb(pa_context *c, const pa_sink_info *i, int is_last, void *userdata)
{
@@ -50,18 +58,52 @@ static void sink_info_cb(pa_context *c, const pa_sink_info *i, int is_last, void
assert(ctl && i);
- if (ctl->volume.channels == i->volume.channels) {
- for (chan = 0;chan < ctl->volume.channels;chan++)
- if (i->volume.values[chan] != ctl->volume.values[chan])
+ if (ctl->sink_volume.channels == i->volume.channels) {
+ for (chan = 0;chan < ctl->sink_volume.channels;chan++)
+ if (i->volume.values[chan] != ctl->sink_volume.values[chan])
break;
- if (chan == ctl->volume.channels)
+ if (chan == ctl->sink_volume.channels)
return;
ctl->updated = 1;
}
- memcpy(&ctl->volume, &i->volume, sizeof(pa_cvolume));
+ memcpy(&ctl->sink_volume, &i->volume, sizeof(pa_cvolume));
+
+ if (!!ctl->sink_muted != !!i->mute) {
+ ctl->sink_muted = i->mute;
+ ctl->updated = 1;
+ }
+}
+
+static void source_info_cb(pa_context *c, const pa_source_info *i, int is_last, void *userdata)
+{
+ snd_ctl_polyp_t *ctl = (snd_ctl_polyp_t*)userdata;
+ int chan;
+
+ if (is_last)
+ return;
+
+ assert(ctl && i);
+
+ if (ctl->source_volume.channels == i->volume.channels) {
+ for (chan = 0;chan < ctl->source_volume.channels;chan++)
+ if (i->volume.values[chan] != ctl->source_volume.values[chan])
+ break;
+
+ if (chan == ctl->source_volume.channels)
+ return;
+
+ ctl->updated = 1;
+ }
+
+ memcpy(&ctl->source_volume, &i->volume, sizeof(pa_cvolume));
+
+ if (!!ctl->source_muted != !!i->mute) {
+ ctl->source_muted = i->mute;
+ ctl->updated = 1;
+ }
}
static void event_cb(pa_context *c, pa_subscription_event_type_t t,
@@ -72,9 +114,13 @@ static void event_cb(pa_context *c, pa_subscription_event_type_t t,
assert(ctl && ctl->p && ctl->p->context);
- o = pa_context_get_sink_info_by_name(ctl->p->context, ctl->device,
+ o = pa_context_get_sink_info_by_name(ctl->p->context, ctl->sink,
sink_info_cb, ctl);
pa_operation_unref(o);
+
+ o = pa_context_get_source_info_by_name(ctl->p->context, ctl->source,
+ source_info_cb, ctl);
+ pa_operation_unref(o);
}
static int polyp_update_volume(snd_ctl_polyp_t *ctl)
@@ -84,26 +130,36 @@ static int polyp_update_volume(snd_ctl_polyp_t *ctl)
assert(ctl && ctl->p && ctl->p->context);
- o = pa_context_get_sink_info_by_name(ctl->p->context, ctl->device,
+ o = pa_context_get_sink_info_by_name(ctl->p->context, ctl->sink,
sink_info_cb, ctl);
err = polyp_wait_operation(ctl->p, o);
pa_operation_unref(o);
if (err < 0)
return err;
+ o = pa_context_get_source_info_by_name(ctl->p->context, ctl->source,
+ source_info_cb, ctl);
+ err = polyp_wait_operation(ctl->p, o);
+ pa_operation_unref(o);
+ if (err < 0)
+ return err;
+
return 0;
}
static int polyp_elem_count(snd_ctl_ext_t *ext)
{
snd_ctl_polyp_t *ctl = ext->private_data;
+ int count = 0;
assert(ctl);
- if (ctl->device)
- return 1;
+ if (ctl->source)
+ count += 2;
+ if (ctl->sink)
+ count += 2;
- return 0;
+ return count;
}
static int polyp_elem_list(snd_ctl_ext_t *ext, unsigned int offset,
@@ -114,7 +170,19 @@ static int polyp_elem_list(snd_ctl_ext_t *ext, unsigned int offset,
assert(ctl);
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
- snd_ctl_elem_id_set_name(id, MIXER_NAME);
+
+ if (ctl->source) {
+ if (offset == 0)
+ snd_ctl_elem_id_set_name(id, SOURCE_VOL_NAME);
+ else if (offset == 1)
+ snd_ctl_elem_id_set_name(id, SOURCE_MUTE_NAME);
+ } else
+ offset += 2;
+
+ if (offset == 2)
+ snd_ctl_elem_id_set_name(id, SINK_VOL_NAME);
+ else if (offset == 3)
+ snd_ctl_elem_id_set_name(id, SINK_MUTE_NAME);
return 0;
}
@@ -126,8 +194,14 @@ static snd_ctl_ext_key_t polyp_find_elem(snd_ctl_ext_t *ext,
name = snd_ctl_elem_id_get_name(id);
- if (strcmp(name, MIXER_NAME) == 0)
+ if (strcmp(name, SOURCE_VOL_NAME) == 0)
return 0;
+ if (strcmp(name, SOURCE_MUTE_NAME) == 0)
+ return 1;
+ if (strcmp(name, SINK_VOL_NAME) == 0)
+ return 2;
+ if (strcmp(name, SINK_MUTE_NAME) == 0)
+ return 3;
return SND_CTL_EXT_KEY_NOT_FOUND;
}
@@ -140,7 +214,7 @@ static int polyp_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
assert(ctl && ctl->p);
- if (key != 0)
+ if (key > 3)
return -EINVAL;
err = polyp_finish_poll(ctl->p);
@@ -155,9 +229,19 @@ static int polyp_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
if (err < 0)
return err;
- *type = SND_CTL_ELEM_TYPE_INTEGER;
+ if (key & 1)
+ *type = SND_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ *type = SND_CTL_ELEM_TYPE_INTEGER;
+
*acc = SND_CTL_EXT_ACCESS_READWRITE;
- *count = ctl->volume.channels;
+
+ if (key == 0)
+ *count = ctl->source_volume.channels;
+ else if (key == 2)
+ *count = ctl->sink_volume.channels;
+ else
+ *count = 1;
return 0;
}
@@ -165,9 +249,6 @@ static int polyp_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
static int polyp_get_integer_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
long *imin, long *imax, long *istep)
{
- if (key != 0)
- return -EINVAL;
-
*istep = 1;
*imin = 0;
*imax = PA_VOLUME_NORM;
@@ -180,12 +261,10 @@ static int polyp_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
{
snd_ctl_polyp_t *ctl = ext->private_data;
int err, i;
+ pa_cvolume *vol = NULL;
assert(ctl && ctl->p);
- if (key != 0)
- return -EINVAL;
-
err = polyp_finish_poll(ctl->p);
if (err < 0)
return err;
@@ -198,8 +277,27 @@ static int polyp_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
if (err < 0)
return err;
- for (i = 0;i < ctl->volume.channels;i++)
- value[i] = ctl->volume.values[i];
+ switch (key) {
+ case 0:
+ vol = &ctl->source_volume;
+ break;
+ case 1:
+ *value = !ctl->source_muted;
+ break;
+ case 2:
+ vol = &ctl->sink_volume;
+ break;
+ case 3:
+ *value = !ctl->sink_muted;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (vol) {
+ for (i = 0;i < vol->channels;i++)
+ value[i] = vol->values[i];
+ }
return 0;
}
@@ -209,14 +307,11 @@ static int polyp_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
{
snd_ctl_polyp_t *ctl = ext->private_data;
int err, i;
- pa_cvolume vol;
pa_operation *o;
+ pa_cvolume *vol = NULL;
assert(ctl && ctl->p && ctl->p->context);
- if (key != 0)
- return -EINVAL;
-
err = polyp_finish_poll(ctl->p);
if (err < 0)
return err;
@@ -229,21 +324,52 @@ static int polyp_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
if (err < 0)
return err;
- for (i = 0;i < ctl->volume.channels;i++)
- if (value[i] != ctl->volume.values[i])
- break;
-
- if (i == ctl->volume.channels)
- return 0;
-
- memset(&vol, 0, sizeof(pa_cvolume));
+ switch (key) {
+ case 0:
+ vol = &ctl->source_volume;
+ break;
+ case 1:
+ if (!!ctl->source_muted == !*value)
+ return 0;
+ ctl->source_muted = !*value;
+ break;
+ case 2:
+ vol = &ctl->sink_volume;
+ break;
+ case 3:
+ if (!!ctl->sink_muted == !*value)
+ return 0;
+ ctl->sink_muted = !*value;
+ break;
+ default:
+ return -EINVAL;
+ }
- vol.channels = ctl->volume.channels;
- for (i = 0;i < vol.channels;i++)
- vol.values[i] = value[i];
+ if (vol) {
+ for (i = 0;i < vol->channels;i++)
+ if (value[i] != vol->values[i])
+ break;
- o = pa_context_set_sink_volume_by_name(ctl->p->context, ctl->device, &vol,
- NULL, NULL);
+ if (i == vol->channels)
+ return 0;
+
+ for (i = 0;i < vol->channels;i++)
+ vol->values[i] = value[i];
+
+ if (key == 0)
+ o = pa_context_set_source_volume_by_name(ctl->p->context,
+ ctl->source, vol, NULL, NULL);
+ else
+ o = pa_context_set_sink_volume_by_name(ctl->p->context,
+ ctl->sink, vol, NULL, NULL);
+ } else {
+ if (key == 1)
+ o = pa_context_set_source_mute_by_name(ctl->p->context,
+ ctl->source, ctl->source_muted, NULL, NULL);
+ else
+ o = pa_context_set_sink_mute_by_name(ctl->p->context,
+ ctl->sink, ctl->sink_muted, NULL, NULL);
+ }
err = polyp_wait_operation(ctl->p, o);
pa_operation_unref(o);
@@ -325,8 +451,10 @@ static void polyp_close(snd_ctl_ext_t *ext)
if (ctl->p)
polyp_free(ctl->p);
- if (ctl->device)
- free(ctl->device);
+ if (ctl->source)
+ free(ctl->source);
+ if (ctl->sink)
+ free(ctl->sink);
free(ctl);
}
@@ -351,9 +479,12 @@ static void server_info_cb(pa_context *c, const pa_server_info*i, void *userdata
{
snd_ctl_polyp_t *ctl = (snd_ctl_polyp_t*)userdata;
- assert(ctl && i && i->default_sink_name);
+ assert(ctl && i);
- ctl->device = strdup(i->default_sink_name);
+ if (i->default_source_name && !ctl->source)
+ ctl->source = strdup(i->default_source_name);
+ if (i->default_sink_name && !ctl->sink)
+ ctl->sink = strdup(i->default_sink_name);
}
SND_CTL_PLUGIN_DEFINE_FUNC(polyp)
@@ -361,6 +492,8 @@ SND_CTL_PLUGIN_DEFINE_FUNC(polyp)
snd_config_iterator_t i, next;
const char *server = NULL;
const char *device = NULL;
+ const char *source = NULL;
+ const char *sink = NULL;
int err;
snd_ctl_polyp_t *ctl;
pa_operation *o;
@@ -386,6 +519,20 @@ SND_CTL_PLUGIN_DEFINE_FUNC(polyp)
}
continue;
}
+ if (strcmp(id, "source") == 0) {
+ if (snd_config_get_string(n, &source) < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+ continue;
+ }
+ if (strcmp(id, "sink") == 0) {
+ if (snd_config_get_string(n, &sink) < 0) {
+ SNDERR("Invalid type for %s", id);
+ return -EINVAL;
+ }
+ continue;
+ }
SNDERR("Unknown field %s", id);
return -EINVAL;
}
@@ -403,9 +550,17 @@ SND_CTL_PLUGIN_DEFINE_FUNC(polyp)
if (err < 0)
goto error;
- if (device)
- ctl->device = strdup(device);
- else {
+ if (source)
+ ctl->source = strdup(source);
+ else if (device)
+ ctl->source = strdup(device);
+
+ if (sink)
+ ctl->sink = strdup(sink);
+ else if (device)
+ ctl->sink = strdup(device);
+
+ if (!ctl->source || !ctl->sink) {
o = pa_context_get_server_info(ctl->p->context, server_info_cb, ctl);
err = polyp_wait_operation(ctl->p, o);
pa_operation_unref(o);
@@ -415,7 +570,8 @@ SND_CTL_PLUGIN_DEFINE_FUNC(polyp)
pa_context_set_subscribe_callback(ctl->p->context, event_cb, ctl);
- o = pa_context_subscribe(ctl->p->context, PA_SUBSCRIPTION_MASK_SINK, NULL, NULL);
+ o = pa_context_subscribe(ctl->p->context,
+ PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, NULL, NULL);
err = polyp_wait_operation(ctl->p, o);
pa_operation_unref(o);
if (err < 0)
@@ -441,8 +597,10 @@ SND_CTL_PLUGIN_DEFINE_FUNC(polyp)
return 0;
error:
- if (ctl->device)
- free(ctl->device);
+ if (ctl->source)
+ free(ctl->source);
+ if (ctl->sink)
+ free(ctl->sink);
if (ctl->p)
polyp_free(ctl->p);