aboutsummaryrefslogtreecommitdiffstats
path: root/pulsemix.c
diff options
context:
space:
mode:
authorDave Reisner <dreisner@archlinux.org>2012-08-14 08:58:50 -0400
committerDave Reisner <dreisner@archlinux.org>2012-08-14 08:58:50 -0400
commit4382c2acf0a893eb4b96c3465af73523560a4815 (patch)
tree635bd8f5235999e8786860ae358cbb546e1af90a /pulsemix.c
parent33d2495f66f052377794473bc58ce60e79a9be34 (diff)
downloadmirror-ponymix-4382c2acf0a893eb4b96c3465af73523560a4815.tar.gz
mirror-ponymix-4382c2acf0a893eb4b96c3465af73523560a4815.tar.bz2
mirror-ponymix-4382c2acf0a893eb4b96c3465af73523560a4815.zip
This repo is now about ponies.
Diffstat (limited to 'pulsemix.c')
-rw-r--r--pulsemix.c860
1 files changed, 0 insertions, 860 deletions
diff --git a/pulsemix.c b/pulsemix.c
deleted file mode 100644
index c053db7..0000000
--- a/pulsemix.c
+++ /dev/null
@@ -1,860 +0,0 @@
-/* Copyright (c) 2012 Dave Reisner
- *
- * pulsemix.c
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#define _GNU_SOURCE
-#include <errno.h>
-#include <err.h>
-#include <getopt.h>
-#include <math.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <pulse/pulseaudio.h>
-
-#define UNUSED __attribute__((unused))
-
-#define CLAMP(x, low, high) \
- __extension__ ({ \
- typeof(x) _x = (x); \
- typeof(low) _low = (low); \
- typeof(high) _high = (high); \
- ((_x > _high) ? _high : ((_x < _low) ? _low : _x)); \
- })
-
-enum connectstate {
- STATE_CONNECTING = 0,
- STATE_CONNECTED,
- STATE_ERROR
-};
-
-enum mode {
- MODE_DEVICE = 0,
- MODE_APP,
- MODE_INVALID
-};
-
-enum action {
- ACTION_DEFAULTS = 0,
- ACTION_LIST,
- ACTION_GETVOL,
- ACTION_SETVOL,
- ACTION_GETBAL,
- ACTION_SETBAL,
- ACTION_ADJBAL,
- ACTION_INCREASE,
- ACTION_DECREASE,
- ACTION_MUTE,
- ACTION_UNMUTE,
- ACTION_TOGGLE,
- ACTION_ISMUTED,
- ACTION_SETDEFAULT,
- ACTION_MOVE,
- ACTION_KILL,
- ACTION_INVALID
-};
-
-static const char *actions[ACTION_INVALID] = {
- [ACTION_DEFAULTS] = "defaults",
- [ACTION_LIST] = "list",
- [ACTION_GETVOL] = "get-volume",
- [ACTION_SETVOL] = "set-volume",
- [ACTION_GETBAL] = "get-balance",
- [ACTION_SETBAL] = "set-balance",
- [ACTION_ADJBAL] = "adj-balance",
- [ACTION_INCREASE] = "increase",
- [ACTION_DECREASE] = "decrease",
- [ACTION_MUTE] = "mute",
- [ACTION_UNMUTE] = "unmute",
- [ACTION_TOGGLE] = "toggle",
- [ACTION_ISMUTED] = "is-muted",
- [ACTION_SETDEFAULT] = "set-default",
- [ACTION_MOVE] = "move",
- [ACTION_KILL] = "kill"
-};
-
-struct io_t {
- uint32_t idx;
- char *name;
- char *desc;
- const char *pp_name;
- pa_cvolume volume;
- pa_channel_map channels;
- int volume_percent;
- int balance;
- int mute;
-
- struct ops_t {
- pa_operation *(*mute)(pa_context *, uint32_t, int, pa_context_success_cb_t, void *);
- pa_operation *(*setvol)(pa_context *, uint32_t, const pa_cvolume *, pa_context_success_cb_t, void *);
- pa_operation *(*setdefault)(pa_context *, const char *, pa_context_success_cb_t, void *);
- pa_operation *(*move)(pa_context *, uint32_t, uint32_t, pa_context_success_cb_t, void *);
- pa_operation *(*kill)(pa_context *, uint32_t, pa_context_success_cb_t, void *);
- } op;
-
- struct io_t *next;
-};
-
-struct pulseaudio_t {
- pa_context *cxt;
- pa_mainloop *mainloop;
- enum connectstate state;
- int success;
-
- struct io_t *head;
-};
-
-static int xstrtol(const char *str, long *out)
-{
- char *end = NULL;
-
- if (str == NULL || *str == '\0')
- return -1;
- errno = 0;
-
- *out = strtol(str, &end, 10);
- if (errno || str == end || (end && *end))
- return -1;
-
- return 0;
-}
-
-static void populate_levels(struct io_t *node)
-{
- node->volume_percent = (int)(((double)pa_cvolume_avg(&node->volume) * 100)
- / PA_VOLUME_NORM);
- node->balance = (int)((double)pa_cvolume_get_balance(&node->volume,
- &node->channels) * 100);
-}
-
-#define IO_NEW(io, info, pp) \
- io = calloc(1, sizeof(struct io_t)); \
- io->idx = info->index; \
- io->mute = info->mute; \
- io->name = strdup(info->name); \
- io->pp_name = pp; \
- memcpy(&io->volume, &info->volume, sizeof(pa_cvolume)); \
- memcpy(&io->channels, &info->channel_map, sizeof(pa_channel_map)); \
- populate_levels(io);
-
-static struct io_t *sink_new(const pa_sink_info *info)
-{
- struct io_t *sink;
-
- IO_NEW(sink, info, "sink");
- sink->desc = strdup(info->description);
- sink->op.mute = pa_context_set_sink_mute_by_index;
- sink->op.setvol = pa_context_set_sink_volume_by_index;
- sink->op.setdefault = pa_context_set_default_sink;
-
- return sink;
-}
-
-static struct io_t *sink_input_new(const pa_sink_input_info *info)
-{
- struct io_t *sink;
-
- IO_NEW(sink, info, "sink");
- sink->desc = strdup(
- pa_proplist_gets(info->proplist, PA_PROP_APPLICATION_NAME));
- sink->op.mute = pa_context_set_sink_input_mute;
- sink->op.setvol = pa_context_set_sink_input_volume;
- sink->op.move = pa_context_move_sink_input_by_index;
- sink->op.kill = pa_context_kill_sink_input;
-
- return sink;
-}
-
-static struct io_t *source_new(const pa_source_info *info)
-{
- struct io_t *source;
-
- IO_NEW(source, info, "source");
- source->desc = strdup(info->description);
- source->op.mute = pa_context_set_source_mute_by_index;
- source->op.setvol = pa_context_set_source_volume_by_index;
- source->op.setdefault = pa_context_set_default_source;
-
- return source;
-}
-
-static struct io_t *source_output_new(const pa_source_output_info *info)
-{
- struct io_t *source;
-
- IO_NEW(source, info, "source");
- source->desc = strdup(
- pa_proplist_gets(info->proplist, PA_PROP_APPLICATION_NAME));
- source->op.mute = pa_context_set_source_output_mute;
- source->op.setvol = pa_context_set_source_output_volume;
- source->op.move = pa_context_move_source_output_by_index;
- source->op.kill = pa_context_kill_source_output;
-
- return source;
-}
-
-static void sink_add_cb(pa_context UNUSED *c, const pa_sink_info *i, int eol,
- void *raw)
-{
- struct pulseaudio_t *pulse = raw;
- struct io_t *sink;
-
- if (eol)
- return;
-
- sink = sink_new(i);
- sink->next = pulse->head;
- pulse->head = sink;
-}
-
-static void sink_input_add_cb(pa_context UNUSED *c, const pa_sink_input_info *i, int eol,
- void *raw)
-{
- struct pulseaudio_t *pulse = raw;
- struct io_t *sink;
-
- if (eol)
- return;
-
- sink = sink_input_new(i);
- sink->next = pulse->head;
- pulse->head = sink;
-}
-
-static void source_add_cb(pa_context UNUSED *c, const pa_source_info *i, int eol, void *raw)
-{
- struct pulseaudio_t *pulse = raw;
- struct io_t *source;
-
- if (eol)
- return;
-
- source = source_new(i);
- source->next = pulse->head;
- pulse->head = source;
-}
-
-static void source_output_add_cb(pa_context UNUSED *c, const pa_source_output_info *i, int eol,
- void *raw)
-{
- struct pulseaudio_t *pulse = raw;
- struct io_t *source;
-
- if (eol)
- return;
-
- source = source_output_new(i);
- source->next = pulse->head;
- pulse->head = source;
-}
-
-static void server_info_cb(pa_context UNUSED *c, const pa_server_info *i,
- void *raw)
-{
- const char **sink_name = raw;
-
- *sink_name = i->default_sink_name;
-}
-
-static void source_info_cb(pa_context UNUSED *c, const pa_server_info *i, void *raw)
-{
- const char **source_name = raw;
-
- *source_name = i->default_source_name;
-}
-
-static void state_cb(pa_context UNUSED *c, void *raw)
-{
- struct pulseaudio_t *pulse = raw;
-
- switch (pa_context_get_state(pulse->cxt)) {
- case PA_CONTEXT_READY:
- pulse->state = STATE_CONNECTED;
- break;
- case PA_CONTEXT_FAILED:
- pulse->state = STATE_ERROR;
- break;
- case PA_CONTEXT_UNCONNECTED:
- case PA_CONTEXT_AUTHORIZING:
- case PA_CONTEXT_SETTING_NAME:
- case PA_CONTEXT_CONNECTING:
- case PA_CONTEXT_TERMINATED:
- break;
- }
-}
-
-static void success_cb(pa_context UNUSED *c, int success, void *raw)
-{
- struct pulseaudio_t *pulse = raw;
- pulse->success = success;
-}
-
-static void pulse_async_wait(struct pulseaudio_t *pulse, pa_operation *op)
-{
- while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
- pa_mainloop_iterate(pulse->mainloop, 1, NULL);
-}
-
-static int set_volume(struct pulseaudio_t *pulse, struct io_t *dev, long v)
-{
- pa_cvolume *vol = pa_cvolume_set(&dev->volume, dev->volume.channels,
- (int)fmax((double)(v + .5) * PA_VOLUME_NORM / 100, 0));
- pa_operation *op = pulse->head->op.setvol(pulse->cxt, dev->idx, vol,
- success_cb, pulse);
- pulse_async_wait(pulse, op);
-
- if (pulse->success)
- printf("%ld\n", v);
- else {
- int err = pa_context_errno(pulse->cxt);
- fprintf(stderr, "failed to set volume: %s\n", pa_strerror(err));
- }
-
- pa_operation_unref(op);
-
- return !pulse->success;
-}
-
-static int set_balance(struct pulseaudio_t *pulse, struct io_t *dev, long v)
-{
- pa_cvolume *vol;
- pa_operation *op;
-
- if (pa_channel_map_valid(&dev->channels) == 0) {
- warnx("can't set balance on that device.");
- return 1;
- }
-
- vol = pa_cvolume_set_balance(&dev->volume, &dev->channels, v / 100.0);
- op = dev->op.setvol(pulse->cxt, dev->idx, vol, success_cb, pulse);
- pulse_async_wait(pulse, op);
-
- if (pulse->success)
- printf("%ld\n", v);
- else {
- int err = pa_context_errno(pulse->cxt);
- warnx("failed to set balance: %s", pa_strerror(err));
- }
-
- pa_operation_unref(op);
-
- return !pulse->success;
-}
-
-static int set_mute(struct pulseaudio_t *pulse, struct io_t *dev, int mute)
-{
- pa_operation* op;
-
- /* new effective volume */
- printf("%d\n", mute ? 0 : dev->volume_percent);
-
- op = pulse->head->op.mute(pulse->cxt, dev->idx, mute,
- success_cb, pulse);
-
- pulse_async_wait(pulse, op);
-
- if (!pulse->success) {
- int err = pa_context_errno(pulse->cxt);
- fprintf(stderr, "failed to mute device: %s\n", pa_strerror(err));
- }
-
- pa_operation_unref(op);
-
- return !pulse->success;
-}
-
-static int kill_client(struct pulseaudio_t *pulse, struct io_t *dev)
-{
- pa_operation *op;
-
- if (dev->op.kill == NULL) {
- warnx("only clients can be killed");
- return 1;
- }
-
- op = dev->op.kill(pulse->cxt, dev->idx, success_cb, pulse);
- pulse_async_wait(pulse, op);
-
- if (!pulse->success) {
- int err = pa_context_errno(pulse->cxt);
- fprintf(stderr, "failed to kill client: %s\n", pa_strerror(err));
- }
-
- pa_operation_unref(op);
-
- return !pulse->success;
-}
-
-static int move_client(struct pulseaudio_t *pulse, struct io_t *dev)
-{
- pa_operation* op;
-
- if (dev->next == NULL) {
- warnx("no destination to move to");
- return 1;
- }
- if (dev->next->op.move == NULL) {
- warnx("only clients can be moved");
- return 1;
- }
-
- op = dev->next->op.move(pulse->cxt, dev->next->idx, dev->idx, success_cb,
- pulse);
-
- pulse_async_wait(pulse, op);
-
- if (!pulse->success) {
- int err = pa_context_errno(pulse->cxt);
- fprintf(stderr, "failed to move client: %s\n", pa_strerror(err));
- }
-
- pa_operation_unref(op);
-
- return !pulse->success;
-}
-
-static void print(struct io_t *dev)
-{
- printf("%s %2d: %s\n %s\n Avg. Volume: %d%% %s\n", dev->pp_name,
- dev->idx, dev->name, dev->desc, dev->volume_percent,
- dev->mute ? "[Muted]" : "");
-}
-
-static void print_all(struct pulseaudio_t *pulse)
-{
- struct io_t *dev = pulse->head;
-
- while (dev) {
- print(dev);
- dev = dev->next;
- }
-}
-
-static void populate_sinks(struct pulseaudio_t *pulse, enum mode mode)
-{
- pa_operation *op;
-
- switch (mode) {
- case MODE_APP:
- op = pa_context_get_sink_input_info_list(pulse->cxt, sink_input_add_cb, pulse);
- break;
- case MODE_DEVICE:
- default:
- op = pa_context_get_sink_info_list(pulse->cxt, sink_add_cb, pulse);
- }
-
- pulse_async_wait(pulse, op);
- pa_operation_unref(op);
-}
-
-static int get_sink_by_name(struct pulseaudio_t *pulse, const char *name, enum mode mode)
-{
- pa_operation *op;
-
- switch (mode) {
- case MODE_APP:
- {
- long id;
- if (xstrtol(name, &id) < 0) {
- warnx("application sink not valid id: %s", name);
- return 1;
- }
- op = pa_context_get_sink_input_info(pulse->cxt, (uint32_t)id, sink_input_add_cb, pulse);
- break;
- }
- case MODE_DEVICE:
- default:
- op = pa_context_get_sink_info_by_name(pulse->cxt, name, sink_add_cb, pulse);
- }
-
- pulse_async_wait(pulse, op);
- pa_operation_unref(op);
-
- return 0;
-}
-
-static int get_default_sink(struct pulseaudio_t *pulse)
-{
- const char *sink_name;
- pa_operation *op = pa_context_get_server_info(pulse->cxt, server_info_cb,
- &sink_name);
- pulse_async_wait(pulse, op);
- pa_operation_unref(op);
-
- return get_sink_by_name(pulse, sink_name, MODE_DEVICE);
-}
-
-static void populate_sources(struct pulseaudio_t *pulse, enum mode mode)
-{
- pa_operation *op;
-
- switch (mode) {
- case MODE_APP:
- op = pa_context_get_source_output_info_list(pulse->cxt, source_output_add_cb, pulse);
- break;
- case MODE_DEVICE:
- default:
- op = pa_context_get_source_info_list(pulse->cxt, source_add_cb, pulse);
- }
-
- pulse_async_wait(pulse, op);
- pa_operation_unref(op);
-}
-
-static int get_source_by_name(struct pulseaudio_t *pulse, const char *name, enum mode mode)
-{
- pa_operation *op;
-
- switch (mode) {
- case MODE_APP:
- {
- long id;
- if (xstrtol(name, &id) < 0) {
- warnx("application source not valid id: %s", name);
- return 1;
- }
- op = pa_context_get_source_output_info(pulse->cxt, (uint32_t)id, source_output_add_cb, pulse);
- break;
- }
- case MODE_DEVICE:
- default:
- op = pa_context_get_source_info_by_name(pulse->cxt, name, source_add_cb, pulse);
- }
-
- pulse_async_wait(pulse, op);
- pa_operation_unref(op);
-
- return 0;
-}
-
-static int get_default_source(struct pulseaudio_t *pulse)
-{
- const char *source_name;
- pa_operation *op = pa_context_get_server_info(pulse->cxt, source_info_cb,
- &source_name);
- pulse_async_wait(pulse, op);
- pa_operation_unref(op);
-
- return get_source_by_name(pulse, source_name, MODE_DEVICE);
-}
-
-static int set_default(struct pulseaudio_t *pulse, struct io_t *dev)
-{
- pa_operation *op;
-
- if (dev->op.setdefault == NULL) {
- warnx("valid operation only for devices");
- return 1;
- }
-
- op = dev->op.setdefault(pulse->cxt, dev->name, success_cb, pulse);
- pulse_async_wait(pulse, op);
-
- if (!pulse->success) {
- int err = pa_context_errno(pulse->cxt);
- fprintf(stderr, "failed to set default %s to %s: %s\n", dev->pp_name,
- dev->name, pa_strerror(err));
- }
-
- pa_operation_unref(op);
-
- return !pulse->success;
-}
-
-static int pulse_connect(struct pulseaudio_t *pulse)
-{
- pa_context_connect(pulse->cxt, NULL, PA_CONTEXT_NOFLAGS, NULL);
- while (pulse->state == STATE_CONNECTING)
- pa_mainloop_iterate(pulse->mainloop, 1, NULL);
-
- if (pulse->state == STATE_ERROR) {
- int r = pa_context_errno(pulse->cxt);
- fprintf(stderr, "failed to connect to pulse daemon: %s\n",
- pa_strerror(r));
- return 1;
- }
-
- return 0;
-}
-
-static int pulse_init(struct pulseaudio_t *pulse)
-{
- pulse->mainloop = pa_mainloop_new();
- pulse->cxt = pa_context_new(pa_mainloop_get_api(pulse->mainloop), "lolpulse");
- pulse->state = STATE_CONNECTING;
- pulse->head = NULL;
-
- pa_context_set_state_callback(pulse->cxt, state_cb, pulse);
- return pulse_connect(pulse);
-}
-
-static void pulse_deinit(struct pulseaudio_t *pulse)
-{
- struct io_t *node = pulse->head;
-
- pa_context_disconnect(pulse->cxt);
- pa_mainloop_free(pulse->mainloop);
-
- while (node) {
- node = pulse->head->next;
- free(pulse->head->name);
- free(pulse->head->desc);
- free(pulse->head);
- pulse->head = node;
- }
-}
-
-static void __attribute__((__noreturn__)) usage(FILE *out)
-{
- fprintf(out, "usage: %s [options] <command>...\n", program_invocation_short_name);
- fputs("\nOptions:\n"
- " -h, --help display this help and exit\n"
-
- "\n -d, --device set device mode (default)\n"
- " -a, --app set application mode\n"
-
- "\n -o, --sink=<name> control a sink other than the default\n"
- " -i, --source=<name> control a source\n", out);
-
- fputs("\nCommon Commands:\n"
- " list list available devices\n"
- " get-volume get volume for device\n"
- " set-volume VALUE set volume for device\n"
- " get-balance get balance for device\n"
- " set-balance VALUE set balance for device\n"
- " adj-balance VALUE increase or decrease balance for device\n"
- " increase VALUE increase volume\n", out);
- fputs(" decrease VALUE decrease volume\n"
- " mute mute device\n"
- " unmute unmute device\n"
- " toggle toggle mute\n"
- " is-muted check if muted\n", out);
-
- fputs("\nDevice Commands:\n"
- " defaults list default devices\n"
- " set-default DEVICE_ID set default device by ID\n"
-
- "\nApplication Commands:\n"
- " move APP_ID DEVICE_ID move application stream by ID to device ID\n"
- " kill APP_ID kill an application stream by ID\n", out);
-
- exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
-}
-
-static enum action string_to_verb(const char *string)
-{
- size_t i;
-
- for (i = 0; i < ACTION_INVALID; i++)
- if (strcmp(actions[i], string) == 0)
- break;
-
- return i;
-}
-
-static int do_verb(struct pulseaudio_t *pulse, enum action verb, int value)
-{
- switch (verb) {
- case ACTION_GETVOL:
- printf("%d\n", pulse->head->volume_percent);
- return 0;
- case ACTION_SETVOL:
- return set_volume(pulse, pulse->head, CLAMP(value, 0, 150));
- case ACTION_GETBAL:
- printf("%d\n", pulse->head->balance);
- return 0;
- case ACTION_SETBAL:
- return set_balance(pulse, pulse->head, CLAMP(value, -100, 100));
- case ACTION_ADJBAL:
- return set_balance(pulse, pulse->head,
- CLAMP(pulse->head->balance + value, -100, 100));
- case ACTION_INCREASE:
- return set_volume(pulse, pulse->head,
- CLAMP(pulse->head->volume_percent + value, 0, 100));
- case ACTION_DECREASE:
- return set_volume(pulse, pulse->head,
- CLAMP(pulse->head->volume_percent - value, 0, 100));
- case ACTION_MUTE:
- return set_mute(pulse, pulse->head, 1);
- case ACTION_UNMUTE:
- return set_mute(pulse, pulse->head, 0);
- case ACTION_TOGGLE:
- return set_mute(pulse, pulse->head, !pulse->head->mute);
- case ACTION_ISMUTED:
- return !pulse->head->mute;
- case ACTION_MOVE:
- return move_client(pulse, pulse->head);
- case ACTION_KILL:
- return kill_client(pulse, pulse->head);
- case ACTION_SETDEFAULT:
- return set_default(pulse, pulse->head);
- default:
- errx(EXIT_FAILURE, "internal error: unhandled verb id %d\n", verb);
- }
-}
-
-int main(int argc, char *argv[])
-{
- struct pulseaudio_t pulse;
- enum action verb;
- char *id = NULL, *arg = NULL;
- long value = 0;
- enum mode mode = MODE_DEVICE;
- int rc = EXIT_SUCCESS;
-
- const char *pp_name = "sink";
- int (*fn_get_default)(struct pulseaudio_t *) = get_default_sink;
- int (*fn_get_by_name)(struct pulseaudio_t *, const char *, enum mode) = get_sink_by_name;
-
- static const struct option opts[] = {
- { "app", no_argument, 0, 'a' },
- { "device", no_argument, 0, 'd' },
- { "help", no_argument, 0, 'h' },
- { "sink", optional_argument, 0, 'o' },
- { "source", optional_argument, 0, 'i' },
- { 0, 0, 0, 0 },
- };
-
- for (;;) {
- int opt = getopt_long(argc, argv, "adhi::o::", opts, NULL);
- if (opt == -1)
- break;
-
- switch (opt) {
- case 'h':
- usage(stdout);
- case 'd':
- mode = MODE_DEVICE;
- break;
- case 'a':
- mode = MODE_APP;
- break;
- case 'o':
- id = optarg;
- fn_get_default = get_default_sink;
- fn_get_by_name = get_sink_by_name;
- pp_name = "sink";
- break;
- case 'i':
- id = optarg;
- fn_get_default = get_default_source;
- fn_get_by_name = get_source_by_name;
- pp_name = "source";
- break;
- default:
- return EXIT_FAILURE;
- }
- }
-
- /* string -> enum */
- verb = (optind == argc) ? (mode ? ACTION_LIST : ACTION_DEFAULTS) : string_to_verb(argv[optind]);
- if (verb == ACTION_INVALID)
- errx(EXIT_FAILURE, "unknown action: %s", argv[optind]);
-
- optind++;
- switch (verb) {
- case ACTION_SETVOL:
- case ACTION_SETBAL:
- case ACTION_ADJBAL:
- case ACTION_INCREASE:
- case ACTION_DECREASE:
- if (optind == argc)
- errx(EXIT_FAILURE, "missing value for action '%s'", argv[optind - 1]);
- else {
- /* validate to number */
- if (xstrtol(argv[optind], &value) < 0)
- errx(EXIT_FAILURE, "invalid number: %s", argv[optind]);
- }
- break;
- case ACTION_SETDEFAULT:
- case ACTION_KILL:
- if (optind == argc)
- errx(EXIT_FAILURE, "missing arguments for action '%s'", argv[optind - 1]);
- else
- id = argv[optind];
- break;
- case ACTION_MOVE:
- if (optind > argc - 2)
- errx(EXIT_FAILURE, "missing arguments for action '%s'", argv[optind - 1]);
- else {
- id = argv[optind++];
- arg = argv[optind];
- }
- break;
- default:
- break;
- }
-
- /* initialize connection */
- if (pulse_init(&pulse) != 0)
- return EXIT_FAILURE;
-
- switch (verb) {
- case ACTION_DEFAULTS:
- get_default_sink(&pulse);
- get_default_source(&pulse);
- print_all(&pulse);
- goto done;
- case ACTION_LIST:
- populate_sinks(&pulse, mode);
- populate_sources(&pulse, mode);
- print_all(&pulse);
- goto done;
- default:
- break;
- }
-
- if (id && fn_get_by_name) {
- if (fn_get_by_name(&pulse, id, mode) != 0)
- goto done;
- } else if (!mode && verb != ACTION_SETDEFAULT && fn_get_default) {
- if (fn_get_default(&pulse) != 0)
- goto done;
- }
-
- if (pulse.head == NULL) {
- if (mode && !id)
- warnx("%s id not set, no default operations", pp_name);
- else
- warnx("%s not found: %s", pp_name, id ? id : "default");
- rc = EXIT_FAILURE;
- goto done;
- }
-
- if (arg && fn_get_by_name)
- fn_get_by_name(&pulse, arg, MODE_DEVICE);
-
- rc = do_verb(&pulse, verb, value);
-
-done:
- /* shut down */
- pulse_deinit(&pulse);
-
- return rc;
-}
-
-/* vim: set noet ts=2 sw=2: */