メモです。
twitchとかの配信系をUdonで流す時にやったことについて書きます。
どっかに既に書かれているのかもしれない。
前提
VRChat Examples/Prefabs/VideoPlayer/UdonSyncPlayer (AVPro).prefab
が元々サンプルとして入ってます。
ですがソースを覗いてみるとどうやら通常のビデオ再生用っぽい仕組みが入っていて。
「ownerの再生時刻から一定時間ズレてると再同期」するんですが、ストリームの場合の再生時刻は各ローカルで変わるのでこのままだと「owner以外無限にリロードし続ける」感じになっちゃいます。なってました。
USharpVideoにはその防止はちゃんと含まれてるんですが、なんか音が鳴らなかったりした (私が悪いのかもしれない) しまぁそこまでの機能は要らない。
ということで自分で作ってみることにしました。
基本設定
VRCAVProVideoPlayer
が使うメインのコンポーネントです。こいつは適当なところに置いておきます。
諸々 (スクリーン・スピーカー) がpull型の振る舞いをします (たしかにね)。その辺の設定はExamplesのを拾ってくるのが早いと思います。
まぁそうなる。†立体音響†はお好みで。
Use Low Latency
はtwitchにはうまく効かなかったみたいです。まぁその辺は詳しい方が居るでしょう…
重要なんですが、まずこの時点でちゃんとストリームは再生されます。それくらい単純に使えるようには出来ています。すごい。
ただ配信が止まったりローカルで不安定なこともあるので、いつでもリロード出来るようにする為にUdonを取り付けます。
予め public で VideoPlayer を参照しておく必要が多分あります (GetComponentできなかったので)。
Reloadする為に Url も教えておきました (VRCUrl型)。AutoPlayされるものと同じものにしています。今回は配信先が一定なので全部ベタですけど変わるなら変えればいいと思います。
Textは現在状態表示用です。こういうのは内部で何が起きてるかわからないがちなので気軽に出力できる場所を用意しとくと気持ちが楽になります。私は。
うどん
using UdonSharp; using UnityEngine; using UnityEngine.UI; using VRC.SDKBase; using VRC.Udon; using VRC.SDK3.Video.Components.AVPro; using VRC.SDK3.Components.Video; public class StreamPlayer : UdonSharpBehaviour { public VRCAVProVideoPlayer videoPlayer; private bool waitForResponse; public Text display; [Space(10)] public VRCUrl url; public void Sync() { if(waitForResponse) return; waitForResponse = true; display.text = "Sync"; videoPlayer.LoadURL(url); } public override void OnVideoReady() { waitForResponse = false; display.text = "Ready"; videoPlayer.Play(); } public override void OnVideoStart() { display.text = "Start"; } public override void OnVideoError(VideoError videoError) { waitForResponse = false; display.text = $"Error: {videoError}"; } public override void OnVideoEnd() { display.text = "End"; } }
基本的に勝手にイベントが引かれるのでそれを読むだけです。
LoadUrl
でリロードが行われます。成功すると OnVideoReady
、失敗すると OnVideoError
が呼ばれます。リロード中に LoadUrl
すると怒られる (Rate Limit Exceeded) し無意味なのでそれを防ぐために waitForResponse
を立てています。
OnVideoReady
が来たらさっさと再生を開始。そのうち OnVideoStart
が呼ばれます。
配信が終了すると OnVideoEnd
が呼ばれます。
これで終わり。
同期ボタン
Sync
を実行するUdonを作ります。やるだけです。
using UdonSharp; using UnityEngine; using VRC.SDKBase; using VRC.Udon; public class SyncButton : UdonSharpBehaviour { public StreamPlayer streamPlayer; public bool local; public bool restrictOperator; public string operatorName; public override void Interact() { if(local) streamPlayer.Sync(); else { if(!restrictOperator || Networking.LocalPlayer.displayName == operatorName) { streamPlayer.SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, "Sync"); } } } }
ええと、何をしているかというと、「ローカルで同期・グローバルで同期」の切り替えと、「同期機構を特定の人だけが使える仕組み」が入ってます。
ローカルの場合は直接 streamPlayer.Sync
を呼べばいいです。グローバルの場合は SendCustomNetworkEvent
経由で全員に飛ばします。
あと特定の人しか使えないようにする為に適当に Networking.LocalPlayer.displayName
を拾っています。displayName被りが起きるとヤバい気はしますがまぁ大丈夫でしょう。
「誰でもローカルでリロードする」ボタンと「ワールド主が全員強制リロードさせる」ボタンがあると便利かなという気持ちがあります。配信停止したりすると自動再開とかはしないので、ちゃんとリロードは自前で発火しないといけません。
まぁ機能は各々好きに付け足せばいいと思います。Sync
はローカルで作られてるのでどうしようかは外側の自由です。
おわり
簡単でした。自分でつくろうと思ってからは。
VRCSDK2と違ってお節介をしないことが何よりもありがたいです。