Raspberry PiのPipeWireオーディオが「バチバチ」途切れる問題をRLimitから解決した話

自宅のオーディオ環境は、複数のPCからVBANプロトコルでRaspberry Piに音声を集約し、PipeWireでミキシングした後、FiiO BTA30 Pro経由でBluetoothヘッドホンに送る構成になっている。ある日、この音声が「バチバチ」と途切れ始めた。

CPU負荷も高くない。温度も52°C前後で正常。VBANのストリームも生きている。原因がどこにあるのか——PipeWireのスレッドスケジューリングまで辿り着くまでの記録。

症状:ストリーム個別ではなく全部で発生

重要な観察は「特定のストリームではなく、どのストリームでも発生する」という点。これにより、VBANプロトコル固有の問題ではなく、受信側のオーディオスタック全体の問題に絞り込めた。

根本原因:PipeWireスレッドがリアルタイム優先度で動いていなかった

確認すると、PipeWireのデータループスレッドのスケジューリングクラスが TS(Time Sharing)——つまり通常のプロセスと同じ優先度——になっていた。CPU負荷が上がると、音声処理スレッドが他のプロセスにプリエンプト(割り込み)され、バチバチという途切れが発生していた。

PipeWireは本来 module-rt プラグイン経由でSCHED_FIFO(リアルタイムスケジューリング)を取得する設計だが、これが機能していなかった。

原因の3層構造

設定ファイルは全部正しく書いてあった。それでも動かなかった。原因は2層のメカニズムが絡んでいた。

層1:PAM limits

/etc/security/limits.d/25-pw-rlimits.conf@pipewire グループに rtprio 95 を設定済み。piadmin ユーザーも pipewire グループに追加済み。

しかし、グループ追加が起動後だったため、PAMがlimitsを適用していなかった。

層2:systemd user managerのRLimit

さらに重要な問題。systemdのユーザーマネージャー(user@1000.service, PID 691)自体の LimitRTPRIO0 だった。

Linuxの setrlimit は、現在のhard limitを超えて設定できない。ユーザーマネージャーのRLIMIT_RTPRIOが0なので、PipeWireがmodule-rtで95を要求してもカーネルが弾く

つまり、設定ファイルに正しく書いてあっても、それを継承する親プロセスのRLimitが0では意味がない。

修正:システムレベルのdrop-in

システムレベルの user@1000.service にdrop-inを作成した。

sudo mkdir -p /etc/systemd/system/user@1000.service.d
sudo tee /etc/systemd/system/user@1000.service.d/rt-limits.conf << 'EOF'
[Service]
LimitRTPRIO=95
LimitNICE=39
LimitMEMLOCK=4194304
EOF
sudo systemctl daemon-reload

再起動後、PipeWireのスレッド状態を確認:

ps -Lo tid,cls,rtprio,ni,comm -p $(pgrep -x pipewire)

TID  CLS RTPRIO  NI COMMAND
795  TS      -  -11 pipewire
839  FF     88   -  data-loop.0

データループスレッドが FF(SCHED_FIFO)88 になった。pipewire-pulse と wireplumber も同様。RLimitも通った(rtprio=95, nice=39)。

なぜこの問題が難しいのか

「設定は全部正しく書いてあるのに動かない」という状態。PAMのlimits適用タイミングと、systemd user managerのRLimit継承という、2層のメカニズムが重なった落とし穴だった。

よくあるガイドでは「pipewireグループに追加してlimits.confに書けばよい」と説明されるが、これはログインセッションに対しては正しい。しかし、systemd --user サービスとして動くPipeWireの場合、ユーザーマネージャー自体のRLimitがボトルネックになる。ここをdrop-inで引き上げないと、module-rtが呼んでもカーネルが拒否する。

まとめ

  • VBAN経由オーディオのノイズは、PipeWireのRTスケジューリング未適用が原因
  • 直接の原因は user@1000.service のLimitRTPRIO=0
  • /etc/systemd/system/user@1000.service.d/rt-limits.conf にdrop-inで解決
  • ログインセッションとsystemd user sessionは、RLimitの継承パスが違うことに注意

Raspberry Piでオーディオを扱う方は、PipeWireが本当にRTで動いているか、一度 ps -Lo cls,rtprio,comm -p $(pgrep -x pipewire) で確認してみるとよい。CLS列が「TS」ではなく「FF」になっていれば正常。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール