Steven
Steven1 分で読める

画面録画がなぜ間違ったモニターを撮るのか(そして私たちの修正)

デュアルモニター環境で、GeekByeはあなたがどちらの画面で作業していようとプライマリディスプレイを録画・スクリーンショットしていました。修正は小さな関数ひとつ — でもその最初のバージョンは間違っていて、コードレビューがその理由を見抜きました。

画面録画
マルチディスプレイ
エンジニアリング
GeekByeリリース
画面録画がなぜ間違ったモニターを撮るのか(そして私たちの修正)

これはモニターを2台持っている場合にだけ存在するバグ — だからこそしばらく静かに生き延びていました。サイドのディスプレイで作業をしていて、GeekByeの録画を始めると、録画されるのはプライマリモニターです。メニューバーのある方。あなたが見ていなかった方。

同じ欠陥が、より静かに、より厄介な形で、GeekByeがコンテキストとしてAIに送るスクリーンショットも直撃しました。2枚目のモニターでスクリーンショットのショートカットを押すと、AIは1枚目の画像を受け取ります。目に見える手がかりはなく — アシスタントはただ間違った画面について答え、あなたはなぜ混乱しているのかと首をかしげることになります。GeekBye v2.0.10は両方を修正しました。

2つのパイプライン、1つの怠けたデフォルト

デスクトップの画面キャプチャは2つの別々のコードパスで、どちらも独立してプライマリディスプレイを選んでいました:

  • 動画録画は利用可能な画面ソースを列挙し、最初の1つ — sources[0] を取っていました。macOSでは、それは事実上いつもメインディスプレイです。ピッカーもなければ、実際にどこにいたかを考えるロジックもありません。私たち自身のコードのコメントには、文字どおり*「最初の画面ソースを自動選択」*と書いてありました。
  • スクリーンショットはmacOSのscreencaptureコマンドを-mフラグ付きで使っていました。このフラグの意味はただ一つ: メインディスプレイのみ。 ハードコードでした。

どちらのパスも、肝心の問いを一度も尋ねませんでした: ユーザーはどの画面にいるのか?

決して壊れていなかったことを一つ、勘違いされがちなので明確にしておきます: 同じモニター上でmacOSのSpacesを切り替えるのは常に正しく動いていました。キャプチャはディスプレイ単位で起こり — 選ばれたディスプレイに表示されているSpaceを、そのまま掴みます。このバグはSpacesの話ではありませんでした。ずっと、間違った物理ディスプレイを選ぶ話だったのです。

明白に見えた修正 — そしてそれは間違いだった

正しいシグナルは簡単そうに見えます: ユーザーがいるディスプレイをキャプチャする。私たちの最初の実装は、GeekByeのオーバーレイウィンドウを基準にしました — オーバーレイが存在するディスプレイをキャプチャする、というものです。

コードレビューがそれを、正しく葬りました。GeekByeのオーバーレイは、プライマリディスプレイ上に、位置(0,0)で、作業領域いっぱいのウィンドウとして作られます。あなたがそのピルを物理的に別のモニターへドラッグしたときにだけ移動し — そして、それを動かすキーボードショートカットはプライマリディスプレイの寸法にクランプされるため、2枚目のモニターへはまったく動かせません。オーバーレイを基準にキャプチャするということは、つまり: 作業画面にオーバーレイをたまたまドラッグしていなかったすべてのユーザーにとって、その「修正」はまっすぐプライマリディスプレイへ戻ってしまうのです。ほとんど誰も直らなかったでしょう — それでいて、シングルモニターの開発機での手早いテストでは、動いているように見えたのです。

正しい基準はカーソルです。マウスがある場所、それがあなたの作業しているディスプレイです — そしてそれは、キャプチャが始まるあらゆる経路で正しい: キーボードショートカットはあなたが指している場所で発火し、Recordボタンをクリックすれば、定義上あなたのカーソルはそのディスプレイにあります。最終的な修正は2行の関数です: カーソルに最も近いディスプレイ。動画は自身のキャプチャソースをそのディスプレイのidに合わせ; スクリーンショットは-mのメインディスプレイフラグの代わりに、そのディスプレイの境界をscreencapture -R(特定の矩形)へ渡します。

