]> code.delx.au - pulseaudio/commitdiff
add pactl tool
authorLennart Poettering <lennart@poettering.net>
Thu, 15 Jul 2004 20:51:55 +0000 (20:51 +0000)
committerLennart Poettering <lennart@poettering.net>
Thu, 15 Jul 2004 20:51:55 +0000 (20:51 +0000)
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@71 fefdeb5f-60dc-0310-8127-8f9354f1896f

src/Makefile.am
src/pacat.c
src/pactl.c [new file with mode: 0644]
src/polyp.c
src/polyp.h
src/protocol-native-spec.h
src/protocol-native.c
src/todo

index c973af52f374e3f1bfb48706f913063a9317e855..7aa0721520c7a866a4eb93bdbb1069b4930a1c5e 100644 (file)
@@ -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)
index 80d4835fb5e3bdf2fce23704843ec2a48c4d955f..c9257d03054c737cbe17d7b2bf2ff65b00c23cc0 100644 (file)
@@ -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);
 
-    pa_signal_done();
-    if (m)
+    if (m) {
+        pa_signal_done();
         pa_mainloop_free(m);
+    }
+    
     if (buffer)
         free(buffer);
     
diff --git a/src/pactl.c b/src/pactl.c
new file mode 100644 (file)
index 0000000..688e110
--- /dev/null
@@ -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;
+}
index 75187d793c8540efc3dddebc92a9f6cfb1092385..bc6bff5aec47302d39ffa04839e72caf91129c2a 100644 (file)
@@ -53,6 +53,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);
+}
index c49a72b2ca496025628951bee360519240257578..5b7303022c3dff4682a9710d232c47077111cb57 100644 (file)
@@ -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(
index 78dc06c24f55400eb9c3e150b69bc752d9494094..0a60fd80f96858aa20732d262bcb00a24eb1f431 100644 (file)
@@ -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
 };
 
index abd170263f48852dfa9e581568e0a45e11e6ca15..56395e9807a48b1026ae46cd1637f7f6e968811a 100644 (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_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) {
index 5eb4329d29d8f4ae6fa0daac3d8520665ea3a2ab..107fa787e97b42cf7af562c0922852f57f4ce008 100644 (file)
--- a/src/todo
+++ b/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