/* play/meta_gate.h — 媒体会话 META 上报闸(M10:META 洪泛修复点;纯逻辑,宿主可驱动)。 * * 背景(真机证据):launcher meow_20261105_122541.log 里 21016 条 `ipc: META app=dev.player.ncm * state=0 pos=0/0 rc=0 -> ACK`,间隔 ~100ms(每次 launcher 收帧都要写日志+归并会话)。 * 旧 ipc_media 的节奏是 `if (now - last_meta >= 1000)`,同样依赖 meow_ui_time_ms() 的 64 位差值; * 真机该值高 32 位是垃圾(REPORT §42)→ 条件几乎恒真 → 每个 IPC 轮次都发 META, * 1s 心跳退化成 10Hz 洪泛,把 launcher 的 SD 写/会话归并拖满,整机卡死。 * * 修复后的上报策略(不再是定时器,而是「变化 + 低频心跳」): * - 状态/时长/标题/歌手/专辑/封面/歌词标志变化 → 立即上报(用户操作要即时可见); * - 播放中位置相对上次上报偏移 ≥ 5s(含 seek 前后跳)→ 上报,给 launcher 重锚进度 * (launcher meow_media_display_pos 会按 last_active 自行外推,5s 足够); * - 心跳:播放中 5s、非播放 30s(保活会话/防 launcher 会话超时清理); * - 硬下限 250ms:任何路径(含状态抖动)都不快于 4 帧/秒。 * 时间基准由调用方给单调钟(ipc_media 传 core 的 ncm_monotonic_ms())。 */ #ifndef NCM_META_GATE_H #define NCM_META_GATE_H #include /* 与 meow_ipc.h 的 m_meta_t.state 同口径(MF_PLAYBACK 会话状态)。 */ enum { NCM_META_ST_STOPPED = 0, NCM_META_ST_PLAYING = 1, NCM_META_ST_PAUSED = 2, NCM_META_ST_BUFFER = 3, }; /* 一次上报快照(字符串由调用方持有,本模块只拷贝比较,不接管所有权)。 */ typedef struct { int state; /* NCM_META_ST_* */ int pos_ms; int dur_ms; int flags; /* MF_ART/MF_COVER/MF_LYRIC 位 */ const char *title; const char *artist; const char *album; const char *artwork; } ncm_meta_snap; typedef struct { int inited; int state; int dur_ms; int flags; int last_pos_ms; /* 上次上报时的播放位置(判进度偏移/seek) */ int64_t last_send_ms; /* 上次上报的单调毫秒 */ char title[128]; char artist[128]; char album[128]; char artwork[192]; } ncm_meta_gate; #define NCM_META_POS_RESEND_MS 5000 /* 播放中位置偏移(ms)触发重报 */ #define NCM_META_HB_PLAY_MS 5000 /* 播放中心跳 */ #define NCM_META_HB_IDLE_MS 30000 /* 非播放心跳 */ #define NCM_META_MIN_GAP_MS 250 /* 硬下限:任何情况下 ≤ 4 帧/秒 */ void ncm_meta_gate_init(ncm_meta_gate *g); /* 返回 1=现在应当发送(内部已把本次快照记为「已上报」);0=不必发。 * now_ms=单调毫秒(建议 ncm_monotonic_ms())。未初始化时首调必发(注册媒体源)。 */ int ncm_meta_gate_should_send(ncm_meta_gate *g, const ncm_meta_snap *s, int64_t now_ms); #endif /* NCM_META_GATE_H */