私たちは意図して-R(グローバル画面座標での明示的な矩形)を-D(ディスプレイのインデックス)より選びました: OSのディスプレイインデックスはフレームワークのディスプレイ順序と対応する保証がなく、インデックスでは二段目の当てずっぽうになってしまうからです。実際のディスプレイ境界から来る矩形は曖昧さがありません — そして出荷前に、プライマリの左に配置されたディスプレイの負座標を含めて、このフラグの挙動を実機のマルチモニター環境で検証しました。

なぜこれが良い「教材バグ」なのか

  1. 「画面をキャプチャする」は一つの決定を隠している。 シングルディスプレイでは決定がないので、その決定は設計されることがなく — デフォルトで済まされます。マルチモニターこそ、あらゆる暗黙のデフォルトが表面化する場所です。
  2. 静かに間違っているのは、目に見えて間違っているより厄介。 動画のバグは人を苛立たせました。スクリーンショットのバグはAIを、目に見えない形で誤誘導しました。モデルにコンテキストを供給する機能を作るとき、間違った入力はどこにもエラーを出さないまま、自信満々に間違った出力を生みます。それこそ、最も執念深く狩る価値のある失敗です。
  3. 自分のマシンで通る修正が、他のみんなのマシンでは落ちることがある。 オーバーレイ基準のバージョンは、シングルモニターのテストでは動きました。バグの本質はまさに複数モニターです — そしてレビュアーは、緑のテストを信じる代わりに、ウィンドウの実際の位置について推論しました。レビューは動いているコードへのゴム印ではありません; それはコードがなぜ動くのかについての、二つ目のモデルなのです。

GeekBye v2.0.10は、録画とスクリーンショットの両方にカーソルベースの修正を出荷します。複数のディスプレイを使っているなら、キャプチャは今、あなたについてきます。

このシリーズの近隣リリースについては、AIノートテイカーはなぜ会議の途中で録音を止めるのか(v2.0.9)とAI文字起こしはなぜ専門用語を聞き間違えるのか(v2.0.11)をご覧ください。通話中にオーバーレイがどう振る舞うかは、画面共有中に不可視のままでいる方法をどうぞ。

関連記事

沈黙は耐荷重だった
Steven
Steven1 分で読める

沈黙は耐荷重だった

GeekBye v1の最後の二つのリリースは、同じ居心地の悪い真実についてのものです: 現実のネットワーク越しのリアルタイム文字起こしはロスレスではなく、誠実な一手はそのふりをやめることだ、と。v1.8.20は、再接続中にオーディオチャンクをドロップする前に、そのすべてのコピーをディスクに保ち、そして文字起こしのギャップを声に出して印づけ始めました。v1.9.0は帯域幅を節約するために沈黙を送るのをやめ — そして、その沈黙こそが、文の終わりを知るために文字起こしエンジンが使っていたまさにその信号だったと気づきました。物を投げ捨てることの代償についての、二つのリリースです。

エンジニアリング
Audio
信頼性
Web Audioを生かし続ける三つの動詞
Steven
Steven2 分で読める

Web Audioを生かし続ける三つの動詞

二ヶ月を隔てて別々のファイルで出た二つのGeekByeポイントリリースが、私たちのオーディオコードに同じ教訓を正反対の端から教えました: ブラウザのAudioContextを使い捨てとして扱うのをやめよ、と。一方のリリースは、macOSが録画中にこっそりsuspendしたコンテキストをresume()することを学びました; もう一方は、連続するセッションがChromiumのおよそ六コンテキストの上限に激突するのをやめさせるべく、close()する代わりにsuspend()することを学びました。resume、suspend、close — それが筋の全部です。

エンジニアリング
Audio
デスクトップ
開いているアプリと通話中を見分ける
Steven
Steven2 分で読める

開いているアプリと通話中を見分ける

GeekByeは、あなたがビデオ会議に参加したことに気づき、ワンクリックでの録画を差し出せます。検出のほうは、実のところ簡単な半分でした — 10秒ごとにウィンドウタイトルを読むSwiftバイナリです。難しい半分は精度です: Zoomがただ開いているだけのときに発火しないこと、すでに録画している会議についてうながさないこと、そしてあなたが実際にいる通話のマイクをミュートしないこと。三つのリリース、そのどれもが、自分自身を打ち負かさないことを学ばねばならなかったガードなのです。

エンジニアリング
macOS
デスクトップ