Files

122 lines
6.4 KiB
C
Raw Permalink 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.
/* meow_media.h — MeowOS 媒体会话(阶段 D · 附录 B / D1)。
*
* 定位:媒体会话注册表(App 声明 MF_PLAYBACK + 上报 MSG_META → 成为媒体源;
* 最近活跃者=当前源)。通知中心媒体卡片 / Now Playing 页 / 物理媒体键 / 控制器统一消费;
* PLAYCTL 经会话的连接 fd 直接下发。语义对齐 FRAMEWORK_DESIGN 附录 B 的「启动器表现」与
* 附录 D1(MPRIS 最近活跃源选择)。
*
* 设计:
* - 会话=一个 App 一个槽(app_id 归并;单 App 恒 1 槽,防多发 META 占满)。
* - 当前源=last_active_ms 最大者(最近上报 META)。多源时此即「最近活跃」。
* - 判定源死亡:播放中(1)/缓冲(3) 超 MEOW_MEDIA_STALE_MS 无 META → 清槽回空态(App 死/
* 服务断);暂停(2)/停止(0) 不超时(暂停属合法驻留,停止由 state 判空态)。
* - 空态:无会话,或当前源 state==0(停止)。
*
* 自包含:不依赖 launcher static 符号;发送/日志经 meow_media_ops 注入(launcher 用
* ipc_send / logmsg;宿主单测用 socket write / NULL)。可独立单测(test_media.c)。
*/
#ifndef MEOW_MEDIA_H
#define MEOW_MEDIA_H
#include <stdint.h>
#include <stddef.h>
#include "meow_ipc.h"
/* 同时维护的媒体会话上限(防御;一个 App 一槽) */
#define MEOW_MEDIA_MAX 4
/* 播放中(1)/缓冲(3) 无 META 超此毫秒 → 判源死清槽(回空态);暂停/停止不超时 */
#define MEOW_MEDIA_STALE_MS 30000u
/* state 取值(与 m_meta_t.state 一致) */
#define MEOW_MEDIA_STOPPED 0u
#define MEOW_MEDIA_PLAYING 1u
#define MEOW_MEDIA_PAUSED 2u
#define MEOW_MEDIA_BUFFER 3u
/* 媒体会话(一个 App 一个槽)。fd=最近上报 META 的连接 fd(下发 PLAYCTL 用)。 */
typedef struct meow_media_session {
int used;
int fd;
char app_id[MEOW_APP_ID_MAX];
uint64_t last_active_ms; /* 最近 META 时刻(monotonic ms,进度推进用) */
uint64_t active_seq; /* 最近活跃净序(全局递增,供「最近活跃」严格排序) */
uint32_t state;
uint32_t pos_ms;
uint32_t dur_ms;
uint32_t flags;
char title[128];
char artist[128];
char album[128];
char artwork[192];
char lyric[192]; /* 歌词源路径/槽位(沿用 META.lyric) */
/* 批3:当前曲 live 歌词(App 经 MSG_META_LYRIC 上报;有界缓冲,新 seq 重置)。
* lyric_lrc/lyric_tlrc 为当前曲歌词原文/翻译文本(桌面歌词页 meow_lyric_parse 用);
* lyric_seq=歌曲代际(App 新歌/新词自增,launcher 见新 seq 清旧词)。 */
uint32_t lyric_seq;
uint32_t lyric_lrc_len;
uint32_t lyric_tlrc_len;
char lyric_lrc[MEOW_MEDIA_LRC_MAX];
char lyric_tlrc[MEOW_MEDIA_TLRC_MAX];
} meow_media_session_t;
/* 依赖注入:send=发一帧(launcher 用 ipc_send 包装;宿主单测用 socket 写);
* log=日志(launcher 用 logmsg;NULL=静默)。send 返回写入字节。 */
typedef struct meow_media_ops {
size_t (*send)(int fd, uint16_t type, uint32_t req_id,
const void *payload, uint32_t len);
void (*log)(const char *fmt, ...);
} meow_media_ops;
/* 注入 ops(send/log);NULL 清空。launcher 启动时(meow_ipc_init)调用一次。 */
void meow_media_init(const meow_media_ops *ops);
/* App 上报 META:按 m->app_id 归并到会话(无则建槽);记录 fd/last_active;
* 截断安全(不越界)。返回 0=成功,-1=会话满/参数非法。 */
int meow_media_meta(const m_meta_t *m, int fd);
/* 当前源 = 最近活跃会话(last_active_ms 最大)。无会话返回 NULL。 */
const meow_media_session_t *meow_media_current(void);
/* 是否有活动媒体源:当前源存在且 state != 0(停止)。通知中心卡片/播放页据此显示。 */
int meow_media_has_source(void);
/* §10.5 叠加会话保活判定:当前源(最近活跃会话)存在、state==PLAYING 且 app_id 匹配。
* launcher 据此决定通知中心叠加不 SIGSTOP 该 App(保 PCM 供流),SDK present 层自抑上屏。 */
int meow_media_app_playing(const char *app_id);
/* 批①后台常驻判定:该 app 的媒体会话「活跃可驻留」= 会话存在且 state != STOPPED
* (PLAYING/PAUSED/BUFFER 皆常驻)。按 app 自身会话判(sess_find),不读最近活跃源——
* 多源时不误判「当前源≠本 App」。launcher 转后台保活依据。 */
int meow_media_app_resident(const char *app_id);
/* 向当前源下发 PLAYCTL(卡片按钮/播放页/媒体键/控制器)。返回 0=已发,-1=无源/发送失败。 */
int meow_media_playctl(uint32_t cmd, int64_t seek_ms);
/* 向指定 app 的会话下发 PLAYCTL;无匹配会话返回 -1。 */
int meow_media_playctl_to(const char *app_id, uint32_t cmd, int64_t seek_ms);
/* 清某 app 的会话(App 退出/源死亡/主动停止时调)。app_id 空/NULL=清全部。 */
void meow_media_clear(const char *app_id);
/* 主循环周期调(~1s):播放中(1)/缓冲(3) 超时无 META → 清槽。 */
void meow_media_tick(void);
/* 显示用虚拟位置:播放中按墙钟推进 pos_ms(clamp 到 dur);暂停/缓冲/停止原样。 */
uint32_t meow_media_display_pos(const meow_media_session_t *s);
/* ---- 歌词(批3 · live lyric 数据源)----
* App 上报当前曲歌词(MSG_META_LYRIC 分片):按 app_id 归并到会话,seq 为歌曲代际、
* 新代际清旧词;分片按 kind(0=原文/1=翻译)/off 写入会话内有序缓冲(超 MEOW_MEDIA_LRC_MAX/
* MEOW_MEDIA_TLRC_MAX 截断)。会话不存在(未先报 META 注册)→ 丢弃返回 -1(防 fd=0 槽)。
* meow_media_lyric_valid/lrc/tlrc:桌面歌词页从当前会话取歌词文本,交由批1 meow_lyric_parse
* 解析 + meow_lyric_line_at(meow_media_display_pos(s)) 驱动批2 meow_lyric_view 实时滚动。 */
int meow_media_lyric(const m_lyric_t *l); /* 0=已写入;-1=会话不存在/参数非法 */
int meow_media_lyric_valid(const meow_media_session_t *s); /* 会话携带有效歌词(lrc 非空) */
const char *meow_media_lyric_lrc(const meow_media_session_t *s); /* 原文;无则 "" */
const char *meow_media_lyric_tlrc(const meow_media_session_t *s); /* 翻译;无则 "" */
/* 调试打印(经 ops->log,前缀+每会话一行)。 */
void meow_media_dump(const char *prefix);
#endif /* MEOW_MEDIA_H */