feat(media): 批3歌词数据源框架 — meow_media_session扩实时歌词(lrc/tlrc/seq)+MSG_META_LYRIC上报分片+ncm上报+launcher读meow_media_lyric_* 接批1/2;宿主L1-L7全过/ncm热更27554dd8,launcher待固件收编

This commit is contained in:
AskaEth committed 2026-09-03 19:49:28 +08:00
1 parent 7ca3e5bd84
commit 2e5b814059
8 files changed
+363 -4

No files matched your search

+44
View File
@@ -295,3 +295,47 @@ void ipc_media_stop(void)
/* 线程在 200ms poll 内退出(detach,不 join)*/
g_thr_on = 0;
}
/* ---- 批3:live 歌词上报(lrc 原文 + tlrc 翻译 → 媒体会话,桌面歌词页实时滚动源)---- */
/* 歌词代际(换歌/换词自增;launcher 见新 seq 清旧词)。IC 线程外调用(lyric_worker),
* 单线程写(worker 是唯一调用者),无需锁。 */
static uint32_t g_lyr_media_seq;
/* 把一个 kind 的歌词文本按分片发到媒体会话(≤MEOW_LYRIC_CHUNK 一帧)。cmax=该 kind 上限:
* 0=MEOW_MEDIA_LRC_MAX,1=MEOW_MEDIA_TLRC_MAX。total=0(空串)时发一个空帧=清词。 */
static void send_lyric_kind(int fd, uint32_t seq, uint16_t kind, const char *text, size_t cmax)
{
if (!text) text = "";
size_t total = strlen(text);
if (total > cmax) total = cmax; /* 接收侧缓冲上限:超限截断 */
size_t off = 0;
do {
size_t n = total - off;
if (n > MEOW_LYRIC_CHUNK) n = MEOW_LYRIC_CHUNK;
m_lyric_t ly;
memset(&ly, 0, sizeof ly);
ncm_strlcpy(ly.app_id, "dev.player.ncm", sizeof ly.app_id);
ly.seq = seq;
ly.kind = kind;
ly.total = (uint16_t)total;
ly.off = (uint16_t)off;
ly.len = (uint16_t)n;
if (n) memcpy(ly.data, text + off, n);
ly.data[n] = 0;
send_frame(fd, MSG_META_LYRIC, seq, &ly, sizeof ly);
off += n;
} while (off < total);
}
void ipc_media_lyric_report(const char *lrc, const char *tl)
{
g_lyr_media_seq++;
int fd = connect_path(sock_path());
if (fd < 0) { meow_log(MEOW_LOG_WARN, "ipc: lyric no launcher socket"); return; }
send_lyric_kind(fd, g_lyr_media_seq, 0, lrc, MEOW_MEDIA_LRC_MAX); /* 原文 */
send_lyric_kind(fd, g_lyr_media_seq, 1, tl, MEOW_MEDIA_TLRC_MAX); /* 翻译 */
close(fd);
meow_log(MEOW_LOG_INFO, "ipc: lyric reported seq=%u lrc=%zuB tlrc=%zuB",
g_lyr_media_seq, lrc ? strlen(lrc) : 0, tl ? strlen(tl) : 0);
}
+7 -1
View File
@@ -1045,8 +1045,14 @@ static void *lyric_worker(void *arg)
pthread_mutex_lock(&g_lyrmu); g_lyr_state = 0; pthread_mutex_unlock(&g_lyrmu);
continue;
}
lrc[0] = tl[0] = 0; /* 默认空串(fetch 失败/空词时上报清词,防会话留旧曲歌词) */
int rc = ncm_api_lyric(g_st.ctx.device_id, g_st.ctx.cookie, id, lrc, 64 * 1024, tl, 32 * 1024);
if (rc == NCM_OK) lyric_parse(lrc, tl);
if (rc == NCM_OK) {
lyric_parse(lrc, tl);
ipc_media_lyric_report(lrc, tl); /* 批3:上报 live 歌词到媒体会话 */
} else {
ipc_media_lyric_report("", ""); /* 无词/拉取失败:清 media session 该曲歌词 */
}
free(lrc); free(tl);
pthread_mutex_lock(&g_lyrmu);
+4
View File
@@ -58,6 +58,8 @@ size_t ncm_strlcpy(char *dst, const char *src, size_t sz)
}
void meow_log(meow_log_level lvl, const char *fmt, ...) { (void)lvl; (void)fmt; }
void meow_audio_on_preempt(meow_audio_preempt_fn cb, void *ctx) { (void)cb; (void)ctx; }
/* core/ncm_common.c 提供 ncm_now_ms(墙钟毫秒);本 sim 不链 ncm_common.o,提供同语义桩。 */
int64_t ncm_now_ms(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (int64_t)ts.tv_sec*1000 + ts.tv_nsec/1000000; }
/* ---- appstate stub:窗内全命中,id=1000+idx;fee 可注入(§20 P8) ---- */
static int g_fee = 0;
@@ -315,6 +317,8 @@ void audio_out_set_target(int ms) { (void)ms; }
/* ---- 歌词(未被调用的 worker 会被 gc-sections 丢弃;lyric_clear 由 worker 用,防御性提供) ---- */
void lyric_clear(void) { }
int lyric_parse(const char *a, const char *b) { (void)a; (void)b; return 0; }
/* 批3:player_manager 的 lyric_worker 会上报歌词到媒体会话;本 sim 不链 ipc_media.c,提供空桩。 */
void ipc_media_lyric_report(const char *lrc, const char *tl) { (void)lrc; (void)tl; }
static int g_fail;
#define CHECK(cond, fmt, ...) do { \