ncm 三期三批: 歌曲对象瘦身(1324→608B)+滑动窗口(NCM_SONG_WINDOW=256, 取消1000截断支撑任意长度歌单)+播放快照解耦 — agent-251

- core/ncm_api.h: ncm_song_t 瘦身 id24/name128/art96/al96/pic256/dt int32 (1324B→608B)
- appstate.c 滑动窗口: song_ids 全量 trackIds 索引(16384) + songs[256] 窗口感知
  (song_valid 位图/window_base/滑窗 memmove 保留重叠), ensure_range 批网格(100)对齐
  预取, songmeta.c 盘缓存 <cache_dir>/meta/<id>.bin (回滚/二次进入 0 网络请求)
- playlist.c 触底分页退役→视口 ensure(±24 行), 占位行可直点(播放线程 fetch 物化),
  footer 改视口区间/总数
- 播放兼容: g_play.play_song 快照(mu), run_song 起播物化后全链路(下载/歌词/IPC META/
  播放页 UI)读快照——窗口滑出当前播放曲不崩; 边界 song_count→track_ids_count
- 验证(0 真实请求): pagination_sim 全 PASS(5191 无截断/52 批); window_sim 6000 首
  全程下滚 750 步视口全物化/song_detail 恰 60 次/回滚+0 请求/播放 fetch 不滑窗;
  core 宿主+qemu 全 PASS; mipsel -Wall -Wextra 0 warning, bss 2052068→1080900(-47%)
- 未部署真机(设备音频线排查中, 部署留主会话)
This commit is contained in:
MeowOS committed 2026-09-01 04:03:01 +08:00
1 parent d8898afa09
commit 997f89f879
18 files changed
+987 -209

No files matched your search

+31 -16
View File
@@ -25,6 +25,7 @@ static ncm_rect_t r_cont;
static int g_custom_disc, g_custom_dyn;
static int g_landscape;
static int g_last_pos_ms, g_last_state, g_last_line, g_last_song;
static char g_last_meta_id[24]; /* 已上封面的元数据 id(快照滞后 settle 时纠正封面/歌名) */
/* 运行期几何(player_compute_geom 填充;各带绘制物/命中共用)。 */
static ncm_rect_t g_disc_r, g_dyn_r; /* 盘带 / 动态带 bbox(不重叠) */
@@ -40,7 +41,16 @@ static ncm_rect_t g_lyr; /* 歌词区 */
static int cur_song(void)
{
int c = player_manager_playing_song();
return (c >= 0 && c < g_st.song_count) ? c : -1;
return (c >= 0 && c < g_st.track_ids_count) ? c : -1;
}
/* 当前播放曲元数据(§17):优先播放快照(窗口无关);快照未就绪时退窗口拷贝。 */
static int cur_song_meta(ncm_song_t *out)
{
if (player_manager_current_song(out) == 0) return 0;
int sc = cur_song();
if (sc >= 0 && appstate_song_copy(sc, out) == 0) return 0;
return -1;
}
static void fmt_ms(int64_t ms, char *out, size_t sz)
@@ -188,10 +198,10 @@ static void plr_draw_dyn(void *ctx)
if (meow_ui_activity_active() != ACT_PLAYER) return;
const meow_theme *th = meow_theme_get();
const ncm_pal_t *pa = ncm_palette(g_dark);
int sc = cur_song();
const ncm_song_t *s = (sc >= 0) ? &g_st.songs[sc] : NULL;
const char *nm = s ? s->name : "暂无播放";
const char *ar = s ? s->art_name : "";
ncm_song_t sm;
int have = (cur_song_meta(&sm) == 0);
const char *nm = have ? sm.name : "暂无播放";
const char *ar = have ? sm.art_name : "";
if (g_landscape) {
meow_ui_text(g_info_x, g_title_y, ncm_text_fit(nm, g_info_w, 28), 28, th->onSurface);
@@ -204,7 +214,7 @@ static void plr_draw_dyn(void *ctx)
/* 进度条 + 时间 */
int pos = (int)player_manager_pos_ms();
int dur = (int)player_manager_dur_ms();
if (dur <= 0 && sc >= 0) dur = (int)(g_st.songs[sc].duration_ms);
if (dur <= 0 && have) dur = (int)sm.duration_ms;
int frac = dur > 0 ? (int)((int64_t)pos * 1000 / dur) : 0;
if (frac < 0) frac = 0; if (frac > 1000) frac = 1000;
char lp[16], rp[16];
@@ -302,11 +312,12 @@ void player_on_tap(int x, int y)
void player_play_song(int idx)
{
if (idx < 0 || idx >= g_st.song_count) return;
/* 二期:黑胶封面用真实专辑图(song_detail 的 al.picUrl,经 ncm_cache 缓存/限幅),
* 无 al.picUrl(如无版权占位)时回落歌单封面。 */
const ncm_song_t *s = &g_st.songs[idx];
const char *cover = (s && s->al_pic[0]) ? s->al_pic : g_st.cover_url;
if (idx < 0 || idx >= g_st.track_ids_count) return;
/* 黑胶封面用真实专辑图(song_detail 的 al.picUrl,经 ncm_cache 缓存/限幅);
* 滑窗未物化(占位行直点)时回落歌单封面,元数据由播放线程物化后快照接管(§17)。 */
ncm_song_t s;
const char *cover = (appstate_song_copy(idx, &s) == 0 && s.al_pic[0])
? s.al_pic : g_st.cover_url;
player_manager_play(idx);
appstate_set_playing_song(idx, cover);
cover_request(cover);
@@ -338,13 +349,16 @@ void player_tick(uint64_t now)
if (sc != g_last_song) {
g_last_song = sc;
/* 切歌(next/prev/自动顺延)→ 请求新曲专辑封面(黑胶盘换图) */
if (sc >= 0) {
const ncm_song_t *s2 = &g_st.songs[sc];
cover_request(s2->al_pic[0] ? s2->al_pic : g_st.cover_url);
}
meow_ui_invalidate(g_dyn_r.x, g_dyn_r.y, g_dyn_r.w, g_dyn_r.h); /* 歌名/歌手变 */
}
/* 元数据 id 变化(含快照滞后 settle:切歌瞬间快照仍是旧曲,play 线程更新后此处纠正)→
* 请求新曲专辑封面(黑胶盘换图)+ 刷动态带。 */
ncm_song_t s2;
if (sc >= 0 && cur_song_meta(&s2) == 0 && strcmp(s2.id, g_last_meta_id) != 0) {
ncm_strlcpy(g_last_meta_id, s2.id, sizeof g_last_meta_id);
cover_request(s2.al_pic[0] ? s2.al_pic : g_st.cover_url);
meow_ui_invalidate(g_dyn_r.x, g_dyn_r.y, g_dyn_r.w, g_dyn_r.h);
}
if (cover_changed()) {
cover_ack();
meow_ui_invalidate(g_disc_r.x, g_disc_r.y, g_disc_r.w, g_disc_r.h);
@@ -376,6 +390,7 @@ static void plr_page_create(meow_view *v, void *ctx)
g_custom_dyn = meow_draw_custom_register(11, g_dyn_r.x, g_dyn_r.y, g_dyn_r.w, g_dyn_r.h,
plr_draw_dyn, NULL);
g_last_pos_ms = -1; g_last_state = -1; g_last_line = -1; g_last_song = -1;
g_last_meta_id[0] = 0;
}
static void plr_page_enter(meow_view *v, void *ctx)