Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/audio.c
T
MeowOS e6f0b665e3 refactor(launcher): 拆分 meow_launcherd.c(9778行)→meow_launcherd/ 多文件(agent-149)
- 14 模块 .c + meow_launcher_internal.h(642): util/font_theme/fb_compositor/settings_page/power_menu/notif_center/app_launcher/main_menu/audio/backlight/net/keys/about/statusbar; meow_launcherd.c 已删
- 按行逐字搬移(0-diff), 118函数提升非static+47组extern(内部头), #if0退役区不编入(源码留.pre_split.bak)
- 关于本机小改: 作者 AskaEth/17 + info/item[13]防越界 + s_dd_modal 超高滚动(clamp/触摸滚动/音量键跟随/裁剪, 仅超高启用)
- build_launcher.sh 编译列表→模块; 文档/注释引用 meow_launcherd.c→模块/目录
- 编译0warning/-Wall -Wextra告警集与原文一致(77条无新增)/qemu-mipsel冒烟一致(--scan/--sysdump); launcher=c0799357(505KB; md5因多文件重编译与原文异,非回归依据)
- 备份 meow_launcherd.c.pre_split.bak/meow_launcherd.pre_split.bak; M2.69(0.7.64)已推卡并用户验证OK
2026-08-30 21:38:30 +08:00

