153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 753a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 853a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 953a5a1b3Sopenharmony_ci or (at your option) any later version. 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1253a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1353a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1453a5a1b3Sopenharmony_ci General Public License for more details. 1553a5a1b3Sopenharmony_ci 1653a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1753a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1853a5a1b3Sopenharmony_ci***/ 1953a5a1b3Sopenharmony_ci 2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2153a5a1b3Sopenharmony_ci#include <config.h> 2253a5a1b3Sopenharmony_ci#endif 2353a5a1b3Sopenharmony_ci 2453a5a1b3Sopenharmony_ci#include <stdlib.h> 2553a5a1b3Sopenharmony_ci#include <stdio.h> 2653a5a1b3Sopenharmony_ci#include <errno.h> 2753a5a1b3Sopenharmony_ci#include <string.h> 2853a5a1b3Sopenharmony_ci#include <unistd.h> 2953a5a1b3Sopenharmony_ci 3053a5a1b3Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 3153a5a1b3Sopenharmony_ci#include <netinet/in.h> 3253a5a1b3Sopenharmony_ci#endif 3353a5a1b3Sopenharmony_ci 3453a5a1b3Sopenharmony_ci#ifdef HAVE_NETINET_TCP_H 3553a5a1b3Sopenharmony_ci#include <netinet/tcp.h> 3653a5a1b3Sopenharmony_ci#endif 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H 3953a5a1b3Sopenharmony_ci#include <sys/ioctl.h> 4053a5a1b3Sopenharmony_ci#endif 4153a5a1b3Sopenharmony_ci 4253a5a1b3Sopenharmony_ci#ifdef HAVE_LINUX_SOCKIOS_H 4353a5a1b3Sopenharmony_ci#include <linux/sockios.h> 4453a5a1b3Sopenharmony_ci#endif 4553a5a1b3Sopenharmony_ci 4653a5a1b3Sopenharmony_ci#include <pulse/rtclock.h> 4753a5a1b3Sopenharmony_ci#include <pulse/timeval.h> 4853a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 4953a5a1b3Sopenharmony_ci 5053a5a1b3Sopenharmony_ci#include <pulsecore/socket.h> 5153a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h> 5253a5a1b3Sopenharmony_ci#include <pulsecore/iochannel.h> 5353a5a1b3Sopenharmony_ci#include <pulsecore/sink.h> 5453a5a1b3Sopenharmony_ci#include <pulsecore/module.h> 5553a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 5653a5a1b3Sopenharmony_ci#include <pulsecore/modargs.h> 5753a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 5853a5a1b3Sopenharmony_ci#include <pulsecore/socket-client.h> 5953a5a1b3Sopenharmony_ci#include <pulsecore/esound.h> 6053a5a1b3Sopenharmony_ci#include <pulsecore/authkey.h> 6153a5a1b3Sopenharmony_ci#include <pulsecore/thread-mq.h> 6253a5a1b3Sopenharmony_ci#include <pulsecore/thread.h> 6353a5a1b3Sopenharmony_ci 6453a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 6553a5a1b3Sopenharmony_ci#include <pulsecore/time-smoother_2.h> 6653a5a1b3Sopenharmony_ci#else 6753a5a1b3Sopenharmony_ci#include <pulsecore/time-smoother.h> 6853a5a1b3Sopenharmony_ci#endif 6953a5a1b3Sopenharmony_ci 7053a5a1b3Sopenharmony_ci#include <pulsecore/socket-util.h> 7153a5a1b3Sopenharmony_ci#include <pulsecore/rtpoll.h> 7253a5a1b3Sopenharmony_ci#include <pulsecore/poll.h> 7353a5a1b3Sopenharmony_ci 7453a5a1b3Sopenharmony_ciPA_MODULE_AUTHOR("Lennart Poettering"); 7553a5a1b3Sopenharmony_ciPA_MODULE_DESCRIPTION("ESOUND Sink"); 7653a5a1b3Sopenharmony_ciPA_MODULE_VERSION(PACKAGE_VERSION); 7753a5a1b3Sopenharmony_ciPA_MODULE_LOAD_ONCE(false); 7853a5a1b3Sopenharmony_ciPA_MODULE_USAGE( 7953a5a1b3Sopenharmony_ci "sink_name=<name for the sink> " 8053a5a1b3Sopenharmony_ci "sink_properties=<properties for the sink> " 8153a5a1b3Sopenharmony_ci "server=<address> cookie=<filename> " 8253a5a1b3Sopenharmony_ci "format=<sample format> " 8353a5a1b3Sopenharmony_ci "rate=<sample rate> " 8453a5a1b3Sopenharmony_ci "channels=<number of channels>"); 8553a5a1b3Sopenharmony_ci 8653a5a1b3Sopenharmony_ci#define DEFAULT_SINK_NAME "esound_out" 8753a5a1b3Sopenharmony_ci 8853a5a1b3Sopenharmony_cistruct userdata { 8953a5a1b3Sopenharmony_ci pa_core *core; 9053a5a1b3Sopenharmony_ci pa_module *module; 9153a5a1b3Sopenharmony_ci pa_sink *sink; 9253a5a1b3Sopenharmony_ci 9353a5a1b3Sopenharmony_ci pa_thread_mq thread_mq; 9453a5a1b3Sopenharmony_ci pa_rtpoll *rtpoll; 9553a5a1b3Sopenharmony_ci pa_rtpoll_item *rtpoll_item; 9653a5a1b3Sopenharmony_ci pa_thread *thread; 9753a5a1b3Sopenharmony_ci 9853a5a1b3Sopenharmony_ci pa_memchunk memchunk; 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_ci void *write_data; 10153a5a1b3Sopenharmony_ci size_t write_length, write_index; 10253a5a1b3Sopenharmony_ci 10353a5a1b3Sopenharmony_ci void *read_data; 10453a5a1b3Sopenharmony_ci size_t read_length, read_index; 10553a5a1b3Sopenharmony_ci 10653a5a1b3Sopenharmony_ci enum { 10753a5a1b3Sopenharmony_ci STATE_AUTH, 10853a5a1b3Sopenharmony_ci STATE_LATENCY, 10953a5a1b3Sopenharmony_ci STATE_PREPARE, 11053a5a1b3Sopenharmony_ci STATE_RUNNING, 11153a5a1b3Sopenharmony_ci STATE_DEAD 11253a5a1b3Sopenharmony_ci } state; 11353a5a1b3Sopenharmony_ci 11453a5a1b3Sopenharmony_ci pa_usec_t latency; 11553a5a1b3Sopenharmony_ci 11653a5a1b3Sopenharmony_ci esd_format_t format; 11753a5a1b3Sopenharmony_ci int32_t rate; 11853a5a1b3Sopenharmony_ci 11953a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 12053a5a1b3Sopenharmony_ci pa_smoother_2 *smoother; 12153a5a1b3Sopenharmony_ci#else 12253a5a1b3Sopenharmony_ci pa_smoother *smoother; 12353a5a1b3Sopenharmony_ci#endif 12453a5a1b3Sopenharmony_ci 12553a5a1b3Sopenharmony_ci int fd; 12653a5a1b3Sopenharmony_ci 12753a5a1b3Sopenharmony_ci int64_t offset; 12853a5a1b3Sopenharmony_ci 12953a5a1b3Sopenharmony_ci pa_iochannel *io; 13053a5a1b3Sopenharmony_ci pa_socket_client *client; 13153a5a1b3Sopenharmony_ci 13253a5a1b3Sopenharmony_ci size_t block_size; 13353a5a1b3Sopenharmony_ci}; 13453a5a1b3Sopenharmony_ci 13553a5a1b3Sopenharmony_cistatic const char* const valid_modargs[] = { 13653a5a1b3Sopenharmony_ci "sink_name", 13753a5a1b3Sopenharmony_ci "sink_properties", 13853a5a1b3Sopenharmony_ci "server", 13953a5a1b3Sopenharmony_ci "cookie", 14053a5a1b3Sopenharmony_ci "format", 14153a5a1b3Sopenharmony_ci "rate", 14253a5a1b3Sopenharmony_ci "channels", 14353a5a1b3Sopenharmony_ci NULL 14453a5a1b3Sopenharmony_ci}; 14553a5a1b3Sopenharmony_ci 14653a5a1b3Sopenharmony_cienum { 14753a5a1b3Sopenharmony_ci SINK_MESSAGE_PASS_SOCKET = PA_SINK_MESSAGE_MAX 14853a5a1b3Sopenharmony_ci}; 14953a5a1b3Sopenharmony_ci 15053a5a1b3Sopenharmony_cistatic int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { 15153a5a1b3Sopenharmony_ci struct userdata *u = PA_SINK(o)->userdata; 15253a5a1b3Sopenharmony_ci 15353a5a1b3Sopenharmony_ci switch (code) { 15453a5a1b3Sopenharmony_ci 15553a5a1b3Sopenharmony_ci case PA_SINK_MESSAGE_GET_LATENCY: { 15653a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 15753a5a1b3Sopenharmony_ci *((int64_t*) data) = pa_smoother_2_get_delay(u->smoother, pa_rtclock_now(), (uint64_t)u->offset + u->memchunk.length); 15853a5a1b3Sopenharmony_ci#else 15953a5a1b3Sopenharmony_ci pa_usec_t w, r; 16053a5a1b3Sopenharmony_ci 16153a5a1b3Sopenharmony_ci r = pa_smoother_get(u->smoother, pa_rtclock_now()); 16253a5a1b3Sopenharmony_ci w = pa_bytes_to_usec((uint64_t) u->offset + u->memchunk.length, &u->sink->sample_spec); 16353a5a1b3Sopenharmony_ci 16453a5a1b3Sopenharmony_ci *((int64_t*) data) = (int64_t)w - r; 16553a5a1b3Sopenharmony_ci#endif 16653a5a1b3Sopenharmony_ci return 0; 16753a5a1b3Sopenharmony_ci } 16853a5a1b3Sopenharmony_ci 16953a5a1b3Sopenharmony_ci case SINK_MESSAGE_PASS_SOCKET: { 17053a5a1b3Sopenharmony_ci struct pollfd *pollfd; 17153a5a1b3Sopenharmony_ci 17253a5a1b3Sopenharmony_ci pa_assert(!u->rtpoll_item); 17353a5a1b3Sopenharmony_ci 17453a5a1b3Sopenharmony_ci u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); 17553a5a1b3Sopenharmony_ci pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); 17653a5a1b3Sopenharmony_ci pollfd->fd = u->fd; 17753a5a1b3Sopenharmony_ci pollfd->events = pollfd->revents = 0; 17853a5a1b3Sopenharmony_ci 17953a5a1b3Sopenharmony_ci return 0; 18053a5a1b3Sopenharmony_ci } 18153a5a1b3Sopenharmony_ci } 18253a5a1b3Sopenharmony_ci 18353a5a1b3Sopenharmony_ci return pa_sink_process_msg(o, code, data, offset, chunk); 18453a5a1b3Sopenharmony_ci} 18553a5a1b3Sopenharmony_ci 18653a5a1b3Sopenharmony_ci/* Called from the IO thread. */ 18753a5a1b3Sopenharmony_cistatic int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { 18853a5a1b3Sopenharmony_ci struct userdata *u; 18953a5a1b3Sopenharmony_ci 19053a5a1b3Sopenharmony_ci pa_assert(s); 19153a5a1b3Sopenharmony_ci pa_assert_se(u = s->userdata); 19253a5a1b3Sopenharmony_ci 19353a5a1b3Sopenharmony_ci /* It may be that only the suspend cause is changing, in which case there's 19453a5a1b3Sopenharmony_ci * nothing to do. */ 19553a5a1b3Sopenharmony_ci if (new_state == s->thread_info.state) 19653a5a1b3Sopenharmony_ci return 0; 19753a5a1b3Sopenharmony_ci 19853a5a1b3Sopenharmony_ci switch (new_state) { 19953a5a1b3Sopenharmony_ci 20053a5a1b3Sopenharmony_ci case PA_SINK_SUSPENDED: 20153a5a1b3Sopenharmony_ci pa_assert(PA_SINK_IS_OPENED(s->thread_info.state)); 20253a5a1b3Sopenharmony_ci 20353a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 20453a5a1b3Sopenharmony_ci pa_smoother_2_pause(u->smoother, pa_rtclock_now()); 20553a5a1b3Sopenharmony_ci#else 20653a5a1b3Sopenharmony_ci pa_smoother_pause(u->smoother, pa_rtclock_now()); 20753a5a1b3Sopenharmony_ci#endif 20853a5a1b3Sopenharmony_ci break; 20953a5a1b3Sopenharmony_ci 21053a5a1b3Sopenharmony_ci case PA_SINK_IDLE: 21153a5a1b3Sopenharmony_ci case PA_SINK_RUNNING: 21253a5a1b3Sopenharmony_ci 21353a5a1b3Sopenharmony_ci if (s->thread_info.state == PA_SINK_SUSPENDED) 21453a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 21553a5a1b3Sopenharmony_ci pa_smoother_2_resume(u->smoother, pa_rtclock_now()); 21653a5a1b3Sopenharmony_ci#else 21753a5a1b3Sopenharmony_ci pa_smoother_resume(u->smoother, pa_rtclock_now(), true); 21853a5a1b3Sopenharmony_ci#endif 21953a5a1b3Sopenharmony_ci break; 22053a5a1b3Sopenharmony_ci 22153a5a1b3Sopenharmony_ci case PA_SINK_UNLINKED: 22253a5a1b3Sopenharmony_ci case PA_SINK_INIT: 22353a5a1b3Sopenharmony_ci case PA_SINK_INVALID_STATE: 22453a5a1b3Sopenharmony_ci ; 22553a5a1b3Sopenharmony_ci } 22653a5a1b3Sopenharmony_ci 22753a5a1b3Sopenharmony_ci return 0; 22853a5a1b3Sopenharmony_ci} 22953a5a1b3Sopenharmony_ci 23053a5a1b3Sopenharmony_cistatic void thread_func(void *userdata) { 23153a5a1b3Sopenharmony_ci struct userdata *u = userdata; 23253a5a1b3Sopenharmony_ci int write_type = 0; 23353a5a1b3Sopenharmony_ci 23453a5a1b3Sopenharmony_ci pa_assert(u); 23553a5a1b3Sopenharmony_ci 23653a5a1b3Sopenharmony_ci pa_log_debug("Thread starting up"); 23753a5a1b3Sopenharmony_ci 23853a5a1b3Sopenharmony_ci pa_thread_mq_install(&u->thread_mq); 23953a5a1b3Sopenharmony_ci 24053a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 24153a5a1b3Sopenharmony_ci pa_smoother_2_reset(u->smoother, pa_rtclock_now()); 24253a5a1b3Sopenharmony_ci#else 24353a5a1b3Sopenharmony_ci pa_smoother_set_time_offset(u->smoother, pa_rtclock_now()); 24453a5a1b3Sopenharmony_ci#endif 24553a5a1b3Sopenharmony_ci 24653a5a1b3Sopenharmony_ci for (;;) { 24753a5a1b3Sopenharmony_ci int ret; 24853a5a1b3Sopenharmony_ci 24953a5a1b3Sopenharmony_ci if (PA_UNLIKELY(u->sink->thread_info.rewind_requested)) 25053a5a1b3Sopenharmony_ci pa_sink_process_rewind(u->sink, 0); 25153a5a1b3Sopenharmony_ci 25253a5a1b3Sopenharmony_ci if (u->rtpoll_item) { 25353a5a1b3Sopenharmony_ci struct pollfd *pollfd; 25453a5a1b3Sopenharmony_ci pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); 25553a5a1b3Sopenharmony_ci 25653a5a1b3Sopenharmony_ci /* Render some data and write it to the fifo */ 25753a5a1b3Sopenharmony_ci if (PA_SINK_IS_OPENED(u->sink->thread_info.state) && pollfd->revents) { 25853a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 25953a5a1b3Sopenharmony_ci size_t bytes; 26053a5a1b3Sopenharmony_ci#else 26153a5a1b3Sopenharmony_ci pa_usec_t usec; 26253a5a1b3Sopenharmony_ci#endif 26353a5a1b3Sopenharmony_ci int64_t n; 26453a5a1b3Sopenharmony_ci 26553a5a1b3Sopenharmony_ci for (;;) { 26653a5a1b3Sopenharmony_ci ssize_t l; 26753a5a1b3Sopenharmony_ci void *p; 26853a5a1b3Sopenharmony_ci 26953a5a1b3Sopenharmony_ci if (u->memchunk.length <= 0) 27053a5a1b3Sopenharmony_ci pa_sink_render(u->sink, u->block_size, &u->memchunk); 27153a5a1b3Sopenharmony_ci 27253a5a1b3Sopenharmony_ci pa_assert(u->memchunk.length > 0); 27353a5a1b3Sopenharmony_ci 27453a5a1b3Sopenharmony_ci p = pa_memblock_acquire(u->memchunk.memblock); 27553a5a1b3Sopenharmony_ci l = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type); 27653a5a1b3Sopenharmony_ci pa_memblock_release(u->memchunk.memblock); 27753a5a1b3Sopenharmony_ci 27853a5a1b3Sopenharmony_ci pa_assert(l != 0); 27953a5a1b3Sopenharmony_ci 28053a5a1b3Sopenharmony_ci if (l < 0) { 28153a5a1b3Sopenharmony_ci 28253a5a1b3Sopenharmony_ci if (errno == EAGAIN) { 28353a5a1b3Sopenharmony_ci 28453a5a1b3Sopenharmony_ci /* OK, we filled all socket buffers up 28553a5a1b3Sopenharmony_ci * now. */ 28653a5a1b3Sopenharmony_ci goto filled_up; 28753a5a1b3Sopenharmony_ci 28853a5a1b3Sopenharmony_ci } else { 28953a5a1b3Sopenharmony_ci pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno)); 29053a5a1b3Sopenharmony_ci goto fail; 29153a5a1b3Sopenharmony_ci } 29253a5a1b3Sopenharmony_ci 29353a5a1b3Sopenharmony_ci } else { 29453a5a1b3Sopenharmony_ci u->offset += l; 29553a5a1b3Sopenharmony_ci 29653a5a1b3Sopenharmony_ci u->memchunk.index += (size_t) l; 29753a5a1b3Sopenharmony_ci u->memchunk.length -= (size_t) l; 29853a5a1b3Sopenharmony_ci 29953a5a1b3Sopenharmony_ci if (u->memchunk.length <= 0) { 30053a5a1b3Sopenharmony_ci pa_memblock_unref(u->memchunk.memblock); 30153a5a1b3Sopenharmony_ci pa_memchunk_reset(&u->memchunk); 30253a5a1b3Sopenharmony_ci } 30353a5a1b3Sopenharmony_ci 30453a5a1b3Sopenharmony_ci pollfd->revents = 0; 30553a5a1b3Sopenharmony_ci 30653a5a1b3Sopenharmony_ci if (u->memchunk.length > 0) 30753a5a1b3Sopenharmony_ci 30853a5a1b3Sopenharmony_ci /* OK, we wrote less that we asked for, 30953a5a1b3Sopenharmony_ci * hence we can assume that the socket 31053a5a1b3Sopenharmony_ci * buffers are full now */ 31153a5a1b3Sopenharmony_ci goto filled_up; 31253a5a1b3Sopenharmony_ci } 31353a5a1b3Sopenharmony_ci } 31453a5a1b3Sopenharmony_ci 31553a5a1b3Sopenharmony_ci filled_up: 31653a5a1b3Sopenharmony_ci 31753a5a1b3Sopenharmony_ci /* At this spot we know that the socket buffers are 31853a5a1b3Sopenharmony_ci * fully filled up. This is the best time to estimate 31953a5a1b3Sopenharmony_ci * the playback position of the server */ 32053a5a1b3Sopenharmony_ci 32153a5a1b3Sopenharmony_ci n = u->offset; 32253a5a1b3Sopenharmony_ci 32353a5a1b3Sopenharmony_ci#ifdef SIOCOUTQ 32453a5a1b3Sopenharmony_ci { 32553a5a1b3Sopenharmony_ci int l; 32653a5a1b3Sopenharmony_ci if (ioctl(u->fd, SIOCOUTQ, &l) >= 0 && l > 0) 32753a5a1b3Sopenharmony_ci n -= l; 32853a5a1b3Sopenharmony_ci } 32953a5a1b3Sopenharmony_ci#endif 33053a5a1b3Sopenharmony_ci 33153a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 33253a5a1b3Sopenharmony_ci bytes = pa_usec_to_bytes(u->latency, &u->sink->sample_spec); 33353a5a1b3Sopenharmony_ci 33453a5a1b3Sopenharmony_ci if ((uint64_t)n > bytes) 33553a5a1b3Sopenharmony_ci bytes = n - bytes; 33653a5a1b3Sopenharmony_ci else 33753a5a1b3Sopenharmony_ci bytes = 0; 33853a5a1b3Sopenharmony_ci 33953a5a1b3Sopenharmony_ci pa_smoother_2_put(u->smoother, pa_rtclock_now(), bytes); 34053a5a1b3Sopenharmony_ci#else 34153a5a1b3Sopenharmony_ci usec = pa_bytes_to_usec((uint64_t) n, &u->sink->sample_spec); 34253a5a1b3Sopenharmony_ci 34353a5a1b3Sopenharmony_ci if (usec > u->latency) 34453a5a1b3Sopenharmony_ci usec -= u->latency; 34553a5a1b3Sopenharmony_ci else 34653a5a1b3Sopenharmony_ci usec = 0; 34753a5a1b3Sopenharmony_ci 34853a5a1b3Sopenharmony_ci pa_smoother_put(u->smoother, pa_rtclock_now(), usec); 34953a5a1b3Sopenharmony_ci#endif 35053a5a1b3Sopenharmony_ci } 35153a5a1b3Sopenharmony_ci 35253a5a1b3Sopenharmony_ci /* Hmm, nothing to do. Let's sleep */ 35353a5a1b3Sopenharmony_ci pollfd->events = (short) (PA_SINK_IS_OPENED(u->sink->thread_info.state) ? POLLOUT : 0); 35453a5a1b3Sopenharmony_ci } 35553a5a1b3Sopenharmony_ci 35653a5a1b3Sopenharmony_ci if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) 35753a5a1b3Sopenharmony_ci goto fail; 35853a5a1b3Sopenharmony_ci 35953a5a1b3Sopenharmony_ci if (ret == 0) 36053a5a1b3Sopenharmony_ci goto finish; 36153a5a1b3Sopenharmony_ci 36253a5a1b3Sopenharmony_ci if (u->rtpoll_item) { 36353a5a1b3Sopenharmony_ci struct pollfd* pollfd; 36453a5a1b3Sopenharmony_ci 36553a5a1b3Sopenharmony_ci pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); 36653a5a1b3Sopenharmony_ci 36753a5a1b3Sopenharmony_ci if (pollfd->revents & ~POLLOUT) { 36853a5a1b3Sopenharmony_ci pa_log("FIFO shutdown."); 36953a5a1b3Sopenharmony_ci goto fail; 37053a5a1b3Sopenharmony_ci } 37153a5a1b3Sopenharmony_ci } 37253a5a1b3Sopenharmony_ci } 37353a5a1b3Sopenharmony_ci 37453a5a1b3Sopenharmony_cifail: 37553a5a1b3Sopenharmony_ci /* If this was no regular exit from the loop we have to continue 37653a5a1b3Sopenharmony_ci * processing messages until we received PA_MESSAGE_SHUTDOWN */ 37753a5a1b3Sopenharmony_ci pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); 37853a5a1b3Sopenharmony_ci pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); 37953a5a1b3Sopenharmony_ci 38053a5a1b3Sopenharmony_cifinish: 38153a5a1b3Sopenharmony_ci pa_log_debug("Thread shutting down"); 38253a5a1b3Sopenharmony_ci} 38353a5a1b3Sopenharmony_ci 38453a5a1b3Sopenharmony_cistatic int do_write(struct userdata *u) { 38553a5a1b3Sopenharmony_ci ssize_t r; 38653a5a1b3Sopenharmony_ci pa_assert(u); 38753a5a1b3Sopenharmony_ci 38853a5a1b3Sopenharmony_ci if (!pa_iochannel_is_writable(u->io)) 38953a5a1b3Sopenharmony_ci return 0; 39053a5a1b3Sopenharmony_ci 39153a5a1b3Sopenharmony_ci if (u->write_data) { 39253a5a1b3Sopenharmony_ci pa_assert(u->write_index < u->write_length); 39353a5a1b3Sopenharmony_ci 39453a5a1b3Sopenharmony_ci if ((r = pa_iochannel_write(u->io, (uint8_t*) u->write_data + u->write_index, u->write_length - u->write_index)) < 0) { 39553a5a1b3Sopenharmony_ci pa_log("write() failed: %s", pa_cstrerror(errno)); 39653a5a1b3Sopenharmony_ci return -1; 39753a5a1b3Sopenharmony_ci } 39853a5a1b3Sopenharmony_ci 39953a5a1b3Sopenharmony_ci u->write_index += (size_t) r; 40053a5a1b3Sopenharmony_ci pa_assert(u->write_index <= u->write_length); 40153a5a1b3Sopenharmony_ci 40253a5a1b3Sopenharmony_ci if (u->write_index == u->write_length) { 40353a5a1b3Sopenharmony_ci pa_xfree(u->write_data); 40453a5a1b3Sopenharmony_ci u->write_data = NULL; 40553a5a1b3Sopenharmony_ci u->write_index = u->write_length = 0; 40653a5a1b3Sopenharmony_ci } 40753a5a1b3Sopenharmony_ci } 40853a5a1b3Sopenharmony_ci 40953a5a1b3Sopenharmony_ci if (!u->write_data && u->state == STATE_PREPARE) { 41053a5a1b3Sopenharmony_ci int so_sndbuf = 0; 41153a5a1b3Sopenharmony_ci socklen_t sl = sizeof(int); 41253a5a1b3Sopenharmony_ci 41353a5a1b3Sopenharmony_ci /* OK, we're done with sending all control data we need to, so 41453a5a1b3Sopenharmony_ci * let's hand the socket over to the IO thread now */ 41553a5a1b3Sopenharmony_ci 41653a5a1b3Sopenharmony_ci pa_assert(u->fd < 0); 41753a5a1b3Sopenharmony_ci u->fd = pa_iochannel_get_send_fd(u->io); 41853a5a1b3Sopenharmony_ci 41953a5a1b3Sopenharmony_ci pa_iochannel_set_noclose(u->io, true); 42053a5a1b3Sopenharmony_ci pa_iochannel_free(u->io); 42153a5a1b3Sopenharmony_ci u->io = NULL; 42253a5a1b3Sopenharmony_ci 42353a5a1b3Sopenharmony_ci pa_make_tcp_socket_low_delay(u->fd); 42453a5a1b3Sopenharmony_ci 42553a5a1b3Sopenharmony_ci if (getsockopt(u->fd, SOL_SOCKET, SO_SNDBUF, (void *) &so_sndbuf, &sl) < 0) 42653a5a1b3Sopenharmony_ci pa_log_warn("getsockopt(SO_SNDBUF) failed: %s", pa_cstrerror(errno)); 42753a5a1b3Sopenharmony_ci else { 42853a5a1b3Sopenharmony_ci pa_log_debug("SO_SNDBUF is %zu.", (size_t) so_sndbuf); 42953a5a1b3Sopenharmony_ci pa_sink_set_max_request(u->sink, PA_MAX((size_t) so_sndbuf, u->block_size)); 43053a5a1b3Sopenharmony_ci } 43153a5a1b3Sopenharmony_ci 43253a5a1b3Sopenharmony_ci pa_log_debug("Connection authenticated, handing fd to IO thread..."); 43353a5a1b3Sopenharmony_ci 43453a5a1b3Sopenharmony_ci pa_asyncmsgq_post(u->thread_mq.inq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_PASS_SOCKET, NULL, 0, NULL, NULL); 43553a5a1b3Sopenharmony_ci u->state = STATE_RUNNING; 43653a5a1b3Sopenharmony_ci } 43753a5a1b3Sopenharmony_ci 43853a5a1b3Sopenharmony_ci return 0; 43953a5a1b3Sopenharmony_ci} 44053a5a1b3Sopenharmony_ci 44153a5a1b3Sopenharmony_cistatic int handle_response(struct userdata *u) { 44253a5a1b3Sopenharmony_ci pa_assert(u); 44353a5a1b3Sopenharmony_ci 44453a5a1b3Sopenharmony_ci switch (u->state) { 44553a5a1b3Sopenharmony_ci 44653a5a1b3Sopenharmony_ci case STATE_AUTH: 44753a5a1b3Sopenharmony_ci pa_assert(u->read_length == sizeof(int32_t)); 44853a5a1b3Sopenharmony_ci 44953a5a1b3Sopenharmony_ci /* Process auth data */ 45053a5a1b3Sopenharmony_ci if (!*(int32_t*) u->read_data) { 45153a5a1b3Sopenharmony_ci pa_log("Authentication failed: %s", pa_cstrerror(errno)); 45253a5a1b3Sopenharmony_ci return -1; 45353a5a1b3Sopenharmony_ci } 45453a5a1b3Sopenharmony_ci 45553a5a1b3Sopenharmony_ci /* Request latency data */ 45653a5a1b3Sopenharmony_ci pa_assert(!u->write_data); 45753a5a1b3Sopenharmony_ci *(int32_t*) (u->write_data = pa_xmalloc(u->write_length = sizeof(int32_t))) = ESD_PROTO_LATENCY; 45853a5a1b3Sopenharmony_ci 45953a5a1b3Sopenharmony_ci u->write_index = 0; 46053a5a1b3Sopenharmony_ci u->state = STATE_LATENCY; 46153a5a1b3Sopenharmony_ci 46253a5a1b3Sopenharmony_ci /* Space for next response */ 46353a5a1b3Sopenharmony_ci pa_assert(u->read_length >= sizeof(int32_t)); 46453a5a1b3Sopenharmony_ci u->read_index = 0; 46553a5a1b3Sopenharmony_ci u->read_length = sizeof(int32_t); 46653a5a1b3Sopenharmony_ci 46753a5a1b3Sopenharmony_ci break; 46853a5a1b3Sopenharmony_ci 46953a5a1b3Sopenharmony_ci case STATE_LATENCY: { 47053a5a1b3Sopenharmony_ci int32_t *p; 47153a5a1b3Sopenharmony_ci pa_assert(u->read_length == sizeof(int32_t)); 47253a5a1b3Sopenharmony_ci 47353a5a1b3Sopenharmony_ci /* Process latency info */ 47453a5a1b3Sopenharmony_ci u->latency = (pa_usec_t) ((double) (*(int32_t*) u->read_data) * 1000000 / 44100); 47553a5a1b3Sopenharmony_ci if (u->latency > 10000000) { 47653a5a1b3Sopenharmony_ci pa_log_warn("Invalid latency information received from server"); 47753a5a1b3Sopenharmony_ci u->latency = 0; 47853a5a1b3Sopenharmony_ci } 47953a5a1b3Sopenharmony_ci 48053a5a1b3Sopenharmony_ci /* Create stream */ 48153a5a1b3Sopenharmony_ci pa_assert(!u->write_data); 48253a5a1b3Sopenharmony_ci p = u->write_data = pa_xmalloc0(u->write_length = sizeof(int32_t)*3+ESD_NAME_MAX); 48353a5a1b3Sopenharmony_ci *(p++) = ESD_PROTO_STREAM_PLAY; 48453a5a1b3Sopenharmony_ci *(p++) = u->format; 48553a5a1b3Sopenharmony_ci *(p++) = u->rate; 48653a5a1b3Sopenharmony_ci pa_strlcpy((char*) p, "PulseAudio Tunnel", ESD_NAME_MAX); 48753a5a1b3Sopenharmony_ci 48853a5a1b3Sopenharmony_ci u->write_index = 0; 48953a5a1b3Sopenharmony_ci u->state = STATE_PREPARE; 49053a5a1b3Sopenharmony_ci 49153a5a1b3Sopenharmony_ci /* Don't read any further */ 49253a5a1b3Sopenharmony_ci pa_xfree(u->read_data); 49353a5a1b3Sopenharmony_ci u->read_data = NULL; 49453a5a1b3Sopenharmony_ci u->read_index = u->read_length = 0; 49553a5a1b3Sopenharmony_ci 49653a5a1b3Sopenharmony_ci break; 49753a5a1b3Sopenharmony_ci } 49853a5a1b3Sopenharmony_ci 49953a5a1b3Sopenharmony_ci default: 50053a5a1b3Sopenharmony_ci pa_assert_not_reached(); 50153a5a1b3Sopenharmony_ci } 50253a5a1b3Sopenharmony_ci 50353a5a1b3Sopenharmony_ci return 0; 50453a5a1b3Sopenharmony_ci} 50553a5a1b3Sopenharmony_ci 50653a5a1b3Sopenharmony_cistatic int do_read(struct userdata *u) { 50753a5a1b3Sopenharmony_ci pa_assert(u); 50853a5a1b3Sopenharmony_ci 50953a5a1b3Sopenharmony_ci if (!pa_iochannel_is_readable(u->io)) 51053a5a1b3Sopenharmony_ci return 0; 51153a5a1b3Sopenharmony_ci 51253a5a1b3Sopenharmony_ci if (u->state == STATE_AUTH || u->state == STATE_LATENCY) { 51353a5a1b3Sopenharmony_ci ssize_t r; 51453a5a1b3Sopenharmony_ci 51553a5a1b3Sopenharmony_ci if (!u->read_data) 51653a5a1b3Sopenharmony_ci return 0; 51753a5a1b3Sopenharmony_ci 51853a5a1b3Sopenharmony_ci pa_assert(u->read_index < u->read_length); 51953a5a1b3Sopenharmony_ci 52053a5a1b3Sopenharmony_ci if ((r = pa_iochannel_read(u->io, (uint8_t*) u->read_data + u->read_index, u->read_length - u->read_index)) <= 0) { 52153a5a1b3Sopenharmony_ci pa_log("read() failed: %s", r < 0 ? pa_cstrerror(errno) : "EOF"); 52253a5a1b3Sopenharmony_ci return -1; 52353a5a1b3Sopenharmony_ci } 52453a5a1b3Sopenharmony_ci 52553a5a1b3Sopenharmony_ci u->read_index += (size_t) r; 52653a5a1b3Sopenharmony_ci pa_assert(u->read_index <= u->read_length); 52753a5a1b3Sopenharmony_ci 52853a5a1b3Sopenharmony_ci if (u->read_index == u->read_length) 52953a5a1b3Sopenharmony_ci return handle_response(u); 53053a5a1b3Sopenharmony_ci } 53153a5a1b3Sopenharmony_ci 53253a5a1b3Sopenharmony_ci return 0; 53353a5a1b3Sopenharmony_ci} 53453a5a1b3Sopenharmony_ci 53553a5a1b3Sopenharmony_cistatic void io_callback(pa_iochannel *io, void*userdata) { 53653a5a1b3Sopenharmony_ci struct userdata *u = userdata; 53753a5a1b3Sopenharmony_ci pa_assert(u); 53853a5a1b3Sopenharmony_ci 53953a5a1b3Sopenharmony_ci if (do_read(u) < 0 || do_write(u) < 0) { 54053a5a1b3Sopenharmony_ci 54153a5a1b3Sopenharmony_ci if (u->io) { 54253a5a1b3Sopenharmony_ci pa_iochannel_free(u->io); 54353a5a1b3Sopenharmony_ci u->io = NULL; 54453a5a1b3Sopenharmony_ci } 54553a5a1b3Sopenharmony_ci 54653a5a1b3Sopenharmony_ci pa_module_unload_request(u->module, true); 54753a5a1b3Sopenharmony_ci } 54853a5a1b3Sopenharmony_ci} 54953a5a1b3Sopenharmony_ci 55053a5a1b3Sopenharmony_cistatic void on_connection(pa_socket_client *c, pa_iochannel*io, void *userdata) { 55153a5a1b3Sopenharmony_ci struct userdata *u = userdata; 55253a5a1b3Sopenharmony_ci 55353a5a1b3Sopenharmony_ci pa_socket_client_unref(u->client); 55453a5a1b3Sopenharmony_ci u->client = NULL; 55553a5a1b3Sopenharmony_ci 55653a5a1b3Sopenharmony_ci if (!io) { 55753a5a1b3Sopenharmony_ci pa_log("Connection failed: %s", pa_cstrerror(errno)); 55853a5a1b3Sopenharmony_ci pa_module_unload_request(u->module, true); 55953a5a1b3Sopenharmony_ci return; 56053a5a1b3Sopenharmony_ci } 56153a5a1b3Sopenharmony_ci 56253a5a1b3Sopenharmony_ci pa_assert(!u->io); 56353a5a1b3Sopenharmony_ci u->io = io; 56453a5a1b3Sopenharmony_ci pa_iochannel_set_callback(u->io, io_callback, u); 56553a5a1b3Sopenharmony_ci 56653a5a1b3Sopenharmony_ci pa_log_debug("Connection established, authenticating ..."); 56753a5a1b3Sopenharmony_ci} 56853a5a1b3Sopenharmony_ci 56953a5a1b3Sopenharmony_ciint pa__init(pa_module*m) { 57053a5a1b3Sopenharmony_ci struct userdata *u = NULL; 57153a5a1b3Sopenharmony_ci pa_sample_spec ss; 57253a5a1b3Sopenharmony_ci pa_modargs *ma = NULL; 57353a5a1b3Sopenharmony_ci const char *espeaker; 57453a5a1b3Sopenharmony_ci uint32_t key; 57553a5a1b3Sopenharmony_ci pa_sink_new_data data; 57653a5a1b3Sopenharmony_ci char *cookie_path; 57753a5a1b3Sopenharmony_ci int r; 57853a5a1b3Sopenharmony_ci 57953a5a1b3Sopenharmony_ci pa_assert(m); 58053a5a1b3Sopenharmony_ci 58153a5a1b3Sopenharmony_ci if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { 58253a5a1b3Sopenharmony_ci pa_log("failed to parse module arguments"); 58353a5a1b3Sopenharmony_ci goto fail; 58453a5a1b3Sopenharmony_ci } 58553a5a1b3Sopenharmony_ci 58653a5a1b3Sopenharmony_ci ss = m->core->default_sample_spec; 58753a5a1b3Sopenharmony_ci if (pa_modargs_get_sample_spec(ma, &ss) < 0) { 58853a5a1b3Sopenharmony_ci pa_log("invalid sample format specification"); 58953a5a1b3Sopenharmony_ci goto fail; 59053a5a1b3Sopenharmony_ci } 59153a5a1b3Sopenharmony_ci 59253a5a1b3Sopenharmony_ci if ((ss.format != PA_SAMPLE_U8 && ss.format != PA_SAMPLE_S16NE) || 59353a5a1b3Sopenharmony_ci (ss.channels > 2)) { 59453a5a1b3Sopenharmony_ci pa_log("esound sample type support is limited to mono/stereo and U8 or S16NE sample data"); 59553a5a1b3Sopenharmony_ci goto fail; 59653a5a1b3Sopenharmony_ci } 59753a5a1b3Sopenharmony_ci 59853a5a1b3Sopenharmony_ci u = pa_xnew0(struct userdata, 1); 59953a5a1b3Sopenharmony_ci u->core = m->core; 60053a5a1b3Sopenharmony_ci u->module = m; 60153a5a1b3Sopenharmony_ci m->userdata = u; 60253a5a1b3Sopenharmony_ci u->fd = -1; 60353a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 60453a5a1b3Sopenharmony_ci u->smoother = pa_smoother_2_new(5*PA_USEC_PER_SEC, pa_rtclock_now(), pa_frame_size(&ss), ss.rate); 60553a5a1b3Sopenharmony_ci#else 60653a5a1b3Sopenharmony_ci u->smoother = pa_smoother_new( 60753a5a1b3Sopenharmony_ci PA_USEC_PER_SEC, 60853a5a1b3Sopenharmony_ci PA_USEC_PER_SEC*2, 60953a5a1b3Sopenharmony_ci true, 61053a5a1b3Sopenharmony_ci true, 61153a5a1b3Sopenharmony_ci 10, 61253a5a1b3Sopenharmony_ci 0, 61353a5a1b3Sopenharmony_ci false); 61453a5a1b3Sopenharmony_ci#endif 61553a5a1b3Sopenharmony_ci pa_memchunk_reset(&u->memchunk); 61653a5a1b3Sopenharmony_ci u->offset = 0; 61753a5a1b3Sopenharmony_ci 61853a5a1b3Sopenharmony_ci u->rtpoll = pa_rtpoll_new(); 61953a5a1b3Sopenharmony_ci 62053a5a1b3Sopenharmony_ci if (pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll) < 0) { 62153a5a1b3Sopenharmony_ci pa_log("pa_thread_mq_init() failed."); 62253a5a1b3Sopenharmony_ci goto fail; 62353a5a1b3Sopenharmony_ci } 62453a5a1b3Sopenharmony_ci 62553a5a1b3Sopenharmony_ci u->rtpoll_item = NULL; 62653a5a1b3Sopenharmony_ci 62753a5a1b3Sopenharmony_ci u->format = 62853a5a1b3Sopenharmony_ci (ss.format == PA_SAMPLE_U8 ? ESD_BITS8 : ESD_BITS16) | 62953a5a1b3Sopenharmony_ci (ss.channels == 2 ? ESD_STEREO : ESD_MONO); 63053a5a1b3Sopenharmony_ci u->rate = (int32_t) ss.rate; 63153a5a1b3Sopenharmony_ci u->block_size = pa_usec_to_bytes(PA_USEC_PER_SEC/20, &ss); 63253a5a1b3Sopenharmony_ci 63353a5a1b3Sopenharmony_ci u->read_data = u->write_data = NULL; 63453a5a1b3Sopenharmony_ci u->read_index = u->write_index = u->read_length = u->write_length = 0; 63553a5a1b3Sopenharmony_ci 63653a5a1b3Sopenharmony_ci u->state = STATE_AUTH; 63753a5a1b3Sopenharmony_ci u->latency = 0; 63853a5a1b3Sopenharmony_ci 63953a5a1b3Sopenharmony_ci if (!(espeaker = getenv("ESPEAKER"))) 64053a5a1b3Sopenharmony_ci espeaker = ESD_UNIX_SOCKET_NAME; 64153a5a1b3Sopenharmony_ci 64253a5a1b3Sopenharmony_ci espeaker = pa_modargs_get_value(ma, "server", espeaker); 64353a5a1b3Sopenharmony_ci 64453a5a1b3Sopenharmony_ci pa_sink_new_data_init(&data); 64553a5a1b3Sopenharmony_ci data.driver = __FILE__; 64653a5a1b3Sopenharmony_ci data.module = m; 64753a5a1b3Sopenharmony_ci pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); 64853a5a1b3Sopenharmony_ci pa_sink_new_data_set_sample_spec(&data, &ss); 64953a5a1b3Sopenharmony_ci pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, espeaker); 65053a5a1b3Sopenharmony_ci pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "esd"); 65153a5a1b3Sopenharmony_ci pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "EsounD Output on %s", espeaker); 65253a5a1b3Sopenharmony_ci 65353a5a1b3Sopenharmony_ci if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { 65453a5a1b3Sopenharmony_ci pa_log("Invalid properties"); 65553a5a1b3Sopenharmony_ci pa_sink_new_data_done(&data); 65653a5a1b3Sopenharmony_ci goto fail; 65753a5a1b3Sopenharmony_ci } 65853a5a1b3Sopenharmony_ci 65953a5a1b3Sopenharmony_ci u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY|PA_SINK_NETWORK); 66053a5a1b3Sopenharmony_ci pa_sink_new_data_done(&data); 66153a5a1b3Sopenharmony_ci 66253a5a1b3Sopenharmony_ci if (!u->sink) { 66353a5a1b3Sopenharmony_ci pa_log("Failed to create sink."); 66453a5a1b3Sopenharmony_ci goto fail; 66553a5a1b3Sopenharmony_ci } 66653a5a1b3Sopenharmony_ci 66753a5a1b3Sopenharmony_ci u->sink->parent.process_msg = sink_process_msg; 66853a5a1b3Sopenharmony_ci u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb; 66953a5a1b3Sopenharmony_ci u->sink->userdata = u; 67053a5a1b3Sopenharmony_ci 67153a5a1b3Sopenharmony_ci pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); 67253a5a1b3Sopenharmony_ci pa_sink_set_rtpoll(u->sink, u->rtpoll); 67353a5a1b3Sopenharmony_ci 67453a5a1b3Sopenharmony_ci if (!(u->client = pa_socket_client_new_string(u->core->mainloop, true, espeaker, ESD_DEFAULT_PORT))) { 67553a5a1b3Sopenharmony_ci pa_log("Failed to connect to server."); 67653a5a1b3Sopenharmony_ci goto fail; 67753a5a1b3Sopenharmony_ci } 67853a5a1b3Sopenharmony_ci 67953a5a1b3Sopenharmony_ci pa_socket_client_set_callback(u->client, on_connection, u); 68053a5a1b3Sopenharmony_ci 68153a5a1b3Sopenharmony_ci cookie_path = pa_xstrdup(pa_modargs_get_value(ma, "cookie", NULL)); 68253a5a1b3Sopenharmony_ci if (!cookie_path) { 68353a5a1b3Sopenharmony_ci if (pa_append_to_home_dir(".esd_auth", &cookie_path) < 0) 68453a5a1b3Sopenharmony_ci goto fail; 68553a5a1b3Sopenharmony_ci } 68653a5a1b3Sopenharmony_ci 68753a5a1b3Sopenharmony_ci /* Prepare the initial request */ 68853a5a1b3Sopenharmony_ci u->write_data = pa_xmalloc(u->write_length = ESD_KEY_LEN + sizeof(int32_t)); 68953a5a1b3Sopenharmony_ci 69053a5a1b3Sopenharmony_ci r = pa_authkey_load(cookie_path, true, u->write_data, ESD_KEY_LEN); 69153a5a1b3Sopenharmony_ci pa_xfree(cookie_path); 69253a5a1b3Sopenharmony_ci if (r < 0) { 69353a5a1b3Sopenharmony_ci pa_log("Failed to load cookie"); 69453a5a1b3Sopenharmony_ci goto fail; 69553a5a1b3Sopenharmony_ci } 69653a5a1b3Sopenharmony_ci 69753a5a1b3Sopenharmony_ci key = ESD_ENDIAN_KEY; 69853a5a1b3Sopenharmony_ci memcpy((uint8_t*) u->write_data + ESD_KEY_LEN, &key, sizeof(key)); 69953a5a1b3Sopenharmony_ci 70053a5a1b3Sopenharmony_ci /* Reserve space for the response */ 70153a5a1b3Sopenharmony_ci u->read_data = pa_xmalloc(u->read_length = sizeof(int32_t)); 70253a5a1b3Sopenharmony_ci 70353a5a1b3Sopenharmony_ci if (!(u->thread = pa_thread_new("esound-sink", thread_func, u))) { 70453a5a1b3Sopenharmony_ci pa_log("Failed to create thread."); 70553a5a1b3Sopenharmony_ci goto fail; 70653a5a1b3Sopenharmony_ci } 70753a5a1b3Sopenharmony_ci 70853a5a1b3Sopenharmony_ci pa_sink_put(u->sink); 70953a5a1b3Sopenharmony_ci 71053a5a1b3Sopenharmony_ci pa_modargs_free(ma); 71153a5a1b3Sopenharmony_ci 71253a5a1b3Sopenharmony_ci return 0; 71353a5a1b3Sopenharmony_ci 71453a5a1b3Sopenharmony_cifail: 71553a5a1b3Sopenharmony_ci if (ma) 71653a5a1b3Sopenharmony_ci pa_modargs_free(ma); 71753a5a1b3Sopenharmony_ci 71853a5a1b3Sopenharmony_ci pa__done(m); 71953a5a1b3Sopenharmony_ci 72053a5a1b3Sopenharmony_ci return -1; 72153a5a1b3Sopenharmony_ci} 72253a5a1b3Sopenharmony_ci 72353a5a1b3Sopenharmony_ciint pa__get_n_used(pa_module *m) { 72453a5a1b3Sopenharmony_ci struct userdata *u; 72553a5a1b3Sopenharmony_ci 72653a5a1b3Sopenharmony_ci pa_assert(m); 72753a5a1b3Sopenharmony_ci pa_assert_se(u = m->userdata); 72853a5a1b3Sopenharmony_ci 72953a5a1b3Sopenharmony_ci return pa_sink_linked_by(u->sink); 73053a5a1b3Sopenharmony_ci} 73153a5a1b3Sopenharmony_ci 73253a5a1b3Sopenharmony_civoid pa__done(pa_module*m) { 73353a5a1b3Sopenharmony_ci struct userdata *u; 73453a5a1b3Sopenharmony_ci pa_assert(m); 73553a5a1b3Sopenharmony_ci 73653a5a1b3Sopenharmony_ci if (!(u = m->userdata)) 73753a5a1b3Sopenharmony_ci return; 73853a5a1b3Sopenharmony_ci 73953a5a1b3Sopenharmony_ci if (u->sink) 74053a5a1b3Sopenharmony_ci pa_sink_unlink(u->sink); 74153a5a1b3Sopenharmony_ci 74253a5a1b3Sopenharmony_ci if (u->thread) { 74353a5a1b3Sopenharmony_ci pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); 74453a5a1b3Sopenharmony_ci pa_thread_free(u->thread); 74553a5a1b3Sopenharmony_ci } 74653a5a1b3Sopenharmony_ci 74753a5a1b3Sopenharmony_ci pa_thread_mq_done(&u->thread_mq); 74853a5a1b3Sopenharmony_ci 74953a5a1b3Sopenharmony_ci if (u->sink) 75053a5a1b3Sopenharmony_ci pa_sink_unref(u->sink); 75153a5a1b3Sopenharmony_ci 75253a5a1b3Sopenharmony_ci if (u->io) 75353a5a1b3Sopenharmony_ci pa_iochannel_free(u->io); 75453a5a1b3Sopenharmony_ci 75553a5a1b3Sopenharmony_ci if (u->rtpoll_item) 75653a5a1b3Sopenharmony_ci pa_rtpoll_item_free(u->rtpoll_item); 75753a5a1b3Sopenharmony_ci 75853a5a1b3Sopenharmony_ci if (u->rtpoll) 75953a5a1b3Sopenharmony_ci pa_rtpoll_free(u->rtpoll); 76053a5a1b3Sopenharmony_ci 76153a5a1b3Sopenharmony_ci if (u->memchunk.memblock) 76253a5a1b3Sopenharmony_ci pa_memblock_unref(u->memchunk.memblock); 76353a5a1b3Sopenharmony_ci 76453a5a1b3Sopenharmony_ci if (u->client) 76553a5a1b3Sopenharmony_ci pa_socket_client_unref(u->client); 76653a5a1b3Sopenharmony_ci 76753a5a1b3Sopenharmony_ci pa_xfree(u->read_data); 76853a5a1b3Sopenharmony_ci pa_xfree(u->write_data); 76953a5a1b3Sopenharmony_ci 77053a5a1b3Sopenharmony_ci if (u->smoother) 77153a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 77253a5a1b3Sopenharmony_ci pa_smoother_2_free(u->smoother); 77353a5a1b3Sopenharmony_ci#else 77453a5a1b3Sopenharmony_ci pa_smoother_free(u->smoother); 77553a5a1b3Sopenharmony_ci#endif 77653a5a1b3Sopenharmony_ci 77753a5a1b3Sopenharmony_ci if (u->fd >= 0) 77853a5a1b3Sopenharmony_ci pa_close(u->fd); 77953a5a1b3Sopenharmony_ci 78053a5a1b3Sopenharmony_ci pa_xfree(u); 78153a5a1b3Sopenharmony_ci} 782