no more pulseaudio, stream straight to /tmp/esp32_audio
parent
1545f60d78
commit
85b213e194
|
|
@ -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)
|
||||||
|
|
@ -1,34 +1,18 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=ESP32 Serial Audio to PulseAudio
|
Description=ESP32 Audio Stream to FIFO
|
||||||
After=pulseaudio.service
|
After=default.target
|
||||||
Requires=pulseaudio.service
|
Requires=dev-ttyESP32.device
|
||||||
# Tie service start to the device node so it won’t launch until udev creates it
|
BindsTo=dev-ttyESP32.device
|
||||||
Requires=dev-ttyESP32_A.device
|
|
||||||
After=dev-ttyESP32_A.device
|
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
# Ensure PulseAudio runtime dir is set so pactl can connect
|
ExecStartPre=/bin/mkdir -p /tmp
|
||||||
Environment=XDG_RUNTIME_DIR=/run/user/%U
|
ExecStartPre=/bin/rm -f /tmp/esp32_audio
|
||||||
Environment=LANG=en_US.UTF-8
|
ExecStartPre=/usr/bin/mkfifo /tmp/esp32_audio
|
||||||
WorkingDirectory=/home/littlesophia/serial_audio_catcher
|
|
||||||
|
|
||||||
# Wait until PulseAudio socket and serial device exist
|
ExecStart=/bin/sh -c '/home/radxa/serial_audio_catcher/serial_to_stdout /dev/ttyESP32 > /tmp/esp32_audio'
|
||||||
ExecStartPre=/bin/sh -c 'until [ -S "$XDG_RUNTIME_DIR/pulse/native" ] && [ -e /dev/ttyESP32_A ]; do sleep 2; done'
|
|
||||||
|
|
||||||
# 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
|
Restart=always
|
||||||
RestartSec=5
|
RestartSec=2
|
||||||
|
|
||||||
# Log output to journal
|
|
||||||
StandardOutput=journal
|
|
||||||
StandardError=journal
|
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=default.target
|
WantedBy=default.target
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,57 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue