unityController - Genvid クライアント初期化

Genvid クライアント初期化セクションには、ストリーム開始、さまざまな変数の初期化、イベントリスナーの割り当てに必要なほとんどのコードが含まれています。

onConnect

onConnect()

onConnect メソッドがサービスへの接続を開始します。接続が適切に実行できると、検出した IChannelJoinResponse()on_channel_join を実行します。

        // Start the connection to the services
        onConnect() {
            let promise = $.post("/api/public/channels/join", {}, (joinRep) => {
                this.on_channel_join(<genvid.IChannelJoinResponse>joinRep);
            });
            promise.fail((err) => {
                alert("Can't get the stream info:" + err);
            });
        }

on_channel_join

on_channel_join(info: genvid.IChannelJoinResponse)

on_channel_join メソッドは、サービスとチャネルに接続後、Genvid クライアントを作成します。このプロセスで検出された情報と、class 作成プロセスで送信された video_player_id を使用してクライアントを作成します (これは unityController class の引数です)。

その後、この class に特定のイベントを関連付ける必要があります。

onVideoPlayerReady
ビデオストリームの準備が完了した時にトリガします (コンテンツの初期化に使用)。
onStreamsReceived
ストリームコンテンツを受信した時にトリガします (タイムコードとゲームデータの取得に使用)。
ゲームデータの取得に使用)。
onNotificationsReceived
通知を受信した時にトリガします (popularity に使用)。
onDraw
ビデオで新しいフレームの描画時にトリガします。

次に、 start() メソッドでクライアントを開始します。

        // Create the genvid Client and the function listening to it
        private on_channel_join(joinRep: genvid.IChannelJoinResponse) {
            this.streamInfo = joinRep.info;
            this.client = genvid.createGenvidClient(this.streamInfo, joinRep.uri, joinRep.token, this.video_player_id);
            this.client.onVideoPlayerReady((elem) => { this.on_video_player_ready(elem); });
            this.client.onStreamsReceived((streams) => { this.on_streams_received(streams); });
            this.client.onNotificationsReceived(this.on_notifications_received.bind(this));
            this.client.onDraw((frame) => { this.on_new_frame(frame); });
            this.client.onDisconnect(() => {this.on_disconnect_detected();});
            this.client.start();
        }

on_disconnect_detected

on_disconnect_detected()

このサンプルでは、onDisconnect() コールバック (IGenvidClient() インターフェイスにより公開) を使って、クライアントのソケットが閉じるタイミングを通知します。指定のコールバックをバインドすることで、実行しています。

this.client.onDisconnect(() => {this.on_disconnect_detected();});

クライアントソケットの閉鎖通知が届いたら、スクリプトに再接続試行の指示を行います。

        private on_disconnect_detected(){
            let promise = $.post("/api/public/channels/join", {}, (joinRep) => {
                this.client.reconnect(joinRep.info, joinRep.uri, joinRep.token);
                this.resetFibNums();
            });
            promise.fail( async () => {
                await this.sleep(this.getNewSleepDuration());
                this.on_disconnect_detected();
            });
        }

ここで、新しい leaf アドレス、新しいトークン、新しい streamInfo の情報リクエストを行います。

リクエストが成功した場合、reconnect() を呼び出して、この情報を使用して新しい websocket 接続を確立します。

リクエストが失敗した場合 (利用可能な leaf がないなど)、しばらく待って再試行します。インクリメンタルなフィボナッチ数の計算結果を使用して、待機時間を決定します。

        private sleep(ms) {
            return new Promise(resolve => setTimeout(resolve, ms));
        }

        private getNewSleepDuration() {
            this.fibNumResult = this.fibNumOne + this.fibNumTwo;
            this.fibNumOne = this.fibNumTwo;
            this.fibNumTwo = this.fibNumResult;
            this.delayBetweenReconnectionAttempts = this.fibNumResult + (this.fibNumResult * Math.floor(Math.random() * 10) * 0.01); // + 0 to 10% 
            return this.delayBetweenReconnectionAttempts * 1000; // milliseconds
        }

        private resetFibNums() {
            this.fibNumOne = 0;
            this.fibNumTwo = 1;
        }

フィボナッチ数列の結果に 10% のランダム要素を追加します。これにより、2 つのサービスが同時に接続を開始する状況を回避します。接続に成功したときにフィボナッチ数をリセットします。

on_video_player_ready

on_video_player_ready(_elem: HTMLElement)

