From 27960adc8926dbcc0399bf1b2f8408ebeaaa5700 Mon Sep 17 00:00:00 2001 From: XANTRONIX Development Date: Tue, 1 Feb 2022 16:58:46 -0500 Subject: Again, with the whole "this stuff compiles" thing --- src/vox.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 218 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/vox.c b/src/vox.c index 047200a..43684e3 100644 --- a/src/vox.c +++ b/src/vox.c @@ -1,34 +1,175 @@ #include +#include #include +#include +#include #include +#include +#include #include -static void vox_cleanup(xas_vox *vox, xas_audio_stream *stream) { - int status; +static int vox_stop(xas_vox *vox) { + if (vox->stdin >= 0) { + (void)close(vox->stdin); + + vox->stdin = -1; + } + + if (vox->stdout >= 0) { + (void)close(vox->stdout); + + vox->stdout = -1; + } + + if (vox->in) { + (void)fclose(vox->in); + + vox->in = NULL; + } + + if (vox->output) { + xas_audio_stream_destroy(vox->output); + + vox->output = NULL; + } + + if (vox->pid) { + int status; + + if (waitpid(vox->pid, &status, 0) < 0) { + goto error_waitpid; + } + + vox->pid = -1; + } + + vox->flags &= ~XAS_VOX_ACTIVE; + + return 0; + +error_waitpid: + return -1; +} - if (vox->flags & XAS_VOX_ACTIVE) { - if (vox->pid >= 0) { - (void)waitpid(vox->pid, &status, 0); +static int vox_start(xas_vox *vox) { + int pipe_stdin[2], + pipe_stdout[2]; + + int pid; + + char sample_rate[40]; + + char *args[] = { + (char *)vox->text2wave_path, + "-F", + sample_rate, + "-", + "-o", + "-", + NULL + }; + + snprintf(sample_rate, sizeof(sample_rate)-1, "%zu", vox->sample_rate); + + (void)vox_stop(vox); + + if (pipe(pipe_stdin) < 0) { + goto error_pipe_stdin; + } + + if (pipe(pipe_stdout) < 0) { + goto error_pipe_stdout; + } + + if ((pid = fork()) < 0) { + goto error_fork; + } + + if (pid == 0) { + int fd; + + if ((fd = open("/dev/null", O_WRONLY)) < 0) { + goto error_child; + } + + close(pipe_stdin[1]); + close(pipe_stdout[0]); + + if (dup2(pipe_stdin[0], 0) < 0) { + goto error_child; } - if (vox->stdout >= 0) { - (void)close(vox->stdout); + if (dup2(pipe_stdout[1], 1) < 0) { + goto error_child; } + + if (dup2(fd, 2) < 0) { + goto error_child; + } + + if (execv(vox->text2wave_path, args) < 0) { + goto error_child; + } + +error_child: + exit(EX_OSERR); } + + close(pipe_stdin[0]); + close(pipe_stdout[1]); + + vox->pid = pid; + vox->stdin = pipe_stdin[1]; + vox->stdout = pipe_stdout[0]; + vox->in = fdopen(pipe_stdin[1], "w"); + vox->output = NULL; + + return 0; + +error_fork: + (void)close(pipe_stdout[1]); + (void)close(pipe_stdout[0]); + +error_pipe_stdout: + (void)close(pipe_stdin[1]); + (void)close(pipe_stdin[0]); + +error_pipe_stdin: + return -1; +} + +static void vox_cleanup(xas_vox *vox, xas_audio_stream *stream) { + (void)vox_stop(vox); } static ssize_t vox_fill(xas_vox *vox, int16_t *samples, size_t count, xas_audio_stream *stream) { - size_t i; + ssize_t readlen; + int16_t *buf; - for (i=0; iflags & XAS_VOX_ACTIVE)) { + memset(samples, '\0', count * vox->sample_size); + + return count; } - return i; + if ((readlen = xas_audio_stream_read(vox->output, + (void **)&buf, + count)) < 0) { + goto error_audio_stream_read; + } + + if (readlen == 0) { + vox_stop(vox); + } + + return readlen; + +error_audio_stream_read: + return -1; } xas_vox *xas_vox_new(const char *text2wave_path, @@ -50,7 +191,9 @@ xas_vox *xas_vox_new(const char *text2wave_path, vox->flags = XAS_VOX_IDLE; vox->pid = -1; + vox->stdin = -1; vox->stdout = -1; + vox->in = NULL; return vox; @@ -58,6 +201,70 @@ error_malloc_vox: return NULL; } +void xas_vox_destroy(xas_vox *vox) { + free(vox); +} + +int xas_vox_stop(xas_vox *vox) { + return vox_stop(vox); +} + +int xas_vox_vsayf(xas_vox *vox, const char *format, va_list args) { + int ret; + + if (vox_start(vox) < 0) { + goto error_vox_start; + } + + if ((ret = vfprintf(vox->in, format, args)) < 0) { + goto error_vfprintf; + } + + (void)close(vox->stdin); + vox->stdin = -1; + + (void)fclose(vox->in); + vox->in = NULL; + + if ((vox->output = xas_riff_open_fd(vox->stdout)) == NULL) { + goto error_riff_open_fd; + } + + if (vox->output->sample_size != vox->sample_size + || vox->output->sample_rate != vox->sample_rate) { + errno = EINVAL; + + goto error_invalid_stream; + } + + return ret; + +error_invalid_stream: + xas_audio_stream_destroy(vox->output); + +error_riff_open_fd: +error_vfprintf: + (void)vox_stop(vox); + +error_vox_start: + return -1; +} + +int xas_vox_sayf(xas_vox *vox, const char *format, ...) { + int ret; + va_list args; + + va_start(args, format); + ret = xas_vox_vsayf(vox, format, args); + va_end(args); + + return ret; +} + +int xas_vox_say(xas_vox *vox, const char *message) { + return xas_vox_sayf(vox, "%\n", message); +} + xas_audio_stream *xas_vox_stream_new(xas_vox *vox) { return xas_audio_stream_new_source((xas_audio_fill)vox_fill, (xas_audio_cleanup)vox_cleanup, -- cgit v1.2.3