feat: M6.10–M6.19 批量收编 + M6.19 推卡验收
- M7 launcher 重写 5 期(虚拟化宫格/meow_theme 单一权威/横幅动画/自定义 PIN 键盘) - OOM 通用化(cachegov 上收 SDK)、自动切歌根治、meowpanel jv_free 泄漏修复、Hello 滚动卡顿修复 - ncm 歌词 UI / 媒体通知封面 / 封面分辨率 640 - 5 bug 修复:ncm 后台化 UI 叠层+点击穿透、再进 ncm 桌面叠层、播放页新旧 UI 叠层抢刷脏区(meow_ui_gfx 恢复边沿整帧重画)、PIN 亮屏亮度跳(keys.c meow_panel_on 按 settings_brightness_clamped 恢复)、通知中心封面显歌单封面(cover.c save_cover_raw 加 is_song + 命中块守卫) - 四 App 统一重链新 meow_ui.a 51caee4a;M6.19=0.8.19 固件 2d2331f2 推卡自刷验收全绿
This commit is contained in:
1 parent
c2ee7626a4
commit
3d70a3dd2c
176 files changed
+15507
-597
No files matched your search
@@ -32,6 +32,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include "decoder.h"
|
||||
#include "stream_src.h"
|
||||
#include "mem_watch.h"
|
||||
|
||||
static pthread_t g_thr;
|
||||
static int g_thr_on;
|
||||
@@ -43,6 +44,10 @@ static char g_path[512]; /* 本地音频路径(缓存,mp3/flac
|
||||
static int64_t g_file_bytes;
|
||||
static int g_level; /* 音质档(来自设置) */
|
||||
static int g_cache_gb;
|
||||
/* 任务3(§re-entry):pending_replay=1 表示「切音质/缓存后点了正在播的同曲」——此时重播须换档
|
||||
* (P12 语义,seq++),不得被「同曲不重播」护栏吞掉。set_quality 置位;player_manager_play 的
|
||||
* 同曲护栏据它分流:pending=1 走重播(换档),pending=0 只聚焦不重播(点正在播的曲)。 */
|
||||
static int g_pending_replay;
|
||||
|
||||
/* 被抢占回调(SDK 读线程分发;audiod 后开流赢):走 g_play 命令通道暂停(内部持锁),
|
||||
* 不直接动锁外状态。恢复时 audio_out_pause(0) 会检测流死并自动重开(见 audio_out.c)。 */
|
||||
@@ -90,12 +95,25 @@ void player_manager_set_quality(int level, int cache_gb)
|
||||
pthread_mutex_lock(&g_play.mu);
|
||||
g_play.err = 0;
|
||||
ncm_cache_set_limit_gb(&g_st.ctx.cache, cache_gb);
|
||||
g_pending_replay = 1; /* 任务3:改档后点正在播的同曲 → 强制换档重播(§25 P12) */
|
||||
pthread_mutex_unlock(&g_play.mu);
|
||||
}
|
||||
|
||||
void player_manager_play(int song_idx)
|
||||
{
|
||||
pthread_mutex_lock(&g_play.mu);
|
||||
/* 任务3:点「正在播的曲」(同 idx 且 PLAYING/PAUSED,非切档重播)→ 只聚焦不重播:
|
||||
* 不 seq++、不置 BUFFER——旧曲继续出声/停原状态,UI 由调用方 nav 到播放页。
|
||||
* 注意:set_quality 已置 g_pending_replay=1(切音质后重播同曲须换档,P12),此护栏放行。
|
||||
* 非 PLAYING/PAUSED(STOPPED/另一曲)不受影响,照旧起播。 */
|
||||
if (song_idx == g_play.cur_song && !g_pending_replay &&
|
||||
(g_play.state == NCM_PC_PLAYING || g_play.state == NCM_PC_PAUSED)) {
|
||||
pthread_mutex_unlock(&g_play.mu);
|
||||
meow_log(MEOW_LOG_INFO, "play: re-enter current idx=%d state=%d -> no restart",
|
||||
song_idx, g_play.state);
|
||||
return;
|
||||
}
|
||||
g_pending_replay = 0; /* 消费掉(新播放意图落地,后续同曲 tap 恢复「只聚焦」) */
|
||||
g_play.cur_song = song_idx;
|
||||
g_play.cmd = 0;
|
||||
g_play.state = NCM_PC_BUFFER;
|
||||
@@ -108,6 +126,7 @@ void player_manager_play(int song_idx)
|
||||
g_play.underruns = 0; /* §21:边下边播统计随新播放意图清零 */
|
||||
g_play.underrun_ms = 0;
|
||||
g_play.stalled = 0;
|
||||
g_play.refaults = 0; /* §2.3:refault 取证随新播放意图清零 */
|
||||
pthread_mutex_unlock(&g_play.mu);
|
||||
}
|
||||
|
||||
@@ -135,6 +154,7 @@ void player_manager_next(int dir)
|
||||
int cnt = appstate_queue_count(); /* §23:按队列来源(窗口全量 或 搜索条数) */
|
||||
if (c >= cnt) c = cnt - 1;
|
||||
if (c != g_play.cur_song) {
|
||||
g_pending_replay = 0; /* 新播放意图落地:清「切档重播」待办 */
|
||||
g_play.cur_song = c;
|
||||
g_play.cmd = 0;
|
||||
g_play.state = NCM_PC_BUFFER;
|
||||
@@ -147,6 +167,7 @@ void player_manager_next(int dir)
|
||||
g_play.underruns = 0;
|
||||
g_play.underrun_ms = 0;
|
||||
g_play.stalled = 0;
|
||||
g_play.refaults = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&g_play.mu);
|
||||
}
|
||||
@@ -154,6 +175,7 @@ void player_manager_next(int dir)
|
||||
void player_manager_stop(void)
|
||||
{
|
||||
pthread_mutex_lock(&g_play.mu);
|
||||
g_pending_replay = 0; /* 停止:清「切档重播」待办 */
|
||||
g_play.cur_song = -1;
|
||||
g_play.state = NCM_PC_STOPPED;
|
||||
g_play.pos_ms = 0;
|
||||
@@ -189,8 +211,19 @@ typedef struct {
|
||||
int *st_ptr; /* 指向 dl_thread 的 status 局部变量(同线程,无竞态) */
|
||||
int need_fresh; /* 416/其它:服务器拒绝续传 → 放 .part、交调用方整首重下 */
|
||||
uint64_t skip; /* 200 忽略 Range:body 前 skip 字节与 .part 前缀重复,丢弃 */
|
||||
/* page-cache 治理(A:meow_cachegov)登记路径:播放实际读的文件(流式=.tmp/.part,命中=final)。 */
|
||||
char gov_path[512];
|
||||
/* 曲终 L0 用:commit 后的正式路径(流式 commit rename 后 = final;命中=gov_path 同)。 */
|
||||
char gov_final_path[512];
|
||||
} song_src_t;
|
||||
|
||||
/* page-cache 治理(A):SDK meow_cachegov 的 read_pos 回调——返回当前解码逻辑读指针
|
||||
* (stream_src 内部维护,经 stream_src_read_pos 读取;回调上下文=stream_src*)。 */
|
||||
static uint64_t gov_read_pos(void *ctx)
|
||||
{
|
||||
return stream_src_read_pos((stream_src_t *)ctx);
|
||||
}
|
||||
|
||||
/* http 体回调(下载线程上下文;ncm_http 每次投递 ≤4KB):write(2) 直写落盘 +
|
||||
* 锁内推进 written + broadcast 唤醒读端 + 进度反馈。
|
||||
* 阶段3 续传(§5.2):首 body 字节按 response status 切换写姿态——
|
||||
@@ -201,6 +234,11 @@ static int stream_dl_cb(void *ctx, const unsigned char *data, size_t len)
|
||||
{
|
||||
song_src_t *ss = (song_src_t *)ctx;
|
||||
if (stream_src_aborted(ss->src)) return 1; /* 切歌/停止:中止 http */
|
||||
/* page-cache 治理(§2.3/§3):下载 cb 查 meow_cachegov_download_paused()(A 回退硬暂停
|
||||
* OR svc_perf C Cached 降载)→ 暂停下载(限速),优先解码播放;不打断播放线程
|
||||
* (读端追上下载走既有 underrun/停滞联动)。每 50ms 查一次中止,切歌可立即脱身。 */
|
||||
while (meow_cachegov_download_paused() && !stream_src_aborted(ss->src))
|
||||
usleep(50 * 1000);
|
||||
if (ss->first_body) {
|
||||
ss->first_body = 0;
|
||||
int st = ss->st_ptr ? *ss->st_ptr : 0;
|
||||
@@ -295,6 +333,15 @@ static void song_src_dispose(song_src_t *ss)
|
||||
if (ss->src) { stream_src_close(ss->src); ss->src = NULL; }
|
||||
}
|
||||
|
||||
/* page-cache 治理(A)曲终清理:注销 L1 登记条目 + 下载完整(commit 成功)则对正式文件做
|
||||
* L0 整文件 DONTNEED(仅曲终安全窗口;未 commit/中断保留 .part 不丢)。 */
|
||||
static void song_gov_cleanup(song_src_t *ss)
|
||||
{
|
||||
if (ss->gov_path[0]) meow_cachegov_unregister(ss->gov_path);
|
||||
if (ss->dl_rc == NCM_OK && ss->gov_final_path[0])
|
||||
meow_cachegov_drop_finished(ss->gov_final_path);
|
||||
}
|
||||
|
||||
/* 缓存键(用户定案 NCM_CACHE_DESIGN §2.5):歌曲ID + 音质档位 → "song_<id>_<level>.<ext>"。
|
||||
* 同歌同档命中不重复下载;换档=新条目,旧档留给 LRU 自然淘汰。
|
||||
* §20:键后缀用 ncm_api_level_key(sky 与 sky_c51 可区分)。 */
|
||||
@@ -587,6 +634,7 @@ static void run_song(int idx)
|
||||
g_play.play_song = s;
|
||||
g_play.play_song_valid = 1;
|
||||
pthread_mutex_unlock(&g_play.mu);
|
||||
mem_watch_song_begin(); /* 边播边监控:本曲峰值从当前起算(下载/解码/播放全程记录) */
|
||||
|
||||
song_src_t ss;
|
||||
int64_t file_bytes = 0;
|
||||
@@ -602,11 +650,22 @@ static void run_song(int idx)
|
||||
}
|
||||
if (!still_intent(idx, my_seq)) { /* 预缓冲完成但已切歌/同曲重播:勿开解码/勿动状态 */
|
||||
song_src_dispose(&ss);
|
||||
song_gov_cleanup(&ss); /* 未登记(register 在其后)时为 no-op,统一清理 */
|
||||
mem_watch_song_end(); /* 释放钩子:join 下载线程+关源+缓冲 free+.part 收尾 */
|
||||
return;
|
||||
}
|
||||
ncm_strlcpy(g_path, path, sizeof g_path);
|
||||
g_file_bytes = file_bytes;
|
||||
|
||||
/* page-cache 治理(A):登记本曲缓存文件(播放实际读的路径)+ read_pos 回调,供 L1 丢已读
|
||||
* 前缀 / refault 回退。cache 命中(ss.w==NULL)path=正式文件;流式 path=.tmp/.part
|
||||
* (cur file 即正被 pread 的文件,DONTNEED 只作用于它;正式路径待 commit 后 L0 用)。 */
|
||||
ncm_strlcpy(ss.gov_path, path, sizeof ss.gov_path);
|
||||
if (ss.w) ncm_strlcpy(ss.gov_final_path, ncm_cache_writer_final_path(ss.w), sizeof ss.gov_final_path);
|
||||
else ncm_strlcpy(ss.gov_final_path, path, sizeof ss.gov_final_path);
|
||||
meow_cachegov_register(ss.gov_path, (uint64_t)(file_bytes > 0 ? file_bytes : 0),
|
||||
gov_read_pos, ss.src);
|
||||
|
||||
int64_t dur = s.duration_ms > 0 ? s.duration_ms : 0;
|
||||
|
||||
/* 解码分发(§19/§21):stream_src 上 magic 探测 fLaC→dr_flac / 其它→minimp3(open_cb
|
||||
@@ -616,6 +675,8 @@ static void run_song(int idx)
|
||||
int64_t total_frames = 0;
|
||||
if (ncm_dec_open_src(&dec, ss.src, &rate, &ch, &bits, &total_frames) != 0) {
|
||||
song_src_dispose(&ss);
|
||||
song_gov_cleanup(&ss);
|
||||
mem_watch_song_end(); /* 释放钩子 */
|
||||
if (!still_intent(idx, my_seq)) return; /* open 期间(flac 元数据等待)已切歌/重播 */
|
||||
set_err(NCM_ERR_IO, "decode open failed"); return;
|
||||
}
|
||||
@@ -623,7 +684,8 @@ static void run_song(int idx)
|
||||
|
||||
/* 音频输出:按实际流参数开(flac ≤16bit→S16,>16bit→S32;audiod 侧格式归一+原生率跟随) */
|
||||
if (audio_out_open(rate, ch, bits) != 0) {
|
||||
ncm_dec_close(dec); song_src_dispose(&ss);
|
||||
ncm_dec_close(dec); song_src_dispose(&ss); song_gov_cleanup(&ss);
|
||||
mem_watch_song_end(); /* 释放钩子 */
|
||||
set_err(NCM_ERR_IO, "audio open failed"); return;
|
||||
}
|
||||
|
||||
@@ -645,6 +707,7 @@ static void run_song(int idx)
|
||||
int paused_edge = 0; /* 暂停沿:进暂停已向 audiod 发 pause */
|
||||
int stalled_edge = 0; /* §21 停滞沿:已对 audiod pause(1),待数据恢复 pause(0) */
|
||||
int underruns_seen = 0;
|
||||
int refaults_seen = 0; /* §2.3:本曲 DONTNEED 丢页重读 TF 计数(取证) */
|
||||
|
||||
for (;;) {
|
||||
if (g_app_quit) break;
|
||||
@@ -751,6 +814,18 @@ static void run_song(int idx)
|
||||
idx, u, (unsigned long long)wm);
|
||||
}
|
||||
}
|
||||
/* page-cache 治理(A):refault 取证落 g_play + 节拍执行 L1 丢弃/refault 回退 */
|
||||
{
|
||||
int rf = stream_src_refaults(ss.src);
|
||||
if (rf != refaults_seen) {
|
||||
refaults_seen = rf;
|
||||
pthread_mutex_lock(&g_play.mu);
|
||||
g_play.refaults = rf;
|
||||
pthread_mutex_unlock(&g_play.mu);
|
||||
meow_log(MEOW_LOG_INFO, "play: refault idx=%d count=%d", idx, rf);
|
||||
}
|
||||
meow_cachegov_tick();
|
||||
}
|
||||
/* 更新进度(~200ms 节流)*/
|
||||
int64_t pos = rate > 0 ? frames_done * 1000 / rate : 0;
|
||||
pthread_mutex_lock(&g_play.mu);
|
||||
@@ -763,6 +838,9 @@ static void run_song(int idx)
|
||||
ncm_dec_close(dec);
|
||||
/* 下载完成由播放线程 commit(rename) / 中断 abort(阶段 2 语义,§21) */
|
||||
song_src_dispose(&ss);
|
||||
song_gov_cleanup(&ss); /* page-cache 治理(A)曲终:注销 L1 条目 + commit 成功则 L0 整文件 DONTNEED */
|
||||
mem_watch_song_end(); /* 调度器释放钩子:上一首缓冲完全清空(decoder 关 + 下载线程
|
||||
* join + 源关 + 缓冲 free + .part 收尾)——给下一首让内存 */
|
||||
/* 若应继续播下一首且非因命令打断,由外层处理(外层见 cur==idx 且需自然结束) */
|
||||
}
|
||||
|
||||
@@ -835,7 +913,9 @@ static void *lyric_worker(void *arg)
|
||||
}
|
||||
if (!id[0]) continue;
|
||||
if (strcmp(id, last_id) == 0) continue; /* 同一曲已拉/在拉 */
|
||||
|
||||
if (meow_cachegov_prefetch_paused()) continue; /* page-cache 治理(§2.3/§3):暂停歌词预取
|
||||
* (A 回退硬暂停 OR svc_perf C Cached 降载),
|
||||
* 不置 last_id → 降载恢复后下轮再拉。 */
|
||||
ncm_strlcpy(last_id, id, sizeof last_id);
|
||||
lyric_clear();
|
||||
pthread_mutex_lock(&g_lyrmu);
|
||||
@@ -898,6 +978,7 @@ int player_manager_start(void)
|
||||
g_cache_gb = g_st.cache_limit_gb;
|
||||
pthread_mutex_init(&g_play.mu, NULL);
|
||||
meow_audio_on_preempt(on_audio_preempt, NULL); /* 被抢占 → 暂停(SDK 读线程分发) */
|
||||
mem_watch_start(); /* 边播边监控(防 OOM):起监控线程读 RSS,驱下载降载 */
|
||||
if (ncm_thread_create(&g_thr, player_thread, NULL) != 0) return -1;
|
||||
g_thr_on = 1;
|
||||
return 0;
|
||||
@@ -908,6 +989,7 @@ void player_manager_stop_thread(void)
|
||||
g_want_run = 0;
|
||||
g_app_quit = 1;
|
||||
audio_out_close(); /* 打断阻塞写 */
|
||||
mem_watch_stop(); /* 停监控线程 */
|
||||
if (g_thr_on) {
|
||||
pthread_join(g_thr, NULL);
|
||||
g_thr_on = 0;
|
||||
|
||||
Reference in new issue
Block a user