← Works
PerAppAudio のアイコン

PerAppAudio

macOSの標準機能ではできない「アプリ単位の出力先と音量の切り替え」を、メニューバーから行えるようにしたアプリです。

SwiftSwiftUICore AudioC個人利用macOS 26+macOSアプリ

ふつう、Macで再生するオーディオの出力デバイスはMac全体で共通です。
「会議の音はAirPodsで聞きたいけれど、音楽はディスプレイのスピーカーで流しておきたい」ということは通常できません。
PerAppAudioを使うことで、アプリごとに異なるデバイスで再生できるようになります。

何ができるか

PerAppAudioはメニューバーに常駐し、いま音を出しているアプリを一覧にします。パネルからアプリごとの出力先を設定すると、そのアプリの音だけが指定したデバイスから鳴ります。

これまでは全アプリが同じ出力先。PerAppAudioではアプリごとに出力先を分けられる これまで Chrome Zoom ミュージック Safari スピーカー 全部ここから PerAppAudio Chrome Zoom ミュージック Safari スピーカー AirPods ディスプレイ アプリごとに音量も変えられる
左:macOSの標準。右:PerAppAudio。会議の音だけAirPodsに、音楽はディスプレイのスピーカーに、といった分け方ができます。

音量もアプリごとに0〜100%で変えられます。

使い方

メニューバーのアイコンを押すとパネルが開きます。
右のプルダウンで出力先を、スライダーで音量を選ぶだけです。

PerAppAudio のパネル。WebKit(Safari など)の行に、出力先のプルダウン(MacBook Air のスピーカー)と音量スライダー(100%)が並んでいるパネル
出力先のプルダウンを開いたところ。システムのデフォルトに従う、Panasonic-TV、EarPods、MacBook Air のスピーカー、Microsoft Teams Audio が並ぶ出力先を選ぶ
実際のパネル。接続中のデバイスがプルダウンに並び、選ぶとすぐにオーディオ出力先が切り替わります。
  • デバイスが外れても大丈夫:指定したデバイスが見つからない間はシステムのデフォルトに従います。つなぎ直すと自動で指定した出力先に戻ります。
  • まとめて元に戻せる:「すべてシステムのデフォルトに戻す」を押すことで、出力先も音量も全部戻せます。
  • 再起動で設定はリセットされます:ログアウトやMacの再起動をすると全ての設定がデフォルトに戻ります。アプリがオーディオ接続の設定を掴み続けて原因不明の音響トラブルが発生する、という事態をある程度予防できます。

設定メニューでは、Macにログインしたときに自動で起動するようにできます。
メニューバーが混んでいてアイコンがノッチの裏に隠れてしまう場合に備えて、起動時にウィンドウも表示する設定も用意しています。

設定画面の「起動」の項目。Mac にログインしたら自動で起動、起動時にウィンドウも表示する、の 2 つにチェックが入っている
設定の「起動」の項目。

どうやって実現しているか

音の行き先を変える方法には、仮想のオーディオドライバを入れるやり方もありますが、PerAppAudioはドライバも非公開APIも使っていません。macOS 14.2から入ったCore AudioのProcess Tapを使い、公開APIだけで組み立てています。

アプリの音をProcess Tapで取り出し、集約デバイスを通してCのIOProcで音量をかけ、指定した出力デバイスへ流す Core Audioの公開APIだけで組み立てる アプリ Zoomなど Process Tap 音を取り出し、 元の出力は消音 集約デバイス 出力先 + Tapを 1つに束ねる IOProc(C) 音量をかけて そのまま流す AirPods 選んだ出力先 バンドルIDで指定するので あとから起動しても取り込める メモリ確保・ロックなしの リアルタイム処理
音データの処理経路。

流れは図のとおりです。まずProcess Tapでアプリの音を取り出し、元の出力先には流さないようにします。次に、選んだ出力デバイスとTapを「集約デバイス」にまとめ、Cで書いた処理(IOProc)が音量をかけて、そのまま出力先へ流します。

この最後の処理は、音が途切れないようにリアルタイムで動く部分です。そのためSwiftではなくCで書き、処理の中ではメモリの確保もロックも一切しないと決めています。音量を変更した際には経路を作り直さずに値だけを差し替えるので、スライダーを動かしている間も音は途切れません。

約40msアプリの起動から、音を取り出し始めるまで
0サードパーティのライブラリ
5モジュール(C・Core Audio・ルール・診断・UI)
26+対応するmacOSのバージョン

安定して動かすために

音の出力先は、イヤホンの抜き差し、アプリの起動と終了、スリープからの復帰など、いろいろな理由で変わります。ひとつひとつのイベントに個別に対応すると、イベントが重なったり抜けたりしたときに状態がずれてしまいます。

そこでPerAppAudioでは、何が起きても「あるべき姿」と「今の姿」を比べて、差分だけを直す方式にしています。きっかけとなるイベントは200ミリ秒でまとめ、さらに5秒ごとに見回るので、途中で何かを取りこぼしても最後は正しい状態にそろいます。

さまざまなきっかけを200ミリ秒でまとめ、あるべき姿と今の姿の差分だけを適用する きっかけ デバイスの抜き差し アプリの起動・終了 デフォルトの変更 スリープからの復帰 5秒ごとの見回り 200ms でまとめる 照合 あるべき姿 − 今の姿 差分だけ 作り直す ルートは「直す」のではなく、毎回まるごと作り直す1通りだけ

経路を作るのに失敗したときは、間隔を空けて再試行します。5回失敗したらあきらめて、元の出力先で鳴らします。「設定通りに鳴らない」よりも「音が出ない」ほうが困るので、安全な側に倒しています。

  1. 0.5秒1回目
  2. 1秒2回目
  3. 2秒3回目
  4. 4秒4回目
  5. 停止元の音に戻す
失敗したときは間隔を空けて再試行し、5回でやめます。そのときは音を消さずに、元の出力先で鳴らします。

他にも、Chromeのように裏方のプロセスから音を出すアプリを一項目にまとめる、スリープ前に経路を片付けて復帰後に作り直す、といった工夫をしています。不具合が起きたときは、パネルの「不具合を報告」からログをまとめて、Claudeにそのまま貼れる形でコピーできます。

不具合を報告の画面。症状のボタン(音が出ない、音飛び・ノイズ、遅延、違うデバイスから鳴る、アプリが落ちた、その他)、一行メモ、Claude用にコピーのボタンが並ぶ
「不具合を報告」の画面。症状を選んで「Claude用にコピー」を押すと、ログをまとめたレポートがコピーされます。そのままClaude CodeにコピペすることでClaudeが状況を調査してくれます。
次の作品AlarmBridge