153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 553a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 653a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 753a5a1b3Sopenharmony_ci or (at your option) any later version. 853a5a1b3Sopenharmony_ci 953a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1053a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1153a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1253a5a1b3Sopenharmony_ci General Public License for more details. 1353a5a1b3Sopenharmony_ci 1453a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1553a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1653a5a1b3Sopenharmony_ci***/ 1753a5a1b3Sopenharmony_ci 1853a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 1953a5a1b3Sopenharmony_ci#include <config.h> 2053a5a1b3Sopenharmony_ci#endif 2153a5a1b3Sopenharmony_ci 2253a5a1b3Sopenharmony_ci#include <signal.h> 2353a5a1b3Sopenharmony_ci#include <string.h> 2453a5a1b3Sopenharmony_ci#include <errno.h> 2553a5a1b3Sopenharmony_ci#include <unistd.h> 2653a5a1b3Sopenharmony_ci#include <stdio.h> 2753a5a1b3Sopenharmony_ci#include <stdlib.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#include <check.h> 3053a5a1b3Sopenharmony_ci 3153a5a1b3Sopenharmony_ci#include <pulse/pulseaudio.h> 3253a5a1b3Sopenharmony_ci#include <pulse/mainloop.h> 3353a5a1b3Sopenharmony_ci 3453a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 3553a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 3653a5a1b3Sopenharmony_ci#include <pulsecore/thread.h> 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci#define INTERPOLATE 3953a5a1b3Sopenharmony_ci//#define CORK 4053a5a1b3Sopenharmony_ci 4153a5a1b3Sopenharmony_cistatic pa_context *context = NULL; 4253a5a1b3Sopenharmony_cistatic pa_stream *stream = NULL; 4353a5a1b3Sopenharmony_cistatic pa_mainloop_api *mainloop_api = NULL; 4453a5a1b3Sopenharmony_cistatic bool playback = true; 4553a5a1b3Sopenharmony_cistatic pa_usec_t latency = 0; 4653a5a1b3Sopenharmony_cistatic const char *bname = NULL; 4753a5a1b3Sopenharmony_ci 4853a5a1b3Sopenharmony_cistatic void stream_write_cb(pa_stream *p, size_t nbytes, void *userdata) { 4953a5a1b3Sopenharmony_ci /* Just some silence */ 5053a5a1b3Sopenharmony_ci 5153a5a1b3Sopenharmony_ci for (;;) { 5253a5a1b3Sopenharmony_ci void *data; 5353a5a1b3Sopenharmony_ci 5453a5a1b3Sopenharmony_ci fail_unless((nbytes = pa_stream_writable_size(p)) != (size_t) -1); 5553a5a1b3Sopenharmony_ci 5653a5a1b3Sopenharmony_ci if (nbytes <= 0) 5753a5a1b3Sopenharmony_ci break; 5853a5a1b3Sopenharmony_ci 5953a5a1b3Sopenharmony_ci fail_unless(pa_stream_begin_write(p, &data, &nbytes) == 0); 6053a5a1b3Sopenharmony_ci pa_memzero(data, nbytes); 6153a5a1b3Sopenharmony_ci fail_unless(pa_stream_write(p, data, nbytes, NULL, 0, PA_SEEK_RELATIVE) == 0); 6253a5a1b3Sopenharmony_ci } 6353a5a1b3Sopenharmony_ci} 6453a5a1b3Sopenharmony_ci 6553a5a1b3Sopenharmony_cistatic void stream_read_cb(pa_stream *p, size_t nbytes, void *userdata) { 6653a5a1b3Sopenharmony_ci /* We don't care about the data, just drop it */ 6753a5a1b3Sopenharmony_ci 6853a5a1b3Sopenharmony_ci for (;;) { 6953a5a1b3Sopenharmony_ci const void *data; 7053a5a1b3Sopenharmony_ci 7153a5a1b3Sopenharmony_ci pa_assert_se((nbytes = pa_stream_readable_size(p)) != (size_t) -1); 7253a5a1b3Sopenharmony_ci 7353a5a1b3Sopenharmony_ci if (nbytes <= 0) 7453a5a1b3Sopenharmony_ci break; 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_ci fail_unless(pa_stream_peek(p, &data, &nbytes) == 0); 7753a5a1b3Sopenharmony_ci fail_unless(pa_stream_drop(p) == 0); 7853a5a1b3Sopenharmony_ci } 7953a5a1b3Sopenharmony_ci} 8053a5a1b3Sopenharmony_ci 8153a5a1b3Sopenharmony_cistatic void stream_latency_cb(pa_stream *p, void *userdata) { 8253a5a1b3Sopenharmony_ci#ifndef INTERPOLATE 8353a5a1b3Sopenharmony_ci pa_operation *o; 8453a5a1b3Sopenharmony_ci 8553a5a1b3Sopenharmony_ci o = pa_stream_update_timing_info(p, NULL, NULL); 8653a5a1b3Sopenharmony_ci pa_operation_unref(o); 8753a5a1b3Sopenharmony_ci#endif 8853a5a1b3Sopenharmony_ci} 8953a5a1b3Sopenharmony_ci 9053a5a1b3Sopenharmony_ci/* This is called whenever the context status changes */ 9153a5a1b3Sopenharmony_cistatic void context_state_callback(pa_context *c, void *userdata) { 9253a5a1b3Sopenharmony_ci fail_unless(c != NULL); 9353a5a1b3Sopenharmony_ci 9453a5a1b3Sopenharmony_ci switch (pa_context_get_state(c)) { 9553a5a1b3Sopenharmony_ci case PA_CONTEXT_CONNECTING: 9653a5a1b3Sopenharmony_ci case PA_CONTEXT_AUTHORIZING: 9753a5a1b3Sopenharmony_ci case PA_CONTEXT_SETTING_NAME: 9853a5a1b3Sopenharmony_ci break; 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_ci case PA_CONTEXT_READY: { 10153a5a1b3Sopenharmony_ci pa_stream_flags_t flags = PA_STREAM_AUTO_TIMING_UPDATE; 10253a5a1b3Sopenharmony_ci pa_buffer_attr attr; 10353a5a1b3Sopenharmony_ci static const pa_sample_spec ss = { 10453a5a1b3Sopenharmony_ci .format = PA_SAMPLE_S16LE, 10553a5a1b3Sopenharmony_ci .rate = 44100, 10653a5a1b3Sopenharmony_ci .channels = 2 10753a5a1b3Sopenharmony_ci }; 10853a5a1b3Sopenharmony_ci 10953a5a1b3Sopenharmony_ci pa_zero(attr); 11053a5a1b3Sopenharmony_ci attr.maxlength = (uint32_t) -1; 11153a5a1b3Sopenharmony_ci attr.tlength = latency > 0 ? (uint32_t) pa_usec_to_bytes(latency, &ss) : (uint32_t) -1; 11253a5a1b3Sopenharmony_ci attr.prebuf = (uint32_t) -1; 11353a5a1b3Sopenharmony_ci attr.minreq = (uint32_t) -1; 11453a5a1b3Sopenharmony_ci attr.fragsize = (uint32_t) -1; 11553a5a1b3Sopenharmony_ci 11653a5a1b3Sopenharmony_ci#ifdef INTERPOLATE 11753a5a1b3Sopenharmony_ci flags |= PA_STREAM_INTERPOLATE_TIMING; 11853a5a1b3Sopenharmony_ci#endif 11953a5a1b3Sopenharmony_ci 12053a5a1b3Sopenharmony_ci if (latency > 0) 12153a5a1b3Sopenharmony_ci flags |= PA_STREAM_ADJUST_LATENCY; 12253a5a1b3Sopenharmony_ci 12353a5a1b3Sopenharmony_ci pa_log("Connection established"); 12453a5a1b3Sopenharmony_ci 12553a5a1b3Sopenharmony_ci stream = pa_stream_new(c, "interpol-test", &ss, NULL); 12653a5a1b3Sopenharmony_ci fail_unless(stream != NULL); 12753a5a1b3Sopenharmony_ci 12853a5a1b3Sopenharmony_ci if (playback) { 12953a5a1b3Sopenharmony_ci pa_assert_se(pa_stream_connect_playback(stream, NULL, &attr, flags, NULL, NULL) == 0); 13053a5a1b3Sopenharmony_ci pa_stream_set_write_callback(stream, stream_write_cb, NULL); 13153a5a1b3Sopenharmony_ci } else { 13253a5a1b3Sopenharmony_ci pa_assert_se(pa_stream_connect_record(stream, NULL, &attr, flags) == 0); 13353a5a1b3Sopenharmony_ci pa_stream_set_read_callback(stream, stream_read_cb, NULL); 13453a5a1b3Sopenharmony_ci } 13553a5a1b3Sopenharmony_ci 13653a5a1b3Sopenharmony_ci pa_stream_set_latency_update_callback(stream, stream_latency_cb, NULL); 13753a5a1b3Sopenharmony_ci 13853a5a1b3Sopenharmony_ci break; 13953a5a1b3Sopenharmony_ci } 14053a5a1b3Sopenharmony_ci 14153a5a1b3Sopenharmony_ci case PA_CONTEXT_TERMINATED: 14253a5a1b3Sopenharmony_ci break; 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_ci case PA_CONTEXT_FAILED: 14553a5a1b3Sopenharmony_ci default: 14653a5a1b3Sopenharmony_ci pa_log_error("Context error: %s", pa_strerror(pa_context_errno(c))); 14753a5a1b3Sopenharmony_ci ck_abort(); 14853a5a1b3Sopenharmony_ci } 14953a5a1b3Sopenharmony_ci} 15053a5a1b3Sopenharmony_ci 15153a5a1b3Sopenharmony_ciSTART_TEST (interpol_test) { 15253a5a1b3Sopenharmony_ci pa_threaded_mainloop* m = NULL; 15353a5a1b3Sopenharmony_ci int k; 15453a5a1b3Sopenharmony_ci struct timeval start, last_info = { 0, 0 }; 15553a5a1b3Sopenharmony_ci pa_usec_t old_t = 0, old_rtc = 0; 15653a5a1b3Sopenharmony_ci#ifdef CORK 15753a5a1b3Sopenharmony_ci bool corked = false; 15853a5a1b3Sopenharmony_ci#endif 15953a5a1b3Sopenharmony_ci 16053a5a1b3Sopenharmony_ci /* Set up a new main loop */ 16153a5a1b3Sopenharmony_ci m = pa_threaded_mainloop_new(); 16253a5a1b3Sopenharmony_ci fail_unless(m != NULL); 16353a5a1b3Sopenharmony_ci mainloop_api = pa_threaded_mainloop_get_api(m); 16453a5a1b3Sopenharmony_ci fail_unless(mainloop_api != NULL); 16553a5a1b3Sopenharmony_ci context = pa_context_new(mainloop_api, bname); 16653a5a1b3Sopenharmony_ci fail_unless(context != NULL); 16753a5a1b3Sopenharmony_ci 16853a5a1b3Sopenharmony_ci pa_context_set_state_callback(context, context_state_callback, NULL); 16953a5a1b3Sopenharmony_ci 17053a5a1b3Sopenharmony_ci fail_unless(pa_context_connect(context, NULL, 0, NULL) >= 0); 17153a5a1b3Sopenharmony_ci 17253a5a1b3Sopenharmony_ci pa_gettimeofday(&start); 17353a5a1b3Sopenharmony_ci 17453a5a1b3Sopenharmony_ci fail_unless(pa_threaded_mainloop_start(m) >= 0); 17553a5a1b3Sopenharmony_ci 17653a5a1b3Sopenharmony_ci/* #ifdef CORK */ 17753a5a1b3Sopenharmony_ci for (k = 0; k < 20000; k++) 17853a5a1b3Sopenharmony_ci/* #else */ 17953a5a1b3Sopenharmony_ci/* for (k = 0; k < 2000; k++) */ 18053a5a1b3Sopenharmony_ci/* #endif */ 18153a5a1b3Sopenharmony_ci { 18253a5a1b3Sopenharmony_ci bool success = false, changed = false; 18353a5a1b3Sopenharmony_ci pa_usec_t t, rtc, d; 18453a5a1b3Sopenharmony_ci struct timeval now, tv; 18553a5a1b3Sopenharmony_ci bool playing = false; 18653a5a1b3Sopenharmony_ci 18753a5a1b3Sopenharmony_ci pa_threaded_mainloop_lock(m); 18853a5a1b3Sopenharmony_ci 18953a5a1b3Sopenharmony_ci if (stream) { 19053a5a1b3Sopenharmony_ci const pa_timing_info *info; 19153a5a1b3Sopenharmony_ci 19253a5a1b3Sopenharmony_ci if (pa_stream_get_time(stream, &t) >= 0 && 19353a5a1b3Sopenharmony_ci pa_stream_get_latency(stream, &d, NULL) >= 0) 19453a5a1b3Sopenharmony_ci success = true; 19553a5a1b3Sopenharmony_ci 19653a5a1b3Sopenharmony_ci if ((info = pa_stream_get_timing_info(stream))) { 19753a5a1b3Sopenharmony_ci if (memcmp(&last_info, &info->timestamp, sizeof(struct timeval))) { 19853a5a1b3Sopenharmony_ci changed = true; 19953a5a1b3Sopenharmony_ci last_info = info->timestamp; 20053a5a1b3Sopenharmony_ci } 20153a5a1b3Sopenharmony_ci if (info->playing) 20253a5a1b3Sopenharmony_ci playing = true; 20353a5a1b3Sopenharmony_ci } 20453a5a1b3Sopenharmony_ci } 20553a5a1b3Sopenharmony_ci 20653a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(m); 20753a5a1b3Sopenharmony_ci 20853a5a1b3Sopenharmony_ci pa_gettimeofday(&now); 20953a5a1b3Sopenharmony_ci 21053a5a1b3Sopenharmony_ci if (success) { 21153a5a1b3Sopenharmony_ci#ifdef CORK 21253a5a1b3Sopenharmony_ci bool cork_now; 21353a5a1b3Sopenharmony_ci#endif 21453a5a1b3Sopenharmony_ci rtc = pa_timeval_diff(&now, &start); 21553a5a1b3Sopenharmony_ci pa_log_info("%i\t%llu\t%llu\t%llu\t%llu\t%lli\t%u\t%u\t%llu\t%llu", k, 21653a5a1b3Sopenharmony_ci (unsigned long long) rtc, 21753a5a1b3Sopenharmony_ci (unsigned long long) t, 21853a5a1b3Sopenharmony_ci (unsigned long long) (rtc-old_rtc), 21953a5a1b3Sopenharmony_ci (unsigned long long) (t-old_t), 22053a5a1b3Sopenharmony_ci (signed long long) rtc - (signed long long) t, 22153a5a1b3Sopenharmony_ci changed, 22253a5a1b3Sopenharmony_ci playing, 22353a5a1b3Sopenharmony_ci (unsigned long long) latency, 22453a5a1b3Sopenharmony_ci (unsigned long long) d); 22553a5a1b3Sopenharmony_ci 22653a5a1b3Sopenharmony_ci fflush(stdout); 22753a5a1b3Sopenharmony_ci old_t = t; 22853a5a1b3Sopenharmony_ci old_rtc = rtc; 22953a5a1b3Sopenharmony_ci 23053a5a1b3Sopenharmony_ci#ifdef CORK 23153a5a1b3Sopenharmony_ci cork_now = (rtc / (2*PA_USEC_PER_SEC)) % 2 == 1; 23253a5a1b3Sopenharmony_ci 23353a5a1b3Sopenharmony_ci if (corked != cork_now) { 23453a5a1b3Sopenharmony_ci pa_threaded_mainloop_lock(m); 23553a5a1b3Sopenharmony_ci pa_operation_unref(pa_stream_cork(stream, cork_now, NULL, NULL)); 23653a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(m); 23753a5a1b3Sopenharmony_ci 23853a5a1b3Sopenharmony_ci pa_log(cork_now ? "Corking" : "Uncorking"); 23953a5a1b3Sopenharmony_ci 24053a5a1b3Sopenharmony_ci corked = cork_now; 24153a5a1b3Sopenharmony_ci } 24253a5a1b3Sopenharmony_ci#endif 24353a5a1b3Sopenharmony_ci } 24453a5a1b3Sopenharmony_ci 24553a5a1b3Sopenharmony_ci /* Spin loop, ugly but normal usleep() is just too badly grained */ 24653a5a1b3Sopenharmony_ci tv = now; 24753a5a1b3Sopenharmony_ci while (pa_timeval_diff(pa_gettimeofday(&now), &tv) < 1000) 24853a5a1b3Sopenharmony_ci pa_thread_yield(); 24953a5a1b3Sopenharmony_ci } 25053a5a1b3Sopenharmony_ci 25153a5a1b3Sopenharmony_ci if (m) 25253a5a1b3Sopenharmony_ci pa_threaded_mainloop_stop(m); 25353a5a1b3Sopenharmony_ci 25453a5a1b3Sopenharmony_ci if (stream) { 25553a5a1b3Sopenharmony_ci pa_stream_disconnect(stream); 25653a5a1b3Sopenharmony_ci pa_stream_unref(stream); 25753a5a1b3Sopenharmony_ci } 25853a5a1b3Sopenharmony_ci 25953a5a1b3Sopenharmony_ci if (context) { 26053a5a1b3Sopenharmony_ci pa_context_disconnect(context); 26153a5a1b3Sopenharmony_ci pa_context_unref(context); 26253a5a1b3Sopenharmony_ci } 26353a5a1b3Sopenharmony_ci 26453a5a1b3Sopenharmony_ci if (m) 26553a5a1b3Sopenharmony_ci pa_threaded_mainloop_free(m); 26653a5a1b3Sopenharmony_ci} 26753a5a1b3Sopenharmony_ciEND_TEST 26853a5a1b3Sopenharmony_ci 26953a5a1b3Sopenharmony_ciint main(int argc, char *argv[]) { 27053a5a1b3Sopenharmony_ci int failed = 0; 27153a5a1b3Sopenharmony_ci Suite *s; 27253a5a1b3Sopenharmony_ci TCase *tc; 27353a5a1b3Sopenharmony_ci SRunner *sr; 27453a5a1b3Sopenharmony_ci 27553a5a1b3Sopenharmony_ci if (!getenv("MAKE_CHECK")) 27653a5a1b3Sopenharmony_ci pa_log_set_level(PA_LOG_DEBUG); 27753a5a1b3Sopenharmony_ci 27853a5a1b3Sopenharmony_ci bname = argv[0]; 27953a5a1b3Sopenharmony_ci playback = argc <= 1 || !pa_streq(argv[1], "-r"); 28053a5a1b3Sopenharmony_ci latency = (argc >= 2 && !pa_streq(argv[1], "-r")) ? atoi(argv[1]) : (argc >= 3 ? atoi(argv[2]) : 0); 28153a5a1b3Sopenharmony_ci 28253a5a1b3Sopenharmony_ci s = suite_create("Interpol"); 28353a5a1b3Sopenharmony_ci tc = tcase_create("interpol"); 28453a5a1b3Sopenharmony_ci tcase_add_test(tc, interpol_test); 28553a5a1b3Sopenharmony_ci tcase_set_timeout(tc, 5 * 60); 28653a5a1b3Sopenharmony_ci suite_add_tcase(s, tc); 28753a5a1b3Sopenharmony_ci 28853a5a1b3Sopenharmony_ci sr = srunner_create(s); 28953a5a1b3Sopenharmony_ci srunner_run_all(sr, CK_NORMAL); 29053a5a1b3Sopenharmony_ci failed = srunner_ntests_failed(sr); 29153a5a1b3Sopenharmony_ci srunner_free(sr); 29253a5a1b3Sopenharmony_ci 29353a5a1b3Sopenharmony_ci return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 29453a5a1b3Sopenharmony_ci} 295