summaryrefslogtreecommitdiff
path: root/input/fifo.c
diff options
context:
space:
mode:
Diffstat (limited to 'input/fifo.c')
-rw-r--r--input/fifo.c79
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;
+}