media: resolve the audio user once, thread-safely
SpawnPw() looked the desktop user up with getpwnam() — one static buffer — from the mic thread and the playout thread at the same instant. When the race made both lookups fail, uid stayed 0 and both pw helpers were started with XDG_RUNTIME_DIR=/run/user/0, where no PipeWire session lives: pw-record hit EOF at once, pw-play never connected, and a call that was up with RTP flowing both ways was answered into static (tx_mic=0 rx_played=0 qdrop=883, dev phone 2026-09-08 20:01, first time in years of calls — timing). AudioUid() resolves AUDIO_USER once under std::call_once with getpwnam_r and a private buffer, complains when the user does not exist, and logs the session the helpers are aimed at on every call, so a field journal answers "where did the audio go" directly.
This commit is contained in:
parent
69d8b2a716
commit
b8d439246a
1 changed files with 23 additions and 3 deletions
|
|
@ -410,6 +410,28 @@ std::size_t RtpPayloadOffset(std::span<const std::uint8_t> pkt) {
|
||||||
return off;
|
return off;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The desktop user's uid, resolved ONCE and thread-safely. getpwnam() hands
|
||||||
|
// out one static buffer, and the mic and playout threads spawn their pw
|
||||||
|
// helpers at the same instant — the race sent both into /run/user/0, where
|
||||||
|
// no PipeWire session lives, and a call was answered into static (dev phone,
|
||||||
|
// 2026-09-08 20:01: tx_mic=0 rx_played=0 qdrop=883). Logged per call so a
|
||||||
|
// journal shows which session the helpers were aimed at.
|
||||||
|
uid_t AudioUid() {
|
||||||
|
static std::once_flag once;
|
||||||
|
static uid_t uid = 0;
|
||||||
|
std::call_once(once, [] {
|
||||||
|
std::string user = EnvOr("AUDIO_USER", "user");
|
||||||
|
passwd pw{};
|
||||||
|
passwd* res = nullptr;
|
||||||
|
char buf[4096];
|
||||||
|
if (getpwnam_r(user.c_str(), &pw, buf, sizeof buf, &res) == 0 && res) uid = res->pw_uid;
|
||||||
|
else
|
||||||
|
std::println(std::cerr, "imsd-media: AUDIO_USER '{}' not found; no PipeWire session for uid 0", user);
|
||||||
|
std::println(std::cerr, "imsd-media: audio session: {} -> /run/user/{}", user, uid);
|
||||||
|
});
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
// Spawn pw-record/pw-play in the desktop user's PipeWire session (sudo -u
|
// Spawn pw-record/pw-play in the desktop user's PipeWire session (sudo -u
|
||||||
// when run as root). AUDIO_USER names the session owner; the default "user"
|
// when run as root). AUDIO_USER names the session owner; the default "user"
|
||||||
// is postmarketOS's standard account. `toChild` true = we write the child's
|
// is postmarketOS's standard account. `toChild` true = we write the child's
|
||||||
|
|
@ -421,10 +443,8 @@ Child SpawnPw(bool play, bool toChild, int rate) {
|
||||||
std::vector<std::string> argv;
|
std::vector<std::string> argv;
|
||||||
if (geteuid() == 0) {
|
if (geteuid() == 0) {
|
||||||
std::string user = EnvOr("AUDIO_USER", "user");
|
std::string user = EnvOr("AUDIO_USER", "user");
|
||||||
uid_t uid = 0;
|
|
||||||
if (passwd* pw = getpwnam(user.c_str())) uid = pw->pw_uid;
|
|
||||||
argv = {"sudo", "-u", user, "env",
|
argv = {"sudo", "-u", user, "env",
|
||||||
std::format("XDG_RUNTIME_DIR=/run/user/{}", uid)};
|
std::format("XDG_RUNTIME_DIR=/run/user/{}", AudioUid())};
|
||||||
}
|
}
|
||||||
const char* tool = play ? "pw-play" : "pw-record";
|
const char* tool = play ? "pw-play" : "pw-record";
|
||||||
const char* lat = play ? "40ms" : "20ms";
|
const char* lat = play ? "40ms" : "20ms";
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue