StreamControl ことはじめ

### OBSで得点表示をしたい
検索をするとStreamControlでできるよと書いてくれている。
どんなものかね？と思って調べるとStreamControl学会が出てくるのと、Qiitaの記事が出てくる
[日本StreamControl学会](http://streamcontroljapan.blog.jp)
[Qiitaの記事](https://qiita.com/Anaakikutsushit/items/27948a73010cd2dfedb0)

この記事は上記及び日本StreamControl学会さまの、**AuraSphere** というテンプレートのコードをそのまま流用させていただいています。
問題がある場合は、連絡いただければ記事を削除いたします。

### 仕組み
StreamControlで名前などを入力　→　jsonで保存
OBSに読み込んだテンプレートからjsonを取得　→　こうしんされたJSONを監視
[![Image from Gyazo](https://i.gyazo.com/868831f9737ac8949462216e2746f6a7.gif)](https://gyazo.com/868831f9737ac8949462216e2746f6a7)

### StreamControl設定
名前や得点、ステージ名などはxmlで自由に書いて拡張することができます。
```setting.xml
<!DOCTYPE StreamControlLayout>
<layout width="390" height="340" tabbed="1">
    <tab name="Match">
        <label x="10" y="24" width="26" height="13">P1</label>
        ...
        <lineEdit id="pName1" x="30" y="20" width="100" height="20" dataSet="players.csv" />
        ...
    </tab>
</layout>
```
のように、愚直にxmlを書きます。
datasetにcsvを指定していると、チーム名などから保管入力してくれたりするのでオペレーションでは便利ですね。
このxmlは、configrationから指定できます。
[![Image from Gyazo](https://i.gyazo.com/f62a5e7e5626e7db93cca8524083af45.gif)](https://gyazo.com/f62a5e7e5626e7db93cca8524083af45)

### OBSに読み込むHTML
```test.html
<html>
    <head>
    //省略　jsは後述
    </head>
    <body onload="init()">
        <div id="container">
        <div id="player1" style="color: white ;">aaa</div>
        <div id="score1" style="color: white ;">0</div>
        <div id="player2" style="color: white ;">bbb</div>
        <div id="score2" style="color: white ;">0</div>
    </div> 
    </body>
</html>
```
名前と得点だけを表示するHTMLを書きました。
アニメーションやレイアウトはすごい人に任せることとしました。
### JSONの読み込み
今回は初期化時と、500ミリ秒に一回jsonを更新されていないかを確認して更新されていればhtmlを書き換えるという処理を愚直に書きました
```sctest.js
var xhr = new XMLHttpRequest();

//最初かどうかのフラグ
var firstupdate = true;
var animating = 0;

//初期化時以降はタイムスタンプで判定
var timestampOld=0;
var timestamp=0;
var cacheBusterValiable=Date.now();
var cacheBuster=0;

var switchCount = 0;

//パラメーター
var currPlayer1;
var currPlayer2;
var currScore1;
var currScore2; 

//html呼び出し時の処理
function init(){
    xhr.overrideMimeType('application/json');

    xhr.onreadystatechange = scLoaded;
    pollHandler();
    //500ミリ秒に一度pollHandlerでjsonを取得し直す
    setInterval(function() {
        pollHandler();
    }, 500);
}

//jsonの取得
function pollHandler() {
    xhr.open('GET', "streamcontrol.json?"+cacheBusterValiable+"="+cacheBuster,true);
    xhr.send();
    cacheBuster++;
}

//jsonのパース及びオブジェクトへの代入
function scLoaded() {
    if (xhr.readyState === 4) {
        scObj = JSON.parse(xhr.responseText);

        timestampOld = timestamp;
        timestamp = scObj["timestamp"];
        //console.log(timestamp);
        if (timestamp != timestampOld && animating == 0 || firstupdate) {
            update();
        } else {
            switchCount++;
        }
    }
}

function update(){
    var datetime = new Date();
    var unixTime = Math.round(datetime.getTime()/1000);

    //初期化時変数の代入
    if(firstupdate){
        currPlayer1 = scObj["pName1"].toString().toUpperCase();
        currPlayer2 = scObj["pName2"].toString().toUpperCase();
        document.getElementById("player1").innerHTML = currPlayer1;
        document.getElementById("player2").innerHTML = currPlayer2;

        currScore1 = scObj["pScore1"];
        currScore2 = scObj["pScore2"];
        document.getElementById("score1").innerHTML = currScore1;
        document.getElementById("score2").innerHTML = currScore2;

        firstupdate = false;
    } else {　//今回は初期家事以外はelseで値を更新
        currPlayer1 = scObj["pName1"].toString().toUpperCase();
        currPlayer2 = scObj["pName2"].toString().toUpperCase();
        document.getElementById("player1").innerHTML = currPlayer1;
        document.getElementById("player2").innerHTML = currPlayer2;

        currScore1 = scObj["pScore1"];
        currScore2 = scObj["pScore2"];
        document.getElementById("score1").innerHTML = currScore1;
        document.getElementById("score2").innerHTML = currScore2;
    }

}
```
このjsonのファイル名は、streamcontrol.jsonらしく、これの中身はstreamcontrolを定義した最初のxmlに準拠しているようです。

### 装飾など
これはお好みで、CSS書いたり、jsのアニメライブなりを使うなどして立地にすればよいかと思います。
ただし、なんかOBSの内部ブラウザがモダンではないようなので、そのへんは考える必要があると思います。

### おまけ
OBSでデバッグができないのがなと思って調べたら、以下のページを見つけました。
**OBSのブラウザソースからJavaScript扱う時の豆知識**
https://tech.packetroom.net/obs-browser-source-remote-debugging

ここでOBSで動いているブラウザソースをデバックできたりすることが書かれているので、非常にありがたかったです。

### まとめ
今回、StreamControlを触りたかったけど、なんかごちゃごちゃしてるし最低限どう触ればいいのだろうということでメモとして残しました。
js部分などは本当にそのままコピーさせてもらったので、問題があれば記事を消しますのでコメントください。
配信などで、スコア表示をしたいというニーズはあると思ったので改めてコア部分だけを取り上げました。
今回実行ファイル版ですが、どうやらブラウザ版もあるようなので、モダンな方はそちらを使うほうがいいかもしれません。