0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIの作業をスマホで眺める環境を作ろうとしたら、ローカルIPとHTTPSの壁にぶち当たった話(Jev対応も)

0
Posted at

まず、何を作っているかの話から

AIを何本も同時に走らせることだけを考えて作った、Windows 用のターミナルを公開しています。「SHIKISHA-TERM」といいます。名前の由来はオーケストラの「指揮者」で、日本人である私自身が開発しています。

AIが一度の指示で実用的なコードを出力できるようになった今、システムエンジニアの役割は自ら手を動かすことから「指揮者」へと変化しました。これからの勝負どころは、「いかに多くのタスクを同時に進行できるか」に尽きます。10個のAIプロセスを同時に走らせ、人間は「指示」と「判断」のみに専念する。このワークフローを実現するためのツールです。

AIがゴリゴリと作業を進めている間、指揮者である私は「待つ」ことになります。コーヒーを淹れに行ったり、外出したりと席を離れることも多いのですが、その間も進捗はスマホから監視できるように、このターミナルには「PCの画面をスマホへ転送する仕組み」を内蔵しています。

しかし、そこに大きな不満がありました。画面に変化があるたびにJPEG画像を1枚ずつスマホへ送るという素朴な作りだったため、スクロールはカクつき、動画は紙芝居になり、音声も送れなかったのです。

本記事は、この劣悪な「JPEG紙芝居」を滑らかな動画配信へと作り直そうとした際、「プライベートIPアドレスにはHTTPS(SSL証明書)が使えない」という巨大な壁にぶつかり、そこから方式を選び直して実運用に乗せるまでの格闘の記録です。
(今回の話とは直接は関係ないですが、最新版はJevにも対応しています!サクサク自動操作できますよ♪)

対象は v0.12.0 から v0.18.0、2026年9月14日から21日までの1週間の開発記録です。

「モダンなAPIで解決だ」という目論見と、立ちはだかった壁

画面転送を動画化するにあたり、最初はとても楽観的でした。
「動画をWebSocketで転送し、ブラウザの新しいAPI(WebCodecs)を使ってスマホ側で再生すればいいじゃないか」と考えたのです。これなら既存のWebSocketの仕組みをそのまま流用でき、複雑な接続の段取りも不要です。「よし、これでいこう!」と意気込んで実装の構想を練り始めました。

しかし、この目論見は無残にも打ち砕かれます。
WebCodecsをはじめとするモダンなブラウザAPIの多くは、HTTPS(Secure Context)環境であることを必須条件としているからです。

「え、でも自分のPCに繋ぐだけなんだから、どうにかHTTPS化できないの?」と思うかもしれません。ここが最大の罠でした。
外出先のスマホから自宅やオフィスのPCに繋ぐとき、宛先は 192.168.x.x のようなLANのIPか、VPNのIPになります。公的な認証局は、そういったプライベートIPアドレスに対しては証明書を発行しません。 誰の所有物でもないアドレスであり、持ち主を厳密に証明できないからです。

つまり、IPアドレスで直結している限り、鍵マークの付いたHTTPSのURLは絶対に作れないのです。

例外として、Tailscaleの *.ts.net のように、VPN側が独自のドメイン名と証明書を割り当ててくれる環境ならHTTPS化は可能です。しかし、それを前提にしてしまうと「特定のVPNサービスを使っている人にしか恩恵がないツール」になってしまいます。これでは万人に届きません。

「社内LANだから平文のHTTPでいいや」と決めた時点で、現代のブラウザの強力な機能の多くは入口でシャットアウトされてしまう。この事実に直面し、私は頭を抱えました。

WebRTCが「唯一の道」だと確信した瞬間

途方に暮れていたとき、ふと「WebRTCならどうだろうか?」という考えがよぎりました。
複雑で手を出したくなかった技術ですが、藁にもすがる思いでiPhoneの実機を取り出し、VPNのIPを平文のHTTPで開いてテストしてみました。

ブラウザのURLバーには「安全ではありません(Secure Contextではない)」という警告が出ています。しかし、画面にはPCからの映像がしっかりと映し出されたのです。

