~vilhalmer/pavc

75d3ff9c97e2871200002476ceacc38b86f72877 — Bill Doyle 1 year, 10 days ago 8f7276a
Add option parsing infrastructure
1 files changed, 102 insertions(+), 10 deletions(-)

M pavc.c
M pavc.c => pavc.c +102 -10
@@ 1,21 1,33 @@
// PulseAudio Volume Control
// It does one thing

#include <pulse/context.h>
#include <pulse/def.h>
#include <pulse/introspect.h>
#include <pulse/mainloop.h>
#include <pulse/proplist.h>
#include <pulse/pulseaudio.h>
#include <pulse/volume.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <pulse/pulseaudio.h>

struct pavc {
	pa_mainloop * loop;

	enum {
		PRINT = 0,
		MUTE,
		UNMUTE,
		TOGGLE,
		UP,
		DOWN,
		SET,
	} mode;
	char * sink;
};

static void query_volume_sink(pa_context * ctx, const pa_sink_info * info, int eol, void * userdata) {
static void query_volume_sink(
		pa_context * ctx __attribute__((unused)),
		const pa_sink_info * info,
		int eol,
		void * userdata) {
	struct pavc * pavc = userdata;
	if (eol) {
		pa_mainloop_quit(pavc->loop, 0);


@@ 38,7 50,9 @@ static void state_changed(pa_context * ctx, void * userdata) {
		break;
	case PA_CONTEXT_READY:
		// woohoo
		pa_context_get_sink_info_by_name(ctx, "@DEFAULT_SINK@", query_volume_sink, pavc);
		if (pavc->mode == PRINT) {
			pa_context_get_sink_info_by_name(ctx, pavc->sink, query_volume_sink, pavc);
		}
		break;
	case PA_CONTEXT_UNCONNECTED:
	case PA_CONTEXT_AUTHORIZING:


@@ 50,6 64,25 @@ static void state_changed(pa_context * ctx, void * userdata) {
	}
}


const char * usage =
	"Usage: pavc [-h] [-s sink_idx] [<command> [<args>]]\n"
	"  -h        Show this help\n"
	"  -s        Operate on a specific sink instead of the default\n"
	"\n"
	"Commands:\n"
	"  mute      Mute the sink\n"
	"  unmute    Unmute the sink\n"
	"  toggle    Toggle between muted and unmuted\n"
	"  up [%]    Increase the volume by the given percent, or 5% by default\n"
	"  down [%]  Decrease the volume by the given percent, or 5% by default\n"
	"  set <%>   Set the volume to an absolute percent\n"
	"\n"
	"If no command is given, the current volume of the selected sink is printed.\n"
	"Commands may be abbreviated.\n"
	"";


int main(int argc, char * argv[]) {
	pa_mainloop * loop = pa_mainloop_new();
	assert(loop);


@@ 65,8 98,67 @@ int main(int argc, char * argv[]) {

	struct pavc pavc = {
		.loop = loop,
		.mode = PRINT,
		.sink = "@DEFAULT_SINK@",
	};

	int opt;
	while ((opt = getopt(argc, argv, "hs:")) != -1) {
		switch (opt) {
		case 's':
			pavc.sink = optarg;
			break;
		case 'h':
			printf("%s", usage);
			return 0;
		default:
			printf("%s", usage);
			return 1;
		}
	}

	int i = optind;
	if (i < argc) {
		if (strncmp("mute", argv[i], strlen(argv[i])) == 0) {
			pavc.mode = MUTE;
		}
		else if (strncmp("unmute", argv[i], strlen(argv[i])) == 0) {
			pavc.mode = UNMUTE;
		}
		else if (strncmp("toggle", argv[i], strlen(argv[i])) == 0) {
			pavc.mode = TOGGLE;
		}
		else if (strncmp("up", argv[i], strlen(argv[i])) == 0) {
			pavc.mode = UP;
		}
		else if (strncmp("down", argv[i], strlen(argv[i])) == 0) {
			pavc.mode = DOWN;
		}
		else if (strncmp("set", argv[i], strlen(argv[i])) == 0) {
			pavc.mode = SET;
		}
		else {
			printf("%s", usage);
			return 1;
		}
		++i;
	}

	int amount = 0;
	if (i < argc) {
		if (pavc.mode == UP || pavc.mode == DOWN || pavc.mode == SET) {
			char * extra;
			amount = strtol(argv[i], &extra, 10);
			if ((*extra != '%' && *extra != '\0') || amount < 0) {
				fprintf(stderr, "Invalid percent '%s'\n", argv[i]);
				return 1;
			}
		}
		else {
			fprintf(stderr, "Unexpected argument\n");
			return 1;
		}
	}
	pa_context_set_state_callback(ctx, state_changed, &pavc);

	int exit = 0;