-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fifo.c
90 lines (76 loc) · 2.86 KB
/
fifo.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include "fifo.h"
#include "common.h"
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
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 SAMPLES_PER_BUFFER = audio->input_buffer_size;
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);
int test_mode = 0;
if (strcmp(audio->source, "/dev/zero") == 0) {
test_mode = 1;
}
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_input_buffers(SAMPLES_PER_BUFFER, (int16_t *)samples, audio);
if (test_mode) {
nanosleep(&(struct timespec){.tv_sec = 0, .tv_nsec = 1000000},
NULL); // sleep 1 ms to prevent deadlock reading from /dev/zero
}
}
close(fd);
if (bytes_per_sample != 2) {
free(samples);
}
return 0;
}