WebRTCは(機能制限は一部あるものの)HTTPのままでも動作しました。
この瞬間、転送方式はWebRTCに決定しました。これが、すべてのユーザー環境に等しく体験を届けるための「唯一の道」だったからです。

もし私が「作りやすさ」だけでWebCodecsの実装をゴリゴリと進め、最後の最後で「あ、これHTTPS必須なのか、動かないじゃん」と気づいていたら、数日間の作業がすべて水の泡になるところでした。実機が1台あれば5分で確かめられることなので、本格的な設計に入る前に検証しておいて本当に正解でした。

見込みで作らずに測ったら、判断が2回ひっくり返った

「WebRTC(動画)になれば、JPEGよりデータも軽いしサクサク動くはずだ」
そう確信して作り始めようとしましたが、念のため事前にパフォーマンスを計測した結果、私の思い込みは見事に2回覆りました。

1つめ。動きのある画面では、マシンスペックが低いほど「動画」が有利。
クラウドで借りる想定の低スペックな2コアのマシンでテストすると、従来のJPEG方式は1.15コア・669 KB/sを消費したのに対し、動画(H.264)は0.67コア・75 KB/sと、通信量は約9分の1に激減しました。
ところが、手元の20コアのハイスペックマシンで同じ計測を行うと、優劣が逆転し、CPU負荷はJPEGのほうが軽くなりました。画像全体を1枚ずつ圧縮し直すJPEG方式は、コア数が多い環境であれば力技の並列処理で負荷を逃がせるからです。パフォーマンスの比較は、本番環境のマシンスペックで測らなければ容易に向きが変わります。

2つめ。止まっている画面においては、「JPEG方式」の圧勝。
文字だけのターミナル画面を6秒間放置して計測しました。すると、JPEG側は「6秒で1フレーム送信・5 KB/s」で済み、CPU使用率はほぼゼロでした。画面が変わったときしか画像を生成しない仕組みのため、1日中タブを開きっぱなしにしていてもコストはタダだったのです。

もしここで素朴に「タイマー駆動で毎秒30フレーム取得して動画配信する」という実装にしていたら、何も起きていない待機時間にも無駄にCPUと帯域を燃やし続けることになります。クラウドの従量課金環境であれば、この「チリツモ」がそのまま請求書に直撃します。

この計測結果から、動画方式も**「画面が変わった(イベントが発生した)ときだけエンコーダを回す」**というイベント駆動の設計にすることを固く決意しました。

席を離れている間のことが、手元でハッキリ分かるようになった

こうして苦労の末に組み込んだWebRTCにより、スマホから確認できる画面のUXは劇的に進化しました。

  • 画面が滑らかな動画で届く(スクロールも、ページ上の動画コンテンツもスムーズ)。
  • 対象のブラウザの音だけが一緒に届く(別のアプリの通知音などは混入しない)。プライバシーに配慮し、スマホ側で🔊ボタンを押すまでPC側は録音を開始しない。
  • マウス操作モード時はタップした場所が正確にクリックされる(指操作モード時は従来どおりトラックパッドのようにカーソルを動かせる)。
  • 別の部屋のノートPCなどから、キーボードを使ってターミナルへ直接コマンド入力ができる。

スマホから見た画面。右上の「動画」が、いまどちらの経路で届いているかを言っている

遅延に関しては、静止画のときが54ミリ秒、動画化後が78ミリ秒。このわずか24ミリ秒の増加は、エンコードとデコードにかかる純粋な処理時間であり、動画圧縮の恩恵を考えれば十分すぎるトレードオフです。

問い合わせが来る前に、画面が答えを持っている

自作ツールを誰かに使ってもらう場合、「うまくいかなかったときにどうなるか(フェイルセーフ)」の設計で運用・サポートの苦労が決まります。今回、私は先回りして以下の設計を組み込みました。

繋がらなければ、自動で従来の静止画方式に戻る。
ネットワーク環境(厳しいファイアウォールなど)によってはWebRTCが確立しないケースもあります。その際に画面が真っ暗になるよりも、従来の静止画モードに自動で落ちたほうがユーザーの仕事は途切れません。また、「動画にするか静止画にするか」を手動で選ばせる設定項目もあえて作りませんでした。選択肢を与えれば、「どちらを選べばいいですか?」という質問対応が発生するからです。

