153a5a1b3Sopenharmony_ci 253a5a1b3Sopenharmony_ci/*** 353a5a1b3Sopenharmony_ci This file is part of PulseAudio. 453a5a1b3Sopenharmony_ci 553a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 953a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 1053a5a1b3Sopenharmony_ci or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1853a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#include <stdio.h> 2653a5a1b3Sopenharmony_ci#include <string.h> 2753a5a1b3Sopenharmony_ci#include <stdlib.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#include <pulse/pulseaudio.h> 3053a5a1b3Sopenharmony_ci#include <pulse/thread-mainloop.h> 3153a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 3453a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 3553a5a1b3Sopenharmony_ci 3653a5a1b3Sopenharmony_ci#include "simple.h" 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_cistruct pa_simple { 3953a5a1b3Sopenharmony_ci pa_threaded_mainloop *mainloop; 4053a5a1b3Sopenharmony_ci pa_context *context; 4153a5a1b3Sopenharmony_ci pa_stream *stream; 4253a5a1b3Sopenharmony_ci pa_stream_direction_t direction; 4353a5a1b3Sopenharmony_ci 4453a5a1b3Sopenharmony_ci const void *read_data; 4553a5a1b3Sopenharmony_ci size_t read_index, read_length; 4653a5a1b3Sopenharmony_ci 4753a5a1b3Sopenharmony_ci int operation_success; 4853a5a1b3Sopenharmony_ci}; 4953a5a1b3Sopenharmony_ci 5053a5a1b3Sopenharmony_ci#define CHECK_VALIDITY_RETURN_ANY(rerror, expression, error, ret) \ 5153a5a1b3Sopenharmony_ci do { \ 5253a5a1b3Sopenharmony_ci if (!(expression)) { \ 5353a5a1b3Sopenharmony_ci if (rerror) \ 5453a5a1b3Sopenharmony_ci *(rerror) = error; \ 5553a5a1b3Sopenharmony_ci return (ret); \ 5653a5a1b3Sopenharmony_ci } \ 5753a5a1b3Sopenharmony_ci } while(false); 5853a5a1b3Sopenharmony_ci 5953a5a1b3Sopenharmony_ci#define CHECK_SUCCESS_GOTO(p, rerror, expression, label) \ 6053a5a1b3Sopenharmony_ci do { \ 6153a5a1b3Sopenharmony_ci if (!(expression)) { \ 6253a5a1b3Sopenharmony_ci if (rerror) \ 6353a5a1b3Sopenharmony_ci *(rerror) = pa_context_errno((p)->context); \ 6453a5a1b3Sopenharmony_ci goto label; \ 6553a5a1b3Sopenharmony_ci } \ 6653a5a1b3Sopenharmony_ci } while(false); 6753a5a1b3Sopenharmony_ci 6853a5a1b3Sopenharmony_ci#define CHECK_DEAD_GOTO(p, rerror, label) \ 6953a5a1b3Sopenharmony_ci do { \ 7053a5a1b3Sopenharmony_ci if (!(p)->context || !PA_CONTEXT_IS_GOOD(pa_context_get_state((p)->context)) || \ 7153a5a1b3Sopenharmony_ci !(p)->stream || !PA_STREAM_IS_GOOD(pa_stream_get_state((p)->stream))) { \ 7253a5a1b3Sopenharmony_ci if (((p)->context && pa_context_get_state((p)->context) == PA_CONTEXT_FAILED) || \ 7353a5a1b3Sopenharmony_ci ((p)->stream && pa_stream_get_state((p)->stream) == PA_STREAM_FAILED)) { \ 7453a5a1b3Sopenharmony_ci if (rerror) \ 7553a5a1b3Sopenharmony_ci *(rerror) = pa_context_errno((p)->context); \ 7653a5a1b3Sopenharmony_ci } else \ 7753a5a1b3Sopenharmony_ci if (rerror) \ 7853a5a1b3Sopenharmony_ci *(rerror) = PA_ERR_BADSTATE; \ 7953a5a1b3Sopenharmony_ci goto label; \ 8053a5a1b3Sopenharmony_ci } \ 8153a5a1b3Sopenharmony_ci } while(false); 8253a5a1b3Sopenharmony_ci 8353a5a1b3Sopenharmony_cistatic void context_state_cb(pa_context *c, void *userdata) { 8453a5a1b3Sopenharmony_ci pa_simple *p = userdata; 8553a5a1b3Sopenharmony_ci pa_assert(c); 8653a5a1b3Sopenharmony_ci pa_assert(p); 8753a5a1b3Sopenharmony_ci 8853a5a1b3Sopenharmony_ci switch (pa_context_get_state(c)) { 8953a5a1b3Sopenharmony_ci case PA_CONTEXT_READY: 9053a5a1b3Sopenharmony_ci case PA_CONTEXT_TERMINATED: 9153a5a1b3Sopenharmony_ci case PA_CONTEXT_FAILED: 9253a5a1b3Sopenharmony_ci pa_threaded_mainloop_signal(p->mainloop, 0); 9353a5a1b3Sopenharmony_ci break; 9453a5a1b3Sopenharmony_ci 9553a5a1b3Sopenharmony_ci case PA_CONTEXT_UNCONNECTED: 9653a5a1b3Sopenharmony_ci case PA_CONTEXT_CONNECTING: 9753a5a1b3Sopenharmony_ci case PA_CONTEXT_AUTHORIZING: 9853a5a1b3Sopenharmony_ci case PA_CONTEXT_SETTING_NAME: 9953a5a1b3Sopenharmony_ci break; 10053a5a1b3Sopenharmony_ci } 10153a5a1b3Sopenharmony_ci} 10253a5a1b3Sopenharmony_ci 10353a5a1b3Sopenharmony_cistatic void stream_state_cb(pa_stream *s, void * userdata) { 10453a5a1b3Sopenharmony_ci pa_simple *p = userdata; 10553a5a1b3Sopenharmony_ci pa_assert(s); 10653a5a1b3Sopenharmony_ci pa_assert(p); 10753a5a1b3Sopenharmony_ci 10853a5a1b3Sopenharmony_ci switch (pa_stream_get_state(s)) { 10953a5a1b3Sopenharmony_ci 11053a5a1b3Sopenharmony_ci case PA_STREAM_READY: 11153a5a1b3Sopenharmony_ci case PA_STREAM_FAILED: 11253a5a1b3Sopenharmony_ci case PA_STREAM_TERMINATED: 11353a5a1b3Sopenharmony_ci pa_threaded_mainloop_signal(p->mainloop, 0); 11453a5a1b3Sopenharmony_ci break; 11553a5a1b3Sopenharmony_ci 11653a5a1b3Sopenharmony_ci case PA_STREAM_UNCONNECTED: 11753a5a1b3Sopenharmony_ci case PA_STREAM_CREATING: 11853a5a1b3Sopenharmony_ci break; 11953a5a1b3Sopenharmony_ci } 12053a5a1b3Sopenharmony_ci} 12153a5a1b3Sopenharmony_ci 12253a5a1b3Sopenharmony_cistatic void stream_request_cb(pa_stream *s, size_t length, void *userdata) { 12353a5a1b3Sopenharmony_ci pa_simple *p = userdata; 12453a5a1b3Sopenharmony_ci pa_assert(p); 12553a5a1b3Sopenharmony_ci 12653a5a1b3Sopenharmony_ci pa_threaded_mainloop_signal(p->mainloop, 0); 12753a5a1b3Sopenharmony_ci} 12853a5a1b3Sopenharmony_ci 12953a5a1b3Sopenharmony_cistatic void stream_latency_update_cb(pa_stream *s, void *userdata) { 13053a5a1b3Sopenharmony_ci pa_simple *p = userdata; 13153a5a1b3Sopenharmony_ci 13253a5a1b3Sopenharmony_ci pa_assert(p); 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci pa_threaded_mainloop_signal(p->mainloop, 0); 13553a5a1b3Sopenharmony_ci} 13653a5a1b3Sopenharmony_ci 13753a5a1b3Sopenharmony_cipa_simple* pa_simple_new( 13853a5a1b3Sopenharmony_ci const char *server, 13953a5a1b3Sopenharmony_ci const char *name, 14053a5a1b3Sopenharmony_ci pa_stream_direction_t dir, 14153a5a1b3Sopenharmony_ci const char *dev, 14253a5a1b3Sopenharmony_ci const char *stream_name, 14353a5a1b3Sopenharmony_ci const pa_sample_spec *ss, 14453a5a1b3Sopenharmony_ci const pa_channel_map *map, 14553a5a1b3Sopenharmony_ci const pa_buffer_attr *attr, 14653a5a1b3Sopenharmony_ci int *rerror) { 14753a5a1b3Sopenharmony_ci 14853a5a1b3Sopenharmony_ci pa_simple *p; 14953a5a1b3Sopenharmony_ci int error = PA_ERR_INTERNAL, r; 15053a5a1b3Sopenharmony_ci 15153a5a1b3Sopenharmony_ci CHECK_VALIDITY_RETURN_ANY(rerror, !server || *server, PA_ERR_INVALID, NULL); 15253a5a1b3Sopenharmony_ci CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL); 15353a5a1b3Sopenharmony_ci CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL); 15453a5a1b3Sopenharmony_ci CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL); 15553a5a1b3Sopenharmony_ci CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL) 15653a5a1b3Sopenharmony_ci 15753a5a1b3Sopenharmony_ci p = pa_xnew0(pa_simple, 1); 15853a5a1b3Sopenharmony_ci p->direction = dir; 15953a5a1b3Sopenharmony_ci 16053a5a1b3Sopenharmony_ci if (!(p->mainloop = pa_threaded_mainloop_new())) 16153a5a1b3Sopenharmony_ci goto fail; 16253a5a1b3Sopenharmony_ci 16353a5a1b3Sopenharmony_ci if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name))) 16453a5a1b3Sopenharmony_ci goto fail; 16553a5a1b3Sopenharmony_ci 16653a5a1b3Sopenharmony_ci pa_context_set_state_callback(p->context, context_state_cb, p); 16753a5a1b3Sopenharmony_ci 16853a5a1b3Sopenharmony_ci if (pa_context_connect(p->context, server, 0, NULL) < 0) { 16953a5a1b3Sopenharmony_ci error = pa_context_errno(p->context); 17053a5a1b3Sopenharmony_ci goto fail; 17153a5a1b3Sopenharmony_ci } 17253a5a1b3Sopenharmony_ci 17353a5a1b3Sopenharmony_ci pa_threaded_mainloop_lock(p->mainloop); 17453a5a1b3Sopenharmony_ci 17553a5a1b3Sopenharmony_ci if (pa_threaded_mainloop_start(p->mainloop) < 0) 17653a5a1b3Sopenharmony_ci goto unlock_and_fail; 17753a5a1b3Sopenharmony_ci 17853a5a1b3Sopenharmony_ci for (;;) { 17953a5a1b3Sopenharmony_ci pa_context_state_t state; 18053a5a1b3Sopenharmony_ci 18153a5a1b3Sopenharmony_ci state = pa_context_get_state(p->context); 18253a5a1b3Sopenharmony_ci 18353a5a1b3Sopenharmony_ci if (state == PA_CONTEXT_READY) 18453a5a1b3Sopenharmony_ci break; 18553a5a1b3Sopenharmony_ci 18653a5a1b3Sopenharmony_ci if (!PA_CONTEXT_IS_GOOD(state)) { 18753a5a1b3Sopenharmony_ci error = pa_context_errno(p->context); 18853a5a1b3Sopenharmony_ci goto unlock_and_fail; 18953a5a1b3Sopenharmony_ci } 19053a5a1b3Sopenharmony_ci 19153a5a1b3Sopenharmony_ci /* Wait until the context is ready */ 19253a5a1b3Sopenharmony_ci pa_threaded_mainloop_wait(p->mainloop); 19353a5a1b3Sopenharmony_ci } 19453a5a1b3Sopenharmony_ci 19553a5a1b3Sopenharmony_ci if (!(p->stream = pa_stream_new(p->context, stream_name, ss, map))) { 19653a5a1b3Sopenharmony_ci error = pa_context_errno(p->context); 19753a5a1b3Sopenharmony_ci goto unlock_and_fail; 19853a5a1b3Sopenharmony_ci } 19953a5a1b3Sopenharmony_ci 20053a5a1b3Sopenharmony_ci pa_stream_set_state_callback(p->stream, stream_state_cb, p); 20153a5a1b3Sopenharmony_ci pa_stream_set_read_callback(p->stream, stream_request_cb, p); 20253a5a1b3Sopenharmony_ci pa_stream_set_write_callback(p->stream, stream_request_cb, p); 20353a5a1b3Sopenharmony_ci pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p); 20453a5a1b3Sopenharmony_ci 20553a5a1b3Sopenharmony_ci if (dir == PA_STREAM_PLAYBACK) 20653a5a1b3Sopenharmony_ci r = pa_stream_connect_playback(p->stream, dev, attr, 20753a5a1b3Sopenharmony_ci PA_STREAM_INTERPOLATE_TIMING 20853a5a1b3Sopenharmony_ci |PA_STREAM_ADJUST_LATENCY 20953a5a1b3Sopenharmony_ci |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); 21053a5a1b3Sopenharmony_ci else 21153a5a1b3Sopenharmony_ci r = pa_stream_connect_record(p->stream, dev, attr, 21253a5a1b3Sopenharmony_ci PA_STREAM_INTERPOLATE_TIMING 21353a5a1b3Sopenharmony_ci |PA_STREAM_ADJUST_LATENCY 21453a5a1b3Sopenharmony_ci |PA_STREAM_AUTO_TIMING_UPDATE); 21553a5a1b3Sopenharmony_ci 21653a5a1b3Sopenharmony_ci if (r < 0) { 21753a5a1b3Sopenharmony_ci error = pa_context_errno(p->context); 21853a5a1b3Sopenharmony_ci goto unlock_and_fail; 21953a5a1b3Sopenharmony_ci } 22053a5a1b3Sopenharmony_ci 22153a5a1b3Sopenharmony_ci for (;;) { 22253a5a1b3Sopenharmony_ci pa_stream_state_t state; 22353a5a1b3Sopenharmony_ci 22453a5a1b3Sopenharmony_ci state = pa_stream_get_state(p->stream); 22553a5a1b3Sopenharmony_ci 22653a5a1b3Sopenharmony_ci if (state == PA_STREAM_READY) 22753a5a1b3Sopenharmony_ci break; 22853a5a1b3Sopenharmony_ci 22953a5a1b3Sopenharmony_ci if (!PA_STREAM_IS_GOOD(state)) { 23053a5a1b3Sopenharmony_ci error = pa_context_errno(p->context); 23153a5a1b3Sopenharmony_ci goto unlock_and_fail; 23253a5a1b3Sopenharmony_ci } 23353a5a1b3Sopenharmony_ci 23453a5a1b3Sopenharmony_ci /* Wait until the stream is ready */ 23553a5a1b3Sopenharmony_ci pa_threaded_mainloop_wait(p->mainloop); 23653a5a1b3Sopenharmony_ci } 23753a5a1b3Sopenharmony_ci 23853a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(p->mainloop); 23953a5a1b3Sopenharmony_ci 24053a5a1b3Sopenharmony_ci return p; 24153a5a1b3Sopenharmony_ci 24253a5a1b3Sopenharmony_ciunlock_and_fail: 24353a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(p->mainloop); 24453a5a1b3Sopenharmony_ci 24553a5a1b3Sopenharmony_cifail: 24653a5a1b3Sopenharmony_ci if (rerror) 24753a5a1b3Sopenharmony_ci *rerror = error; 24853a5a1b3Sopenharmony_ci pa_simple_free(p); 24953a5a1b3Sopenharmony_ci return NULL; 25053a5a1b3Sopenharmony_ci} 25153a5a1b3Sopenharmony_ci 25253a5a1b3Sopenharmony_civoid pa_simple_free(pa_simple *s) { 25353a5a1b3Sopenharmony_ci pa_assert(s); 25453a5a1b3Sopenharmony_ci 25553a5a1b3Sopenharmony_ci if (s->mainloop) 25653a5a1b3Sopenharmony_ci pa_threaded_mainloop_stop(s->mainloop); 25753a5a1b3Sopenharmony_ci 25853a5a1b3Sopenharmony_ci if (s->stream) 25953a5a1b3Sopenharmony_ci pa_stream_unref(s->stream); 26053a5a1b3Sopenharmony_ci 26153a5a1b3Sopenharmony_ci if (s->context) { 26253a5a1b3Sopenharmony_ci pa_context_disconnect(s->context); 26353a5a1b3Sopenharmony_ci pa_context_unref(s->context); 26453a5a1b3Sopenharmony_ci } 26553a5a1b3Sopenharmony_ci 26653a5a1b3Sopenharmony_ci if (s->mainloop) 26753a5a1b3Sopenharmony_ci pa_threaded_mainloop_free(s->mainloop); 26853a5a1b3Sopenharmony_ci 26953a5a1b3Sopenharmony_ci pa_xfree(s); 27053a5a1b3Sopenharmony_ci} 27153a5a1b3Sopenharmony_ci 27253a5a1b3Sopenharmony_ciint pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { 27353a5a1b3Sopenharmony_ci pa_assert(p); 27453a5a1b3Sopenharmony_ci 27553a5a1b3Sopenharmony_ci CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); 27653a5a1b3Sopenharmony_ci CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1); 27753a5a1b3Sopenharmony_ci CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1); 27853a5a1b3Sopenharmony_ci 27953a5a1b3Sopenharmony_ci pa_threaded_mainloop_lock(p->mainloop); 28053a5a1b3Sopenharmony_ci 28153a5a1b3Sopenharmony_ci CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 28253a5a1b3Sopenharmony_ci 28353a5a1b3Sopenharmony_ci while (length > 0) { 28453a5a1b3Sopenharmony_ci size_t l; 28553a5a1b3Sopenharmony_ci int r; 28653a5a1b3Sopenharmony_ci 28753a5a1b3Sopenharmony_ci while (!(l = pa_stream_writable_size(p->stream))) { 28853a5a1b3Sopenharmony_ci pa_threaded_mainloop_wait(p->mainloop); 28953a5a1b3Sopenharmony_ci CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 29053a5a1b3Sopenharmony_ci } 29153a5a1b3Sopenharmony_ci 29253a5a1b3Sopenharmony_ci CHECK_SUCCESS_GOTO(p, rerror, l != (size_t) -1, unlock_and_fail); 29353a5a1b3Sopenharmony_ci 29453a5a1b3Sopenharmony_ci if (l > length) 29553a5a1b3Sopenharmony_ci l = length; 29653a5a1b3Sopenharmony_ci 29753a5a1b3Sopenharmony_ci r = pa_stream_write(p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE); 29853a5a1b3Sopenharmony_ci CHECK_SUCCESS_GOTO(p, rerror, r >= 0, unlock_and_fail); 29953a5a1b3Sopenharmony_ci 30053a5a1b3Sopenharmony_ci data = (const uint8_t*) data + l; 30153a5a1b3Sopenharmony_ci length -= l; 30253a5a1b3Sopenharmony_ci } 30353a5a1b3Sopenharmony_ci 30453a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(p->mainloop); 30553a5a1b3Sopenharmony_ci return 0; 30653a5a1b3Sopenharmony_ci 30753a5a1b3Sopenharmony_ciunlock_and_fail: 30853a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(p->mainloop); 30953a5a1b3Sopenharmony_ci return -1; 31053a5a1b3Sopenharmony_ci} 31153a5a1b3Sopenharmony_ci 31253a5a1b3Sopenharmony_ciint pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { 31353a5a1b3Sopenharmony_ci pa_assert(p); 31453a5a1b3Sopenharmony_ci 31553a5a1b3Sopenharmony_ci CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1); 31653a5a1b3Sopenharmony_ci CHECK_VALIDITY_RETURN_ANY(rerror, data, PA_ERR_INVALID, -1); 31753a5a1b3Sopenharmony_ci CHECK_VALIDITY_RETURN_ANY(rerror, length > 0, PA_ERR_INVALID, -1); 31853a5a1b3Sopenharmony_ci 31953a5a1b3Sopenharmony_ci pa_threaded_mainloop_lock(p->mainloop); 32053a5a1b3Sopenharmony_ci 32153a5a1b3Sopenharmony_ci CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 32253a5a1b3Sopenharmony_ci 32353a5a1b3Sopenharmony_ci while (length > 0) { 32453a5a1b3Sopenharmony_ci size_t l; 32553a5a1b3Sopenharmony_ci 32653a5a1b3Sopenharmony_ci while (!p->read_data) { 32753a5a1b3Sopenharmony_ci int r; 32853a5a1b3Sopenharmony_ci 32953a5a1b3Sopenharmony_ci r = pa_stream_peek(p->stream, &p->read_data, &p->read_length); 33053a5a1b3Sopenharmony_ci CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); 33153a5a1b3Sopenharmony_ci 33253a5a1b3Sopenharmony_ci if (p->read_length <= 0) { 33353a5a1b3Sopenharmony_ci pa_threaded_mainloop_wait(p->mainloop); 33453a5a1b3Sopenharmony_ci CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 33553a5a1b3Sopenharmony_ci } else if (!p->read_data) { 33653a5a1b3Sopenharmony_ci /* There's a hole in the stream, skip it. We could generate 33753a5a1b3Sopenharmony_ci * silence, but that wouldn't work for compressed streams. */ 33853a5a1b3Sopenharmony_ci r = pa_stream_drop(p->stream); 33953a5a1b3Sopenharmony_ci CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); 34053a5a1b3Sopenharmony_ci } else 34153a5a1b3Sopenharmony_ci p->read_index = 0; 34253a5a1b3Sopenharmony_ci } 34353a5a1b3Sopenharmony_ci 34453a5a1b3Sopenharmony_ci l = p->read_length < length ? p->read_length : length; 34553a5a1b3Sopenharmony_ci memcpy(data, (const uint8_t*) p->read_data+p->read_index, l); 34653a5a1b3Sopenharmony_ci 34753a5a1b3Sopenharmony_ci data = (uint8_t*) data + l; 34853a5a1b3Sopenharmony_ci length -= l; 34953a5a1b3Sopenharmony_ci 35053a5a1b3Sopenharmony_ci p->read_index += l; 35153a5a1b3Sopenharmony_ci p->read_length -= l; 35253a5a1b3Sopenharmony_ci 35353a5a1b3Sopenharmony_ci if (!p->read_length) { 35453a5a1b3Sopenharmony_ci int r; 35553a5a1b3Sopenharmony_ci 35653a5a1b3Sopenharmony_ci r = pa_stream_drop(p->stream); 35753a5a1b3Sopenharmony_ci p->read_data = NULL; 35853a5a1b3Sopenharmony_ci p->read_length = 0; 35953a5a1b3Sopenharmony_ci p->read_index = 0; 36053a5a1b3Sopenharmony_ci 36153a5a1b3Sopenharmony_ci CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); 36253a5a1b3Sopenharmony_ci } 36353a5a1b3Sopenharmony_ci } 36453a5a1b3Sopenharmony_ci 36553a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(p->mainloop); 36653a5a1b3Sopenharmony_ci return 0; 36753a5a1b3Sopenharmony_ci 36853a5a1b3Sopenharmony_ciunlock_and_fail: 36953a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(p->mainloop); 37053a5a1b3Sopenharmony_ci return -1; 37153a5a1b3Sopenharmony_ci} 37253a5a1b3Sopenharmony_ci 37353a5a1b3Sopenharmony_cistatic void success_cb(pa_stream *s, int success, void *userdata) { 37453a5a1b3Sopenharmony_ci pa_simple *p = userdata; 37553a5a1b3Sopenharmony_ci 37653a5a1b3Sopenharmony_ci pa_assert(s); 37753a5a1b3Sopenharmony_ci pa_assert(p); 37853a5a1b3Sopenharmony_ci 37953a5a1b3Sopenharmony_ci p->operation_success = success; 38053a5a1b3Sopenharmony_ci pa_threaded_mainloop_signal(p->mainloop, 0); 38153a5a1b3Sopenharmony_ci} 38253a5a1b3Sopenharmony_ci 38353a5a1b3Sopenharmony_ciint pa_simple_drain(pa_simple *p, int *rerror) { 38453a5a1b3Sopenharmony_ci pa_operation *o = NULL; 38553a5a1b3Sopenharmony_ci 38653a5a1b3Sopenharmony_ci pa_assert(p); 38753a5a1b3Sopenharmony_ci 38853a5a1b3Sopenharmony_ci CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); 38953a5a1b3Sopenharmony_ci 39053a5a1b3Sopenharmony_ci pa_threaded_mainloop_lock(p->mainloop); 39153a5a1b3Sopenharmony_ci CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 39253a5a1b3Sopenharmony_ci 39353a5a1b3Sopenharmony_ci o = pa_stream_drain(p->stream, success_cb, p); 39453a5a1b3Sopenharmony_ci CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); 39553a5a1b3Sopenharmony_ci 39653a5a1b3Sopenharmony_ci p->operation_success = 0; 39753a5a1b3Sopenharmony_ci while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { 39853a5a1b3Sopenharmony_ci pa_threaded_mainloop_wait(p->mainloop); 39953a5a1b3Sopenharmony_ci CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 40053a5a1b3Sopenharmony_ci } 40153a5a1b3Sopenharmony_ci CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); 40253a5a1b3Sopenharmony_ci 40353a5a1b3Sopenharmony_ci pa_operation_unref(o); 40453a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(p->mainloop); 40553a5a1b3Sopenharmony_ci 40653a5a1b3Sopenharmony_ci return 0; 40753a5a1b3Sopenharmony_ci 40853a5a1b3Sopenharmony_ciunlock_and_fail: 40953a5a1b3Sopenharmony_ci 41053a5a1b3Sopenharmony_ci if (o) { 41153a5a1b3Sopenharmony_ci pa_operation_cancel(o); 41253a5a1b3Sopenharmony_ci pa_operation_unref(o); 41353a5a1b3Sopenharmony_ci } 41453a5a1b3Sopenharmony_ci 41553a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(p->mainloop); 41653a5a1b3Sopenharmony_ci return -1; 41753a5a1b3Sopenharmony_ci} 41853a5a1b3Sopenharmony_ci 41953a5a1b3Sopenharmony_ciint pa_simple_flush(pa_simple *p, int *rerror) { 42053a5a1b3Sopenharmony_ci pa_operation *o = NULL; 42153a5a1b3Sopenharmony_ci 42253a5a1b3Sopenharmony_ci pa_assert(p); 42353a5a1b3Sopenharmony_ci 42453a5a1b3Sopenharmony_ci pa_threaded_mainloop_lock(p->mainloop); 42553a5a1b3Sopenharmony_ci CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 42653a5a1b3Sopenharmony_ci 42753a5a1b3Sopenharmony_ci o = pa_stream_flush(p->stream, success_cb, p); 42853a5a1b3Sopenharmony_ci CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); 42953a5a1b3Sopenharmony_ci 43053a5a1b3Sopenharmony_ci p->operation_success = 0; 43153a5a1b3Sopenharmony_ci while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { 43253a5a1b3Sopenharmony_ci pa_threaded_mainloop_wait(p->mainloop); 43353a5a1b3Sopenharmony_ci CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 43453a5a1b3Sopenharmony_ci } 43553a5a1b3Sopenharmony_ci CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); 43653a5a1b3Sopenharmony_ci 43753a5a1b3Sopenharmony_ci pa_operation_unref(o); 43853a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(p->mainloop); 43953a5a1b3Sopenharmony_ci 44053a5a1b3Sopenharmony_ci return 0; 44153a5a1b3Sopenharmony_ci 44253a5a1b3Sopenharmony_ciunlock_and_fail: 44353a5a1b3Sopenharmony_ci 44453a5a1b3Sopenharmony_ci if (o) { 44553a5a1b3Sopenharmony_ci pa_operation_cancel(o); 44653a5a1b3Sopenharmony_ci pa_operation_unref(o); 44753a5a1b3Sopenharmony_ci } 44853a5a1b3Sopenharmony_ci 44953a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(p->mainloop); 45053a5a1b3Sopenharmony_ci return -1; 45153a5a1b3Sopenharmony_ci} 45253a5a1b3Sopenharmony_ci 45353a5a1b3Sopenharmony_cipa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) { 45453a5a1b3Sopenharmony_ci pa_usec_t t; 45553a5a1b3Sopenharmony_ci 45653a5a1b3Sopenharmony_ci pa_assert(p); 45753a5a1b3Sopenharmony_ci 45853a5a1b3Sopenharmony_ci pa_threaded_mainloop_lock(p->mainloop); 45953a5a1b3Sopenharmony_ci 46053a5a1b3Sopenharmony_ci for (;;) { 46153a5a1b3Sopenharmony_ci int negative; 46253a5a1b3Sopenharmony_ci 46353a5a1b3Sopenharmony_ci CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); 46453a5a1b3Sopenharmony_ci 46553a5a1b3Sopenharmony_ci if (pa_stream_get_latency(p->stream, &t, &negative) >= 0) { 46653a5a1b3Sopenharmony_ci if (p->direction == PA_STREAM_RECORD) { 46753a5a1b3Sopenharmony_ci pa_usec_t already_read; 46853a5a1b3Sopenharmony_ci 46953a5a1b3Sopenharmony_ci /* pa_simple_read() calls pa_stream_peek() to get the next 47053a5a1b3Sopenharmony_ci * chunk of audio. If the next chunk is larger than what the 47153a5a1b3Sopenharmony_ci * pa_simple_read() caller wanted, the leftover data is stored 47253a5a1b3Sopenharmony_ci * in p->read_data until pa_simple_read() is called again. 47353a5a1b3Sopenharmony_ci * pa_stream_drop() won't be called until the whole chunk has 47453a5a1b3Sopenharmony_ci * been consumed, which means that pa_stream_get_latency() will 47553a5a1b3Sopenharmony_ci * return too large values, because the whole size of the 47653a5a1b3Sopenharmony_ci * partially read chunk is included in the latency. Therefore, 47753a5a1b3Sopenharmony_ci * we need to subtract the already-read amount from the 47853a5a1b3Sopenharmony_ci * latency. */ 47953a5a1b3Sopenharmony_ci already_read = pa_bytes_to_usec(p->read_index, pa_stream_get_sample_spec(p->stream)); 48053a5a1b3Sopenharmony_ci 48153a5a1b3Sopenharmony_ci if (!negative) { 48253a5a1b3Sopenharmony_ci if (t > already_read) 48353a5a1b3Sopenharmony_ci t -= already_read; 48453a5a1b3Sopenharmony_ci else 48553a5a1b3Sopenharmony_ci t = 0; 48653a5a1b3Sopenharmony_ci } 48753a5a1b3Sopenharmony_ci } 48853a5a1b3Sopenharmony_ci 48953a5a1b3Sopenharmony_ci /* We don't have a way to report negative latencies from 49053a5a1b3Sopenharmony_ci * pa_simple_get_latency(). If the latency is negative, let's 49153a5a1b3Sopenharmony_ci * report zero. */ 49253a5a1b3Sopenharmony_ci if (negative) 49353a5a1b3Sopenharmony_ci t = 0; 49453a5a1b3Sopenharmony_ci 49553a5a1b3Sopenharmony_ci break; 49653a5a1b3Sopenharmony_ci } 49753a5a1b3Sopenharmony_ci 49853a5a1b3Sopenharmony_ci CHECK_SUCCESS_GOTO(p, rerror, pa_context_errno(p->context) == PA_ERR_NODATA, unlock_and_fail); 49953a5a1b3Sopenharmony_ci 50053a5a1b3Sopenharmony_ci /* Wait until latency data is available again */ 50153a5a1b3Sopenharmony_ci pa_threaded_mainloop_wait(p->mainloop); 50253a5a1b3Sopenharmony_ci } 50353a5a1b3Sopenharmony_ci 50453a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(p->mainloop); 50553a5a1b3Sopenharmony_ci 50653a5a1b3Sopenharmony_ci return t; 50753a5a1b3Sopenharmony_ci 50853a5a1b3Sopenharmony_ciunlock_and_fail: 50953a5a1b3Sopenharmony_ci 51053a5a1b3Sopenharmony_ci pa_threaded_mainloop_unlock(p->mainloop); 51153a5a1b3Sopenharmony_ci return (pa_usec_t) -1; 51253a5a1b3Sopenharmony_ci} 513