mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
add pactl tool
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@71 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
c36dadd2bd
commit
d8f1300661
8 changed files with 246 additions and 7 deletions
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
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 \
|
||||
|
|
@ -246,6 +246,10 @@ pacat_SOURCES = pacat.c #$(libpolyp_la_SOURCES) $(libpolyp_error_la_SOURCES)
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ static void exit_signal_callback(void *id, int sig, void *userdata) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct pa_mainloop* m;
|
||||
struct pa_mainloop* m = NULL;
|
||||
int ret = 1, r;
|
||||
char *bn;
|
||||
|
||||
|
|
@ -279,9 +279,11 @@ quit:
|
|||
if (context)
|
||||
pa_context_free(context);
|
||||
|
||||
if (m) {
|
||||
pa_signal_done();
|
||||
if (m)
|
||||
pa_mainloop_free(m);
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
|
||||
|
|
|
|||
141
src/pactl.c
Normal file
141
src/pactl.c
Normal 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;
|
||||
}
|
||||
61
src/polyp.c
61
src/polyp.c
|
|
@ -54,6 +54,9 @@ struct pa_context {
|
|||
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];
|
||||
};
|
||||
|
||||
|
|
@ -133,6 +136,9 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *
|
|||
c->die_callback = NULL;
|
||||
c->die_userdata = NULL;
|
||||
|
||||
c->stat_callback = NULL;
|
||||
c->stat_userdata = NULL;
|
||||
|
||||
pa_check_for_sigpipe();
|
||||
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_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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ int pa_context_errno(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* pa_stream_new(
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ enum {
|
|||
PA_COMMAND_DRAIN_PLAYBACK_STREAM,
|
||||
PA_COMMAND_PLAYBACK_STREAM_KILLED,
|
||||
PA_COMMAND_RECORD_STREAM_KILLED,
|
||||
PA_COMMAND_STAT,
|
||||
PA_COMMAND_MAX
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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_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 },
|
||||
|
|
@ -91,6 +92,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
|
|||
[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 */
|
||||
|
|
@ -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 ***/
|
||||
|
||||
static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
|
||||
|
|
|
|||
7
src/todo
7
src/todo
|
|
@ -1,12 +1,11 @@
|
|||
- 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
|
||||
|
|
@ -21,6 +20,8 @@
|
|||
- make mcalign merge chunks
|
||||
- modinfo
|
||||
- move the global memblock statistics variables to the core
|
||||
- unix socket directories include user name
|
||||
|
||||
|
||||
drivers:
|
||||
- libao
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue