add pactl tool

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@71 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2004-07-15 20:51:55 +00:00
parent c36dadd2bd
commit d8f1300661
8 changed files with 246 additions and 7 deletions

View file

@ -18,7 +18,7 @@
AM_CFLAGS=-ansi -D_GNU_SOURCE 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 \ pkglib_LTLIBRARIES=libiochannel.la \
libsocket-server.la \ libsocket-server.la \
@ -246,6 +246,10 @@ pacat_SOURCES = pacat.c #$(libpolyp_la_SOURCES) $(libpolyp_error_la_SOURCES)
pacat_LDADD = libpolyp.la libpolyp-error.la pacat_LDADD = libpolyp.la libpolyp-error.la
pacat_CFLAGS = $(AM_CFLAGS) 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_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_LDADD = libpolyp-simple.la libpolyp-error.la
pacat_simple_CFLAGS = $(AM_CFLAGS) pacat_simple_CFLAGS = $(AM_CFLAGS)

View file

@ -222,7 +222,7 @@ static void exit_signal_callback(void *id, int sig, void *userdata) {
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
struct pa_mainloop* m; struct pa_mainloop* m = NULL;
int ret = 1, r; int ret = 1, r;
char *bn; char *bn;
@ -279,9 +279,11 @@ quit:
if (context) if (context)
pa_context_free(context); pa_context_free(context);
pa_signal_done(); if (m) {
if (m) pa_signal_done();
pa_mainloop_free(m); pa_mainloop_free(m);
}
if (buffer) if (buffer)
free(buffer); free(buffer);

141
src/pactl.c Normal file
View file

@ -0,0 +1,141 @@
#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;
}

View file

@ -53,6 +53,9 @@ struct pa_context {
void (*die_callback)(struct pa_context*c, void *userdata); void (*die_callback)(struct pa_context*c, void *userdata);
void *die_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]; uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
}; };
@ -133,6 +136,9 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *
c->die_callback = NULL; c->die_callback = NULL;
c->die_userdata = NULL; c->die_userdata = NULL;
c->stat_callback = NULL;
c->stat_userdata = NULL;
pa_check_for_sigpipe(); pa_check_for_sigpipe();
return c; return c;
} }
@ -834,3 +840,58 @@ void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s,
pa_pstream_send_tagstruct(s->context->pstream, t); pa_pstream_send_tagstruct(s->context->pstream, t);
pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); 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);
}

View file

@ -32,6 +32,9 @@ int pa_context_errno(struct pa_context *c);
int pa_context_is_pending(struct pa_context *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;
struct pa_stream* pa_stream_new( struct pa_stream* pa_stream_new(

View file

@ -18,6 +18,7 @@ enum {
PA_COMMAND_DRAIN_PLAYBACK_STREAM, PA_COMMAND_DRAIN_PLAYBACK_STREAM,
PA_COMMAND_PLAYBACK_STREAM_KILLED, PA_COMMAND_PLAYBACK_STREAM_KILLED,
PA_COMMAND_RECORD_STREAM_KILLED, PA_COMMAND_RECORD_STREAM_KILLED,
PA_COMMAND_STAT,
PA_COMMAND_MAX PA_COMMAND_MAX
}; };

View file

@ -75,6 +75,7 @@ static void command_delete_record_stream(struct pa_pdispatch *pd, uint32_t comma
static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); 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_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_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] = { static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
[PA_COMMAND_ERROR] = { NULL }, [PA_COMMAND_ERROR] = { NULL },
@ -91,6 +92,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
[PA_COMMAND_SET_NAME] = { command_set_name }, [PA_COMMAND_SET_NAME] = { command_set_name },
[PA_COMMAND_LOOKUP_SINK] = { command_lookup }, [PA_COMMAND_LOOKUP_SINK] = { command_lookup },
[PA_COMMAND_LOOKUP_SOURCE] = { command_lookup }, [PA_COMMAND_LOOKUP_SOURCE] = { command_lookup },
[PA_COMMAND_STAT] = { command_stat },
}; };
/* structure management */ /* structure management */
@ -638,6 +640,30 @@ static void command_drain_playback_stream(struct pa_pdispatch *pd, uint32_t comm
} }
} }
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 ***/ /*** pstream callbacks ***/
static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {

View file

@ -1,12 +1,11 @@
- clean secure directory handling (with username) - pactl
- native library/protocol: - native library/protocol:
more functions (esp. latency) more functions (esp. latency)
- prefix modules/libraries with pa_
- xmms+esound latency testing - xmms+esound latency testing
- prefix modules/libraries with pa_
- rename files - rename files
- svn-id and license in every file - svn-id and license in every file
- documentation - documentation
@ -21,6 +20,8 @@
- make mcalign merge chunks - make mcalign merge chunks
- modinfo - modinfo
- move the global memblock statistics variables to the core - move the global memblock statistics variables to the core
- unix socket directories include user name
drivers: drivers:
- libao - libao