139 lines
5.4 KiB
C
139 lines
5.4 KiB
C
/* 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;
|
||
}
|