diff options
Diffstat (limited to 'input/fifo.c')
-rw-r--r-- | input/fifo.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/input/fifo.c b/input/fifo.c new file mode 100644 index 0000000..870785c --- /dev/null +++ b/input/fifo.c @@ -0,0 +1,79 @@ +#include "input/fifo.h" +#include "input/common.h" + +#include <time.h> + +#define SAMPLES_PER_BUFFER 512 + +int open_fifo(const char *path) { + int fd = open(path, O_RDONLY); + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + return fd; +} + +// input: FIFO +void *input_fifo(void *data) { + struct audio_data *audio = (struct audio_data *)data; + int bytes_per_sample = audio->format / 8; + __attribute__((aligned(sizeof(uint16_t)))) uint8_t buf[SAMPLES_PER_BUFFER * bytes_per_sample]; + uint16_t *samples = + bytes_per_sample == 2 ? (uint16_t *)&buf : calloc(SAMPLES_PER_BUFFER, sizeof(uint16_t)); + + int fd = open_fifo(audio->source); + + while (!audio->terminate) { + int time_since_last_input = 0; + unsigned int offset = 0; + do { + int num_read = read(fd, buf + offset, sizeof(buf) - offset); + + if (num_read < 1) { // if no bytes read sleep 10ms and zero shared buffer + nanosleep(&(struct timespec){.tv_sec = 0, .tv_nsec = 10000000}, NULL); + time_since_last_input++; + + if (time_since_last_input > 10) { + reset_output_buffers(audio); + close(fd); + + fd = open_fifo(audio->source); + time_since_last_input = 0; + offset = 0; + } + } else { + offset += num_read; + time_since_last_input = 0; + } + } while (offset < sizeof(buf)); + + switch (bytes_per_sample) { + case 2: + // [samples] = [buf] so there's nothing to do here. + break; + case 3: + for (int i = 0; i < SAMPLES_PER_BUFFER; i++) { + // Really, a sample is composed of buf[3i + 2] | buf[3i + 1] | buf[3i], but our FFT + // only takes 16-bit samples. Since we need to scale them eventually, we can just + // do so here by taking the top 2 bytes. + samples[i] = (buf[3 * i + 2] << 8) | buf[3 * i + 1]; + } + break; + case 4: + for (int i = 0; i < SAMPLES_PER_BUFFER; i++) { + samples[i] = (buf[4 * i + 3] << 8) | buf[4 * i + 2]; + } + break; + } + + // We worked with unsigned ints up until now to save on sign extension, but the FFT wants + // signed ints. + write_to_fftw_input_buffers((int16_t *)samples, SAMPLES_PER_BUFFER / 2, audio); + } + + close(fd); + if (bytes_per_sample != 2) { + free(samples); + } + + return 0; +} |