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