スマホでNintendo Switchのゲームをする
前々回はNintendo Switch Pro ControllerのWeb対応。 前回はNintendo Switchゲーム画面のWeb対応。 今回はNintendo Switchゲーム音声のWeb対応。
何を作ろうとしてるか、だんだんワクワクしてきましたね?
前回の記事の最後に挙げたまとめです。その成果として表題の通り、スマホでNintendo Switchのゲームをすることができました。 そこまでの道筋です。
釣りタイトルっぽくなっているため、Nintendo Switch本体を持ってない人がスマホでNintendo Switchのゲームができると勘違いして迷い込んだ人はお帰りください。
目次
Open 目次
振り返り
これまでの振り返りです。 振り返りつつ、変更点を記します。
Pro Controllerの模倣
この回ではNintendo Switch Pro Controllerの挙動を解析し、スマホから操作するところまでやりました。 libusbgxやGstreamerとの相性を考え、GoやRustを使わずCで書いていたものの、h2oのWebSocket実装が未熟だっり、glibやlibevent使うの辛かったりしたのもあって、Cで書くのをやめて結局Goで書き直しました。 単純な実装ですが、コントローラーのシミュレーション部はGoモジュールとして分離して公開しました。
mzyy94/nscon: Nintendo Switch Controller simulator written in go - GitHub
HDMI入力を扱う
HDMI入力をRaspberry Piで駆使する
昨今の衰えることのない技術トレンドに追従すべく、映像配信とかやりたいなーと思っていた2019年。 めっきり時間がなく何もできず、気付けば2020年になっていました。今年も時間がないだろうなぁと思っていたところ、連日の在宅勤務のおかげで通勤時間がゼロになり、余暇が生まれたので色々やってみることにしました。お題はHDMI入力で遊ぶ、です。...
- Mzyy94
- Multimedia
- 09 Apr, 2020
HDMI入力基板を用いてHDMI入力を扱いました。 Raspberry Pi公式のCamera Moduleとして認識してくれるので、何もせずにH.264で入力を扱えて楽でしたが、これはこれで問題を抱えていました。 再接続時に問題があることがこの時点ではわかっていたんですが、もっと使い込んでいくと入力解像度がおかしくなるなど、さらに問題があることがわかりました。
使用したHDMI入力基板はTC358743XBGというチップを使ってHDMI入力をCSI2に変換していると紹介しました。 このTC358743XBGはLinuxにドライバがあり、Camera Moduleのドライバを用いずにVideo4Linux2のデバイスとして認識させることができます。
linux/tc358743.c at v4.19 · torvalds/linux
このドライバを使うことで、入力機器が転送可能な映像の種類を記すEDIDを扱え、入力解像度をはじめとする諸問題も解決できます。
Raspberry Piでこのドライバを用いるには、デバイスツリーにtc358743を認識させるだけです。
/boot/config.txtにdtoverlay=tc358743
を追記し、再起動することでドライバが読み込まれます。
pi@raspberrypi:~ $ dmesg | grep tc358743
[ 5.718785] tc358743 0-000f: tc358743 found @ 0x1e (bcm2835 I2C adapter)
pi@raspberrypi:~ $ lsmod | grep tc358743
tc358743 40960 1
v4l2_dv_timings 36864 2 bcm2835_unicam,tc358743
v4l2_fwnode 20480 2 bcm2835_unicam,tc358743
v4l2_common 16384 3 bcm2835_unicam,bcm2835_v4l2,tc358743
videodev 200704 9 bcm2835_unicam,v4l2_fwnode,bcm2835_codec,v4l2_common,videobuf2_common,bcm2835_v4l2,v4l2_mem2mem,videobuf2_v4l2,tc358743
media 36864 5 bcm2835_unicam,bcm2835_codec,videodev,v4l2_mem2mem,tc358743
これだけでは入力映像を扱えず、EDIDを機器側に通知して初めて使えるので、ドライバが読み込まれる度にEDIDをセットする必要があります。 このために用意した720P30EDID.txtをダウンロードし、以下のようにEDIDのセットを行うことで、V4L2で1280x720のRAW映像を扱えるようになります。
v4l2-ctl --set-edid=file=720P30EDID.txt
v4l2-ctl --set-dv-bt-timings query
繋がっているHDMI入力の情報はv4l2-ctl --query-dv-timings
で見られます。
結果としてRaspberry PiのCamera Moduleとしては認識しなくなったため、H.264圧縮はされず、YUVのRAW映像としてしか取り込めません。 H.264で遅延の少ない映像を得るにはハードウェアエンコーダーを利用する必要があります。 しかし、このドライバを用いている時は、先の記事で紹介したomxh264encは使えないため、v4l2h264encを使います。
RTPで送信する例は、こんな感じです。
gst-launch-1.0 v4l2src ! video/x-raw,width=1280,height=720,framerate=30/1 ! v4l2h264enc extra-controls="encode,h264_profile=1,h264_level=12;" ! video/x-h264,width=1280,height=720,stream-format=byte-stream,profile=constrained-baseline ! h264parse config-interval=-1 ! rtph264pay pt=96 ! udpsink host=mzyy94.local port=5678
Switchの音声出力を取り込む
UAC GadgetでNintendo Switchの音声出力をRaspberry Piに取り込む
前回の記事 でHDMI映像入力をRaspberry Piで扱う方法を紹介し、その最後に音声の取り込みについて、まだ課題が残っていると書きました。 HDMI入力からの音声取り込みといった、本質的な課題の解決を試みているものの、なかなかに難しい問題に直面しているので、対象を限定して部分的解決に挑みます。主に今HDMI入力の対象として使おうと思っているデバイスは、Nintendo Switchです。...
- Mzyy94
- Multimedia
- 17 Apr, 2020
UAC Gadgetでオーディオデバイスをシミュレートし、ALSA経由で取り込んでWebRTCでブラウザで見られるようにしました。 この時は、GstreamerのWebRTCを用いていましたが、WebRTCのSDPのネゴシエーションに不備があるなど、これも問題を抱えていました。 そのため、iOS SafariやAndroid Chromeなどでは映像と音声が再生されないなどの問題がありました。
WebRTCなんもわからんな pic.twitter.com/v3URQb6LQL
— ミ゛ (@mzyy94) April 4, 2020
Gstreamerはv4l2srcからHDMI入力を取り込み、v4l2h264encでH.264にエンコードするまでを任せ、WebRTCは別のソフトウェアを使うことにしました。 OSSのWebRTCバックエンドは、Goで実装されたPionが有名です。
pion/webrtc: Pure Go implementation of the WebRTC API
以前から使ってみたい興味はあったので、これを用いてWebRTCで転送するようにしました。 exampleにあるコードそのままではコーデック情報が正しく指定できなかったため、SDPをちゃんと読む処理を加えています。 また、GoでGstreamerを扱うため、ある程度必要なものが揃ったバインディングであるnotedit/gstを用いました。
成果物
— ミ゛ (@mzyy94) May 6, 2020
これまでの成果を全部くっつけたものです。 遅延は0.2秒程度あるものの、どうぶつの森であれば十分にプレイできる程度です。 難点はNintendo Switchを遠隔でスリープ復帰できないので、スリープを解除した状態でDockに入れる必要があることくらいで、他は十分に求めるレベルまで達しています。
mzyy94/ns-remote: Play Nintendo Switch anyware
必要なハードウェアが多いですが、GPLv3ライセンスのもと公開しているので、よかったら遊んでみてください。
まとめ
これで湯船に浸かりながらどうぶつの森が遊べるようになりました。
WebRTCとWebSocketで実装してあるので、デバイスに依存せず、例えばWebXR/WebVRとの組み合わせもできるので、幅広い活用ができそうです。 良い自粛のお供ができました。
外出自粛の中、どうしてもピクニックしながらどうぶつの森をやりたい欲が抑えきれなかったのでVRで満たした☺️普通に快適に遊べてとても満足😌 pic.twitter.com/6eNGr6T025
— ミ゛ (@mzyy94) April 18, 2020