diff options
Diffstat (limited to 'polyp/polyp.c')
-rw-r--r-- | polyp/polyp.c | 324 |
1 files changed, 103 insertions, 221 deletions
diff --git a/polyp/polyp.c b/polyp/polyp.c index f10221c..f5e5cac 100644 --- a/polyp/polyp.c +++ b/polyp/polyp.c @@ -19,177 +19,71 @@ */ #include <stdio.h> +#include <unistd.h> #include <signal.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/un.h> - -#include <pthread.h> +#include <sys/poll.h> #include "polyp.h" -enum { - COMMAND_POLL = 'p', - COMMAND_QUIT = 'q', - COMMAND_POLL_DONE = 'P', - COMMAND_POLL_FAILED = 'F', -}; - -static int write_command(snd_polyp_t *p, char command) -{ - if (write(p->main_fd, &command, 1) != 1) - return -errno; - return 0; -} - -static int write_reply(snd_polyp_t *p, char reply) -{ - if (write(p->thread_fd, &reply, 1) != 1) - return -errno; - return 0; -} - -static int read_command(snd_polyp_t *p) -{ - char command; - - if (read(p->thread_fd, &command, 1) != 1) - return -errno; - - return command; -} - -static int read_reply(snd_polyp_t *p) -{ - char reply; - - if (read(p->main_fd, &reply, 1) != 1) - return -errno; - - return reply; -} - -static void* thread_func(void *data) +int polyp_check_connection(snd_polyp_t *p) { - snd_polyp_t *p = (snd_polyp_t*)data; - sigset_t mask; - char command; - int ret; - - sigfillset(&mask); - pthread_sigmask(SIG_BLOCK, &mask, NULL); - - do { - command = read_command(p); - if (command < 0) - break; + pa_context_state_t state; - switch (command) { - case COMMAND_POLL: - do { - ret = pa_mainloop_poll(p->mainloop); - } while ((ret < 0) && (errno == EINTR)); + assert(p && p->context && p->mainloop); - ret = write_reply(p, (ret < 0) ? COMMAND_POLL_FAILED : COMMAND_POLL_DONE); - if (ret < 0) - return NULL; + state = pa_context_get_state(p->context); - break; - } - } while (command != COMMAND_QUIT); + if (state != PA_CONTEXT_READY) + return -EIO; - return NULL; + return 0; } -int polyp_start_poll(snd_polyp_t *p) +void polyp_stream_state_cb(pa_stream *s, void * userdata) { - int err; + snd_polyp_t *p = userdata; + assert(s); assert(p); - if (p->state == POLYP_STATE_POLLING) - return 0; - - assert(p->state == POLYP_STATE_READY); - - err = pa_mainloop_prepare(p->mainloop, -1); - if (err < 0) - return err; - - err = write_command(p, COMMAND_POLL); - if (err < 0) - return err; - - p->state = POLYP_STATE_POLLING; - - return 0; + pa_threaded_mainloop_signal(p->mainloop, 0); } -int polyp_finish_poll(snd_polyp_t *p) +void polyp_stream_success_cb(pa_stream *s, int success, void *userdata) { - char reply; - int err; + snd_polyp_t *p = userdata; + assert(s); assert(p); - if (p->state == POLYP_STATE_READY) - return 0; - - assert(p->state == POLYP_STATE_POLLING); - - p->state = POLYP_STATE_READY; - - pa_mainloop_wakeup(p->mainloop); - - reply = read_reply(p); - - if (reply == COMMAND_POLL_DONE) { - err = pa_mainloop_dispatch(p->mainloop); - if (err < 0) - return err; - } else - return -EIO; - - return 0; + pa_threaded_mainloop_signal(p->mainloop, 0); } -int polyp_check_connection(snd_polyp_t *p) +void polyp_context_success_cb(pa_context *c, int success, void *userdata) { - pa_context_state_t state; - - assert(p && p->context); + snd_polyp_t *p = userdata; - state = pa_context_get_state(p->context); - - if (state != PA_CONTEXT_READY) - return -EIO; + assert(c); + assert(p); - return 0; + pa_threaded_mainloop_signal(p->mainloop, 0); } int polyp_wait_operation(snd_polyp_t *p, pa_operation *o) { - int err; + assert(p && o && (p->state == POLYP_STATE_READY) && p->mainloop); - assert(p && o && (p->state == POLYP_STATE_READY)); - - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { - p->state = POLYP_STATE_POLLING; - err = pa_mainloop_iterate(p->mainloop, 1, NULL); - p->state = POLYP_STATE_READY; - if (err < 0) - return err; - } + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) + pa_threaded_mainloop_wait(p->mainloop); return 0; } int polyp_wait_stream_state(snd_polyp_t *p, pa_stream *stream, pa_stream_state_t target) { - int err; pa_stream_state_t state; - assert(p && stream && (p->state == POLYP_STATE_READY)); + assert(p && stream && (p->state == POLYP_STATE_READY) && p->mainloop); while (1) { state = pa_stream_get_state(stream); @@ -200,34 +94,72 @@ int polyp_wait_stream_state(snd_polyp_t *p, pa_stream *stream, pa_stream_state_t if (state == target) break; - p->state = POLYP_STATE_POLLING; - err = pa_mainloop_iterate(p->mainloop, 1, NULL); - p->state = POLYP_STATE_READY; - if (err < 0) - return -EIO; + pa_threaded_mainloop_wait(p->mainloop); } return 0; } +static void context_state_cb(pa_context *c, void *userdata) { + snd_polyp_t *p = userdata; + assert(c); + + switch (pa_context_get_state(c)) { + case PA_CONTEXT_READY: + case PA_CONTEXT_TERMINATED: + case PA_CONTEXT_FAILED: + pa_threaded_mainloop_signal(p->mainloop, 0); + break; + + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + } +} + snd_polyp_t *polyp_new() { snd_polyp_t *p; + int fd[2] = { -1, -1 }; + char proc[PATH_MAX], buf[PATH_MAX + 20]; p = calloc(1, sizeof(snd_polyp_t)); assert(p); p->state = POLYP_STATE_INIT; - p->main_fd = -1; - p->thread_fd = -1; - p->thread_running = 0; + if (pipe(fd)) { + free(p); + return NULL; + } + + p->main_fd = fd[0]; + p->thread_fd = fd[1]; + + fcntl(fd[0], F_SETFL, O_NONBLOCK); + fcntl(fd[1], F_SETFL, O_NONBLOCK); - p->mainloop = pa_mainloop_new(); + signal(SIGPIPE, SIG_IGN); /* Yes, ugly as hell */ + + p->mainloop = pa_threaded_mainloop_new(); assert(p->mainloop); - p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), - "ALSA Plugin"); + if (pa_threaded_mainloop_start(p->mainloop) < 0) { + pa_threaded_mainloop_free(p->mainloop); + close(fd[0]); + close(fd[1]); + free(p); + return NULL; + } + + if (pa_get_binary_name(proc, sizeof(proc))) + snprintf(buf, sizeof(buf), "ALSA plug-in [%s]", pa_path_get_filename(proc)); + else + snprintf(buf, sizeof(buf), "ALSA plug-in"); + + p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), buf); assert(p->context); return p; @@ -235,22 +167,13 @@ snd_polyp_t *polyp_new() void polyp_free(snd_polyp_t *p) { - if (p->thread_running) { - assert(p->mainloop && p->thread); - write_command(p, COMMAND_QUIT); - pa_mainloop_wakeup(p->mainloop); - pthread_join(p->thread, NULL); - } + pa_threaded_mainloop_stop(p->mainloop); - if (p->context) - pa_context_unref(p->context); - if (p->mainloop) - pa_mainloop_free(p->mainloop); + pa_context_unref(p->context); + pa_threaded_mainloop_free(p->mainloop); - if (p->thread_fd >= 0) - close(p->thread_fd); - if (p->main_fd >= 0) - close(p->main_fd); + close(p->thread_fd); + close(p->main_fd); free(p); } @@ -258,70 +181,52 @@ void polyp_free(snd_polyp_t *p) int polyp_connect(snd_polyp_t *p, const char *server) { int err; - pa_context_state_t state; assert(p && p->context && p->mainloop && (p->state == POLYP_STATE_INIT)); + pa_threaded_mainloop_lock(p->mainloop); + err = pa_context_connect(p->context, server, 0, NULL); if (err < 0) goto error; - while (1) { - state = pa_context_get_state(p->context); + pa_context_set_state_callback(p->context, context_state_cb, p); - if (state == PA_CONTEXT_FAILED) - goto error; + pa_threaded_mainloop_wait(p->mainloop); - if (state == PA_CONTEXT_READY) - break; + if (pa_context_get_state(p->context) != PA_CONTEXT_READY) + goto error; - err = pa_mainloop_iterate(p->mainloop, 1, NULL); - if (err < 0) - return -EIO; - } + pa_threaded_mainloop_unlock(p->mainloop); - p->state = POLYP_STATE_CONNECTED; + p->state = POLYP_STATE_READY; return 0; error: fprintf(stderr, "*** POLYPAUDIO: Unable to connect: %s\n", pa_strerror(pa_context_errno(p->context))); + + pa_threaded_mainloop_unlock(p->mainloop); + return -ECONNREFUSED; } -int polyp_start_thread(snd_polyp_t *p) +void polyp_poll_activate(snd_polyp_t *p) { - int err; - int fd[2] = { -1, -1 }; - - assert(p && (p->state == POLYP_STATE_CONNECTED)); - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) { - perror("socketpair()"); - return -errno; - } - - p->thread_fd = fd[0]; - p->main_fd = fd[1]; - - p->thread_running = 0; + assert(p); - err = pthread_create(&p->thread, NULL, thread_func, p); - if (err) { - SNDERR("pthread_create(): %s", strerror(err)); - close(fd[0]); - close(fd[1]); - p->main_fd = -1; - p->thread_fd = -1; - return -err; - } + write(p->thread_fd, "a", 1); +} - p->thread_running = 1; +void polyp_poll_deactivate(snd_polyp_t *p) +{ + char buf[10]; - p->state = POLYP_STATE_READY; + assert(p); - return 0; + /* Drain the pipe */ + while (read(p->main_fd, buf, sizeof(buf)) > 0); } int polyp_poll_descriptors_count(snd_polyp_t *p) @@ -336,22 +241,12 @@ int polyp_poll_descriptors_count(snd_polyp_t *p) int polyp_poll_descriptors(snd_polyp_t *p, struct pollfd *pfd, unsigned int space) { - int err; - assert(p); - err = polyp_finish_poll(p); - if (err < 0) - return err; - - err = polyp_start_poll(p); - if (err < 0) - return err; - assert(space >= 1); pfd[0].fd = p->main_fd; - pfd[0].events = POLL_IN; + pfd[0].events = POLLIN; pfd[0].revents = 0; return 1; @@ -359,20 +254,7 @@ int polyp_poll_descriptors(snd_polyp_t *p, struct pollfd *pfd, unsigned int spac int polyp_poll_revents(snd_polyp_t *p, struct pollfd *pfd, unsigned int nfds, unsigned short *revents) { - int err; - assert(p); - err = polyp_finish_poll(p); - if (err < 0) - return err; - - err = polyp_check_connection(p); - if (err < 0) - return err; - - /* - * The application might redo the poll immediatly. - */ - return polyp_poll_descriptors(p, pfd, nfds); + return 1; } |