Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/test_media_lyric.c
T

186 lines
8.9 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.
/* test_media_lyric.c — 宿主单测:批3 live 歌词数据源框架(meow_media 会话携带 lrc/tlrc → meow_lyric 解析 → 随播放位置命中当前行)。
*
* 链路:App 上报歌词(分片 m_lyric → meow_media_lyric)→ 会话累积 lrc/tlrc(有界、seq 代际)
* → launcher 读取(meow_media_lyric_valid/lrc/tlrc)→ meow_lyric_parse → meow_lyric_line_at(meow_media_display_pos)。
*
* 覆盖矩阵:
* L1 App 上报 lrc/tlrc → 会话携带歌词(valid/lrc/tlrc 正确)
* L2 launcher 读取 → meow_lyric_parse 成功(count/行文本/翻译合并正确)
* L3 播放位置推进(display_pos 随 PLAYING 单调增)→ line_at 命中当前行(pos 增大 → 行号不降)
* L4 分片重组:>MEOW_LYRIC_CHUNK 的 lrc 拆多帧上报,会话按 off 累积成完整串
* L5 seq 代际切换(换歌)→ 清旧词;同 seq 重报(幂等)不破坏
* L6 会话不存在 → meow_media_lyric 返回 -1;翻译无匹配自动忽略
* L7 多 App 独立:另一源上报自己的歌词,互不串
*
* 编译(宿主):meow_media.c(纯 libc)+ meow_lyric.c(纯 libc+pthread)。
* gcc -Wall -Wextra -pthread -o test_media_lyric test_media_lyric.c meow_media.c ../sdk/meow_lyric.c -I. -I../sdk
* ./test_media_lyric
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/socket.h>
#include "meow_media.h"
#include "meow_ipc.h"
#include "meow_lyric.h"
static int g_fails = 0;
#define CHECK(cond, msg) do { \
if (cond) printf("PASS: %s\n", msg); \
else { printf("FAIL: %s (%s:%d)\n", msg, __FILE__, __LINE__); g_fails++; } } while (0)
static size_t test_send(int fd, uint16_t type, uint32_t req_id,
const void *payload, uint32_t len)
{
/* 用不到(本链路无下行),占位满足 meow_media_ops.send 签名。 */
(void)fd; (void)type; (void)req_id; (void)payload; (void)len;
return 0;
}
static void fill_meta(m_meta_t *m, const char *app, uint32_t state, uint32_t pos, uint32_t dur)
{
memset(m, 0, sizeof *m);
snprintf(m->app_id, sizeof m->app_id, "%s", app);
m->state = state; m->pos_ms = pos; m->dur_ms = dur;
snprintf(m->title, sizeof m->title, "Song");
snprintf(m->artist, sizeof m->artist, "Artist");
}
/* 模拟 ncm 的 send_lyric_kind:把 text 按 ≤MEOW_LYRIC_CHUNK 分片,逐片调 meow_media_lyric。 */
static void report_lyric_chunked(const char *app, 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);
snprintf(ly.app_id, sizeof ly.app_id, "%s", app);
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;
int rc = meow_media_lyric(&ly);
if (rc != 0) { printf(" (report chunk off=%zu rc=%d)\n", off, rc); }
off += n;
} while (off < total);
}
int main(void)
{
meow_media_ops ops;
ops.send = test_send;
ops.log = NULL;
meow_media_init(&ops);
const char *lrc = "[00:01.00]Hello\n[00:02.00]World\n[00:03.00]Bye\n";
const char *tlrc = "[00:01.00]你好\n[00:03.00]再见\n[99:99.99]ignore me\n";
/* ---- L1+L4 大片(跨分片)---- */
char big[4096];
int bi = 0;
bi += snprintf(big + bi, sizeof big - bi, "[00:00.10]p0\n");
for (int i = 1; i <= 40; i++) /* 约 40 行 → >MEOW_LYRIC_CHUNK(980B) */
bi += snprintf(big + bi, sizeof big - bi, "[00:%02d.%02d]line%d\n", i / 60, i % 60, i);
/* 注册会话(META 先行,否则 meow_media_lyric 丢弃) */
m_meta_t m;
fill_meta(&m, "dev.player.ncm", MEOW_MEDIA_PLAYING, 1000, 120000);
CHECK(meow_media_meta(&m, -1) == 0, "META registers session");
/* 上报歌词:seq=1(新代际),lrc 与 tlrc 各分片 */
report_lyric_chunked("dev.player.ncm", 1, 0, lrc, MEOW_MEDIA_LRC_MAX);
report_lyric_chunked("dev.player.ncm", 1, 1, tlrc, MEOW_MEDIA_TLRC_MAX);
const meow_media_session_t *s = meow_media_current();
CHECK(s && !strcmp(s->app_id, "dev.player.ncm"), "current() == dev.player.ncm");
CHECK(meow_media_lyric_valid(s) == 1, "L1: lyric_valid == 1");
CHECK(strcmp(meow_media_lyric_lrc(s), lrc) == 0, "L1: lrc matches");
CHECK(strcmp(meow_media_lyric_tlrc(s), tlrc) == 0, "L1: tlrc matches");
/* ---- L2 launcher 读取 → 解析 ---- */
int n = meow_lyric_parse(meow_media_lyric_lrc(s), meow_media_lyric_tlrc(s));
CHECK(n == 3, "L2: meow_lyric_parse count == 3");
CHECK(meow_lyric_count() == 3, "L2: count() == 3");
CHECK(strcmp(meow_lyric_line_text(0), "Hello") == 0, "L2: line0 text Hello");
CHECK(strcmp(meow_lyric_line_tl(0), "你好") == 0, "L2: line0 tl 你好 (2000ms 合并)");
CHECK(strcmp(meow_lyric_line_text(2), "Bye") == 0, "L2: line2 text Bye");
CHECK(strcmp(meow_lyric_line_tl(2), "再见") == 0, "L2: line2 tl 再见");
CHECK(meow_lyric_count() == 3, "L2: 无匹配翻译行被忽略(仍 3 行)");
/* ---- L3 播放位置推进 → 命中当前行 ---- */
uint32_t pA = meow_media_display_pos(s);
int lineA = meow_lyric_line_at(pA);
CHECK(lineA == 0, "L3: display_pos ≈ 1000ms → line 0 (Hello)");
usleep(600 * 1000); /* 播放中:display_pos 随墙钟推进 */
uint32_t pB = meow_media_display_pos(s);
int lineB = meow_lyric_line_at(pB);
CHECK(pB >= pA, "L3: display_pos advances (playing)");
CHECK(lineB >= lineA, "L3: line_at pos 增大 → 行号不降(随播放命中当前行)");
/* 再推进到 ≥3000ms 应到末行 */
usleep(1500 * 1000);
uint32_t pC = meow_media_display_pos(s);
CHECK(pC >= 3000u || lineB >= 2, "L3: pos 推进后到位(或已末行)");
CHECK(meow_lyric_line_at(pC) >= meow_lyric_line_at(pB), "L3: 行号单调不降");
/* ---- L4 大片分片重组(big lrc)---- */
meow_media_clear(NULL);
fill_meta(&m, "dev.player.ncm", MEOW_MEDIA_PLAYING, 0, 120000);
meow_media_meta(&m, -1);
report_lyric_chunked("dev.player.ncm", 2, 0, big, MEOW_MEDIA_LRC_MAX);
s = meow_media_current();
CHECK(s && meow_media_lyric_valid(s) == 1, "L4: big lyric_valid == 1");
int bn = meow_lyric_parse(meow_media_lyric_lrc(s), NULL);
CHECK(bn > 40, "L4: 大片跨分片重组后解析行数 > 40");
CHECK(meow_lyric_line_at(0) == 0 && meow_lyric_line_at(10) == 0, "L4: 低 pos 命中第0行");
CHECK(meow_lyric_line_at(meow_lyric_line_time(bn - 1)) == bn - 1, "L4: 末行命中");
/* ---- L5 seq 代际切换(换歌)清旧词 ---- */
report_lyric_chunked("dev.player.ncm", 3, 0, "[00:05.00]New song line\n", MEOW_MEDIA_LRC_MAX);
s = meow_media_current();
CHECK(meow_media_lyric_valid(s) == 1, "L5: 新代际仍 valid");
CHECK(strcmp(meow_media_lyric_lrc(s), "[00:05.00]New song line\n") == 0, "L5: 新词覆盖旧词");
CHECK(meow_media_lyric_tlrc(s)[0] == 0, "L5: 新代际清空旧翻译");
/* seq 不变重报:幂等(不清) */
report_lyric_chunked("dev.player.ncm", 3, 1, "[00:05.00]新歌\n", MEOW_MEDIA_TLRC_MAX);
s = meow_media_current();
CHECK(strcmp(meow_media_lyric_tlrc(s), "[00:05.00]新歌\n") == 0, "L5: 同 seq 补翻译不清");
/* ---- L6 会话不存在 → -1;空 app_id → -1 ---- */
m_lyric_t empty;
memset(&empty, 0, sizeof empty);
snprintf(empty.app_id, sizeof empty.app_id, "no.session.app");
empty.seq = 9; empty.kind = 0; empty.total = 0; empty.off = 0; empty.len = 0;
CHECK(meow_media_lyric(&empty) == -1, "L6: 未注册会话 → -1");
memset(&empty, 0, sizeof empty);
CHECK(meow_media_lyric(&empty) == -1, "L6: 空 app_id → -1");
/* ---- L7 多 App 独立 ---- */
fill_meta(&m, "com.player2", MEOW_MEDIA_PLAYING, 0, 180000);
meow_media_meta(&m, -1);
meow_media_clear("dev.player.ncm"); /* 只清 ncm */
report_lyric_chunked("com.player2", 1, 0, "[00:01.00]Second app\n", MEOW_MEDIA_LRC_MAX);
s = meow_media_current();
CHECK(s && !strcmp(s->app_id, "com.player2"), "L7: current == com.player2");
CHECK(meow_media_lyric_valid(s) == 1, "L7: player2 歌词有效");
CHECK(strcmp(meow_media_lyric_lrc(s), "[00:01.00]Second app\n") == 0, "L7: player2 歌词独立");
/* ---- 空歌词(无词歌曲):上报空串 → valid=0 ---- */
report_lyric_chunked("com.player2", 2, 0, "", MEOW_MEDIA_LRC_MAX);
report_lyric_chunked("com.player2", 2, 1, "", MEOW_MEDIA_TLRC_MAX);
s = meow_media_current();
CHECK(meow_media_lyric_valid(s) == 0, "空词上报 → lyric_valid == 0");
printf("\n%s (%d fails)\n", g_fails ? "FAILED" : "ALL PASS", g_fails);
return g_fails ? 1 : 0;
}