78 lines
2.8 KiB
Python
78 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""看音频现场: sink 音量 / 声卡各 route 的音量 / 默认设备(排查"响度怪"用).
|
|
|
|
用法: python3 看音频状态.py
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import subprocess
|
|
from typing import Any
|
|
|
|
|
|
def dump() -> list[dict[str, Any]]:
|
|
raw = subprocess.run(["pw-dump"], capture_output=True, text=True).stdout
|
|
return json.loads(raw)
|
|
|
|
|
|
def vol_of(prm: dict[str, Any]) -> str:
|
|
"""把 Volume 参数压成一行."""
|
|
cv = prm.get("channelVolumes") or prm.get("volume")
|
|
if cv is None:
|
|
return "-"
|
|
if isinstance(cv, (int, float)):
|
|
return f"{cv:.4f}"
|
|
vals = [float(v) for v in cv]
|
|
if not vals:
|
|
return "-"
|
|
return "/".join(f"{v:.4f}" for v in vals)
|
|
|
|
|
|
def main() -> None:
|
|
d = dump()
|
|
print("=== Audio/Sink 节点 ===")
|
|
for o in d:
|
|
if o.get("type") != "PipeWire:Interface:Node":
|
|
continue
|
|
p = o.get("info", {}).get("props", {})
|
|
if p.get("media.class") not in ("Audio/Sink", "Stream/Output/Audio"):
|
|
continue
|
|
prms = o.get("info", {}).get("params", {})
|
|
vol = "-"
|
|
for prm in prms.get("Props", []) or []:
|
|
if "volume" in prm or "channelVolumes" in prm:
|
|
vol = vol_of(prm)
|
|
print(f" id={o['id']:<4} {p.get('media.class'):<20} {p.get('node.name','')}")
|
|
print(f" desc={p.get('node.description','')} vol={vol} "
|
|
f"state={o.get('info',{}).get('state','')}")
|
|
|
|
print()
|
|
print("=== 声卡(Device) 及其 route 音量 ===")
|
|
for o in d:
|
|
if o.get("type") != "PipeWire:Interface:Device":
|
|
continue
|
|
p = o.get("info", {}).get("props", {})
|
|
name = p.get("device.name") or p.get("api.alsa.card.name") or ""
|
|
if "usb" not in name.lower() and "edifier" not in name.lower():
|
|
continue
|
|
print(f" id={o['id']} {p.get('node.name','')} ({p.get('device.description','')})")
|
|
prms = o.get("info", {}).get("params", {})
|
|
print(f" 参数键: {sorted(prms.keys())}")
|
|
for prm in prms.get("Profile", []) or []:
|
|
print(f" 当前 profile: {prm.get('name','')} ({prm.get('description','')})")
|
|
for prm in prms.get("Route", []) or []:
|
|
rp = prm.get("props", {})
|
|
print(f" route={rp.get('route.name',''):<28} "
|
|
f"desc={rp.get('route.description',''):<20} "
|
|
f"prio={rp.get('priority','')} vol={vol_of(prm)} "
|
|
f"avail={prm.get('available','')}")
|
|
for prm in prms.get("EnumRoute", []) or []:
|
|
rp = prm.get("props", {})
|
|
print(f" [enum] {rp.get('route.name',''):<28} "
|
|
f"desc={rp.get('route.description','')} avail={prm.get('available','')}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|