S 氏へ
面白い相談を、ありがとう。
もらった要求をまとめる
- ツーリング時の通話に使いたい
- お金はかけたくない
- デバイスは追加したくない
- いったん切れても自動で再接続してほしい
- LINE の通話よりもラグを減らしたい
- 通信量は抑えたい
いくつか構成を伝えたが、今回はこんなイメージで作る
気になる点はいくつかある
テザリングで端末間の通信はできるのか
簡単にノートパソコン 2 台をスマホのテザリングで接続し
片方でローカルウェブサーバを起動し
片方でアクセスした
成功した
特にテザリングした中では端末間の送信は禁止されていなかった
場合によっては設定で変更かもしれない。。。
ローカルだけで WebRTC 接続できるのか
普通にできるっぽい
インターネット越しに通話するとなるとサーバを使って使えそうな経路を調べることになるが、特にその設定をしなければローカルの経路情報だけが用意されて互いに通信するらしい
SDP は QR コードにできるのか
試しに生成したローカルの経路情報付き SDP を QR コードにしてみた
ものすごい細かさなので読み取りが難しいが読むことはできた
あまりに使い勝手が悪ければ複数の QR コードに分ける手もあるので受け渡し方法は QR で問題なさそう
ざっくりと設計
テザリングをするといっても
親機は SIM のない、モバイルルーターや使わなくなった端末かもしれない
そのため、インターネット接続がなくても動作するようにしたい
ネイティブアプリか PWA が考えられる
かなりどちらでもよかったが Flutter 触りたいのでネイティブアプリとして作る
と思ったがライブラリがビルドできないエラーを抱えているようだったので React(Next)を使った PWA に路線変更した
画面設計
ナビゲーションバーを使ってどの画面へも好きなタイミングで遷移できる
画面名 | 見えるもの | できること |
---|---|---|
TOP | マイクデバイス | 使用デバイスの変更 |
接続状態 | ||
接続中のセッション数 | ||
招待 | リクエスト QR | |
QR 読み取り | カメラプレビュー | QR の読み取り |
レスポンス QR |
※リクエストの QR の読み取り完了後は自動でレスポンスの QR を表示する
※レスポンスの QR の読み取り完了後は自動で TOP 画面へ遷移する
ユーザの利用フロー
- 全員、アプリをインストール
- 全員、同じ Wi-Fi に接続
- 全員、アプリを起動
- 親が QR コードを表示する(招待画面)
- 子が QR コードを読み取る(QR 読み取り画面)
- 子が QR コードを表示する(QR 読み取り画面にて QR が自動で表示される)
- 親が QR コードを読み取る(QR 読み取り画面)
これで通話できる
本来ならサーバ経由で送り合う SDP を QR コードで渡すことで通信を確立する
親 → 子だけでなく、レスポンスとなる子 → 親の情報伝達も必要になる
Flutter であれば親機をサーバにして子 → 親のステップを省けるはずだった
PWA ではサーバ機能を提供できないので断念
使えそうなライブラリ調査
PWA
CSS フレームワーク
まぁ、、、とりあえず Bootstrap でいいか。。。
みんな使ってるし。。。
一応ここで使用率はチェック
WebRTC
そもそも Javascript で WebRTC が扱える
概念的には親子間で通信する際に互いに自分と相手の SDP を設定することで使えるらしい
設定するものとしては以下の表の通り
番号は今回の処理フローにおける設定順
QRで送っているのは1と3の情報
LocalDescription | RemoteDescription | |
---|---|---|
親 | 1 親の OfferSDP | 4 子の AnswerSDP |
子 | 3 子の AnswerSDP | 2 親の OfferSDP |
QR コード生成
React 向けのもあるが
より人気のあるこっちにした
QR コード画像の URL を発行してくれる
QR コードリーダー
すごくいろいろあったが React 使うならこれでよさそう
こちらの記事が大変参考になりました
状態管理
React 標準の context で作ってみる
Redux は Vuex を使ったことがあるのでなんとなく思想がわかったのと
実際に使うとなると学習コストがかかりそうだったので今回はパス
作ってみる
Next.js プロジェクトの初期化
npx create-next-app
コマンドは Nuxt ほどじゃないが気軽に使えてよかった
今回は Typescript と ESLint を有効にした
できれば CSS フレームワークやほかの Linter の導入も支援してほしい。。。
ライブラリの導入
一旦使いそうなライブラリをすべて導入してビルドしてみる
Flutter で最初開発してて、中盤に差し掛かって導入したライブラリがビルドできないとかいう悲劇があったので、今回は最初にその可能性をつぶしておく
Bootstrap は特に問題なし、ついでに空のページとナビバーを追加してページ切り替えの動作確認
QR コードの読み取りは少しトラブル発生
React18 系に標準だと対応していなかった
Issue を参考にnpm i react-qr-reader --legacy-peer-deps
でインストールした
あまりいい対応ではないが動いたのでヨシ
QR コード生成は難なく成功
PWA は各ページのキャッシュ方法が分からなかったが
cacheOnFrontEndNav という設定があったので助かった
ひとまずどのライブラリも問題なく入って動かせた
音声通話を実現する
1 対 1 の通信確立にチャレンジする
この記事がものすごくわかりやすかった
https://lealog.hateblo.jp/entry/2019/04/22/095422
OfferSDPはQRにできたがAnswerSDPが若干容量オーバーでQRにできなかった
そもそもQRが細かすぎてスマホ同士で読める気がしないので
SDPを分割して複数のQRを一定間隔で表示することで情報を渡すことにした
QRの冒頭にインデックス情報をつけることで結合できるように工夫
意外な挙動をもう一つ確認した
AndroidはChromeでマイクを使用しているとChromeを通話アプリとして扱うらしい
このせいで音量が0にできなかった
さらにどのタブかは関係ないらしく、マイクを使っていないタブの音も通話扱いになっていた
今回は通話するためのアプリなのでいったん気にせず進めるが、音量を0にできないのでデバッグ中にハウリングが止まらない
複数人との通話を実現する
接続を複数持って管理できるようにする
これは単純でRTCPeerConnectionのインスタンスを複数持てるようにObjectに格納して保管するだけ
デプロイ
誰でも使えるように公開する
Vercelを使ったことがなく、Nextに触れたこのタイミングで使ってみることにした
驚くほど簡単だった
もうHerokuは時代遅れなのかもしれない。。。