diff options
Diffstat (limited to 'src/tests')
45 files changed, 4274 insertions, 281 deletions
diff --git a/src/tests/Makefile b/src/tests/Makefile deleted file mode 120000 index c110232d..00000000 --- a/src/tests/Makefile +++ /dev/null @@ -1 +0,0 @@ -../pulse/Makefile
\ No newline at end of file diff --git a/src/tests/alsa-time-test.c b/src/tests/alsa-time-test.c new file mode 100644 index 00000000..1a572b30 --- /dev/null +++ b/src/tests/alsa-time-test.c @@ -0,0 +1,224 @@ +#include <assert.h> +#include <inttypes.h> +#include <time.h> + +#include <alsa/asoundlib.h> + +static uint64_t timespec_us(const struct timespec *ts) { + return + ts->tv_sec * 1000000LLU + + ts->tv_nsec / 1000LLU; +} + +int main(int argc, char *argv[]) { + const char *dev; + int r, cap; + snd_pcm_hw_params_t *hwparams; + snd_pcm_sw_params_t *swparams; + snd_pcm_status_t *status; + snd_pcm_t *pcm; + unsigned rate = 44100; + unsigned periods = 2; + snd_pcm_uframes_t boundary, buffer_size = 44100/10; /* 100s */ + int dir = 1; + struct timespec start, last_timestamp = { 0, 0 }; + uint64_t start_us; + snd_pcm_sframes_t last_avail = 0, last_delay = 0; + struct pollfd *pollfds; + int n_pollfd; + int64_t sample_count = 0; + + snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_sw_params_alloca(&swparams); + snd_pcm_status_alloca(&status); + + r = clock_gettime(CLOCK_MONOTONIC, &start); + assert(r == 0); + + start_us = timespec_us(&start); + + dev = argc > 1 ? argv[1] : "front:AudioPCI"; + cap = argc > 2 ? atoi(argv[2]) : 0; + + if (cap == 0) + r = snd_pcm_open(&pcm, dev, SND_PCM_STREAM_PLAYBACK, 0); + else + r = snd_pcm_open(&pcm, dev, SND_PCM_STREAM_CAPTURE, 0); + assert(r == 0); + + r = snd_pcm_hw_params_any(pcm, hwparams); + assert(r == 0); + + r = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 0); + assert(r == 0); + + r = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); + assert(r == 0); + + r = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE); + assert(r == 0); + + r = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, NULL); + assert(r == 0); + + r = snd_pcm_hw_params_set_channels(pcm, hwparams, 2); + assert(r == 0); + + r = snd_pcm_hw_params_set_periods_integer(pcm, hwparams); + assert(r == 0); + + r = snd_pcm_hw_params_set_periods_near(pcm, hwparams, &periods, &dir); + assert(r == 0); + + r = snd_pcm_hw_params_set_buffer_size_near(pcm, hwparams, &buffer_size); + assert(r == 0); + + r = snd_pcm_hw_params(pcm, hwparams); + assert(r == 0); + + r = snd_pcm_hw_params_current(pcm, hwparams); + assert(r == 0); + + r = snd_pcm_sw_params_current(pcm, swparams); + assert(r == 0); + + if (cap == 0) + r = snd_pcm_sw_params_set_avail_min(pcm, swparams, 1); + else + r = snd_pcm_sw_params_set_avail_min(pcm, swparams, 0); + assert(r == 0); + + r = snd_pcm_sw_params_set_period_event(pcm, swparams, 0); + assert(r == 0); + + r = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); + assert(r == 0); + r = snd_pcm_sw_params_set_start_threshold(pcm, swparams, buffer_size); + assert(r == 0); + + r = snd_pcm_sw_params_get_boundary(swparams, &boundary); + assert(r == 0); + r = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary); + assert(r == 0); + + r = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE); + assert(r == 0); + + r = snd_pcm_sw_params(pcm, swparams); + assert(r == 0); + + r = snd_pcm_prepare(pcm); + assert(r == 0); + + r = snd_pcm_sw_params_current(pcm, swparams); + assert(r == 0); + +/* assert(snd_pcm_hw_params_is_monotonic(hwparams) > 0); */ + + n_pollfd = snd_pcm_poll_descriptors_count(pcm); + assert(n_pollfd > 0); + + pollfds = malloc(sizeof(struct pollfd) * n_pollfd); + assert(pollfds); + + r = snd_pcm_poll_descriptors(pcm, pollfds, n_pollfd); + assert(r == n_pollfd); + + if (cap) { + r = snd_pcm_start(pcm); + assert(r == 0); + } + + for (;;) { + snd_pcm_sframes_t avail, delay; + struct timespec now, timestamp; + unsigned short revents; + int handled = 0; + uint64_t now_us, timestamp_us; + snd_pcm_state_t state; + unsigned long long pos; + + r = poll(pollfds, n_pollfd, 0); + assert(r >= 0); + + r = snd_pcm_poll_descriptors_revents(pcm, pollfds, n_pollfd, &revents); + assert(r == 0); + + if (cap == 0) + assert((revents & ~POLLOUT) == 0); + else + assert((revents & ~POLLIN) == 0); + + avail = snd_pcm_avail(pcm); + assert(avail >= 0); + + r = snd_pcm_status(pcm, status); + assert(r == 0); + + /* This assertion fails from time to time. ALSA seems to be broken */ +/* assert(avail == (snd_pcm_sframes_t) snd_pcm_status_get_avail(status)); */ +/* printf("%lu %lu\n", (unsigned long) avail, (unsigned long) snd_pcm_status_get_avail(status)); */ + + snd_pcm_status_get_htstamp(status, ×tamp); + delay = snd_pcm_status_get_delay(status); + state = snd_pcm_status_get_state(status); + + r = clock_gettime(CLOCK_MONOTONIC, &now); + assert(r == 0); + + assert(!revents || avail > 0); + + if ((!cap && avail) || (cap && (unsigned)avail >= buffer_size)) { + snd_pcm_sframes_t sframes; + static const uint16_t psamples[2] = { 0, 0 }; + uint16_t csamples[2]; + + if (cap == 0) + sframes = snd_pcm_writei(pcm, psamples, 1); + else + sframes = snd_pcm_readi(pcm, csamples, 1); + assert(sframes == 1); + + handled = 1; + sample_count++; + } + + if (!handled && + memcmp(×tamp, &last_timestamp, sizeof(timestamp)) == 0 && + avail == last_avail && + delay == last_delay) { + /* This is boring */ + continue; + } + + now_us = timespec_us(&now); + timestamp_us = timespec_us(×tamp); + + if (cap == 0) + pos = (unsigned long long) ((sample_count - handled - delay) * 1000000LU / 44100); + else + pos = (unsigned long long) ((sample_count - handled + delay) * 1000000LU / 44100); + + printf("%llu\t%llu\t%llu\t%llu\t%li\t%li\t%i\t%i\t%i\n", + (unsigned long long) (now_us - start_us), + (unsigned long long) (timestamp_us ? timestamp_us - start_us : 0), + pos, + (unsigned long long) sample_count, + (signed long) avail, + (signed long) delay, + revents, + handled, + state); + + if (cap == 0) + /** When this assert is hit, most likely something bad + * happened, i.e. the avail jumped suddenly. */ + assert((unsigned) avail <= buffer_size); + + last_avail = avail; + last_delay = delay; + last_timestamp = timestamp; + } + + return 0; +} diff --git a/src/tests/asyncmsgq-test.c b/src/tests/asyncmsgq-test.c new file mode 100644 index 00000000..96e5a0df --- /dev/null +++ b/src/tests/asyncmsgq-test.c @@ -0,0 +1,105 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> +#include <unistd.h> + +#include <pulsecore/asyncmsgq.h> +#include <pulsecore/thread.h> +#include <pulsecore/log.h> +#include <pulsecore/macro.h> + +enum { + OPERATION_A, + OPERATION_B, + OPERATION_C, + QUIT +}; + +static void the_thread(void *_q) { + pa_asyncmsgq *q = _q; + int quit = 0; + + do { + int code = 0; + + pa_assert_se(pa_asyncmsgq_get(q, NULL, &code, NULL, NULL, NULL, 1) == 0); + + switch (code) { + + case OPERATION_A: + printf("Operation A\n"); + break; + + case OPERATION_B: + printf("Operation B\n"); + break; + + case OPERATION_C: + printf("Operation C\n"); + break; + + case QUIT: + printf("quit\n"); + quit = 1; + break; + } + + pa_asyncmsgq_done(q, 0); + + } while (!quit); +} + +int main(int argc, char *argv[]) { + pa_asyncmsgq *q; + pa_thread *t; + + pa_assert_se(q = pa_asyncmsgq_new(0)); + + pa_assert_se(t = pa_thread_new("test", the_thread, q)); + + printf("Operation A post\n"); + pa_asyncmsgq_post(q, NULL, OPERATION_A, NULL, 0, NULL, NULL); + + pa_thread_yield(); + + printf("Operation B post\n"); + pa_asyncmsgq_post(q, NULL, OPERATION_B, NULL, 0, NULL, NULL); + + pa_thread_yield(); + + printf("Operation C send\n"); + pa_asyncmsgq_send(q, NULL, OPERATION_C, NULL, 0, NULL); + + pa_thread_yield(); + + printf("Quit post\n"); + pa_asyncmsgq_post(q, NULL, QUIT, NULL, 0, NULL, NULL); + + pa_thread_free(t); + + pa_asyncmsgq_unref(q); + + return 0; +} diff --git a/src/tests/asyncq-test.c b/src/tests/asyncq-test.c new file mode 100644 index 00000000..46bac9f4 --- /dev/null +++ b/src/tests/asyncq-test.c @@ -0,0 +1,83 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> +#include <unistd.h> + +#include <pulse/util.h> +#include <pulsecore/asyncq.h> +#include <pulsecore/thread.h> +#include <pulsecore/log.h> +#include <pulsecore/macro.h> + +static void producer(void *_q) { + pa_asyncq *q = _q; + int i; + + for (i = 0; i < 1000; i++) { + printf("pushing %i\n", i); + pa_asyncq_push(q, PA_UINT_TO_PTR(i+1), 1); + } + + pa_asyncq_push(q, PA_UINT_TO_PTR(-1), TRUE); + printf("pushed end\n"); +} + +static void consumer(void *_q) { + pa_asyncq *q = _q; + void *p; + int i; + + pa_msleep(1000); + + for (i = 0;; i++) { + p = pa_asyncq_pop(q, TRUE); + + if (p == PA_UINT_TO_PTR(-1)) + break; + + pa_assert(p == PA_UINT_TO_PTR(i+1)); + + printf("popped %i\n", i); + } + + printf("popped end\n"); +} + +int main(int argc, char *argv[]) { + pa_asyncq *q; + pa_thread *t1, *t2; + + pa_assert_se(q = pa_asyncq_new(0)); + + pa_assert_se(t1 = pa_thread_new("producer", producer, q)); + pa_assert_se(t2 = pa_thread_new("consumer", consumer, q)); + + pa_thread_free(t1); + pa_thread_free(t2); + + pa_asyncq_free(q, NULL); + + return 0; +} diff --git a/src/tests/channelmap-test.c b/src/tests/channelmap-test.c index 124ce576..70d6a6a9 100644 --- a/src/tests/channelmap-test.c +++ b/src/tests/channelmap-test.c @@ -1,33 +1,37 @@ -/* $Id$ */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif #include <stdio.h> #include <assert.h> #include <pulse/channelmap.h> -#include <pulsecore/gccmacro.h> -int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { +int main(int argc, char *argv[]) { char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_channel_map map, map2; pa_channel_map_init_auto(&map, 6, PA_CHANNEL_MAP_AIFF); - + fprintf(stderr, "map: <%s>\n", pa_channel_map_snprint(cm, sizeof(cm), &map)); pa_channel_map_init_auto(&map, 6, PA_CHANNEL_MAP_AUX); - + fprintf(stderr, "map: <%s>\n", pa_channel_map_snprint(cm, sizeof(cm), &map)); pa_channel_map_init_auto(&map, 6, PA_CHANNEL_MAP_ALSA); - + fprintf(stderr, "map: <%s>\n", pa_channel_map_snprint(cm, sizeof(cm), &map)); - + + pa_channel_map_init_extend(&map, 14, PA_CHANNEL_MAP_ALSA); + + fprintf(stderr, "map: <%s>\n", pa_channel_map_snprint(cm, sizeof(cm), &map)); + pa_channel_map_parse(&map2, cm); assert(pa_channel_map_equal(&map, &map2)); pa_channel_map_parse(&map2, "left,test"); - return 0; } diff --git a/src/tests/close-test.c b/src/tests/close-test.c new file mode 100644 index 00000000..7a6fec57 --- /dev/null +++ b/src/tests/close-test.c @@ -0,0 +1,20 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <unistd.h> +#include <fcntl.h> + +#include <pulsecore/core-util.h> + +int main(int argc, char *argv[]) { + + open("/dev/null", O_RDONLY); + open("/dev/null", O_RDONLY); + open("/dev/null", O_RDONLY); + open("/dev/null", O_RDONLY); + + pa_close_all(5, -1); + + return 0; +} diff --git a/src/tests/connect-stress.c b/src/tests/connect-stress.c new file mode 100644 index 00000000..eadcf885 --- /dev/null +++ b/src/tests/connect-stress.c @@ -0,0 +1,206 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <signal.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include <pulse/pulseaudio.h> +#include <pulse/mainloop.h> + +#include <pulsecore/sink.h> + +/* Set the number of streams such that it allows two simultaneous instances of + * connect-stress to be run and not go above the max limit for streams-per-sink. + * This leaves enough room for a couple other streams from regular system usage, + * which makes a non-error abort less likely (although still easily possible of + * playing >=3 streams outside of the test - including internal loopback, rtp, + * combine, remap streams etc.) */ +#define NSTREAMS ((PA_MAX_INPUTS_PER_SINK/2) - 1) +#define NTESTS 1000 +#define SAMPLE_HZ 44100 + +static pa_context *context = NULL; +static pa_stream *streams[NSTREAMS]; +static pa_threaded_mainloop *mainloop = NULL; + +static const pa_sample_spec sample_spec = { + .format = PA_SAMPLE_FLOAT32, + .rate = SAMPLE_HZ, + .channels = 1 +}; + +static void context_state_callback(pa_context *c, void *userdata); + +static void connect(const char *name, int *try) { + int ret; + pa_mainloop_api *api; + + /* Set up a new main loop */ + mainloop = pa_threaded_mainloop_new(); + assert(mainloop); + + api = pa_threaded_mainloop_get_api(mainloop); + context = pa_context_new(api, name); + assert(context); + + pa_context_set_state_callback(context, context_state_callback, try); + + /* Connect the context */ + if (pa_context_connect(context, NULL, 0, NULL) < 0) { + fprintf(stderr, "pa_context_connect() failed.\n"); + abort(); + } + + ret = pa_threaded_mainloop_start(mainloop); + assert(ret == 0); +} + +static void disconnect(void) { + int i; + + assert(mainloop); + assert(context); + + pa_threaded_mainloop_lock(mainloop); + + for (i = 0; i < NSTREAMS; i++) + if (streams[i]) { + pa_stream_disconnect(streams[i]); + pa_stream_unref(streams[i]); + streams[i] = NULL; + } + + pa_context_disconnect(context); + context = NULL; + + pa_threaded_mainloop_unlock(mainloop); + pa_threaded_mainloop_stop(mainloop); + pa_threaded_mainloop_free(mainloop); + mainloop = NULL; +} + +static const pa_buffer_attr buffer_attr = { + .maxlength = SAMPLE_HZ * sizeof(float) * NSTREAMS, + .tlength = (uint32_t) -1, + .prebuf = 0, /* Setting prebuf to 0 guarantees us the the streams will run synchronously, no matter what */ + .minreq = (uint32_t) -1, + .fragsize = 0 +}; + +static void stream_write_callback(pa_stream *stream, size_t nbytes, void *userdata) { + char silence[8192]; + + memset(silence, 0, sizeof(silence)); + + while (nbytes) { + int n = PA_MIN(sizeof(silence), nbytes); + pa_stream_write(stream, silence, n, NULL, 0, 0); + nbytes -= n; + } +} + +static void stream_state_callback(pa_stream *s, void *userdata) { + assert(s); + + switch (pa_stream_get_state(s)) { + case PA_STREAM_UNCONNECTED: + case PA_STREAM_CREATING: + case PA_STREAM_TERMINATED: + case PA_STREAM_READY: + break; + + default: + case PA_STREAM_FAILED: + fprintf(stderr, "Stream error: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + abort(); + } +} + +static void context_state_callback(pa_context *c, void *userdata) { + int *try; + + assert(c); + assert(userdata); + + try = (int*)userdata; + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: { + + int i; + fprintf(stderr, "Connection (%d of %d) established.\n", (*try)+1, NTESTS); + + for (i = 0; i < NSTREAMS; i++) { + char name[64]; + + snprintf(name, sizeof(name), "stream #%i", i); + streams[i] = pa_stream_new(c, name, &sample_spec, NULL); + assert(streams[i]); + pa_stream_set_state_callback(streams[i], stream_state_callback, NULL); + pa_stream_set_write_callback(streams[i], stream_write_callback, NULL); + pa_stream_connect_playback(streams[i], NULL, &buffer_attr, 0, NULL, NULL); + } + + break; + } + + case PA_CONTEXT_TERMINATED: + fprintf(stderr, "Connection terminated.\n"); + pa_context_unref(context); + context = NULL; + break; + + case PA_CONTEXT_FAILED: + default: + fprintf(stderr, "Context error: %s\n", pa_strerror(pa_context_errno(c))); + abort(); + } +} + +int main(int argc, char *argv[]) { + int i; + + for (i = 0; i < NSTREAMS; i++) + streams[i] = NULL; + + for (i = 0; i < NTESTS; i++) { + connect(argv[0], &i); + usleep(rand() % 500000); + disconnect(); + usleep(rand() % 500000); + } + + fprintf(stderr, "Done.\n"); + + return 0; +} diff --git a/src/tests/cpulimit-test.c b/src/tests/cpulimit-test.c index 2302a26d..8bd03417 100644 --- a/src/tests/cpulimit-test.c +++ b/src/tests/cpulimit-test.c @@ -1,18 +1,16 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the + published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -24,19 +22,18 @@ #endif #include <assert.h> -#include <sys/time.h> +#include <time.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <pulse/mainloop.h> -#include <pulsecore/gccmacro.h> #ifdef TEST2 #include <pulse/mainloop-signal.h> #endif -#include "../daemon/cpulimit.h" +#include <daemon/cpulimit.h> /* A simple example for testing the cpulimit subsystem */ @@ -44,10 +41,10 @@ static time_t start; #ifdef TEST2 -static void func(pa_mainloop_api *m, PA_GCC_UNUSED pa_signal_event *e, PA_GCC_UNUSED int sig, PA_GCC_UNUSED void *userdata) { +static void func(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) { time_t now; time(&now); - + if ((now - start) >= 30) { m->quit(m, 1); fprintf(stderr, "Test failed\n"); @@ -57,9 +54,9 @@ static void func(pa_mainloop_api *m, PA_GCC_UNUSED pa_signal_event *e, PA_GCC_UN #endif -int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { +int main(int argc, char *argv[]) { pa_mainloop *m; - + m = pa_mainloop_new(); assert(m); @@ -77,7 +74,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { for (;;) { time_t now; time(&now); - + if ((now - start) >= 30) { fprintf(stderr, "Test failed\n"); break; @@ -86,7 +83,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { #endif pa_cpu_limit_done(); - + pa_mainloop_free(m); return 0; diff --git a/src/tests/extended-test.c b/src/tests/extended-test.c new file mode 100644 index 00000000..631fdc89 --- /dev/null +++ b/src/tests/extended-test.c @@ -0,0 +1,197 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <signal.h> +#include <errno.h> +#include <unistd.h> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +#include <pulse/pulseaudio.h> +#include <pulse/mainloop.h> + +#define NSTREAMS 4 +#define SINE_HZ 440 +#define SAMPLE_HZ 8000 + +static pa_context *context = NULL; +static pa_stream *streams[NSTREAMS]; +static pa_mainloop_api *mainloop_api = NULL; + +static float data[SAMPLE_HZ]; /* one second space */ + +static int n_streams_ready = 0; + +static const pa_buffer_attr buffer_attr = { + .maxlength = SAMPLE_HZ*sizeof(float)*NSTREAMS, /* exactly space for the entire play time */ + .tlength = (uint32_t) -1, + .prebuf = 0, /* Setting prebuf to 0 guarantees us the the streams will run synchronously, no matter what */ + .minreq = (uint32_t) -1, + .fragsize = 0 +}; + +static void nop_free_cb(void *p) {} + +static void underflow_cb(struct pa_stream *s, void *userdata) { + int i = (int) (long) userdata; + + fprintf(stderr, "Stream %i finished\n", i); + + if (++n_streams_ready >= 2*NSTREAMS) { + fprintf(stderr, "We're done\n"); + mainloop_api->quit(mainloop_api, 0); + } +} + +/* This routine is called whenever the stream state changes */ +static void stream_state_callback(pa_stream *s, void *userdata) { + assert(s); + + switch (pa_stream_get_state(s)) { + case PA_STREAM_UNCONNECTED: + case PA_STREAM_CREATING: + case PA_STREAM_TERMINATED: + break; + + case PA_STREAM_READY: { + + int r, i = (int) (long) userdata; + + fprintf(stderr, "Writing data to stream %i.\n", i); + + r = pa_stream_write(s, data, sizeof(data), nop_free_cb, (int64_t) sizeof(data) * (int64_t) i, PA_SEEK_ABSOLUTE); + assert(r == 0); + + /* Be notified when this stream is drained */ + pa_stream_set_underflow_callback(s, underflow_cb, userdata); + + /* All streams have been set up, let's go! */ + if (++n_streams_ready >= NSTREAMS) { + fprintf(stderr, "Uncorking\n"); + pa_operation_unref(pa_stream_cork(s, 0, NULL, NULL)); + } + + break; + } + + default: + case PA_STREAM_FAILED: + fprintf(stderr, "Stream error: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + abort(); + } +} + +/* This is called whenever the context status changes */ +static void context_state_callback(pa_context *c, void *userdata) { + assert(c); + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: { + + int i; + fprintf(stderr, "Connection established.\n"); + + for (i = 0; i < NSTREAMS; i++) { + char name[64]; + pa_format_info *formats[1]; + + formats[0] = pa_format_info_new(); + formats[0]->encoding = PA_ENCODING_PCM; + pa_format_info_set_sample_format(formats[0], PA_SAMPLE_FLOAT32); + pa_format_info_set_rate(formats[0], SAMPLE_HZ); + pa_format_info_set_channels(formats[0], 1); + + fprintf(stderr, "Creating stream %i\n", i); + + snprintf(name, sizeof(name), "stream #%i", i); + + streams[i] = pa_stream_new_extended(c, name, formats, 1, NULL); + assert(streams[i]); + pa_stream_set_state_callback(streams[i], stream_state_callback, (void*) (long) i); + pa_stream_connect_playback(streams[i], NULL, &buffer_attr, PA_STREAM_START_CORKED, NULL, i == 0 ? NULL : streams[0]); + + pa_format_info_free(formats[0]); + } + + break; + } + + case PA_CONTEXT_TERMINATED: + mainloop_api->quit(mainloop_api, 0); + break; + + case PA_CONTEXT_FAILED: + default: + fprintf(stderr, "Context error: %s\n", pa_strerror(pa_context_errno(c))); + abort(); + } +} + +int main(int argc, char *argv[]) { + pa_mainloop* m = NULL; + int i, ret = 0; + + for (i = 0; i < SAMPLE_HZ; i++) + data[i] = (float) sin(((double) i/SAMPLE_HZ)*2*M_PI*SINE_HZ)/2; + + for (i = 0; i < NSTREAMS; i++) + streams[i] = NULL; + + /* Set up a new main loop */ + m = pa_mainloop_new(); + assert(m); + + mainloop_api = pa_mainloop_get_api(m); + + context = pa_context_new(mainloop_api, argv[0]); + assert(context); + + pa_context_set_state_callback(context, context_state_callback, NULL); + + /* Connect the context */ + if (pa_context_connect(context, NULL, 0, NULL) < 0) { + fprintf(stderr, "pa_context_connect() failed.\n"); + goto quit; + } + + if (pa_mainloop_run(m, &ret) < 0) + fprintf(stderr, "pa_mainloop_run() failed.\n"); + +quit: + pa_context_unref(context); + + for (i = 0; i < NSTREAMS; i++) + if (streams[i]) + pa_stream_unref(streams[i]); + + pa_mainloop_free(m); + + return ret; +} diff --git a/src/tests/flist-test.c b/src/tests/flist-test.c new file mode 100644 index 00000000..69152041 --- /dev/null +++ b/src/tests/flist-test.c @@ -0,0 +1,103 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> +#include <unistd.h> + +#include <pulse/util.h> +#include <pulse/xmalloc.h> +#include <pulsecore/flist.h> +#include <pulsecore/thread.h> +#include <pulsecore/log.h> +#include <pulsecore/core-util.h> + +#define THREADS_MAX 20 + +static pa_flist *flist; +static int quit = 0; + +static void spin(void) { + int k; + + /* Spin a little */ + k = rand() % 10000; + for (; k > 0; k--) + pa_thread_yield(); +} + +static void thread_func(void *data) { + char *s = data; + int n = 0; + int b = 1; + + while (!quit) { + char *text; + + /* Allocate some memory, if possible take it from the flist */ + if (b && (text = pa_flist_pop(flist))) + pa_log("%s: popped '%s'", s, text); + else { + text = pa_sprintf_malloc("Block %i, allocated by %s", n++, s); + pa_log("%s: allocated '%s'", s, text); + } + + b = !b; + + spin(); + + /* Give it back to the flist if possible */ + if (pa_flist_push(flist, text) < 0) { + pa_log("%s: failed to push back '%s'", s, text); + pa_xfree(text); + } else + pa_log("%s: pushed", s); + + spin(); + } + + if (pa_flist_push(flist, s) < 0) + pa_xfree(s); +} + +int main(int argc, char* argv[]) { + pa_thread *threads[THREADS_MAX]; + int i; + + flist = pa_flist_new(0); + + for (i = 0; i < THREADS_MAX; i++) { + threads[i] = pa_thread_new("test", thread_func, pa_sprintf_malloc("Thread #%i", i+1)); + assert(threads[i]); + } + + pa_msleep(60000); + quit = 1; + + for (i = 0; i < THREADS_MAX; i++) + pa_thread_free(threads[i]); + + pa_flist_free(flist, pa_xfree); + + return 0; +} diff --git a/src/tests/format-test.c b/src/tests/format-test.c new file mode 100644 index 00000000..888db8c9 --- /dev/null +++ b/src/tests/format-test.c @@ -0,0 +1,106 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> + +#include <pulsecore/macro.h> +#include <pulse/format.h> + +#define INIT(f) f = pa_format_info_new() +#define DEINIT(f) pa_format_info_free(f); +#define REINIT(f) { DEINIT(f); INIT(f); } + +int main(int argc, char *argv[]) { + pa_format_info *f1 = NULL, *f2 = NULL; + int rates1[] = { 32000, 44100, 48000 }; + const char *strings[] = { "thing1", "thing2", "thing3" }; + + /* 1. Simple fixed format int check */ + INIT(f1); INIT(f2); + f1->encoding = PA_ENCODING_AC3_IEC61937; + pa_format_info_set_prop_int(f1, PA_PROP_FORMAT_RATE, 32000); + f2->encoding = PA_ENCODING_AC3_IEC61937; + pa_format_info_set_prop_int(f2, PA_PROP_FORMAT_RATE, 44100); + pa_assert(!pa_format_info_is_compatible(f1, f2)); + + /* 2. Check int array membership - positive */ + REINIT(f1); REINIT(f2); + f1->encoding = PA_ENCODING_AC3_IEC61937; + pa_format_info_set_prop_int_array(f1, PA_PROP_FORMAT_RATE, rates1, PA_ELEMENTSOF(rates1)); + f2->encoding = PA_ENCODING_AC3_IEC61937; + pa_format_info_set_prop_int(f2, PA_PROP_FORMAT_RATE, 44100); + pa_assert(pa_format_info_is_compatible(f1, f2)); + pa_assert(pa_format_info_is_compatible(f2, f1)); + + /* 3. Check int array memebership - negative */ + REINIT(f2); + f2->encoding = PA_ENCODING_AC3_IEC61937; + pa_format_info_set_prop_int(f2, PA_PROP_FORMAT_RATE, 96000); + pa_assert(!pa_format_info_is_compatible(f1, f2)); + pa_assert(!pa_format_info_is_compatible(f2, f1)); + + /* 4. Check int range - positive */ + REINIT(f1); REINIT(f2); + f1->encoding = PA_ENCODING_AC3_IEC61937; + pa_format_info_set_prop_int_range(f1, PA_PROP_FORMAT_RATE, 32000, 48000); + f2->encoding = PA_ENCODING_AC3_IEC61937; + pa_format_info_set_prop_int(f2, PA_PROP_FORMAT_RATE, 44100); + pa_assert(pa_format_info_is_compatible(f1, f2)); + pa_assert(pa_format_info_is_compatible(f2, f1)); + + /* 5. Check int range - negative */ + REINIT(f2); + f2->encoding = PA_ENCODING_AC3_IEC61937; + pa_format_info_set_prop_int(f2, PA_PROP_FORMAT_RATE, 96000); + pa_assert(!pa_format_info_is_compatible(f1, f2)); + pa_assert(!pa_format_info_is_compatible(f2, f1)); + + /* 6. Simple fixed format string check */ + REINIT(f1); REINIT(f2); + f1->encoding = PA_ENCODING_AC3_IEC61937; + pa_format_info_set_prop_string(f1, "format.test_string", "thing1"); + f2->encoding = PA_ENCODING_AC3_IEC61937; + pa_format_info_set_prop_string(f2, "format.test_string", "notthing1"); + pa_assert(!pa_format_info_is_compatible(f1, f2)); + + /* 7. Check string array membership - positive */ + REINIT(f1); REINIT(f2); + f1->encoding = PA_ENCODING_AC3_IEC61937; + pa_format_info_set_prop_string_array(f1, "format.test_string", strings, PA_ELEMENTSOF(strings)); + f2->encoding = PA_ENCODING_AC3_IEC61937; + pa_format_info_set_prop_string(f2, "format.test_string", "thing3"); + pa_assert(pa_format_info_is_compatible(f1, f2)); + pa_assert(pa_format_info_is_compatible(f2, f1)); + + /* 8. Check string array memebership - negative */ + REINIT(f2); + f2->encoding = PA_ENCODING_AC3_IEC61937; + pa_format_info_set_prop_string(f2, "format.test_string", "thing5"); + pa_assert(!pa_format_info_is_compatible(f1, f2)); + pa_assert(!pa_format_info_is_compatible(f2, f1)); + + DEINIT(f1); + DEINIT(f2); + + return 0; +} diff --git a/src/tests/get-binary-name-test.c b/src/tests/get-binary-name-test.c index 0cea2b6d..4afe81b3 100644 --- a/src/tests/get-binary-name-test.c +++ b/src/tests/get-binary-name-test.c @@ -1,18 +1,16 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -23,14 +21,34 @@ #include <config.h> #endif -#include <limits.h> #include <stdio.h> +#include <string.h> #include <pulse/util.h> +#include <pulse/xmalloc.h> int main(int argc, char *argv[]) { - char exename[PATH_MAX]; + char *exename; + size_t allocated = 128; + + for (;;) { + exename = pa_xmalloc(allocated); + + if (!pa_get_binary_name(exename, allocated)) { + printf("failed to read binary name\n"); + pa_xfree(exename); + break; + } + + if (strlen(exename) < allocated - 1) { + printf("%s\n", exename); + pa_xfree(exename); + break; + } + + pa_xfree(exename); + allocated *= 2; + } - printf("%s\n", pa_get_binary_name(exename, sizeof(exename))); return 0; } diff --git a/src/tests/gtk-test.c b/src/tests/gtk-test.c new file mode 100644 index 00000000..6470e484 --- /dev/null +++ b/src/tests/gtk-test.c @@ -0,0 +1,85 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#pragma GCC diagnostic ignored "-Wstrict-prototypes" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gtk/gtk.h> +#include <glib.h> + +#include <pulse/context.h> +#include <pulse/glib-mainloop.h> + +pa_context *ctxt; +pa_glib_mainloop *m; + +static void context_state_callback(pa_context *c, void *userdata); + +static void connect(void) { + int r; + + ctxt = pa_context_new(pa_glib_mainloop_get_api(m), NULL); + g_assert(ctxt); + + r = pa_context_connect(ctxt, NULL, PA_CONTEXT_NOAUTOSPAWN|PA_CONTEXT_NOFAIL, NULL); + g_assert(r == 0); + + pa_context_set_state_callback(ctxt, context_state_callback, NULL); +} + +static void context_state_callback(pa_context *c, void *userdata) { + switch (pa_context_get_state(c)) { + case PA_CONTEXT_FAILED: + pa_context_unref(ctxt); + ctxt = NULL; + connect(); + break; + default: + break; + } +} + +int main(int argc, char *argv[]) { + + GtkWidget *window; + + gtk_init(&argc, &argv); + + g_set_application_name("This is a test"); + gtk_window_set_default_icon_name("foobar"); + g_setenv("PULSE_PROP_media.role", "phone", TRUE); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW (window), g_get_application_name()); + gtk_widget_show_all(window); + + m = pa_glib_mainloop_new(NULL); + g_assert(m); + + connect(); + gtk_main(); + + pa_context_unref(ctxt); + pa_glib_mainloop_free(m); + + return 0; +} diff --git a/src/tests/hook-list-test.c b/src/tests/hook-list-test.c new file mode 100644 index 00000000..452e4776 --- /dev/null +++ b/src/tests/hook-list-test.c @@ -0,0 +1,37 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <pulsecore/hook-list.h> +#include <pulsecore/log.h> + +static pa_hook_result_t func1(const char *hook_data, const char *call_data, const char *slot_data) { + pa_log("(func1) hook=%s call=%s slot=%s", hook_data, call_data, slot_data); + return PA_HOOK_OK; +} + +static pa_hook_result_t func2(const char *hook_data, const char *call_data, const char *slot_data) { + pa_log("(func2) hook=%s call=%s slot=%s", hook_data, call_data, slot_data); + return PA_HOOK_OK; +} + +int main(int argc, char *argv[]) { + pa_hook hook; + pa_hook_slot *slot; + + pa_hook_init(&hook, (void*) "hook"); + + pa_hook_connect(&hook, PA_HOOK_LATE, (pa_hook_cb_t) func1, (void*) "slot1"); + slot = pa_hook_connect(&hook, PA_HOOK_NORMAL, (pa_hook_cb_t) func2, (void*) "slot2"); + pa_hook_connect(&hook, PA_HOOK_NORMAL, (pa_hook_cb_t) func1, (void*) "slot3"); + + pa_hook_fire(&hook, (void*) "call1"); + + pa_hook_slot_free(slot); + + pa_hook_fire(&hook, (void*) "call2"); + + pa_hook_done(&hook); + + return 0; +} diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c index 2df65a45..ffe4ab38 100644 --- a/src/tests/interpol-test.c +++ b/src/tests/interpol-test.c @@ -1,18 +1,16 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -30,24 +28,61 @@ #include <assert.h> #include <stdio.h> #include <stdlib.h> -#include <getopt.h> -#include <math.h> - -#ifdef HAVE_PTHREAD -#include <pthread.h> -#endif #include <pulse/pulseaudio.h> #include <pulse/mainloop.h> +#include <pulsecore/thread.h> + +#define INTERPOLATE +//#define CORK + static pa_context *context = NULL; static pa_stream *stream = NULL; static pa_mainloop_api *mainloop_api = NULL; +static pa_bool_t playback = TRUE; +static pa_usec_t latency = 0; -static void stream_write_cb(pa_stream *p, size_t length, void *userdata) { - +static void stream_write_cb(pa_stream *p, size_t nbytes, void *userdata) { /* Just some silence */ - pa_stream_write(p, pa_xmalloc0(length), length, pa_xfree, 0, PA_SEEK_RELATIVE); + + for (;;) { + void *data; + + pa_assert_se((nbytes = pa_stream_writable_size(p)) != (size_t) -1); + + if (nbytes <= 0) + break; + + pa_assert_se(pa_stream_begin_write(p, &data, &nbytes) == 0); + pa_memzero(data, nbytes); + pa_assert_se(pa_stream_write(p, data, nbytes, NULL, 0, PA_SEEK_RELATIVE) == 0); + } +} + +static void stream_read_cb(pa_stream *p, size_t nbytes, void *userdata) { + /* We don't care about the data, just drop it */ + + for (;;) { + const void *data; + + pa_assert_se((nbytes = pa_stream_readable_size(p)) != (size_t) -1); + + if (nbytes <= 0) + break; + + pa_assert_se(pa_stream_peek(p, &data, &nbytes) == 0); + pa_assert_se(pa_stream_drop(p) == 0); + } +} + +static void stream_latency_cb(pa_stream *p, void *userdata) { +#ifndef INTERPOLATE + pa_operation *o; + + o = pa_stream_update_timing_info(p, NULL, NULL); + pa_operation_unref(o); +#endif } /* This is called whenever the context status changes */ @@ -59,26 +94,47 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; - - case PA_CONTEXT_READY: { + case PA_CONTEXT_READY: { + pa_stream_flags_t flags = PA_STREAM_AUTO_TIMING_UPDATE; + pa_buffer_attr attr; static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, - .channels = 1 + .channels = 2 }; - + + pa_zero(attr); + attr.maxlength = (uint32_t) -1; + attr.tlength = latency > 0 ? (uint32_t) pa_usec_to_bytes(latency, &ss) : (uint32_t) -1; + attr.prebuf = (uint32_t) -1; + attr.minreq = (uint32_t) -1; + attr.fragsize = (uint32_t) -1; + +#ifdef INTERPOLATE + flags |= PA_STREAM_INTERPOLATE_TIMING; +#endif + + if (latency > 0) + flags |= PA_STREAM_ADJUST_LATENCY; + fprintf(stderr, "Connection established.\n"); - stream = pa_stream_new(c, "interpol-test", &ss, NULL); - assert(stream); - - pa_stream_connect_playback(stream, NULL, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); - pa_stream_set_write_callback(stream, stream_write_cb, NULL); - + pa_assert_se(stream = pa_stream_new(c, "interpol-test", &ss, NULL)); + + if (playback) { + pa_assert_se(pa_stream_connect_playback(stream, NULL, &attr, flags, NULL, NULL) == 0); + pa_stream_set_write_callback(stream, stream_write_cb, NULL); + } else { + pa_assert_se(pa_stream_connect_record(stream, NULL, &attr, flags) == 0); + pa_stream_set_read_callback(stream, stream_read_cb, NULL); + } + + pa_stream_set_latency_update_callback(stream, stream_latency_cb, NULL); + break; } - + case PA_CONTEXT_TERMINATED: break; @@ -91,70 +147,108 @@ static void context_state_callback(pa_context *c, void *userdata) { int main(int argc, char *argv[]) { pa_threaded_mainloop* m = NULL; - int k, r; + int k; struct timeval start, last_info = { 0, 0 }; pa_usec_t old_t = 0, old_rtc = 0; +#ifdef CORK + pa_bool_t corked = FALSE; +#endif - /* Set up a new main loop */ - m = pa_threaded_mainloop_new(); - assert(m); + pa_log_set_level(PA_LOG_DEBUG); - mainloop_api = pa_threaded_mainloop_get_api(m); + playback = argc <= 1 || !pa_streq(argv[1], "-r"); - context = pa_context_new(mainloop_api, argv[0]); - assert(context); + latency = + (argc >= 2 && !pa_streq(argv[1], "-r")) ? atoi(argv[1]) : + (argc >= 3 ? atoi(argv[2]) : 0); + + /* Set up a new main loop */ + pa_assert_se(m = pa_threaded_mainloop_new()); + pa_assert_se(mainloop_api = pa_threaded_mainloop_get_api(m)); + pa_assert_se(context = pa_context_new(mainloop_api, argv[0])); pa_context_set_state_callback(context, context_state_callback, NULL); - r = pa_context_connect(context, NULL, 0, NULL); - assert(r >= 0); + pa_assert_se(pa_context_connect(context, NULL, 0, NULL) >= 0); pa_gettimeofday(&start); - - pa_threaded_mainloop_start(m); - for (k = 0; k < 5000; k++) { - int success = 0, changed = 0; - pa_usec_t t, rtc; + pa_assert_se(pa_threaded_mainloop_start(m) >= 0); + +/* #ifdef CORK */ + for (k = 0; k < 20000; k++) +/* #else */ +/* for (k = 0; k < 2000; k++) */ +/* #endif */ + { + pa_bool_t success = FALSE, changed = FALSE; + pa_usec_t t, rtc, d; struct timeval now, tv; - + pa_bool_t playing = FALSE; + pa_threaded_mainloop_lock(m); if (stream) { const pa_timing_info *info; - - if (pa_stream_get_time(stream, &t) >= 0) - success = 1; - if ((info = pa_stream_get_timing_info(stream))) - if (last_info.tv_usec != info->timestamp.tv_usec || last_info.tv_sec != info->timestamp.tv_sec) { - changed = 1; + if (pa_stream_get_time(stream, &t) >= 0 && + pa_stream_get_latency(stream, &d, NULL) >= 0) + success = TRUE; + + if ((info = pa_stream_get_timing_info(stream))) { + if (memcmp(&last_info, &info->timestamp, sizeof(struct timeval))) { + changed = TRUE; last_info = info->timestamp; } + if (info->playing) + playing = TRUE; + } } - + pa_threaded_mainloop_unlock(m); - - if (success) { - pa_gettimeofday(&now); + pa_gettimeofday(&now); + + if (success) { +#ifdef CORK + pa_bool_t cork_now; +#endif rtc = pa_timeval_diff(&now, &start); - printf("%i\t%llu\t%llu\t%llu\t%llu\t%u\n", k, rtc, t, rtc-old_rtc, t-old_t, changed); + printf("%i\t%llu\t%llu\t%llu\t%llu\t%lli\t%u\t%u\t%llu\t%llu\n", k, + (unsigned long long) rtc, + (unsigned long long) t, + (unsigned long long) (rtc-old_rtc), + (unsigned long long) (t-old_t), + (signed long long) rtc - (signed long long) t, + changed, + playing, + (unsigned long long) latency, + (unsigned long long) d); + + fflush(stdout); old_t = t; old_rtc = rtc; + +#ifdef CORK + cork_now = (rtc / (2*PA_USEC_PER_SEC)) % 2 == 1; + + if (corked != cork_now) { + pa_threaded_mainloop_lock(m); + pa_operation_unref(pa_stream_cork(stream, cork_now, NULL, NULL)); + pa_threaded_mainloop_unlock(m); + + pa_log(cork_now ? "Corking" : "Uncorking"); + + corked = cork_now; + } +#endif } /* Spin loop, ugly but normal usleep() is just too badly grained */ tv = now; while (pa_timeval_diff(pa_gettimeofday(&now), &tv) < 1000) -#ifdef HAVE_PTHREAD_YIELD - pthread_yield(); -#elif defined(OS_IS_WIN32) - Sleep(0); -#else - ; -#endif + pa_thread_yield(); } if (m) @@ -164,7 +258,7 @@ int main(int argc, char *argv[]) { pa_stream_disconnect(stream); pa_stream_unref(stream); } - + if (context) { pa_context_disconnect(context); pa_context_unref(context); @@ -172,6 +266,6 @@ int main(int argc, char *argv[]) { if (m) pa_threaded_mainloop_free(m); - + return 0; } diff --git a/src/tests/ipacl-test.c b/src/tests/ipacl-test.c index b98151ee..be9caadf 100644 --- a/src/tests/ipacl-test.c +++ b/src/tests/ipacl-test.c @@ -1,30 +1,44 @@ -/* $Id$ */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/ip.h> +#include <sys/types.h> #include <stdio.h> #include <unistd.h> -#include <arpa/inet.h> #include <assert.h> #include <string.h> +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_NETINET_IN_SYSTM_H +#include <netinet/in_systm.h> +#endif +#ifdef HAVE_NETINET_IP_H +#include <netinet/ip.h> +#endif + +#include <pulsecore/socket.h> +#include <pulsecore/macro.h> #include <pulsecore/ipacl.h> +#include <pulsecore/arpa-inet.h> int main(int argc, char *argv[]) { struct sockaddr_in sa; +#ifdef HAVE_IPV6 struct sockaddr_in6 sa6; +#endif int fd; int r; pa_ip_acl *acl; - fd = socket(PF_INET, SOCK_STREAM, 0); + fd = socket(PF_INET, SOCK_STREAM, 0); assert(fd >= 0); - + sa.sin_family = AF_INET; sa.sin_port = htons(22); sa.sin_addr.s_addr = inet_addr("127.0.0.1"); - + r = connect(fd, (struct sockaddr*) &sa, sizeof(sa)); assert(r >= 0); @@ -47,7 +61,7 @@ int main(int argc, char *argv[]) { assert(acl); printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd)); pa_ip_acl_free(acl); - + acl = pa_ip_acl_new("127.0.0.2"); assert(acl); printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd)); @@ -67,17 +81,20 @@ int main(int argc, char *argv[]) { assert(acl); printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd)); pa_ip_acl_free(acl); - + close(fd); - fd = socket(PF_INET6, SOCK_STREAM, 0); - assert(fd >= 0); +#ifdef HAVE_IPV6 + if ( (fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0 ) { + printf("Unable to open IPv6 socket, IPv6 tests ignored"); + return 0; + } memset(&sa6, 0, sizeof(sa6)); sa6.sin6_family = AF_INET6; sa6.sin6_port = htons(22); - inet_pton(AF_INET6, "::1", &sa6.sin6_addr); - + pa_assert_se(inet_pton(AF_INET6, "::1", &sa6.sin6_addr) == 1); + r = connect(fd, (struct sockaddr*) &sa6, sizeof(sa6)); assert(r >= 0); @@ -112,6 +129,7 @@ int main(int argc, char *argv[]) { pa_ip_acl_free(acl); close(fd); - +#endif + return 0; } diff --git a/src/tests/lock-autospawn-test.c b/src/tests/lock-autospawn-test.c new file mode 100644 index 00000000..9ba61296 --- /dev/null +++ b/src/tests/lock-autospawn-test.c @@ -0,0 +1,109 @@ +/*** + This file is part of PulseAudio. + + Copyright 2008 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> + +#include <pulsecore/poll.h> +#include <pulsecore/macro.h> +#include <pulsecore/thread.h> +#include <pulsecore/lock-autospawn.h> +#include <pulse/util.h> + +static void thread_func(void*k) { + pa_assert_se(pa_autospawn_lock_init() >= 0); + + pa_log("%i, Trying to acquire lock.", PA_PTR_TO_INT(k)); + + pa_assert_se(pa_autospawn_lock_acquire(TRUE) > 0); + + pa_log("%i, Got the lock!, Sleeping for 5s", PA_PTR_TO_INT(k)); + + pa_msleep(5000); + + pa_log("%i, Releasing", PA_PTR_TO_INT(k)); + + pa_autospawn_lock_release(); + + pa_autospawn_lock_done(FALSE); +} + +static void thread_func2(void *k) { + int fd; + + pa_assert_se((fd = pa_autospawn_lock_init()) >= 0); + + pa_log("%i, Trying to acquire lock.", PA_PTR_TO_INT(k)); + + for (;;) { + struct pollfd pollfd; + int j; + + if ((j = pa_autospawn_lock_acquire(FALSE)) > 0) + break; + + pa_assert(j == 0); + + memset(&pollfd, 0, sizeof(pollfd)); + pollfd.fd = fd; + pollfd.events = POLLIN; + + pa_assert_se(pa_poll(&pollfd, 1, -1) == 1); + + pa_log("%i, woke up", PA_PTR_TO_INT(k)); + } + + pa_log("%i, Got the lock!, Sleeping for 5s", PA_PTR_TO_INT(k)); + + pa_msleep(5000); + + pa_log("%i, Releasing", PA_PTR_TO_INT(k)); + + pa_autospawn_lock_release(); + + pa_autospawn_lock_done(FALSE); +} + +int main(int argc, char**argv) { + pa_thread *a, *b, *c, *d; + + pa_assert_se((a = pa_thread_new("test1", thread_func, PA_INT_TO_PTR(1)))); + pa_assert_se((b = pa_thread_new("test2", thread_func2, PA_INT_TO_PTR(2)))); + pa_assert_se((c = pa_thread_new("test3", thread_func2, PA_INT_TO_PTR(3)))); + pa_assert_se((d = pa_thread_new("test4", thread_func, PA_INT_TO_PTR(4)))); + + pa_thread_join(a); + pa_thread_join(b); + pa_thread_join(c); + pa_thread_join(d); + + pa_thread_free(a); + pa_thread_free(b); + pa_thread_free(c); + pa_thread_free(d); + + pa_log("End"); + + return 0; +} diff --git a/src/tests/mainloop-test.c b/src/tests/mainloop-test.c index b06d0ed1..ab23de43 100644 --- a/src/tests/mainloop-test.c +++ b/src/tests/mainloop-test.c @@ -1,18 +1,16 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -28,10 +26,11 @@ #include <sys/time.h> #include <assert.h> +#include <pulse/rtclock.h> #include <pulse/timeval.h> #include <pulsecore/core-util.h> -#include <pulsecore/gccmacro.h> +#include <pulsecore/core-rtclock.h> #ifdef GLIB_MAIN_LOOP @@ -48,7 +47,7 @@ static pa_defer_event *de; static void iocb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { unsigned char c; - read(fd, &c, sizeof(c)); + pa_assert_se(read(fd, &c, sizeof(c)) >= 0); fprintf(stderr, "IO EVENT: %c\n", c < 32 ? '.' : c); a->defer_enable(de, 1); } @@ -68,7 +67,7 @@ static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, v #endif } -int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { +int main(int argc, char *argv[]) { pa_mainloop_api *a; pa_io_event *ioe; pa_time_event *te; @@ -101,9 +100,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { de = a->defer_new(a, dcb, NULL); assert(de); - pa_gettimeofday(&tv); - tv.tv_sec += 10; - te = a->time_new(a, &tv, tcb, NULL); + te = a->time_new(a, pa_timeval_rtstore(&tv, pa_rtclock_now() + 2 * PA_USEC_PER_SEC, TRUE), tcb, NULL); #if defined(GLIB_MAIN_LOOP) g_main_loop_run(glib_main_loop); @@ -121,6 +118,6 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { #else pa_mainloop_free(m); #endif - + return 0; } diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c index 7a68e6de..75a71dd1 100644 --- a/src/tests/mcalign-test.c +++ b/src/tests/mcalign-test.c @@ -1,18 +1,16 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -33,45 +31,54 @@ #include <pulsecore/core-util.h> #include <pulsecore/mcalign.h> -#include <pulsecore/gccmacro.h> /* A simple program for testing pa_mcalign */ -int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { - pa_mcalign *a = pa_mcalign_new(11, NULL); +int main(int argc, char *argv[]) { + pa_mempool *p; + pa_mcalign *a; pa_memchunk c; + p = pa_mempool_new(FALSE, 0); + + a = pa_mcalign_new(11); + pa_memchunk_reset(&c); - srand(time(NULL)); + srand((unsigned) time(NULL)); for (;;) { ssize_t r; size_t l; if (!c.memblock) { - c.memblock = pa_memblock_new(2048, NULL); + c.memblock = pa_memblock_new(p, 2048); c.index = c.length = 0; } - assert(c.index < c.memblock->length); + assert(c.index < pa_memblock_get_length(c.memblock)); + + l = pa_memblock_get_length(c.memblock) - c.index; + + l = l <= 1 ? l : (size_t) rand() % (l-1) +1; - l = c.memblock->length - c.index; + p = pa_memblock_acquire(c.memblock); - l = l <= 1 ? l : rand() % (l-1) +1 ; - - if ((r = read(STDIN_FILENO, (uint8_t*) c.memblock->data + c.index, l)) <= 0) { + if ((r = read(STDIN_FILENO, (uint8_t*) p + c.index, l)) <= 0) { + pa_memblock_release(c.memblock); fprintf(stderr, "read() failed: %s\n", r < 0 ? strerror(errno) : "EOF"); break; } - c.length = r; + pa_memblock_release(c.memblock); + + c.length = (size_t) r; pa_mcalign_push(a, &c); fprintf(stderr, "Read %ld bytes\n", (long)r); - c.index += r; + c.index += (size_t) r; - if (c.index >= c.memblock->length) { + if (c.index >= pa_memblock_get_length(c.memblock)) { pa_memblock_unref(c.memblock); pa_memchunk_reset(&c); } @@ -82,7 +89,9 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { if (pa_mcalign_pop(a, &t) < 0) break; - pa_loop_write(STDOUT_FILENO, (uint8_t*) t.memblock->data + t.index, t.length, NULL); + p = pa_memblock_acquire(t.memblock); + pa_loop_write(STDOUT_FILENO, (uint8_t*) p + t.index, t.length, NULL); + pa_memblock_release(t.memblock); fprintf(stderr, "Wrote %lu bytes.\n", (unsigned long) t.length); pa_memblock_unref(t.memblock); @@ -94,5 +103,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { if (c.memblock) pa_memblock_unref(c.memblock); + pa_mempool_free(p); + return 0; } diff --git a/src/tests/memblock-test.c b/src/tests/memblock-test.c new file mode 100644 index 00000000..9cf6c78b --- /dev/null +++ b/src/tests/memblock-test.c @@ -0,0 +1,174 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <unistd.h> + +#include <pulsecore/memblock.h> +#include <pulsecore/macro.h> +#include <pulse/xmalloc.h> + +static void release_cb(pa_memimport *i, uint32_t block_id, void *userdata) { + printf("%s: Imported block %u is released.\n", (char*) userdata, block_id); +} + +static void revoke_cb(pa_memexport *e, uint32_t block_id, void *userdata) { + printf("%s: Exported block %u is revoked.\n", (char*) userdata, block_id); +} + +static void print_stats(pa_mempool *p, const char *text) { + const pa_mempool_stat*s = pa_mempool_get_stat(p); + + printf("%s = {\n" + "n_allocated = %u\n" + "n_accumulated = %u\n" + "n_imported = %u\n" + "n_exported = %u\n" + "allocated_size = %u\n" + "accumulated_size = %u\n" + "imported_size = %u\n" + "exported_size = %u\n" + "n_too_large_for_pool = %u\n" + "n_pool_full = %u\n" + "}\n", + text, + (unsigned) pa_atomic_load(&s->n_allocated), + (unsigned) pa_atomic_load(&s->n_accumulated), + (unsigned) pa_atomic_load(&s->n_imported), + (unsigned) pa_atomic_load(&s->n_exported), + (unsigned) pa_atomic_load(&s->allocated_size), + (unsigned) pa_atomic_load(&s->accumulated_size), + (unsigned) pa_atomic_load(&s->imported_size), + (unsigned) pa_atomic_load(&s->exported_size), + (unsigned) pa_atomic_load(&s->n_too_large_for_pool), + (unsigned) pa_atomic_load(&s->n_pool_full)); +} + +int main(int argc, char *argv[]) { + pa_mempool *pool_a, *pool_b, *pool_c; + unsigned id_a, id_b, id_c; + pa_memexport *export_a, *export_b; + pa_memimport *import_b, *import_c; + pa_memblock *mb_a, *mb_b, *mb_c; + int r, i; + pa_memblock* blocks[5]; + uint32_t id, shm_id; + size_t offset, size; + char *x; + + const char txt[] = "This is a test!"; + + pool_a = pa_mempool_new(TRUE, 0); + pool_b = pa_mempool_new(TRUE, 0); + pool_c = pa_mempool_new(TRUE, 0); + + pa_mempool_get_shm_id(pool_a, &id_a); + pa_mempool_get_shm_id(pool_b, &id_b); + pa_mempool_get_shm_id(pool_c, &id_c); + + pa_assert(pool_a && pool_b && pool_c); + + blocks[0] = pa_memblock_new_fixed(pool_a, (void*) txt, sizeof(txt), 1); + + blocks[1] = pa_memblock_new(pool_a, sizeof(txt)); + x = pa_memblock_acquire(blocks[1]); + snprintf(x, pa_memblock_get_length(blocks[1]), "%s", txt); + pa_memblock_release(blocks[1]); + + blocks[2] = pa_memblock_new_pool(pool_a, sizeof(txt)); + x = pa_memblock_acquire(blocks[2]); + snprintf(x, pa_memblock_get_length(blocks[2]), "%s", txt); + pa_memblock_release(blocks[2]); + + blocks[3] = pa_memblock_new_malloced(pool_a, pa_xstrdup(txt), sizeof(txt)); + blocks[4] = NULL; + + for (i = 0; blocks[i]; i++) { + printf("Memory block %u\n", i); + + mb_a = blocks[i]; + pa_assert(mb_a); + + export_a = pa_memexport_new(pool_a, revoke_cb, (void*) "A"); + export_b = pa_memexport_new(pool_b, revoke_cb, (void*) "B"); + + pa_assert(export_a && export_b); + + import_b = pa_memimport_new(pool_b, release_cb, (void*) "B"); + import_c = pa_memimport_new(pool_c, release_cb, (void*) "C"); + + pa_assert(import_b && import_c); + + r = pa_memexport_put(export_a, mb_a, &id, &shm_id, &offset, &size); + pa_assert(r >= 0); + pa_assert(shm_id == id_a); + + printf("A: Memory block exported as %u\n", id); + + mb_b = pa_memimport_get(import_b, id, shm_id, offset, size); + pa_assert(mb_b); + r = pa_memexport_put(export_b, mb_b, &id, &shm_id, &offset, &size); + pa_assert(r >= 0); + pa_assert(shm_id == id_a || shm_id == id_b); + pa_memblock_unref(mb_b); + + printf("B: Memory block exported as %u\n", id); + + mb_c = pa_memimport_get(import_c, id, shm_id, offset, size); + pa_assert(mb_c); + x = pa_memblock_acquire(mb_c); + printf("1 data=%s\n", x); + pa_memblock_release(mb_c); + + print_stats(pool_a, "A"); + print_stats(pool_b, "B"); + print_stats(pool_c, "C"); + + pa_memexport_free(export_b); + x = pa_memblock_acquire(mb_c); + printf("2 data=%s\n", x); + pa_memblock_release(mb_c); + pa_memblock_unref(mb_c); + + pa_memimport_free(import_b); + + pa_memblock_unref(mb_a); + + pa_memimport_free(import_c); + pa_memexport_free(export_a); + } + + printf("vaccuuming...\n"); + + pa_mempool_vacuum(pool_a); + pa_mempool_vacuum(pool_b); + pa_mempool_vacuum(pool_c); + + printf("vaccuuming done...\n"); + + pa_mempool_free(pool_a); + pa_mempool_free(pool_b); + pa_mempool_free(pool_c); + + return 0; +} diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c index af43d06f..b6c60039 100644 --- a/src/tests/memblockq-test.c +++ b/src/tests/memblockq-test.c @@ -1,18 +1,16 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -26,122 +24,157 @@ #include <stdlib.h> #include <assert.h> #include <stdio.h> +#include <signal.h> #include <pulsecore/memblockq.h> #include <pulsecore/log.h> +static void dump_chunk(const pa_memchunk *chunk) { + size_t n; + void *q; + char *e; + + pa_assert(chunk); + + q = pa_memblock_acquire(chunk->memblock); + for (e = (char*) q + chunk->index, n = 0; n < chunk->length; n++, e++) + printf("%c", *e); + pa_memblock_release(chunk->memblock); +} + +static void dump(pa_memblockq *bq) { + pa_memchunk out; + + pa_assert(bq); + + /* First let's dump this as fixed block */ + printf("FIXED >"); + pa_memblockq_peek_fixed_size(bq, 64, &out); + dump_chunk(&out); + pa_memblock_unref(out.memblock); + printf("<\n"); + + /* Then let's dump the queue manually */ + printf("MANUAL>"); + + for (;;) { + if (pa_memblockq_peek(bq, &out) < 0) + break; + + dump_chunk(&out); + pa_memblock_unref(out.memblock); + pa_memblockq_drop(bq, out.length); + } + + printf("<\n"); +} + int main(int argc, char *argv[]) { int ret; + + pa_mempool *p; pa_memblockq *bq; pa_memchunk chunk1, chunk2, chunk3, chunk4; - pa_memblock *silence; + pa_memchunk silence; - pa_log_set_maximal_level(PA_LOG_DEBUG); - - silence = pa_memblock_new_fixed((char*) "__", 2, 1, NULL); - assert(silence); + pa_log_set_level(PA_LOG_DEBUG); - bq = pa_memblockq_new(0, 40, 10, 2, 4, 4, silence, NULL); + p = pa_mempool_new(FALSE, 0); + + silence.memblock = pa_memblock_new_fixed(p, (char*) "__", 2, 1); + assert(silence.memblock); + silence.index = 0; + silence.length = pa_memblock_get_length(silence.memblock); + + bq = pa_memblockq_new(0, 200, 10, 2, 4, 4, 40, &silence); assert(bq); - chunk1.memblock = pa_memblock_new_fixed((char*) "AA", 2, 1, NULL); + chunk1.memblock = pa_memblock_new_fixed(p, (char*) "11", 2, 1); chunk1.index = 0; chunk1.length = 2; assert(chunk1.memblock); - - chunk2.memblock = pa_memblock_new_fixed((char*) "TTBB", 4, 1, NULL); + + chunk2.memblock = pa_memblock_new_fixed(p, (char*) "XX22", 4, 1); chunk2.index = 2; chunk2.length = 2; assert(chunk2.memblock); - chunk3.memblock = pa_memblock_new_fixed((char*) "ZZZZ", 4, 1, NULL); + chunk3.memblock = pa_memblock_new_fixed(p, (char*) "3333", 4, 1); chunk3.index = 0; chunk3.length = 4; assert(chunk3.memblock); - chunk4.memblock = pa_memblock_new_fixed((char*) "KKKKKKKK", 8, 1, NULL); + chunk4.memblock = pa_memblock_new_fixed(p, (char*) "44444444", 8, 1); chunk4.index = 0; chunk4.length = 8; assert(chunk4.memblock); ret = pa_memblockq_push(bq, &chunk1); assert(ret == 0); - - ret = pa_memblockq_push(bq, &chunk1); - assert(ret == 0); - - ret = pa_memblockq_push(bq, &chunk2); - assert(ret == 0); - + ret = pa_memblockq_push(bq, &chunk2); assert(ret == 0); - pa_memblockq_seek(bq, -6, 0); ret = pa_memblockq_push(bq, &chunk3); assert(ret == 0); - pa_memblockq_seek(bq, -2, 0); + ret = pa_memblockq_push(bq, &chunk4); + assert(ret == 0); + + pa_memblockq_seek(bq, -6, 0, TRUE); ret = pa_memblockq_push(bq, &chunk3); assert(ret == 0); - pa_memblockq_seek(bq, -10, 0); + pa_memblockq_seek(bq, -2, 0, TRUE); + ret = pa_memblockq_push(bq, &chunk1); + assert(ret == 0); + + pa_memblockq_seek(bq, -10, 0, TRUE); ret = pa_memblockq_push(bq, &chunk4); assert(ret == 0); - pa_memblockq_seek(bq, 10, 0); + pa_memblockq_seek(bq, 10, 0, TRUE); ret = pa_memblockq_push(bq, &chunk1); assert(ret == 0); - pa_memblockq_seek(bq, -6, 0); + pa_memblockq_seek(bq, -6, 0, TRUE); ret = pa_memblockq_push(bq, &chunk2); assert(ret == 0); /* Test splitting */ - pa_memblockq_seek(bq, -12, 0); + pa_memblockq_seek(bq, -12, 0, TRUE); ret = pa_memblockq_push(bq, &chunk1); assert(ret == 0); - pa_memblockq_seek(bq, 20, 0); + pa_memblockq_seek(bq, 20, 0, TRUE); /* Test merging */ ret = pa_memblockq_push(bq, &chunk3); assert(ret == 0); - pa_memblockq_seek(bq, -2, 0); + pa_memblockq_seek(bq, -2, 0, TRUE); chunk3.index += 2; chunk3.length -= 2; - ret = pa_memblockq_push(bq, &chunk3); assert(ret == 0); - - printf(">"); - pa_memblockq_shorten(bq, 6); - - for (;;) { - pa_memchunk out; - char *e; - size_t n; - - if (pa_memblockq_peek(bq, &out) < 0) - break; + pa_memblockq_seek(bq, 30, PA_SEEK_RELATIVE, TRUE); - for (e = (char*) out.memblock->data + out.index, n = 0; n < out.length; n++) - printf("%c", *e); + dump(bq); + + pa_memblockq_rewind(bq, 52); + + dump(bq); - pa_memblock_unref(out.memblock); - pa_memblockq_drop(bq, &out, out.length); - } - - printf("<\n"); - pa_memblockq_free(bq); - pa_memblock_unref(silence); + pa_memblock_unref(silence.memblock); pa_memblock_unref(chunk1.memblock); pa_memblock_unref(chunk2.memblock); pa_memblock_unref(chunk3.memblock); pa_memblock_unref(chunk4.memblock); - + + pa_mempool_free(p); + return 0; } diff --git a/src/tests/mix-test.c b/src/tests/mix-test.c new file mode 100644 index 00000000..7c05b8ed --- /dev/null +++ b/src/tests/mix-test.c @@ -0,0 +1,264 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> + +#include <pulse/sample.h> +#include <pulse/volume.h> + +#include <pulsecore/macro.h> +#include <pulsecore/endianmacros.h> +#include <pulsecore/memblock.h> +#include <pulsecore/sample-util.h> + +static void dump_block(const pa_sample_spec *ss, const pa_memchunk *chunk) { + void *d; + unsigned i; + + d = pa_memblock_acquire(chunk->memblock); + + switch (ss->format) { + + case PA_SAMPLE_U8: + case PA_SAMPLE_ULAW: + case PA_SAMPLE_ALAW: { + uint8_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) + printf("0x%02x ", *(u++)); + + break; + } + + case PA_SAMPLE_S16NE: + case PA_SAMPLE_S16RE: { + uint16_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) + printf("0x%04x ", *(u++)); + + break; + } + + case PA_SAMPLE_S24_32NE: + case PA_SAMPLE_S24_32RE: + case PA_SAMPLE_S32NE: + case PA_SAMPLE_S32RE: { + uint32_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) + printf("0x%08x ", *(u++)); + + break; + } + + case PA_SAMPLE_S24NE: + case PA_SAMPLE_S24RE: { + uint8_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) { + printf("0x%02x%02x%02xx ", *u, *(u+1), *(u+2)); + u += 3; + } + + break; + } + + case PA_SAMPLE_FLOAT32NE: + case PA_SAMPLE_FLOAT32RE: { + float *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) { + printf("%1.5f ", ss->format == PA_SAMPLE_FLOAT32NE ? *u : PA_FLOAT32_SWAP(*u)); + u++; + } + + break; + } + + default: + pa_assert_not_reached(); + } + + printf("\n"); + + pa_memblock_release(chunk->memblock); +} + +static pa_memblock* generate_block(pa_mempool *pool, const pa_sample_spec *ss) { + pa_memblock *r; + void *d; + unsigned i; + + pa_assert_se(r = pa_memblock_new(pool, pa_frame_size(ss) * 10)); + d = pa_memblock_acquire(r); + + switch (ss->format) { + + case PA_SAMPLE_U8: + case PA_SAMPLE_ULAW: + case PA_SAMPLE_ALAW: { + static const uint8_t u8_samples[] = { + 0x00, 0xFF, 0x7F, 0x80, 0x9f, + 0x3f, 0x01, 0xF0, 0x20, 0x21 + }; + + memcpy(d, u8_samples, sizeof(u8_samples)); + break; + } + + case PA_SAMPLE_S16NE: + case PA_SAMPLE_S16RE: { + static const uint16_t u16_samples[] = { + 0x0000, 0xFFFF, 0x7FFF, 0x8000, 0x9fff, + 0x3fff, 0x0001, 0xF000, 0x0020, 0x0021 + }; + + memcpy(d, u16_samples, sizeof(u16_samples)); + break; + } + + case PA_SAMPLE_S24_32NE: + case PA_SAMPLE_S24_32RE: + case PA_SAMPLE_S32NE: + case PA_SAMPLE_S32RE: { + static const uint32_t u32_samples[] = { + 0x00000001, 0xFFFF0002, 0x7FFF0003, 0x80000004, 0x9fff0005, + 0x3fff0006, 0x00010007, 0xF0000008, 0x00200009, 0x0021000A + }; + + memcpy(d, u32_samples, sizeof(u32_samples)); + break; + } + + case PA_SAMPLE_S24NE: + case PA_SAMPLE_S24RE: { + /* Need to be on a byte array because they are not aligned */ + static const uint8_t u24_samples[] = { + 0x00, 0x00, 0x01, + 0xFF, 0xFF, 0x02, + 0x7F, 0xFF, 0x03, + 0x80, 0x00, 0x04, + 0x9f, 0xff, 0x05, + 0x3f, 0xff, 0x06, + 0x01, 0x00, 0x07, + 0xF0, 0x00, 0x08, + 0x20, 0x00, 0x09, + 0x21, 0x00, 0x0A + }; + + memcpy(d, u24_samples, sizeof(u24_samples)); + break; + } + + case PA_SAMPLE_FLOAT32NE: + case PA_SAMPLE_FLOAT32RE: { + float *u = d; + static const float float_samples[] = { + 0.0f, -1.0f, 1.0f, 4711.0f, 0.222f, + 0.33f, -.3f, 99.0f, -0.555f, -.123f + }; + + if (ss->format == PA_SAMPLE_FLOAT32RE) { + for (i = 0; i < 10; i++) + u[i] = PA_FLOAT32_SWAP(float_samples[i]); + } else + memcpy(d, float_samples, sizeof(float_samples)); + + break; + } + + default: + pa_assert_not_reached(); + } + + pa_memblock_release(r); + + return r; +} + +int main(int argc, char *argv[]) { + pa_mempool *pool; + pa_sample_spec a; + pa_cvolume v; + + pa_log_set_level(PA_LOG_DEBUG); + + pa_assert_se(pool = pa_mempool_new(FALSE, 0)); + + a.channels = 1; + a.rate = 44100; + + v.channels = a.channels; + v.values[0] = pa_sw_volume_from_linear(0.9); + + for (a.format = 0; a.format < PA_SAMPLE_MAX; a.format ++) { + pa_memchunk i, j, k; + pa_mix_info m[2]; + void *ptr; + + printf("=== mixing: %s\n", pa_sample_format_to_string(a.format)); + + /* Generate block */ + i.memblock = generate_block(pool, &a); + i.length = pa_memblock_get_length(i.memblock); + i.index = 0; + + dump_block(&a, &i); + + /* Make a copy */ + j = i; + pa_memblock_ref(j.memblock); + pa_memchunk_make_writable(&j, 0); + + /* Adjust volume of the copy */ + pa_volume_memchunk(&j, &a, &v); + + dump_block(&a, &j); + + m[0].chunk = i; + m[0].volume.values[0] = PA_VOLUME_NORM; + m[0].volume.channels = a.channels; + m[1].chunk = j; + m[1].volume.values[0] = PA_VOLUME_NORM; + m[1].volume.channels = a.channels; + + k.memblock = pa_memblock_new(pool, i.length); + k.length = i.length; + k.index = 0; + + ptr = (uint8_t*) pa_memblock_acquire(k.memblock) + k.index; + pa_mix(m, 2, ptr, k.length, &a, NULL, FALSE); + pa_memblock_release(k.memblock); + + dump_block(&a, &k); + + pa_memblock_unref(i.memblock); + pa_memblock_unref(j.memblock); + pa_memblock_unref(k.memblock); + } + + pa_mempool_free(pool); + + return 0; +} diff --git a/src/tests/once-test.c b/src/tests/once-test.c new file mode 100644 index 00000000..8a9995da --- /dev/null +++ b/src/tests/once-test.c @@ -0,0 +1,111 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_PTHREAD +#include <pthread.h> +#endif + +#include <pulsecore/thread.h> +#include <pulsecore/once.h> +#include <pulsecore/log.h> +#include <pulsecore/core-util.h> +#include <pulsecore/atomic.h> +#include <pulse/xmalloc.h> + +static pa_once once = PA_ONCE_INIT; +static volatile unsigned n_run = 0; +static const char * volatile ran_by = NULL; +#ifdef HAVE_PTHREAD +static pthread_barrier_t barrier; +#endif +static unsigned n_cpu; + +#define N_ITERATIONS 500 +#define N_THREADS 100 + +static void once_func(void) { + n_run++; + ran_by = (const char*) pa_thread_get_data(pa_thread_self()); +} + +static void thread_func(void *data) { +#ifdef HAVE_PTHREAD + int r; + +#ifdef HAVE_PTHREAD_SETAFFINITY_NP + static pa_atomic_t i_cpu = PA_ATOMIC_INIT(0); + cpu_set_t mask; + + CPU_ZERO(&mask); + CPU_SET((size_t) (pa_atomic_inc(&i_cpu) % n_cpu), &mask); + pa_assert_se(pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) == 0); +#endif + + /* pa_log("started up: %s", data); */ + + r = pthread_barrier_wait(&barrier); + pa_assert(r == 0 || r == PTHREAD_BARRIER_SERIAL_THREAD); +#endif /* HAVE_PTHREAD */ + + pa_run_once(&once, once_func); +} + +int main(int argc, char *argv[]) { + unsigned n, i; + + n_cpu = pa_ncpus(); + + for (n = 0; n < N_ITERATIONS; n++) { + pa_thread* threads[N_THREADS]; + +#ifdef HAVE_PTHREAD + pa_assert_se(pthread_barrier_init(&barrier, NULL, N_THREADS) == 0); +#endif + + /* Yes, kinda ugly */ + pa_zero(once); + + for (i = 0; i < N_THREADS; i++) + threads[i] = pa_thread_new("once", thread_func, pa_sprintf_malloc("Thread #%i", i+1)); + + for (i = 0; i < N_THREADS; i++) + pa_thread_join(threads[i]); + + pa_assert(n_run == 1); + pa_log("ran by %s", ran_by); + + for (i = 0; i < N_THREADS; i++) { + pa_xfree(pa_thread_get_data(threads[i])); + pa_thread_free(threads[i]); + } + + n_run = 0; + ran_by = NULL; + +#ifdef HAVE_PTHREAD + pa_assert_se(pthread_barrier_destroy(&barrier) == 0); +#endif + } + + return 0; +} diff --git a/src/tests/pacat-simple.c b/src/tests/pacat-simple.c index 364e1ad6..7d119c44 100644 --- a/src/tests/pacat-simple.c +++ b/src/tests/pacat-simple.c @@ -1,18 +1,16 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -31,11 +29,10 @@ #include <pulse/simple.h> #include <pulse/error.h> -#include <pulsecore/gccmacro.h> #define BUFSIZE 1024 -int main(PA_GCC_UNUSED int argc, char*argv[]) { +int main(int argc, char*argv[]) { /* The Sample format to use */ static const pa_sample_spec ss = { @@ -43,7 +40,7 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { .rate = 44100, .channels = 2 }; - + pa_simple *s = NULL; int ret = 1; int error; @@ -61,10 +58,10 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { fprintf(stderr, __FILE__": dup2() failed: %s\n", strerror(errno)); goto finish; } - + close(fd); } - + /* Create a new playback stream */ if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); @@ -90,13 +87,13 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { if ((r = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) { if (r == 0) /* EOF */ break; - + fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno)); goto finish; } /* ... and play it */ - if (pa_simple_write(s, buf, r, &error) < 0) { + if (pa_simple_write(s, buf, (size_t) r, &error) < 0) { fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error)); goto finish; } @@ -114,6 +111,6 @@ finish: if (s) pa_simple_free(s); - + return ret; } diff --git a/src/tests/parec-simple.c b/src/tests/parec-simple.c index 45a52288..dfa43f0f 100644 --- a/src/tests/parec-simple.c +++ b/src/tests/parec-simple.c @@ -1,18 +1,16 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -30,7 +28,6 @@ #include <pulse/simple.h> #include <pulse/error.h> -#include <pulsecore/gccmacro.h> #define BUFSIZE 1024 @@ -46,16 +43,16 @@ static ssize_t loop_write(int fd, const void*data, size_t size) { if (r == 0) break; - + ret += r; data = (const uint8_t*) data + r; - size -= r; + size -= (size_t) r; } return ret; } -int main(PA_GCC_UNUSED int argc, char*argv[]) { +int main(int argc, char*argv[]) { /* The sample type to use */ static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, @@ -74,7 +71,6 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { for (;;) { uint8_t buf[BUFSIZE]; - ssize_t r; /* Record some data ... */ if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) { @@ -83,7 +79,7 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { } /* And write it to STDOUT */ - if ((r = loop_write(STDOUT_FILENO, buf, sizeof(buf))) <= 0) { + if (loop_write(STDOUT_FILENO, buf, sizeof(buf)) != sizeof(buf)) { fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno)); goto finish; } @@ -95,6 +91,6 @@ finish: if (s) pa_simple_free(s); - + return ret; } diff --git a/src/tests/prioq-test.c b/src/tests/prioq-test.c new file mode 100644 index 00000000..120b512b --- /dev/null +++ b/src/tests/prioq-test.c @@ -0,0 +1,44 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <pulsecore/prioq.h> +#include <pulsecore/macro.h> + +#define N 1024 + +int main(int argc, char *argv[]) { + pa_prioq *q; + unsigned i; + + srand(0); + + q = pa_prioq_new(pa_idxset_trivial_compare_func); + + /* Fill in 1024 */ + for (i = 0; i < N; i++) + pa_prioq_put(q, PA_UINT_TO_PTR((unsigned) rand())); + + /* Remove half of it again */ + for (i = 0; i < N/2; i++){ + unsigned u = PA_PTR_TO_UINT(pa_prioq_pop(q)); + pa_log("%16u", u); + } + + pa_log("Refilling"); + + /* Fill in another 1024 */ + for (i = 0; i < N; i++) + pa_prioq_put(q, PA_UINT_TO_PTR((unsigned) rand())); + + + /* Remove everything */ + while (!pa_prioq_isempty(q)) { + unsigned u = PA_PTR_TO_UINT(pa_prioq_pop(q)); + pa_log("%16u", u); + } + + pa_prioq_free(q, NULL, NULL); + + return 0; +} diff --git a/src/tests/proplist-test.c b/src/tests/proplist-test.c new file mode 100644 index 00000000..27a0d3fe --- /dev/null +++ b/src/tests/proplist-test.c @@ -0,0 +1,96 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> + +#include <pulse/proplist.h> +#include <pulse/xmalloc.h> +#include <pulsecore/macro.h> +#include <pulsecore/core-util.h> +#include <pulsecore/modargs.h> + +int main(int argc, char*argv[]) { + pa_modargs *ma; + pa_proplist *a, *b, *c, *d; + char *s, *t, *u, *v; + const char *text; + const char *x[] = { "foo", NULL }; + + a = pa_proplist_new(); + pa_assert_se(pa_proplist_sets(a, PA_PROP_MEDIA_TITLE, "Brandenburgische Konzerte") == 0); + pa_assert_se(pa_proplist_sets(a, PA_PROP_MEDIA_ARTIST, "Johann Sebastian Bach") == 0); + + b = pa_proplist_new(); + pa_assert_se(pa_proplist_sets(b, PA_PROP_MEDIA_TITLE, "Goldbergvariationen") == 0); + pa_assert_se(pa_proplist_set(b, PA_PROP_MEDIA_ICON, "\0\1\2\3\4\5\6\7", 8) == 0); + + pa_proplist_update(a, PA_UPDATE_MERGE, b); + + pa_assert_se(!pa_proplist_gets(a, PA_PROP_MEDIA_ICON)); + + printf("%s\n", pa_strnull(pa_proplist_gets(a, PA_PROP_MEDIA_TITLE))); + pa_assert_se(pa_proplist_unset(b, PA_PROP_MEDIA_TITLE) == 0); + + s = pa_proplist_to_string(a); + t = pa_proplist_to_string(b); + printf("---\n%s---\n%s", s, t); + + c = pa_proplist_from_string(s); + u = pa_proplist_to_string(c); + pa_assert_se(pa_streq(s, u)); + + pa_xfree(s); + pa_xfree(t); + pa_xfree(u); + + pa_proplist_free(a); + pa_proplist_free(b); + pa_proplist_free(c); + + text = " eins = zwei drei = \"\\\"vier\\\"\" fuenf=sechs sieben ='\\a\\c\\h\\t\\'\\\"' neun= hex:0123456789abCDef "; + + printf("%s\n", text); + d = pa_proplist_from_string(text); + v = pa_proplist_to_string(d); + pa_proplist_free(d); + printf("%s\n", v); + d = pa_proplist_from_string(v); + pa_xfree(v); + v = pa_proplist_to_string(d); + pa_proplist_free(d); + printf("%s\n", v); + pa_xfree(v); + + pa_assert_se(ma = pa_modargs_new("foo='foobar=waldo foo2=\"lj\\\\\"dhflh\" foo3=\\'kjlskj\\\\\\'\\''", x)); + pa_assert_se(a = pa_proplist_new()); + + pa_assert_se(pa_modargs_get_proplist(ma, "foo", a, PA_UPDATE_REPLACE) >= 0); + + printf("%s\n", v = pa_proplist_to_string(a)); + pa_xfree(v); + + pa_proplist_free(a); + pa_modargs_free(ma); + + return 0; +} diff --git a/src/tests/queue-test.c b/src/tests/queue-test.c new file mode 100644 index 00000000..b21775e8 --- /dev/null +++ b/src/tests/queue-test.c @@ -0,0 +1,64 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> +#include <unistd.h> + +#include <pulsecore/queue.h> +#include <pulsecore/log.h> +#include <pulsecore/macro.h> + +int main(int argc, char *argv[]) { + pa_queue *q; + + pa_assert_se(q = pa_queue_new()); + + pa_assert(pa_queue_isempty(q)); + + pa_queue_push(q, (void*) "eins"); + pa_log("%s\n", (char*) pa_queue_pop(q)); + + pa_assert(pa_queue_isempty(q)); + + pa_queue_push(q, (void*) "zwei"); + pa_queue_push(q, (void*) "drei"); + pa_queue_push(q, (void*) "vier"); + + pa_log("%s\n", (char*) pa_queue_pop(q)); + pa_log("%s\n", (char*) pa_queue_pop(q)); + + pa_queue_push(q, (void*) "fuenf"); + + pa_log("%s\n", (char*) pa_queue_pop(q)); + pa_log("%s\n", (char*) pa_queue_pop(q)); + + pa_assert(pa_queue_isempty(q)); + + pa_queue_push(q, (void*) "sechs"); + pa_queue_push(q, (void*) "sieben"); + + pa_queue_free(q, NULL, NULL); + + return 0; +} diff --git a/src/tests/remix-test.c b/src/tests/remix-test.c new file mode 100644 index 00000000..19f5582b --- /dev/null +++ b/src/tests/remix-test.c @@ -0,0 +1,83 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> + +#include <pulse/sample.h> + +#include <pulsecore/resampler.h> +#include <pulsecore/macro.h> +#include <pulsecore/memblock.h> + +int main(int argc, char *argv[]) { + + static const pa_channel_map maps[] = { + { 1, { PA_CHANNEL_POSITION_MONO } }, + { 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT } }, + { 3, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_CENTER } }, + { 3, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_LFE } }, + { 3, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_REAR_CENTER } }, + { 4, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_LFE } }, + { 4, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_REAR_CENTER } }, + { 4, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT } }, + { 5, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_CENTER } }, + { 5, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_LFE } }, + { 6, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_LFE, PA_CHANNEL_POSITION_CENTER } }, + { 8, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT, PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_LFE, PA_CHANNEL_POSITION_CENTER, PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT } }, + { 0, { 0 } } + }; + + unsigned i, j; + pa_mempool *pool; + + pa_log_set_level(PA_LOG_DEBUG); + + pa_assert_se(pool = pa_mempool_new(FALSE, 0)); + + for (i = 0; maps[i].channels > 0; i++) + for (j = 0; maps[j].channels > 0; j++) { + char a[PA_CHANNEL_MAP_SNPRINT_MAX], b[PA_CHANNEL_MAP_SNPRINT_MAX]; + pa_resampler *r; + pa_sample_spec ss1, ss2; + + pa_log_info("Converting from '%s' to '%s'.\n", pa_channel_map_snprint(a, sizeof(a), &maps[i]), pa_channel_map_snprint(b, sizeof(b), &maps[j])); + + ss1.channels = maps[i].channels; + ss2.channels = maps[j].channels; + + ss1.rate = ss2.rate = 44100; + ss1.format = ss2.format = PA_SAMPLE_S16NE; + + r = pa_resampler_new(pool, &ss1, &maps[i], &ss2, &maps[j], PA_RESAMPLER_AUTO, 0); + + /* We don't really care for the resampler. We just want to + * see the remixing debug output. */ + + pa_resampler_free(r); + } + + + pa_mempool_free(pool); + + return 0; +} diff --git a/src/tests/resampler-test.c b/src/tests/resampler-test.c new file mode 100644 index 00000000..78461da5 --- /dev/null +++ b/src/tests/resampler-test.c @@ -0,0 +1,487 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <getopt.h> +#include <locale.h> + +#include <pulse/i18n.h> +#include <pulse/pulseaudio.h> + +#include <pulse/rtclock.h> +#include <pulse/sample.h> +#include <pulse/volume.h> + +#include <pulsecore/resampler.h> +#include <pulsecore/macro.h> +#include <pulsecore/endianmacros.h> +#include <pulsecore/memblock.h> +#include <pulsecore/sample-util.h> +#include <pulsecore/core-util.h> + +static void dump_block(const pa_sample_spec *ss, const pa_memchunk *chunk) { + void *d; + unsigned i; + + d = pa_memblock_acquire(chunk->memblock); + + switch (ss->format) { + + case PA_SAMPLE_U8: + case PA_SAMPLE_ULAW: + case PA_SAMPLE_ALAW: { + uint8_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) + printf(" 0x%02x ", *(u++)); + + break; + } + + case PA_SAMPLE_S16NE: + case PA_SAMPLE_S16RE: { + uint16_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) + printf(" 0x%04x ", *(u++)); + + break; + } + + case PA_SAMPLE_S32NE: + case PA_SAMPLE_S32RE: { + uint32_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) + printf("0x%08x ", *(u++)); + + break; + } + + case PA_SAMPLE_S24_32NE: + case PA_SAMPLE_S24_32RE: { + uint32_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) + printf("0x%08x ", *(u++)); + + break; + } + + case PA_SAMPLE_FLOAT32NE: + case PA_SAMPLE_FLOAT32RE: { + float *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) { + printf("%4.3g ", ss->format == PA_SAMPLE_FLOAT32NE ? *u : PA_FLOAT32_SWAP(*u)); + u++; + } + + break; + } + + case PA_SAMPLE_S24LE: + case PA_SAMPLE_S24BE: { + uint8_t *u = d; + + for (i = 0; i < chunk->length / pa_frame_size(ss); i++) { + printf(" 0x%06x ", PA_READ24NE(u)); + u += pa_frame_size(ss); + } + + break; + } + + default: + pa_assert_not_reached(); + } + + printf("\n"); + + pa_memblock_release(chunk->memblock); +} + +static pa_memblock* generate_block(pa_mempool *pool, const pa_sample_spec *ss) { + pa_memblock *r; + void *d; + unsigned i; + + pa_assert_se(r = pa_memblock_new(pool, pa_frame_size(ss) * 10)); + d = pa_memblock_acquire(r); + + switch (ss->format) { + + case PA_SAMPLE_U8: + case PA_SAMPLE_ULAW: + case PA_SAMPLE_ALAW: { + uint8_t *u = d; + + u[0] = 0x00; + u[1] = 0xFF; + u[2] = 0x7F; + u[3] = 0x80; + u[4] = 0x9f; + u[5] = 0x3f; + u[6] = 0x1; + u[7] = 0xF0; + u[8] = 0x20; + u[9] = 0x21; + break; + } + + case PA_SAMPLE_S16NE: + case PA_SAMPLE_S16RE: { + uint16_t *u = d; + + u[0] = 0x0000; + u[1] = 0xFFFF; + u[2] = 0x7FFF; + u[3] = 0x8000; + u[4] = 0x9fff; + u[5] = 0x3fff; + u[6] = 0x1; + u[7] = 0xF000; + u[8] = 0x20; + u[9] = 0x21; + break; + } + + case PA_SAMPLE_S32NE: + case PA_SAMPLE_S32RE: { + uint32_t *u = d; + + u[0] = 0x00000001; + u[1] = 0xFFFF0002; + u[2] = 0x7FFF0003; + u[3] = 0x80000004; + u[4] = 0x9fff0005; + u[5] = 0x3fff0006; + u[6] = 0x10007; + u[7] = 0xF0000008; + u[8] = 0x200009; + u[9] = 0x21000A; + break; + } + + case PA_SAMPLE_S24_32NE: + case PA_SAMPLE_S24_32RE: { + uint32_t *u = d; + + u[0] = 0x000001; + u[1] = 0xFF0002; + u[2] = 0x7F0003; + u[3] = 0x800004; + u[4] = 0x9f0005; + u[5] = 0x3f0006; + u[6] = 0x107; + u[7] = 0xF00008; + u[8] = 0x2009; + u[9] = 0x210A; + break; + } + + case PA_SAMPLE_FLOAT32NE: + case PA_SAMPLE_FLOAT32RE: { + float *u = d; + + u[0] = 0.0f; + u[1] = -1.0f; + u[2] = 1.0f; + u[3] = 4711.0f; + u[4] = 0.222f; + u[5] = 0.33f; + u[6] = -.3f; + u[7] = 99.0f; + u[8] = -0.555f; + u[9] = -.123f; + + if (ss->format == PA_SAMPLE_FLOAT32RE) + for (i = 0; i < 10; i++) + u[i] = PA_FLOAT32_SWAP(u[i]); + + break; + } + + case PA_SAMPLE_S24NE: + case PA_SAMPLE_S24RE: { + uint8_t *u = d; + + PA_WRITE24NE(u, 0x000001); + PA_WRITE24NE(u+3, 0xFF0002); + PA_WRITE24NE(u+6, 0x7F0003); + PA_WRITE24NE(u+9, 0x800004); + PA_WRITE24NE(u+12, 0x9f0005); + PA_WRITE24NE(u+15, 0x3f0006); + PA_WRITE24NE(u+18, 0x107); + PA_WRITE24NE(u+21, 0xF00008); + PA_WRITE24NE(u+24, 0x2009); + PA_WRITE24NE(u+27, 0x210A); + break; + } + + default: + pa_assert_not_reached(); + } + + pa_memblock_release(r); + + return r; +} + +static void help(const char *argv0) { + printf(_("%s [options]\n\n" + "-h, --help Show this help\n" + "-v, --verbose Print debug messages\n" + " --from-rate=SAMPLERATE From sample rate in Hz (defaults to 44100)\n" + " --from-format=SAMPLEFORMAT From sample type (defaults to s16le)\n" + " --from-channels=CHANNELS From number of channels (defaults to 1)\n" + " --to-rate=SAMPLERATE To sample rate in Hz (defaults to 44100)\n" + " --to-format=SAMPLEFORMAT To sample type (defaults to s16le)\n" + " --to-channels=CHANNELS To number of channels (defaults to 1)\n" + " --resample-method=METHOD Resample method (defaults to auto)\n" + " --seconds=SECONDS From stream duration (defaults to 60)\n" + "\n" + "If the formats are not specified, the test performs all formats combinations,\n" + "back and forth.\n" + "\n" + "Sample type must be one of s16le, s16be, u8, float32le, float32be, ulaw, alaw,\n" + "32le, s32be (defaults to s16ne)\n" + "\n" + "See --dump-resample-methods for possible values of resample methods.\n"), + argv0); +} + +enum { + ARG_VERSION = 256, + ARG_FROM_SAMPLERATE, + ARG_FROM_SAMPLEFORMAT, + ARG_FROM_CHANNELS, + ARG_TO_SAMPLERATE, + ARG_TO_SAMPLEFORMAT, + ARG_TO_CHANNELS, + ARG_SECONDS, + ARG_RESAMPLE_METHOD, + ARG_DUMP_RESAMPLE_METHODS +}; + +static void dump_resample_methods(void) { + int i; + + for (i = 0; i < PA_RESAMPLER_MAX; i++) + if (pa_resample_method_supported(i)) + printf("%s\n", pa_resample_method_to_string(i)); + +} + +int main(int argc, char *argv[]) { + pa_mempool *pool = NULL; + pa_sample_spec a, b; + pa_cvolume v; + int ret = 1, verbose = 0, c; + pa_bool_t all_formats = TRUE; + pa_resample_method_t method; + int seconds; + + static const struct option long_options[] = { + {"help", 0, NULL, 'h'}, + {"verbose", 0, NULL, 'v'}, + {"version", 0, NULL, ARG_VERSION}, + {"from-rate", 1, NULL, ARG_FROM_SAMPLERATE}, + {"from-format", 1, NULL, ARG_FROM_SAMPLEFORMAT}, + {"from-channels", 1, NULL, ARG_FROM_CHANNELS}, + {"to-rate", 1, NULL, ARG_TO_SAMPLERATE}, + {"to-format", 1, NULL, ARG_TO_SAMPLEFORMAT}, + {"to-channels", 1, NULL, ARG_TO_CHANNELS}, + {"seconds", 1, NULL, ARG_SECONDS}, + {"resample-method", 1, NULL, ARG_RESAMPLE_METHOD}, + {"dump-resample-methods", 0, NULL, ARG_DUMP_RESAMPLE_METHODS}, + {NULL, 0, NULL, 0} + }; + + setlocale(LC_ALL, ""); + bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); + + pa_log_set_level(PA_LOG_DEBUG); + + pa_assert_se(pool = pa_mempool_new(FALSE, 0)); + + a.channels = b.channels = 1; + a.rate = b.rate = 44100; + a.format = b.format = PA_SAMPLE_S16LE; + v.channels = a.channels; + v.values[0] = pa_sw_volume_from_linear(0.5); + + method = PA_RESAMPLER_AUTO; + seconds = 60; + + while ((c = getopt_long(argc, argv, "hv", long_options, NULL)) != -1) { + + switch (c) { + case 'h' : + help(argv[0]); + ret = 0; + goto quit; + + case 'v': + pa_log_set_level(PA_LOG_DEBUG); + verbose = 1; + break; + + case ARG_VERSION: + printf(_("%s %s\n"), argv[0], PACKAGE_VERSION); + ret = 0; + goto quit; + + case ARG_DUMP_RESAMPLE_METHODS: + dump_resample_methods(); + ret = 0; + goto quit; + + case ARG_FROM_CHANNELS: + a.channels = (uint8_t) atoi(optarg); + break; + + case ARG_FROM_SAMPLEFORMAT: + a.format = pa_parse_sample_format(optarg); + all_formats = FALSE; + break; + + case ARG_FROM_SAMPLERATE: + a.rate = (uint32_t) atoi(optarg); + break; + + case ARG_TO_CHANNELS: + b.channels = (uint8_t) atoi(optarg); + break; + + case ARG_TO_SAMPLEFORMAT: + b.format = pa_parse_sample_format(optarg); + all_formats = FALSE; + break; + + case ARG_TO_SAMPLERATE: + b.rate = (uint32_t) atoi(optarg); + break; + + case ARG_SECONDS: + seconds = atoi(optarg); + break; + + case ARG_RESAMPLE_METHOD: + if (*optarg == '\0' || pa_streq(optarg, "help")) { + dump_resample_methods(); + ret = 0; + goto quit; + } + method = pa_parse_resample_method(optarg); + break; + + default: + goto quit; + } + } + + ret = 0; + pa_assert_se(pool = pa_mempool_new(FALSE, 0)); + + if (!all_formats) { + + pa_resampler *resampler; + pa_memchunk i, j; + pa_usec_t ts; + + if (verbose) { + printf(_("Compilation CFLAGS: %s\n"), PA_CFLAGS); + printf(_("=== %d seconds: %d Hz %d ch (%s) -> %d Hz %d ch (%s)\n"), seconds, + a.rate, a.channels, pa_sample_format_to_string(a.format), + b.rate, b.channels, pa_sample_format_to_string(b.format)); + } + + ts = pa_rtclock_now(); + pa_assert_se(resampler = pa_resampler_new(pool, &a, NULL, &b, NULL, method, 0)); + printf("init: %llu\n", (long long unsigned)(pa_rtclock_now() - ts)); + + i.memblock = pa_memblock_new(pool, pa_usec_to_bytes(1*PA_USEC_PER_SEC, &a) / pa_frame_size(&a)); + + ts = pa_rtclock_now(); + i.length = pa_memblock_get_length(i.memblock); + i.index = 0; + while (seconds--) { + pa_resampler_run(resampler, &i, &j); + pa_memblock_unref(j.memblock); + } + printf("resampling: %llu\n", (long long unsigned)(pa_rtclock_now() - ts)); + pa_memblock_unref(i.memblock); + + pa_resampler_free(resampler); + + goto quit; + } + + for (a.format = 0; a.format < PA_SAMPLE_MAX; a.format ++) { + for (b.format = 0; b.format < PA_SAMPLE_MAX; b.format ++) { + pa_resampler *forth, *back; + pa_memchunk i, j, k; + + if (verbose) + printf("=== %s -> %s -> %s -> /2\n", + pa_sample_format_to_string(a.format), + pa_sample_format_to_string(b.format), + pa_sample_format_to_string(a.format)); + + pa_assert_se(forth = pa_resampler_new(pool, &a, NULL, &b, NULL, method, 0)); + pa_assert_se(back = pa_resampler_new(pool, &b, NULL, &a, NULL, method, 0)); + + i.memblock = generate_block(pool, &a); + i.length = pa_memblock_get_length(i.memblock); + i.index = 0; + pa_resampler_run(forth, &i, &j); + pa_resampler_run(back, &j, &k); + + printf("before: "); + dump_block(&a, &i); + printf("after : "); + dump_block(&b, &j); + printf("reverse: "); + dump_block(&a, &k); + + pa_memblock_unref(j.memblock); + pa_memblock_unref(k.memblock); + + pa_volume_memchunk(&i, &a, &v); + printf("volume: "); + dump_block(&a, &i); + + pa_memblock_unref(i.memblock); + + pa_resampler_free(forth); + pa_resampler_free(back); + } + } + + quit: + if (pool) + pa_mempool_free(pool); + + return ret; +} diff --git a/src/tests/rtpoll-test.c b/src/tests/rtpoll-test.c new file mode 100644 index 00000000..6a6b73a8 --- /dev/null +++ b/src/tests/rtpoll-test.c @@ -0,0 +1,85 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <signal.h> + +#include <pulsecore/poll.h> +#include <pulsecore/log.h> +#include <pulsecore/rtpoll.h> + +static int before(pa_rtpoll_item *i) { + pa_log("before"); + return 0; +} + +static void after(pa_rtpoll_item *i) { + pa_log("after"); +} + +static int worker(pa_rtpoll_item *w) { + pa_log("worker"); + return 0; +} + +int main(int argc, char *argv[]) { + pa_rtpoll *p; + pa_rtpoll_item *i, *w; + struct pollfd *pollfd; + + p = pa_rtpoll_new(); + + i = pa_rtpoll_item_new(p, PA_RTPOLL_EARLY, 1); + pa_rtpoll_item_set_before_callback(i, before); + pa_rtpoll_item_set_after_callback(i, after); + + pollfd = pa_rtpoll_item_get_pollfd(i, NULL); + pollfd->fd = 0; + pollfd->events = POLLIN; + + w = pa_rtpoll_item_new(p, PA_RTPOLL_NORMAL, 0); + pa_rtpoll_item_set_before_callback(w, worker); + + pa_rtpoll_set_timer_relative(p, 10000000); /* 10 s */ + + pa_rtpoll_run(p, 1); + + pa_rtpoll_item_free(i); + + i = pa_rtpoll_item_new(p, PA_RTPOLL_EARLY, 1); + pa_rtpoll_item_set_before_callback(i, before); + pa_rtpoll_item_set_after_callback(i, after); + + pollfd = pa_rtpoll_item_get_pollfd(i, NULL); + pollfd->fd = 0; + pollfd->events = POLLIN; + + pa_rtpoll_run(p, 1); + + pa_rtpoll_item_free(i); + + pa_rtpoll_item_free(w); + + pa_rtpoll_free(p); + + return 0; +} diff --git a/src/tests/rtstutter.c b/src/tests/rtstutter.c new file mode 100644 index 00000000..739683d5 --- /dev/null +++ b/src/tests/rtstutter.c @@ -0,0 +1,117 @@ +/*** + This file is part of PulseAudio. + + Copyright 2008 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include <inttypes.h> + +#ifdef HAVE_PTHREAD +#include <pthread.h> +#endif + +#include <pulse/util.h> +#include <pulse/timeval.h> +#include <pulse/gccmacro.h> + +#include <pulsecore/log.h> +#include <pulsecore/macro.h> +#include <pulsecore/thread.h> +#include <pulsecore/core-util.h> +#include <pulsecore/core-rtclock.h> + +static int msec_lower, msec_upper; + +static void work(void *p) PA_GCC_NORETURN; + +static void work(void *p) { + + pa_log_notice("CPU%i: Created thread.", PA_PTR_TO_UINT(p)); + + pa_make_realtime(12); + +#ifdef HAVE_PTHREAD_SETAFFINITY_NP +{ + cpu_set_t mask; + + CPU_ZERO(&mask); + CPU_SET((size_t) PA_PTR_TO_UINT(p), &mask); + pa_assert_se(pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) == 0); +} +#endif + + for (;;) { + struct timeval now, end; + uint64_t usec; + + pa_log_notice("CPU%i: Sleeping for 1s", PA_PTR_TO_UINT(p)); + pa_msleep(1000); + + usec = + (uint64_t) ((((double) rand())*(double)(msec_upper-msec_lower)*PA_USEC_PER_MSEC)/RAND_MAX) + + (uint64_t) ((uint64_t) msec_lower*PA_USEC_PER_MSEC); + + pa_log_notice("CPU%i: Freezing for %ims", PA_PTR_TO_UINT(p), (int) (usec/PA_USEC_PER_MSEC)); + + pa_rtclock_get(&end); + pa_timeval_add(&end, usec); + + do { + pa_rtclock_get(&now); + } while (pa_timeval_cmp(&now, &end) < 0); + } +} + +int main(int argc, char*argv[]) { + unsigned n; + + pa_log_set_level(PA_LOG_INFO); + + srand((unsigned) time(NULL)); + + if (argc >= 3) { + msec_lower = atoi(argv[1]); + msec_upper = atoi(argv[2]); + } else if (argc >= 2) { + msec_lower = 0; + msec_upper = atoi(argv[1]); + } else { + msec_lower = 0; + msec_upper = 1000; + } + + pa_assert(msec_upper > 0); + pa_assert(msec_upper >= msec_lower); + + pa_log_notice("Creating random latencies in the range of %ims to %ims.", msec_lower, msec_upper); + + for (n = 1; n < pa_ncpus(); n++) { + pa_assert_se(pa_thread_new("rtstutter", work, PA_UINT_TO_PTR(n))); + } + + work(PA_INT_TO_PTR(0)); + + return 0; +} diff --git a/src/tests/sig2str-test.c b/src/tests/sig2str-test.c new file mode 100644 index 00000000..0cd929ca --- /dev/null +++ b/src/tests/sig2str-test.c @@ -0,0 +1,37 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <signal.h> +#include <stdio.h> + +#include <pulsecore/macro.h> +#include <pulsecore/core-util.h> + +int main(int argc, char *argv[]) { + int sig; + + for (sig = -1; sig <= NSIG; sig++) + printf("%i = %s\n", sig, pa_sig2str(sig)); + + return 0; +} diff --git a/src/tests/sigbus-test.c b/src/tests/sigbus-test.c new file mode 100644 index 00000000..4b9ca840 --- /dev/null +++ b/src/tests/sigbus-test.c @@ -0,0 +1,70 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <fcntl.h> +#include <sys/mman.h> + +#include <pulsecore/memtrap.h> +#include <pulsecore/core-util.h> + +int main(int argc, char *argv[]) { + void *p; + int fd; + pa_memtrap *m; + + pa_log_set_level(PA_LOG_DEBUG); + pa_memtrap_install(); + + /* Create the memory map */ + pa_assert_se((fd = open("sigbus-test-map", O_RDWR|O_TRUNC|O_CREAT, 0660)) >= 0); + pa_assert_se(unlink("sigbus-test-map") == 0); + pa_assert_se(ftruncate(fd, PA_PAGE_SIZE) >= 0); + pa_assert_se((p = mmap(NULL, PA_PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) != MAP_FAILED); + + /* Register memory map */ + m = pa_memtrap_add(p, PA_PAGE_SIZE); + + /* Use memory map */ + pa_snprintf(p, PA_PAGE_SIZE, "This is a test that should work fine."); + + /* Verify memory map */ + pa_log("Let's see if this worked: %s", (char*) p); + pa_log("And memtrap says it is good: %s", pa_yes_no(pa_memtrap_is_good(m))); + + /* Invalidate mapping */ + pa_assert_se(ftruncate(fd, 0) >= 0); + + /* Use memory map */ + pa_snprintf(p, PA_PAGE_SIZE, "This is a test that should fail but get caught."); + + /* Verify memory map */ + pa_log("Let's see if this worked: %s", (char*) p); + pa_log("And memtrap says it is good: %s", pa_yes_no(pa_memtrap_is_good(m))); + + pa_memtrap_remove(m); + munmap(p, PA_PAGE_SIZE); + + return 0; +} diff --git a/src/tests/smoother-test.c b/src/tests/smoother-test.c new file mode 100644 index 00000000..2cc9f58b --- /dev/null +++ b/src/tests/smoother-test.c @@ -0,0 +1,82 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> + +#include <pulsecore/time-smoother.h> +#include <pulse/timeval.h> + +int main(int argc, char*argv[]) { + pa_usec_t x; + unsigned u = 0; + pa_smoother *s; + int m; + +/* unsigned msec[] = { */ +/* 200, 200, */ +/* 300, 320, */ +/* 400, 400, */ +/* 500, 480, */ +/* 0, 0 */ +/* }; */ + + int msec[200]; + + srand(0); + + pa_log_set_level(PA_LOG_DEBUG); + + for (m = 0, u = 0; u < PA_ELEMENTSOF(msec); u+= 2) { + + msec[u] = m+1 + (rand() % 100) - 50; + msec[u+1] = m + (rand() % 2000) - 1000 + 5000; + + m += rand() % 100; + + if (msec[u] < 0) + msec[u] = 0; + + if (msec[u+1] < 0) + msec[u+1] = 0; + } + + s = pa_smoother_new(700*PA_USEC_PER_MSEC, 2000*PA_USEC_PER_MSEC, FALSE, TRUE, 6, 0, TRUE); + + for (x = 0, u = 0; x < PA_USEC_PER_SEC * 10; x += PA_USEC_PER_MSEC) { + + while (u < PA_ELEMENTSOF(msec) && (pa_usec_t) msec[u]*PA_USEC_PER_MSEC < x) { + pa_smoother_put(s, (pa_usec_t) msec[u] * PA_USEC_PER_MSEC, (pa_usec_t) msec[u+1] * PA_USEC_PER_MSEC); + printf("%i\t\t%i\n", msec[u], msec[u+1]); + u += 2; + + pa_smoother_resume(s, (pa_usec_t) msec[u] * PA_USEC_PER_MSEC, TRUE); + } + + printf("%llu\t%llu\n", (unsigned long long) (x/PA_USEC_PER_MSEC), (unsigned long long) (pa_smoother_get(s, x)/PA_USEC_PER_MSEC)); + } + + pa_smoother_free(s); + + return 0; +} diff --git a/src/tests/stripnul.c b/src/tests/stripnul.c new file mode 100644 index 00000000..d677ad20 --- /dev/null +++ b/src/tests/stripnul.c @@ -0,0 +1,70 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#include <pulse/xmalloc.h> +#include <pulsecore/macro.h> + +int main(int argc, char *argv[]) { + FILE *i, *o; + size_t granularity; + pa_bool_t found = FALSE; + uint8_t *zero; + + pa_assert_se(argc >= 2); + pa_assert_se((granularity = (size_t) atoi(argv[1])) >= 1); + pa_assert_se((i = (argc >= 3) ? fopen(argv[2], "r") : stdin)); + pa_assert_se((o = (argc >= 4) ? fopen(argv[3], "w") : stdout)); + + zero = pa_xmalloc0(granularity); + + for (;;) { + uint8_t buffer[16*1024], *p; + size_t k; + + k = fread(buffer, granularity, sizeof(buffer)/granularity, i); + + if (k <= 0) + break; + + if (found) + pa_assert_se(fwrite(buffer, granularity, k, o) == k); + else { + for (p = buffer; ((size_t) (p-buffer)/granularity) < k; p += granularity) + if (memcmp(p, zero, granularity)) { + size_t left; + found = TRUE; + left = (size_t) (k - (size_t) (p-buffer)/granularity); + pa_assert_se(fwrite(p, granularity, left, o) == left); + break; + } + } + } + + fflush(o); + + return 0; +} diff --git a/src/tests/strlist-test.c b/src/tests/strlist-test.c index 4262a001..86f4f075 100644 --- a/src/tests/strlist-test.c +++ b/src/tests/strlist-test.c @@ -1,10 +1,10 @@ #include <stdio.h> #include <pulse/xmalloc.h> + #include <pulsecore/strlist.h> -#include <pulsecore/gccmacro.h> -int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char* argv[]) { +int main(int argc, char* argv[]) { char *t, *u; pa_strlist *l = NULL; @@ -16,7 +16,7 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char* argv[]) { t = pa_strlist_tostring(l); pa_strlist_free(l); - + fprintf(stderr, "1: %s\n", t); l = pa_strlist_parse(t); @@ -29,9 +29,9 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char* argv[]) { l = pa_strlist_pop(l, &u); fprintf(stderr, "3: %s\n", u); pa_xfree(u); - + l = pa_strlist_remove(l, "c"); - + t = pa_strlist_tostring(l); fprintf(stderr, "4: %s\n", t); pa_xfree(t); diff --git a/src/tests/sync-playback.c b/src/tests/sync-playback.c index 39c6aac4..8eaa25fe 100644 --- a/src/tests/sync-playback.c +++ b/src/tests/sync-playback.c @@ -1,18 +1,16 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -24,13 +22,11 @@ #endif #include <signal.h> -#include <string.h> #include <errno.h> #include <unistd.h> #include <assert.h> #include <stdio.h> #include <stdlib.h> -#include <getopt.h> #include <math.h> #include <pulse/pulseaudio.h> @@ -56,9 +52,10 @@ static const pa_sample_spec sample_spec = { static const pa_buffer_attr buffer_attr = { .maxlength = SAMPLE_HZ*sizeof(float)*NSTREAMS, /* exactly space for the entire play time */ - .tlength = 0, + .tlength = (uint32_t) -1, .prebuf = 0, /* Setting prebuf to 0 guarantees us the the streams will run synchronously, no matter what */ - .minreq = 0 + .minreq = (uint32_t) -1, + .fragsize = 0 }; static void nop_free_cb(void *p) {} @@ -67,7 +64,7 @@ static void underflow_cb(struct pa_stream *s, void *userdata) { int i = (int) (long) userdata; fprintf(stderr, "Stream %i finished\n", i); - + if (++n_streams_ready >= 2*NSTREAMS) { fprintf(stderr, "We're done\n"); mainloop_api->quit(mainloop_api, 0); @@ -89,19 +86,19 @@ static void stream_state_callback(pa_stream *s, void *userdata) { int r, i = (int) (long) userdata; fprintf(stderr, "Writing data to stream %i.\n", i); - - r = pa_stream_write(s, data, sizeof(data), nop_free_cb, sizeof(data) * i, PA_SEEK_ABSOLUTE); + + r = pa_stream_write(s, data, sizeof(data), nop_free_cb, (int64_t) sizeof(data) * (int64_t) i, PA_SEEK_ABSOLUTE); assert(r == 0); /* Be notified when this stream is drained */ pa_stream_set_underflow_callback(s, underflow_cb, userdata); - + /* All streams have been set up, let's go! */ if (++n_streams_ready >= NSTREAMS) { fprintf(stderr, "Uncorking\n"); pa_operation_unref(pa_stream_cork(s, 0, NULL, NULL)); } - + break; } @@ -121,7 +118,7 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; - + case PA_CONTEXT_READY: { int i; @@ -131,18 +128,18 @@ static void context_state_callback(pa_context *c, void *userdata) { char name[64]; fprintf(stderr, "Creating stream %i\n", i); - + snprintf(name, sizeof(name), "stream #%i", i); - + streams[i] = pa_stream_new(c, name, &sample_spec, NULL); assert(streams[i]); pa_stream_set_state_callback(streams[i], stream_state_callback, (void*) (long) i); pa_stream_connect_playback(streams[i], NULL, &buffer_attr, PA_STREAM_START_CORKED, NULL, i == 0 ? NULL : streams[0]); } - + break; } - + case PA_CONTEXT_TERMINATED: mainloop_api->quit(mainloop_api, 0); break; @@ -163,7 +160,7 @@ int main(int argc, char *argv[]) { for (i = 0; i < NSTREAMS; i++) streams[i] = NULL; - + /* Set up a new main loop */ m = pa_mainloop_new(); assert(m); @@ -175,11 +172,16 @@ int main(int argc, char *argv[]) { pa_context_set_state_callback(context, context_state_callback, NULL); - pa_context_connect(context, NULL, 0, NULL); + /* Connect the context */ + if (pa_context_connect(context, NULL, 0, NULL) < 0) { + fprintf(stderr, "pa_context_connect() failed.\n"); + goto quit; + } if (pa_mainloop_run(m, &ret) < 0) fprintf(stderr, "pa_mainloop_run() failed.\n"); +quit: pa_context_unref(context); for (i = 0; i < NSTREAMS; i++) @@ -187,6 +189,6 @@ int main(int argc, char *argv[]) { pa_stream_unref(streams[i]); pa_mainloop_free(m); - + return ret; } diff --git a/src/tests/thread-mainloop-test.c b/src/tests/thread-mainloop-test.c index bf3d4cd2..72275972 100644 --- a/src/tests/thread-mainloop-test.c +++ b/src/tests/thread-mainloop-test.c @@ -1,18 +1,16 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -23,49 +21,49 @@ #include <config.h> #endif -#include <assert.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> +#include <pulse/rtclock.h> #include <pulse/timeval.h> #include <pulse/util.h> - -#include <pulsecore/gccmacro.h> #include <pulse/thread-mainloop.h> -static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) { +#include <pulsecore/macro.h> +#include <pulsecore/core-rtclock.h> + +static void tcb(pa_mainloop_api *a, pa_time_event *e, const struct timeval *tv, void *userdata) { + pa_assert_se(pa_threaded_mainloop_in_thread(userdata)); fprintf(stderr, "TIME EVENT START\n"); pa_threaded_mainloop_signal(userdata, 1); fprintf(stderr, "TIME EVENT END\n"); } -int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { +int main(int argc, char *argv[]) { pa_mainloop_api *a; pa_threaded_mainloop *m; struct timeval tv; - m = pa_threaded_mainloop_new(); - assert(m); - a = pa_threaded_mainloop_get_api(m); - assert(a); + pa_assert_se(m = pa_threaded_mainloop_new()); + pa_assert_se(a = pa_threaded_mainloop_get_api(m)); - pa_threaded_mainloop_start(m); + pa_assert_se(pa_threaded_mainloop_start(m) >= 0); pa_threaded_mainloop_lock(m); - - pa_gettimeofday(&tv); - tv.tv_sec += 5; - a->time_new(a, &tv, tcb, m); - + + pa_assert_se(!pa_threaded_mainloop_in_thread(m)); + + a->time_new(a, pa_timeval_rtstore(&tv, pa_rtclock_now() + 5 * PA_USEC_PER_SEC, TRUE), tcb, m); + fprintf(stderr, "waiting 5s (signal)\n"); pa_threaded_mainloop_wait(m); fprintf(stderr, "wait completed\n"); pa_threaded_mainloop_accept(m); fprintf(stderr, "signal accepted\n"); - + pa_threaded_mainloop_unlock(m); - + fprintf(stderr, "waiting 5s (sleep)\n"); pa_msleep(5000); diff --git a/src/tests/thread-test.c b/src/tests/thread-test.c new file mode 100644 index 00000000..4071e429 --- /dev/null +++ b/src/tests/thread-test.c @@ -0,0 +1,140 @@ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <pulsecore/thread.h> +#include <pulsecore/mutex.h> +#include <pulsecore/once.h> +#include <pulsecore/log.h> +#include <pulsecore/core-util.h> +#include <pulse/xmalloc.h> + +static pa_mutex *mutex = NULL; +static pa_cond *cond1 = NULL, *cond2 = NULL; +static pa_tls *tls = NULL; + +static int magic_number = 0; + +#define THREADS_MAX 20 + +static void once_func(void) { + pa_log("once!"); +} + +static pa_once once = PA_ONCE_INIT; + +static void thread_func(void *data) { + pa_tls_set(tls, data); + + pa_log("thread_func() for %s starting...", (char*) pa_tls_get(tls)); + + pa_mutex_lock(mutex); + + for (;;) { + int k, n; + + pa_log("%s waiting ...", (char*) pa_tls_get(tls)); + + for (;;) { + + if (magic_number < 0) + goto quit; + + if (magic_number != 0) + break; + + pa_cond_wait(cond1, mutex); + } + + k = magic_number; + magic_number = 0; + + pa_mutex_unlock(mutex); + + pa_run_once(&once, once_func); + + pa_cond_signal(cond2, 0); + + pa_log("%s got number %i", (char*) pa_tls_get(tls), k); + + /* Spin! */ + for (n = 0; n < k; n++) + pa_thread_yield(); + + pa_mutex_lock(mutex); + } + +quit: + + pa_mutex_unlock(mutex); + + pa_log("thread_func() for %s done...", (char*) pa_tls_get(tls)); +} + +int main(int argc, char *argv[]) { + int i, k; + pa_thread* t[THREADS_MAX]; + + mutex = pa_mutex_new(FALSE, FALSE); + cond1 = pa_cond_new(); + cond2 = pa_cond_new(); + tls = pa_tls_new(pa_xfree); + + for (i = 0; i < THREADS_MAX; i++) { + t[i] = pa_thread_new("test", thread_func, pa_sprintf_malloc("Thread #%i", i+1)); + assert(t[i]); + } + + pa_mutex_lock(mutex); + + pa_log("loop-init"); + + for (k = 0; k < 100; k++) { + assert(magic_number == 0); + + + magic_number = (int) rand() % 0x10000; + + pa_log("iteration %i (%i)", k, magic_number); + + pa_cond_signal(cond1, 0); + + pa_cond_wait(cond2, mutex); + } + + pa_log("loop-exit"); + + magic_number = -1; + pa_cond_signal(cond1, 1); + + pa_mutex_unlock(mutex); + + for (i = 0; i < THREADS_MAX; i++) + pa_thread_free(t[i]); + + pa_mutex_free(mutex); + pa_cond_free(cond1); + pa_cond_free(cond2); + pa_tls_free(tls); + + return 0; +} diff --git a/src/tests/usergroup-test.c b/src/tests/usergroup-test.c new file mode 100644 index 00000000..3948e0f8 --- /dev/null +++ b/src/tests/usergroup-test.c @@ -0,0 +1,155 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Ted Percival + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <pwd.h> +#include <grp.h> +#include <errno.h> + +#include <pulsecore/usergroup.h> + +static int load_reference_structs(struct group **gr, struct passwd **pw) { + setpwent(); + *pw = getpwent(); + endpwent(); + + setgrent(); + *gr = getgrent(); + endgrent(); + + return (*gr && *pw) ? 0 : 1; +} + +static int compare_group(const struct group *a, const struct group *b) { + char **amem, **bmem; + + if (strcmp(a->gr_name, b->gr_name)) { + fprintf(stderr, "Group name mismatch: [%s] [%s]\n", a->gr_name, b->gr_name); + return 1; + } + + if (strcmp(a->gr_passwd, b->gr_passwd)) { + fprintf(stderr, "Group password mismatch: [%s] [%s]\n", a->gr_passwd, b->gr_passwd); + return 1; + } + + if (a->gr_gid != b->gr_gid) { + fprintf(stderr, "Gid mismatch: [%lu] [%lu]\n", (unsigned long) a->gr_gid, (unsigned long) b->gr_gid); + return 1; + } + + /* XXX: Assuming the group ordering is identical. */ + for (amem = a->gr_mem, bmem = b->gr_mem; *amem && *bmem; ++amem, ++bmem) { + if (strcmp(*amem, *bmem)) { + fprintf(stderr, "Group member mismatch: [%s] [%s]\n", *amem, *bmem); + return 1; + } + } + + if (*amem || *bmem) { + fprintf(stderr, "Mismatched group count\n"); + return 1; + } + + return 0; +} + +static int compare_passwd(const struct passwd *a, const struct passwd *b) { + if (strcmp(a->pw_name, b->pw_name)) { + fprintf(stderr, "pw_name mismatch: [%s] [%s]\n", a->pw_name, b->pw_name); + return 1; + } + + if (strcmp(a->pw_passwd, b->pw_passwd)) { + fprintf(stderr, "pw_passwd mismatch: [%s] [%s]\n", a->pw_passwd, b->pw_passwd); + return 1; + } + + if (a->pw_uid != b->pw_uid) { + fprintf(stderr, "pw_uid mismatch: [%lu] [%lu]\n", (unsigned long) a->pw_uid, (unsigned long) b->pw_uid); + return 1; + } + + if (a->pw_gid != b->pw_gid) { + fprintf(stderr, "pw_gid mismatch: [%lu] [%lu]\n", (unsigned long) a->pw_gid, (unsigned long) b->pw_gid); + return 1; + } + + if (strcmp(a->pw_gecos, b->pw_gecos)) { + fprintf(stderr, "pw_gecos mismatch: [%s] [%s]\n", a->pw_gecos, b->pw_gecos); + return 1; + } + + if (strcmp(a->pw_dir, b->pw_dir)) { + fprintf(stderr, "pw_dir mismatch: [%s] [%s]\n", a->pw_dir, b->pw_dir); + return 1; + } + + if (strcmp(a->pw_shell, b->pw_shell)) { + fprintf(stderr, "pw_shell mismatch: [%s] [%s]\n", a->pw_shell, b->pw_shell); + return 1; + } + + return 0; +} + +int main(int argc, char *argv[]) { + struct group *gr; + struct passwd *pw; + int err; + struct group *reference_group = NULL; + struct passwd *reference_passwd = NULL; + + err = load_reference_structs(&reference_group, &reference_passwd); + if (err) + return 77; + + errno = 0; + gr = pa_getgrgid_malloc(reference_group->gr_gid); + if (compare_group(reference_group, gr)) + return 1; + pa_getgrgid_free(gr); + + errno = 0; + gr = pa_getgrnam_malloc(reference_group->gr_name); + if (compare_group(reference_group, gr)) + return 1; + pa_getgrnam_free(gr); + + errno = 0; + pw = pa_getpwuid_malloc(reference_passwd->pw_uid); + if (compare_passwd(reference_passwd, pw)) + return 1; + pa_getpwuid_free(pw); + + errno = 0; + pw = pa_getpwnam_malloc(reference_passwd->pw_name); + if (compare_passwd(reference_passwd, pw)) + return 1; + pa_getpwnam_free(pw); + + return 0; +} diff --git a/src/tests/utf8-test.c b/src/tests/utf8-test.c index 2e9f128a..f1708ad4 100644 --- a/src/tests/utf8-test.c +++ b/src/tests/utf8-test.c @@ -1,5 +1,3 @@ -/* $Id$ */ - #include <stdio.h> #include <assert.h> @@ -8,13 +6,13 @@ int main(int argc, char *argv[]) { char *c; - + assert(pa_utf8_valid("hallo")); assert(pa_utf8_valid("hallo\n")); assert(!pa_utf8_valid("hüpfburg\n")); assert(pa_utf8_valid("hallo\n")); assert(pa_utf8_valid("hüpfburg\n")); - + printf("LATIN1: %s\n", c = pa_utf8_filter("hüpfburg")); pa_xfree(c); printf("UTF8: %sx\n", c = pa_utf8_filter("hüpfburg")); diff --git a/src/tests/vector-test.c b/src/tests/vector-test.c new file mode 100644 index 00000000..7494348c --- /dev/null +++ b/src/tests/vector-test.c @@ -0,0 +1,83 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <pulsecore/vector.h> +#include <pulsecore/log.h> + +int main(int argc, char *argv[]) { + +#ifdef __SSE2__ + pa_int16_vector_t input, zero; + pa_int32_vector_t unpacked1, unpacked2; + pa_int32_vector_t volume1, volume2, volume1_hi, volume1_lo, volume2_hi, volume2_lo, reduce, mask; + pa_int16_vector_t output; + + unsigned u; + + zero.v = PA_INT16_VECTOR_MAKE(0); + reduce.v = PA_INT32_VECTOR_MAKE(0x10000); + volume1.v = volume2.v = PA_INT32_VECTOR_MAKE(0x10000*2+7); + mask.v = PA_INT32_VECTOR_MAKE(0xFFFF); + + volume1_lo.m = _mm_and_si128(volume1.m, mask.m); + volume2_lo.m = _mm_and_si128(volume2.m, mask.m); + volume1_hi.m = _mm_srli_epi32(volume1.m, 16); + volume2_hi.m = _mm_srli_epi32(volume2.m, 16); + + input.v = PA_INT16_VECTOR_MAKE(32000); + + for (u = 0; u < PA_INT16_VECTOR_SIZE; u++) + pa_log("input=%i\n", input.i[u]); + + unpacked1.m = _mm_unpackhi_epi16(zero.m, input.m); + unpacked2.m = _mm_unpacklo_epi16(zero.m, input.m); + + for (u = 0; u < PA_INT32_VECTOR_SIZE; u++) + pa_log("unpacked1=%i\n", unpacked1.i[u]); + + unpacked1.v /= reduce.v; + unpacked2.v /= reduce.v; + + for (u = 0; u < PA_INT32_VECTOR_SIZE; u++) + pa_log("unpacked1=%i\n", unpacked1.i[u]); + + for (u = 0; u < PA_INT32_VECTOR_SIZE; u++) + pa_log("volume1=%i\n", volume1.i[u]); + + unpacked1.v = (unpacked1.v * volume1_lo.v) / reduce.v + unpacked1.v * volume1_hi.v; + unpacked2.v = (unpacked2.v * volume2_lo.v) / reduce.v + unpacked2.v * volume2_hi.v; + + for (u = 0; u < PA_INT32_VECTOR_SIZE; u++) + pa_log("unpacked1=%i\n", unpacked1.i[u]); + + output.m = _mm_packs_epi32(unpacked1.m, unpacked2.m); + + for (u = 0; u < PA_INT16_VECTOR_SIZE; u++) + pa_log("output=%i\n", output.i[u]); + +#endif + + return 0; +} diff --git a/src/tests/voltest.c b/src/tests/voltest.c index 3de884af..ece86f85 100644 --- a/src/tests/voltest.c +++ b/src/tests/voltest.c @@ -1,22 +1,134 @@ -/* $Id$ */ +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif #include <stdio.h> +#include <math.h> #include <pulse/volume.h> -#include <pulsecore/gccmacro.h> -int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { +#include <pulsecore/macro.h> + +int main(int argc, char *argv[]) { pa_volume_t v; + pa_cvolume cv; + float b; + pa_channel_map map; + pa_volume_t md = 0; + unsigned mdn = 0; + + printf("Attenuation of sample 1 against 32767: %g dB\n", 20.0*log10(1.0/32767.0)); + printf("Smallest possible attenutation > 0 applied to 32767: %li\n", lrint(32767.0*pa_sw_volume_to_linear(1))); for (v = PA_VOLUME_MUTED; v <= PA_VOLUME_NORM*2; v += 256) { double dB = pa_sw_volume_to_dB(v); double f = pa_sw_volume_to_linear(v); - + printf("Volume: %3i; percent: %i%%; decibel %0.2f; linear = %0.2f; volume(decibel): %3i; volume(linear): %3i\n", v, (v*100)/PA_VOLUME_NORM, dB, f, pa_sw_volume_from_dB(dB), pa_sw_volume_from_linear(f)); + } + + for (v = PA_VOLUME_MUTED; v <= PA_VOLUME_NORM*2; v += 256) { + char s[PA_CVOLUME_SNPRINT_MAX], t[PA_SW_CVOLUME_SNPRINT_DB_MAX]; + + pa_cvolume_set(&cv, 2, v); + + printf("Volume: %3i [%s] [%s]\n", + v, + pa_cvolume_snprint(s, sizeof(s), &cv), + pa_sw_cvolume_snprint_dB(t, sizeof(t), &cv)); + + } + + map.channels = cv.channels = 2; + map.map[0] = PA_CHANNEL_POSITION_LEFT; + map.map[1] = PA_CHANNEL_POSITION_RIGHT; + for (cv.values[0] = PA_VOLUME_MUTED; cv.values[0] <= PA_VOLUME_NORM*2; cv.values[0] += 4096) + for (cv.values[1] = PA_VOLUME_MUTED; cv.values[1] <= PA_VOLUME_NORM*2; cv.values[1] += 4096) { + char s[PA_CVOLUME_SNPRINT_MAX]; + + printf("Volume: [%s]; balance: %2.1f\n", pa_cvolume_snprint(s, sizeof(s), &cv), pa_cvolume_get_balance(&cv, &map)); + } + + for (cv.values[0] = PA_VOLUME_MUTED+4096; cv.values[0] <= PA_VOLUME_NORM*2; cv.values[0] += 4096) + for (cv.values[1] = PA_VOLUME_MUTED; cv.values[1] <= PA_VOLUME_NORM*2; cv.values[1] += 4096) + for (b = -1.0f; b <= 1.0f; b += 0.2f) { + char s[PA_CVOLUME_SNPRINT_MAX]; + pa_cvolume r; + float k; + + printf("Before: volume: [%s]; balance: %2.1f\n", pa_cvolume_snprint(s, sizeof(s), &cv), pa_cvolume_get_balance(&cv, &map)); + + r = cv; + pa_cvolume_set_balance(&r, &map,b); + + k = pa_cvolume_get_balance(&r, &map); + printf("After: volume: [%s]; balance: %2.1f (intended: %2.1f) %s\n", pa_cvolume_snprint(s, sizeof(s), &r), k, b, k < b-.05 || k > b+.5 ? "MISMATCH" : ""); + } + + for (v = PA_VOLUME_MUTED; v <= PA_VOLUME_NORM*2; v += 51) { + + double l = pa_sw_volume_to_linear(v); + pa_volume_t k = pa_sw_volume_from_linear(l); + double db = pa_sw_volume_to_dB(v); + pa_volume_t r = pa_sw_volume_from_dB(db); + pa_volume_t w; + + pa_assert(k == v); + pa_assert(r == v); + + for (w = PA_VOLUME_MUTED; w < PA_VOLUME_NORM*2; w += 37) { + + double t = pa_sw_volume_to_linear(w); + double db2 = pa_sw_volume_to_dB(w); + pa_volume_t p, p1, p2; + double q, qq; + + p = pa_sw_volume_multiply(v, w); + qq = db + db2; + p2 = pa_sw_volume_from_dB(qq); + q = l*t; + p1 = pa_sw_volume_from_linear(q); + + if (p2 > p && p2 - p > md) + md = p2 - p; + if (p2 < p && p - p2 > md) + md = p - p2; + if (p1 > p && p1 - p > md) + md = p1 - p; + if (p1 < p && p - p1 > md) + md = p - p1; + + if (p1 != p || p2 != p) + mdn++; + } } + printf("max deviation: %lu n=%lu\n", (unsigned long) md, (unsigned long) mdn); + + pa_assert(md <= 1); + pa_assert(mdn <= 251); + return 0; } diff --git a/src/tests/volume-ui.py b/src/tests/volume-ui.py new file mode 100644 index 00000000..7909b801 --- /dev/null +++ b/src/tests/volume-ui.py @@ -0,0 +1,282 @@ +#!/usr/bin/python + +import pygtk, gtk, sys +from ctypes import * + +try: + libpulse = cdll.LoadLibrary("../.libs/libpulse.so") +except OSError: + try: + libpulse = cdll.LoadLibrary(".libs/libpulse.so") + except OSError: + libpulse = cdll.LoadLibrary("libpulse.so") + +class ChannelMap(Structure): + _fields_ = [("channels", c_ubyte), + ("map", c_uint * 32)] + + _to_name = libpulse.pa_channel_map_to_name + _to_name.restype = c_char_p + _to_name.argtypes = [c_void_p] + + _to_pretty_name = libpulse.pa_channel_map_to_pretty_name + _to_pretty_name.restype = c_char_p + _to_pretty_name.argtypes = [c_void_p] + + _snprint = libpulse.pa_channel_map_snprint + _snprint.restype = c_char_p + _snprint.argtypes = [c_char_p, c_ulong, c_void_p] + + _position_to_string = libpulse.pa_channel_position_to_string + _position_to_string.restype = c_char_p + _position_to_string.argtypes = [c_uint] + + _position_to_pretty_string = libpulse.pa_channel_position_to_pretty_string + _position_to_pretty_string.restype = c_char_p + _position_to_pretty_string.argtypes = [c_uint] + + _can_balance = libpulse.pa_channel_map_can_balance + _can_balance.restype = c_int + _can_balance.argtypes = [c_void_p] + + _can_fade = libpulse.pa_channel_map_can_fade + _can_fade.restype = c_int + _can_fade.argtypes = [c_void_p] + + _parse = libpulse.pa_channel_map_parse + _parse.restype = c_void_p + _parse.argtypes = [c_void_p, c_char_p] + + def to_name(this): + return this._to_name(byref(this)) + + def to_pretty_name(this): + return this._to_pretty_name(byref(this)) + + def snprint(this): + s = create_string_buffer(336) + r = this._snprint(s, len(s), byref(this)) + + if r is None: + return None + else: + return s.value + + def position_to_string(this, pos): + return this._position_to_string(pos) + + def position_to_pretty_string(this, pos): + return this._position_to_pretty_string(pos) + + def can_balance(this): + return bool(this._can_balance(byref(this))) + + def can_fade(this): + return bool(this._can_fade(byref(this))) + + def parse(this, s): + if this._parse(byref(this), s) is None: + raise Exception("Parse failure") + + +class CVolume(Structure): + _fields_ = [("channels", c_ubyte), + ("values", c_uint32 * 32)] + + _snprint = libpulse.pa_cvolume_snprint + _snprint.restype = c_char_p + _snprint.argtypes = [c_char_p, c_ulong, c_void_p] + + _max = libpulse.pa_cvolume_max + _max.restype = c_uint32 + _max.argtypes = [c_void_p] + + _scale = libpulse.pa_cvolume_scale + _scale.restype = c_void_p + _scale.argtypes = [c_void_p, c_uint32] + + _get_balance = libpulse.pa_cvolume_get_balance + _get_balance.restype = c_float + _get_balance.argtypes = [c_void_p, c_void_p] + + _get_fade = libpulse.pa_cvolume_get_fade + _get_fade.restype = c_float + _get_fade.argtypes = [c_void_p, c_void_p] + + _set_balance = libpulse.pa_cvolume_set_balance + _set_balance.restype = c_void_p + _set_balance.argtypes = [c_void_p, c_void_p, c_float] + + _set_fade = libpulse.pa_cvolume_set_fade + _set_fade.restype = c_void_p + _set_fade.argtypes = [c_void_p, c_void_p, c_float] + + _to_dB = libpulse.pa_sw_volume_to_dB + _to_dB.restype = c_double + _to_dB.argytpes = [c_uint32] + + def snprint(this): + s = create_string_buffer(320) + r = this._snprint(s, len(s), byref(this)) + + if r is None: + return None + else: + return s.raw + + def max(this): + return this._max(byref(this)) + + def scale(this, v): + return this._scale(byref(this), v) + + def get_balance(this, cm): + return this._get_balance(byref(this), byref(cm)) + + def get_fade(this, cm): + return this._get_fade(byref(this), byref(cm)) + + def set_balance(this, cm, f): + return this._set_balance(byref(this), byref(cm), f) + + def set_fade(this, cm, f): + return this._set_fade(byref(this), byref(cm), f) + + def to_dB(this, channel = None): + if channel is None: + return this._to_dB(this.max()) + + return this._to_dB(this.values[channel]) + +cm = ChannelMap() + +if len(sys.argv) > 1: + cm.parse(sys.argv[1]) +else: + cm.parse("surround-51") + +v = CVolume() +v.channels = cm.channels + +for i in range(cm.channels): + v.values[i] = 65536 + +title = cm.to_pretty_name() +if title is None: + title = cm.snprint() + +window = gtk.Window(gtk.WINDOW_TOPLEVEL) +window.set_title(unicode(title)) +window.set_border_width(12) + +vbox = gtk.VBox(spacing=6) + +channel_labels = {} +channel_scales = {} +channel_dB_labels = {} + +def update_volume(update_channels = True, update_fade = True, update_balance = True, update_scale = True): + if update_channels: + for i in range(cm.channels): + channel_scales[i].set_value(v.values[i]) + + if update_scale: + value_scale.set_value(v.max()) + + if update_balance: + balance_scale.set_value(v.get_balance(cm)) + + if update_fade: + fade_scale.set_value(v.get_fade(cm)) + + for i in range(cm.channels): + channel_dB_labels[i].set_label("%0.2f dB" % v.to_dB(i)) + + value_dB_label.set_label("%0.2f dB" % v.to_dB()) + +def fade_value_changed(fs): + v.set_fade(cm, fade_scale.get_value()) + update_volume(update_fade = False) + +def balance_value_changed(fs): + v.set_balance(cm, balance_scale.get_value()) + update_volume(update_balance = False) + +def value_value_changed(fs): + v.scale(int(value_scale.get_value())) + update_volume(update_scale = False) + +def channel_value_changed(fs, i): + v.values[i] = int(channel_scales[i].get_value()) + update_volume(update_channels = False) + +for i in range(cm.channels): + channel_labels[i] = gtk.Label(cm.position_to_pretty_string(cm.map[i])) + channel_labels[i].set_alignment(0, 1) + vbox.pack_start(channel_labels[i], expand=False, fill=True) + + channel_scales[i] = gtk.HScale() + channel_scales[i].set_range(0, 65536*3/2) + channel_scales[i].set_digits(0) + channel_scales[i].set_value_pos(gtk.POS_RIGHT) + vbox.pack_start(channel_scales[i], expand=False, fill=True) + + channel_dB_labels[i] = gtk.Label("-xxx dB") + channel_dB_labels[i].set_alignment(1, 1) + vbox.pack_start(channel_dB_labels[i], expand=False, fill=True) + +value_label = gtk.Label("Value") +value_label.set_alignment(0, .5) +vbox.pack_start(value_label, expand=False, fill=True) +value_scale = gtk.HScale() +value_scale.set_range(0, 65536*3/2) +value_scale.set_value_pos(gtk.POS_RIGHT) +value_scale.set_digits(0) +vbox.pack_start(value_scale, expand=False, fill=True) +value_dB_label = gtk.Label("-xxx dB") +value_dB_label.set_alignment(1, 1) +vbox.pack_start(value_dB_label, expand=False, fill=True) + +balance_label = gtk.Label("Balance") +balance_label.set_alignment(0, .5) +vbox.pack_start(balance_label, expand=False, fill=True) +balance_scale = gtk.HScale() +balance_scale.set_range(-1.0, +1.0) +balance_scale.set_value_pos(gtk.POS_RIGHT) +balance_scale.set_digits(2) +vbox.pack_start(balance_scale, expand=False, fill=True) + +fade_label = gtk.Label("Fade") +fade_label.set_alignment(0, .5) +vbox.pack_start(fade_label, expand=False, fill=True) +fade_scale = gtk.HScale() +fade_scale.set_range(-1.0, +1.0) +fade_scale.set_value_pos(gtk.POS_RIGHT) +fade_scale.set_digits(2) +vbox.pack_start(fade_scale, expand=False, fill=True) + +window.add(vbox) +window.set_default_size(600, 50) + +update_volume() + +for i in range(cm.channels): + channel_scales[i].connect("value_changed", channel_value_changed, i) +fade_scale.connect("value_changed", fade_value_changed) +balance_scale.connect("value_changed", balance_value_changed) +value_scale.connect("value_changed", value_value_changed) + +vbox.show_all() + +if not cm.can_balance(): + balance_label.hide() + balance_scale.hide() + +if not cm.can_fade(): + fade_label.hide() + fade_scale.hide() + + +window.show() + +gtk.main() |
