fix(lyric/bt): ①桌面歌词页封面不显示修复(根因:歌词页从不画封面+scrim逐秒叠涂压黑→新增np_draw_lyric_coverbg封面背景+1s整页重绘;播放页封面宿实证非批5破坏) ②alsa.conf pcm.bluealsa DEV自动识别(bt_dev.c:audiod BT打开时bluealsa-cli检测a2dpsrc设备幂等改写DEV=保留codec/ldac_eqmid等);test_bt_dev 14/14,0warning
This commit is contained in:
1 parent
ef6eca86b1
commit
8c165bb8e6
6 files changed
+359
-13
No files matched your search
@@ -0,0 +1,138 @@
|
||||
/* bt_dev.c — 蓝牙 A2DP 设备自识别(纯逻辑实现,见 bt_dev.h 契约)。
|
||||
*
|
||||
* 纯 libc(string / stdlib),无任何 meow_* 调用、无 popen、无文件 I/O —— meow_audiod 负责
|
||||
* 读取 /usr/data/alsa.conf、执行 `bluealsa-cli list-pcms` 及写回。宿主单测零链路重。
|
||||
*/
|
||||
#include "bt_dev.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* 解析 bluealsa-cli list-pcms 输出,取第一个 a2dpsrc/a2dp_source 端点的设备 MAC。
|
||||
* 端点形如 `a2dpsrc/AA:BB:CC:DD:EE:FF`(MAC 在端点 token 内最后一个 '/' 之后到空白前)。
|
||||
* 逐个**有界行**匹配(strstr 必须在行内,避免跨换行误把后一行当本行端点——如行 1
|
||||
* "profile/aptx" 与行 3 "a2dp_source/..." 的经典误判)。 */
|
||||
int bt_dev_detect_mac(const char *listpcms, char *mac, size_t macsz)
|
||||
{
|
||||
if (!listpcms || !mac || macsz < 2) return -1;
|
||||
mac[0] = 0;
|
||||
const char *ln = listpcms;
|
||||
while (ln && *ln) {
|
||||
const char *nl = strchr(ln, '\n');
|
||||
const char *le = nl ? nl : (ln + strlen(ln));
|
||||
size_t linelen = (size_t)(le - ln);
|
||||
char line[256];
|
||||
if (linelen >= sizeof line) linelen = sizeof line - 1;
|
||||
memcpy(line, ln, linelen); line[linelen] = 0;
|
||||
const char *p = line;
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
const char *hit = strstr(p, "a2dpsrc");
|
||||
if (!hit) hit = strstr(p, "a2dp_source");
|
||||
if (hit) {
|
||||
const char *te = hit;
|
||||
while (*te && *te != ' ' && *te != '\t' && *te != '\n') te++;
|
||||
const char *slash = NULL;
|
||||
for (const char *q = hit; q < te; q++) if (*q == '/') slash = q;
|
||||
if (slash && (slash + 1) < te) {
|
||||
const char *start = slash + 1;
|
||||
size_t len = (size_t)(te - start);
|
||||
if (len > 0 && len < macsz) {
|
||||
memcpy(mac, start, len);
|
||||
mac[len] = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!nl) break;
|
||||
ln = nl + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 在单行内把 anchor("DEV=" / "device")后的 MAC 值替换为 mac,保留引号风格。
|
||||
* 行未含 anchor → 返回 1(out=原样);含 anchor → 写回新行并返回 0。 */
|
||||
static int line_replace_mac(char *out, size_t outsz, const char *line,
|
||||
const char *anchor, const char *mac)
|
||||
{
|
||||
const char *at = strstr(line, anchor);
|
||||
if (!at) { snprintf(out, outsz, "%s", line); return 1; }
|
||||
const char *vp = at + strlen(anchor);
|
||||
while (*vp == ' ' || *vp == '\t') vp++;
|
||||
if (*vp == '"') vp++; /* 引号风格:值可带双引号 */
|
||||
const char *ve = vp;
|
||||
while (*ve && *ve != ' ' && *ve != '\t' && *ve != '\n' &&
|
||||
*ve != '"' && *ve != '{' && *ve != '}') ve++;
|
||||
size_t prefix = (size_t)(vp - line); /* 前段(含开引号,若带) */
|
||||
size_t tail = (size_t)(ve - line); /* 值终点(不含闭引号,若带) */
|
||||
/* 前段 + mac + 尾段(尾段保留闭引号与其后内容) */
|
||||
snprintf(out, outsz, "%.*s%s%s", (int)prefix, line, mac, line + tail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 幂等改写 alsa.conf:只把 `pcm.bluealsa` 块内 `DEV=` 与 `device` 后的 MAC 换成 mac。
|
||||
* 逐行处理;无 pcm.bluealsa / 无 DEV= / device token → -1;两端已一致 → 1;改了 → 0。 */
|
||||
int bt_dev_rewrite(const char *in, size_t in_len, const char *mac,
|
||||
char **out, size_t *out_len)
|
||||
{
|
||||
if (!in || !mac || !mac[0] || !out || !out_len || in_len == 0) return -1;
|
||||
if (!strstr(in, "pcm.bluealsa") ||
|
||||
(!strstr(in, "DEV=") && !strstr(in, "device"))) return -1;
|
||||
|
||||
size_t cap = in_len + 128;
|
||||
char *res = malloc(cap ? cap : 1);
|
||||
if (!res) return -1;
|
||||
size_t o = 0, changed = 0;
|
||||
const char *p = in, *end = in + in_len;
|
||||
|
||||
while (p < end) {
|
||||
const char *nl = memchr(p, '\n', (size_t)(end - p));
|
||||
const char *le = nl ? nl : end;
|
||||
size_t linelen = (size_t)(le - p);
|
||||
char line[512], newline[512];
|
||||
if (linelen >= sizeof line) linelen = sizeof line - 1;
|
||||
memcpy(line, p, linelen); line[linelen] = 0;
|
||||
|
||||
const char *k = line;
|
||||
while (*k == ' ' || *k == '\t') k++;
|
||||
int anchored = 0;
|
||||
if (strstr(k, "DEV=")) {
|
||||
line_replace_mac(newline, sizeof newline, line, "DEV=", mac);
|
||||
anchored = 1;
|
||||
} else if (strncmp(k, "device", 6) == 0 &&
|
||||
(k[6] == ' ' || k[6] == '\t' || k[6] == 0)) {
|
||||
line_replace_mac(newline, sizeof newline, line, "device", mac);
|
||||
anchored = 1;
|
||||
}
|
||||
if (anchored) {
|
||||
if (strcmp(line, newline) != 0) changed = 1;
|
||||
size_t n = strlen(newline);
|
||||
if (o + n + 2 > cap) {
|
||||
cap = o + n + 256;
|
||||
char *t = realloc(res, cap);
|
||||
if (!t) { free(res); return -1; }
|
||||
res = t;
|
||||
}
|
||||
memcpy(res + o, newline, n); o += n;
|
||||
if (nl) res[o++] = '\n';
|
||||
} else {
|
||||
size_t n = linelen;
|
||||
if (o + n + 2 > cap) {
|
||||
cap = o + n + 256;
|
||||
char *t = realloc(res, cap);
|
||||
if (!t) { free(res); return -1; }
|
||||
res = t;
|
||||
}
|
||||
memcpy(res + o, p, n); o += n;
|
||||
if (nl) res[o++] = '\n';
|
||||
}
|
||||
if (!nl) break;
|
||||
p = nl + 1;
|
||||
}
|
||||
|
||||
if (!changed) { free(res); return 1; }
|
||||
res[o] = 0;
|
||||
*out = res;
|
||||
*out_len = o;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/* bt_dev.h — 蓝牙 A2DP 设备自识别(DEV 自动更新纯逻辑,宿主可单测)。
|
||||
*
|
||||
* 背景:/usr/data/alsa.conf 的 `pcm.bluealsa`(plug→bluealsa)需把 DEV/device 钉在当前
|
||||
* 连接的 A2DP sink 设备 MAC 上才能正确出声。本模块提供两段纯逻辑(无 meow_* / popen / 文件
|
||||
* I/O —— meow_audiod 负责读文件与执行系统命令):
|
||||
* - bt_dev_detect_mac:从 `bluealsa-cli list-pcms` 输出提取第一个 a2dpsrc 端点的设备 MAC;
|
||||
* - bt_dev_rewrite:幂等改写 alsa.conf 文本,把 `pcm.bluealsa` 块内 `DEV=<mac>` 与
|
||||
* `device <mac>` 两处换成目标 MAC(保留引号风格 / codec / 其余 token)。
|
||||
* 纯 libc(string / stdlib),独立编译,宿主零链接重。
|
||||
*/
|
||||
#ifndef BT_DEV_H
|
||||
#define BT_DEV_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* 解析 bluealsa-cli list-pcms 输出,取第一个 a2dpsrc/a2dp_source 端点的设备 MAC。
|
||||
* 返回 0=找到并写入 mac(NUL 结尾),-1=无 a2dpsrc 端点 / 参数非法。macsz 建议 ≥18。 */
|
||||
int bt_dev_detect_mac(const char *listpcms, char *mac, size_t macsz);
|
||||
|
||||
/* 幂等改写 alsa.conf 文本(in_len 不含 NUL):把 `pcm.bluealsa` 块内 `DEV=<mac>` 与
|
||||
* `device <mac>` 两处 MAC 换成 mac(保留引号风格、codec/其它 token 原样)。
|
||||
* 返回 0=已改动(*out 与 *out_len 给出新文本,调用方负责 free);1=无需改动(两端已一致);
|
||||
* -1=无 pcm.bluealsa / 无 DEV= 或 device token / 参数非法(不动)。 */
|
||||
int bt_dev_rewrite(const char *in, size_t in_len, const char *mac,
|
||||
char **out, size_t *out_len);
|
||||
|
||||
#endif /* BT_DEV_H */
|
||||
@@ -28,12 +28,15 @@ if [ "$1" = "host" ]; then
|
||||
HOST_CC="${CC_HOST:-cc}"
|
||||
# BT 目标直链宿主 libasound.so.2(无 asoundlib.h,原型内联于 meow_audiod.c;-l: 精确到版本,
|
||||
# 不依赖 unversioned dev 链接)。删 -ldl:BT 不再用 dlopen。
|
||||
"$HOST_CC" $INC -Os -Wall -Wextra meow_audiod.c -o meow_audiod_host -lpthread -l:libasound.so.2
|
||||
"$HOST_CC" $INC -Os -Wall -Wextra meow_audiod.c bt_dev.c -o meow_audiod_host -lpthread -l:libasound.so.2
|
||||
"$HOST_CC" $INC -Os -Wall -Wextra meow_audio.c -o meow_audio_host -lm
|
||||
"$HOST_CC" $INC -Os -Wall -Wextra test_audiod_host.c -o test_audiod_host -lm
|
||||
"$HOST_CC" -Os -Wall -Wextra test_bt_dev.c bt_dev.c -o test_bt_dev -lm
|
||||
echo "== host builds =="
|
||||
ls -la meow_audiod_host meow_audio_host test_audiod_host
|
||||
file meow_audiod_host meow_audio_host test_audiod_host
|
||||
ls -la meow_audiod_host meow_audio_host test_audiod_host test_bt_dev
|
||||
file meow_audiod_host meow_audio_host test_audiod_host test_bt_dev
|
||||
echo "== host regression (test_bt_dev: BT DEV auto-detect) =="
|
||||
./test_bt_dev || { echo "!! test_bt_dev FAILED"; exit 1; }
|
||||
echo "== host regression (test_audiod_host) =="
|
||||
./test_audiod_host || { echo "!! host regression FAILED"; exit 1; }
|
||||
exit 0
|
||||
@@ -56,7 +59,7 @@ mkdir -p "$LIBBT"
|
||||
if [ ! -f "$LIBBT/libasound.so.2.0.0" ]; then cp "$ASOUND_SRC" "$LIBBT/libasound.so.2.0.0"; fi
|
||||
ln -sf libasound.so.2.0.0 "$LIBBT/libasound.so"
|
||||
ln -sf libasound.so.2.0.0 "$LIBBT/libasound.so.2"
|
||||
"$ZIG" cc --target=mipsel-linux-gnueabihf.2.22 $INC -Os -Wall -Wextra meow_audiod.c -o meow_audiod \
|
||||
"$ZIG" cc --target=mipsel-linux-gnueabihf.2.22 $INC -Os -Wall -Wextra meow_audiod.c bt_dev.c -o meow_audiod \
|
||||
-lpthread -Llibbt -lasound
|
||||
echo "== meow_audiod (mipsel glibc-dynamic, BT links libasound.so.2) =="
|
||||
ls -la meow_audiod
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include "meow_ipc.h"
|
||||
#include "bt_dev.h" /* P2:DEV 自识别(a2dpsrc 端点 → MAC → alsa.conf 幂等改写) */
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sound/asound.h>
|
||||
@@ -910,6 +911,50 @@ static void bt_apply_codec_conf(void)
|
||||
free(out);
|
||||
}
|
||||
|
||||
/* P2 BT DEV 自识别:把 /usr/data/alsa.conf 的 `pcm.bluealsa` DEV/device 自动改为**当前连接的
|
||||
* A2DP sink 设备** MAC(bluealsa-cli list-pcms 的 a2dpsrc 端点)。幂等(设备未变不重写)、
|
||||
* 无设备/失败跳过;只改 DEV/device 两处、保留 codec/其余 token。BT 打开前调用,实现
|
||||
* 「连哪个设备就播哪个」。跟 bt_apply_codec_conf 同构(外科式 token 替换,绝不建结构)。 */
|
||||
static void bt_apply_device_conf(void)
|
||||
{
|
||||
char mac[32] = "";
|
||||
char *o = popen_read_tmo(1500, "bluealsa-cli list-pcms 2>/dev/null");
|
||||
if (!o) { logmsg("bt: dev conf skipped (no bluealsa-cli)"); return; }
|
||||
if (bt_dev_detect_mac(o, mac, sizeof mac) != 0) {
|
||||
logmsg("bt: dev conf skipped (no a2dpsrc pcm)");
|
||||
return;
|
||||
}
|
||||
logmsg("bt: current a2dp dev %s", mac);
|
||||
const char *path = "/usr/data/alsa.conf";
|
||||
FILE *f = fopen(path, "r");
|
||||
if (!f) return;
|
||||
fseek(f, 0, SEEK_END); long sz = ftell(f);
|
||||
if (sz <= 0 || sz > 64 * 1024) { fclose(f); return; }
|
||||
fseek(f, 0, SEEK_SET);
|
||||
char *data = malloc((size_t)sz + 1);
|
||||
if (!data) { fclose(f); return; }
|
||||
size_t rl = fread(data, 1, (size_t)sz, f); data[rl] = 0;
|
||||
fclose(f);
|
||||
char *outdata = NULL; size_t outlen = 0;
|
||||
int rc = bt_dev_rewrite(data, rl, mac, &outdata, &outlen);
|
||||
free(data);
|
||||
if (rc == 0) {
|
||||
int fd = open(path, O_WRONLY | O_TRUNC, 0644);
|
||||
if (fd >= 0) {
|
||||
if (write(fd, outdata, outlen) < 0) { }
|
||||
close(fd);
|
||||
logmsg("bt: dev conf auto-updated %s -> %s", path, mac);
|
||||
} else {
|
||||
logmsg("bt: dev conf %s not writable, skip", path);
|
||||
}
|
||||
} else if (rc == 1) {
|
||||
logmsg("bt: dev conf ok (already %s)", mac);
|
||||
} else {
|
||||
logmsg("bt: dev conf skip (no pcm.bluealsa/no DEV token)");
|
||||
}
|
||||
if (outdata) free(outdata);
|
||||
}
|
||||
|
||||
/* BT 打开:libasound → snd_pcm_open(pcm.bluealsa/bluealsa, PLAYBACK, NONBLOCK) →
|
||||
* set_params(S16_LE, RW, ch, rate, soft_resample, 100ms)。返回 0=ok。失败置 g_bt_open=0。 */
|
||||
static int bt_open(void)
|
||||
@@ -1177,6 +1222,7 @@ static int dev_open(void)
|
||||
* 宿主即 FILE/NULL sink 时不走此支——因此宿主可测「目标选择/音量隔离/格式归一」逻辑,
|
||||
* 真实 bluealsa 传输留给真机(见 bt_* 注释)。失败 → 降级丢帧(自感知兜底 §五)。 */
|
||||
if (g_target == AUDIO_OUT_BT && g_sink == SINK_ALSA) {
|
||||
bt_apply_device_conf(); /* P2:DEV 幂等自更新到当前连接 A2DP 设备(连哪台播哪台) */
|
||||
bt_apply_codec_conf();
|
||||
if (bt_open() == 0) return 0; /* g_bt_open=1;返回 0=逻辑已开(真实句柄在 g_bt_hdl) */
|
||||
logmsg("bt: open failed (degrade: drop PCM until next OPEN)");
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/* test_bt_dev.c — 蓝牙 DEV 自识别宿主验证(纯逻辑,bt_dev.c)。
|
||||
*
|
||||
* 覆盖矩阵(对齐任务B 宿主测试要求):
|
||||
* D1 bt_dev_detect_mac:a2dpsrc/<MAC> 端点 → 提取 MAC(含 a2dp_source、多空行、多设备取第一个、
|
||||
* 无 a2dpsrc / 空输出 / NULL → -1)。
|
||||
* D2 bt_dev_rewrite:真实 alsa.conf 文本 → DEV=、device 两处 MAC 换成目标,保留 codec/其余 token;
|
||||
* 同值 → 1(无需改动);无 pcm.bluealsa / 无 DEV= → -1;带引号风格保留。
|
||||
*
|
||||
* 编译(在 patch_v2/meow_audiod 下):
|
||||
* cc -Wall -Wextra -o test_bt_dev test_bt_dev.c bt_dev.c
|
||||
* 运行:./test_bt_dev
|
||||
*/
|
||||
#include "bt_dev.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static int g_pass = 0, g_fail = 0;
|
||||
static void check(int cond, const char *name)
|
||||
{
|
||||
if (cond) { printf(" PASS %s\n", name); g_pass++; }
|
||||
else { printf(" FAIL %s\n", name); g_fail++; }
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
/* ---- D1 设备列表 → 选中 a2dpsrc 连接设备 ---- */
|
||||
{
|
||||
char mac[32] = "";
|
||||
int rc = bt_dev_detect_mac(
|
||||
"a2dpsrc/E0:42:6D:79:C5:98\na2dpsnk/E0:42:6D:79:C5:98\n", mac, sizeof mac);
|
||||
check(rc == 0 && strcmp(mac, "E0:42:6D:79:C5:98") == 0, "D1a a2dpsrc/<MAC> -> extract MAC");
|
||||
}
|
||||
{
|
||||
char mac[32] = "";
|
||||
int rc = bt_dev_detect_mac(
|
||||
"profile/aptx\n\na2dp_source/33:DE:2E:21:AD:30\n", mac, sizeof mac);
|
||||
check(rc == 0 && strcmp(mac, "33:DE:2E:21:AD:30") == 0, "D1b a2dp_source/<MAC> -> extract MAC");
|
||||
}
|
||||
{
|
||||
char mac[32] = "";
|
||||
int rc = bt_dev_detect_mac(
|
||||
"a2dpsrc/AA:BB:CC:DD:EE:FF 0\na2dpsrc/11:22:33:44:55:66 1\n", mac, sizeof mac);
|
||||
check(rc == 0 && strcmp(mac, "AA:BB:CC:DD:EE:FF") == 0, "D1c multi-device -> first a2dpsrc");
|
||||
}
|
||||
{
|
||||
char mac[32] = "";
|
||||
int rc = bt_dev_detect_mac("\n", mac, sizeof mac);
|
||||
check(rc == -1, "D1d empty output -> -1");
|
||||
}
|
||||
{
|
||||
char mac[32] = "";
|
||||
int rc = bt_dev_detect_mac("a2dpsnk/11:22:33:44:55:66\n", mac, sizeof mac);
|
||||
check(rc == -1, "D1e only sink (no a2dpsrc) -> -1");
|
||||
}
|
||||
{
|
||||
char mac[32] = "";
|
||||
int rc = bt_dev_detect_mac(NULL, mac, sizeof mac);
|
||||
check(rc == -1, "D1f NULL input -> -1");
|
||||
}
|
||||
|
||||
/* ---- D2 DEV 串入 / 保留其它 token ---- */
|
||||
{
|
||||
const char *conf =
|
||||
"pcm.bluealsa:DEV=E0:42:6D:79:C5:98 {\n"
|
||||
" type plug\n"
|
||||
" slave {\n"
|
||||
" pcm {\n"
|
||||
" type bluealsa\n"
|
||||
" device E0:42:6D:79:C5:98\n"
|
||||
" profile \"a2dp\"\n"
|
||||
" codec \"LDAC\"\n"
|
||||
" ldac_eqmid \"LDAC_ABR\"\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
char *out = NULL; size_t olen = 0;
|
||||
int rc = bt_dev_rewrite(conf, strlen(conf), "33:DE:2E:21:AD:30", &out, &olen);
|
||||
check(rc == 0 && out != NULL, "D2a rewrite returns changed");
|
||||
check(out && strstr(out, ":DEV=33:DE:2E:21:AD:30 {"), "D2b DEV= updated");
|
||||
check(out && strstr(out, "device 33:DE:2E:21:AD:30\n"), "D2c device updated");
|
||||
check(out && strstr(out, "codec \"LDAC\"") && strstr(out, "ldac_eqmid \"LDAC_ABR\""),
|
||||
"D2d codec/other tokens preserved");
|
||||
/* 旧 MAC 不再出现 */
|
||||
check(out && !strstr(out, "E0:42:6D:79:C5:98"), "D2e old MAC gone");
|
||||
free(out);
|
||||
}
|
||||
{
|
||||
const char *conf =
|
||||
"pcm.bluealsa:DEV=33:DE:2E:21:AD:30 {\n"
|
||||
" type plug\n slave {\n pcm {\n"
|
||||
" type bluealsa\n device 33:DE:2E:21:AD:30\n"
|
||||
" profile \"a2dp\"\n codec \"LDAC\"\n }\n }\n}\n";
|
||||
char *out = NULL; size_t olen = 0;
|
||||
int rc = bt_dev_rewrite(conf, strlen(conf), "33:DE:2E:21:AD:30", &out, &olen);
|
||||
check(rc == 1 && out == NULL, "D2f same MAC -> unchanged (idempotent)");
|
||||
}
|
||||
{
|
||||
const char *conf = "pcm.bluealsa {\n type bluealsa\n device \"E0:42:6D:79:C5:98\"\n}\n";
|
||||
char *out = NULL; size_t olen = 0;
|
||||
int rc = bt_dev_rewrite(conf, strlen(conf), "33:DE:2E:21:AD:30", &out, &olen);
|
||||
check(rc == 0 && out && strstr(out, "device \"33:DE:2E:21:AD:30\""),
|
||||
"D2g quoted device preserved (no DEV= token)");
|
||||
free(out);
|
||||
}
|
||||
{
|
||||
char *out = NULL; size_t olen = 0;
|
||||
int rc = bt_dev_rewrite("pcm.hw {\n type hw\n}\n", 21, "33:DE:2E:21:AD:30", &out, &olen);
|
||||
check(rc == -1 && out == NULL, "D2h no pcm.bluealsa -> -1");
|
||||
}
|
||||
|
||||
printf(g_fail ? "\nRESULT: %d FAIL(S)\n" : "\nRESULT: ALL PASS\n", g_fail);
|
||||
return g_fail;
|
||||
}
|
||||
@@ -291,6 +291,19 @@ static void np_lyric_refresh(const meow_media_session_t *s)
|
||||
g_np_lyric_last_valid = valid;
|
||||
}
|
||||
|
||||
/* 歌词页封面作整页背景:等比 cover 到 max(W, H-SB_BAR_H) 方块、居中铺满内容区(裁剪溢出
|
||||
* 部分),衬在 lyric_view 半透明 scrim 之下形成压暗封面;无封面不画(回退渐变/主题面)。
|
||||
* 批6:批5 只铺渐变、从不画封面 → 歌词页无封面;此处补上封面背景,取色只做附加。 */
|
||||
static void np_draw_lyric_coverbg(int W, int H)
|
||||
{
|
||||
if (!g_np_cover) return;
|
||||
int size = W > (H - SB_BAR_H) ? W : (H - SB_BAR_H);
|
||||
int x = (W - size) / 2;
|
||||
int y = SB_BAR_H + (H - SB_BAR_H - size) / 2;
|
||||
if (y < SB_BAR_H) y = SB_BAR_H;
|
||||
meow_ui_img_cover(x, y, size, g_np_cover);
|
||||
}
|
||||
|
||||
/* 歌词页整页绘制:铺封面取色渐变(或 theme surface)底 → lyric_view(自绘 scrim + 歌词/空态)。 */
|
||||
static void np_draw_lyric_page(int redraw_sb)
|
||||
{
|
||||
@@ -298,13 +311,17 @@ static void np_draw_lyric_page(int redraw_sb)
|
||||
int W = fb_xres, H = fb_yres;
|
||||
if (!g_np_init) np_widgets_create();
|
||||
if (redraw_sb) fill_rect(0, 0, W, SB_BAR_H, th->surface);
|
||||
/* 批5:封面取色背景(主→次渐变)或主题面;并注入歌词页 set_colors。 */
|
||||
/* 批5:封面取色背景(主→次渐变)或主题面;并注入歌词页 set_colors。
|
||||
* 批6:有封面时以封面作整页背景(衬在 lyric_view 半透明 scrim 之下),取色只做附加;
|
||||
* 无封面回退渐变/主题面。 */
|
||||
np_cover_theme_update();
|
||||
if (g_np_cc_valid)
|
||||
np_apply_lyric_colors();
|
||||
if (g_np_cover)
|
||||
np_draw_lyric_coverbg(W, H);
|
||||
else if (g_np_cc_valid)
|
||||
np_fill_gradient(0, SB_BAR_H, W, H - SB_BAR_H, g_np_cc.bg_top, g_np_cc.bg_bottom);
|
||||
else
|
||||
fill_rect(0, SB_BAR_H, W, H - SB_BAR_H, th->surface);
|
||||
np_apply_lyric_colors();
|
||||
np_lyric_refresh(meow_media_current());
|
||||
if (g_np_lyric)
|
||||
meow_widget_draw(meow_lyric_view_widget(g_np_lyric));
|
||||
@@ -607,12 +624,11 @@ void run_now_playing(struct app *apps, int napps)
|
||||
/* 进度推进(按页分流):播放页=进度带+按钮;歌词页=歌词实时滚动重绘(当前行随 pos)。 */
|
||||
last_prog = now;
|
||||
if (g_np_page == NP_PAGE_LYRIC) {
|
||||
np_lyric_refresh(s);
|
||||
if (g_np_lyric) {
|
||||
meow_widget_draw(meow_lyric_view_widget(g_np_lyric));
|
||||
meow_dirty_add(0, SB_BAR_H, fb_xres, fb_yres - SB_BAR_H);
|
||||
meow_ui_flush();
|
||||
}
|
||||
/* 批6:整页重绘(封面背景+scrim+歌词),避免 lyric_view 半透明 scrim 每 1s
|
||||
* 叠涂把封面/背景逐秒压黑(批4 既有「只重绘控件不重铺背景」结构修正)。 */
|
||||
np_draw_lyric_page(0);
|
||||
meow_dirty_add(0, SB_BAR_H, fb_xres, fb_yres - SB_BAR_H);
|
||||
meow_ui_flush();
|
||||
} else {
|
||||
np_repaint_progress();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user