diff --git a/meow_ui_audio.c b/meow_ui_audio.c index e16afb8..eb7a008 100644 --- a/meow_ui_audio.c +++ b/meow_ui_audio.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -73,15 +74,39 @@ static const char *sock_path(void) return (e && e[0]) ? e : AUD_SOCK_DEFAULT; } +/* 连接 audiod。**全部有界**:connect 非阻塞 + poll 2s(对端 listen backlog 满/wedge 时 + * 阻塞 connect 会把 App 播放线程永久压进内核——真机长流卡死时 ncm 卡死的同款路径); + * 建连后 SO_SNDTIMEO/RCVTIMEO 2s:audiod 停摆时 write 超时返回错误 → 标记流死, + * App 走「重新 open」恢复路径,绝不永久阻塞。 */ +#define AUD_CONN_TMO_MS 2000 static int connect_path(const char *path) { int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) return -1; + int fl = fcntl(fd, F_GETFL, 0); + if (fl >= 0) fcntl(fd, F_SETFL, fl | O_NONBLOCK); struct sockaddr_un a; memset(&a, 0, sizeof a); a.sun_family = AF_UNIX; strncpy(a.sun_path, path, sizeof a.sun_path - 1); - if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) { close(fd); return -1; } + int r = connect(fd, (struct sockaddr *)&a, sizeof a); + if (r < 0 && errno == EINPROGRESS) { + struct pollfd p; + p.fd = fd; p.events = POLLOUT; p.revents = 0; + if (poll(&p, 1, AUD_CONN_TMO_MS) > 0) { + int err = 0; + socklen_t el = sizeof err; + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &el) == 0 && err != 0) { errno = err; r = -1; } + } else { + r = -1; /* 超时/错误 */ + } + } + if (r < 0) { close(fd); return -1; } + if (fl >= 0) fcntl(fd, F_SETFL, fl); /* 回阻塞模式;读写超时由 SO_*TIMEO 兜底 */ + struct timeval tv; + tv.tv_sec = AUD_CONN_TMO_MS / 1000; tv.tv_usec = 0; + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv); + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); return fd; }