fix(media): 物理播放/暂停键(164)改发 PLAYCTL cmd=6 toggle + App 前台状态栏音量%实时刷新

Bug1: SDK meow_ui_media 按 g_last_state 本地判 play/pause,但 ncm 走自有 ipc_media
线程不经 SDK meta 上报 → g_last_state 恒 0 → 恒发 cmd=1(播放),播放中按键无效。
修:SDK 164 恒发 cmd=6 toggle(删 g_last_state 判定),ncm apply_playctl case 6
按 player_manager_state() 当前态翻转(源是状态权威);launcher meow_media/util
本就透传 cmd 不动结构,仅 meow_ipc.h/SPEC_REF 注释补 6=toggle。媒体卡片/NP 页
按钮(按 launcher 侧 s->state 判,来自 META 是准的)维持现状。

Bug2: App 前台时状态栏为 launcher 叠加层,App 内 SDK 改音量/亮度只写
settings.conf+DAC,launcher meow_settings 内存表不感知 → g_sys.vol 停旧值。
修:app_overlay_statusbar 前插 app_overlay_settings_poll——1s 节流 stat
settings.conf,mtime 变才 meow_settings_init 重读+sync 缓存+g_sys.vol/brightness
(meow_settings 新增 meow_settings_file_path() 访问器防硬编码分叉)。

验证:宿主 test_sdk_input_keys 19/19(K4 改 toggle 断言)、test_media +cmd=6
透传用例 ALL PASS、ncm bench/toggle_sim 10/10(新)、player_flow/cache_evict
sim PASS、ncm core 宿主+qemu-mipsel PASS、test_settings_brightness PASS;
mipsel 交叉 -Wall -Wextra 0 warning(改动文件单独验+整构建)。
真机(0.7.91):ncm 热更(.new+mv)后 autoplay(Docu) 起播缓存曲 → meow_ipc
playctl 6 二连发 → paused(pos=139691)/resumed 日志实证 toggle 全链路。
md5:ncm 8f10eee5 / meow_ui.a 7b359ec9(gitignore)/ launcher eba4f2b2
(/usr/bin 只读,fw_content.conf 已更新待固件)。物理键 164 实体按压留用户终验。
This commit is contained in:
MeowOS committed 2026-09-01 14:44:55 +08:00
1 parent 9a4ea10c64
commit 820d1e52bf
17 files changed
+173 -26

No files matched your search

