80 lines
4.2 KiB
C
80 lines
4.2 KiB
C
/* 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);
|
||
/* 缓存命中路径:完整文件,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 */
|