225 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* audio.c — MeowOS launcher 拆分模块(LAUNCHER_SPLIT_PLAN 拆分)。*/
/* 本文件由拆分工具从 meow_launcherd.c 按职责搬移;逻辑与原文 0-diff(仅 static 可见性按跨模块需求调整)。*/
#include "meow_launcher_internal.h"
static int amixer_vol(int numid)
{
char cmd[96];
snprintf(cmd, sizeof cmd, "amixer -c 0 cget numid=%d 2>/dev/null", numid);
FILE *p = popen(cmd, "r");
if (!p) return -1;
char buf[128];
int v = -1;
while (fgets(buf, sizeof buf, p)) {
/* ": values=N" line — the other "values=1" on the type line is the
* element's value COUNT, not the actual volume */
char *s = strstr(buf, ": values=");
if (s) { v = atoi(s + 9); break; }
}
pclose(p);
return v;
}
static void amixer_set(int numid, int v)
{
if (v < 0) return;
char cmd[96];
snprintf(cmd, sizeof cmd, "amixer -c 0 cset numid=%d %d >/dev/null 2>&1",
numid, v);
system(cmd);
}
struct vol_snap vol_snapshot(void)
{
struct vol_snap s = { amixer_vol(1), amixer_vol(2) };
return s;
}
void vol_restore(struct vol_snap s)
{
logmsg("volume restore -> L=%d R=%d", s.l, s.r);
amixer_set(1, s.l);
amixer_set(2, s.r);
}
int settings_volume = MEOW_VOL_DEFAULT; /* 当前音量 0-100(= 写入 DAC 的映射值) */
int settings_volume_max = MEOW_VOL_MAX_DEFAULT; /* 最大音量上限 clamp */
int settings_volume_step = MEOW_VOL_STEP_DEFAULT; /* 跳步 */
/* M2.17/M2.16:把 meow_settings 当前值同步到本模块的缓存全局。读取方
* (DAC/状态栏/息屏/刷新率调度)统一从缓存取,避免散读 backend。 */
void settings_sync_cache_from_backend(void)
{
int v;
if (meow_settings_get_int("audio.volume", &v) == 0) settings_volume = v;
if (meow_settings_get_int("audio.volume_max", &v) == 0) settings_volume_max = v;
if (meow_settings_get_int("audio.volume_step", &v) == 0) settings_volume_step = v;
if (meow_settings_get_enum("display.refresh_rate", &v) == 0) /* names "60,30,15" */
refresh_rate_cfg = (v == 1) ? 30 : (v == 2) ? 15 : 60;
if (meow_settings_get_bool("display.refresh_always_max", &v) == 0) refresh_always_max = v;
if (meow_settings_get_int("display.screen_off_timeout", &v) == 0) screen_off_timeout = v;
if (meow_settings_get_enum("display.screen_off_mode", &v) == 0) screen_off_mode = v;
if (meow_settings_get_int("power.longpress_menu_ms", &v) == 0) power_longpress_menu_ms = v;
if (meow_settings_get_int("power.forceoff_ms", &v) == 0) power_forceoff_ms = v;
}
/* meow_settings 变更回调:set_*(如音量键)后同步缓存全局,保证既有引用
* settings_volume 等变量的代码与 backend 单点一致(SYSTEM_SETTINGS §3)。 */
void settings_sync_cache_listener(const char *key)
{
if (!strcmp(key, "audio.volume")) { int v; if (meow_settings_get_int("audio.volume", &v) == 0) settings_volume = v; }
else if (!strcmp(key, "audio.volume_max")) { int v; if (meow_settings_get_int("audio.volume_max", &v) == 0) settings_volume_max = v; }
else if (!strcmp(key, "audio.volume_step")) { int v; if (meow_settings_get_int("audio.volume_step", &v) == 0) settings_volume_step = v; }
else if (!strcmp(key, "display.refresh_rate")) { int v; if (meow_settings_get_enum("display.refresh_rate", &v) == 0) refresh_rate_cfg = (v == 1) ? 30 : (v == 2) ? 15 : 60; }
else if (!strcmp(key, "display.refresh_always_max")) { int v; if (meow_settings_get_bool("display.refresh_always_max", &v) == 0) refresh_always_max = v; }
else if (!strcmp(key, "display.screen_off_timeout")) { int v; if (meow_settings_get_int("display.screen_off_timeout", &v) == 0) screen_off_timeout = v; }
else if (!strcmp(key, "display.screen_off_mode")) { int v; if (meow_settings_get_enum("display.screen_off_mode", &v) == 0) screen_off_mode = v; }
else if (!strcmp(key, "power.longpress_menu_ms")) { int v; if (meow_settings_get_int("power.longpress_menu_ms", &v) == 0) power_longpress_menu_ms = v; }
else if (!strcmp(key, "power.forceoff_ms")) { int v; if (meow_settings_get_int("power.forceoff_ms", &v) == 0) power_forceoff_ms = v; }
}
/* 启动加载(M2.11/M2.24):统一由 meow_settings 后端读 settings.conf;
* 此处仅注册监听(一次性)+ 把 backend 当前值同步到缓存全局。重载(应用期
* watchdog 可能改音量)等价于 meow_settings_init() + 手动同步。 */
int settings_cache_registered = 0; /* M2.24:监听只注册一次 */
/* ---- MeowOS 真实 DAC 音量(CS43198,ANALYSIS §18.39)----
* HibyOS 播放器经 ioctl 直写 /dev/snd/controlC0 的 "Left/Right Playback
* Volume"(numid 1/2,0-255)→ codec 驱动 cs43198_vol_*_put → I2C 直写 CS43198
* 寄存器(0x9000-0x9002/0x7000-0x7001,双片 L/R)。我们复刻同路径(amixer
* cset = SNDRV_CTL_IOCTL_ELEM_WRITE),0-100 → 0-255 映射直写两声道。
* 读回不可用(驱动 get 为 dummy 恒 0;/dev/i2c-3 被驱动占用),故 meow_vol_get()
* 返回我们写入的跟踪值(= 真实 DAC 映射值)。 */
void meow_dac_vol_write(int pct)
{
int dac = pct * 255 / 100;
if (dac < 0) dac = 0;
if (dac > 255) dac = 255;
char cmd[160];
snprintf(cmd, sizeof cmd,
"amixer -c 0 cset numid=1 %d >/dev/null 2>&1; amixer -c 0 cset numid=2 %d >/dev/null 2>&1",
dac, dac);
system(cmd);
logmsg("DAC vol -> L/R=%d (pct %d)", dac, pct);
}
static unsigned long long vol_dac_last_ms = 0;
void meow_dac_vol_write_throttled(void)
{
unsigned long long now = now_ms();
if (now - vol_dac_last_ms < VOL_DRAG_DAC_MS) return; /* 节流窗口内跳过,等抬手统一写 */
vol_dac_last_ms = now;
meow_dac_vol_write(settings_volume);
}
/* 抬手/点击提交连 save 时调用:无条件直写一次真实 DAC(绕过节流,保证最终音量落 DAC/落盘)。 */
void meow_dac_vol_flush(void)
{
vol_dac_last_ms = now_ms();
meow_dac_vol_write(settings_volume);
}
/* clamp 集中:0..MEOW_VOL_MAX,再 clamp 到上限 settings_volume_max。 */
int vol_clamp(int v)
{
if (v < 0) v = 0;
if (v > MEOW_VOL_MAX) v = MEOW_VOL_MAX;
if (v > settings_volume_max) v = settings_volume_max;
return v;
}
static void settings_volume_set(int v)
{
v = vol_clamp(v); /* 0..MEOW_VOL_MAX,再 clamp 到上限 */
meow_settings_set_int("audio.volume", v); /* clamp 集中在 backend;listener 同步缓存 */
meow_dac_vol_write(settings_volume); /* 每次变更即直写真实 DAC(CS43198) */
meow_settings_save(); /* 单点变更即落盘 */
}
int settings_volume_get(void) { return settings_volume; }
int vol_ramp_dir = 0; /* +1 上 / -1 下 / 0 停 */
static int vol_ramp_target = -1; /* 目标值;-1=无 */
static unsigned long long vol_ramp_next_at = 0;
static unsigned long long vol_ramp_press_at = 0; /* M2.18 Bug 4:本方向键按下时刻(长按判据) */
static void vol_ramp_begin(int delta)
{
int target = vol_clamp(settings_volume + delta);
if (target == settings_volume) return;
vol_ramp_dir = (target > settings_volume) ? 1 : -1;
vol_ramp_target = target;
vol_ramp_press_at = now_ms(); /* M2.18 Bug 4:记录该方向键按下时刻,供 CLICK_MS 长按判定 */
vol_ramp_next_at = 0; /* 立即迈第一步,给即时反馈 */
}
/* 每主循环 tick 调;key_held=该方向按键是否仍按住(长按续爬)。返回 1=仍在渐变。
* M2.18 Bug 4 语义:单击(<CLICK_MS=400ms) 到 target 即停(只跳 step 格);长按(≥400ms) 才
* 续段连续爬。普通按压力 50-150ms 远大于 VOL_RAMP_MS(15ms),旧逻辑在到 target 后只要
* key_held=1 就续段 → 单击被当成长按,连爬 6~7 格(「点一下跳好几格」)。CLICK_MS 此前只
* 被 kd_tick 状态机使用,vol_ramp 路径从未接上。 */
int vol_ramp_tick(int key_held)
{
if (vol_ramp_dir == 0) return 0;
unsigned long long now = now_ms();
if (now < vol_ramp_next_at) return 1;
vol_ramp_next_at = now + VOL_RAMP_MS;
/* 先看是否已到「当前目标值」(settings_volume 等于 target,而非候选 v)——
* 因为一旦在 target 再取 v=settings_volume+dir 便越过 target,导致 hold_wait 失效继续爬。 */
if (settings_volume == vol_ramp_target) {
if (!key_held) { /* 松开 → 一段完成,结束(单击到 target 即停,只跳 step 格) */
vol_ramp_dir = 0; vol_ramp_target = -1;
meow_settings_save(); return 0;
}
if (now - vol_ramp_press_at < CLICK_MS) {
/* hold_wait:已到 target 但未到长按阈值 → 停在 target 不爬(保持待命不清 dir,
* 等长按激活或松开);若直接续段,长按第一次到 target 就断了。 */
return 1;
}
/* 长按激活:续段(在 target 基础上再 +step) */
vol_ramp_target = vol_clamp(vol_ramp_target + vol_ramp_dir * settings_volume_step);
if (vol_ramp_target == settings_volume) { /* 续段到上限无进展 → 结束 */
vol_ramp_dir = 0; vol_ramp_target = -1;
meow_settings_save(); return 0;
}
}
int v = vol_clamp(settings_volume + vol_ramp_dir);
if (v == settings_volume) { /* 已达上下限 */
vol_ramp_dir = 0; vol_ramp_target = -1;
meow_settings_save(); return 0;
}
meow_settings_set_int("audio.volume", v); /* 更新 backend 内存 + 同步缓存(不逐 1% 落盘) */
meow_dac_vol_write(settings_volume); /* 每 1% 写一次真实 DAC(settings_volume 已同步) */
return 1;
}
/* 步进调节(±settings_volume_step)→ 起线性渐变(1% 爬,见上)。 */
void settings_volume_adj(int delta) { vol_ramp_begin(delta); }
/* MeowOS 音量 API:get 返回当前(= 写入 DAC 的映射值);set 写真实 DAC + 持久化。 */
static void meow_vol_set(int pct) { settings_volume_set(pct); }
static int meow_vol_get(void) { return settings_volume; }