diff --git a/new_latency_test.py b/new_latency_test.py new file mode 100644 index 0000000..d23edef --- /dev/null +++ b/new_latency_test.py @@ -0,0 +1,16 @@ +import numpy as np +import time + +SAMPLERATE = 16000 +CHANNELS = 1 +BLOCKSIZE = 256 + +with open("/tmp/esp32_audio", "rb") as f: + while True: + data = f.read(BLOCKSIZE * CHANNELS * 2) # 2 bytes per sample + if not data: + continue + audio = np.frombuffer(data, dtype=np.int16) + peak = np.max(np.abs(audio)) + bar = "#" * int(peak * 50 / 32767) + print(f"[{bar:<50}] {peak}", flush=True) diff --git a/service/esp32-audio.service b/service/esp32-audio.service index dbcccf6..3c15968 100644 --- a/service/esp32-audio.service +++ b/service/esp32-audio.service @@ -1,34 +1,18 @@ [Unit] -Description=ESP32 Serial Audio to PulseAudio -After=pulseaudio.service -Requires=pulseaudio.service -# Tie service start to the device node so it won’t launch until udev creates it -Requires=dev-ttyESP32_A.device -After=dev-ttyESP32_A.device +Description=ESP32 Audio Stream to FIFO +After=default.target +Requires=dev-ttyESP32.device +BindsTo=dev-ttyESP32.device [Service] -# Ensure PulseAudio runtime dir is set so pactl can connect -Environment=XDG_RUNTIME_DIR=/run/user/%U -Environment=LANG=en_US.UTF-8 -WorkingDirectory=/home/littlesophia/serial_audio_catcher +ExecStartPre=/bin/mkdir -p /tmp +ExecStartPre=/bin/rm -f /tmp/esp32_audio +ExecStartPre=/usr/bin/mkfifo /tmp/esp32_audio -# Wait until PulseAudio socket and serial device exist -ExecStartPre=/bin/sh -c 'until [ -S "$XDG_RUNTIME_DIR/pulse/native" ] && [ -e /dev/ttyESP32_A ]; do sleep 2; done' +ExecStart=/bin/sh -c '/home/radxa/serial_audio_catcher/serial_to_stdout /dev/ttyESP32 > /tmp/esp32_audio' -# Create the null sink before starting the pipeline -ExecStartPre=/usr/bin/pactl unload-module module-null-sink -ExecStartPre=/usr/bin/pactl load-module module-null-sink sink_name=esp32 rate=16000 channels=2 format=s16le - -# Run the pipeline through a shell so the pipe is interpreted correctly -ExecStart=/bin/sh -c '/home/littlesophia/serial_audio_catcher/serial_to_stdout /dev/ttyESP32_A | /usr/bin/pacat --raw --rate=16000 --channels=2 --format=s16le --device=esp32' - -# Restart automatically if it crashes or exits Restart=always -RestartSec=5 - -# Log output to journal -StandardOutput=journal -StandardError=journal +RestartSec=2 [Install] WantedBy=default.target diff --git a/wavemonitor b/wavemonitor new file mode 100755 index 0000000..d8a29d5 Binary files /dev/null and b/wavemonitor differ diff --git a/wavemonitor.c b/wavemonitor.c new file mode 100644 index 0000000..c024f3f --- /dev/null +++ b/wavemonitor.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include + +#define BLOCK_FRAMES 256 // ~16 ms at 16 kHz +#define CHANNELS 1 // adjust to 2 if stereo +#define SAMPLE_RATE 16000 +#define BYTES_PER_SAMPLE 2 // s16le + +int main(void) { + int fd = open("/tmp/esp32_audio", O_RDONLY); + if (fd < 0) { + perror("open"); + return 1; + } + + size_t block_bytes = BLOCK_FRAMES * CHANNELS * BYTES_PER_SAMPLE; + int16_t *buffer = malloc(block_bytes); + + if (!buffer) { + perror("malloc"); + close(fd); + return 1; + } + + while (1) { + ssize_t n = read(fd, buffer, block_bytes); + if (n <= 0) { + usleep(1000); + continue; + } + + // compute peak + int16_t peak = 0; + for (ssize_t i = 0; i < n / 2; i++) { + int16_t sample = buffer[i]; + if (sample < 0) sample = -sample; + if (sample > peak) peak = sample; + } + + // scale to 50 chars + int bar_len = (peak * 50) / 32767; + char bar[51]; + memset(bar, '#', bar_len); + bar[bar_len] = '\0'; + + printf("[%s]\r", bar); + fflush(stdout); + } + + free(buffer); + close(fd); + return 0; +}