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]
|
||||
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
|
||||
|
|
|
|||
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