初めまして
はじめましてです。はじめてQita書きます。現在、来年から共学化される男子校に通っている高校生です。趣味はご家庭ネットワーク?と自宅サーバーやWindowsCE系の組み込み向けソフトウェアの開発をしてみたり、最近はVPNの検証にはまってます。自己紹介はこれくらいにして早速本題に入ります!
私の学校の”文化祭”
わたしの学校の文化祭は男子校(田舎だからなのかも)ということもあり、屋台をやるといったきらびやかな文化祭でなく、基本的に体育館で劇をするか教室で展示するかの2択とかなり変わってます。おかげで、私のような自称SEにとってはいろんな技術を確かめられる最高の検証環境になってるのですが。。。
何を作ったか?
現状
わたしの学校の文化祭はすでに先輩が自作のアプリで体育館の上の部分にプロジェクターで題名(劇の名前とする学年)やバンドの時に歌詞を表示するといったことをしていました。ただ、先輩が卒業して私が運営を引き継いだ際に、いちいち2階(卓球場になってる)にいって歌詞送りや題名を送らないといけない(先輩がいたときはネットにつないでGASをつかってスプレットシートに5秒に1回アクセスして自動切換えしてたらしいですが)ので、非冷房の体育館に半日(しかも上の階)にいないといけないので非常に体力的にきつかったです。
さらに、先輩の方法では以下の問題点がありました。
1,いちいち上にいないといけなくて体力的にきつい
上で述べた通りです
2,C# WPFで作られているせいで配布端末では動かない
うちの学校の配布端末はWindows11SEを搭載したSurface Laptop SEなので管理者の許可(というかMSの意向)で決められたアプリしか動かず、Win32APIを利用したアプリは学校用のPCか個人のPCを用いなければならなかった。普通のS modeでもないのでUWPも動作しない。
3,C# WPFのせいでバグが多いし、起こっても対処できない
これは私がC#をやってないのがいけないんですけど、あとあとの後輩のことを考えるとこれ以上使えない。。。。
加えて保護者や生徒から要望がありました。
4,劇や動画が見にくい
生徒席が一番前でその後ろに保護者席が続く形をとるので保護者が必然的に舞台から遠くなって劇が見づらくなる。
5,戦闘シーンが見えづらい
わたしの学校の文化祭は高3が伝統的にやる戦隊ものチックな劇があるのですが、その劇では実際に体育館内で戦闘シーンをする際に、保護者席と生徒席の間で行うので端の人が戦闘シーンを楽しめない。
以上の問題があったので上のプロジェクター表示は残しつつ、いろいろ改良を加えていかないとなぁと思っていました。
解決(本題)
以上の問題の解決策を考えて以下の理由からアプリを新規開発することにしました。
1,いちいち上にいないといけなくて体力的にきつい
→ ネットワークを構築して本部席から遠隔で操作したい。
2,C# WPFで作られているせいで配布端末では動かない
→ もうこのアプリは使えない。Chromeは使えるのでWebアプリにすればいいのでは?
3,C# WPFのせいでバグが多いし、起こっても対処できない
→ 同上。
4,劇や動画が見にくい
→ サイドディスプレイを配置して劇の映像を音楽ライブのようにサイドに映せればいいのでは?
5,戦闘シーンが見えづらい
→ 可搬カメラを作って4のサイドモニターに映せばいいのでは
これから以下の要件で開発することにしました。
・Edge(Chrome)等のWebブラウザ上で実行できるようにする。
・遅延をおさえるため、ネットワークはすべて有線で構築する。
・ネットワークの都合上、オフライン動作できるようにする。
・詳しくない人でも運用できるだれでも扱えるシンプルなシステムにする。
・依存関係を減らして、マルチプラットフォームで開発する。
・予算を抑えるため、学校にある既存機器をできる限り利用する。
・サーバーレスで構築する。
開発!
難関1:WebRTCのシグナリング
開発にあたっていろいろ調べてるとWebRTCという仕組みが目に留まりました。これは、P2Pで映像データーなどをやり取りする仕組みです。ZoomやInstagram通話などの著名なP2Pビデオ通話機能にも利用されている技術ですね。これがやりたいことができる仕組みだ!と思ったのですが、調べていくうちにいくつか問題が見つかりました。
「STUNサーバーを利用する前提のシステムなのでサーバーがないとシグナリングできない。」
という点です。どういうことかというと、WebRTCというシステムはもともとサーバーのあるネットワーク上での利用を想定しているので、サーバーがないと接続情報の交換ができないんですよね。これは困ったと思っていろいろ探ってると、どうやら、接続情報にはSDP(Session Description Protocol),ICE(Interactive Connectivity Establishment)というものを1往復ずつ、計2往復4回の情報の交換によって通信を確立してるということが分かりました。
図にすると、以下のようになります。
手順としては、
1,SDPを利用して接続先に問い合わせ
2,受け取った情報をもとに元の相手にSDPを利用して問い合わせ
3,ICEを利用して再度接続先に問い合わせ
4,受け取った情報をもとに元の相手にICEを利用して問い合わせ
5,接続完了!
らしいです。
ただ、毎回4回も情報交換するのも面倒だと思って探してたら、以下の記事にたどり着きました。https://qiita.com/massie_g/items/f5baf316652bbc6fcef1
これは、SDP,ICEの片道の情報を一つにしてしまい、1往復の情報交換で接続するという画期的な方法です。普通に使うんだとセキュリティ的に問題があるのかもしれませんが、今回はオフライン運用であるうえ、とにかく手間なく迅速につなげればいいのでこの方法にしました。
引用元の図を参考(上記図も引用元から)
1,SDP(ICE情報も含む)を接続先に問い合わせ
2,受け取った情報をもとに元の相手にSDP(ICE情報も含む)を利用して問い合わせ
3,接続完了!
という手順です。手順を半減できたのですごく楽になりました!
難関2:シグナリング情報のやりとり
次に問題となったのが、SDP(with ICE)の情報交換の手法です。通常、WebRTCではSTUNサーバーやTURNサーバーといった接続情報の仲介を行うサーバーを利用して構築しますが、今回はサーバーレスで立てるという都合上、この方法をとることができませんでした。
ここで考えたのが以下の交換方法です
1.SDP,ICE情報をJSON化し、USBまたは共有ドライブにJSONファイルを入れて交換する。
2.SDP,ICE情報をQRコード化し、QRコードの読み取りで交換する。
3.ネットワーク上でファイル交換する。
しかしながらこれらにおいて、結局実現できたのは1のみでした。理由は以下の通りです。
2(QRコード式)の場合
QRコードでの認証情報の交換が不可能だったのは、SDP/ICE情報が多かったためです。通常、これらをQRコード等で共有する場合は、これらの情報を仲介する仲介サーバーを通します。そうすることで共通データをサーバー側で所持することでき、短い情報(認証コードやQRコード)でも情報交換が可能となります。ただ、前述したとおり今回はサーバーを構築できないというしばりがありましたので、このような交換方式はできません。これでもなお行おうとしたのには、
I.素のSDP/ICE情報をQRコードとして表示する
II.Chrome上でサーバーを構築する。
これらがあったためです。
まず、Iに関しては文字通りで、素のSDP/ICE情報をQRコード化するということです。ただ、想像つくと思いますが、こんなことは無理です。SDP/ICEは通常数百行の情報から構成されるため、これをQRコード化するとものすごい細かくなってしまいます。配布端末は内蔵のカメラが720pなので、こんなもの読み取れるはずもなく、汎用性が皆無でした。これを踏まえて、一時はSDP/ICE情報の共通部分のみをあえて固定化して、それをアプリ内に埋め込んだうえで、変数データーのみをさらに圧縮したうえでそれをQRコードで共有する方法(一応この方法だと理論上は読み取り可能なQRコードにできる)も考えましたが、あまりに複雑になるうえ、先輩から不安定になるからやめとけとの助言があったので、今回は実装しませんでした。(時間があれば実装すると思う)
次に、IIに関しては、サーバーを構築しないというしばりに反する形にはなりますが、交換の簡略化のために、構想はしました。当初、chormeに搭載されたいるsocket_apiであるchrome-tcp-socket-apiを利用しようとしていました。しかし、後々このAPIはManifest V3で廃止されるChrom App (Chrome ExtensionやPWAとは別物)のみで使用可能なAPIであり今後の継続的な運用が見込めないことがあって、採用対象外にしました。(ちなみに、ChromeAPPが使えればUSB自動書き込み機能なども付けれました。このUSB書き込みAPIを利用した例のChromeOSリカバリーユーティリティだけはV3化の対象外になっていて、この開発の際に非常にGoogleに対していろいろと思いました。)
難関3:プログラミングと機材調達
当初は前述のこともあってChrome-Extensionで素のHTML+JSで作成しようとしていました。しかし、これをずっと運営していた先輩に相談したところ、Chrome-ExtensionでなくPWAで制作したほうが、マルチプラットフォームだし、やりやすいということで、それまで私が検証に使っていたExtensionたちは没となり、PWAで再度プログラミングしました。PWA化に際しては、React+Viteで行いました。私は、素のHTMLとJavaScriptくらいしかできないので、これを機に先輩からReactを教えてもらいながら、先輩と共同で制作しました。プログラムに関しては、結構先輩を頼った部分が大きいので、もう少しちゃんと勉強していこうと思います。
機材についてですがこちらは結構うまいこと行って、情報科の先生が結構親身になって協力してくださり、生徒会執行部でもないのに生徒会の予算を利用してLANケーブル200M(100Mは学校から、もう100Mは情報科の先生の実家から)やパソコン室に余っていたL2スイッチ。先輩から学校に送ってもらったHDMI-LANエクステンダーや友達から譲り受けて学校備品にしたルーターやその他もろもろのアダプターを購入して揃えました。LANケーブルに関しては体育館を引き回す都合上ものすごい長さなので、事前に先生と長さを測ってLANケーブルは後輩と頑張って自作しました。(徹夜でカシメました)モニターやプロジェクターは学校にもともと備品としておいてあるやつを使わせてもらいました。(プロジェクター2台、大型モニター4台)
難関4:シグナリングエラー
ここからは当日の運営の話です。前日はリハーサルと同時に設営をしていたのですが、その際、シグナリングに失敗するエラーに遭遇しました。具体的には、一回目の接続時tのシグナリングでは成功するのですが、2回目以降に原因不明のエラーで接続時のシグナリングに失敗しました。USBでシグナリングデータの送信を行っているため、データ破損によるエラーではないと当初考えていましたが、当該シグナリングファイルを見てみると、Ansewerデータのみファイルが完全に文字化けしていました。このことから、デバックはMac環境だったためUTF-8の自動コーデックがかかるのに対して、運営時はWindowsだったため文字コードがShifut_JISとなり、シグナリングデーターが文字化けしているというのが原因でした。なお、当日モニターとのシグナリングできなくなった場合に備えてコントローラーのプレビュー画面を最大画面化してとりあえず移せる機能も追加しました。
その他での活用例
同様のシステムを用いて、クラスマッチ(毎年学校全体でやるスポーツマッチ)で教室からでも体育館の競技を観戦できるようにしました。以前から、YoutubeLiveの限定配信で同じようなことをしていたのですが、それをこのシステムに置き換えた形です。この場合は、校内LANを用いて(体育館にもWifiはあるので)無線でシグナリングをしました。熱中症対策になると先生にも好評でした。
終わりに。
学校運営にも貢献できる実用的なシステムが作れたと思います。Webベースにしたことで互換性問題も考えなくていいので、今後5年くらいは運営できそうです。今後は、当初断念したQRコードでのシグナリングに再挑戦してみて、もっと便利に使えるようにしたいと思います。また、体育祭を含む様々なイベントで活用をしていきたいとも思っています。最後に、この運営及び設計にアドバイスしてくださったshakenokirimi先輩、H先生はじめ多くの学校関係者の方に感謝します。今後もより良い学校運営ができるように後輩に引き継いでいく予定です。本当に高校最後の年にできてよかったです。ありがとうございました。
運営に欠かせない学校のSurface Go2