feat(audiod): A3+DSD — ①24/32bit高清byte-exact(偏好S32) ②独立AUDIO_FMT_DOP DoP DSD透传+失败报错关流(拒BT) ③音量收编v2双组写PCM+DSD_VOLUME平方锥度audiod权威 ④/api/audio/monitor监控+前端音频页监控卡;宿主100/0,0warning;SDK meow_ui_audio ABI变大M6.34需重编meow_ui.a+重链四App

This commit is contained in:
AskaEth committed 2026-09-04 00:56:57 +08:00
1 parent 2dc4cad454
commit effce6d0db
6 files changed
+533 -56

No files matched your search

+9
View File
@@ -38,6 +38,7 @@ typedef struct meow_audio_state {
int paused; /* 当前流是否暂停 */
int route_port; /* 当前路由口(-1 未知) */
int vol; /* 当前音量 0-100 */
int dsd; /* 当前流是否为 DoP DSD(fmt==AUDIO_FMT_DOP 且 audiod 已授权) */
} meow_audio_state;
/* 被抢占回调:by_app=抢占者 app_id(非空)。ctx 由 on_preempt 注册时传入。 */
@@ -48,6 +49,10 @@ typedef void (*meow_audio_preempt_fn)(const char *by_app, void *ctx);
* MEOW_ERR_NODEV=无可用 PCM 设备;MEOW_ERR_* 常量本身即负值)。open 后客户端须按内部记录的
* grant 格式产出 PCM。 */
int meow_audio_open(int rate, int ch, int fmt);
/* 开流(带 flags)。flags=AUDIO_FLAG_DSD 且 fmt=AUDIO_FMT_DOP 时为 DoP DSD 流(A3+DSD 定案):
* App 侧须把 DSD 解码封装为 DoP(每样本 32-bit 容器:16bit DSD 数据 + 标记 + 0),audiod 只透传
* (不引 dsd2pcm、不做 DOP_EN 之外的任何处理)。DSD 打不开/不支持 → open 返回负错误码(报错关流)。 */
int meow_audio_open_ex(int rate, int ch, int fmt, uint32_t flags);
/* 写 PCM。pcm=native fmt/ch 样本(open 传的参数),frames=帧数;内部归一成 grant 并分批发送。
* 返回写入帧数;<0=流已死(被抢占/audiod 断开),App 应重新 open。阻塞(socket 背压)。 */
int meow_audio_write(const void *pcm, int frames);
@@ -57,6 +62,10 @@ int meow_audio_pause(int sid, int paused);
int meow_audio_close(int sid);
/* 查询 audiod 快照(填充 out)。返回 0 成功;<0 失败。 */
int meow_audio_query(meow_audio_state *out);
/* 设置音量 0-100(audiod 唯一权威:写 DAC numid=1/2 + DSD_VOLUME 双组保切换连续 + 持久化
* settings.conf audio.volume,与 launcher/watchdog 同源同键)。BT 输出目标时音量由 AVRCP 侧控,
* audiod 不下发 DAC 反转。返回 0 成功;<0 失败(audiod 不在)。 */
int meow_audio_set_volume(int pct);
/* 注册被抢占回调(可选;内部读线程分发)。重复调用幂等。 */
void meow_audio_on_preempt(meow_audio_preempt_fn cb, void *ctx);
+39 -4
View File
@@ -229,7 +229,8 @@ static int fmt_bps(int fmt)
case AUDIO_FMT_S16: return 2;
case AUDIO_FMT_S24:
case AUDIO_FMT_S32:
case AUDIO_FMT_FLOAT: return 4;
case AUDIO_FMT_FLOAT:
case AUDIO_FMT_DOP: return 4; /* DOP=32-bit DoP 容器(16bit DSD+标记+0),同 S32 宽 */
default: return 2;
}
}
@@ -262,7 +263,7 @@ static int send_write_chunk(const uint8_t *p, uint32_t len)
/* ---- 公开 API ---- */
int meow_audio_open(int rate, int ch, int fmt)
int meow_audio_open_ex(int rate, int ch, int fmt, uint32_t flags)
{
/* env 检查:调试直开 */
const char *de = getenv("MEOW_AUDIO_DIRECT");
@@ -270,7 +271,10 @@ int meow_audio_open(int rate, int ch, int fmt)
pthread_mutex_lock(&g_mu);
if (g_has_stream) { pthread_mutex_unlock(&g_mu); return MEOW_ERR_BUSY; }
if (ch > 2 || ch < 1 || rate <= 0 || fmt < AUDIO_FMT_S16 || fmt > AUDIO_FMT_FLOAT || fmt == AUDIO_FMT_FLOAT) {
int dsd = (fmt == AUDIO_FMT_DOP) && (flags & AUDIO_FLAG_DSD);
int fmt_ok = (fmt == AUDIO_FMT_S16 || fmt == AUDIO_FMT_S24 ||
fmt == AUDIO_FMT_S32 || fmt == AUDIO_FMT_DOP);
if (ch > 2 || ch < 1 || rate <= 0 || !fmt_ok || (fmt == AUDIO_FMT_DOP && !dsd)) {
pthread_mutex_unlock(&g_mu);
return MEOW_ERR_INVAL;
}
@@ -297,7 +301,7 @@ int meow_audio_open(int rate, int ch, int fmt)
m_audio_open_t o;
memset(&o, 0, sizeof o);
snprintf(o.app_id, sizeof o.app_id, "%s", getenv("MEOW_LOG_APP") ? getenv("MEOW_LOG_APP") : "app");
o.rate = (uint32_t)rate; o.ch = (uint16_t)ch; o.fmt = (uint16_t)fmt;
o.rate = (uint32_t)rate; o.ch = (uint16_t)ch; o.fmt = (uint16_t)fmt; o.flags = flags;
uint32_t req = (g_pending == 0xFFFFFFFF) ? 1 : (g_pending + 1); /* 单调递增(单个挂起) */
g_pending = req;
g_resp_len = 0;
@@ -322,6 +326,35 @@ int meow_audio_open(int rate, int ch, int fmt)
return (int)g_sid;
}
int meow_audio_open(int rate, int ch, int fmt)
{
return meow_audio_open_ex(rate, ch, fmt, 0);
}
int meow_audio_set_volume(int pct)
{
if (pct < 0) pct = 0;
if (pct > 100) pct = 100;
pthread_mutex_lock(&g_mu);
int fd = conn_locked();
if (fd < 0) { pthread_mutex_unlock(&g_mu); return MEOW_ERR_NOENT; }
m_audio_volume_t v; v.pct = (int32_t)pct;
uint32_t req = (g_pending == 0xFFFFFFFF) ? 1 : (g_pending + 1);
g_pending = req;
if (send_frame(g_fd, MSG_AUDIO_VOLUME, req, &v, sizeof v) != 0) {
mark_dead_locked(); pthread_mutex_unlock(&g_mu); return MEOW_ERR_IO;
}
/* 等 ACK(3s 超时;audiod 停摆时透明失败标记流死) */
struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += 3;
int rc = 0;
while (g_pending == req) {
if (pthread_cond_timedwait(&g_cond, &g_mu, &ts) != 0) { rc = MEOW_ERR_TIMEOUT; break; }
}
if (g_resp_type != MSG_ACK) rc = (rc == 0) ? MEOW_ERR_IO : rc;
pthread_mutex_unlock(&g_mu);
return rc;
}
int meow_audio_write(const void *pcm, int frames)
{
if (!pcm || frames <= 0) return 0;
@@ -429,8 +462,10 @@ static int state_text_parse(const char *t, meow_audio_state *o)
if (strncmp(p + 4, "S16", 3) == 0) f = AUDIO_FMT_S16;
else if (strncmp(p + 4, "S24", 3) == 0) f = AUDIO_FMT_S24;
else if (strncmp(p + 4, "S32", 3) == 0) f = AUDIO_FMT_S32;
else if (strncmp(p + 4, "DoP", 3) == 0) f = AUDIO_FMT_DOP;
o->fmt = (uint16_t)f;
}
if ((p = strstr(t, "dsd="))) o->dsd = atoi(p + 4);
if ((p = strstr(t, "written="))) o->written_frames = (uint64_t)strtoull(p + 8, NULL, 10);
if ((p = strstr(t, "played="))) o->played_frames = (uint64_t)strtoull(p + 7, NULL, 10);
if ((p = strstr(t, "underrun="))) o->underrun = (uint32_t)atoi(p + 9);