Files
MeowOS-For-R3P2/patch_v2/ncm_app/app/play/stream_src.h
T
MeowOS 19e8fc93ed feat(ncm §24): 流媒体客户端边下边播阶段3——.part断点续传(Range/206/200/416)+LRU防淘汰(.tmp/.part跳过)+失败重试1次退避
按 devdocs/plan/NCM_STREAM_PLAY.md §8 阶段3:
- .part 断续传:中断留 .part,续传带 Range,206 追加 / 200 丢头段 / 416 删残留整首重下;URL 每次新拉
- LRU 防淘汰:evict/total_bytes 跳过 .tmp/.part(在播文件不被动过)
- 失败重试:预缓冲前网络失败重试 1 次,退避 800ms,重试拿新签名 URL(风控:0 真实请求,未部署)
- 顺手修:gb_to_bytes 返回 int 溢出致默认 10GB 上限失效 -> uint64_t
- 验证:stream_sim(续传 PCM 金标准+全矩阵)/player_flow_sim(P9/P10/P11)/cache_evict_sim(case7/8)/test_ncm_core 宿主+qemu-mipsel 全 PASS;build_ncm.sh 0 warning;ncm_host 离屏正常

md5 ncm f8f316a1e6f3bdd8f6b5921fdbb3f3a2
2026-09-01 20:00:14 +08:00

83 lines
4.5 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.
/* play/stream_src.h — 边下边播共享流源(REPORT §21,方案 NCM_STREAM_PLAY A:写穿缓存)。
*
* 模型:下载线程把字节顺序写进 .tmp(ncm_cache 写者 write(2) 直写,不走 stdio 缓冲),
* 解码线程经本对象 pread 同一文件——落盘的文件本身就是下载缓冲,内存里无第二份拷贝。
* 写端每写完一块调用 stream_src_note_written() 推进可读边界并 broadcast 唤醒读端;
* 下载结束(完成/中断)stream_src_finish() 置 final;切歌/停止 stream_src_abort()。
*
* 读回调契约(实测红线 F7):stream_src_read_cb 严格 fread 语义——填满才返回,
* 真 EOF(final/failed/abort 且数据耗尽)才短读;否则 minimp3 把短读当 EOF 假播完。
* dr_flac 回调语义不同(返回实际读到的字节数):本对象同样先尽力填满再返回,
* 两种契约同时满足。
*
* 本层只依赖 pthread/pread/write,不依赖 core(保持 app/play 层自含)。
*/
#ifndef NCM_STREAM_SRC_H
#define NCM_STREAM_SRC_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct stream_src stream_src_t;
/* seek 原点(与 drflac_seek_origin 同值,避免本头依赖 dr_flac.h)。 */
enum { STREAM_SRC_SEEK_SET = 0, STREAM_SRC_SEEK_CUR = 1, STREAM_SRC_SEEK_END = 2 };
/* 下载路径:tmp_path 已由 ncm_cache_open 创建(写端持有自己的写 fd);
* 本函数只开只读 fd(pread 与写端 write 无偏移冲突),written 从 0 起由写端推进。 */
int stream_src_open_stream(stream_src_t **out, const char *tmp_path);
/* 断点续传(阶段3,§5.2):path 已含既存前缀(.part),written 置为前缀字节数——
* 读端 read_pos=0 可立即读到已下前缀(秒开播),写端从 written 继续推进。 */
int stream_src_open_stream_at(stream_src_t **out, const char *path, uint64_t written);
/* 缓存命中路径:完整文件,written=final=size,read 永不阻塞(同一套读回调)。 */
int stream_src_open_static(stream_src_t **out, const char *path, uint64_t size);
void stream_src_close(stream_src_t *s);
/* ---- 写端(下载线程) ---- */
/* 数据已落盘(ncm_cache_write 成功)后调用:推进可读边界 + 唤醒读端。 */
void stream_src_note_written(stream_src_t *s, uint64_t n);
/* 下载结束:err==0=完成(final=written),否则中断(final=written + failed=err)。
* 之后 read_cb 数据耗尽即短读(真 EOF),解码自然结束于截断点(F5)。 */
void stream_src_finish(stream_src_t *s, int err);
/* 切歌/停止:唤醒所有等待,read 立即按 EOF 短读返回;下载回调应随后返回 NZ 中止 http。 */
void stream_src_abort(stream_src_t *s);
int stream_src_aborted(stream_src_t *s); /* 下载回调每块开头廉价检查 */
/* ---- 预缓冲 ---- */
/* 等 written >= need;final/failed/abort 提前返回。timeout_ms 为单次等待上限
* (调用方在循环里套切歌护栏)。返回 1=满足,0=超时,<0=已结束/失败/中止。 */
int stream_src_wait(stream_src_t *s, uint64_t need, int timeout_ms);
/* 同步 peek(pread,不动 read_pos):magic 探测用。off+n 超出 written 的部分不读,
* 返回实际读到字节数。 */
size_t stream_src_peek(stream_src_t *s, void *buf, size_t n, uint64_t off);
/* ---- minimp3 回调(MP3D_READ_CB / MP3D_SEEK_CB) ---- */
size_t stream_src_read_cb(void *buf, size_t size, void *ud);
int stream_src_seek_cb(uint64_t pos, void *ud);
/* ---- dr_flac 回调(drflac_read_proc / drflac_seek_proc / drflac_tell_proc) ---- */
size_t stream_src_drflac_read(void *ud, void *buf, size_t bytes_to_read);
int stream_src_drflac_seek(void *ud, int offset, int origin); /* origin=STREAM_SRC_SEEK_* */
int stream_src_drflac_tell(void *ud, int64_t *cursor);
/* ---- 统计 / 停滞联动 ---- */
/* underrun=read_cb 追上下载(无数据可给)的等待次数;wait_ms=累计等待 ms。 */
void stream_src_stats(stream_src_t *s, int *underruns, uint64_t *wait_ms);
/* 单次 read 等待 >1s 置位(播放线程下一轮对 audiod pause(1),恢复后 pause(0))。
* 取走即清零。 */
int stream_src_take_stalled(stream_src_t *s);
uint64_t stream_src_written(stream_src_t *s);
uint64_t stream_src_final(stream_src_t *s); /* 0=下载中;>0=最终大小(完成=全长,中断=截断点) */
int stream_src_failed(stream_src_t *s); /* 0=无错误;<0=下载/IO 错误码 */
#ifdef __cplusplus
}
#endif
#endif /* NCM_STREAM_SRC_H */