要旨
Flutter/Android用にSkyWayを使ったサンプルが見当たらないので作ってみました。
p2pの1:1ビデオチャット、SFUまたはMesh(p2p)を使ったビデオカンファレンスの3つのサンプルを1つのアプリにまとめています。
適当に作ったので冗長な/余分なところところも散見されますが多めに見てけろ?
プロジェクトリポジトリはこちらskyway_flutter_test @ github
チェックポイント
ちょっと手間くったのは次の通りでし。
- Dart側で生成したPlatformViewをプラットフォーム側から参照する方法
- パーミッションの処理
- SFU/Mesh接続のときのUIレイアウト
- SkyWayの処理を直接Kotlinのコードから呼び出すとSDK内でクラッシュする
- Android用skywayのSDKでv2.0.3以下と2.0.4と2.1.0が混在したときの挙動確認
Dart側で生成したPlatformViewをプラットフォーム側から参照する方法
これはどうするのがベストプラクティスがようわからん?
とりあえずDart側のから呼び出されるプラットフォーム側のラッパークラス・ファクトリーメソッドでDart側から設定されるidをキーとしてラッパークラスのインスタンスをstaticに保存しておいて(HashMap)、必要なときにはDrart側からidを引き渡して保存しておいた参照を探すということにしました。
いろいろ調べた限りではFlutterでは通常のAndroidアプリと違ってViewの階層構造の中にPlatformViewを入れているわけじゃないのと、レイアウトxmlファイルで指定するのと違ってDart側から渡されるid(見た感じ生成したPlatformViewの連番)から直接
View#findViewById とするわけにはいかないっぽいので。
かといってSkyWay関係の処理を行うクラス内で適当に生成すると親ViewがいないのとDart側のwidgetとの関係がうまく構成できないのでしかなく。
ちなみにプラットフォーム側のViewの内容が直接画面へ描画されるのではなく、一旦Canvas/仮想ディスプレーを使ってオフスクリーン描画を行った後Flutter側のウイジェットへ転送されて描画されるという仕組みでボチボチなパフォーマンスなようです。
このプロジェクトでは使っていませんが、パフォーマンスが必要な場合は
Texture ウイジェットへテクスチャとして使用できるオフスクリーン(Androidの場合は
SurfaceTexture)を経由して描画すると良いです(このテストプロジェクトを作る前にUVC機器をFlutterから使えるようにするプラグインを作るときにテストしましたが通常のAndroidアプリと同じフレームレートで描画できました)
パーミッションの処理
これもFlutter特有の問題で、プラグインや FlutterActivity を継承した MainActivity から ActivityCompat#requestPermissions 等を使って直接動的パーミッションを要求してもパーミッション要求ダイアログすら表示されません。しかも端末のアプリ設定からパーミッションを許可すると実行はできるもののなにがしらかのエラーメッセージがlogCatに出力されてしまいます。
いろいろ調べた結果、プラグインを作るなりしてFlutter様の要求仕様通りにパーミッション要求しないとだめということらしいです。Flutterの公式サンプルのカメラアプリとかを参考にすれば自分で作れそうですが面倒なので、絶対こんな面倒なことは誰かがすでに作っているに違いないとプラグインを漁ったところいくつか見つかりました。今回はそのうちのpermission_handlerというのを使わせていただきました。
SFU/Mesh接続のときのUIレイアウト
ほんとうはwebのビデオカンファレンスアプリとかでよくある
- 下端にリモート側ユーザー一覧を並べておいて選択したのが大きく拡大表示
- 選択した1人だけ拡大したタイル表示
あたりにしようかと思ってしばらく頑張ったのですがFlutter/Dartスキルが足らず断念しました(途中で飽きたともいう)?
SkyWayの処理を直接Kotlinのコードから呼び出すとSDK内でクラッシュする
自分の実装ミスかもしれないですが、SkyWayのSDK内でNoNull指定されているところにNullが設定されことがあるらしくSkyWayのSDK内でクラッシュしてしました。なので一旦KotlinとSkyWay SDK間にJavaのヘルパークラスを挟むようにしました(。・_・。)
Android用skywayのSDKでv2.0.3以下と2.0.4と2.1.0が混在したときの挙動確認
これはFlutterとか関係ない話なので今回のテストアプリを作る前から知っていたのですが、Android SDK v2.0.4及びiOS SDK v3.0.1で「WebRTC通信が一時的な切断状態になった場合に、自動で再接続を試行する」変更が入っています。
使っているアプリ全てがこの変更に対応したSDKを使っていれば問題ないのですが、モバイルアプリの場合はアプリを更新してもすぐにユーザーが更新してくれるとは限りません。その結果再接続試行機能の入ったバージョンと入っていないバージョンが混在した場合に、リモート側から通話を切断した場合に、再接続試行機能の入った新しいバージョンを使うアプリでは十数秒〜数十秒間映像が更新されず&かといって切断もされない状態になってしまってました(一見アプリがフリーズ/ANRしたように見えてガッツリUXがかわる)。
8-9月らへんに作ってた仕事のアプリでは再接続試行機能の入っていないAndroid SDK v2.0.3及びiOS SDK v3.0.0を使うことでごまかしていたのですが、新しく作ったこのプロジェクトで2.0.4(テスト的には2.1.0)を使ってしまったのです。その結果以前作ったテストアプリ(SDK2.0.3)と接続すると一見フリーズしたかのように見えてしまうことに気づきました。
Twitterで愚痴っていたらSkyWayの中の人から連絡をいただき対応を追加していただけることになりました。
skywayのAndroid SDKの2.0.4以降って接続が切れた時に勝手に再接続を試行するように改悪されてしまったんだけどこれめっちゃ邪魔だよね?正規に相手側から切断されても映像止まったまま数秒間放置されちゃうんだよ?せめてタイムアウトまでの時間を設定できるとか再試行前イベントを起こしてくれんかな
— さきちゃんの中の人、お仕事欲しい? (@serenegiant) November 11, 2020
今時点(2020/11/12 21:40)ではリリースはまだですが近日公開されるようです。
ありがとうございます、お手数をおかけしましたm(_ _)m
以前のSDKと混在が想定される環境ではAndroid SDK v2.1.0,v2.0.4・iOS SDK v3.1.0,v3.0.1 へのアップデートはお控えください