+9 -13
View File
@@ -30,11 +30,6 @@ static pthread_t g_thr;
static int g_thr_on = 0;
static volatile int g_quit = 0;
static meow_media_playctl_fn g_cb = NULL;
/* 本进程最后一次经 meow_ui_media_meta 上报的 state(0=停 1=播放 2=暂停 3=缓冲)。
* 供「物理播放/暂停键」做切换判据:播放中→暂停(2),否则→播放(1)。与 launcher
* now_playing.c 的同款判定(state==PLAYING ? 2 : 1)对齐。 */
static int g_last_state = 0;
#define MEOW_UI_MEDIA_STATE_PLAYING 1
/* 后台线程主体(定义在文件后段;on_playctl 懒起时引用)。 */
static void *media_thread_main(void *arg);
@@ -182,7 +177,6 @@ void meow_ui_media_meta(uint32_t state, uint32_t pos_ms, uint32_t dur_ms,
memset(&mm, 0, sizeof mm);
pthread_mutex_lock(&g_mu);
media_app_id();
g_last_state = (int)state; /* 记录最近上报 state:供物理播放/暂停键切换判据(见 sys_key) */
snprintf(mm.app_id, sizeof mm.app_id, "%s", g_app);
mm.state = state;
mm.pos_ms = pos_ms;
@@ -218,14 +212,16 @@ void meow_ui_media_stop(void)
* 本进程注册过 playctl 回调(= 本 App 是媒体源)→ 直接本地回调(最简,无 IPC 往返);
* 否则经 IPC 发 MSG_PLAYCTL 给 launcher 转发到「最近活跃媒体会话」。best-effort 绝不崩。 */
/* 物理媒体键 keycode → MSG_PLAYCTL cmd(1=播放 2=暂停 3=上一首 4=下一首 5=seek)。
* 播放/暂停(164)按最近上报 state 切换(播放中→暂停,否则→播放);上一曲 165/19→3,下一曲 163→4。
* 非媒体键返回 -1。last_state 由调用方在持锁下传入(读 g_last_state 快照)。 */
static int media_key_cmd(int code, int last_state)
/* 物理媒体键 keycode → MSG_PLAYCTL cmd(1=播放 2=暂停 3=上一首 4=下一首 5=seek 6=播放/暂停切换)。
* 播放/暂停(164)恒发 cmd=6 toggle——SDK 本地不再按「最近上报 state」判 play/pause:
* 走自有 IPC 线程的媒体源(如 ncm 的 ipc_media.c)不经 meow_ui_media_meta 上报,
* 本地 state 恒 0 → 恒发「播放」,播放中按键无效(真机 bug)。toggle 由媒体源按自身
* 当前态翻转(权威在源)。上一曲 165/19→3,下一曲 163→4。非媒体键返回 -1。 */
static int media_key_cmd(int code)
{
switch (code) {
case 164: /* KEY_PLAYPAUSE:切换(依最近上报 state) */
return (last_state == MEOW_UI_MEDIA_STATE_PLAYING) ? 2 : 1;
case 164: /* KEY_PLAYPAUSE:toggle(源侧按当前态翻转) */
return 6;
case 165: case 19: /* KEY_PREVIOUSSONG / 旧码 */
return 3;
case 163: /* KEY_NEXTSONG */
@@ -264,8 +260,8 @@ void meow_ui_media_sys_key(int code)
{
pthread_mutex_lock(&g_mu);
meow_media_playctl_fn cb = g_cb;
int cmd = media_key_cmd(code, g_last_state);
pthread_mutex_unlock(&g_mu);
int cmd = media_key_cmd(code);
if (cmd <= 0) return;
if (cb) { cb(cmd, 0); return; } /* 本 App 是媒体源(注册过回调)→ 本地回调 */
send_playctl_upstream(cmd, 0); /* 否则经 IPC 发 launcher 转发到最近活跃会话 */
+3 -2
View File
@@ -19,7 +19,8 @@
extern "C" {
#endif
/* 播放控制回调:cmd 1=播放 2=暂停 3=上一首 4=下一首 5=seek(seek_ms 为毫秒)。 */
/* 播放控制回调:cmd 1=播放 2=暂停 3=上一首 4=下一首 5=seek(seek_ms 为毫秒)6=播放/暂停切换
* (toggle:物理播放/暂停键 164 恒发 6,由媒体源按自身当前态翻转——源是状态权威)。 */
typedef void (*meow_media_playctl_fn)(int cmd, int64_t seek_ms);
/* 指定 app_id(NULL=env MEOW_LOG_APP,缺省 "app")。幂等,首次调用生效。 */
@@ -40,7 +41,7 @@ void meow_ui_media_meta(uint32_t state, uint32_t pos_ms, uint32_t dur_ms,
void meow_ui_media_stop(void);
/* 物理媒体键 → 系统语义(SDK 输入层调用;App 前台也生效)。
* code:164=播放/暂停、165/19=上一曲、163=下一曲。
* code:164=播放/暂停(恒发 cmd=6 toggle,源侧翻转)、165/19=上一曲、163=下一曲。
* 本 App 注册过 playctl 回调(媒体源)→ 本地直接回调 cb(cmd,seek_ms);
* 否则经 IPC 发 MSG_PLAYCTL 给 launcher 转发到最近活跃媒体会话。非媒体键/无源静默。
* best-effort:无 launcher/socket → 优雅降级,绝不崩。 */
Binary file not shown.
+6 -5
View File
@@ -6,7 +6,8 @@
* K2 音量 ± clamp:volume_max 软上限、0 下限、硬上限 100;到限不再写;
* K3 保留其它键:改 audio.volume 不整文件 O_TRUNC(display.brightness/注释保留);
* K4 媒体键本地回调:注册 playctl 回调后,sys_key(上一曲/下一曲/播放暂停) → 回调 cmd 正确
* (播放/暂停按最近上报 state 切换:播放中→暂停(2),暂停/停止→播放(1));
* (播放/暂停恒发 toggle(6),SDK 不再本地判 state——走自有 IPC 线程的源不经 SDK meta
* 上报,本地 state 恒 0 会恒发「播放」致播放中按键无效;源侧按当前态翻转);
* K5 媒体键 IPC 兜底:未注册回调(g_cb==NULL)→ 走 IPC 发 launcher(无 socket → 静默不崩)。
*
* 编译(宿主 gcc,仅链 vol/media 两个 TU;无需 meow_ui 其它子系统):
@@ -101,16 +102,16 @@ int main(void)
meow_ui_media_sys_key(19); /* 旧码上一曲 */
check("K4 旧码(19) -> cb(3)", cb_calls == 3 && cb_cmd == 3);
/* 播放/暂停按最近上报 state 切换 */
/* 播放/暂停物理键恒发 toggle(6):与最近上报 state 无关(源侧按当前态翻转) */
meow_ui_media_meta(1, 0, 0, "t", "a", "al", NULL, NULL); /* state=PLAYING */
meow_ui_media_sys_key(164);
check("K4 播放中按播放/暂停 -> cb(2) 暂停", cb_calls == 4 && cb_cmd == 2);
check("K4 播放中按播放/暂停 -> cb(6) toggle", cb_calls == 4 && cb_cmd == 6);
meow_ui_media_meta(2, 0, 0, "t", "a", "al", NULL, NULL); /* state=PAUSED */
meow_ui_media_sys_key(164);
check("K4 暂停中按播放/暂停 -> cb(1) 播放", cb_calls == 5 && cb_cmd == 1);
check("K4 暂停中按播放/暂停 -> cb(6) toggle", cb_calls == 5 && cb_cmd == 6);
meow_ui_media_meta(0, 0, 0, "t", "a", "al", NULL, NULL); /* state=STOPPED */
meow_ui_media_sys_key(164);
check("K4 停止中按播放/暂停 -> cb(1) 播放", cb_calls == 6 && cb_cmd == 1);
check("K4 停止中按播放/暂停 -> cb(6) toggle", cb_calls == 6 && cb_cmd == 6);
meow_ui_media_stop();