そのうえで、現在どちらの通信方式を利用しているかを画面の隅に明示する。
これは実運用を考えると絶対に外せません。裏側で勝手にフォールバックすると、ユーザーは「なぜか今日は動作が重い」としか認識できず、バグレポートをもらっても原因を特定できません。そこで、スマホ画面の右上に「動画」または「静止画」とステータスを出すようにしました。トラブル時にユーザーが読み上げられる情報が画面にあるだけで、問題解決の往復やりとりが1回減ります。

録音する音声の範囲は、明確に説明できる仕様に限定する。
WindowsのAPIを利用し、対象ブラウザが鳴らしている音だけを録音しています。他人のPC環境に介入するツールを配るなら、「何が録音されないか(部屋の環境音や他のアプリの音は漏れない)」をあらかじめ明確に説明できるようにしておくべきです。「私の声も漏れてますか?」と聞かれてからコードを調べるのでは遅いのです。

実機で出た不具合は、ほとんどが「動画」とは無関係だった

意気揚々とAndroidの実機で表示を確認したところ、画面が極端に拡大され、数文字が縦に長く引き伸ばされた奇妙な画面が表示されました。原因を調べると、PC側がページを128×220という極小サイズでレンダリングしていました。

実はWindowsは、最小化されたウィンドウのサイズを「0」ではなく、微小な矩形(このPCでは128×220)として報告する仕様があります。私のコードは「サイズが0より大きいか」しか判定していなかったため、この極小サイズがそのまま適用されてしまっていたのです。

スマホからPCの様子を確認するとき、PC側のウィンドウを最小化しておくのはごく当たり前の操作です。
つまりこの不具合は、スマホから見るという機能が「最もよく使われる場面」でだけ発動していました。恐ろしいことに、これはJPEG転送時代からずっと潜んでいたバグだったのですが、誰も気づいていなかったのです。動画化の過程で「解像度」周りの処理に手を入れたことで、初めて暗がりから引きずり出されました。

この種の潜在バグを見つける方法は、自分の作ったものを**「本番とまったく同じ使われ方」で通しテストする**こと以外にありません。現在はこの教訓を活かし、ヘッドレスブラウザをスマホサイズで起動し、対象ウィンドウを最小化してから表示を検証するテストコードを書き、CIに自動監視させています。

そのほか

同じ期間に実装した、日々の作業効率に直結する機能も紹介します。
設定画面の「?」ボタンを押すと、アプリ自身が設定項目を読み込んでAIが質問に回答し、さらに該当する設定画面を一発で開くショートカットボタンまで提示してくれるようになりました。新しいメンバーにツールを渡す際、マニュアル代わりとして機能します。

また、Gitの作業フォルダ名(ブランチ名)が、そこでAIに頼んだ作業内容から自動で命名されるようになりました。履歴列からブランチを切って、プルリクエストを作成するところまでアプリ内で完結でき、CIが落ちた場合はその失敗ログを直接AIタブに渡してデバッグさせることも可能です。

残りの細かいアップデート内容はCHANGELOGに記載しています。

確かめる順番は、「HTTPSが張れるか」、次に「止まっている時間の費用」

外部からアクセスする仕組みを設計するとき、真っ先に確かめておくべき教訓が2つ得られました。

1つは、そのネットワーク環境(宛先)でHTTPSが張れるかどうか。
ローカルIPアドレスで直結する環境なら張れません。それによって採用できるブラウザAPIが強制的に決まるため、アーキテクチャ設計よりも前の段階で制約として重くのしかかります。

もう1つは、何も起きていない(アイドル)時間の運用コスト。
アプリが全力で動いているときのベンチマークは誰でも測りますが、止まっているときにどれだけCPUやネットワークを消費するかを測る人は意外と少ないです。ツールの実際の使われ方が「大半の時間は待機している(止まっている)」状態なのであれば、その待機時の軽さこそが、真の性能指標になります。


作っているツールはこちらです: SHIKISHA-TERM(複数AIを同時指揮するWindows用ターミナル。Microsoft Storeでも公開中です)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?