概要
最終的にはMacOS、Android、iOSで
unityとwebrtcを連携させて色々やるのが目標
今回はMacOSで動作させる方向
まず手はじめに必要なライブラリ等を揃えた話
https://qiita.com/taktod/items/a8c87068265fff951c0f
次に実際にプログラムを組んでみた時の話
https://qiita.com/taktod/items/76f0fc450745e5e87f57
今回は作ってみた時にハマったアレコレ
signalingで利用するwebsocket
いろんな端末に対応する上で処理をできるだけUnityの動作に委ねる方が楽だと考えた。
なので、websocketで利用するプログラムを当初、Websocket-sharpにしてみた。
すると・・・
なぜかはわからないけど、webrtcのプログラムが暴走した。
どうやらwebrtcの世界に第三の世界から触るのはよろしくないみたい。
逆にwebrtcのthreadからcsharpの関数をcallすると・・・
これもだめみたい。
c++で実装したコードからunity側のcsharpのコードをcallすることができるので、webrtcのイベント、例えばdataChannelでメッセージを受けた時にcsharp側の特定の関数をcallする・・・
というコードを書いてみた
すると全く動作しない。
unityの世界では、unityが設定したthreadから処理しなければいけないという制限がある模様。
映像データの表示
webrtc経由できたVideoFrameの映像データ
僕のイメージだとYUVデータできているのわけですが・・・
これも試行錯誤しました。
まずは、plugin側でyuv -> rgb変換して応答するやり方
素直な動作ではあるんですが、CPUで計算してやる動作は想定以上に重かった。
yuvの要素をそのまま渡してshaderでyuv -> rgbする方法
それぞれの要素のデータをそのままcsharp側にIntPtrの形で渡してやって、それでunity上でtextureを3つ1セットつくって表示させる・・・
これをやってみたところ、そこそこの動作したのですが、unity側でtextureを作りまくった結果。
textureが保持するデータが解放されないみたいで、メモリー使いすぎて死にました。
native側でtextureを準備する方法
で、結局これに行き着きました。
native側でtextureの更新をしてしまえば、メモリーリークしないことがわかっているので、この方法で調整しました。
websocketと同じく、環境依存なコードを書く必要がありましたが、まぁ・・・なんとか
metalで動作させる場合は、考慮する必要はあまりないですが、OpenGL使う場合は、このrenderThreadに手を加える必要が出てくるのでややこしかった。
というわけでMacOSの動作はこんな具合になりました。
nativePluginを作成する。
signalingはSocketRocketを使って動作する形に・・・で、nativePlugin側に練り込む形にしました。
dataChannelのやりとりメッセージは、取得したらクラスインスタンスが保持する形にしておき、unity側のthreadから必要ように応じて問い合わせる形にした。
これにより、取得ミスするデータが生まれる懸念や、通信が遅れる懸念も出てきた。
音声データは全てwebrtcに任せる形にした。
映像データの取り扱いはTexture自体はUnity側で作るけど、その更新をnativePluginで実施するという形に
Metalはidが取得できるので、それを保持して、webrtcのVideoSinkで取得したyuvデータを設定
OpenGLはGLuintでtextureIdが取得できるので、RenderThreadをうまく使って更新する感じに・・・
音声の配信はwebrtcに任せる形にした。
映像の配信は未実装
プログラムは基本c++で実装だけど拡張子はmmでobjective-c++の体裁を取っておきました。
となりました。