AM_CFLAGS=-ansi -D_GNU_SOURCE
-bin_PROGRAMS = polypaudio pacat pacat-simple parec-simple
+bin_PROGRAMS = polypaudio pacat pactl pacat-simple parec-simple
pkglib_LTLIBRARIES=libiochannel.la \
libsocket-server.la \
pacat_LDADD = libpolyp.la libpolyp-error.la
pacat_CFLAGS = $(AM_CFLAGS)
+pactl_SOURCES = pactl.c #$(libpolyp_la_SOURCES) $(libpolyp_error_la_SOURCES)
+pactl_LDADD = libpolyp.la libpolyp-error.la
+pactl_CFLAGS = $(AM_CFLAGS)
+
pacat_simple_SOURCES = pacat-simple.c #$(libpolyp_la_SOURCES) $(libpolyp_simple_la_SOURCES) $(libpolyp_error_la_SOURCES)
pacat_simple_LDADD = libpolyp-simple.la libpolyp-error.la
pacat_simple_CFLAGS = $(AM_CFLAGS)
}
int main(int argc, char *argv[]) {
- struct pa_mainloop* m;
+ struct pa_mainloop* m = NULL;
int ret = 1, r;
char *bn;
if (context)
pa_context_free(context);
- pa_signal_done();
- if (m)
+ if (m) {
+ pa_signal_done();
pa_mainloop_free(m);
+ }
+
if (buffer)
free(buffer);
--- /dev/null
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "polyp.h"
+#include "polyp-error.h"
+#include "mainloop.h"
+#include "mainloop-signal.h"
+
+static struct pa_context *context = NULL;
+static struct pa_mainloop_api *mainloop_api = NULL;
+
+static enum {
+ NONE,
+ EXIT,
+ STAT
+} action = NONE;
+
+static void quit(int ret) {
+ assert(mainloop_api);
+ mainloop_api->quit(mainloop_api, ret);
+}
+
+static void context_die_callback(struct pa_context *c, void *userdata) {
+ assert(c);
+ fprintf(stderr, "Connection to server shut down, exiting.\n");
+ quit(1);
+}
+
+static void context_drain_complete(struct pa_context *c, void *userdata) {
+ assert(c);
+ fprintf(stderr, "Connection to server shut down, exiting.\n");
+ quit(0);
+}
+
+static void drain(void) {
+ if (pa_context_drain(context, context_drain_complete, NULL) < 0)
+ quit(0);
+}
+
+static void stat_callback(struct pa_context *c, uint32_t blocks, uint32_t total, void *userdata) {
+ if (blocks == (uint32_t) -1) {
+ fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c)));
+ quit(1);
+ return;
+ }
+
+ fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n", blocks, total);
+ drain();
+}
+
+static void context_complete_callback(struct pa_context *c, int success, void *userdata) {
+ assert(c);
+
+ if (!success) {
+ fprintf(stderr, "Connection failed: %s\n", pa_strerror(pa_context_errno(c)));
+ goto fail;
+ }
+
+ fprintf(stderr, "Connection established.\n");
+
+ if (action == STAT)
+ pa_context_stat(c, stat_callback, NULL);
+ else {
+ assert(action == EXIT);
+ pa_context_exit(c);
+ drain();
+ }
+
+ return;
+
+fail:
+ quit(1);
+}
+
+static void exit_signal_callback(void *id, int sig, void *userdata) {
+ fprintf(stderr, "Got SIGINT, exiting.\n");
+ quit(0);
+
+}
+
+int main(int argc, char *argv[]) {
+ struct pa_mainloop* m = NULL;
+ int ret = 1, r;
+
+ if (argc >= 2) {
+ if (!strcmp(argv[1], "stat"))
+ action = STAT;
+ else if (!strcmp(argv[1], "exit"))
+ action = EXIT;
+ }
+
+ if (action == NONE) {
+ fprintf(stderr, "No valid action specified. Use one of: stat, exit\n");
+ goto quit;
+ }
+
+ if (!(m = pa_mainloop_new())) {
+ fprintf(stderr, "pa_mainloop_new() failed.\n");
+ goto quit;
+ }
+
+ mainloop_api = pa_mainloop_get_api(m);
+
+ r = pa_signal_init(mainloop_api);
+ assert(r == 0);
+ pa_signal_register(SIGINT, exit_signal_callback, NULL);
+ signal(SIGPIPE, SIG_IGN);
+
+ if (!(context = pa_context_new(mainloop_api, argv[0]))) {
+ fprintf(stderr, "pa_context_new() failed.\n");
+ goto quit;
+ }
+
+ if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) {
+ fprintf(stderr, "pa_context_connext() failed.\n");
+ goto quit;
+ }
+
+ pa_context_set_die_callback(context, context_die_callback, NULL);
+
+ if (pa_mainloop_run(m, &ret) < 0) {
+ fprintf(stderr, "pa_mainloop_run() failed.\n");
+ goto quit;
+ }
+
+quit:
+ if (context)
+ pa_context_free(context);
+
+ if (m) {
+ pa_signal_done();
+ pa_mainloop_free(m);
+ }
+
+ return ret;
+}
void (*die_callback)(struct pa_context*c, void *userdata);
void *die_userdata;
+
+ void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata);
+ void *stat_userdata;
uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
};
c->die_callback = NULL;
c->die_userdata = NULL;
+ c->stat_callback = NULL;
+ c->stat_userdata = NULL;
+
pa_check_for_sigpipe();
return c;
}
pa_pstream_send_tagstruct(s->context->pstream, t);
pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s);
}
+
+void pa_context_exit(struct pa_context *c) {
+ struct pa_tagstruct *t;
+ t = pa_tagstruct_new(NULL, 0);
+ assert(t);
+ pa_tagstruct_putu32(t, PA_COMMAND_EXIT);
+ pa_tagstruct_putu32(t, c->ctag++);
+ pa_pstream_send_tagstruct(c->pstream, t);
+}
+
+static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+ struct pa_context *c = userdata;
+ uint32_t total, count;
+ assert(pd && c);
+
+ if (command != PA_COMMAND_REPLY) {
+ if (handle_error(c, command, t) < 0) {
+ context_dead(c);
+ return;
+ }
+
+ if (c->stat_callback)
+ c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata);
+ return;
+ }
+
+ if (pa_tagstruct_getu32(t, &count) < 0 ||
+ pa_tagstruct_getu32(t, &total) < 0 ||
+ !pa_tagstruct_eof(t)) {
+ c->error = PA_ERROR_PROTOCOL;
+ context_dead(c);
+ return;
+ }
+
+ if (c->stat_callback)
+ c->stat_callback(c, count, total, c->stat_userdata);
+}
+
+void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) {
+ uint32_t tag;
+ struct pa_tagstruct *t;
+
+ c->stat_callback = cb;
+ c->stat_userdata = userdata;
+
+ if (cb == NULL)
+ return;
+
+ t = pa_tagstruct_new(NULL, 0);
+ assert(t);
+ pa_tagstruct_putu32(t, PA_COMMAND_STAT);
+ pa_tagstruct_putu32(t, tag = c->ctag++);
+ pa_pstream_send_tagstruct(c->pstream, t);
+ pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c);
+}
int pa_context_is_pending(struct pa_context *c);
+void pa_context_exit(struct pa_context *c);
+void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata);
+
struct pa_stream;
struct pa_stream* pa_stream_new(
PA_COMMAND_DRAIN_PLAYBACK_STREAM,
PA_COMMAND_PLAYBACK_STREAM_KILLED,
PA_COMMAND_RECORD_STREAM_KILLED,
+ PA_COMMAND_STAT,
PA_COMMAND_MAX
};
static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
+static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
[PA_COMMAND_ERROR] = { NULL },
[PA_COMMAND_SET_NAME] = { command_set_name },
[PA_COMMAND_LOOKUP_SINK] = { command_lookup },
[PA_COMMAND_LOOKUP_SOURCE] = { command_lookup },
+ [PA_COMMAND_STAT] = { command_stat },
};
/* structure management */
}
}
+static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+ struct connection *c = userdata;
+ assert(c && t);
+ struct pa_tagstruct *reply;
+
+ if (!pa_tagstruct_eof(t)) {
+ protocol_error(c);
+ return;
+ }
+
+ if (!c->authorized) {
+ pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS);
+ return;
+ }
+
+ reply = pa_tagstruct_new(NULL, 0);
+ assert(reply);
+ pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
+ pa_tagstruct_putu32(reply, tag);
+ pa_tagstruct_putu32(reply, pa_memblock_get_count());
+ pa_tagstruct_putu32(reply, pa_memblock_get_total());
+ pa_pstream_send_tagstruct(c->pstream, reply);
+}
+
/*** pstream callbacks ***/
static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
-- clean secure directory handling (with username)
+- pactl
- native library/protocol:
more functions (esp. latency)
-- prefix modules/libraries with pa_
-
- xmms+esound latency testing
+- prefix modules/libraries with pa_
- rename files
- svn-id and license in every file
- documentation
- make mcalign merge chunks
- modinfo
- move the global memblock statistics variables to the core
+- unix socket directories include user name
+
drivers:
- libao