Files
MeowOS-For-R3P2/patch_v2/ncm_app/bench/toggle_sim.c
T
MeowOS 820d1e52bf 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 实体按压留用户终验。
2026-09-01 14:44:55 +08:00

97 lines
4.1 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.
/* bench/toggle_sim.c — MSG_PLAYCTL cmd=6(toggle) 离线回归(0 真实请求)。
*
* 背景(真机 bug):物理播放/暂停键(164)在 SDK 侧曾按「最近上报 state」本地判 play/pause,
* 但 ncm 走自有 ipc_media 线程、不经 SDK meow_ui_media_meta 上报 → SDK 侧 state 恒 0 →
* 恒发 cmd=1(播放),播放中按键无效。修法:SDK 恒发 cmd=6 toggle,源侧(本文件 apply_playctl)
* 按自身当前态翻转——源是状态权威。
*
* 同 TU 平移 app/play/ipc_media.c(含 static apply_playctl),player_manager_* 用记录桩
* (-ffunction-sections + --gc-sections 丢弃未触达的 send_meta/ipc_thread 及其依赖)。
*
* 用例:
* T1 播放中 toggle → pause(1);
* T2 暂停中 toggle → pause(0);
* T3 停止/缓冲中 toggle → pause(1)(player_manager_pause 内部按态过滤,no-op 安全);
* T4 旧 cmd 回归:1=play→pause(0) 2=pause→pause(1) 3=prev→next(-1) 4=next→next(1) 5=seek。
*
* 编译(宿主,ncm_app 目录下):
* gcc -Wall -Wextra -O2 -ffunction-sections -DJSMN_HEADER -I. -I../sdk -I../meow_launcherd \
* -Icore -Ivendor/jsmn -c bench/toggle_sim.c -o /tmp/tg.o
* gcc -O2 -Wl,--gc-sections -o toggle_sim /tmp/tg.o -lpthread -lm
* 运行:./toggle_sim (PASS/FAIL 退出码)
*/
#include "../app/ncm_app_internal.h"
/* ---- player_manager 记录桩(覆盖真实实现,仅记录调用)---- */
static int g_fake_state = NCM_PC_STOPPED;
static int g_pause_calls = 0, g_pause_last = -1;
static int g_next_calls = 0, g_next_last = 0;
static int g_seek_calls = 0; static int64_t g_seek_last = -1;
int player_manager_state(void) { return g_fake_state; }
void player_manager_pause(int on) { g_pause_calls++; g_pause_last = on; }
void player_manager_next(int dir) { g_next_calls++; g_next_last = dir; }
void player_manager_seek(int64_t ms) { g_seek_calls++; g_seek_last = ms; }
/* ---- 被平移 TU 引用但本测试不触达的符号(gc-sections 会丢,仅为防漏列桩)---- */
#include "../app/play/ipc_media.c"
static int failures = 0;
static void check(const char *name, int cond)
{
printf("%s %s\n", cond ? "PASS" : "FAIL", name);
if (!cond) failures++;
}
static m_playctl_t mk(uint32_t cmd, int64_t seek)
{
m_playctl_t c;
memset(&c, 0, sizeof c);
c.cmd = cmd;
c.seek_ms = seek;
return c;
}
int main(void)
{
m_playctl_t c;
/* T1 播放中 toggle → 暂停 */
g_fake_state = NCM_PC_PLAYING;
c = mk(NCM_CTL_TOGGLE, 0);
apply_playctl(&c);
check("T1 PLAYING+toggle -> pause(1)", g_pause_calls == 1 && g_pause_last == 1);
/* T2 暂停中 toggle → 播放 */
g_fake_state = NCM_PC_PAUSED;
apply_playctl(&c);
check("T2 PAUSED+toggle -> pause(0)", g_pause_calls == 2 && g_pause_last == 0);
/* T3 停止/缓冲 toggle → pause(1)(内部按态过滤,不崩) */
g_fake_state = NCM_PC_STOPPED;
apply_playctl(&c);
check("T3 STOPPED+toggle -> pause(1) 内部过滤", g_pause_calls == 3 && g_pause_last == 1);
g_fake_state = NCM_PC_BUFFER;
apply_playctl(&c);
check("T3 BUFFER+toggle -> pause(1) 内部过滤", g_pause_calls == 4 && g_pause_last == 1);
/* T4 旧 cmd 回归 */
c = mk(NCM_CTL_PLAY, 0); apply_playctl(&c);
check("T4 PLAY -> pause(0)", g_pause_calls == 5 && g_pause_last == 0);
c = mk(NCM_CTL_PAUSE, 0); apply_playctl(&c);
check("T4 PAUSE -> pause(1)", g_pause_calls == 6 && g_pause_last == 1);
c = mk(NCM_CTL_PREV, 0); apply_playctl(&c);
check("T4 PREV -> next(-1)", g_next_calls == 1 && g_next_last == -1);
c = mk(NCM_CTL_NEXT, 0); apply_playctl(&c);
check("T4 NEXT -> next(1)", g_next_calls == 2 && g_next_last == 1);
c = mk(NCM_CTL_SEEK, 12345); apply_playctl(&c);
check("T4 SEEK -> seek(12345)", g_seek_calls == 1 && g_seek_last == 12345);
c = mk(99, 0); apply_playctl(&c); /* 未知 cmd:无动作不崩 */
check("T4 unknown cmd=99 -> no-op",
g_pause_calls == 6 && g_next_calls == 2 && g_seek_calls == 1);
printf("\n%s (%d failure%s)\n", failures ? "RESULT: FAIL" : "RESULT: PASS",
failures, failures == 1 ? "" : "s");
return failures ? 1 : 0;
}