PerAppAudio
macOSの標準機能ではできない「アプリ単位の出力先と音量の切り替え」を、メニューバーから行えるようにしたアプリです。
ふつう、Macで再生するオーディオの出力デバイスはMac全体で共通です。
「会議の音はAirPodsで聞きたいけれど、音楽はディスプレイのスピーカーで流しておきたい」ということは通常できません。
PerAppAudioを使うことで、アプリごとに異なるデバイスで再生できるようになります。
何ができるか
PerAppAudioはメニューバーに常駐し、いま音を出しているアプリを一覧にします。パネルからアプリごとの出力先を設定すると、そのアプリの音だけが指定したデバイスから鳴ります。
音量もアプリごとに0〜100%で変えられます。
使い方
メニューバーのアイコンを押すとパネルが開きます。
右のプルダウンで出力先を、スライダーで音量を選ぶだけです。
パネル
出力先を選ぶ- デバイスが外れても大丈夫:指定したデバイスが見つからない間はシステムのデフォルトに従います。つなぎ直すと自動で指定した出力先に戻ります。
- まとめて元に戻せる:「すべてシステムのデフォルトに戻す」を押すことで、出力先も音量も全部戻せます。
- 再起動で設定はリセットされます:ログアウトやMacの再起動をすると全ての設定がデフォルトに戻ります。アプリがオーディオ接続の設定を掴み続けて原因不明の音響トラブルが発生する、という事態をある程度予防できます。
設定メニューでは、Macにログインしたときに自動で起動するようにできます。
メニューバーが混んでいてアイコンがノッチの裏に隠れてしまう場合に備えて、起動時にウィンドウも表示する設定も用意しています。

どうやって実現しているか
音の行き先を変える方法には、仮想のオーディオドライバを入れるやり方もありますが、PerAppAudioはドライバも非公開APIも使っていません。macOS 14.2から入ったCore AudioのProcess Tapを使い、公開APIだけで組み立てています。
流れは図のとおりです。まずProcess Tapでアプリの音を取り出し、元の出力先には流さないようにします。次に、選んだ出力デバイスとTapを「集約デバイス」にまとめ、Cで書いた処理(IOProc)が音量をかけて、そのまま出力先へ流します。
この最後の処理は、音が途切れないようにリアルタイムで動く部分です。そのためSwiftではなくCで書き、処理の中ではメモリの確保もロックも一切しないと決めています。音量を変更した際には経路を作り直さずに値だけを差し替えるので、スライダーを動かしている間も音は途切れません。
安定して動かすために
音の出力先は、イヤホンの抜き差し、アプリの起動と終了、スリープからの復帰など、いろいろな理由で変わります。ひとつひとつのイベントに個別に対応すると、イベントが重なったり抜けたりしたときに状態がずれてしまいます。
そこでPerAppAudioでは、何が起きても「あるべき姿」と「今の姿」を比べて、差分だけを直す方式にしています。きっかけとなるイベントは200ミリ秒でまとめ、さらに5秒ごとに見回るので、途中で何かを取りこぼしても最後は正しい状態にそろいます。
経路を作るのに失敗したときは、間隔を空けて再試行します。5回失敗したらあきらめて、元の出力先で鳴らします。「設定通りに鳴らない」よりも「音が出ない」ほうが困るので、安全な側に倒しています。
- 0.5秒1回目
- 1秒2回目
- 2秒3回目
- 4秒4回目
- 停止元の音に戻す
他にも、Chromeのように裏方のプロセスから音を出すアプリを一項目にまとめる、スリープ前に経路を片付けて復帰後に作り直す、といった工夫をしています。不具合が起きたときは、パネルの「不具合を報告」からログをまとめて、Claudeにそのまま貼れる形でコピーできます。
