Commit 5aa82d41 authored by minus's avatar minus

Add PA controlling functions and wire them up

parent 5a61dfa8
......@@ -4,7 +4,6 @@
#include "panelcontrol.h"
#include "pa.h"
#include "pa_siso_watch_list.h"
static pa_glib_mainloop *xpa_main_loop;
......@@ -20,8 +19,7 @@ static void xpa_on_sink_input_info(pa_context *ctx,
struct siso_watch_list *wl = userdata;
struct siso_watch *w = siso_get(wl, info->name);
if (w) {
siso_watch_add_index(w, info->index);
siso_watch_update(w, info->sink, info->volume.values[0], info->mute != 0);
siso_watch_update(w, info->index, info->sink, info->volume, info->mute != 0);
}
}
......@@ -34,8 +32,7 @@ static void xpa_on_sink_info(pa_context *ctx,
struct siso_watch_list *wl = userdata;
struct siso_watch *w = siso_get(wl, info->name);
if (w) {
siso_watch_add_index(w, info->index);
siso_watch_update(w, -1, info->volume.values[0], info->mute != 0);
siso_watch_update(w, info->index, -1, info->volume, info->mute != 0);
}
}
......@@ -51,6 +48,7 @@ static void xpa_on_subscribe(pa_context *ctx,
struct siso_watch_list *wl = NULL;
pa_sink_info_cb_t cb = NULL;
if ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) {
type_str = "sink input";
if (etype == PA_SUBSCRIPTION_EVENT_REMOVE) {
siso_remove_index(&sink_inputs, idx);
} else {
......@@ -59,6 +57,7 @@ static void xpa_on_subscribe(pa_context *ctx,
pa_operation_unref(op);
}
} else if ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
type_str = "sink";
if (etype == PA_SUBSCRIPTION_EVENT_REMOVE) {
siso_remove_index(&sinks, idx);
} else {
......@@ -85,11 +84,41 @@ static void xpa_on_connect(pa_context *ctx, void *userdata) {
}
}
static pa_context *ctx;
void xpa_sink_input_set_volume(struct siso_watch *w, float delta) {
for (size_t i = 0; i < w->sisos.len; i++) {
struct siso *s = &w->sisos.items[i];
for (int ch = 0; ch < s->volume.channels; ch++) {
float p = (float)(s->volume.values[ch] - PA_VOLUME_MUTED) / (PA_VOLUME_NORM - PA_VOLUME_MUTED);
p += delta;
if (p > 1.0f) p = 1.0f;
else if (p < 0.0f) p = 0.0f;
s->volume.values[ch] = PA_VOLUME_MUTED + p * (PA_VOLUME_NORM - PA_VOLUME_MUTED);
}
pa_operation_unref(pa_context_set_sink_input_volume(ctx, s->index, &s->volume, NULL, NULL));
}
}
void xpa_sink_input_set_mute(struct siso_watch *w, bool mute) {
for (size_t i = 0; i < w->sisos.len; i++) {
struct siso *s = &w->sisos.items[i];
pa_operation_unref(pa_context_set_sink_input_mute(ctx, s->index, mute, NULL, NULL));
}
}
void xpa_sink_input_set_sink(struct siso_watch *w, uint32_t sink_index) {
for (size_t i = 0; i < w->sisos.len; i++) {
struct siso *s = &w->sisos.items[i];
pa_operation_unref(pa_context_move_sink_input_by_index(ctx, s->index, sink_index, NULL, NULL));
}
}
void pa() {
// connect to PA
xpa_main_loop = pa_glib_mainloop_new(g_main_context_default());
pa_mainloop_api *api = pa_glib_mainloop_get_api(xpa_main_loop);
pa_context *ctx = pa_context_new(api, CLIENT_NAME);
ctx = pa_context_new(api, CLIENT_NAME);
pa_context_connect(ctx, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
pa_context_set_state_callback(ctx, &xpa_on_connect, NULL);
......
#ifndef PA_H
#define PA_H
#include "pa_siso_watch_list.h"
extern struct siso_watch_list sink_inputs;
extern struct siso_watch_list sinks;
void xpa_sink_input_set_volume(struct siso_watch *w, float delta);
void xpa_sink_input_set_mute(struct siso_watch *w, bool mute);
void xpa_sink_input_set_sink(struct siso_watch *w, uint32_t sink_index);
void pa();
#endif
......@@ -2,46 +2,50 @@
#include "pa_siso_watch_list.h"
void siso_watch_add_index(struct siso_watch *w, uint32_t pa_index) {
for (size_t i = 0; i < w->indices.len;) {
if (w->indices.items[i] == pa_index) {
return;
}
}
w->indices.len++;
w->indices.items = realloc(w->indices.items,
sizeof(uint32_t) * w->indices.len);
w->indices.items[w->indices.len - 1] = pa_index;
}
void siso_watch_remove_index(struct siso_watch *w, uint32_t pa_index) {
if (w->indices.len == 0) return;
if (w->sisos.len == 0) return;
for (size_t i = 0; i < w->indices.len;) {
if (w->indices.items[i] == pa_index) {
memmove(&w->indices.items[i], &w->indices.items[i + 1],
w->indices.len - i - 1);
w->indices.len--;
w->indices.items = realloc(w->indices.items,
sizeof(uint32_t) * w->indices.len);
for (size_t i = 0; i < w->sisos.len;) {
if (w->sisos.items[i].index == pa_index) {
memmove(&w->sisos.items[i], &w->sisos.items[i + 1],
w->sisos.len - i - 1);
w->sisos.len--;
w->sisos.items = realloc(w->sisos.items,
sizeof(uint32_t) * w->sisos.len);
} else {
i++;
}
}
}
void siso_watch_update(struct siso_watch *w, uint32_t target_index, pa_volume_t volume, bool mute) {
void siso_watch_update(struct siso_watch *w, uint32_t pa_index, uint32_t target_index, pa_cvolume volume, bool mute) {
w->target = target_index;
w->volume = volume;
w->mute = mute;
struct siso *s = NULL;
for (size_t i = 0; i < w->sisos.len; i++) {
if (w->sisos.items[i].index == pa_index) {
s = &w->sisos.items[i];
break;
}
}
if (!s) {
w->sisos.len++;
w->sisos.items = realloc(w->sisos.items,
sizeof(struct siso) * w->sisos.len);
s = &w->sisos.items[w->sisos.len - 1];
}
s->index = pa_index;
s->volume = volume;
s->mute = mute;
if (w->volume_changed) {
w->volume_changed(w);
}
}
uint32_t siso_watch_get_first_or_default(struct siso_watch *w, uint32_t default_) {
if (!w || w->indices.len == 0) return default_;
return w->indices.items[0];
if (!w || w->sisos.len == 0) return default_;
return w->sisos.items[0].index;
}
struct siso_watch *siso_add_name(struct siso_watch_list *wl, const char* name) {
......@@ -51,10 +55,9 @@ struct siso_watch *siso_add_name(struct siso_watch_list *wl, const char* name) {
struct siso_watch *item = &wl->items[wl->len - 1];
item->name = strdup(name);
item->target = -1;
item->volume = PA_VOLUME_MUTED;
item->mute = true;
item->indices.len = 0;
item->indices.items = NULL;
item->sisos.len = 0;
item->sisos.items = NULL;
item->volume_changed = NULL;
item->userdata = NULL;
......
......@@ -7,15 +7,20 @@
// siso (sink source) watch lists help keeping track of the indices of
// PulseAudio Sink/Source/Sink Input/Source Output indices by name.
struct siso {
uint32_t index;
pa_cvolume volume;
bool mute;
};
struct siso_watch {
const char *name;
uint32_t target; // sink in case of watching a sink input
pa_volume_t volume;
bool mute;
struct indices_list {
size_t len;
uint32_t *items;
} indices;
struct siso *items;
} sisos;
void (*volume_changed)(struct siso_watch *);
void *userdata;
};
......@@ -25,9 +30,9 @@ struct siso_watch_list {
struct siso_watch *items;
};
void siso_watch_add_index(struct siso_watch *w, uint32_t pa_index);
void siso_watch_remove_index(struct siso_watch *w, uint32_t pa_index);
void siso_watch_update(struct siso_watch *w, uint32_t target_index, pa_volume_t volume, bool mute);
void siso_watch_update(struct siso_watch *w, uint32_t pa_index,
uint32_t target_index, pa_cvolume volume, bool mute);
uint32_t siso_watch_get_first_or_default(struct siso_watch *w, uint32_t default_);
struct siso_watch *siso_add_name(struct siso_watch_list *wl, const char* name);
struct siso_watch *siso_get(struct siso_watch_list *wl, const char *name);
......
......@@ -22,12 +22,28 @@ void show_mute_and_speakers(struct siso_watch *w) {
midi_button_led(sp->seq, sp->port, BOTTOM1, w->target == speakers ? BUTTON_LED_ON : BUTTON_LED_OFF);
}
void button_test(enum button button, enum button_direction direction, void *userdata) {
void button_mute(enum button button, enum button_direction direction, void *userdata) {
fprintf(stdout, "button pressed: %i dir=%i\n", button, direction);
if (direction != BUTTON_PRESS) return;
struct siso_watch *w = userdata;
xpa_sink_input_set_mute(w, !w->mute);
}
void encoder_test(enum encoder encoder, int delta, void *userdata) {
void button_sink(enum button button, enum button_direction direction, void *userdata) {
fprintf(stdout, "button pressed: %i dir=%i\n", button, direction);
if (direction != BUTTON_PRESS) return;
struct siso_watch *w = userdata;
uint32_t speakers = siso_watch_get_first_or_default(siso_get(&sinks, "speakers"), -1);
uint32_t headphones = siso_watch_get_first_or_default(siso_get(&sinks, "headphones"), -1);
uint32_t sink = w->target == speakers ? headphones : speakers;
xpa_sink_input_set_sink(w, sink);
}
void encoder_volume(enum encoder encoder, int delta, void *userdata) {
fprintf(stdout, "encoder turned: %i delta=%i\n", encoder, delta);
struct siso_watch *w = userdata;
if (delta >= 64) delta = -(delta - 64);
xpa_sink_input_set_volume(w, delta / 100.0f);
}
int main(int argc, char *argv[]) {
......@@ -39,6 +55,7 @@ int main(int argc, char *argv[]) {
// keep track of speakers sink PA index
siso_add_name(&sinks, "speakers");
siso_add_name(&sinks, "headphones");
struct seq_port sp;
alsa(source, &sp.seq, &sp.port);
......@@ -48,8 +65,9 @@ int main(int argc, char *argv[]) {
mpd->volume_changed = show_mute_and_speakers;
button_callback_add(TOP1, button_test, NULL);
encoder_callback_add(ENC1, encoder_test, NULL);
button_callback_add(TOP1, button_mute, mpd);
button_callback_add(BOTTOM1, button_sink, mpd);
encoder_callback_add(ENC1, encoder_volume, mpd);
pa();
......
......@@ -35,8 +35,8 @@ enum button_led_state {
};
enum button_direction {
BUTTON_DOWN = 127,
BUTTON_UP = 0,
BUTTON_PRESS = 127,
BUTTON_RELEASE = 0,
};
enum encoder {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment