ncm: FLAC 解码落地(dr_flac 0.13.4 单头入库) + 缓存键=歌曲ID+音质档位
- 解码分发 decoder.c:magic(fLaC→dr_flac / 其它→minimp3);flac ≤16bit→S16、 >16bit→S32 满幅送 audiod(AUDIO_FMT_S32),rate/ch/bits 按实际流,零 SRC 零裁剪 - song_url_auto 接受 flac(type 权威/url 扩展名兜底),降级语义不变;flac 下载限幅 1GB - 缓存键 song_<id>_<level>.<ext>:同歌同档命中不重下,换档新条目旧档留 LRU; ext 前导点正名(修双点名),lookup 回退历史双点名+旧无档键温和兼容 - audio_out S32 通路(AUDIOD/ALSA/WAV)+ 流死重开按 bits 还原格式 - 验证(0 真实请求):44.1k/16 与 96k/24 自制样本宿主+qemu 帧数/时长精确、 逐样本零误差;mp3 回归逐帧一致;player_flow_sim P1-P6(新 P6 档位键/flac ext)、 cache_evict/cover/pagination/window/audiod_chain sim 全 PASS;mipsel 0 warning - REPORT §19 / VENDOR_NOTES dr_flac 条目;未部署真机(留主会话)
This commit is contained in:
1 parent
80bc191593
commit
70aec677ce
23 files changed
+13377
-110
No files matched your search
@@ -267,12 +267,19 @@ int ncm_api_song_url_auto(const char *device_id, const char *cookie, const char
|
||||
ncm_play_url_t p;
|
||||
int rc = ncm_api_song_url(device_id, cookie, id, lv, &p);
|
||||
if (rc != NCM_OK) continue;
|
||||
/* 只接受有 url 且 type 为 mp3(v1 不解 flac) */
|
||||
if (p.url[0] && (ncm_streq(p.type, "mp3") || p.type[0] == 0)) {
|
||||
/* §19:接受 mp3 与 flac(dr_flac 落地后无损/Hi-Res 真实生效)。
|
||||
* type 权威;type 缺失(旧端点兼容)时看 url 扩展名,默认当 mp3 收。 */
|
||||
int ok = ncm_streq(p.type, "mp3") || ncm_streq(p.type, "flac");
|
||||
if (!p.type[0]) {
|
||||
ok = 1;
|
||||
const char *dot = strrchr(p.url, '.');
|
||||
if (dot && ncm_streq(dot, ".flac")) ncm_strlcpy(p.type, "flac", sizeof p.type);
|
||||
}
|
||||
if (p.url[0] && ok) {
|
||||
*out = p;
|
||||
return NCM_OK;
|
||||
}
|
||||
/* url 为 null 或 flac:继续降级 */
|
||||
/* url 为 null 或未知格式:继续降级 */
|
||||
}
|
||||
return NCM_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* 音质档位(song_url_v1 level)。v1 可解码 mp3:standard/higher/exhigh。 */
|
||||
/* 音质档位(song_url_v1 level)。可解码 mp3 + flac(§19 dr_flac 落地):
|
||||
* standard/higher/exhigh 通常 mp3;lossless/hires 通常 flac(取决于曲库与会员)。 */
|
||||
enum {
|
||||
NCM_LEVEL_STANDARD = 0,
|
||||
NCM_LEVEL_HIGHER,
|
||||
@@ -75,8 +76,8 @@ int ncm_api_song_detail(const char *device_id, const char *cookie, const int64_t
|
||||
int ncm_api_song_url(const char *device_id, const char *cookie, const char *id,
|
||||
int level, ncm_play_url_t *out);
|
||||
|
||||
/* 播放地址自动降级:从 desired 档开始,遇 url 为 null 或非 mp3(本机不可解码)则逐步降档,
|
||||
* 只返回 mp3。desired 默认 hires。 */
|
||||
/* 播放地址自动降级:从 desired 档开始,遇 url 为 null 或未知格式则逐步降档。
|
||||
* §19 起接受 mp3 与 flac(type 权威;type 缺失看 url 扩展名,默认 mp3)。desired 默认 hires。 */
|
||||
int ncm_api_song_url_auto(const char *device_id, const char *cookie, const char *id,
|
||||
int desired, ncm_play_url_t *out);
|
||||
|
||||
|
||||
@@ -63,9 +63,12 @@ const char *ncm_cache_dir(const ncm_cache_t *c) {
|
||||
return c ? c->dir : "";
|
||||
}
|
||||
|
||||
/* 路径:song_<id>.<ext>。§19 正名:ext 剥离至多一个前导点——旧版调用方传 ".mp3"
|
||||
* 会生成双点文件名 `song_<id>..mp3`(历史存量),新版一律单点。 */
|
||||
int ncm_cache_path(const ncm_cache_t *c, const char *id, const char *ext,
|
||||
char *out, size_t out_sz) {
|
||||
if (!c || !id || !out) return NCM_ERR_ARG;
|
||||
if (ext && ext[0] == '.') ext++;
|
||||
int n = snprintf(out, out_sz, "%s/song_%s.%s", c->dir, id, ext ? ext : "bin");
|
||||
return (n >= 0 && (size_t)n < out_sz) ? NCM_OK : NCM_ERR_FULL;
|
||||
}
|
||||
@@ -75,8 +78,15 @@ int ncm_cache_lookup(const ncm_cache_t *c, const char *id, const char *ext,
|
||||
char path[NCM_CACHE_DIR_MAX + 32];
|
||||
if (ncm_cache_path(c, id, ext, path, sizeof path) != 0) return NCM_ERR_FULL;
|
||||
struct stat st;
|
||||
if (stat(path, &st) != 0) return NCM_ERR_NOENT;
|
||||
if (!S_ISREG(st.st_mode)) return NCM_ERR_NOENT;
|
||||
if (stat(path, &st) != 0 || !S_ISREG(st.st_mode)) {
|
||||
/* §19 温和兼容:历史双点名 `song_<id>..<ext>`(旧版 ext 带前导点所致)。
|
||||
* 命中照常刷新 LRU;不主动改名/删除,由 LRU 自然淘汰。 */
|
||||
const char *e = ext;
|
||||
if (e && e[0] == '.') e++;
|
||||
int n = snprintf(path, sizeof path, "%s/song_%s..%s", c->dir, id, e ? e : "bin");
|
||||
if (n < 0 || (size_t)n >= sizeof path) return NCM_ERR_FULL;
|
||||
if (stat(path, &st) != 0 || !S_ISREG(st.st_mode)) return NCM_ERR_NOENT;
|
||||
}
|
||||
utime(path, NULL); /* 刷新最后访问(按 mtime LRU) */
|
||||
ncm_strlcpy(out, path, out_sz);
|
||||
return NCM_OK;
|
||||
|
||||
@@ -38,7 +38,8 @@ const char *ncm_cache_dir(const ncm_cache_t *c);
|
||||
int ncm_cache_path(const ncm_cache_t *c, const char *id, const char *ext,
|
||||
char *out, size_t out_sz);
|
||||
|
||||
/* 查找已缓存文件。命中:写 out 路径并刷新 mtime,返回 NCM_OK。未命中:NCM_ERR_NOENT。 */
|
||||
/* 查找已缓存文件。命中:写 out 路径并刷新 mtime,返回 NCM_OK。未命中:NCM_ERR_NOENT。
|
||||
* §19:ext 前导点被忽略(新旧调用方同路径);单点 miss 时回退历史双点名 `song_<id>..<ext>`。 */
|
||||
int ncm_cache_lookup(const ncm_cache_t *c, const char *id, const char *ext,
|
||||
char *out, size_t out_sz);
|
||||
|
||||
|
||||
Reference in new issue
Block a user