変数の開始、WebGL コンテキストの作成、イベントリスナーの追加に使用します。

  1. この関数では、Div と Link エレメントのほとんどを JQuery で取得します。

                this.video_player = this.client.videoPlayer;
    
                this.timeLocalDiv = <HTMLDivElement>document.querySelector("#time_local");
                this.timeVideoDiv = <HTMLDivElement>document.querySelector("#time_video");
                this.timeVideoRawDiv = <HTMLDivElement>document.querySelector("#time_video_raw");
                this.timeComposeDiv = <HTMLDivElement>document.querySelector("#time_compose");
                this.timeComposeLastDiv = <HTMLDivElement>document.querySelector("#time_compose_last");
                this.timeStreamDiv = <HTMLDivElement>document.querySelector("#time_stream");
                this.latencyDiv = <HTMLDivElement>document.querySelector("#latency");
                this.delayOffsetDiv = <HTMLDivElement>document.querySelector("#delay_offset");
                this.controlsDiv = <HTMLDivElement>document.querySelector("#game-controls");
    
                this.timeCamSceneDiv = <HTMLDivElement>document.querySelector("#timeCamScene_overlay");
    
                this.promptOverlay = <HTMLDivElement>document.querySelector("#prompt_overlay");
    
                this.videoOverlay = <HTMLDivElement>document.querySelector("#video_overlay");
                this.canvas3d = <HTMLCanvasElement>document.querySelector("#canvas_overlay_3d");
    
                this.mouseOverlay = <HTMLDivElement>document.querySelector("#mouse_overlay");
    
                this.genvidOverlayButton = <HTMLLinkElement>document.querySelector("#genvid_overlay_button");
                this.genvidOverlay = <HTMLDivElement>document.querySelector("#genvid_overlay");
                this.help_overlay = <HTMLDivElement>document.querySelector("#help_overlay");
                this.helpButton = <HTMLLinkElement>document.querySelector("#help_button");
                this.fullScreenDiv = <HTMLDivElement>document.querySelector(".fullscreen-button");
                this.fullScreenElement = <HTMLElement>document.querySelector(".fa-expand");
    
  2. canvas3d を選択して WebGLContext を作成します。

  3. ウィンドウ変更のイベントリスナー (全画面、サイズ変更) をすべて追加します。

  4. mouseOverlay のクリック操作用イベントリスナー (ビデオオブジェクトのクリック判定用)、 Genvid ボタン、 Help ボタンのクリック操作用イベントリスナーを追加します。

                this.hideOverlay();
                this.client.videoPlayer.addEventListener(genvid.PlayerEvents.PAUSE, () => {
                    this.hideOverlay();
                });
    
                this.client.videoPlayer.addEventListener(genvid.PlayerEvents.PLAYING, () => {
                    this.showOverlay();
                });
    
                this.genvidWebGL = genvid.createWebGLContext(this.canvas3d); // Need to assign before any resize.
    
                document.addEventListener("fullscreenchange", () => { this.onResize(); });
                document.addEventListener("webkitfullscreenchange", () => { this.onResize(); });
                document.addEventListener("mozfullscreenchange", () => { this.onResize(); });
                _elem.addEventListener("resize", () => { this.onResize(); });
    
                window.addEventListener("resize", () => { this.onResize(); }, true);
                window.addEventListener("orientationchange", () => { this.onResize(); }, true);
                window.addEventListener("sizemodechange", () => { this.onResize(); }, true);
                window.setInterval(() => { this.onResize(); }, 1000); // Just a safety, in case something goes wrong.
    
                this.mouseOverlay.addEventListener("click", (event) => { this.clickCube(event); }, false);
                this.genvidOverlayButton.addEventListener("click", (_event) => { this.toggleGenvidOverlay(); }, false);
                this.helpButton.addEventListener("click", (_event) => { this.onHelpActivation(); }, false);
                this.fullScreenDiv.addEventListener("click", (_event) => { this.toggleFullScreen(); }, false);
    
  5. onResize() を実行して、適切なウィンドウサイズにオーバーレイを合わせます (この処理を行わないと、オーバーレイが小さくなりすぎます)。

  6. 最後に WebGL オーバーレイを初期化します。

                this.onResize();
    
                // Initialize graphics stuff.
                this.genvidWebGL.clear();
                let gl = this.genvidWebGL.gl;
                gl.disable(gl.DEPTH_TEST);
    
                this.gfx_initShaders();
                this.gfx_initRenderCommands();
                const muteIcon = document.getElementById("mute-button");
                muteIcon.addEventListener("click", () => this.onMute());
                if (!this.video_player.getMuted()) {
                    this.onMute();
                }
    
                this.videoReady = true;