From b118982674effa44aa1687e8bd0d2bc0eb6254b2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 19 Sep 2004 23:12:41 +0000 Subject: remove obnoxious assert from module-combine tagstruct: add support for NULL strings improve pactl correct pa_bytes_snprint() pa_sample_spec_snprint(): don't fail on invalid sample spec rename PA_SAMPLE_SNPRINT_MAX_LENGTH to PA_SAMPLE_SPEC_SNPRINT_MAX git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@222 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/cli-command.c | 2 + polyp/cli-text.c | 10 +- polyp/cmdline.c | 2 +- polyp/module-combine.c | 2 +- polyp/pacat.c | 4 +- polyp/pactl.c | 545 +++++++++++++++++++++++++++++++++++++++----- polyp/pdispatch.c | 6 +- polyp/polyplib-introspect.c | 8 +- polyp/polyplib-scache.c | 2 +- polyp/polyplib-stream.c | 5 +- polyp/protocol-native.c | 66 +++--- polyp/sample.c | 20 +- polyp/sample.h | 4 +- polyp/tagstruct.c | 28 ++- 14 files changed, 579 insertions(+), 125 deletions(-) (limited to 'polyp') diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 750d67ea..39ea9cc1 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -236,6 +236,8 @@ static int pa_cli_command_stat(struct pa_core *c, struct pa_tokenizer *t, struct "Default source name: %s\n", pa_namereg_get_default_sink_name(c), pa_namereg_get_default_source_name(c)); + + return 0; } diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 9932e568..3cedf920 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -88,7 +88,7 @@ char *pa_sink_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_ncontents(c->sinks)); for (sink = pa_idxset_first(c->sinks, &index); sink; sink = pa_idxset_next(c->sinks, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec); assert(sink->monitor_source); pa_strbuf_printf( @@ -123,7 +123,7 @@ char *pa_source_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_ncontents(c->sources)); for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec); pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', @@ -156,7 +156,7 @@ char *pa_source_output_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_ncontents(c->source_outputs)); for (o = pa_idxset_first(c->source_outputs, &index); o; o = pa_idxset_next(c->source_outputs, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec); assert(o->source); pa_strbuf_printf( @@ -186,7 +186,7 @@ char *pa_sink_input_list_to_string(struct pa_core *c) { pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_ncontents(c->sink_inputs)); for (i = pa_idxset_first(c->sink_inputs, &index); i; i = pa_idxset_next(c->sink_inputs, &index)) { - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH]; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec); assert(i->sink); pa_strbuf_printf( @@ -223,7 +223,7 @@ char *pa_scache_list_to_string(struct pa_core *c) { for (e = pa_idxset_first(c->scache, &index); e; e = pa_idxset_next(c->scache, &index)) { double l = 0; - char ss[PA_SAMPLE_SNPRINT_MAX_LENGTH] = "n/a"; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a"; if (e->memchunk.memblock) { pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); diff --git a/polyp/cmdline.c b/polyp/cmdline.c index 82ac6183..c32d9a0f 100644 --- a/polyp/cmdline.c +++ b/polyp/cmdline.c @@ -84,7 +84,7 @@ void pa_cmdline_help(const char *argv0) { else e = argv0; - printf("%s [options]\n" + printf("%s [options]\n\n" " -h, --help Show this help\n" " --version Show version\n" " --dump-conf Dump default configuration\n" diff --git a/polyp/module-combine.c b/polyp/module-combine.c index f6d596bc..1bb183ec 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -106,7 +106,7 @@ static void adjust_rates(struct userdata *u) { min_total_latency = o->total_latency; } - assert(max_sink_latency > 0 && min_total_latency != (pa_usec_t) -1); + assert(min_total_latency != (pa_usec_t) -1); target_latency = max_sink_latency > min_total_latency ? max_sink_latency : min_total_latency; diff --git a/polyp/pacat.c b/polyp/pacat.c index a0db7594..b9cb047a 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -320,7 +320,7 @@ static void sigusr1_signal_callback(struct pa_mainloop_api*m, struct pa_signal_e static void help(const char *argv0) { - printf("%s [options]\n" + printf("%s [options]\n\n" " -h, --help Show this help\n" " --version Show version\n\n" " -r, --record Create a connection for recording\n" @@ -378,7 +378,7 @@ int main(int argc, char *argv[]) { goto quit; case ARG_VERSION: - printf("pacat "PACKAGE_VERSION"\n"); + printf("pacat "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); ret = 0; goto quit; diff --git a/polyp/pactl.c b/polyp/pactl.c index c93fd235..2a466b39 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -45,14 +46,16 @@ static struct pa_context *context = NULL; static struct pa_mainloop_api *mainloop_api = NULL; -static char **process_argv = NULL; +static char *device = NULL, *sample_name = NULL; static SNDFILE *sndfile = NULL; static struct pa_stream *sample_stream = NULL; static struct pa_sample_spec sample_spec; static size_t sample_length = 0; -static char *sample_name = NULL; +static int actions = 1; + +static int nl = 0; static enum { NONE, @@ -60,7 +63,8 @@ static enum { STAT, UPLOAD_SAMPLE, PLAY_SAMPLE, - REMOVE_SAMPLE + REMOVE_SAMPLE, + LIST } action = NONE; static void quit(int ret) { @@ -81,37 +85,373 @@ static void drain(void) { pa_operation_unref(o); } + +static void complete_action(void) { + assert(actions > 0); + + if (!(--actions)) + drain(); +} + static void stat_callback(struct pa_context *c, const struct pa_stat_info *i, void *userdata) { + char s[128]; if (!i) { fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c))); quit(1); return; } + + pa_bytes_snprint(s, sizeof(s), i->memblock_total_size); + printf("Currently in use: %u blocks containing %s bytes total.\n", i->memblock_total, s); + + pa_bytes_snprint(s, sizeof(s), i->memblock_allocated_size); + printf("Allocated during whole lifetime: %u blocks containing %s bytes total.\n", i->memblock_allocated, s); + + pa_bytes_snprint(s, sizeof(s), i->scache_size); + printf("Sample cache size: %s\n", s); - fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n" - "Allocated during whole lifetime: %u blocks containing %u bytes total.\n", - i->memblock_total, i->memblock_total_size, i->memblock_allocated, i->memblock_allocated_size); - drain(); + complete_action(); } -static void play_sample_callback(struct pa_context *c, int success, void *userdata) { - if (!success) { - fprintf(stderr, "Failed to play sample: %s\n", pa_strerror(pa_context_errno(c))); +static void get_server_info_callback(struct pa_context *c, const struct pa_server_info *i, void *useerdata) { + char s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (!i) { + fprintf(stderr, "Failed to get server information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + + printf("User name: %s\n" + "Host Name: %s\n" + "Server Name: %s\n" + "Server Version: %s\n" + "Default Sample Specification: %s\n" + "Default Sink: %s\n" + "Default Source: %s\n", + i->user_name, + i->host_name, + i->server_name, + i->server_version, + s, + i->default_sink_name, + i->default_source_name); + + complete_action(); +} + +static void get_sink_info_callback(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata) { + char s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + + printf("*** Sink #%u ***\n" + "Name: %s\n" + "Description: %s\n" + "Sample Specification: %s\n" + "Owner Module: %u\n" + "Volume: 0x%03x (%0.2f dB)\n" + "Monitor Source: %u\n" + "Latency: %0.0f usec\n", + i->index, + i->name, + i->description, + s, + i->owner_module, + i->volume, pa_volume_to_dB(i->volume), + i->monitor_source, + (double) i->latency); +} + +static void get_source_info_callback(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata) { + char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get source information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + snprintf(t, sizeof(t), "%u", i->monitor_of_sink); + + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + + printf("*** Source #%u ***\n" + "Name: %s\n" + "Description: %s\n" + "Sample Specification: %s\n" + "Owner Module: %u\n" + "Monitor of Sink: %s\n" + "Latency: %0.0f usec\n", + i->index, + i->name, + i->description, + s, + i->owner_module, + i->monitor_of_sink != PA_INVALID_INDEX ? t : "no", + (double) i->latency); +} + +static void get_module_info_callback(struct pa_context *c, const struct pa_module_info *i, int is_last, void *userdata) { + char t[32]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get module information: %s\n", pa_strerror(pa_context_errno(c))); quit(1); return; } - drain(); + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + snprintf(t, sizeof(t), "%u", i->n_used); + + printf("*** Module #%u ***\n" + "Name: %s\n" + "Argument: %s\n" + "Usage counter: %s\n" + "Auto unload: %s\n", + i->index, + i->name, + i->argument, + i->n_used != PA_INVALID_INDEX ? t : "n/a", + i->auto_unload ? "yes" : "no"); +} + +static void get_client_info_callback(struct pa_context *c, const struct pa_client_info *i, int is_last, void *userdata) { + char t[32]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get client information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + snprintf(t, sizeof(t), "%u", i->owner_module); + + printf("*** Client #%u ***\n" + "Name: %s\n" + "Owner Module: %s\n" + "Protocol Name: %s\n", + i->index, + i->name, + i->owner_module != PA_INVALID_INDEX ? t : "n/a", + i->protocol_name); } -static void remove_sample_callback(struct pa_context *c, int success, void *userdata) { +static void get_sink_input_info_callback(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) { + char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get sink input information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + snprintf(t, sizeof(t), "%u", i->owner_module); + snprintf(k, sizeof(k), "%u", i->client); + + printf("*** Sink Input #%u ***\n" + "Name: %s\n" + "Owner Module: %s\n" + "Client: %s\n" + "Sink: %u\n" + "Sample Specification: %s\n" + "Volume: 0x%03x (%0.2f dB)\n" + "Buffer Latency: %0.0f usec\n" + "Sink Latency: %0.0f usec\n", + i->index, + i->name, + i->owner_module != PA_INVALID_INDEX ? t : "n/a", + i->client != PA_INVALID_INDEX ? k : "n/a", + i->sink, + s, + i->volume, pa_volume_to_dB(i->volume), + (double) i->buffer_usec, + (double) i->sink_usec); +} + +static void get_source_output_info_callback(struct pa_context *c, const struct pa_source_output_info *i, int is_last, void *userdata) { + char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get source output information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + snprintf(t, sizeof(t), "%u", i->owner_module); + snprintf(k, sizeof(k), "%u", i->client); + + printf("*** Source Output #%u ***\n" + "Name: %s\n" + "Owner Module: %s\n" + "Client: %s\n" + "Source: %u\n" + "Sample Specification: %s\n" + "Buffer Latency: %0.0f usec\n" + "Source Latency: %0.0f usec\n", + i->index, + i->name, + i->owner_module != PA_INVALID_INDEX ? t : "n/a", + i->client != PA_INVALID_INDEX ? k : "n/a", + i->source, + s, + (double) i->buffer_usec, + (double) i->source_usec); +} + +static void get_sample_info_callback(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata) { + char t[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + + if (is_last < 0) { + fprintf(stderr, "Failed to get sample information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + pa_bytes_snprint(t, sizeof(t), i->bytes); + + printf("*** Sample #%u ***\n" + "Name: %s\n" + "Volume: 0x%03x (%0.2f dB)\n" + "Sample Specification: %s\n" + "Duration: %0.1fs\n" + "Size: %s\n" + "Lazy: %s\n" + "Filename: %s\n", + i->index, + i->name, + i->volume, pa_volume_to_dB(i->volume), + pa_sample_spec_valid(&i->sample_spec) ? s : "n/a", + (double) i->duration/1000000, + t, + i->lazy ? "yes" : "no", + i->filename ? i->filename : "n/a"); +} + +static void get_autoload_info_callback(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata) { + if (is_last < 0) { + fprintf(stderr, "Failed to get autoload information: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); + return; + } + + if (is_last) { + complete_action(); + return; + } + + assert(i); + + if (nl) + printf("\n"); + nl = 1; + + printf("*** Autoload Entry ***\n" + "Name: %s\n" + "Type: %s\n" + "Module: %s\n" + "Argument: %s\n", + i->name, + i->type == PA_AUTOLOAD_SINK ? "sink" : "source", + i->module, + i->argument); +} + +static void simple_callback(struct pa_context *c, int success, void *userdata) { if (!success) { - fprintf(stderr, "Failed to remove sample: %s\n", pa_strerror(pa_context_errno(c))); + fprintf(stderr, "Failure: %s\n", pa_strerror(pa_context_errno(c))); quit(1); return; } - drain(); + complete_action(); } static void stream_state_callback(struct pa_stream *s, void *userdata) { @@ -169,24 +509,48 @@ static void context_state_callback(struct pa_context *c, void *userdata) { break; case PA_CONTEXT_READY: - if (action == STAT) - pa_operation_unref(pa_context_stat(c, stat_callback, NULL)); - else if (action == PLAY_SAMPLE) - pa_operation_unref(pa_context_play_sample(c, process_argv[2], NULL, 0x100, play_sample_callback, NULL)); - else if (action == REMOVE_SAMPLE) - pa_operation_unref(pa_context_remove_sample(c, process_argv[2], remove_sample_callback, NULL)); - else if (action == UPLOAD_SAMPLE) { - - sample_stream = pa_stream_new(c, sample_name, &sample_spec); - assert(sample_stream); - - pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL); - pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL); - pa_stream_connect_upload(sample_stream, sample_length); - } else { - assert(action == EXIT); - pa_context_exit_daemon(c); - drain(); + switch (action) { + case STAT: + actions = 2; + pa_operation_unref(pa_context_stat(c, stat_callback, NULL)); + pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL)); + break; + + case PLAY_SAMPLE: + pa_operation_unref(pa_context_play_sample(c, sample_name, device, PA_VOLUME_NORM, simple_callback, NULL)); + break; + + case REMOVE_SAMPLE: + pa_operation_unref(pa_context_remove_sample(c, sample_name, simple_callback, NULL)); + break; + + case UPLOAD_SAMPLE: + sample_stream = pa_stream_new(c, sample_name, &sample_spec); + assert(sample_stream); + + pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL); + pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL); + pa_stream_connect_upload(sample_stream, sample_length); + break; + + case EXIT: + pa_context_exit_daemon(c); + drain(); + + case LIST: + actions = 8; + pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL)); + pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL)); + pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL)); + pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL)); + pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL)); + pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL)); + pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL)); + pa_operation_unref(pa_context_get_autoload_info_list(c, get_autoload_info_callback, NULL)); + break; + + default: + assert(0); } break; @@ -206,43 +570,106 @@ static void exit_signal_callback(struct pa_mainloop_api *m, struct pa_signal_eve quit(0); } +static void help(const char *argv0) { + + printf("%s [options] stat\n" + "%s [options] list\n" + "%s [options] exit\n" + "%s [options] upload-sample FILENAME [NAME]\n" + "%s [options] play-sample NAME [SINK]\n" + "%s [options] remove-sample NAME\n\n" + " -h, --help Show this help\n" + " --version Show version\n\n" + " -s, --server=SERVER The name of the server to connect to\n" + " -n, --client-name=NAME How to call this client on the server\n", + argv0, argv0, argv0, argv0, argv0, argv0); +} + +enum { ARG_VERSION = 256 }; + int main(int argc, char *argv[]) { struct pa_mainloop* m = NULL; char tmp[PATH_MAX]; + int ret = 1, r, c; + char *server = NULL, *client_name = NULL, *bn; + + static const struct option long_options[] = { + {"server", 1, NULL, 's'}, + {"client-name", 1, NULL, 'n'}, + {"version", 0, NULL, ARG_VERSION}, + {"help", 0, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + if (!(bn = strrchr(argv[0], '/'))) + bn = argv[0]; + else + bn++; - int ret = 1, r; + while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) { + switch (c) { + case 'h' : + help(bn); + ret = 0; + goto quit; + + case ARG_VERSION: + printf("pactl "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version()); + ret = 0; + goto quit; + + case 's': + free(server); + server = strdup(optarg); + break; + + case 'n': + free(client_name); + client_name = strdup(optarg); + break; + + default: + goto quit; + } + } - if (argc >= 2) { - if (!strcmp(argv[1], "stat")) + if (!client_name) + client_name = strdup(bn); + + if (optind < argc) { + if (!strcmp(argv[optind], "stat")) action = STAT; - else if (!strcmp(argv[1], "exit")) + else if (!strcmp(argv[optind], "exit")) action = EXIT; - else if (!strcmp(argv[1], "scache_upload")) { + else if (!strcmp(argv[optind], "list")) + action = LIST; + else if (!strcmp(argv[optind], "upload-sample")) { struct SF_INFO sfinfo; action = UPLOAD_SAMPLE; - if (argc < 3) { + if (optind+1 >= argc) { fprintf(stderr, "Please specify a sample file to load\n"); goto quit; } - if (argc >= 4) - sample_name = argv[3]; + if (optind+2 < argc) + sample_name = strdup(argv[optind+2]); else { - char *f = strrchr(argv[2], '/'); + char *f = strrchr(argv[optind+1], '/'); size_t n; if (f) f++; else - f = argv[2]; + f = argv[optind]; n = strcspn(f, "."); - strncpy(sample_name = tmp, f, n); - tmp[n] = 0; + strncpy(tmp, f, n); + tmp[n] = 0; + sample_name = strdup(tmp); } memset(&sfinfo, 0, sizeof(sfinfo)); - if (!(sndfile = sf_open(argv[2], SFM_READ, &sfinfo))) { + if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfinfo))) { fprintf(stderr, "Failed to open sound file.\n"); goto quit; } @@ -252,28 +679,34 @@ int main(int argc, char *argv[]) { sample_spec.channels = sfinfo.channels; sample_length = sfinfo.frames*pa_frame_size(&sample_spec); - } else if (!strcmp(argv[1], "scache_play")) { + } else if (!strcmp(argv[optind], "play-sample")) { action = PLAY_SAMPLE; - if (argc < 3) { + if (optind+1 >= argc) { fprintf(stderr, "You have to specify a sample name to play\n"); goto quit; } - } else if (!strcmp(argv[1], "scache_remove")) { + + sample_name = strdup(argv[optind+1]); + + if (optind+2 < argc) + device = strdup(argv[optind+2]); + + } else if (!strcmp(argv[optind], "remove-sample")) { action = REMOVE_SAMPLE; - if (argc < 3) { + if (optind+1 >= argc) { fprintf(stderr, "You have to specify a sample name to remove\n"); goto quit; } + + sample_name = strdup(argv[optind+1]); } } if (action == NONE) { - fprintf(stderr, "No valid action specified. Use one of: stat, exit, scache_upload, scache_play, scache_remove\n"); + fprintf(stderr, "No valid command specified.\n"); goto quit; } - process_argv = argv; - if (!(m = pa_mainloop_new())) { fprintf(stderr, "pa_mainloop_new() failed.\n"); goto quit; @@ -286,13 +719,13 @@ int main(int argc, char *argv[]) { pa_signal_new(SIGINT, exit_signal_callback, NULL); signal(SIGPIPE, SIG_IGN); - if (!(context = pa_context_new(mainloop_api, argv[0]))) { + if (!(context = pa_context_new(mainloop_api, client_name))) { fprintf(stderr, "pa_context_new() failed.\n"); goto quit; } pa_context_set_state_callback(context, context_state_callback, NULL); - pa_context_connect(context, NULL, 1, NULL); + pa_context_connect(context, server, 1, NULL); if (pa_mainloop_run(m, &ret) < 0) { fprintf(stderr, "pa_mainloop_run() failed.\n"); @@ -314,5 +747,9 @@ quit: if (sndfile) sf_close(sndfile); + free(server); + free(device); + free(sample_name); + return ret; } diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c index 88f85e02..f6481fa0 100644 --- a/polyp/pdispatch.c +++ b/polyp/pdispatch.c @@ -33,7 +33,7 @@ #include "llist.h" #include "log.h" -/*#define DEBUG_OPCODES*/ +/* #define DEBUG_OPCODES */ #ifdef DEBUG_OPCODES @@ -48,7 +48,7 @@ static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_AUTH] = "AUTH", [PA_COMMAND_REQUEST] = "REQUEST", [PA_COMMAND_EXIT] = "EXIT", - [PA_COMMAND_SET_NAME] = "SET_NAME", + [PA_COMMAND_SET_CLIENT_NAME] = "SET_CLIENT_NAME", [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK", [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE", [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM", @@ -83,6 +83,8 @@ static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = "TRIGGER_PLAYBACK_STREAM", [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = "FLUSH_PLAYBACK_STREAM", [PA_COMMAND_CORK_PLAYBACK_STREAM] = "CORK_PLAYBACK_STREAM", + [PA_COMMAND_GET_AUTOLOAD_INFO] = "GET_AUTOLOAD_INFO", + [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = "GET_AUTOLOAD_INFO_LIST", }; #endif diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 1673be9b..267af95b 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -170,7 +170,7 @@ struct pa_operation* pa_context_get_sink_info_by_index(struct pa_context *c, uin pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); + pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); @@ -263,7 +263,7 @@ struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, u pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); + pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); @@ -581,7 +581,7 @@ struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, u pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); + pa_tagstruct_puts(t, NULL); pa_tagstruct_putu32(t, volume); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); @@ -713,7 +713,7 @@ struct pa_operation* pa_context_get_sample_info_by_index(struct pa_context *c, u pa_tagstruct_putu32(t, PA_COMMAND_GET_SAMPLE_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); + pa_tagstruct_puts(t, NULL); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, o); diff --git a/polyp/polyplib-scache.c b/polyp/polyplib-scache.c index 7221420c..45220d10 100644 --- a/polyp/polyplib-scache.c +++ b/polyp/polyplib-scache.c @@ -95,7 +95,7 @@ struct pa_operation * pa_context_play_sample(struct pa_context *c, const char *n pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_puts(t, dev); pa_tagstruct_putu32(t, volume); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 6055a220..8bd098d4 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -194,7 +194,7 @@ void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32 if (pa_tagstruct_getu32(t, &s->channel) < 0 || ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - ((s->direction == PA_STREAM_PLAYBACK) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0) || + ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0) || !pa_tagstruct_eof(t)) { pa_context_fail(s->context, PA_ERROR_PROTOCOL); goto finish; @@ -245,7 +245,7 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_ pa_tagstruct_puts(t, s->name); pa_tagstruct_put_sample_spec(t, &s->sample_spec); pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, dev ? dev : ""); + pa_tagstruct_puts(t, dev); pa_tagstruct_putu32(t, s->buffer_attr.maxlength); if (s->direction == PA_STREAM_PLAYBACK) { pa_tagstruct_putu32(t, s->buffer_attr.tlength); @@ -536,7 +536,6 @@ struct pa_operation* pa_stream_send_simple_command(struct pa_stream *s, uint32_t return pa_operation_ref(o); } - struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { return pa_stream_send_simple_command(s, PA_COMMAND_FLUSH_PLAYBACK_STREAM, cb, userdata); } diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 021c1a60..4c1e9696 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -540,7 +540,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com pa_volume_t volume; assert(c && t && c->protocol && c->protocol->core); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_getu32(t, &sink_index) < 0 || pa_tagstruct_gets(t, &sink_name) < 0 || @@ -554,6 +554,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com return; } + if (!c->authorized) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); return; @@ -562,7 +563,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com if (sink_index != (uint32_t) -1) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); else - sink = pa_namereg_get(c->protocol->core, *sink_name ? sink_name : NULL, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); if (!sink) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); @@ -643,7 +644,7 @@ static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t comma struct pa_source *source; assert(c && t && c->protocol && c->protocol->core); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_getu32(t, &source_index) < 0 || pa_tagstruct_gets(t, &source_name) < 0 || @@ -662,7 +663,7 @@ static void command_create_record_stream(struct pa_pdispatch *pd, uint32_t comma if (source_index != (uint32_t) -1) source = pa_idxset_get_by_index(c->protocol->core->sources, source_index); else - source = pa_namereg_get(c->protocol->core, *source_name ? source_name : NULL, PA_NAMEREG_SOURCE, 1); + source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE, 1); if (!source) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); @@ -734,7 +735,7 @@ static void command_set_client_name(struct pa_pdispatch *pd, uint32_t command, u const char *name; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -751,7 +752,7 @@ static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t t uint32_t index = PA_IDXSET_INVALID; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -939,7 +940,7 @@ static void command_create_upload_stream(struct pa_pdispatch *pd, uint32_t comma struct pa_tagstruct *reply; assert(c && t && c->protocol && c->protocol->core); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_getu32(t, &length) < 0 || !pa_tagstruct_eof(t)) { @@ -967,13 +968,6 @@ static void command_create_upload_stream(struct pa_pdispatch *pd, uint32_t comma pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); pa_tagstruct_putu32(reply, tag); pa_tagstruct_putu32(reply, s->index); - pa_pstream_send_tagstruct(c->pstream, reply); - - reply = pa_tagstruct_new(NULL, 0); - assert(reply); - pa_tagstruct_putu32(reply, PA_COMMAND_REQUEST); - pa_tagstruct_putu32(reply, (uint32_t) -1); /* tag */ - pa_tagstruct_putu32(reply, s->index); pa_tagstruct_putu32(reply, length); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1016,7 +1010,7 @@ static void command_play_sample(struct pa_pdispatch *pd, uint32_t command, uint3 if (pa_tagstruct_getu32(t, &sink_index) < 0 || pa_tagstruct_gets(t, &sink_name) < 0 || pa_tagstruct_getu32(t, &volume) < 0 || - pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &name) < 0 || !name || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1030,7 +1024,7 @@ static void command_play_sample(struct pa_pdispatch *pd, uint32_t command, uint3 if (sink_index != (uint32_t) -1) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); else - sink = pa_namereg_get(c->protocol->core, *sink_name ? sink_name : NULL, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); if (!sink) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); @@ -1050,7 +1044,7 @@ static void command_remove_sample(struct pa_pdispatch *pd, uint32_t command, uin const char *name; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1073,7 +1067,7 @@ static void sink_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink *sink) { assert(t && sink); pa_tagstruct_putu32(t, sink->index); pa_tagstruct_puts(t, sink->name); - pa_tagstruct_puts(t, sink->description ? sink->description : ""); + pa_tagstruct_puts(t, sink->description); pa_tagstruct_put_sample_spec(t, &sink->sample_spec); pa_tagstruct_putu32(t, sink->owner ? sink->owner->index : (uint32_t) -1); pa_tagstruct_putu32(t, sink->volume); @@ -1086,11 +1080,11 @@ static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *sour assert(t && source); pa_tagstruct_putu32(t, source->index); pa_tagstruct_puts(t, source->name); - pa_tagstruct_puts(t, source->description ? source->description : ""); + pa_tagstruct_puts(t, source->description); pa_tagstruct_put_sample_spec(t, &source->sample_spec); pa_tagstruct_putu32(t, source->owner ? source->owner->index : (uint32_t) -1); pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->index : (uint32_t) -1); - pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : ""); + pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : NULL); pa_tagstruct_put_usec(t, pa_source_get_latency(source)); } @@ -1106,7 +1100,7 @@ static void module_fill_tagstruct(struct pa_tagstruct *t, struct pa_module *modu assert(t && module); pa_tagstruct_putu32(t, module->index); pa_tagstruct_puts(t, module->name); - pa_tagstruct_puts(t, module->argument ? module->argument : ""); + pa_tagstruct_puts(t, module->argument); pa_tagstruct_putu32(t, module->n_used); pa_tagstruct_put_boolean(t, module->auto_unload); } @@ -1114,7 +1108,7 @@ static void module_fill_tagstruct(struct pa_tagstruct *t, struct pa_module *modu static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_input *s) { assert(t && s); pa_tagstruct_putu32(t, s->index); - pa_tagstruct_puts(t, s->name ? s->name : ""); + pa_tagstruct_puts(t, s->name); pa_tagstruct_putu32(t, s->owner ? s->owner->index : (uint32_t) -1); pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); pa_tagstruct_putu32(t, s->sink->index); @@ -1127,7 +1121,7 @@ static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_inp static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_source_output *s) { assert(t && s); pa_tagstruct_putu32(t, s->index); - pa_tagstruct_puts(t, s->name ? s->name : ""); + pa_tagstruct_puts(t, s->name); pa_tagstruct_putu32(t, s->owner ? s->owner->index : (uint32_t) -1); pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); pa_tagstruct_putu32(t, s->source->index); @@ -1183,12 +1177,12 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t if (index != (uint32_t) -1) sink = pa_idxset_get_by_index(c->protocol->core->sinks, index); else - sink = pa_namereg_get(c->protocol->core, *name ? name : NULL, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); } else if (command == PA_COMMAND_GET_SOURCE_INFO) { if (index != (uint32_t) -1) source = pa_idxset_get_by_index(c->protocol->core->sources, index); else - source = pa_namereg_get(c->protocol->core, *name ? name : NULL, PA_NAMEREG_SOURCE, 1); + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); } else if (command == PA_COMMAND_GET_CLIENT_INFO) client = pa_idxset_get_by_index(c->protocol->core->clients, index); else if (command == PA_COMMAND_GET_MODULE_INFO) @@ -1198,7 +1192,7 @@ static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO) so = pa_idxset_get_by_index(c->protocol->core->source_outputs, index); else { - assert(command == PA_COMMAND_GET_SAMPLE_INFO && name); + assert(command == PA_COMMAND_GET_SAMPLE_INFO); if (index != (uint32_t) -1) sce = pa_idxset_get_by_index(c->protocol->core->scache, index); else @@ -1323,9 +1317,9 @@ static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, u pa_tagstruct_put_sample_spec(reply, &c->protocol->core->default_sample_spec); n = pa_namereg_get_default_sink_name(c->protocol->core); - pa_tagstruct_puts(reply, n ? n : ""); + pa_tagstruct_puts(reply, n); n = pa_namereg_get_default_source_name(c->protocol->core); - pa_tagstruct_puts(reply, n ? n : ""); + pa_tagstruct_puts(reply, n); pa_pstream_send_tagstruct(c->pstream, reply); } @@ -1396,7 +1390,7 @@ static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32 if (index != (uint32_t) -1) sink = pa_idxset_get_by_index(c->protocol->core->sinks, index); else - sink = pa_namereg_get(c->protocol->core, *name ? name : NULL, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); } else { assert(command == PA_COMMAND_SET_SINK_INPUT_VOLUME); si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, index); @@ -1485,7 +1479,7 @@ static void command_set_default_sink_or_source(struct pa_pdispatch *pd, uint32_t assert(c && t); if (pa_tagstruct_getu32(t, &index) < 0 || - pa_tagstruct_gets(t, &s) < 0 || + pa_tagstruct_gets(t, &s) < 0 || !s || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1507,7 +1501,7 @@ static void command_set_stream_name(struct pa_pdispatch *pd, uint32_t command, u assert(c && t); if (pa_tagstruct_getu32(t, &index) < 0 || - pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &name) < 0 || !name || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1599,7 +1593,7 @@ static void command_load_module(struct pa_pdispatch *pd, uint32_t command, uint3 struct pa_tagstruct *reply; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_gets(t, &argument) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1655,9 +1649,9 @@ static void command_add_autoload(struct pa_pdispatch *pd, uint32_t command, uint uint32_t type; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_getu32(t, &type) < 0 || type > 1 || - pa_tagstruct_gets(t, &module) < 0 || + pa_tagstruct_gets(t, &module) < 0 || !module || pa_tagstruct_gets(t, &argument) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1683,7 +1677,7 @@ static void command_remove_autoload(struct pa_pdispatch *pd, uint32_t command, u uint32_t type; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_getu32(t, &type) < 0 || type > 1 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1719,7 +1713,7 @@ static void command_get_autoload_info(struct pa_pdispatch *pd, uint32_t command, struct pa_tagstruct *reply; assert(c && t); - if (pa_tagstruct_gets(t, &name) < 0 || + if (pa_tagstruct_gets(t, &name) < 0 || name || pa_tagstruct_getu32(t, &type) < 0 || type > 1 || !pa_tagstruct_eof(t)) { protocol_error(c); diff --git a/polyp/sample.c b/polyp/sample.c index 397e57a2..143e1e41 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -94,7 +94,11 @@ void pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec [PA_SAMPLE_FLOAT32BE] = "FLOAT32BE", }; - assert(pa_sample_spec_valid(spec)); + if (!pa_sample_spec_valid(spec)) { + snprintf(s, l, "Invalid"); + return; + } + snprintf(s, l, "%s %uch %uHz", table[spec->format], spec->channels, spec->rate); } @@ -120,13 +124,13 @@ double pa_volume_to_dB(pa_volume_t v) { return 20*log10((double) v/PA_VOLUME_NORM); } -void pa_bytes_snprint(char *s, size_t l, off_t v) { - if (v >= (off_t) 1024*1024*1024) - snprintf(s, l, "%0.1f GB", (double) v/1024/1024/1024); - else if (v >= (off_t) 1024*1024) - snprintf(s, l, "%0.1f MB", (double) v/1024/1024); - else if (v >= (off_t) 1024) - snprintf(s, l, "%0.1f KB", (double) v/1024); +void pa_bytes_snprint(char *s, size_t l, unsigned v) { + if (v >= ((unsigned) 1024)*1024*1024) + snprintf(s, l, "%0.1f GB", ((double) v)/1024/1024/1024); + else if (v >= ((unsigned) 1024)*1024) + snprintf(s, l, "%0.1f MB", ((double) v)/1024/1024); + else if (v >= (unsigned) 1024) + snprintf(s, l, "%0.1f KB", ((double) v)/1024); else snprintf(s, l, "%u B", (unsigned) v); } diff --git a/polyp/sample.h b/polyp/sample.h index 1e42a260..501172a8 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -86,7 +86,7 @@ int pa_sample_spec_valid(const struct pa_sample_spec *spec); int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b); /** Maximum required string length for pa_sample_spec_snprint() */ -#define PA_SAMPLE_SNPRINT_MAX_LENGTH 32 +#define PA_SAMPLE_SPEC_SNPRINT_MAX 32 /** Pretty print a sample type specification to a string */ void pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec); @@ -117,7 +117,7 @@ double pa_volume_to_dB(pa_volume_t v); #endif /** Pretty print a byte size value. (i.e. "2.5 MB") */ -void pa_bytes_snprint(char *s, size_t l, off_t v); +void pa_bytes_snprint(char *s, size_t l, unsigned v); PA_C_DECL_END diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index d571b713..39ae87b5 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -33,6 +33,7 @@ enum tags { TAG_STRING = 't', + TAG_NULL_STRING = 'N', TAG_U32 = 'L', TAG_S32 = 'l', TAG_U16 = 'S', @@ -97,12 +98,18 @@ static void extend(struct pa_tagstruct*t, size_t l) { void pa_tagstruct_puts(struct pa_tagstruct*t, const char *s) { size_t l; - assert(t && s); - l = strlen(s)+2; - extend(t, l); - t->data[t->length] = TAG_STRING; - strcpy((char*) (t->data+t->length+1), s); - t->length += l; + assert(t); + if (s) { + l = strlen(s)+2; + extend(t, l); + t->data[t->length] = TAG_STRING; + strcpy((char*) (t->data+t->length+1), s); + t->length += l; + } else { + extend(t, 1); + t->data[t->length] = TAG_NULL_STRING; + t->length += 1; + } } void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i) { @@ -173,6 +180,15 @@ int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) { char *c; assert(t && s); + if (t->rindex+1 > t->length) + return -1; + + if (t->data[t->rindex] == TAG_NULL_STRING) { + t->rindex++; + *s = NULL; + return 0; + } + if (t->rindex+2 > t->length) return -1; -- cgit