feat(audiod): DAC 实时监控 — 数字域电平表(100ms窗口整数RMS/peak,deci-dBFS)+1s监控日志(TF audio_monitor_<bootts>.log,流停即停)+CLI monitor 电平条;STATE 补 rms/peak/lvlseq 键(ABI兼容)。宿主47/47,qemu+真机0.7.91 tone验证(1kHz 0.3幅:rms=-13.9 peak=-10.8dBFS,hwrate~44.1k健康)。audiod ab193a2b meow_audio 891ab264
This commit is contained in:
1 parent
70aec677ce
commit
9a4ea10c64
9 files changed
+377
-5
No files matched your search
@@ -7,6 +7,7 @@
|
||||
* meow_audio tone [freq] [ms] [rate] 正弦测试音(默认 440Hz 500ms 44100;排查无声不须开 App)
|
||||
* meow_audio route <0|2|3> 手动切路由(0=auto 2=3.5 3=4.4;调试/面板)
|
||||
* meow_audio vol [0-100] 设置音量(无参=查询;v1 透传写 DAC numid=1/2 + settings.conf)
|
||||
* meow_audio monitor [秒] 终端实时电平表(rms/peak dBFS + 文本电平条,200ms 刷新)
|
||||
*
|
||||
* 传输:AF_UNIX SOCK_STREAM 到 audiod socket(env MEOW_AUDIO_SOCK / --sock 覆盖,宿主/qemu)。
|
||||
* 帧格式复用 meow_ipc.h 16B 头 + m_audio_* 负载。无 audiod → 连接失败/超时 → 打印友好错误并退出。
|
||||
@@ -23,6 +24,7 @@
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
@@ -163,6 +165,93 @@ static int cmd_status(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---- monitor:终端实时电平表(200ms 刷新,文本电平条;数据源=MSG_AUDIO_STATE 的 rms/peak 键) ---- */
|
||||
static volatile sig_atomic_t g_mon_stop = 0;
|
||||
static void on_mon_sig(int sig) { (void)sig; g_mon_stop = 1; }
|
||||
|
||||
/* 从 STATE 文本取整型字段(key 含 '=',如 "rms=";缺省 def) */
|
||||
static int txt_get_int(const char *t, const char *key, int def)
|
||||
{
|
||||
const char *p = strstr(t, key);
|
||||
return p ? atoi(p + strlen(key)) : def;
|
||||
}
|
||||
static void txt_get_str(const char *t, const char *key, char *out, size_t n)
|
||||
{
|
||||
const char *p = strstr(t, key);
|
||||
if (!p) { snprintf(out, n, "-"); return; }
|
||||
p += strlen(key);
|
||||
size_t k = 0;
|
||||
while (p[k] && p[k] != ' ' && p[k] != '\n' && p[k] != '\t' && k < n - 1) { out[k] = p[k]; k++; }
|
||||
out[k] = 0;
|
||||
}
|
||||
/* deci-dB → "-13.1"(地板显 "-inf") */
|
||||
static void fmt_db10(char *out, size_t n, int v)
|
||||
{
|
||||
if (v <= -990) { snprintf(out, n, " -inf"); return; }
|
||||
int neg = v < 0;
|
||||
int a = neg ? -v : v;
|
||||
snprintf(out, n, "%s%3d.%d", neg ? "-" : " ", a / 10, a % 10);
|
||||
}
|
||||
/* 文本电平条:-60..0 dBFS → 0..30 格 */
|
||||
static void print_bar(int db10)
|
||||
{
|
||||
int cells = 0;
|
||||
if (db10 > -600) cells = (db10 + 600) * 30 / 600;
|
||||
if (cells > 30) cells = 30;
|
||||
putchar('[');
|
||||
for (int i = 0; i < 30; i++) putchar(i < cells ? '#' : '-');
|
||||
putchar(']');
|
||||
}
|
||||
|
||||
static int cmd_monitor(int secs)
|
||||
{
|
||||
if (g_fd < 0) { fprintf(stderr, "meow_audio: no audiod (%s) — 音频服务不可用\n", g_sock); return 1; }
|
||||
signal(SIGINT, on_mon_sig);
|
||||
signal(SIGTERM, on_mon_sig);
|
||||
printf("monitor: 5Hz 刷新,%s(Ctrl-C 退出)\n", secs > 0 ? "定时自动停" : "持续监视");
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
uint64_t t0 = (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
|
||||
uint8_t rbuf[MEOW_IPC_MAX];
|
||||
uint16_t rt;
|
||||
while (!g_mon_stop) {
|
||||
int n = req_resp(MSG_AUDIO_QUERY, NULL, 0, &rt, rbuf, sizeof rbuf);
|
||||
if (n < 0 || rt != MSG_AUDIO_STATE) {
|
||||
fprintf(stderr, "\nmeow_audio: query failed (audiod died?)\n");
|
||||
return 1;
|
||||
}
|
||||
rbuf[n < (int)sizeof rbuf - 1 ? n : (int)sizeof rbuf - 1] = 0;
|
||||
const char *txt = (const char *)rbuf;
|
||||
int active = txt_get_int(txt, "active=", 0);
|
||||
int rms = txt_get_int(txt, "rms=", -990);
|
||||
int pk = txt_get_int(txt, "peak=", -990);
|
||||
int vol = txt_get_int(txt, "vol=", -1);
|
||||
int port = txt_get_int(txt, "port=", -1);
|
||||
int rate = txt_get_int(txt, "rate=", 0);
|
||||
char app[40];
|
||||
txt_get_str(txt, "app=", app, sizeof app);
|
||||
char rmsb[16], pkb[16];
|
||||
fmt_db10(rmsb, sizeof rmsb, rms);
|
||||
fmt_db10(pkb, sizeof pkb, pk);
|
||||
if (active) {
|
||||
printf("\rLIVE rms=%sdBFS peak=%sdBFS ", rmsb, pkb);
|
||||
print_bar(pk);
|
||||
printf(" %s %dHz port=%d vol=%d%% ", app, rate, port, vol);
|
||||
} else {
|
||||
printf("\rIDLE 无活跃流(等待播放…) ");
|
||||
}
|
||||
fflush(stdout);
|
||||
if (secs > 0) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
uint64_t now = (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
|
||||
if (now - t0 >= (uint64_t)secs * 1000) break;
|
||||
}
|
||||
usleep(200000); /* 200ms 刷新 */
|
||||
}
|
||||
putchar('\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_route(int port)
|
||||
{
|
||||
m_audio_route_t r; r.port = (uint32_t)port;
|
||||
@@ -284,7 +373,8 @@ static int cmd_tone(int freq, int ms, int rate)
|
||||
|
||||
static void usage(const char *argv0)
|
||||
{
|
||||
fprintf(stderr, "usage: %s status | tone [freq] [ms] [rate] | route <0|2|3> | vol [0-100]\n"
|
||||
fprintf(stderr, "usage: %s status | tone [freq] [ms] [rate] | route <0|2|3> | vol [0-100] | monitor [秒]\n"
|
||||
" monitor: 终端实时电平表(200ms 刷新+文本电平条;缺省 10s,0=持续到 Ctrl-C)\n"
|
||||
" env: MEOW_AUDIO_SOCK (socket 缺省 %s)\n", argv0, AUD_SOCK_DEFAULT);
|
||||
}
|
||||
|
||||
@@ -325,6 +415,10 @@ int main(int argc, char **argv)
|
||||
if (freq <= 0 || ms <= 0 || rate <= 0) { fprintf(stderr, "tone: bad params\n"); return 2; }
|
||||
if (g_fd < 0) { fprintf(stderr, "meow_audio: no audiod (%s) — 音频服务不可用\n", g_sock); return 1; }
|
||||
return cmd_tone(freq, ms, rate);
|
||||
} else if (!strcmp(cmd, "monitor")) {
|
||||
int secs = (argc >= 3) ? atoi(argv[2]) : 10;
|
||||
if (secs < 0) secs = 10;
|
||||
return cmd_monitor(secs);
|
||||
}
|
||||
usage(argv[0]);
|
||||
return 2;
|
||||
|
||||
Reference in new issue
Block a user